Category Archives: Security

Dealing with Token Timeout in Windows Identity Foundation

When a Security Token Service (STS) creates a token, that token has an absolute expiration. Usually this is about 60 minutes, after which the Relying Party (RP) has to send the user back to the STS to acquire a new token. When using Windows Identity Foundation (WIF) in ASP.NET (so for passive federation), this is the default behavior, because the SessionAuthenticationModule stores the token in the FedAuth cookie and checks that token on each request.

What’s the problem?

I hear you thinking “Cool, WIF takes care of all that for me”, and that is cool. But there’s also a nasty side effect, one which all web developers have encountered in a different context: sessions. If a user logs in, starts filling out some form, and then gets interrupted by a phone call, chances are that the session expires. This can lead to problems when the user submits the form, because the user has to log in again. The original posted data gets lost in the process, much to the frustration of the user. Because sessions use sliding expiration the problem is minor. But with absolute expiration, expiration can wreak havoc even if the user posts a form just a minute after the form was presented to the user.

Solving the problem

There are several ways to solve the problem outlined above:

  1. Don’t use the SessionAuthenticationModule.
  2. Modify the stored token to implement sliding expiration.
  3. Force reacquiring a token in the background, so you can control when this happens.

Ditching the SessionAuthenticationModule

Not using the SessionAuthenticationModule appears to be simple. Just remove it from web.config and you’re done. However, if you remove it, you have to ensure a user stays logged in after receiving the token, and you need to keep track of the received claims. This means you need to use a cookie or session data to keep track of the user. Basically you would be recreating what the SessionAuthenticationModule does for you for free.

Making token expiration sliding

This is actually easier than ditching the SessionAuthenticationModule. All you have to do is handle the SessionSecurityTokenReceived event and modify the ValidTo property of the token, as shown in this MSDN Forums post.
Tip: You can hookup the event in the Application_Start event in global.asx using FederatedAuthentication.SessionAuthenticationModule to point to the module.

Force reacquiring a token

The above methods work fine, but have some drawbacks. One of these is the fact that Single Sign-On (SSO) no longer works properly if a user spends too long in a single application. This is because the login session with the Identity Provider will expire at some point. Another issue arises if you want to use delegation or impersonation when you call a web service. WS-Trust 1.4 supports delegation (ActAs) and impersonation (OnBehalfOf). Even though WIF officially implements WS-Trust 1.3, WIF does support these constructs. When calling web services from a web application, using delegation is a recommended practice, because it greatly improves the security. The reason is that in order for the web application to make the web service call on your behalf, it needs to acquire a token from the STS, based on the original token. This means a malicious user would need that token in order to make the web service call. Breaking into the web application is not enough.

So, how can you ensure you get a new token once in a while? Although the implementation is somewhat more difficult, the principle is simple: logout of the RP. That triggers the RP to re-authenticate the user by redirecting to the STS. As long as the user is still known in the STS, a new token is transparently given out. You can do this in roughly two ways: in an invisible iframe that does this process under the covers or in the main request stream. The latter is more visible to the user and requires you to bring the user back to where he was before the logout was forced, which is slightly more complicated than a simple redirect. The iframe solution is more elegant, because it does not interrupt the main working process. Basically all you have to do is point the iframe to a handler that logs the user out if necessary, triggering the re-authentication process when necessary and coming back to the handler to produce an empty HTML page. The handler to do this is shown in the code below.

using System;
using System.Configuration;
using System.Globalization;
using System.IdentityModel.Tokens;
using System.Threading;
using System.Web;
using Microsoft.IdentityModel.Claims;
using Microsoft.IdentityModel.Web;
namespace WebApp
{
    /// 
    /// HTTP Handler triggering token renewal when this is necessary.
    /// 
    public class TokenRenewalHandler : IHttpHandler
    {
        /// 
        /// The default number of minutes before the token expires when renewal should be triggerd.
        /// 
        private const int DefaultTokenRenewalWindow = 20;

        /// 
        /// Value container for the TokenRenewalWindow
        /// 
        private int m_TokenRenewalWindow = 0;

        /// 
        /// Number of minutes before the token expires when renewal should be triggerd.
        /// 
        /// Should be less or equal to the session timeout.
        protected int TokenRenewalWindow
        {
            get
            {
                if (m_TokenRenewalWindow == 0)
                {
                    int securityTokenRenewalWindow;
                    if (!int.TryParse(
                           ConfigurationManager.AppSettings["SecurityTokenRenewalWindow"],
                           NumberStyles.Integer, CultureInfo.InvariantCulture,
                           out securityTokenRenewalWindow))
                    {
                        securityTokenRenewalWindow = DefaultTokenRenewalWindow;
                    }
                    m_TokenRenewalWindow = securityTokenRenewalWindow;
                }
                return m_TokenRenewalWindow;
            }
        }

        /// 
        /// Handles the HTTP reqyest and forces a signout to renew the token if necessary.
        /// 
        public void ProcessRequest(HttpContext context)
        {
            SecurityToken token = null;
            IClaimsPrincipal principal = Thread.CurrentPrincipal as IClaimsPrincipal;
            if (principal != null && principal.Identities.Count > 0)
            {
                token = principal.Identities[0].BootstrapToken;
                if (token != null)
                {
                    DateTime tokenExpirationTime = DateTime.Now.ToUniversalTime().AddMinutes(TokenRenewalWindow);
                    if (token.ValidTo.ToUniversalTime().CompareTo(tokenExpirationTime) < 0)
                    {
                        if (FederatedAuthentication.WSFederationAuthenticationModule != null)
                        {
                            // Force sign-out.
                            FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false);
                        }
                        // Redirect to this handler to force a new sign-in request to the STS
                        context.Response.Redirect(context.Request.RawUrl, true);
                    }
                }
            }
            // Return an empty HTML page
            context.Response.ContentType = “text/html”;
            context.Response.Write(“”);
        }

        public bool IsReusable
        {
            get { return false; } }
    }
}

Common Windows Identity Foundation misconceptions

I am on crusade to get Windows Identity Foundation (WIF) adopted by the Microsoft .NET community at large. Why? Because maintaining a user store within an application as is propagated by ASP.NET Membership is just plain stupid these days. Yes, I may be a little harsh with that judgment, but sparing the rod spoils the child. Applications should no longer be islands, but should be working together. And if applications such as Spotify and Flickr can (re)use a user’s identity from Facebook, Twitter, LinkedIn, and so on, why can’t yours?

“A thousand mile journey begins with one step” – Lao Tze

In the past couple of years I’ve been speaking about WIF on many occasions, both at conference and with individual developers. Across the board I can say that WIF is largely misunderstood. Hence my first step is to address some of the misconceptions surrounding WIF, and more in general the concepts underlying WIF.

Misconception 1: WIF is Microsoft-only and not interoperable.

WIF actually implements the WS-Federation standard. Microsoft is an active participant in the standards commonly known as the WS-* specifications, a host of web services specifications for security, transactions, and reliable messaging. The WS-Federation standard is implemented by many other platforms, and WIF can interoperate with these just fine.

Misconception 2: WIF can only be used to secure web applications, not web services.

The WS-Federation protocol defines two profiles: Active and Passive. Passive federation is for browser based applications, because browsers don’t support the full cryptographic stack required for WS-Federation to work. Active federation is used for web services and can be used with clients that do support the needed cryptographic capabilities. I’ll get back to what this all means in another post.

Misconception 3: WIF can only be used to secure web services, not web applications.

See misconception #2.

Misconception 4: WIF is only for cloud (Azure) applications.

WIF works with any application written in .NET 3.5 and up. You can host that application anywhere you like, in the cloud or in your own data center. In fact, there is nothing that prevents you from creating applications with WIF for use in just the local network and for internal use only.

Misconception 5: You can’t do role-based security with WIF.

Quite the opposite is true. You can still do role-based security if you want to, but you can do much more. The underlying protocol is much more flexible, and you can implement security checks in your applications based on the information you get about a use any way you like.

Misconception 6: WIF only adds complexity.

It is indeed true that properly connecting a WIF enabled application to a security token service can be a challenge. You need to get the protocol settings to match and need certificates for encryption and signing. However, inside your applications WIF is just as easy as role-based security as you are used to. If you want to do more elaborate things, things obviously get more complex, but this is true for any type of security.

Misconception 7: To use WIF in an existing application I need to re-architect the whole application.

WIF extends the IIdentity and IPrincipal interfaces. This means that your existing application will keep working if you migrate to WIF to get authenticate and authorize the user. The only thing you need to be aware of is the fact that because you don’t have a local user directory anymore, you can’t do things for which you require information about another user. This means you may have to provide a different way to deal with such scenarios. If you use ASP.NET Profiles for this kind of information, a custom provider may be all you need.

Merging Claims Based Authorization and Application Authorization

It is typically a good idea to separate general authorizations of a user from application specific authorizations. This is why we invented Application Roles (Settings Administrator), which are separate from Organizational Roles (System Administrator).When using Application Roles, we can map these roles to Organizational Roles. In organizations using Active Directory, Organizational Roles are typically stored in AD. Application Roles can then be stored using Authorization Manager (AzMan) in XML or AD in Application Mode (separate from the organization AD).

Over the years I’ve built quite a few applications that use the above model, and it works well if you authorize with roles. But these days I do most of my work using things like Claims Based Authorization, so the question is “Does this translate to teh CBA world? And if so, how?”. The answer is that yes, it does translate (very well actually), at least in Windows Identity Foundation.

In the CBA world an application receives a token with claims about the user. Like with roles, this should typically be claims not specific to the application, unless the only source for the claim information lies within (or is only accessible to) the STS. This serves two purposes:

  1. The token is generally usable across applications, so the STS can deal with this more easily.
  2. Tokens are not stuffed with a lot of claims.

The latter is actually more important than you might think. Adding more claims means a bigger token, and there comes a point where the token is so large that for instance ASP.NET rejects the request, because it is bigger than the accepted request size (which you should only increase if really necessary).

Now, one of the great things about CBA is that it enables me to create business logic which checks the authorization based on meaningful values, rather than a role. On top of that, I wouldn’t want to have a hybrid security system for the claims stuff and the application specific stuff. Fortunately, In Windows Identity Foundation I can add claims to a claims identity, and these claims then behave the same as the claims acquired from the STS token. The only difference is that the issuer is set to LOCAL AUTHORITY, rather than the STS, which means these claims are really only usable locally in my app (or service). The code to add a local claim is easy:

IClaimsPrincipal claimsPrincipal = Page.User as IClaimsPrincipal;
IClaimsIdentity claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
claimsIdentity.Claims.Add(new Claim("http://MyApp/SomeAppClaim", "SomeValue"));

You can execute code like this when a session starts, and add all application specific claims for the user (identified by an STS claim) to the claims identity. The local claims then get the same lifetime as the claims originally from the token, so you only have to add them once. This way adding application specific claims is still separated from the functional code. Which was the benefit to start with.

Although the above code will definitly work, there is another option when using WCF, known as Claims Transformation. With Claims Transformation you can define policies that define ClaimSets to add to a user’s token. This model is much more flexible, as explained in the MSDN article Service Station: Authorization in WCF-Based Services (jumps straight to the Claims Tranformation section). That article is from the pre-WIF era, but you can do similar stuff with teh ClaimsAuthorizationManager in Microsoft.IdentityModel.

Aantekeningen SDN Event 13 December 2010

Op het SDN Event van 13 december heb ik twee presentaties gegeven. Hieronder kun je de aantekeningen downloaden die ik gemaakt heb op de tablet (voor wie er niet bij was: ik heb in plaats van slides mijn sessie gedaan met behulp van tekenen in OneNote).

Windows Identity Foundation released

Windows Identity Foundation, formerly known as “Geneva”, has shipped. I’ve been talking about Geneva/WIF on several occasions and I absolutely love it. It opens the door for a whole new realm of authentication/authorization scenario’s. SharePoint 2010 will be the first Microsoft Product to support it, apart from the new Active Directory Federation Services 2.0, which was part of the development effort and was formerly known as “Geneva” Server. Be sure to check it out!