Thinktecture Identity Server claims - claims-based-identity

I'm using Thinktecture Identity Server V3 for authentication and having a problem getting the information from HttpContext.Current.User.
I'm using an API to handle calls but when I call HttpContext.Current.User the ID is not avilable only the claims set by Identity server.
Also when I make a call through signalR the hubs HttpContext.Current.User is null and I can't get the users ID or even look at the cliams.
I'm currently using a custom user service hooked into AspNetIdentity and overriding PostAuthenticateLocalAsync and trying to use the user manager to CreateIdentityAsync but this fails.
Is there any way to populate the default claims on login and retrieve the details on a signalr connection and Web API call?
Thanks

Did you end up solving this?
I'm still pretty new to Thinktecture Identity Server, but I'm going to take a stab at this.
There is an option IncludeAllClaimsForUser on the Scope which is set to false by default. Based on what I'm reading, this option will remove the filter when calling the GetProfileAsync() endpoint.
Here's some links on where I found this info:
http://identityserver.github.io/Documentation/docs/configuration/scopesAndClaims.html
https://github.com/IdentityServer/IdentityServer3/issues/621

No I had to park it until I had time to figure it out.
I did use the IncludeAllClaimsForUser property on the scope which would populate the claims. The issue I had was that User.Identity.GetUserId() would always return null as this is now set within the claim "sub".
This was not such a big issue but when I passed through a bearer token on a signalR connection, Current.User is always null and I can't even read the "sub" claim.
Its like the bearer token is not being validated on a signalR connection so I can't get the users details.
Thanks for the help, its much appreciated.

Related

Get "groups" claims from Okta using the OpenID Connect Authorization Code Flow

I'm trying to include "groups" claims in what is returned by Okta after a user authenticates. It returns them when the response_type is 'id_token' but not when response_type is 'code'. For the Authorization Code flow I would expect to get the groups claims from the userinfo endpoint but they're not there.
However I've read that the authorization code flow is more secure than the hybrid flow (id_token) so I'd like to ensure there is not a way to do this?
My webapp is built on ASPNET Core 3 and I've tried the Okta.AspNetCore Nuget package.
One thing that might trip you up is that Okta do return the tokens you ask for, but the OpenIDConnect handler in your client blocks them.
You need to explicitly map those extra claims in your client, using code like:
options.ClaimActions.MapUniqueJsonKey("website", "website");
options.ClaimActions.MapUniqueJsonKey("gender", "gender");
options.ClaimActions.MapUniqueJsonKey("birthdate", "birthdate");
There is also this option you can set:
options.GetClaimsFromUserInfoEndpoint = true;
Do verify using tools like Fiddler the the claims actually is returned or not.
And yes, authorization code flow is what you should aim to use.
/userinfo response should contain all claims (for all flows including authorization code flow) including 'groups' as long as the groups scope is sent in the requests to mint the token.
Could you make sure the user is part of this group and the right scope is passed in the request ?
You can easily add 'groups' claim in access token as well. You can refer to the guide below:
https://developer.okta.com/docs/guides/customize-tokens-groups-claim/overview/

Is there a way to know which aad to use for authenticating in advance?

I have a UWP app that needs to authenticate, and I would like to avoid asking the user to choose which national cloud to authenticate with. I could just try them all, but I hope there is a better way to tell which Azure Active Directory the user belongs to (.us or .com)
Native apps can discover the Azure AD endpoint for a national cloud by passing an instance_aware parameter in the authorization request to the global Azure AD endpoint. This is done in the acquireToken call, where you need to pass in instance_aware = true as an extra query parameter when initializing the Authentication context.
From the Authentication result, you can read and store the cloud_instance_host_name attribute to learn the correct Azure AD endpoint. You must pass this value as the authority to re-initialize the Authentication context for the subsequent acquireTokenSilent calls to succeed.
An example ADAL.Net code snippet is below:
var authenticationContext= new AuthenticationContext(Authority, false, new TokenCache());
var authenticationResult = await authenticationContext.AcquireTokenAsync(resource,
clientId,
redirectUri,
platformParameters,
userIdentifier,
"instance_aware=true"
);
Also, here are example OAuth request and responses using the instance_aware parameter:
Request:
https://login.microsoftonline.com/common/oauth2/authorize?
response_type=code&
client_id=f5d01c1c-abe6-4207-ae2d-5bc9af251724&
instance_aware=true&
redirect_uri=http://localhost/appcheck&
resource=00000002-0000-0000-c000-000000000000
Response:
http://localhost/appcheck?
code=AQABAAIAAQDnLpu3ikefR73l_aNlxt5x0ulCIcjaTlOoWp412SJ2Oxlih65_h_Ju3OdOqpEy-mz0giFzZtU2_MbIgSG12e6RjwxpcaXaVPene_lMtmR2DPexUZZ3QhFRl8Vgl76SidX_nJ1CN-hJAejCi139FG_YZit4ePbiNySC3zR9GcP3B3St7HDsdEhMh1Vi1XHSSKfpgVqzLnOiBSO_jXrm1WJVqXSlt4_M_KO92Gdpbpy8H7zpsRg0O6blbuSw_83YUcj0w1gEfByHZP2Hk5AToDy_DWepPqJ0GWOJYeKcfIiEFleNYaeyEJDDuMyFhV16IOT28mq1oNOWL0dnhjwr-OV0JnyajQCT_LZzapxp7Y-8jSPDgW6SR878sgrq6CS2z3Zos8_T31n4DucQaPqv2Ae_jxlGHHSENBFy2RhHy397B7BBohXGqhDj_OdIroimDOJGVewn612gQOA6-9p0llv-PNd7vj9VZL-9Q8kEuYuhTqaBsH3yKm6y9FfgxMWovVkYtDt4YgxbqCV2Wb_lzImtyTHKxazn6YhH6R2pCvFdVSAA&
cloud_instance_name=microsoftonline.us&
cloud_instance_host_name=login.microsoftonline.us&
cloud_graph_host_name=graph.windows.net&
msgraph_host=graph.microsoft.com&
session_state=899b8a55-034f-4dcd-8b4b-888b7874b041
One way to "spot check" which cloud/AAD environment the user belongs to is by making a call to the Azure AD OpenID Connect discovery endpoint:
https://login.microsoftonline.com/place_tenantname_or_tenantid_here/.well-known/openid-configuration
For Azure Government, "USG" or "USGov" as the value in the tenant_region_scope field will indicate tenants that should be using login.microsoftonline.us.
I hope this helps. Let me know if not.
Bernie

Look up the user with bearer token with Openiddict Core

I am currently using Openiddict, Identity and Entity Framework to manage my users and assign Bearer tokens to users to protect my API.
My infrastructure is currently using ASP.NET Core Web API in the back end and a separate React application in the front end. The React application makes HTTP calls to my API to retrieve it's data. There is no server side HTML rendering at all in the back end.
Everything works as I need it to for the most part. I can register users and retrieve tokens from the API. These tokens are included in my HTTP call in the Authorization header. My AuthorizationController uses this: https://github.com/openiddict/openiddict-samples/blob/dev/samples/PasswordFlow/AuthorizationServer/Controllers/AuthorizationController.cs with a few minor tweaks. My Startup.cs also uses almost exactly this https://github.com/openiddict/openiddict-samples/blob/dev/samples/PasswordFlow/AuthorizationServer/Startup.cs
In some instances, I need to make API calls to the endpoints that are specific to the user. For instance, if I need to know if a user has voted on a comment or not. Instead of passing along the users ID in a query string to get the user details, I would like to use the Bearer token I received that they use to make the API call for that endpoint. I am not sure how to do this though.
In some research I have done it looks like some samples use ASP.NET Core MVC as opposed to the API to retrieve the user with the User variable as seen here https://github.com/openiddict/openiddict-samples/blob/dev/samples/PasswordFlow/AuthorizationServer/Controllers/ResourceController.cs#L20-L31 however this seems not to apply to my infrastructure.
My question is how do I look up a user based on the Bearer token passed to the API to look up a users details from my database? I am assuming that all of the tokens passed out by the API are assigned to that specific user, right? If that's the case it should be easy to look them up based on the Bearer token.
The question is: How with Openiddict can you look up a user based on the token that was assigned to them for API calls? I need to get the user details before anything else can be done with the application first. Is there something baked internally or do I have to write my own support for this?
When you create an AuthenticationTicket in your authorization controller (which is later used by OpenIddict to generate an access token), you have to add a sub claim that corresponds to the subject/entity represented by the access token.
Assuming you use the user identifier as the sub claim, you can easily extract it from your API endpoints using User.FindFirst(OpenIdConnectConstants.Claims.Subject)?.Value and use it to make your DB lookup.

Azure Mobile App refreshing tokens on server

Here's the background:
Need to authenticate with google/facebook/msa
Need to add our own claims to MobileServiceAuthenticationToken for use on client
Want to have refresh token capabilities (I know FB doesn't have that)
I have this working by LoginAsync and getting a MobileServiceAuthenticationToken back. Then I call a custom auth controller which has an [Authorize] attribute on it.
The custom auth controller copies some claims from the principal then adds our claims to those and creates a new token which it returns to the client.
Using the LoginAsync for all of this keeps the tokens flowing for all calls and that's great.
So, the token expires and I call RefreshUserAsync on the client. At this point the MobileServiceAuthenticationToken with our custom claims is replaced by the default one from the MobileAppService without our claims. I expect that.
So now I have to call the custom auth controller again to get our claims added back to the identity token.
This works, but it feels clumsy. And it's two round trips.
What I'm looking for is to refresh the identity provider access token on the server side, and in the same method, update the identity token with our stuff.
I'm aware of the /.auth/refresh call from the client side as an alternative to RefreshUserAsync. Is there a similar call I can make from my controller in the backend without setting up the whole System.Net.Http.HttpClient thing?
For example: I use this.User.GetAppServiceIdentityAsync<GoogleCredentials>( this.Request ) in the backend to get identity provider information without making HTTP calls.
Something like that?
Thanks in advance.
Short version - no.
Longer version - you need to call the /.auth/refresh on the backend on behalf of the user, then add your claims. The /.auth endpoints are on a different service that your backend does not have access to except via Http.
The GetAppServiceIdentityAsync() method still does a HttpClient call, so you aren't saving yourself a round trip.

Restricting Azure Identity Providers

I have set up authentication for my application using the Azure Rest API / OAuth 2 flow, following the steps outlined here:
https://ahmetalpbalkan.com/blog/azure-rest-api-with-oauth2/
I have created an ActiveDirectory application within Azure which is linked to an ActiveDirectory instance.
Inside my own application I have configured it to post to the following Azure OAuth endpoint:
https://login.windows.net/<<MY-AD-TENANT-ID>>/oauth2/authorize?client_id=<<GUID>>&response_type=code
This all works fine. I can authenticate against my ActiveDirectory using emails of the form
someuser#<myDomain>.com
However, I have realised that I can also authenticate using any valid microsoft email address, which obviously means that anyone with a valid microsoft email can get an access token for my application e.g.
randomUser#hotmail.com
Can anyone tell me how I can restrict the authentication to just allow users who are in my Active directory? Users with emails of the form
someuser#<myDomain>.com
I have looked through the documentation but have had no luck so far.
Mechanics of Token Validation
What does that really mean: to validate a token? It boils down to three things, really:
Verify that it is well-formed
Verify that it is coming from the intended authority
Verify that it is meant for the current application
Your problem is that you are not doing the number 3 validation.
You probably are missing something like this in your application where you are validating the token:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Audience = ConfigurationManager.AppSettings["ida:Audience"],
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
});
Currently I have the same problem and trying to figure out a solution.
That's what I found out:
After authentication you get back a JSON Web Token (see this page https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx). After decoding this, there are several information available. But I am not sure which of those could possibly make sure to only allow login of the specified Active Directory.
#Aram refers to the values audience (aud) and tenant (tid). Unfortunately audience is always set to the app_id given with the request and tenant is always set to the tenant-id of the Azure tenant, although you are using a live.com account, for example.
Finally, I came up with the idea of checking for the existence of oid (»Object identifier (ID) of the user object in Azure AD.«, https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx). I hope that this one will only be set if the user is part of the Active Directory that is issuing the authorization.
As a result, I set my app up to do the following: If in the decoded version of the id_token of the Access token response there is no oid property set – the login-request will be rejected.
Problem is: I can't confirm that my approach works, because I don't have a second Azure AD and can't check if only live/hotmail/... users will not be given a oid, but also users from different ADs. Maybe #bobbyr you could try that out and report?
Thanks to Thomas Ebert's prompt I've figured out a way to solve my problem. I don't know if it will help anyone else, but...
Basically when my app gets the token from Azure, before passing it on to the client, I can decode the JWT and just look at the email field.
In my case if the email address isn't one that belongs to my domain I can just send a 401 unauthorized back to the client.
It feels weird that Azure doesn't offer some way of doing this via config, maybe it does, but noone has answered this for me, and I've read enough of their docs now to want to pull my own eyes out so I never see the word Azure again...