Kentor Identify Identity Provider After Acs ReturnUrl - kentor-authservices

I Have multiple identity providers defined to work with my AuthServices,
Each of them send a SamlResponse to my AssertionService as is supposed to then redirect to my RedirectUrl like "ExternalLoginCallback" that is defined in Sustainsys.Saml2.StubIdp example.
I have no way to know witch of Identity provider returned the externalIdentity,
I have to check that the current user belongs this idp.
I hope I don't have to force them to send a special claim with there Idp Id or something like that.
Does it exist a way to pass the entityId between Acs to my callback action ?
thanks

Ok I found the answer...
I extract idp id from Claim Issuer like this :
var externalIdentity = context.Authentication.GetExternalIdentity(ExternalCookie.Name);
var idp = externalIdentity.FindFirst(AuthServicesClaimTypes.LogoutNameIdentifier)?.Issuer;

Related

SID from ZUMO Login (MobileServiceUser) differs from the users' ObjectId

I am working on a Xamarin.Forms based crossplatform app targetting iOS and Android. My backend is an ASP.NET Webapplication hosted as an Azure App Service and users can register accounts that I manage with Azure Active Directory B2C. For authentication, I use MSAL 4.0 and the client application communicates with the backend using the MobileServiceClient library.
Because the users' data has relationships, I chose to let the controllers' put methods add the users' SIDs automatically and filter requested data on that SID, because this identifier is available after authorization though the users IClaimsPrincipal anyway.
However, I don't understand the origins of these SIDs because I cannot find them anywhere else.
This is what I can tell so far:
Within Azure ADB2C, I have two registered users. One of them (UserA) came in using Facebook as IdentityProvider, the other (UserB) Microsoft.
UserA has the Object Id FFC1*** on ADB2C.
UserB has the Object Id E990*** on ADB2C.
Both have the same name, but different registered email addresses.
This is how I instantiate the MSAL client:
public static IPublicClientApplication PCA = null;
...
PCA = PublicClientApplicationBuilder.Create(ClientID)
.WithRedirectUri($"msal{ClientID}://auth")
.WithB2CAuthority(Authority)
.WithIosKeychainSecurityGroup("com.microsoft.msalrocks")
.Build();
ClientId refers to Azure Active Directory B2C > Applications > Application > Application Id
Authority resolves to something like https://application.b2clogin.com/tfp/application.onmicrosoft.com/B2C_1_SignInSignUp
The policy configuration (user flow) on B2C is configured to include the following claims:
Given Name
Identity Provider
User's Object Id
I log in using MSAL this way:
var accounts = await App.PCA.GetAccountsAsync();
var result = await App.PCA.AcquireTokenSilent(
App.Scopes,
accounts.FirstOrDefault())
.WithB2CAuthority(App.Authority)
.ExecuteAsync();
App.Scopes resolves to
public static string[] Scopes = {
"https://application.onmicrosoft.com/api/user_impersonation",
"https://application.onmicrosoft.com/api/offline_access"};
At this point, I have an AuthenticationResult which I could extract valuable information from such as the users' given name or the Object Id which equals the Object Id I can also see in the user management pane in my Azure B2C directory:
JObject authenticatedUser = AuthenticationHelper.ParseIdToken(result.IdToken);
var objectId = authenticatedUser["sub"]?.ToString();
var username = authenticatedUser["given_name"]?.ToString();
The AuthenticationResult contains an IdToken and an AccessToken. They are almost identical with the AccessToken adding an scp attribute containing scopes. In my case it contains "user_impersonation".
Now with the user being authenticated against ADB2C, I need my app to also forward the authentication to ZUMO, that is, the MobileServiceClient, so that the user can make authorized calls against my backends' controllers.
For this, I need the resturned AccessToken (which I can also extract from the above AuthenticationResult), wrap it into a JObject and finally transmit it to the MobileServiceClient like this:
MobileServiceClient client;
client = new MobileServiceClient("https://application.azurewebsites.net");
var zumoPayload = new JObject()
{
["access_token"] = result.AccessToken
};
await client.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, zumoPayload);
Now that the MobileServiceClient has an authenticated user, every future httprequest will contain respective information that the controllers' [authorize] attribute satisfy.
HOWEVER.
This is when it becomes strange.
When the MobileServiceClient is instantiated and its LoginAsync method called using the ZumoPayload from above, the resulting MobileServiceUser is being populated with two properties:
MobileServiceAuthenticationToken and
UserId
The funny thing is, that this token looks very different from the IdToken or AccessToken I received when authenticating with MSAL, but what bugs me even more is that the User Id is even something totally different!
There is a sub attribute included containing something like sid:956b*** for UserA and sid:e358*** for UserB which clearly differ from the above Object Ids.
Can anyone explain to me where these SIDs come from?

C#/OWIN/ASP.NET: can I *manually* generate and get a valid bearer token string in my API code?

I am using the OWIN OAuthAuthorizationServer library in an OWIN ASP.NET C# web API to generate and process bearer tokens.
Right now, I have a single endpoint (which you set in the OAuthAuthorizationServerOptions struct) that accepts the grant_type, username and password fields from the frontend. I created a provider class that performs the validation, and then calls context.Validated() or context.SetError() accordingly. The middleware then handles generating the token and returning it to the user, and also "takes over" the login endpoint, doing all the work internally.
Now, I am adding a new feature to my API where the user can change their "role" (e.g. an admin can set themselves as a regular user to view the results of their work, a user can select among multiple roles, etc.) Since I already handle this through the bearer token (I store the user's role there and all my endpoints use the bearer token to determine the current role), I now have a reason to update the contents of the bearer token from the API backend.
What I'm looking to do is to allow the frontend to call an endpoint (e.g. api/set_role) that will accept a parameter. The user requests a certain role, and their current bearer token would accompany the request. The server then would check if the user in question is allowed to use that specific role and, if so, would generate a new token and return it to the user in the response body. The frontend would then update its token in local storage. Or, of course, if the user is not permitted to switch to that role, the backend would return an appropriate error and the frontend would react accordingly.
To do this I basically want to be able to manually generate a token. Similar to how I use identity.AddClaim() in my login provider, I'd like to be able to do that at any arbitrary position within the API's code. The method would take responsibility for transferring over any necessary existing information (e.g. the user's username) into the new token, since it already has the existing one.
Pseudocode for what I want:
if (!userCanUseRole(requestedRoleId)) return Request.CreateErrorResponse(...);
// we have a struct containing parsed information for the current token in the variable cToken
bearerToken newToken = new bearerToken();
newToken.AddClaim(new Claim("user", cToken.user));
newToken.AddClaim(new Claim("role", requestedRoleId));
string tokenToReturnToFrontend = newToken.getTokenString(); // string suitable for using in Authorization Bearer header
return Request.CreateResponse(new StringContent(tokenToReturnToFrontend));
I am not too familiar with "refresh" tokens, but the only way I am using them right now is extending token expiration. To that end the frontend explicitly requests a refresh token and provides its own, which the backend simply copies to a new token and edits the expiry time. The problem with this is that there's a single method for getting a refresh token, and since I have now at least one other reason to refresh a token (and possibly, future developments could add even more reasons to change token contents at various times), I'd then have to deal with storing transient data somewhere (E.g. "when requesting a refresh token, what is the thing the user wanted to do? has it been too long since they requested to do that? etc.) It'd be much easier if I could simply generate a bearer token on demand in the same way that the OAuthAuthorizationServer itself does. (I know it uses the MachineKey to do this, but I don't know exactly how it does it, nor how I would go about doing what I'm trying to do.)
Of note: In another project I provided internal access to the OAuthBearerAuthenticationOptions class that is passed to the authorization server instance, and was able to use that to decode a bearer token inside of a test. I haven't seen anything obvious thought that would let me encode a bearer token this way.
EDIT: I explored the (extremely tersely, almost uselessly documented) OWIN namespace and found the AccessTokenFormat class which appears that it should do what I want. I wrote this code:
Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(new ClaimsIdentity
{
Label="claims"
}
, new Microsoft.Owin.Security.AuthenticationProperties
{
AllowRefresh=true,
IsPersistent=true,
IssuedUtc=DateTime.UtcNow,
ExpiresUtc=DateTime.UtcNow.AddMinutes(5),
});
at.Identity.AddClaim(new Claim("hello", "world"));
string token = Startup.oabao.AccessTokenFormat.Protect(at);
return Request.CreateResponse(HttpStatusCode.OK, new StringContent(token, System.Text.Encoding.ASCII, "text/plain"));
which seems like it should work. (I again allow access to the OAuthBearerAuthenticationOptions class passed to the OAuthAuthorizationServer instance.) However, this code throws an ArgumentNull exception. The stacktrace indicates that it is writing to a BinaryWriter but the OWIN code is passing a null value to the Write method on the BinaryWriter.
Still have no solution.
I did figure out the code to make this work. One could argue I'm "not using OAuth right", but strictly, this code WILL accomplish what I want - to generate a token in code at any arbitrary point and get the string.
First, as I said, I have to provide access to the OAuthBearerAuthenticationOptions class instance. When the OAuth server initializes I'm guessing it populates this class with all of the various objects used for tokens. The key is that we do have access to Protect and Unprotect which can both encode and decode bearer tokens directly.
This code will generate a token assuming that oabao is the OAuthBearerAuthenticationOptions class that has been passed to the OAuthAuthorizationServer instance:
Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(new ClaimsIdentity("Bearer", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"),
new Microsoft.Owin.Security.AuthenticationProperties
{
AllowRefresh = true,
IsPersistent = true,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddDays(1) // whenever you want your new token's expiration to happen
});
// add any claims you want here like this:
at.Identity.AddClaim(new Claim("userRole", role));
// and so on
string token = oabao.AccessTokenFormat.Protect(at);
// You now have the token string in the token variable.

Authorization by Role/Group in ASP.NET using Auth0

Thanks in advance for your help in this matter!
I was hoping someone could help me figure out how to authorize API access by Group assigned in the Auth0 Authorization extension.
I currently am using the [Authorize] attribute in the web api perfectly - it allows an api call if they have signed in successfully and blocks it if not.
However, if I try [Authorize(Roles = "myGroupName")] authorization fails. Same occurs if I add it to the users app_metadata manually in the Users dashboard on the Auth0 website instead of assigning through the extension.
My project is set up by following the Angular Quick Start and Asp.Net Quick Start. My webapiconfig where I validate the token server side is:
class WebApiConfig
{
public static void Register(HttpConfiguration configuration)
{
var clientID = WebConfigurationManager.AppSettings["auth0:ClientId"];
var clientSecret = WebConfigurationManager.AppSettings["auth0:ClientSecret"];
configuration.MessageHandlers.Add(new JsonWebTokenValidationHandler()
{
Audience = clientID,
SymmetricKey = clientSecret
});
configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
}
}
The Auth0 Authorization extension currently supports authorization decisions through the concept of groups. You can create a group, assign users to that group and that configure an application to only be accessible to user within a specific group. All of this would be handled automatically and any user outside of the application expected groups would be denied complete access.
Your use case is a bit different, but valid nonetheless. You want the groups configured with the extension to be sent along the generated token so that the application itself makes authorization decisions based on those values.
In order for the groups configured within the extension to be sent along in the token, the first thing you need to do is request them. For this, you need to include the groups scope when performing the authentication requests.
Add the user's group membership to the outgoing token (which can be requested via the OpenID groups scope);
(emphasis is mine, source: Authorization Extension Docs, section Rule Behavior)
If you request a token using that scope and then decode it in jwt.io, you would get something similar to this (the actual groups would vary by user):
{
"groups": [
"GROUP-1",
"GROUP-2"
],
"iss": "https://[tenant].auth0.com/"
}
Now, for the validation of this information on the ASP .NET API side. Assuming the sample you're using is this one (ASP.NET Web API), the group information contained within the token would be mapped to the following claims:
Type: groups | Value: GROUP-1
Type: groups | Value: GROUP-2
This happens because of the logic that exists in the JsonWebToken class which handles arrays coming from the JWT payload by creating per-value claim that share the same type.
The final part is making sure the AuthorizeAttribute checks these claims of type groups instead of trying to lookup role claims. You should be able to accomplish this, by changing the RoleClaimType constant in the JsonWebToken class to have the value "groups" instead of "http://schemas.microsoft.com/ws/2008/06/identity/claims/role".
Like you certrainly know, the Authorize attribute works using what is in the principal: something that inherits IPrincipal.
In web api, it is even more specific; it is something that inherits ClaimsPrincipal (this implements himself IPrincipal).
As you certainly know already, a claim is like a key-value pair.
The ClaimsPrincipal contains a serie of key-value pairs that are directly taken from the authentication token. This authentication token is issued by the authentication server most of time as JWT (Json Web Token). Most of time as well, the authentication server is using OAuth, like is your case.
If the user group, that you expect to be the role in your application doesn't work by using the out-of-the-box Authorize attribute, it's because it is not mapped correctly: Auhtorize checks the claim with claim type: http://schemas.microsoft.com/ws/2008/06/identity/claims/role (the "claim type" is the "key" of the key-value pair). That means that if you want your Authorize to work, this claim must be valued with the group.
You can do several things to have a clean authorization in your application.
Make a custom Authorize attribute. This Authorize attribute would check the role using a different claim type. The claim type that refers to the user group depends on your authentication server. If you don't find what claim type is used for groups in the doc of your authentication server, run your application in debug, and check every claim that is contained in the property User of your controller. You will certainly find what the claim type you are interested in.
Change the setup of your authorization server by redefining the mapping between user information and claims of the token that is produced (in your case, map groups of the user to the claim that has the type http://schemas.microsoft.com/ws/2008/06/identity/claims/role). Generally, this can be setup per client application or even globally. For example this is the way that must be done if you use an ADFS authentication, AzureAD or WSO2 authentication server (http://wso2.com/products/identity-server/)
Add an owin middleware to modify the current principal. It will change the current principal by copying the value of the claim that contains groups into the claim type http://schemas.microsoft.com/ws/2008/06/identity/claims/role. This middleware must be inserted in the flow after the authentication middleware
I have no rights to comment so I'm going to inquire from here. Why are you doing this
[Authorize(Roles = "myGroupName")]
as far as I remember when I was implementing group based authorization I was still typing
[Authorize(Roles = "myRoleName")]
Not other way around.

How to query ADFS repository for authentication in ASP.NET

I have an ASP.NET Web Forms application and ADFS correctly implemented.
I successfully use ADFS for SSO in many applications but now I need to use the ADFS repository just to validate login credentials on-premises, not for the login itself.
My application is a simple form with Textboxes for username and password and a Login button. Once the user inserts username and password and clicks on login I need to check with ADFS whether the data are correct, receive the response and based on that perform some other task.
In the SSO I already implemented it is the STS itself that displays the pop-up for login credentials but in this case I want this task to be fulfilled by my app.
Anybody might tell me if that is possible and point me to the right direction?
Are you sure you want to have your own login form in a web app? That doesn't sound fair, if the ADFS is further federated with other identity providers, your check could just miss that.
Having said that, if you really want this, you should enable a usernamemixed endpoint endpoint in the ADFS configuration, configure your application as a relying party and request a token:
string stsEndpoint = "https://WIN-2013.win2008.marz.com/adfs/services/trust/13/usernamemixed";
string relyingPartyUri = "https://www.yourrelyingpartyuri.com";
WSTrustChannelFactory factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(stsEndpoint));
factory.TrustVersion = TrustVersion.WSTrust13;
// Username and Password here...
factory.Credentials.UserName.UserName = "remote_user01";
factory.Credentials.UserName.Password = "the_password";
RequestSecurityToken rst = new RequestSecurityToken
{
RequestType = Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(relyingPartyUri),
KeyType = Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13Constants.KeyTypes.Bearer,
};
IWSTrustChannelContract channel = factory.CreateChannel();
SecurityToken token = channel.Issue(rst);
//if authentication is failed, exception will be thrown. Error is inside the innerexception.
//Console.WriteLine("Token Id: " + token.Id);
This particular snippet is copied from this blog entry:
http://leandrob.com/2012/04/requesting-a-token-from-adfs-2-0-using-ws-trust-with-username-and-password/

Is it possible to forward the current user's FormsAuthentication Identity to another Controller action?

I'd like to use ASP.NET MVC's views as mail template engine. For that, I am calling one controller action from another controller action using a System.ComponentModel.Component.WebClient, parse the returned web page and send it via e-mail.
In this scenario, is it possible to forward the current user's login credentials (I am using FormsAuthentication) to the controller action requested by the WebClient? User passwords are encrypted, so I can't just create a new NetworkCredentials instance with his user name and password.
Yes, you can just copy the .ASPXAUTH cookie from your current Request object to the WebClient
EDIT: I haven't actually tried this myself, so maybe the .ASPXAUTH cookie is removed from the Request object for security reasons.
But since you have access to the machine key, you can create your own cookies on the fly. Here's the code that should do it (I can't find the project where I actually did that)
var ticket = new FormsAuthenticationTicket(User.Identity.Name, true, 5);
string aspxAuthCookieValue = FormsAuthentication.Encrypt(ticket);
This code creates a forms authentication cookie for your current user name and with an expiration time of 5 minutes.
Instead of performing a http request, aren't you looking for something like "rendering a view to a string"

Resources