Sunday, June 14, 2015

SSO -- All we need is "Claims"

Bypass application security with right claims




Now-a-days security is all about tokens and claims. If you have the token with right claims, you can get into any application or service without anyone ever knowing about it. Sounds scary isn't? All the security you have ever implemented in the application can just be compromised by anyone if they get their hands on the token your application is getting from it's IDP.

Since I scared you enough now, let me just explain what I did. 

The requirements were to redirect user from a mobile App to one of our secured websites which uses ForgeRock OpenAM for authentication. And since the users are already logged in the mobile App, we never wanted those users getting redirected to OpenAM again for login when they hit our secured website. So in short, we wanted the website to consider the users logged in when they come from our mobile app without going to OpenAM even once. 

Now, there two ways you can achieve above. One is to override the authentication manager of the website to accept users when they come from mobile app. You can just give mobile users an identifier which tells the website that this is a mobile app user and let them in but here you are compromising the security of your application.

Second is to mimic the security which OpenAM and website is using to validate their users. This is comparatively more elegant approach as first you are using out of the box functionality of both OpenAM & website and secondly you are not compromising the security by introducing a loop hole.

In order to implement the second, you need to know how the authentication works between any identity provider & consumer. Below is a picture I found online to explain the process.




I am not going to explain Federated security here but at high level, when any identity provider (in our case OpenAM) authenticates the user. It issues a security token to them which contains claims. These claims are nothing but some information about the user issued by IDP post successful authentication and some information about the service you are trying to access. This part is very important and I will come back to this later.

So, if you can generate the same claims in a token and pass that token to the application then it really doesn’t cares whether you got that token from it’s IDP or you made it yourself. This is what we are going to do and you can use below .net code to achieve this with any identity provider. What claims your application expects in the token depends upon application to application but overall principal is same.

First, let's create some claims:-


//Create claims
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, "NAME-IDENTIFIER", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.microsoft.com/identity/claims/tenantid", "TENANT-ID", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.microsoft.com/identity/claims/objectidentifier", "OBJECT-IDENTIFIER", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "PiyushTest@ABC.com", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
 claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname", "Gupta", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
 claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname", "Piyush", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.microsoft.com/identity/claims/displayname", "Piyush Gupta", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.microsoft.com/identity/claims/identityprovider", "IDENTITY-PROVIDER-URL", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "IDENTITY-PROVIDER-URL", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", "AUTHENTICATION-METHOD", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));
claims.Add(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant", "2015-06-09T07:10:32.080Z", "http://www.w3.org/2001/XMLSchema#string", "https://issuerUrl/", "https://issuerUrl/"));

Now create an identity and add these claims to it:-

//create claims identity using above claims
var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);
        

Create ClaimsPrincipal and add the identity created above in it and set it in current thread because this is where your application will look for it.

//creating principal
ClaimsPrincipal principal = new ClaimsPrincipal(identity);
Thread.CurrentPrincipal = principal;

 And finally, use SessionSecurityToken class to write a cookie with all this data.

SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(principal, TimeSpan.FromHours(8));
sessionSecurityToken.IsReferenceMode = true;
            FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);

return Redirect("To-My-Secured-Website");

Once you have done above and set the right claims in the token, your application will silently accept this and let the user in without going to the identity provider for authentication.

Now, after you implement this don't think you application security is useless :) It's not.

Somewhere above I said, I will come back to this. Your application needs a token and claims in order to let the user's in. Now these claims and it's value is everything and not anyone can get their hands on them otherwise I just compromised my application by showing you above :)

As I mentioned earlier, half of these claims contains information about the user which only identity provider can give once you provide your correct username/password. Rest of the information is of your application which either you have access or someone else can if they hack into your server. Now both of these are big IFs and if someone has correct username/password of the user or hack into your servers then creating false claims would be the last thing they would plan to do with it :)

Hope you enjoyed this hack!