Identity Server 4 Custom Scheme - authentication

I'm currently working on setting up Identity Server 4 as a centralized authn point for multiple products as well as a federation gateway. It's all pretty standard:
I have users that can authenticate into an SPA that uses the OIDC-Client js lib to interact with my identity server using the implicit flow. User stores are as follows:
a user store local to IDSRV (Asp.net identity). They'd enter their credentials into a form hosted in IDSRV, just as seen in the docs
an openid connect or oauth 2 store, either a social (google, linkedin, etc) integration or an IDP provided by one of our clients. Also working, just like in the docs.
a "destination key", described below
Destination key - the application in question has the ability to generate a unique link with a key (pretend it's a guid, for example purposes). This key maps to a specific destination in the app, and serves as a defacto authentication. It's a lot like the resource owner password flow, except that the key is the sole component needed to authenticate. (I'm aware that this isn't the utmost in security, but it's a business decision, taking into account the lower levels of protection).
Which brings me to my question: what is the proper "identity server" way of accomplishing this destination key authentication mechanism. Some things I've considered:
a custom authentication scheme configured in IDSRV. I added a generic scheme called "destkey", with accompanying AuthenticationHandler and AuthenticationSchemeOptions implementations. The HandleAuthenticateAsync method would use an injected service to validate the destination key. For some reason, it ignores this and continues to validate against Asp.Net identity
a custom grant type. I looked to create an implementation of IExtensionGrantValidator that would utilize the destination key service to validate the key. I haven't been able to get this working, at least in part because the OIDC lib doesn't allow the configuration of a grant type.
repurposing the "Login" method of the AccountController from the IDSRV Quickstart [HttpGet]
public async Task<IActionResult> Login(string returnUrl) This would basically strip the destination key off the URL and call HttpContext.SignInAsync using the dest key as the subject. This isn't working, as it seems to check the database for the existence of the subject (which is how I ended up attempting to create a custom scheme as described above)
Any thoughts on the proper extensibility point to accomplish this would be most welcome...

Not sure if this is the best approach, but I ended up creating a custom implementation of IProfileService. It wraps an instance of IdentityServer4.AspNetIdentity.ProfileService, and checks for the existence of a "destination_key" claim. If the dest claim exists, it references the destination key service for validation - otherwise, it delegates the logic to the underlying ProfileService instance, which uses Asp.net identity.
In the Login method of the AccountController, I simply check the acr_values for a destination key passed from the client. This is set in the signinRedirect method of the OIDC-Client.js lib.

Related

OpenIddict 4 WebProviders does not configure external authentication schemes

I am just wondering if anyone has some experience with this. I am trying out OpenIddict 4.0.0 to put together a real-life solution with the new Identity UI and razor pages approach. However when I register an external auth provider using the suggested unified OpenIddict.Client.WebIntegration package, I cannot see the providers on the default login page external section.
I also tried to use the openiddict-core sandbox aspnet.core server app but that as well does not show the configured GitHub external login option.
I could explicitly create links for the providers, however I do not see that as a convenient solution. The default code segment that calls SignInManager.GetExternalAuthenticationSchemesAsync() does not seem to collect the external providers registered using
options.UseWebProviders().UseGitHub() ...
What am I missing here? Thanks
It's a deliberate design choice, explained in this post comparing the aspnet-contrib providers with the OpenIddict providers:
The aspnet-contrib providers use an authentication scheme per
provider, which means you can do [Authorize(AuthenticationSchemes = "Facebook")] to trigger an authentication dance. In contrast, the
OpenIddict client uses a single authentication scheme and requires
setting the issuer as an AuthenticationProperties item if multiple
providers are registered.
For the same reason, the providers registered via the OpenIddict
client are not listed by Identity's
SignInManager.GetExternalAuthenticationSchemesAsync() and so don't
appear in the "external providers" list returned by the default
Identity UI. In practice, many users will prefer customizing this part
to be more user-friendly, for instance by using localized provider
names or logos, which is not something you can natively do with
SignInManager.GetExternalAuthenticationSchemesAsync() anyway.

add custom fields to current user on gateway after authenticating with keycloak server

We're using Keycloak server for authenticating against several IDPS (google, active directory, etc). We have a spring gateway microservice which plays role of a client and several other microservices which play role of resource servers.
When user authenticates via keycloak, we want to associate the authenticated user with some custom fields (like context, roles, user details) from our custom database (NOT Keycloak DB) and send those fields to other microservices as well, so that we do not need to load the fields from DB in every microservice.
How would you do that? Making a GlobalFilter in the Gateway which would add those fields to request headers and setting those headers somehow to the principal object in resource servers? Or using cache (redis) to store the fields on gateway and load them in resource servers? Or do you have some other solution? For example extending access token, overiding UserDetailsService, etc..
What's important to note is, that we don't want to extends Keycloak Database, since we want to have the whole role management in our custom database. Reason for that is that keycloak schema is not very flexible. We want to use keycloak only as a dummy authentication server.
The preferred option for security related values is for Keycloak to reach out to your APIs or custom data sources at the time of token issuance, then include your domain specific claims in JWT access tokens. In keycloak I believe this is done via a protocol mapper, as in this answer.
This design pattern is discussed in the Claims Best Practices article. It is recommended to not send secure values such as roles in custom headers etc, since they are potentially easier to change by a hostile party. Instead each API should receive the JWT and validate it, in a zero trust manner, then use the received claims for authorization.
For non secure values, such as a session_id or correlation_id used for logging, simple HTTP headers work well.

Is to possible to expose Security Stamp from Asp.Net Core Identity as a claim for OIDC

I am using the IdentityServer4 with Asp.Net Core Identity and I'd like to check in my MVC client (which is connected to IdentityServer4) that User's SecurityStamp has changed.
My idea is expose the SecurityStamp like a claim in id_token and check it in my MVC client in some event in Cookie middleware.
If user's security stamp has changed then it will be necessary to login again.
I want to create this round trip especially because I'd like to check if user's roles have changed.
1) Is it good choise to expose SecurityStamp like claim?
2) Is there something how to check if user's security stamp is still valid in OIDC? Or it is necessary to build my own endpoint for this one? Like own API?
We've done this and it works well. I return it as the st claim in the tokens and also via the user info endpoint so it's easy for clients to check if it's changed.
We then made it a requirement that (internal) clients periodically check via the userinfo endpoint that st hasn't changed. We also have a custom impersonation implementation and clients check for impersonation grant revocation the same way.
So in short - yes it's a good idea (IMO) and no you don't need to build an API - just expose it via the userinfo endpoint.

Identity Server 4 and ASP.NET Core Identity

A project I’m working on consists of a web API, a single page react application, and a mobile application. From each client, the user would need to supply their username and password in order to access protected parts of the web API. I’ve set up an Identity Server 4 authentication server that uses my own implementation of the IProfileService and IResourceOwnerPasswordValidator interfaces because I’m using ASP.NET Core Identity. This allows Identity Server to access the ASP.NET Core Identity UserManager, RoleManager, and SignInManagers to determine if the supplied username and password is valid.
The grant type I have been using for all of this is the “ResourceOwnerPassword” type. I haven’t totally integrated authorization into the single page app, but I can pass a user’s username and password to the identity server and a token is generated that I can add to the header of a request to my API.
I’ve done more research about Identity Server and related technologies because I’m new to all of this. It seems like it is undesirable to use the ResourceOwnerPassword grant type. From what I can tell it seems like I should be using the Implicit grant type, but I don’t fully understand how usernames and passwords fit into that flow. Does anyone have any insight into which type I should be using? Is the system I described only possible using ResourceOwnerPassword grant type?
The resource owner password grant type has this written about it on the IdentityServer docs:
The resource owner password grant type allows to request tokens on
behalf of a user by sending the user’s name and password to the token
endpoint. This is so called “non-interactive” authentication and is
generally not recommended.
There might be reasons for certain legacy or first-party integration
scenarios, where this grant type is useful, but the general
recommendation is to use an interactive flow like implicit or hybrid
for user authentication instead.
(Emphasis is mine)
All other flows involve redirects: the user clicks login on your website and is redirected to an identity server login page instead, they enter their credentials there and then are redirected back to your original webpage.
This is the same using your Google account, for example, to log in to other websites. Google wouldn't want you to enter that users name and password into your own site, because you could steal them, and this is generally why the resource owner password grant type is discouraged.
But if you are doing a first-party integration (i.e. the website is yours, and you trust yourself with the user entering their password on your website) then I don't see what the problem is.
You should have a read (and look at the examples) for the other flows/grant types. They definitely have their place and I am not dismissing them, but if you are doing a first party integration then what are doing should be fine.

Multiple Authentication / Authorization support for Web API via OWIN

I have a Web API project of ours that needs to be secured. I am planning to allow the user's that registered with my app to use the API [Forms Authentication], users with their own organizational accounts [ADFS] and Social Sign-In.
I have all the middleware available to plug-in and make available to the user's. However, in my application I do have custom roles and privileges that are to be provided so that my application authorizes the service calls based on the existing privileges. What is the best way to accomplish this.
I think that I will be required to provide my own custom implementation of the UserStore and UserManager with my own IUser Implementation.
Kindly suggest the best practice for this scenario.
With multiple authentication middleware registered, you can get multiple claimidentity's.
register each type of authentication you want to support.
I would be sure to add a claims transformation module at the end of the pipeline. Thinktecture has an example. ThinkTecture Owin Claims Transformer
This would give you one place to look up and add all the application type claims for an authenticated user in one spot.
Simple pseudo example (geared to webapi, but concept the same). Authenticate with bearer or basic or both then transform.
//identity 2.0 user manager stuff used in your modules
app.CreatePerOwinContext(ApplicationSession.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Token Authentication -> get a principle
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
// Basic Authentication. -> get a principle
app.UseBasicAuthentication(app.CreateLogger<BasicAuthenticationMiddleware>(),
"Realm", ValidateUser);
// transform claims to application identity. Add additional claims if needed
app.UseClaimsTransformation(TransformClaims);
It sounds like you are looking for externalized authorization. Externalized authorization is the act of:
decoupling business logic from authorization logic
expressing authorization logic as centrally managed, centralized authorization policies
protecting your APIs through a common layer
enabling fine-grained & dynamic access control through the use of attribute-based access control (ABAC) which extends what's possible with RBAC (role-based access control).
Have a look at XACML, the eXtensible Access Control Markup Language. You can find some more information on OASIS's website.
Also check out NIST's project on ABAC.
Once you defined your authorization logic, you can decide how to enforce it. This can be done either via direct enforcement at the entry of your apps or can be done in a provisioning way whereby the permissions derived from the authorization policies are fed into an authentication token e.g. SAML as attribute assignments.
HTH
This is what I ended up designing for a system with similar requirements. The key is to separate the authentication and authorization logic.
Build Owin authentication middleware components that take care of establishing user identity based on various login methods you mentioned. Looks like you have this accomplished. Set ASP.NET identity based on the user.
Retrieve the roles/permissions for the logged in user from your store. This can be done as a separate Owin middleware or a part of your authentication. Add the permissions as Claims to your Principal.
Extend your roles/permissions store to map API service operations to the application permissions.
Implement a custom API Authorize attribute and apply it to every API operation. In this attribute you will have access to the operation name and the user Claims (permissions). Match the Claims with the permissions you mapped in the step above. If there is a match, return IsAuthorized=true, otherwise, return false.
Here is a similar issue at a simpler level.
How do you setup mixed authorizations for different authentications in .net (web api 2 + owin)