ARCHITECTURE
Need to know how to authorise a user for each microservice in the given architecture. I.e. deny requests to each microservice if they are not authorised to have that module as per user data in the main db.
I also need to share the user from the main db between each microservice db to maintain data integrity.
Is there a way to do this? Or do I need to re-create a user table in each microservice? Basically meaning that everytime a user wants access to a microservice I have to create a new user (POST from main api) in the microservice (at the loss of data integrity).
I haven't tried anything yet looking for suggestions/a solid and SECURE architecture. Each microservice will be hosted on a subdomain on same PAAS as to avoid transfer attacks and reduce delay.
deny requests to each microservice if they are not authorised to have that module as per user data in the main db.
Assuming you are using OAuth2.0 with JWT access and refresh tokens, you could use the "aud" claim of JWT token to carry the authorizations or entitlements or permissions to access individual microservices. In the "aud" claim, you could provide the individual service URL, or service id that the user is authorized to access. At the individual micro service (or resource server in OAuth terminology) you need to check if the JWT carries the particular microservice UR or id in its "aud" claim. If not, access will be denied.
I also need to share the user from the main db between each microservice db to maintain data integrity.
That's not usually how this is done.
You usually have an authorization server. That is the master of all the user information. Any unauthenticated user trying to access any service will be redirected to the authorization server and asked to provide their authorizations after authenticating themselves. Once the authentication is done and authorizations are given, the user will be redirected to the service page with appropriate access and refresh tokens which will thereafter accompany all user requests. Even when the request goes from User A -> Service B -> Service C. Service B and C would then need to check:
Is the JWT valid (not tampered by anybody)? (using the digital signature in the JWT - usually HMACSHA256)
Is the access token (usually a JWT) still valid as per the expiry date and time set in the "exp" claim of the JWT by the authorization server?
Is the service URL or id present in the "aud" claim?
If all the 3 questions are answered as "yes", access is granted and each service can find out the user name from the "sub" claim of the JWT. The user name can be the logged for audit
I also recommend you read this answer.
Related
Have an API in Azure API Management (APIM).
The API operation validates a JWT generated by Azure Active Directory (AAD) using a scope from a backend app registration (the scope is NOT User.Read). Note: client id is another app registration which is an authorized app of that backend scope.
After the JWT is validated, am I able take that token, extract user info out of it and verify if the user is part of a email distribution list (DL)? If so, how to do it within an APIM policy?
I am aware of MS Graph APIs. Using Postman I can confirm the DL is listed in the tenant's groups and can get its group ID. I can also confirm the user is a member of the group. The bit I'm stuck with for Graph API is that it needs a different token to the one supplied by the client application (due to he scopes being from different domains custom app registration vs graph) and I'm stuck at this point. Should I make the client app also get a graph token and pass it in a separate header, or is there way to orchestrate things from within APIM or something else?
The non-APIM part of this solution is provided by a Microsoft article. I've summarised those and combined with the APIM parts in the following steps:
In Azure, create a new Azure App Registration (note the client id for later)
Under "Certificates and secrets", add a client secret (note the secret for later)
Under "API Permissions", add a new MS Graph Application Permission (can be User.Read.All, Group.Read.All, GroupMember.Read.All depending on your situation). MS Graph's "groups" includes both AD groups and Distribution Lists (DL). Note: don't use Delegated permission.
Application permissions allow the authorized app to enquire about any user/group. You will need an Azure Admin to Grant Admin Consent for the App Registration to have the chosen Application Permission.
Now in Azure APIM, go to your API and edit the inbound policy.
Validate the JWT from the user making the call (See validate-jwt or newer validate-azure-ad-token) to ensure the User is authorized to call this API.
Extract the oid claim from the JWT (this is the user ID I'll use for the graph call) and save it in a variable using set-variable policy
Add a send-request policy request an auth token for MS Graph using client-credentials flow (this is when you'll need the client id and secret from earlier App registration). Note: secrets should be stored in a secure store like KeyVault but that is outside the scope of this answer.
Extract the access_token field from the JSON response body and put it in a variable using set-variable policy.
Create another send-request policy, but this time to the MS Graph endpoint. For User.Read.All permission you'd use /users/<userIdFromJwtOidClaim>/memberof/<groupId>. MS Graph v1.0 API Reference, and pass the access_token in the Authorization header using <set-header> element.
A status code of 200 indicates the user is a member of the group. IIRC A status code of 403 indicates the user isn't a member of the group.
Use a choose policy to perform logic depending on the user's group membership.
Use return-response policy to send a response back to the user.
I have an existing signup/login system: a user enters an email and password. The password is hashed. I store it in a database.
When a user logs in, they entire their email and password. The password is hashed, and I look up the email in the database and check that the email matches. If it does, they are logged in.
I want to add a system to let users login with a 3rd party OAuth, such as GitHub. I have that setup, but I am unsure what data to store in my database.
I was thinking I take their GitHub email as the email and then use the access token for their GitHub as the password (so I would hash it and store it.)
I think this would work, but I am worried that the access tokens could change meaning they would be locked out of their account.
If I shouldn't be using the access token as a password, what should I be using? I need to store the user's email on my database but that requires a password currently, which I can't get if they use GitHub login.
(Note that when the user logs in, I call my backend to generate an access token (JWT) which I can use to require their user details and then store it in local storage. I'd like to then be able to do the same thing with with GitHub or whatever.)
oAuth is usually for authorization. Meaning, you get an access token from the authorization server, the resource server validates it and let the user access to the data.
In your case, you "do not really need" the access token - you want to use oAuth just for the authentication. Web-applications (like StackOverflow) do this to "save the trouble" of handling the authentication flows. Meaning, if I write a secured application, I need to implement somehow the create account flow, login flow, forgot password, etc. When you use a 3rd-party authentication, you save this trouble.
However, your application does need some user-id to perform actions; so you must create a user-id in you app when a user appears for the first time. Since then, you do not need to worry about password-expiry, forgotten-password and even not for the login. When the user logs-in, you get the access token and all you need to do is to get yours app' user-id from it.
Thus, I do not see a reason why you need to store a 'password', or the access token.
Hope that makes sense.
What you are looking for is actually OpenID Connect - it's an authentication framework built on top of OAuth, which lets you log in users using external Identity Providers, like Github.
When a user logs in using GitHub then you will receive an id_token in a form of a signed JWT. You can easily verify the authenticity of the JWT - so you can easily make sure that the id token really comes from Github and presents real data. Usually one of the information in the id token will be the user's email. You can use that to look up the user in your database. You don't need any password in this case.
So, you will have two ways of finding a user in your DB - either through comparing the email and password, or by looking up the user's email from a validated id token from Github.
I am integrating the security aspect of webapplication. I have decided to use OAuth,
so we have a REST WebApi in AspNet Core 3.0, the client which is a SPA created in React, and the Identity Server 4.0 app which is also in AspNet Core 3.0.
I read that OAuth is created for Authorization and not for Authentication.
For Authentication, seems that exists something else called OpenIDConnect, so the first question that comes to my mind, and on which I cannot find an easy answer is: are OAuth, OpenIDConnect and IdentityServer related technology?
Which is the best solution for authentication, considering that I would like to create users in a SqlServer Database, and if it's possible I would like to use Entity Framework for the porpose?
The flow for my authentication would be:
User writes Username and Password, if they are right he receive the JWT Token, without redirecting him/her to the authorization page.
At this point the problem are:
which is the right endpoint to do this flow:
is it the /authorize or the /token endpoint?
I have a lot of confusion for the questions above.
The second thing, what is the best way to retrieve the user informations?
For example if my endpoint needs to understand from the logged in user what are his data, I think that or I retrieve from the endpoint or from the JWT token.
Even here I have no clue on which is the best.
I read that OAuth is created for Authorization and not for Authentication. For Authentication, seems that exists something else called OpenIDConnect, so the first question that comes to my mind, and on which I cannot find an easy answer is: are OAuth, OpenIDConnect and IdentityServer related technology?
That's right. OAuth was the first one introduced and allows the person requesting it access to the resources (its handing out access tokens). OIDC (OpenID Connect) on the other-side extends this concept by an identity, the authentication part.
The identity token verifies the identity of the person to your application. Instead of providing identity via username + password (i.e. user creating an account on your website), they get redirected to your authentication provider/app and enter their login there and you get an identity token in return (and/or an access token, depending on the flow and scopes you request).
The identity token is an JWT token (or reference token). The JWT token contains all of the users identity information required for your application (user id, email, displayname, age, etc.) and is cryptographically signed. Only the Identity Server knows the key used to sign it up and you can verify it with the public key from the OIDC (IdSrv here) provider.
Reference token works similar, but claims are requested on the server side and cached.
With identity token you can not access the users resources. Example: Facebook.
When you sign in your application with an facebook account, most page will only request identity token to verify that its the same user (instead of using a username / password combination). But with that one, the application can't access your facebook posts or do posts in your name.
If the application requests an access token (token scope), then also an access token will be returned (if the application is allowed to via allowed scopes). You will be asked to grant the permissions to the resources which the application requests.
With that token, the application can read your posts or post in your name.
Which is the best solution for authentication, considering that I would like to create users in a SqlServer Database, and if it's possible I would like to use Entity Framework for the porpose?
Doesn't really matter. Either one can be used, all you really need is the "sid" (subject id) claim and associate that one with your user.
Identity Server can issue both, depending on what the client asks (if client asks for id_token response type, it will receive an identity token, if it asks for token an access token. Both can be specified or just one).
At this point the problem are: which is the right endpoint to do this flow: is it the /authorize or the /token endpoint? I have a lot of confusion for the questions above.
/authorize is used to authorize the user (have him login, and send back to your website). Its used for so called interactive flows, where the user enters credentials
/token endpoint you can only retrieve a token (resource owner flow (username + password), client credentials (for machine to machine authentication), refresh token (to get a new access token by using an refresh token (if you asked for offline_access scope, which gives and refresh token)
The second thing, what is the best way to retrieve the user informations?
the /userinfo endpoint, see docs: http://docs.identityserver.io/en/latest/endpoints/userinfo.html
As the doc says to access that, the client needs to request the openid scope.
For example if my endpoint needs to understand from the logged in user what are his data, I think that or I retrieve from the endpoint or from the JWT token.
Yes you can retrieve it from JWT token, if you use JWT token. If you use reference token, its just an ID.
And last but not least the /introspection endpoint can be used to validate the token (if your consuming application has no libraries to decrypt and validate signature of the token.
If you can, its best to use the Identity Server client libraries (i.e. IdentityServer4.AccessTokenValidation package for ASP.NET Core or oidc-client for npm/javascript based applications) which should be picking up the correct endpoints, so you don't have to worry about it
I have a requirement where Customer care people login with their credentials and have to impersonate the actual users.
You can implement service account flow for same. Using it you can get token of respective client with all allowed scopes to client (This client has all the scope required to access customer care resource).
I'm using Identityserver4 and ASPIdentity for user management. I want users dont have access to all applications(clients). I'm going to add table like UserClients, which specifies allowed applications for user. I'm interested in your advice, whether it is possible and does not conflict with the principles of SSO?
IdentityServer takes care of client access configuration and user authentication, but not of authorization at client/user level.
Users are not bound to a client. Thus, as you've noticed, all users have access to a client. IdentityServer authenticates the user, regardless which client is used or whether the user logs in at IdentityServer directly.
So it is the client (and also api) that has to authorize the user.
It doesn't matter if the user is already authenticated (SSO) or not. It is the responsibility of the client / api to determine whether the user is authorized. In order to solve this 'problem' they've build the PolicyServer, to decouple authentication and authorization.
By adding middleware (as done in PolicyServer) you can grant or deny a user access.
You can add some discriminator in IdentityServer, e.g. a specific claim type / role, use a seperate authorization server or use resource based authorization, e.g. when a (business) user is present then the user has access.
In the end, authorization is done by the resource that needs to be protected, because only the resource can interpret the claims and business rules.
All you have to do is short-circuit the pipeline in case the authenticated user has no access.
It's perfectly fine if you want to 'disable' SSO. Simply ignore the IdentityServer cookie (in the client), thus forcing the user to login (for that client).
But you should not deny authentication (e.g. return invalid login) when the user has no access to the client / resource.
That's why there is http status 401 Unauthorized and 403 Forbidden. So you can notify the user that it is not authorized to use this client.
Regarding your setup, in your case you can also add claims to the UserClaims table (instead of creating an additional table) to configure the allowed apps, e.g. user A:
http://mycompany/appname = app1
http://mycompany/appname = app2
http://mycompany/appname = app3
Add the ClaimType to the IdentityClaims table and the ApiClaims table in order to make sure the claims make it to the access / identity token.
Add middleware in the client / resource or add business rules (policies) where you check the claimtype and required value. If not present then deny access. E.g. app1 should look for the required claim type http://mycompany/appname with the value 'app1'.