openid jwks rotation - reload on server without internet access - single-sign-on

I have a question about the "best practice" of refreshing jwks data.
A customer has an java spring web intranet application with very strict network settings. So, the webserver is not allowed to make requests into the internet.
We must implement a SSO solution with MS Azure. So, we import the well-known openid configuration and import the data from the jwks_uri. Initially this is not a problem. So, the SSO login works - but only till the keys in the jwks_uri changes.
But how should we update the content from the jwks_uri?
The server is not allowed to access this internet resource.
As I have understood this, normally we should reload this data on a daily base. The content of the jwks_uri could change.
Is there a best practice for such a setup?
Or must I convince the security team to allow the server to access this two Microsoft URLs?
In the configuration of this SSO solution, the administrator fetches the wellknown openid configuration and the content from the jwks_uri and pastes the content to the intranet application admin interface.
So, the intranet server knows the public keys from the MS Azure service and can validate the signature of the id_tokens.
But this keys changes from time to time on MS Azure side.
So, is there a best practice for this how the intranet application comes to the new public keys?
Is there any "magic" I do not know?

You should allow the services that depend on AzureAD to also be able to communicate with them. Otherwise, you can't for example
get the tokens if you are using the authorization code flow.
use the refresh tokens to get a new access token
I don't see how you can get it to work if the services both public and internally can't talk directly to AzureAD.
However, there is one alternative and that is to have a local token service (IdentityServer, Keycloak...) to proxy between your local services and the public internet.
In general your services should only trust one token issuer.
The alternative is to provide the keys manually, for example by setting:
.AddJwtBearer("MyScheme", options =>
{
var key = Encoding.UTF8.GetBytes(Configuration["JwtConfig:AccessTokenSecret"]);
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
...
...
};
See sample answer here
How to set Dynamic IssuerSigningKey and TokenDecryptionKey in AddJwtBearer options in ConfigureServices method on Startup.cs file

Related

Restrict front client connexion with groups / roles in a realm

I'm looking for a way to restrict user access to specific clients in a realm.
I know I can do it with client where Authorization is enabled (fine-grained authorization support) but it doesn't work when trying to connect from front (client need to be public and not confidential).
I'm using a javascript application to login from front-end.
Is there a way to enable Authorization for public client or a work around ?
Thanks.
I'm not sure if this will totally answer your question because it's still not specific enougth but it may give you some further help.
In case you're new to the topic, please see difference between public and confidential clients here.
The current best practice for public clients like HTML/Javascipt applications is to use OpenId Connect with the Authorization Code Flow + PKCE. HTTPS is of course a must have. I recommend you use a javascript openid connect adapter for this like the following for example:
https://github.com/panva/node-openid-client
Basically your authentication / authorization flow is shown here:
When the user wants to login from your frontend client application first a unique verifier is generated which is only available to the exact user / browser session. This value get's hashed as a code challege. Then the user gets redirected to the login page of your authorization server (Keycloak for example) passing some parameters like a redirect uri and the challenge.
With successful login the user get's a session at the keycloak server which also stores the hashed challenge. Then the user gets redirected to given redirect uri (a path in your application) together with a code to obtain an access token. Back in your application you application uses the original value together with the code to get the actual token. The authorization server ckecks the value against the stored challenge and geturns the access token if it matches. You see the extra verifier is to prevent that anybody compromises your code fragment to obtain a token on your behalf.
Now you have an encoded access token in your browser app. Note the token itself is normally only encoded not encrypted but it can be signed. Those signatures can later be used from your backend to ckeck the token integrity but we will come to that soon. Roles, claimes, scopes and so on included in your access token tell you the privileges of the user/identity. You can of course use them to enable/disable functions in your app, block routes etc. but in the end client protection is never really effective so your real authorization ande resource protection happens at your resource server which is your backend (node, .net core, java etc.) maybe a restful Web Api. You pass your access token as a part of the http request header with every request to the backend. Now your backend checks the token integrity (optional) expiration time etc. analyzes scopes, claimes and roles to restrict the resource access.
For example a simple GET myapi/car/{1} may only need a token or can even be annonymous while a POST myapi/cars or PUT myapi/car/{1} may need a special role or higher privileges.
Does that help you out?

IdentityServer3 Multi Tenant IdSvr (single instance) with Multi Tenant Api (single instance) - needed multiple authserver addresses

We have IdSvr single instance with Web Api single instance that both support multi tenant. Our web app is deployed to multiple domains with their own styling on each. The business does not want them to be redirected to the IdSvr such as http://multiauth.identityserver.com. They want to go from a website domain to the IdSvr using http://auth.websitedomain1.com and another would use http://auth.websitedomain2.com, etc
The issue is with the Web Api and setting up the Bearer authentication.
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = Constants.BaseAddress,
RequiredScopes = new[] { "cspwebapi" },
// client credentials for the introspection endpoint
ClientId = "cspclient",
ClientSecret = "8BE96BA5-79F1-4FA4-8E41-6BCE7EA7090F",
});
I can only specify http://multiauth.identityserver.com as the Authority and not multiple such as http://auth.websitedomain1.com and http://auth.websitedomain2.com. The client gets a 401.
So far I have the single instance IdSvr with bindings auth.websitedomain1.com, auth.websitedomain2.com, auth.websitedomain3.com. Now on the Web Api (resource server) I iterate through the array of domain names and create a new app.Map(....) with each domain for the Authority property. The resource server spins up without issue meaning it can see the IdSvr at each domain name. The app.Map(....) segment needs to be the same for all of them...I now have found that doing app.Map('') for all of them will not work for the second or third domain name. Am I on to something here or is this the wrong approach? How else can I configure this to work per the requirements?
Use multiple instances of UseIdentityServerBearerTokenAuthentication in your pipeline, one for each of your IdentityServer installations, each configured with a different authentication scheme (AuthenticationType).
Then in your authorization logic, you can check what auth scheme the token authenticated with and authorize access to data accordingly.

Programatically create an OpenID Connect id_token with IdentityServer3

I am adding IdentityServer3 on to an existing website (NopCommerce to be specific). It has it's own registration and authentication system, but we need to also offer OpenID Connect so that a back end application can be integrated. Calls to the back end need to have an id_token for the current user that the back end validates to confirm the identity.
I've found information about how to use an existing membership database to provide the user data for IdentityServer3 to check, however I am bit stuck on how to generate the id_token for each user. I guess the obvious answer is to replace the website login with IdentityServer, however that raises further issues for the rest of the project. Ideally I'd like the user to log in as normal and then call a method in IdentityServer to generate the id_token.
Is this possible? I've been hunting around, but can't find anything so far. The best I found was an answer to programmatically sign in to identityserver3. I think it's suggesting making a HTTP post to IdentityServer, but it feels kind of hacky.
I also found Implementing OAuth 2.0 and OpenId Connect provider using IdentityServer3 with existing login server and membership provider, but I have to admit it's assuming quite a bit of knowledge I don't have (yet).
My solution based on John C's answer worked using a NopCommece external authentication plugin, but I was unhappy with having to leave Nop to authenticate and register when IdentityServer was using the Nop database. Going via the external auth route seemed to be the only way to get an OpenID Connect id_token. After a break and some time to revisit the code though I found the following:
https://identityserver.github.io/Documentation/docsv2/configuration/serviceFactory.html
https://identityserver.github.io/Documentation/docsv2/configuration/serviceFactory.html
By implementing custom services, IdentityServer allows you to mess with the token creation and generation AND the dependency injection system it uses gives you access to instatiated versions of the default services.
Previously I had followed an answer which sent a username and password to the token endpoint. The OpenID specs say that this should only return the access_token, which is exactly what DefaultTokenService in IdenttyService does. By adding a CustomTokenResponseGenerator however, I was able to re-use the request to create and return an id_token too.
CustomTokenResponse class:
internal class CustomTokenResponseGenerator : ICustomTokenResponseGenerator
{
protected ITokenService _tokenService;
public CustomTokenResponseGenerator(ITokenService tokenService)
{
_tokenService = tokenService;
}
public Task<TokenResponse> GenerateAsync(ValidatedTokenRequest request, TokenResponse response)
{
var tokenRequest = new TokenCreationRequest
{
Subject = request.Subject,
Client = request.Client,
Scopes = request.ValidatedScopes.GrantedScopes,
//Nonce = request.AuthorizationCode.Nonce,
ValidatedRequest = request
};
var idToken = _tokenService.CreateIdentityTokenAsync(tokenRequest);
idToken.Wait();
var jwt = _tokenService.CreateSecurityTokenAsync(idToken.Result);
response.IdentityToken = jwt.Result;
return Task.FromResult(response);
}
}
How to inject the custom service in Startup.cs:
factory.TokenService = new Registration<ITokenService, TokenService>();
factory.CustomTokenResponseGenerator = new Registration<ICustomTokenResponseGenerator, CustomTokenResponseGenerator>();
When user logs-in into NopCommerce application, you can send an HTTP authorize request to identityserver. Make sure while sending the authorize request to idsrv you are using prompt=none, this way you will get the id_token or access_token without showing a consent to the user again if the user is already logged-in.
function getAuthorizeRequest() {
var url = global.appSettings.identityServerURL
+ "/connect/authorize?client_id=siteB&response_type=id_token token&redirect_uri="
+ global.appSettings.siteBUrl + "/Main/NopCommerceapp&scope=siteBscope openid email roles&prompt=none&nonce="76767xz676xzc76xz7c67x6c76"
return encodeURI(url);}
Checkout idsrv authorize endpoint https://identityserver.github.io/Documentation/docsv2/endpoints/authorization.html
I think your best solution would be to implement IdentityServer3 and get it reading from your existing Nop membership database. Then create a Web API app that runs on its own that utilizes your IdentityServer3 setup. Inside the Web API, you implement all the functionality that your back end app needs, reading and writing to the Nop database.
Keep your Nop frontend UI separate from your backend API. If you follow the two links below, you should be able to get something up and running pretty quickly.
Creating the simplest OAuth2 Authorization Server, Client and API
MVC Authentication & Web APIs

Custom STS SSO failing

I'm working on a roll-your-own Federation implementation. There are two RPs. SSO between the RPs does not work (erroneously). I suspect it has to do with the cookie that the STS is creating. The STS is writing a fedauth cookie for itself. From my understanding, it should be writing a Forms Authentication cookie?
When hitting the STS for the second time from the other RP I can see in the ClaimsPrincipal that IsAuthenticated=True, yet the user is prompted to login and not automatically redirected back to the RP.
It's worth noting that SSO did work previously, auto redirect and all, but the RPs on the load balancer couldn't share cookies as it was using the machine key (and no sticky sessions). I fixed this by implementing a custom SessionSecurityTokenHandler that utilizes the certificate (code below). It's at this point that the STS started writing FedAuth cookies and SSO started failing.
The sts token is being written with:
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);
Token handler:
var sessionTransforms = new List<CookieTransform>(new CookieTransform[]
{
new DeflateCookieTransform(),
new RsaEncryptionCookieTransform(federationConfiguration.ServiceCertificate),
new RsaSignatureCookieTransform(federationConfiguration.ServiceCertificate)
});
var sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
federationConfiguration.IdentityConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
The STS writes its own cookie. It POSTs the security token to your application. Your application will typically respond by writing a session authentication cookie, which it will use until it expires (and then it goes back to the STS)
If you work in a web farm then there is an out of the box support for this using WIF configuration :
Of course, the machines in the web farm should then share the same machine key. You can of course use your own mechanism but that seldom makes sense.
Next, each RP should therefore write its own "session" cookie that proves your authentication. If two RP's live in the same domain then they should use a different cookie name.

How to use the metadata file (saml2)

I am working on a project that needs to be integrating SAML2.0. I was thrown into this project suddenly, i need to make it work.
Here is the background: We have created the files and wanted Client Company to integrate using SAML2 to get to our web site. We have sent them the meta datafile.
Now the client company had sent their metadata file. I dont know how and what to do with that file. Any help will be appreciated.
ASP.NET, Framework 4.0
The metadata file basically provides you information of your client. Such as entityID, credential, and so on. If it is an IdP then it also contain couple URLs so that you know where to send different request, e.g. login request, attribute query request. You need to give this metadata to your SAML component so that it know which client it should talk to.
Another main purpose is to establish a trust relationship between SP and IdP.
It's kind of old question but I would like to add some additional information and resources for .NET.
SAML Metadata is used to exchange configuration information between Service Provider and Identity Provider and vice versa. The information can include:
Binging location
Organization name
Contact Person
Single Sign On Url
Single Logout Url
The Metadata can be signed and encrypted so that the information is sent securely. The other side may need the corresponding public key to validate and decrypt it and then can be used to understand and establish the connection with the SP or IdP.
You can see some more info at the following blog posts:
http://samlcomponent.net/constructing-saml-metadata-xml-for-single-sign-on-idp/
http://samlcomponent.net/how-to-create-saml-metadata-xml-for-service-provider/
Security Assertion Markup Language (SAML) is a standard for logging users into applications based on their sessions in another context. This single sign-on (SSO) login standard has significant advantages over logging in using a username/password:
1.No need to type in credentials
2.No need to remember and renew passwords
3.No weak passwords
It is easy to manage all applications in one tree using SAML SSO login.
How actually SAML works:
The user accesses the remote application using a link on an intranet, a bookmark, or similar and the application loads.
The application identifies the user’s origin (by application subdomain, user IP address, or similar) and redirects the user back to the identity provider, asking for authentication. This is the authentication request.
The user either has an existing active browser session with the identity provider or establishes one by logging into the identity provider.
The identity provider builds the authentication response in the form of an XML-document containing the user’s username or email address, signs it using an X.509 certificate, and posts this information to the service provider.
The service provider, which already knows the identity provider and has a certificate fingerprint, retrieves the authentication response and validates it using the certificate fingerprint.
The identity of the user is established and the user is provided with app access.
Take a look at the metadata SAML 2.0 specification to check what elements must be read by your implementation.
If you are looking for a SAML2 .Net Tookit, take a look to this thread of stackoverflow
Also take a look on SAML open source implementations to learn how others resolved this problem before:
SimpleSAMLphp (PHP implementation Idp/SP). (Metadata parser)
Shibboleth IdP (Java) (opensaml2) / SP (C)
spring-security-saml: SP (Java) (metadata files)
Jboss (Java)
Metadata is nothing but the xml file containing all the information required by your SAML implementation to talk with host. you can extract information from this meta to get the desired information required. Like public/private keys.
I hope you are also using certificate to talk with host on secure manner.
This key is required for handshaking with unknown host system.