WS-Federated Authentication Module Overview
[Starting with the .NET Framework 4.5, Windows Identity Foundation (WIF) has been fully integrated into the .NET Framework. The version of WIF addressed by this topic, WIF 3.5, is deprecated and should only be used when developing against the .NET Framework 3.5 SP1 or the .NET Framework 4. For more information about WIF in the .NET Framework 4.5, also known as WIF 4.5, see the Windows Identity Foundation documentation in the .NET Framework 4.5 Development Guide.]
Windows® Identity Foundation (WIF) includes support for federated authentication in ASP.NET applications through the WS-Federated Authentication Module (WS-FAM). This topic is written to help you understand how federated authentication works and how to use it.
Overview of Federated Authentication
Federated authentication allows a Security Token Service (STS) in one trust domain to provide authentication information to an STS in another trust domain when there is a trust relationship between the two domains. An example of this is shown in the following illustration.
A client in the Fabrikam trust domain sends a request to a Relying Party (RP) application in the Contoso trust domain.
The RP redirects the client to an STS in the Contoso trust domain. This STS has no knowledge of the client.
The Contoso STS redirects the client to an STS in the Fabrikam trust domain, with which the Contoso trust domain has a trust relationship.
The Fabrikam STS verifies the client’s identity and issues a security token to the Contoso STS.
The Contoso STS uses the Fabrikam token to create its own token that can be used by the RP and sends it to the RP.
The RP extracts the client’s claims from the security token and makes an authorization decision.
Using the Federated Authentication Module with ASP.NET
WSFederationAuthenticationModule (WS-FAM) is an HTTP module that lets you add federated authentication to a ASP.NET application. Federated authentication lets authentication logic be handled by the STS and lets you focus on writing business logic.
You configure the WS-FAM to specify the STS to which non-authenticated requests should be redirected. WIF lets you authenticate a user in two ways:
Using the FederatedPassiveSignIn control. When an unauthenticated user tries to access a protected resource, they are redirected to a logon page in the application. This logon page has the FederatedPassiveSignIn control embedded in it and the control is configured with issuer (STS) information. If you do not require application-wide protection and instead require a logon page in the application and you expect the users to click the control (for example, in a financial institution online site with a login page), then this is the right approach.
Passive redirect: When an unauthenticated user tries to access a protected resource, and you want to simply redirect them to an STS without requiring a login page, then this is the right approach. The STS verifies the user’s identity, and issues a security token that contains the appropriate claims for that user. This option requires the WS-FAM to be added in the HTTP Modules pipeline. For more information, see Establishing Trust from an ASP.NET Relying Party Application to an STS using FedUtil.
In passive redirect, all communication is performed through response/redirect from the client (typically a browser). The WS-FAM supports passive redirect in two ways:
You can add the WS-FAM to your application’s HTTP pipeline, where it watches for unauthenticated user requests and redirects users to the STS you specify.
You can instantiate the WS-FAM and use it to validate requests. This is what the FederatedPassiveSignIn control does.
The WS-FAM also raises several events that let you customize its functionality in an ASP.NET application.
How the WS-FAM Works
The WS-FAM is implemented in the WSFederationAuthenticationModule class. Typically, you add the WS-FAM to the HTTP pipeline of your ASP.NET RP application. When an unauthenticated user tries to access a protected resource, the RP returns a “401 authorization denied” HTTP response. The WS-FAM intercepts this response instead of allowing the client to receive it, then it redirects the user to the specified STS. The STS issues a security token, which the WS-FAM again intercepts. The WS-FAM uses the token to create an instance of IClaimsPrincipal for the authenticated user, which enables regular .NET Framework authorization mechanisms to function.
Because HTTP is stateless, we need a way to avoid repeating this whole process every time that the user tries to access another protected resource. This is where the SessionAuthenticationModule comes in. When the STS issues a security token for the user, SessionAuthenticationModule also creates a session security token for the user and puts it in a cookie. On subsequent requests, the SessionAuthenticationModule intercepts this cookie and uses it to reconstruct the user’s IClaimsPrincipal.
If you want to make your RP application claims-aware, but you do not have an STS (for example, the RP uses Forms authentication or Windows integrated authentication), you can use the ClaimsPrincipalHttpModule. This module sits in your application’s HTTP pipeline and intercepts authentication information. It generates a IClaimsPrincipal for each user based on that user’s username, group memberships, and other authentication information. ClaimsPrincipalHttpModule must be inserted at the end of the <httpModules>
pipeline, which is the first element in the <modules>
section of <system.webServer>
on IIS 7.
The following diagram shows the overall flow of information when the user is redirected to a login page to establish credentials and then redirected to the destination page once authenticated:
The following diagram shows more detail on what happens when the user has authenticated to the STS and their security tokens are posted to the login page:
Finally, the following diagram shows more detail on what happens when the user’s security tokens have been serialized into cookies and are intercepted by the SessionAuthenticationModule:
The following diagram shows the overall flow of information in the passive redirect case. The request is automatically redirected via the STS to establish credentials without a login page:
The following diagram shows more detail on what happens when the user has authenticated to the STS and their security tokens are processed by the WSFederationAuthenticationModule:
Events
WSFederationAuthenticationModule, SessionAuthenticationModule, and their parent, HttpModuleBase, raise events at various stages of processing of an HTTP request. You handle these events in the global.asax
file of your ASP.NET application.
HttpModuleBase raises the
Init
event when the module is initialized.WSFederationAuthenticationModule raises the ServiceConfigurationCreated event when it loads the service configuration. It only raises this event once, not per-module. This event provides the ServiceConfiguration, which you can use to modify the service configuration. You should catch this event in the Application_Start method:
void Application_Start { FA.ServiceConfigurationCreated += new ServiceConfigurationCreatedEventHandler( <your event handler signature>); }
The ServiceConfiguration simply contains the static properties for FederatedAuthentication. FederatedAuthentication has references to the configured WSFederationAuthenticationModule and SessionAuthenticationModule, each of which has its own references to the ServiceConfiguration for FederatedAuthentication.
If you want the WSFederationAuthenticationModule or SessionAuthenticationModule to have their own configurations, you must derive your own class from WSFederationAuthenticationModule or SessionAuthenticationModule, create a new ServiceConfiguration, and reassign the ServiceConfiguration reference in your derived class to the ServiceConfiguration that you have created.
The WS-FAM raises SecurityTokenReceived when it intercepts a security token that has been issued by the STS.
The WS-FAM raises SecurityTokenValidated after it has validated the token.
The SessionAuthenticationModule raises SessionSecurityTokenCreated when it creates a session security token for the user.
The SessionAuthenticationModule raises SessionSecurityTokenReceived when it intercepts subsequent requests with the cookie that contains the session security token.
Before the WS-FAM redirects the user to the issuer, it raises the RedirectingToIdentityProvider event with the ‘federation request’ as a parameter. You may choose to modify the request before sending this out to the issuer.
The WS-FAM raises SignedIn when the cookie is successfully written and the user is signed in.
The WS-FAM raises SigningOut one time per session as the session is being closed down for each user. It is not raised if the session is closed down on the client-side (for example, by deleting the session cookie). In an SSO environment, the IP-STS can request each RP to sign out, too. This will also raise this event, with IsIPInitiated set to true.
Note
You should not call Thread.CurrentPrincipal
during any event raised by WSFederationAuthenticationModule and SessionAuthenticationModule. Thread.CurrentPrincipal
is set after the authentication process, while events are raised during the authentication process.
Scenarios Supported
The WS-FAM supports the following scenarios:
Accessing claims in an ASP.NET RP application that uses WS-Federation for authentication. If the RP application uses Forms authentication or Windows Integrated authentication, only ClaimsPrincipalHttpModule is needed. For more information, see How to: Access Claims in an ASP.NET Page.
Managed card logon to an ASP.NET application. This only requires the SessionAuthenticationModule.
Configuration of Federated Authentication
The following configuration snippet describes the attributes that can be configured in the <federatedAuthentication>
configuration element:
<federatedAuthentication>
<!--
<wsFederattion> defines parameter settings for WS-FEDERATION protocol STS.
This affects the settings for the WSFederationAuthenticationModule.
ATTRIBUTES
passiveRedirectEnabled - Boolean - default false
Controls whether the module is enabled to automatically redirect
unauthorized requests to an STS.
issuer - String - default ""
The URI of the token issuer.
realm - String - default ""
The URI of requesting realm.
freshness - Float - default ""
The value of the required freshness.
reply - String - default ""
The URI of address to reply to.
request - String - default ""
The URI of WS-FEDERATION request.
requestPtr - String - default ""
The URI of WS-FEDERATION request pointer.
resource - String - default ""
The URI of WS-FEDERATION resource value.
authenticationType – String – default “”
The wauth parameter that the application want to specify to STS
requireHttps – Boolean – default false
The Boolean flag to indicate whether to require HTTPs or not for the issuer url
signInMode – String – default “Session”
Either this is session based cookie or single use cookie
homeRealm – String – default “”
Enter a homeRealm value
signInQueryString – String – default “”
signOutQueryString – String – default “”
signOutReply – String – default “”
-->
<wsFederation passiveRedirectEnabled="true|false" issuer="http://sts.com/request.aspx" realm="http://sts.com/request.aspx" freshness="10" reply="" request="" requestPtr="" resource="" />
<!--
<cookieHandler> controls the CookieHandler, which is responsible for
reading and writing raw cookies at the HTTP protocol level.
SessionAuthenticationModule uses the cookieHandler to read and write
cookies.
MODES
Default (default)
The same as Chunked.
Chunked
Uses an instance of the ChunkedCookieHandler class. This cookie
handler ensures that individual cookies do not exceed a set maximum
size. It accomplishes that by potentially "chunking" one logical
cookie into a number of on-the-wire cookies.
Custom
Uses an instance of a custom CookieHandler-derived class, referenced
by the <customCookieHandler> element.
ATTRIBUTES
domain - String - default ""
The domain value for any cookies written.
hideFromScript - Boolean - default true
Controls whether the "HttpOnly" flag is emitted for any cookies
written. Certain web browsers honor this flag by keeping client-side
script from accessing the cookie value.
name - String - default "FedAuth"
Controls the base name for any cookies written.
path - String - default is HttpRuntime.AppDomainAppVirtualPath
Controls the path value for any cookies written.
requireSsl - Boolean - default false
Controls whether the "Secure" flag is emitted for any cookies
written. If this value is set, the sign-in session cookies
will only be available over HTTPS.
-->
<cookieHandler mode="Default|Chunked|Custom" domain=".example.com" hideFromScript="true" name="FedAuth" path="/" requireSsl="false">
<!--
<chunkedCookieHandler> may only be present if the cookieHandler/@mode
is Default or Chunked. It controls the ChunkedCookieHandler.
ATTRIBUTES
chunkSize - Int32 - default 2000
The maximum size in characters of the HTTP cookie data for any
one HTTP cookie. Care must be taken when adjusting the chunk size.
Web browsers have different limits on the size of cookies and number
per domain. The original Netscape specification stipulated these
limits: 300 cookies total, 4096 bytes per cookie header (including
metadata, not just the cookie value), and 20 cookies per domain.
-->
<chunkedCookieHandler chunkSize="2000" />
<!--
<customCookieHandler> may only be present if the cookieManager/@mode
is Custom. It references a custom type which must be derived from
CookieHandler. See the comments before the <configuration> element on
custom type references.
-->
<customCookieHandler type="MyTypes.MyCookieHandler, MyTypes" />
</cookieHandler>
</federatedAuthentication>
Note
If wauth is set by the application, then the application should also check it for its strength. WIF does not perform this check.
Note
If requiredClaims is set in the application’s configuration, the application needs to verify these claims in the ClaimsAuthenticationManager. WIF does not perform this check.