Token gets expired and keeps going to IDP every a few seconds - saml-2.0

Is there a way I can force it to use cookie or modify the timeout span. It keeps going to the IDP every a few clicks or if the session was ideal for less than 3 seconds.

The ASP.NET Core relaying party sample applications ASP.NET Core authentication and thereby actually cookies, where the tokens timeout is transferred to being the authentication / cookie lifetime.
If the problem is caused by short living tokens you can set the authentication / cookie lifetime in the saml2AuthnResponse.CreateSession method in the AuthController.AssertionConsumerService.
In a ASP.NET Core application like this:
await saml2AuthnResponse.CreateSession(HttpContext, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal), lifetime: new TimeSpan(1, 0, 0));

Related

Azure app Service authentication token not refreshing after calling .\auth\refresh endpoint

I have an angular app hosted in one azure windows app service and a asp.net core api hosted in another, both are protected using the app service authentication feature. I am using an app service plan which currently has two servers. I am using the token store and it is using the file system to store the tokens.
When the angular app calls the api it needs to pass an access token in the authorization header. The access token is retrieved by performing a GET on the \.auth\me endpoint and sending the AppServiceAuthSession cookie as the credential. The returned token is then cached in session storage and used for subsequent requests until the token expires. When the token expires I call the \.auth\refresh endpoint (and send the AppServiceAuthSession cookie) and then call the \.auth\me to get the refreshed token.
All this works well when running on one server but when the app service plan is scaled to 2 or more servers the call to \.auth\refresh succeeds but the subsequent call to the .auth\me endpoint gets a token which has already expired. I can tell the token has expired by checking the internal exp claim and also the call to the api fails with a 401 Unauthorized when it would normally succeed.
If I scale back to one server the problem goes away and if I enable ARR affinity the problem goes away but I don't want to have to enable affinity just to resolve this.
also the call to the api fails with a 401 Unauthorized when it would normally succeed.
You shouldn't be calling /.auth/refresh on the API app. You must call /.auth/refresh on the WEB app because the auth token is produced on the WEB app.
Alternative to the bearer token is the AppServiceAuthSession cookie from your client request to /.auth/refresh.
The returned token is then cached in session storage and used for subsequent requests until the token expires. When the token expires I call the .auth\refresh endpoint (and send the AppServiceAuthSession cookie) and then call the .auth\me to get the refreshed token.
We have a user-facing web application that calls an API backend, which in turn queries the MSFT graph, just to be sure we have the context correctly captured. At each phase, we anticipate a distinct AAD registration:
Web app registration (with permission to API app)
API app registration (with permission to Microsoft Graph)
Our initial assumption is that the user hasn't explicitly given their agreement to using the Microsoft Graph because this looked to be tied to adding the graph permission. Since the user isn't involved if you're merely updating the existing token, there isn't a chance for that consent to be obtained. The user would need to re-login with an explicit consent prompt, which could be done by calling /.auth/login/aad?prompt=consent. But we wouldn't anticipate that to cause the expiration problem. I'm speculating here, but it's possible that a cached, outdated value is being utilised in place of the permission error. There would need to be input from Connor.
The logs from the actual Authentication / Authorization layer itself, particularly if there is an error message, are another piece of information that would be useful to have. To obtain these logs:
From your app in the portal (the API app is what I'm most interested in): “Platform features” > “Diagnostic logs”. Change “Application Logging (Filesystem)” to “On” and set the level to “verbose.” Hit Save.
Back to “Platform features” > “Log stream” and keep that window open as you reproduce the issue (in this case, the call to the API app)
Actually, the issue is that AAD bearer tokens are incompatible with the /.auth/refresh API. Instead, you must use a session token (_x-zumo-auth_ header) or a session cookie (_AppServiceAuthSession_ cookie), which are the results of a login activity.
For more info - see here #refreshing-the-access-tokens

Is Refresh Token relevant for OIDC IdentityServer Azure AD SSO Implementation?

I have an implementation of IdentityServer4 which connects with Azure AD for authentication (OIDC). In the callback method, using the IdentityServertools, I am generating the access_token and redirecting the user to SPA with the same. The SPA then stores the access_token into localstorage and uses it for authentication.
Normally, when my SPA app hits the token endpoint of the IdentityServer4, it gives access_token and refresh_token and then uses refresh_token to re-authenticate a returning user.
In this case of SSO with Azure AD, do I need to generate refresh_token manually? If yes, I can build on top of default implementation and that's not the problem (However, the docs suggest against of changing the IRefreshTokenService implementation or building something from scratch)
My real question is, is there a need of refresh_token here? Because refresh_tokens are stored in DB and never get's deleted and after sometime, these refresh_tokens table will swell (right now it already has 80k rows). The user is expected to click on a small tile inside SAP's Successfactor - that will open the signin/consent screen of Azure or will directly take the user to the main page where zhe will just answer a question and done. So it's hardly 2-3 mins business. So I can continue to generate access_tokens from my IdentityServer4 for every click as I don't expect the user to stay authenticated in the browser if zhe has logged out from SAP's Successfactor (or any other app linked with Azure).
Please advise, if I should generate refresh_token? Is it a good architecture?
Access token is used to prove the request is allowed to access the resource(such as api from ms or your custom api) and refresh token is used to refresh access token to make sure the access token isn't expired. Access token will expire in an hour by default and refresh token has 90 days.
At this point, we can easily find the refresh token is designed for some special scenarios because the expired time for refresh token is much longer than access token's expired time, but we can also generate a new access token in other way such as using msal or sign in again.
As you said in the question, you can generate an access token by one click and you don't expect users to stay authenticated for a long time. So I think it's unnecessary for you to use refresh token.

How to stop Web API getting 401 when using OWIN Cookie authentication

I have a web app which is MVC 5 using OWIN cookie authentication. It also uses AngularJS from which web api calls are made. The Angular code is only invoked after the user has successfully logged in and been authenticated and everything works as you would expect.
However, can someone please explain what component (Chrome, OWIN, IIS, ...) is responsible for eventually issuing a 401 if the user has been idle for 20 or so minutes. In MVC this is not a problem because the redirect automatically re-authenticates but with web api my only option is to get the user to log back in again.
Ok so thats the first thing, who is responsible for timing the session out and giving the 401 (and can i alter it) but ALSO is there any way to get web api calls to keep the session alive so that even if the user is idle the api calls stop it timing out?
Specifically, I have implemented SignalR in a way that the signal to the client results in the client issuing an api call to refresh its data. I realise i could push the refresh but at the moment thats a bit tricky. So whats happening is the updates are occuring nicely but eventually this results in a 401 which i want to avoid.
below is an ideal flow
server logs in => creates cookie sets expiration time, passes it to client
client saves cookies & passes it with each request
server checks the cookies for validity including expiration time
if invalid or expired, server responds with 401
the cookie expiration time can be configured in the CookieAuthenticationOptions. See file ~/App_Start/Startup.Auth.cs
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
ExpireTimeSpan=TimeSpan.FromDays(365),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
Set your ExpireTimeSpan to the desired TimeSpan.
For web api calls that fail authentication you could catch 401's and send back a response that tells the browser it's logged out - you could pop up a login dialog or redirect to login url.

Spring Security SAML assertion expiry with Application Session Expiry

I'm getting confused with the SAML assertion expiry vs Application session expiry.
In simple words, when we have an application deployed in a container, there is a session created. This session expiry can be controlled with the below entry in web.xml
<session-config>
<session-timeout>60</session-timeout>
</session-config>
Moving on, when I have Spring Security with SAML extension, obviously the same session concept applies. (I'm deploying the application in WildFly 8.2, if that matters)
Further, when the application session expires, the logout behaviour seems to be equivalent to Local Logout concept.
So far so good. Now lets say that the SAML assertion is good for 2 hours and the user has been actively working for 2 hours. What should happen to the subsequent request then? Should it re-login to the IDP? But, wouldnt that be inconvenient to the user? If the application redirects to IDP for logging in again after 2 hours of assertion expiry, How should AJAX requests be handled?
This is in reference to the question here
Spring SAML issues an ExpiringUsernameAuthenticationToken for authenticated users. The token starts returning false in its isAuthenticated() method once the SAML Assertion used to authenticate the user reaches its sessionNotOnOrAfter time.
This behavior can be disabled by overriding SAMLAuthenticationProvider and changing method getExpirationDate(credential), which returns time when the Assertion expires, or null in case it never does. Application will then fully rely on session expiration configured in the container.
Once the ExpiringUsernameAuthenticationToken expires, Spring Security will pass the current token to the AuthenticationManager (configured in securityContext.xml under <security:authentication-manager>).
You can affect what happens next, by adding your own AuthenticationProvider able to handle the ExpiringUsernameAuthenticationToken. Otherwise system fails with ProviderNotFoundException or some other AuthenticationException like BadCredentialsException (in case you're using username/password authentication at the same time).
The exception is subsequently handled by ExceptionTranslationFilter, which start new authentication process by invoking the configured authentication EntryPoint - e.g. SAMLEntryPoint which either starts authentication with default IDP or displays IDP selection page. The process will also essentially perform local logout, as you say.
System by default behaves the same for all HTTP calls - AJAX or not. You can define different behavior by splitting your API and normal URLs into separate <security:http> elements and use different EntryPoints (interface AuthenticationEntryPoint) for each. For example Http403ForbiddenEntryPoint might be suitable for your AJAX calls.

Spring SAML - Is it mandatory to call SAML local logout when user signs off from application?

As per the answer from the link, I understand that if SAML local logout (/saml/logout?local=true) is invoked Spring-SAML will clean the local cookies. So, I have modified the logout logic in my application to invoke it.
All looks good till now. But my application have session timeout set to 20 minutes in web.xml.
<session-config>
<session-timeout>20</session-timeout>
</session-config>
In case of user inactive for 20 minutes or browser is closed by the user, session will be destroyed by the container silently. In that case SAML Logout is not invoked.
Questions:
Does Spring-SAML maintains any references once user is authenticated after SAML response is received?
If yes, where does it maintain references (session or somewhere else)? Any alternative way to clean them up?
What are the implications if we do not call SAML local logout?
My worry is that if the references are not cleaned up, It might cause memory leaks in a long run of the application.
By default all state of Spring SAML is stored in HttpSession (as part of Spring Security context in object SAMLCredential) and will be cleaned at session timeout (or more precisely at time when your container decides to perform the session cleanup after expiration).
It is exactly the same as with any other authentication method supported by Spring Security, so you don't need to worry about not calling the local logout.

Resources