WS-Federation Authentication Module (WSFAM) and SharePoint Extensions
SharePoint Claims Authentication Series
01 - SharePoint, Claims, WS-* and the Windows Identity Foundation (WIF)
02 - WS-Federation Authentication Module and SharePoint Extensions
03 - The SharePoint Federation Authentication Module
04 - Integrating SharePoint with Windows Azure Active Directory (ACS)
05 - Session Authentication Module and WS-SecureConversation
06 - SharePoint Session Authentication Module
07 - Windows Claims Authentication
08 - Service (ActAs) Tokens
Thank you to Steve Peschka for reviewing these articles!
SharePoint Claims Authentication Part 2
In the Windows Identity Foundation (WIF) and Claims web applications utilizing it, the WS-Federation Authentication Module (WSFAM) and Session Authentication Module (SAM) are responsible for authentication. Like existing authentication modules for IIS and ASP.NET such as the Windows Authentication and Forms Authentication modules, the WIF authentication modules plug into stages in the integrated pipeline to interact with and influence request processing.
SharePoint implementation of WSFAM and SAM
As in so many other areas, SharePoint wraps and simplifies management of Claims authentication via WIF. It does this by deriving custom classes from the standard WSFAM and SAM authentication modules: the SPFederationAuthenticationModule and SPSessionAuthenticationModule, respectively. SharePoint also adds a third module to the pipeline, SPWindowsClaimsAuthenticationHttpModule, which deals specifically with creating Claims-based tokens for Windows users. More on that later. The extensions to the web.config files when Claims authentication is enabled are contained within 14\CONFIG\IdentityModel\webconfig.identitymodel.add.xml; the new modules appear like this in a Web Application's web.config file:
<add name="FederatedAuthentication" type="Microsoft.SharePoint.IdentityModel.SPFederationAuthenticationModule, Microsoft.SharePoint.IdentityModel, Version=22.214.171.124, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="SessionAuthentication" type="Microsoft.SharePoint.IdentityModel.SPSessionAuthenticationModule, Microsoft.SharePoint.IdentityModel, Version=126.96.36.199, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="SPWindowsClaimsAuthentication" type="Microsoft.SharePoint.IdentityModel.SPWindowsClaimsAuthenticationHttpModule, Microsoft.SharePoint.IdentityModel, Version=188.8.131.52, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
Some settings for Claims authentication can be configured declaratively in web.config files like some settings of the Forms, Windows, and other authentication modules. The <microsoft.identityModel> section is used to declare these settings and is added as a direct child of the <configuration> element. In SharePoint web.config files it tends to be at the very bottom of the file. The default configuration for SharePoint web applications is provided in the same XML file as the additional module configuration described above and is provided below for reference. I'd highly recommend not changing this without clear approval or instruction from Microsoft Support. Some of these settings may be surprising, such as passiveRedirectEnabled="false", but as we shall see their values have been chosen for a reason.
<issuerNameRegistry type="Microsoft.SharePoint.IdentityModel.SPPassiveIssuerNameRegistry, Microsoft.SharePoint, Version=184.108.40.206, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add type="Microsoft.IdentityModel.Tokens.X509SecurityTokenHandler, Microsoft.IdentityModel, Version=220.127.116.11, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add type="Microsoft.SharePoint.IdentityModel.SPSaml11SecurityTokenHandler, Microsoft.SharePoint.IdentityModel, Version=18.104.22.168, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
<nameClaimType value="http://schemas.microsoft.com/sharepoint/2009/08/claims/userid" />
<add type="Microsoft.SharePoint.IdentityModel.SPTokenCache, Microsoft.SharePoint.IdentityModel, Version=22.214.171.124, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<wsFederation passiveRedirectEnabled="false" issuer="https://none" realm="https://none" />
<cookieHandler mode="Custom" path="/">
<customCookieHandler type="Microsoft.SharePoint.IdentityModel.SPChunkedCookieHandler, Microsoft.SharePoint.IdentityModel, Version=126.96.36.199, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
Of the various stages in the ASP.NET pipeline (see the Remarks section at the end of the linked page), you will not be surprised to learn that the two WIF authentication modules register for the AuthenticateRequest and PostAuthenticateRequest events. You may be surprised that the WSFAM module registers for the EndRequest event as well. We'll now explain how these modules work, beginning with WSFAM and SPFAM. In this post, we'll describe WSFAM independently and in the next article describe how SharePoint modifies its behavior.
WSFAM: The federation sequence
As its name implies, the WS-Federation Authentication Module is responsible for implementing the WS-Federation profile to request and receive security tokens via a web browser (passive) client. In simple WIF applications, properties such as the federated STS, the source realm, and the desired authentication type can be set in the web.config file at the path configuration/microsoft.identityModel/service/federatedAuthentication/wsFederation as detailed here. If you're familiar with the WS-Federation spec you'll immediately recognize the correspondence between query parameters specified therein and the configuration properties available for WSFAM.
web.config-based configuration of WSFAM allows federation with a single Security Token Service. This may be fine for small applications, but in SharePoint more options are needed. As a result, the wsFederation element for a SharePoint web application is filled mostly with placeholder content. Instead of using this element, SharePoint retrieves details about federation configuration and requirements from its own object model in the SPFAM module process, as we'll discuss later.
As mentioned above, WSFAM registers itself for the AuthenticateRequest pipeline event. Logically and intuitively, the WSFAM passes through this stage first. However, the actions taken at this stage differ significantly on the second time through the pipeline, so we will address the stages of WSFAM as follows:
- AuthenticateRequest (first pass)
- AuthenticateRequest (second pass)
As it passes through the AuthenticateRequest stage, the WSFAM checks the incoming request for a form with a wresult parameter. If you recall from part one of this series, the RSTR from the STS is returned to the Relying Party (RP) application embedded in this wresult form parameter. So in other words, this stage expects to take action only if the browser has already visited and returned from the STS with a security token. That will be the case later on, in the second pass (stage 4). However, if this is the browser's first contact with the web application, the AuthenticateRequest process in WSFAM will not find a wresult parameter and will thus have nothing to do.
In the PostAuthenticateRequest stage, WSFAM checks if a Claims principal has been properly set on the current HTTP context. If authentication succeeded in the AuthenticateRequest stage some principal will have been set on the context, though this principal could be a Windows or Forms principal and not a Claims principal. In that case, the WSFAM converts them into a Claims Principal at this stage. If no principal has been set (i.e. authentication has not yet succeeded), an anonymous Claims principal is set for the context now. In SharePoint, either a Claims principal should already have been set at this point (if authentication has completed, i.e. during the second pass) or the anonymous principal will be set.
After a proper Claims principal has been set on the context, any custom Claims Authentication Manager configured for the application is called. For SharePoint web applications, no Claims Authentication Manager is configured; however, there is a custom Claims Authentication Manager for service applications. Claims Authentication Managers can modify or augment claims set for the incoming principal, or even entirely replace that principal. This may be a valid extensibility point even in a SharePoint web application; however, a custom ClaimProvider would generally be more appropriate.
Finally, we arrive at the EndRequest stage, which is the most significant point on a request's first pass through the pipeline. It is at this point that the browser is redirected to an STS to request a security token. Significantly, by default this entire stage is skipped if the passiveRedirectEnabled property on the wsFederation configuration element is set to "false". As you can see in the configuration above, this is in fact the case for a SharePoint web application. SharePoint provides its own version of OnEndRequest to inject the more complex logic needed there. Let's go ahead and look at what WSFAM does on its own first.
First, EndRequest checks if the incoming request is not authorized by checking for a 401 response code. Thus, this stage is generally only relevant on the first pass through the pipeline. Of course, it's possible that a user was properly authenticated but still not authorized to access the target resource, so EndRequest also checks if an authenticated user has been set on the context. If it hasn't, redirection to the STS is initiated. This is pretty simple - parameters set declaratively and programmatically for the request to the STS are gathered together and placed in a query string, itself appended to the URL of the designated STS. This URL is sent to the browser as a 302 response and the browser heads off to the STS to request a security token, as described in Part 1.
The next step at this point in the WS-Federation profile is authentication at the STS, receipt of a security token from the STS, and posting of that token back to the RP web application. See the first post in this series for more elaboration on these details. Once the RSTR is posted back to the RP web application, we reach the AuthenticateRequest stage in the ASP.NET pipeline again, and we continue our discussion there.
AuthenticateRequest (second pass)
Coming through AuthenticateRequest after returning from the STS, the browser should now be presenting a form with a valid wresult parameter containing an RSTR (RequestSecurityTokenResponse). This time through WSFAM has a lot to do! It must read in the RSTR, find and call appropriate security token handlers, and finally pass off control to the Session Authentication Manager to create a session security token. Let's step through this process step by step.
First, the web form in the incoming request is parsed. The wresult parameter, which contains the RSTR and associated security token, is the most important component here. It is retrieved and then passed to the collection of SecurityTokenHandlers specified in the web.config file (or programmatically). SecurityTokenHandlers are elements in Windows Identity Foundation responsible for reading the raw, serialized Security Token XML and converting it into a SecurityToken object. In the simplest case (such as in SharePoint), a single collection of SecurityTokenHandlers is associated with a web application in its web.config file. Incoming tokens are passed to the configured handlers one by one in order, and the first one that can successfully parse the XML returns a valid SecurityToken object. If you review the snippet from the microsoft.identityModel section of SharePoint's web.config above you'll find that the three token handlers configured in SharePoint 2010 are (in order):
The types of tokens handled by the first two entries are self-evident. The X509 handler is used to parse the signing certificate of incoming SAML tokens and the SAML1.1 handler parses the actual SAML tokens themselves. The SPTokenCache handler is a special handler for managing session security tokens (aka Security Context Tokens, or SCTs). We'll get to those when we get to the Session Authentication Module.
Once the SecurityToken is created from the RSTR, it's used to create a Claims principal. This principal is passed through any custom ClaimsAuthenticationManager (described above) to leave us with the final Claims principal that will be set on the HTTP and thread context for ongoing use in the web application.
And we're done! Well, not quite… Didn't think it was that easy did you? If this were the end, you'd have to re-authenticate each time you requested a new page in the web application. Fortunately, we create a special Session Security Token that can be used to maintain a single authenticated secure conversation across multiple messages. This is the responsibility of the Session Authentication Module, which we'll leave for another article.
Hopefully you now understand how WIF implements the passive requestor pipeline defined in the WS-Federation spec. In the next article, we'll cover the modifications SharePoint makes to this process.