Building a Web-API with Oauth2/OpenID connect - azure

I'm trying to understand conceptually and practically how to perform an oauth2 with openID-connect flow in my web-api application, utilising Azure AD.
Importantly, when a request is made to the API I want to know who made the request.
My current understanding is :-
My client would detect that the user isn't logged in and redirect to a sign-in.
The user would provide their credentials, and be redirected back to the client, along with an oauth2 token.
This token would be supplied to web-api endpoints for any requests.
This is where it gets murky for me.
How exactly do I use this token to authorize access to a particular resource, determine who is accessing the resource, and what is the mechanism that does so?
I'm sort of assuming that I would need to reuse the token to make a call to the Azure AD user endpoint - if the token was indeed valid, the AD endpoint would return the users details - thereby providing some means of determining that the token is valid and providing details on the users identity. Authorizing access to a resource could be done through membership of groups in Azure AD.
BUT ...
I can only assume this a solved problem, and have noticed use of OWIN middleware as per this example
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet
But I'm still rather unsure as to what is exactly going on.
The service makes mention of scopes and claims, but I don't understand where these are derived from (I assume from a token supplied by the client, but not sure). The service must be receiving identity information in the call.
Which brings me to two points, for this to be secure -
The token provided in call to the service would need to be secured in transmission (hence the use of HTTPS) - to prevent MITM.
The token would need to be signed some how - I guess by using client secret or something - to prevent information in the token being spoofed.
Can someone help me clear up this muddled mess?
In particular -
How is the identity of the API caller determined - is identity determined from a call in the client or the server?
How to limit access to some endpoints of the API based on a user role?
What do I do to practically achieve this by building on existing middleware and libraries available to me?

Disclaimer: This will not be a comprehensive answer. It is off the top of my head.
OpenID Connect provides an identity layer on top of OAuth. In your case, Active Directory provides the authentication and sends back an access_token. The access token represents a user that AD has authenticated. If your doing OpenID Connect, then AD will also send an id_token, which may contain additional identity information (such as birthday, avatar, and whatever else AD exposes.)
Neither OpenID Connect nor Active Directory have anything to do with the the roles that your app assigns to a user; roles are entirely the bailiwick of your app. You assign user roles just like you normally would; you assign them to the nameid though instead of to an email address or username. Your app no longer has to authenticate the user but it does need to assign roles to the nameid.
How is the identity of the API caller determined - is identity determined from a call in the client or the server?
The identity is embedded in the access_token that AD includes in its response. This token will have a nameid in it that your app can associate with a user and role. The nameid is like an email address, username, or other uniqueID that your app uses to recognize the user.
How to limit access to some endpoints of the API based on a user role?
You choose. When your app receives a request with a particular access_token, that token will be associated with a particular user via its nameid, and you can assign whatever roles and rights to that user. Basically, associate roles with a nameid.
What do I do to practically achieve this by building on existing middleware and libraries available to me?
There is an unfinished demo here, though it doesn't use Active Directory as the provider, instead, it uses an internal provider. For the demo, the username is shaun and password is Testing123!. The source code is here.
Here is the link to the source of another demo, though again, it doesn't use Active Directory as the provider, instead, it uses Twitter.
The nice thing about OAuth and OpenID Connect is that we can use whatever identity provider we want, so you can adapt the demos to use Active Directory.

Apart from question #1 (the identity is verified on the service side) all your question are very open ended and would require a super long answer.
I would recommend reading https://azure.microsoft.com/en-us/documentation/articles/active-directory-authentication-scenarios/ - it is a good introduction to the flows underlying many of the modern authentication cenarios, including the web API one you are focusing on.
Once you have read that, you will find a complete set of samples in https://azure.microsoft.com/en-us/documentation/articles/active-directory-code-samples/ - in particular, I suggest studying the web API and thru authorization one to find guidance on the 3 questions you listed. HTH!

Related

Azure AD | Service to service auth setup

I'm trying to use Azure AD to lock down access to authenticated users. I'm hoping someone could direct me to a setup that might fit the need here (and I feel like I must be overlooking the solution...).
We have an application that will expose various endpoints to be called by other teams in the organization. Nearly all of the consumers will be other user-less applications. (also none of these are Azure hosted/deployed services)
For auditing purposes, one of the requirements is the need to know what user (service) is calling any given endpoint.
Essentially, in the following:
We would need to be able to have Consumer 1 call My API, Consumer 2 call My API , and be able to determine inside of My API who the current consumer is.
I know with the client credentials flow, we could create multiple secrets and provide one to each consumer. However from the generated token, it appears that these are essentially both tokens on behalf of the Service Principal (so no way to know who the call is coming from).
I'd also looked into the ROPC flow, but I think am running into issue since we are using ADFS with our on prem AD servers.
Any easy button I'm overlooking? (fingerscrossed)
Please allow me to share my humble opinions here.
Firstly, access token is used for calling api which contains the information that if the token has correct scoped for the target api. And Id token contains the user informaion.
So if the Consumer1 and Consumer2 are on behalf of application itself, then it can't add user information within the access token and there's no id token for it. In this scenario, I think what you can do is adding an identifier into the request along with the access token, then your api application can both check if the token is illegal and which Consumer sends this request. This scenario used client credential flow to generate access token.
If the Consumer1 and Consumer2 are on behalf of users, or they are application but the request calling your api application can get the current user information, then you may send id token along with access token, or just send the user id as an identifier. This scenario may need users to sign in, so maybe auth code flow is better then credential flow.

Is it possible to utilise Open ID Connect flows for authentication but then have another source of authorization rules?

My situation is this. I have a legacy Angular application which calls a Node API server. This Node server currently exposes a /login endpoint to which I pass a user/pwd from my Angular SPA. The Node server queries a local Active Directory instance (not ADFS) and if the user authenticates, it uses roles and privileges stored on the application database (not AD) to build a jwt containing this user's claims. The Angular application (there are actually 2) can then use the token contents to suppress menu options/views based on a user's permissions. On calling the API the right to use that endpoint is also evaluated against the passed in token.
We are now looking at moving our source of authentication to an oAuth2.0 provider such that customers can use their own ADFS or other identity provider. They will however need to retain control of authorization rules within my application itself, as administrators do not typically have access to Active Directory to maintain user rights therein.
I can't seem to find an OIDC pattern/workflow that addresses this use case. I was wondering if I could invoke the /authorize endpoint from my clients, but then pass the returned code into my existing Node server to invoke the /token endpoint. If that call was successful within Node then I thought I could keep building my custom JWT as I am now using a mix of information from my oAuth2 token/userinfo and the application database. I'm happy for my existing mechanisms to take care of token refreshes and revoking.
I think I'm making things harder by wanting to know my specific application claims within my client applications so that I can hide menu options. If it were just a case of protecting the API when called I'm guessing I could just do a lookup of permissions by sub every time a protected API was called.
I'm spooked that I can't find any posts of anyone doing anything similar. Am I missing the point of OIDC(to which I am very new!).
Thanks in advance...
Good question, because pretty much all real world authorization is based on domain specific claims, and this is often not explained well. The following notes describe the main behaviors to aim for, regardless of your provider. The Curity articles on scopes and claims provide further background on designing your authorization.
CONFIDENTIAL TOKENS
UIs can read claims from ID tokens, but should not read access tokens. Also, tokens returned to UIs should not contain sensitive data such as names, emails. There are two ways to keep tokens confidential:
The ID token should be a JWT with only a subject claim
The access token should be a JWT with only a subject claim, or should be an opaque token that is introspected
GETTING DOMAIN SPECIFIC CLAIMS IN UIs
How does a UI get the domain specific data it needs? The logical answer here is to send the access token to an API and get back one or both of these types of information:
Identity information from the token
Domain specific data that the API looks up
GETTING DOMAIN SPECIFIC CLAIMS IN APIs
How does an API get the domain specific data it needs from a JWT containing only a UUID subject claim? There are two options here:
The Authorization Server (AS) reaches out to domain specific data at the time of token issuance, to include custom claims in access tokens. The AS then stores the JWT and returns an opaque access token to the UI.
The API looks up domain specific claims when an access token is first received, and forms a Claims Principal consisting of both identity data and domain specific data. See my Node.js API code for an example.
MAPPING IDENTITY DATA TO BUSINESS DATA
At Curity we have a recent article on this topic that may also be useful to you for your migration. This will help you to design tokens and plan end-to-end flows so that the correct claims are made available to your APIs and UIs.
EXTERNAL IDENTITY PROVIDERS
These do not affect the architecture at all. Your UIs always redirect to the AS using OIDC, and the AS manages connections to the IDPs. The tokens issued to your applications are fully determined by the AS, regardless of whether the IDP used SAML etc.
You'll only get authentication from your OAuth provider. You'll have to manage authorization yourself. You won't be able to rely on OIDC in the SAML response or userinfo unless you can hook into the authentication process to inject the values you need. (AWS has a pre-token-gen hook that you can add custom claims to your SAML response.)
If I understand your current process correctly, you'll have to move the data you get from /userinfo to your application's database and provide a way for admins to manage those permissions.
I'm not sure this answer gives you enough information to figure out how to accomplish what you want. If you could let us know what frameworks and infrastructure you use, we might be able to point you to some specific tools that can help.

Why do access tokens issued by AAD contain information about the user?

I read a lot about OAuth 2.0 and OpenId Connect and in theory I understand both concepts now.
But if I go into practice, some things are still confusing for me and I hope you can enlighten me in some way...
First thing is, that in all code samples how to secure a .net core API in an AAD-environment I find lines like this in the configure-section:
app.UseAuthentication()
and lines like this in the ConfigureServices section:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://login.microsoftonline.com/xxxxxxxx";
options.Audience = "xxxx-xxx-xxx-xxx-xxxx";
});
However, to access my API I am not using an ID token, but an access token what is Authorization, not "Authentication" like in the code samples.
This works - but I do not understand it 100%.
So my first question is:
Is the access token also "authenticating" in some way?
The second thing:
I read that access tokens have no standardized format. They can be JWT or not, can have an audience or not etc. For this reason you could even put user information in the token like microsoft does. The access tokens contain claims like a "family name" or "given name" etc.
Id tokens in contrast have a standardized format to ensure that authentication is done in the same way by everyone.
If people are accessing my apis with an access token, I can read their name or e-mail address with "user.identity.name" for example. This value I can use to store the information who edited something or who inserted something.
So I am fetching information about the user with access tokens!
So my second question is:
Am I doing the right thing here? Or should this be done in another way.
and:
Should access tokens ever contain information about the user?
Is the access token also "authenticating" in some way?
Yes.
Your API is validating the access token when it receives it.
This is the authentication part, when your API verifies that the token signature is valid, came from the Azure AD tenant that you trust, that it is meant for your API and that it has not expired.
The authorization is when you check what permissions the token contains.
Your API can define different permissions that are given to client applications, allowing them different levels of access.
A valid token can pass authentication, but it might not pass authorization if it lacks the necessary permissions.
Am I doing the right thing here? Or should this be done in another way.
Fundamentally your are doing the correct thing.
The token tells you who the user is that is using the client application, and if you need to know who it was who did something, that's the info you use.
However, if you really want to connect an action to a user, I suggest you use their object identifier / object id / oid instead of their name / username as those can change.
Unless you just want their display name.
Should access tokens ever contain information about the user?
In the context of Azure AD, an access token will always contain info about the user if a client application is accessing an API on behalf of a user.
This includes authentication flows like authorization code, device code, implicit, and on-behalf-of.
They all use delegated permissions aka scopes to call APIs on behalf of the user.
Thus the token contains info about the calling app and the user.
If an app acquires an access token using the client credentials flow where a user is not involved, there will be no user info in the token.
In this case, application permissions are used instead of delegated permissions in Azure AD.
An application acts as itself, not on behalf of any user.
If your API supports both of these scenarios, sometimes the tokens contain user info and sometimes not.
The part about token formats is basically correct from a specification standpoint.
OAuth doesn't define a strict format for access tokens, while OpenID Connect does define one for ID tokens.
Using an access token to call your API is definitely correct.
The ID token is only meant for the app that initiated the user authentication, not for any APIs that it calls.
That's what access tokens are for.
if you check here: https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens
in the newer access tokens, by default it follows the standard of not having any personal information about the user. which is what the standards suggest, Access tokens should not contain much or any information About the user. rather just information for authorization (things that user can access).
However you can always add the optional claims (and azure lets you do it) for personal info, but best practice suggests you shouldn't.
in terms of the addauthentication: Authentication is basically proving who you say you are. addauthentication(), basically calls microsoft azure ad to perform this task, saying hey aad please ask this person who he is, azure then checks and says ya this is a real person, but i won't tell you anything about him other than an id, and they have access to your api/application. So from your snippit, it's fine.
at this point, your serverside shouldn't have any personal information about the user, just that they have access and what scopes/roles. If it wants info about the user, it should then take that authorization (access token) and request it from whatever endpoint that token has access to (graph)
here's a great read about it: https://auth0.com/blog/why-should-use-accesstokens-to-secure-an-api/
Hopefully this helped clarify somewhat, and not add more confusion to the issue.

Azure Active Directory Token Validation

I'm integrating Azure Active Directory into a cloud platform. As our application is multi-tenant and relies on platform-specific claims, we've identified the simplest way to go about this is get an Azure AD token via our SPA, pass it back to our WebApi, validate it and return to the SPA a platform token with all the claims we need to go about our normal business (as if it was a simple username/password athentication request).
I'm concerned at the level of security for this though.
Some Context
As our platform is multi-tenant, we request that clients each register the application on their Azure AD portal, then supply us with the generated Application (client ID) and Directory (tenant) ID. We use these two pieces of information to make the initial request to Azure via our front-end SPA (following the node.js example provided by Microsoft's Quickstart guide when registering an app). Now because the user is unauthenticated at this point, we needed some way to return those two specific ids for the client. We have accomplished this using a sub-domain for identification.
E.g. acmeinc.mydomain.com will return a different Application (client ID) and Directory (tenant) ID than billy.mydomain.com. These are obviously public now as this request happens from an un-authenticated front-end route.
I can handle the token response just fine, both in the front-end and in the back-end when I pass it along, and validate that these two pieces of information are correct in the token, but seeing as the front-end is given them to begin with, validation on these is redundant. Also, validating the issuer seems equally redundant as someone who knows the Directory (tenant) ID, can fake that too (right?)
Am I missing something here? I would feel far more at ease if it were possible to request the client also include a claim that my platform generates privately such that I could validate this claim alongside the normal JWT validation. Custom claims do not seem possible from the Azure AD Portal.
Am I missing a critical step, or just overthinking this?
Someone cannot fake the issuer in the token because the token is digitally signed.
Without the private keys of Azure AD, it isn't feasible to generate a valid signature.
Without that, any modifications to the token will be immediately noticed because the signature does not match.
Your back-end should already be validating this signature if you are using standard JWT validation.
Requiring customers to register an app in their tenant is a bit of work that I would prefer not to put on them.
Have you considered making your app a multi-tenant app in Azure AD?
That way your customers could login to your app, consent to the permissions required, and start using it. Without needing to manually register anything.
This could be done in an on-boarding flow where the user signs in, and then they can decide what sub-domain they want.
You will at that point know their tenant id, which you can store. So in the future you can always use the correct tenant/directory id when signing them in.
The downside of this approach is managing the reply URLs.
With the specially registered apps, they can register their own sub-domain version as a reply URL.
With this generic multi-tenant app, you'll need to manage them.
And you can't add an infinite amount of them, and wildcards aren't supported anymore either.
So, your authentication would have to happen with a generic authentication reply URL like auth.mydomain.com, from which they would be redirected to their tenant URL.

OAuth authentication client side security issues

I understand the security issues around attempting to use OAuth for authentication from a provider's point of view. However I've been asked to provide users the facility to log on to a new web application using OAuth and obtain their basic identity info from the likes of Google and Twitter, from which a new user account within the client application will be created. Additionally users will be able to regster/login directly via user/passwords for anyone not wishing to use third party accounts.
We do not require any access to the user's details/info or providers APIs, just their basic identity when they first logon, and of course allow them to login via the provider in the future. Not exactly the use case OAuth is intended for, OpenId would have been preferred, but OAuth has been specified and without valid concerns would need to be adhered to.
My question is how safe is it to assume that the user has correctly authenticated themselves with the relevant provider. If I trust say Google to perform adequate authentication and I obtain an access token and their identity, presumably I can consider that a legitimate user? There are obviously issues if some one has access to the resource owners machine and saved passwords in the browser but that issue is present for those users who elect to register directly.
Presumably it possible to fake an access token, e.g. man in the middle pretending to be google? A MITM could fake an access token and supply identity details that matched a registered user's google id? I don't see anything for a client to know that the information definitely came from the provider. Obviously this problem is not unique to OAuth.
Are there another ways someone could illegitimately access an account that used OAuth to authenticate themselves.
OAuth allows that an application to access a specific user resource (that has been provided permission by the user) and it cannot go outside that scope. I have not seen the documentation that refers to creating a new user using OAuth based application.
That being said:
We do not require any access to the user's details/info or providers
APIs, just their basic identity when they first logon
This violates OAuth authorization process. The Service Provider does the authentication and provides the relevant tokens (based on the success of the authentication). This is to ensure that there are no 3rd party authentication done during the OAuth authentication process.
My question is how safe is it to assume that the user has correctly
authenticated themselves with the relevant provider.
This all depends on the service provider itself. To conform to OAuth protocol, one of the requirement is that user authentication must be done in a secured transport layer with a digital certificate (for HTTP, it must be done in HTTPS). OAuth consumer don't have any reference to the authentication process. Also the authentication process basically asks the user if the consumer can access the resource of the specific user (and not anyone else, since he doesn't have authorization to it).
Is it possible to fake an access token, e.g. man in the middle
pretending to be google?
Spoofing a Service Provider IS possible but it'll be tedious. For one, you will have to create a whole OAuth handshake process, create the exact API as the service provider, also setup an environment that is secured (as OAuth recommends). The only thing the spoofing service provider can obtain is the client credentials. If it has its user credentials, there is no need to use the application as there is no way of providing a user credentials using an application to do malicious damage.
Secondly, access tokens do expire so even if you spoof and retrieve an access token, the original application owner can ask for the service provider to block the application and the access token can be useless.
A man in the middle attack won't be possible. You will have to replicate the service provider in a sense that the end user won't be able to distinguish between the original and the spoofing service provider in order to capture all relevant credentials (from both the application and end user).
Sadly saying, the scenario from your last sentence is the truth.
But you should realise that the security is a huge and complex issue, especially in client side. It's not happen just in a single point but many points through the whole internet access life cycle. The scenario you given is not what OAuth try to solve.

Resources