Refreshing token with Hybrid Flow - asp.net

I'm sure I'm missing something.
I have an MVC app & an SSO site that uses Thinktecture Identity Server. The MVC app use hybrid flow to authenticate users on the SSO site. The MVC site uses the Microsoft OpenIdConnect OWIN client to talk to SSO. My tokens have quite a short lifespan - about 5 mins, but I have refresh tokens so the user is constantly re-authenticated. This is a quite useful feature.
However when the token needs refreshing, the user is bounced via the SSO site, which breaks form posts, ajax calls, etc. This is less useful.
Can I not do this renewal on the server, rather than having the user-agent do it? I can't see a way to do this.
I'm also about to look into sliding expiration to try to solve this problem, although I'd been lead to believe sliding expiration was a bad think from a security point of view.

I was missing something. I was getting confused about who was responsible for various activities.
The user should be bounced via the SSO site when their token has expired. I now have sliding expiration on the cookie with an absolute time limit. Ideally this limit should correspond with the expiration of the tokens, but I have a refresh token, so that could be used to refresh the tokens from the server.
Once the relying party has received a valid response, it is responsible for keeping the user logged in, not the SSO site. The SSO site can be used once the tokens need refreshing.

Related

Owin Authentication: SSO token vs ID token

I have implemented sign-in to Microsoft to my ASP.NET web application. Everything works as intended, but I am struggling to comprehend how the sessions work. I am using OWIN middleware and OpenID connect.
What is the difference between the SSO-Token and the ID-token? Which
one keeps me logged in?
What happens if I try to access claims ( e.g.
userClaims?.FindFirst(System.Security.Claims.ClaimTypes.sid)?.Value)
from an expired ID token?
How does !Request.IsAuthenticated realize that the current user is
Authenticated after the microsoft login? Is this because The Generic
Identity, is now a Claims Identity, that returns true?
If I am logged in, and keep refreshing the site, at what point will
I be forced to Authenticate again? And what controls this time?
I understand what an ID-token is, and that it carries claims, and how I access and use the claims. I am just confused about how the session works after a user has logged in with their Microsoft account.
There is no SSO token. The id token represents proof of authentication and some basic user info is included in it. So your web app can get name, email etc.
Expiry is based on an auth cookie that the MS libraries issue. This is tied to another token, the refresh token, which represents the session time.
The id token has a digital signature that is cryptographically verified. Also your app supplies a client secret to help ensure that tokens can be trusted.
The cookie is given an expiry related to the refresh token. When the cookie expires the user has to login again.
FOR BETTER UNDERSTANDING
I would strongly recommend tracing messages, via a tool such as Fiddler, as in this blog post of mine.
Personally I prefer Single Page Apps, which only use tokens and not cookies. They make OAuth aspects easier to understand and code can be simpler, though there are still plenty of subtleties.

Authentication & Authorization in AngularJS

I'm an ASP.NET MVC developer and I recently started to learn AngularJS as it seems like a more modern technology.
However, there's a few complications in my mind when it comes to authentication and authorization in AngularJS. In particular, AngularJS with ASP.NET Web API as the backend.
After authentication and getting the token from the api, I would imagine using Angularjs to store the token in the cookie. So any further requests will include the token. Say for some reason, the token expires, the next angularjs request to the api will fail with unauthorized. However, on the client side, angular thinks that it's authenticated (cookies) and will keep using that invalid token on all requests. I can think of a solution, which is to check for the "unauthorized" response on every request and redirect to login if that's the case. But I would probably be shot for such a practice.
In ASP.NET MVC, protecting a certain page/resource is as simple as adding [Authorize]. But in angular, it seems to be very complicated. How do I many protect many pages againsted the unauthenticated? Do I have to setup and interceptor for every route, etc?
Same goes for Authorization, what if the authenticated user attempts to access, say, the admin panel or parts of admin panel. How do I redirect to unauthorized page if they accessed by direct URL.
There can be many ways of solving your dilemma, but let me give you some tips that I generally use to authenticate and authorize.
Your app has to authenticate with the API (regardless of .NET or otherwise), which may happen by a login request that sets a cookie (during a server redirect), or perhaps a login endpoint the returns a token (like using oAuth). Either way, you have to store the authorization token so Angular can access it. I use cookies or localStorage myself. Then when a user is authenticated, I have a user service store that so I can use it anywhere in the app.
Once this happens, you can use a request http interceptors to attach the authorization header to your request. You can also use a response error interceptor to catch when the token no longer is accepted (usually a 401 status code, easy to check for), and force a login again. This should address issue #1 you raise.
Then for issue #2 and #3, if you are using uiRouter, you can listen for state change events (particularly $stateChangeStart). If I have an admin page, I'll name it admin.whatever and then have a change event that checks if the state has admin or not, and redirect users who are not admins. Likewise, I can do the same for all states to detect if there is no currently logged in user and force a login redirect.
Hope that gives you some ideas, it sounds like you're on the right track but need to hook into the Angular features.
This isn't really an answer but I'm in the same boat as you. I've built some basic Angular pages and small SPA app but now I'm trying to tie it all into an MVC app using .Net Identity. Surprisingly there isn't much out there about this topic. I did come across an good example but it was with .Net Core and MVC 6 which I'm not ready to jump into yet. It's worth watching and might give you some ideas.
http://stephenwalther.com/archive/2015/01/29/asp-net-5-and-angularjs-part-6-security
A couple days ago I came across this video and for the most part it seems to address the issue. It's the only thing that I've found so far with MVC 5, Angular and some .Net Authorization. Take a look and see if it gives you any ideas. I haven't had a chance to implement it yet but I'm hoping to get started doing that in the next couple of days. If you learn or find anything post it here.
https://www.youtube.com/watch?v=f67PFtrldGQ&nohtml5=False

How do you prevent replay attacks with Thinktecture IdentityModel token?

I have two sites on separate domains. I'm implementing SSO using the Thinktecture IdentityModel.
A user logs into Site A. At some point they click a link to take them to site B. Site A redirects the user to site B/Login.aspx?token=< token > with a JWT token. Site B then validates the token by calling an API on Site A to authenticate the user. If authenticated, the user is automatically logged into site B.
By default Thinktecture tokens last for 10 hours, with no way to kill a token(as far as I can tell). If the user logs out of the site, the token is still valid. I can look at the browser history and get the "Login.aspx?token=< token >" url and be automatically logged back in. Is there a way to kill all of a users tokens when they logout? Should the token not be passed as part of the querystring? What is the best way to prevent a replay attack?
As commented on your question by #leastprivilege, you can easily achieve SSO for both your sites just by defining both sites as RP's (relying parties) trusting the same IDP. That would of course simplify your authentication solution architecture.
Having said that, passive authentication using WS-Fed, is still vulnerable to replay attacks. Although the token is posted to your site, hitting "back" on your browser a couple of times (even after sign out) will re-post the token to your site and will sign the user back in.
Fortunately, WIF has a way to mitigate that attack. By configuring:
<identityConfiguration>
.......
<tokenReplayDetection enabled="true" />
.....
</identityConfiguration>
Wif then caches the used token on the server and makes sure it is used only once. (A proper exception is raised if a replay attack is detected SecurityTokenReplayDetectedException).
This cache of course will not survive a process recycle and won't be enough in a web farm scenario. If you want to mitigate this attack for these scenarios as well, you would need some kind of distributed & persistent cache for it.
I implemented one as a contribution to Thinktecture.IdentityModel, you could look into it and use it.
Sounds like POSTing tokens should resolve the issue, at least in this most obvious scenario you describe. Haven't used JWT tokens but SAML tokens are usually POSTed. I bet the server can be configured to post jwt tokens as well.

Combine STS and relying party into same website

I'm working on an MVC project and I'd like to abstract authentication out completely using WIF. By default, without any additional configuration, this app needs to be it's own STS in additional to also being a relying party. Has anyone done that and have any suggestions?
I tried to think of exactly the same mechanism some time ago and I failed.
My reasoning was that to be an RP, the application has to get a signed SAML token issued by an STS. Upon receiving the token, the federation cookie is created.
But to be the STS, the application should have a login page and a mechanism to persist the login session so that users do not have to login again. Then it should react to wsignin1.0 requests and issue SAML tokens.
This leads to a contradiction in my opinion. The application should have a federation cookie (to maintain users sessions as an STS) before it issues the SAML token but in the same time it can create a federation cookie (as an RP) just after it receives the SAML token.
Of course, you could possibly maintain two cookies, a federation cookie for the RP part and a forms cookie (probably) for the STS part but it sounds impractical and against the idea of abstracting the authentication.
In a short way: this is not easily possible in my opinion. However, I would be glad to hear other ideas from someone.

Reauthenticate using ADFS?

I am being tasked with writing an asp.net web app that will use ADFS for authentication. However, at one stage in the application users will have to re-authenticate and supply their username and password again.
Can this be done with ADFS?
The ASP.NET app can be an active client to the STS as well as a passive one. When you need to step up, provide some input fields and ask the user for additional proof of who they are. Using the WSTrustChannelFactory, pass this info (and possibly the original token) to the STS to get a new token that is fresher and contains claims that are sufficient to authorize the the higher value transaction.
What is the goal of the re-authentication, i.e., what does the user need to prove?
I'm presuming the application wants a sign-in token with a recent authentication timestamp (within, say, the last 10 seconds), so that the application is reasonably sure that the client system is really still under that same user's control.
(Watch out for clock differences between your web server and your AD FS server, by the way.)
In the coming months I will be investigating a similar scenario, and my current idea is to use the SessionAuthenticationModule.SessionSecurityTokenReceived Event, as described in this blog post by Vittorio Bertocci. However, that cannot be the entire solution, since this only forces AD FS to give out a token, but it does not force AD FS to give out a token with a recent authentication timestamp.
So no answer yet, but perhaps these hints help.
This article describes a "step-up" procedure that might help you in this scenario. I haven't used it though, so I can't comment in detail. It looks very close to what you are trying to do.
Reducing TokenLifetime property makes you to re-authenticate users. suppose by TokenLifetime is by default is 60 min but it shows popup before 20 mins. but there may be data loss
For ASP.NET using WIF, you are using WS-Federation as the protocol to interact with ADFS and get a token. Within this, you can specify wrefresh=0 in the sign-in request to ADFS. When this is sent, ADFS ignores any prior cookie state (web SSO) and does a fresh authentication and so a new token will be issued to the app. In the case of intranet domain joined machine case, this will be silent.
To have user interaction, you can do one of 2 things
For 2012R2, I recommend that you use MFA and the app can request MFA by requesting for MFA in this 'step-up' scenario. See http://blogs.msdn.com/b/ramical/archive/2014/02/18/under-the-hood-tour-on-multi-factor-authentication-in-ad-fs-part-2-mfa-aware-relying-parties.aspx
Outside of this, you can also force username/password auth and combine it with wrefresh=0. This ensures that prior SSO state is ignored and U/P auth is performed.
Thanks
//Sam (#MrADFS)

Resources