January 2009

Volume 24 Number 01

Geneva Framework - Building A Custom Security Token Service

By Michele Leroux | January 2009

This article is based on a prerelease version of the "Geneva" Framework. All information is subject to change.

This article discusses:

  • Implementing Security Token Services with Geneva Framework
  • Federated security
  • Claims transformation
This article uses the following technologies:
Windows Communication Foundation, ASP.NET, Geneva Framework

Code download available

Contents

A Security Token Services Primer
Building a Custom Active STS
Extending SecurityTokenService
Hosting and Configuring the STS
Security Token Handlers
Building a Custom Passive STS
FederatedPassiveTokenService Control
SessionAuthenticationModule
User Authentication
Claims Transformation
Wrap-Up

The Microsoft claims-basedaccess (CBA) platform strategy—code-named "Geneva"—includes the "Geneva" Framework, "Geneva" Server, and Windows CardSpace "Geneva." The Geneva Framework provides developers with tools to build claims-based applications and services that involve tokens issued by a Security Token Service (STS), as well as tools for building a custom STS and for building Windows CardSpace-enabled applications. Geneva Server is an enterprise STS, while the Geneva Framework makes it possible to build a custom STS for environments that don't require enterprise-level features. Windows CardSpace Geneva is the evolution of Windows CardSpace as the identity selector and identity provider on Windows client machines.

In my last article about the Geneva Framework I discussed a better way to build claims-based Windows Communication Foundation (WCF) services that rely on tokens issued by an STS. Here, I will build a custom STS with the Geneva Framework.

Before reading on, you should read the Geneva Framework white paper for developerswritten by Keith Brown and Sesha Mani and my last article, " Geneva Framework: A Better Approach for Building Claims-Based WCF Services."

A Security Token Services Primer

Whether the STS is based on Geneva Server or built with the Geneva Framework, its primary role is to act as a security gateway to authenticate callers and issue security tokens carrying claims that describe the caller. You'll recall from the aforementioned articles that there are several scenarios supported by STS authentication:

  • Decoupling apps and services from the authentication mechanism so that they can focus on authorizing relevant claims.
  • Supporting multiple credential types without complicating the implementation of applications and services.
  • Supporting federated scenarios where users are authenticated by their domain and granted access to resources in another domain—by establishing trust between each domain's STS.
  • Facilitating identity delegation scenarios where the authenticated user is granted access to downstream services.
  • Facilitating claims transformation so that relevant claims are available for authorization at applications and services.

Any of these scenarios can be based on passive federation (browser-based) or active federation (Windows client-based). Next, I will elaborate on these scenarios while describing how to build relevant logic into a custom STS built with the Geneva Framework.

Before diving into the implementation of an STS, let me first review some fundamentals. An STS used in active federation is an implementation of the WS-Federation Active Requestor Profile (see WS-Federation TC) and (primarily) the WS-Trust specification (see WS-Trust 1.3).

From a high level, WS-Trust describes a contract with four service operations: Issue, Validate, Renew, and Cancel. Respectively, these operations are called by clients to request a security token, to validate a security token, to renew an expired security token, or to cancel a security token that should no longer be used. Each operation is sent messages in the form of Request for Security Token (RST) and return messages in the form of RST Response (RSTR) according to the WS-Trust specification. For this article I am assuming that the issued token is a Security Assertion Markup Language (SAML) 1.1 or SAML 2.0 token.

Figure 1illustrates the core contents of the RST and RSTR for active token issuance. The RST message includes necessary information to request a security token including the type of token to issue (SAML for this discussion), the claims requested by the relying party (RP) to be included in the issued token, the information about the RP (AppliesTo) including the URL and usually the certificate identifying the RP, and optionally (not shown) key material to be used for the proof-of-possession key (proof key) returned with the RSTR.

Figure 1 Token Issuance for an Active Federation Scenario

If token issuance is successful, the RSTR will include the issued SAML token and the proof key (assuming the STS decides which proof key to use and thus must return it in the RSTR). The SAML token will include relevant claims for the authenticated party, is signed by the STS to protect the token from being tampered with, contains the proof key encrypted for the RP, and is itself encrypted for the RP so that only the intended recipient can process the token.

The client uses the proof key to sign the message to the RP. The RP must be able to decrypt the proof key inside the SAML token or reject the message. If the proof key inside the token matches the signature on the message, this proves that the call to the RP was sent by the party that requested the token.

Passive federation scenarios are based on a WS-Federation Passive Requestor Profile, which involves browser-based communication. The underlying messaging is still based on WS-Trust; however, the RST is broken into query string parameters on the STS URL, and the RSTR is typically posted to the RP as a form parameter. The passive STS and RP intercept these parameters with federation Web handlers. The passive STS may process WS-Trust requests directly or pass them to an underlying WS-Trust implementation. Figure 2illustrates how the RST and RSTR are handled in a passive federation scenario.

Figure 2 Token Issuance for a Passive Federation Scenario

One relevant difference between the active and passive federation scenarios is the type of SAML token issued. Active federation usually relies on a SAML token that uses a subject confirmation of type "holder-of-key," which means that there is a proof key used as I have described to prove that the client sending the token to authenticate is the subject that requested the token (also known as ActAs behavior). Passive federation scenarios usually involve a SAML token with a subject confirmation of type "bearer" (it is also known as a bearer token). This type of token does not include a proof key and is sometimes called a keyless token. It relies on the transport to securely procure it from the STS and transmit it to the RP.

These concepts—WS-Federation, WS-Trust, and SAML tokens—are important background information for the discussion that follows. First, I will describe how to build an active STS using the Geneva Framework. Following that, I'll discuss building a passive STS, and finally I'll present some extended scenarios for each.

Building a Custom Active STS

In a simple active federation scenario, such as that shown in Figure 3, the following participants are usually present:

  • An RP, which is the service called by a client.
  • A single STS, also implemented as a service, which supports the WS-Trust protocol. This STS authenticates callers and issues a security token with claims identifying the caller, also known as an Identity Provider or IP-STS.
  • A client, in this case a Windows-based application, that relies on a proxy to authenticate to the STS, to retrieve the resulting issued token, and to send messages to the RP supplying the issued token for authentication and authorization.

fig03a.gif

Figure 3 A Simple Federation Scenario with a Single RP and an Active IP-STS

Figure 4illustrates the moving parts behind this implementation. Included are a custom SecurityTokenService implementation, the use of a ServiceHost extension (WSTrustServiceHost) to initialize the runtime for federation, configuration of one or more WS-Trust endpoints using a derivative of the WSTrustContract type, and other related configuration settings for the identity model runtime. In the sections that are to follow, I will review each one of these elements of a custom STS implementation based on the Geneva Framework.

Figure 4 Implementation Architecture for a Custom Active STS and an Active IP-STS

Extending SecurityTokenService

The Geneva Framework provides the core functionality to build a custom STS through the SecurityTokenService type from the Microsoft.IdentityModel.SecurityTokenService namespace. This abstract class handles the heavy lifting of processing RST and RSTR messages and generating security tokens. A custom STS type inherits this class and provides (at a minimum) the following functionality:

  • A constructor that accepts a custom SecurityTokenServiceConfiguration instance to configure some basic features of the STS (to be discussed later).
  • An override for GetScope to validate the target RP for the request and to supply an appropriate encrypting credential for that RP and a signing credential for the security token.
  • An override for GetOutputClaimsIdentity to supply claims for the resulting security token.

Figure 5shows some code for a simple custom STS implementation with this functionality. Recall the flow of communication for an active STS from Figures 1and 2. The STS implementation, IdentitySTS, validates the incoming RST when GetScope is called—by verifying that the AppliesTo element of the RST indeed points to a trusted URI. Presumably the STS manages a list of trusted RPs for which tokens can be issued, along with their certificates. GetScope sets the EncryptingCredentials property of the scope to the appropriate certificate if AppliesTo passes validation, in this case "RPKey". In addition, the SigningCredentials property is set to the appropriate certificate to be used for signing the issued token. This is usually the private key of the STS, in this case "IPKey".

Figure 5 A Simple Custom STS Implementation

public class IdentitySTS : SecurityTokenService { public IdentitySTS(SecurityTokenServiceConfiguration config) : base( config ) { } protected override IClaimsIdentity GetOutputClaimsIdentity( IClaimsPrincipal principal, RequestSecurityToken request, Scope scope) { IClaimsIdentity claimsIdentity = new ClaimsIdentity(); claimsIdentity.Claims.Add(new Claim(ClaimTypes.Name, principal.Identity.Name)); claimsIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Users")); return claimsIdentity; } protected override Scope GetScope( Microsoft.IdentityModel.Claims.IClaimsPrincipal principal, RequestSecurityToken request) { Scope scope = new Scope(request); scope.EncryptingCredentials = this.GetCredentialsForAppliesTo( request.AppliesTo); scope.SigningCredentials = new X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=IPKey")); return scope; } private X509EncryptingCredentials GetCredentialsForAppliesTo(Endpoint Address appliesTo) { if (appliesTo == null || appliesTo.Uri ==null || string.IsNullOrEmpty(appliesTo.Uri.AbsolutePath)) { throw new InvalidRequestException( "AppliesTo must be supplied in the RST."); } X509EncryptingCredentials creds = null; if (appliesTo.Uri.AbsoluteUri.StartsWith( "http://localhost:8000/RelyingPartyService")) { creds = new X509EncryptingCredentials( CertificateUtil.GetCertificate(StoreName.TrustedPeople, StoreLocation.LocalMachine, "CN=RPKey")); } else throw new InvalidRequestException(String.Format( "Invalid relying party address: {0}", appliesTo.Uri.AbsoluteUri)); return creds; } }

When GetOutputClaimsIdentity is called, a ClaimsPrincipal is passed by the runtime with the authenticated caller's identity. This identity is typically used to determine the appropriate claims to grant the caller. In Figure 5the code generates a name claim and a hardcoded role claim for the caller, and it returns this in the form of a ClaimsIdentity. This ClaimsIdentity supplies claims to the runtime for the token to be issued.

This STS implementation could also be extended with the following functionality:

  • GetOutputClaimsIdentity could include code for looking up the user in a custom credential store and look up additional claims. For example, a list of roles, other relevant details about the user such as her e-mail address, or custom claims representing more granular application rights such as create, read, update, or delete.
  • GetScope could look up the AppliesTo URI in a custom database that lists all trusted RPs with their associated certificates.

Hosting and Configuring the STS

If you are familiar with WCF, you know that one or more endpoints must be configured in order for clients to send messages to a service. In the case of an STS, the service contract to be used for each endpoint must be based on WS-Trust protocol, which includes four operations: Issue, Validate, Renew, and Cancel. In fact, there are two versions of WS-Trust protocol that could be implemented by an STS:

  • WS-Trust 1.3: the latest version of the WS-Trust spec.
  • WS-Trust February 2005: the version of WS-Trust that many industry partners implemented while waiting on the standard to be ratified.

You can also provide asynchronous implementations for GetScope(), GetOutputClaimsIdentity()—among other methods—in your SecurityTokenService type. This improves scalability for I/O intensive operations such as accessing certificates or interacting with claims data. When you configure endpoints for your STS, you must select which contract to expose for the endpoint. The Micro­soft.Iden­tityModel.Protocols namespace includes these two service contracts for STS endpoints: IWSTrust13SyncContract and IWSTrustFeb2005SyncContract. Figure 6shows the configuration for an STS service with two endpoints, one for each contract. Note that there are also asynchronous versions of the contract, which would be used to implement an asynchronous proxy: IWSTrust13AsyncContract and IWSTrustFeb2005AsyncContract.

Figure 6 STS Service Config with Multiple WS-Trust Endpoints

<service name= "Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract" behaviorConfiguration="stsBehavior"> <endpoint address="WSTrustFeb05" binding="wsHttpBinding" contract="Microsoft.IdentityModel.Protocols.WSTrust. IWSTrustFeb2005SyncContract"/> <endpoint address="WSTrust13" binding="wsHttpBinding" contract="Microsoft.IdentityModel.Protocols.WSTrust. IWSTrust13SyncContract"/> </service>

The STS should expose an endpoint based on the WS-Trust February 2005 for backward compatibility with preexisting clients. The service type that implements both contracts is the WSTrustServiceContract type found in the Microsoft.IdentityModel.Protocols.WSTrust namespace. This is the type that should be referenced in the <service> configuration section for the STS.

As illustrated in the diagram in Figure 4, the <service> configuration and its endpoints are used to initialize the host with the correct WSTrustServiceContract type. This type is also initialized with a reference to the custom SecurityTokenService implementation during host initialization. That's how the runtime directs messages to the custom STS.

In Figure 6, both STS endpoints rely on Windows credentials to authenticate callers (the default behavior of wsHttpBinding). The STS can expose multiple endpoints with alternate binding configurations to support different credential types. This also involves configuring an appropriate security token handler for each credential type. I'll discuss token handler configuration settings shortly.

The Geneva Framework supplies a custom ServiceHost type, WSTrustServiceHost, to be used for hosting STS instances. The following code illustrates how to construct the WSTrustServiceHost type in a self-hosting environment:

WSTrustServiceHost stsHost = new WSTrustServiceHost(new IdentitySTSConfiguration()); stsHost.Open();

WSTrustServiceHost relies on a custom SecurityTokenServiceConfiguration instance to initialize the runtime with WS-Trust endpoints, to enable the metadata exchange behavior for the STS, and to configure a metadata exchange endpoint.

When hosted in IIS, the WSTrustServiceHostFactory type is used to achieve the same results. In the .svc file, the @ServiceHost configuration specifies the factory type and the custom SecurityTokenServiceConfiguration type, as follows:

<%@ ServiceHost Factory="Microsoft.IdentityModel.Protocols.WSTrust. WSTrustServiceHostFactory" Service="STS.IdentitySTSConfiguration" %>

The factory initializes the WSTrustServiceHost with the specified configuration upon activation.

A custom SecurityTokenServiceConfiguration type is required to initialize the WSTrustServiceHost for an STS. Figure 7shows a custom implementation called IdentitySTSConfiguration.

Figure 7 A Custom SecurityTokenServiceConfiguration

public class IdentitySTSConfiguration: SecurityTokenServiceConfiguration { public IdentitySTSConfiguration(): base("http://localhost:8010/sts") { this.TokenIssuerName = "http://localhost:8010/sts"; this.SigningCredentials = new X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=IPKey")); this.SecurityTokenService = typeof( IdentitySTS); } }

This type must provide a URI for the STS, a signing credential, and a reference to the STS type with which the configuration is associated. The URL must be valid in the event that the STS issues managed cards—so that Windows CardSpace can import those cards. The base type requires a string value to be passed to the constructor for TokenIssuerName, but I recommend overriding that in code so that you can dynamically set the URI from configuration rather than hardcoding this value passed to the constructor.

The SecurityTokenServiceConfiguration type also exposes properties that can be used to set defaults for key size and token type, to disable access to metadata, to control token lifetime and clock skew, to set custom RST and RSTR serializers, to configure token handlers that authenticate callers, and to configure WS-Trust endpoints.

The following example shows how to disable metadata access and how to initialize WS-Trust endpoints (like those shown in Figure 6) programmatically rather than relying on <service> configuration settings:

IdentitySTSConfiguration config = new IdentitySTSConfiguration(); config.DisableWsdl = true; config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration("WSTrustFeb05", new WSHttpBinding(), typeof(IWSTrustFeb2005SyncContract))); config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration( "WSTrust13", new WSHttpBinding(), typeof(IWSTrust13SyncContract))); WSTrustServiceHost stsHost = new WSTrustServiceHost(config);

The base SecurityTokenServiceConfiguration type also reads the <microsoft.identityModel> configuration section to initialize relevant STS configuration settings. Settings that can be declaratively configured for a custom STS include the maximum clock skew, security token handlers for authentication and issuance, a claims authentication manager, an issuer name registry, and token resolvers. Figure 8shows a few useful settings configured for an STS.

Figure 8 <microsoft.identityModel> Config for an STS

<microsoft.identityModel> <maximumClockSkew value="00:05:00"/> <claimsAuthenticationManager type="STS. CustomClaimsAuthenticationManager, STS"/> <securityTokenHandlers> <remove type="Microsoft.IdentityModel.Tokens. WindowsUserNameSecurityTokenHandler, Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add type="Microsoft.IdentityModel.Tokens. MembershipUserNameSecurityTokenHandler, Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <usernameSecurityTokenHandlerRequirement membershipProvider="CustomProviders.CustomMembershipProvider, CustomProviders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c03h5a64f15d0b3f" /> </add> </securityTokenHandlers> </microsoft.identityModel>

A custom ClaimsAuthenticationManager type is invoked for non-Windows credentials giving the option to supply a custom ClaimsPrincipal type to the runtime prior to issuing claims in GetOutputClaimsIdentity. Custom security token handlers might be configured to supply settings that override the default behavior of a particular handler or to alter the choice of security token handler for a particular credential type.

Security Token Handlers

You probably expect a service behavior configuration to determine how authentication and authorization will take place for each STS endpoint. Recall from my last article that the Geneva Framework does things a little differently. In the case of authentication, the <securityTokenHandlers> collection specifies the Security­TokenHandler types available to authenticate incoming requests.

This collection can only contain one entry for each SecurityTokenHandler type. For example, only one KerberosSecurityToken­Handler, UserNameSecurityTokenHandler, X509SecurityTokenHandler, Saml11SecurityTokenHandler, or Saml2SecurityTokenHandler can be registered to process requests for their respective credential type. If the STS endpoint expects a UserName credential, the default UserNameSecurityTokenHandler registered is the Windows­UserNameSecurityTokenHandler. Figure 8illustrates the removal of WindowsUserNameSecurityTokenHandler and the addition of Membership­UserNameSecurityTokenHandler as its replacement—including related config settings for the membership provider.

You can also create custom SecurityTokenHandler types. Remember, as long as they derive from the appropriate base class matching the token category (such as UserNameSecurityTokenHandler), you can replace the default handler with the new custom handler. Figure 9illustrates a custom UserNameSecurityTokenHandler implementation named CustomUserNameSecurity­TokenHandler.

Figure 9 A Custom UserNameSecurityTokenHandler

public class CustomUserNameSecurityTokenHandler: UserNameSecurityTokenHandler { public override ClaimsIdentityCollection ValidateToken(SecurityToken token) { UserNameSecurityToken userNameToken = token as UserNameSecurityToken; AuthenticateUser(userNameToken.UserName, userNameToken.Password); return new ClaimsIdentityCollection(new IClaimsIdentity[] { new ClaimsIdentity( new Claim(System.IdentityModel.Claims.ClaimTypes.Name, userNameToken.UserName), "CustomUserNameSecurityTokenHandler")}); } public override bool CanValidateToken { get { return true; } } }

At a minimum, ValidateToken and CanValidateToken must be overridden in the custom SecurityTokenHandler implementation. Inside ValidateToken you are responsible for authenticating against the appropriate credential store. The results of that authentication should be a set of claims that can be returned to the runtime to be attached to the ClaimsPrincipal for the request thread.

fig10.gif

Figure 10 A Simple Federation Scenario with a Single RP and a Passive IP-STS

It is also very important to override CanValidateToken and return True. Without this override, the token handler will not be registered in the collection and it will never be invoked.

Building a Custom Passive STS

In a simple passive federation scenario, the same participants are present, as shown in Figure 3, for an active federation scenario—except that the client is a browser, the RP is a Web application, and the IP-STS is also fronted by a Web application to handle HTTP-based communication. Figure 10illustrates the participants and flow of communication for passive federation.

The moving parts behind this scenario are similar to those shown in Figure 4, as far as the core STS is concerned, but there are some obvious differences in how the passive STS handles authentication and in how the underlying STS functionality is invoked. The diagram in Figure 10illustrates these differences from a high level. The passive STS is implemented as a Web site that requires SSL encryption to secure the token issuance process. The default page (Default.aspx) hosts a control that facilitates communication with the underlying custom STS, which is configured just like an active STS.

The STS site must authenticate the caller prior to token issuance, and this is where classic ASP.NET configuration comes into play for authentication and authorization. In Figure 11, the STS application is configured for Forms authentication, so requests are redirected to a login page (Login.aspx) if they have not yet been authenticated by the FormsAuthenticationModule.

A passive STS can share the same core STS implementation as an active STS—with one minor change. In the GetScope override (shown in Figure 5) a passive STS must set the ReplyToAddress property so that the STS can redirect after issuing the token. Usually this is set to the default page for the RP, based on the AppliesTo address supplied with the RST:

Scope scope = new Scope(request); scope.ReplyToAddress = scope.AppliesToAddress + "/default.aspx"; // other scope settings

Figure 11 Implementation Architecture for a Passive STS Using Forms Authentication

The Geneva Framework configuration for a passive STS is no different from an active STS. A SecurityTokenService­Configuration type is used to initialize the STS (shown in Figure 7), and any relevant settings in the <microsoft.identityModel> configuration section are also considered.

FederatedPassiveTokenService Control

The Geneva Framework provides a control that implements the required functionality of a passive STS. That is, it processes sign-in and sign-out HTTP requests, converting each request into an RST and then invoking the underlying STS implementation. The control also processes RSTR responses and handles redirection to the RP, and writing the session cookie for authenticated callers.

Place this control on the default page for the passive STS site and set its Service property to the custom SecurityTokenService­Configuration implementation as follows:

<idfx:FederatedPassiveTokenService ID="FederatedPassiveTokenService1" runat="server" Service="STS.IdentityProviderSTSConfiguration, STS"> </idfx:FederatedPassiveTokenService>

The control requires that the user is authenticated and checks this in its PreRender event. It is expected that the STS site is configured appropriately to ensure that users are redirected elsewhere to authenticate prior to reaching this default page.

As long as authenticated users are always directed to this default page, no other configuration is required to process requests. The control also provides the Error, PreSignInRequested, PostSignInRequested, PreSignOutRequested, and PostSignOut­Requested events to handle exceptions, and to hook sign-in and sign-out requests.

SessionAuthenticationModule

As an alternative to the FederatedPassiveTokenService control, you can programmatically enable passive STS functionality. First enable federated authentication in the <microsoft.identityModel> configuration section:

<microsoft.identityModel> <federatedAuthentication enabled="true"/> </microsoft.identityModel>

Next, enable the federation module for a passive STS, the Session­AuthenticationModule from the Microsoft.IdentityModel.Web namespace:

<modules> <add name="SessionAuthentication" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </modules>

This produces the same result as the FederatedPassiveTokenService control for requests sent to any page in the STS Web site. The module redirects unauthenticated callers to the login page. Upon successful login, callers are redirected to the STS page originally requested. This programmatic approach gives developers additional control beyond that provided by the FederatedPassiveTokenService control. For example, the module exposes the following events to interact with initialization, security token management, sign in, and sign out: ConfigurationLoading, ConfigurationLoaded, SecurityTokenReceived, SecurityTokenValidated, SessionSecurityTokenCreated, SessionSecurityTokenReceived, SignedIn, SigningOut, SignedOut, SignInError, and SignOutError.

User Authentication

The STS site is responsible for authenticating users according to supported credential types. While an active STS implemented with WCF can easily configure multiple endpoints to support different authentication mechanisms, a passive STS can only support one authentication mechanism by nature of the ASP.NET Web site configuration. Thus, a different passive STS site must be provided for each supported authentication mechanism. These sites can all share the same core STS implementation, of course.

Passive STS authentication is based on ASP.NET configuration techniques. Typical choices are Windows authentication, Forms authentication, and Windows CardSpace authentication. In the case of Windows authentication, the following configuration is used:

<authentication mode="Windows"/> <authorization> <deny users="?"/> </authorization>

The user will be authenticated through interactive dialogs prior to reaching the default page of the STS, so a custom login page is not required in this case.

Figure 11 illustrates an example whereby Forms authentication is used. The FormsAuthenticationModule redirects unauthenticated calls to the login page where the user can supply credentials. Once authenticated, the login page will redirect to the default STS page where the federation control will proceed to process the original request. The ASP.NET configuration for this would be as follows:

<authentication mode="Forms"/> <authorization> <deny users="?"/> </authorization>

In the case of Windows CardSpace authentication, the STS site can be configured for Forms authentication, but the login page will include an InformationCard control for Windows CardSpace authentication.

Claims Transformation

Claims transformation is essential to federated security—and this can happen at a variety of points in the flow of federation. In a simple federation scenario where the IP-STS and RP belong to the same domain, the IP-STS is responsible for transforming claims from the initial set of identity claims that the user presents during authentication, to those that the RP can rely on to authorize calls. Users can present any of the supported credential types to authenticate to the IP-STS, each evaluating to a set of claims representative of the credential.

The IP-STS transforms these claims into a normalized set of application claims that the RP relies on to authorize calls—which can be roles or more granular claims such as create, read, update, or delete rights. The diagram in Figure 12illustrates such a scenario where the Admin user logs in and is granted a Role claim and several Action claims including Create, Read, Update, and Delete.

fig12.gif

Figure 12 Claims Transformation at the IP-STS

This type of claims transformation is useful in that authentication to an STS results in a token carrying all of the claims granted to the user. There are cases where an alternate approach to claims transformation would be necessary; for example, to reduce the claims issued to those relevant only for the current call context; to protect the privacy of claims; or to facilitate federation across domains.

It isn't always desirable or appropriate to grant an authenticated caller a long list of claims related to all features exposed by the RP. Not only could the list be very long, but it is also possible that the claims to be granted depend on the call context and thus should not be issued without that context. For example, a user may only be granted the Delete claim if she is interacting with customer orders, but if she is interacting directly with customer records, she may not be granted that right.

In cases such as this one, it can be useful for the RP to request only a few claims from the IP-STS in order to identify the caller, and then request a new token with a specific set of additional claims only for the context of the call. For example, if the user is invoking the DeleteCustomer operation on an RP service, prior to authorizing access to the operation the RP calls to the RP-STS passing in the token from the IP-STS, requesting the Delete claim in the context of the DeleteCustomer operation. If the claim is present, the call is authorized. The diagram in Figure 13illustrates this example.

There are also cases where the claims issued by an STS should not be shared with the RP directly. For example, rather than issuing an Age claim so that the RP knows the user's age, the RP can request the IsOver13 claim to ensure that the caller is old enough to use RP functionality. Thus, the actual value for the Age claim never leaves the STS. Of course, this implies that the ST supplies claims that avoid sharing personal details and yet still include data useful to the RP.

fig13.gif

Figure 13 Claims Transformation at the RP-STS

Claims transformations also take place in a federated scenario where users belonging to one domain are granted access to an RP in another domain. In this case there are two STS involved—the user domain's IP-STS and the RP-STS for the domain that owns the RP.

And also in this case, IP-STS will grant some agreed-upon claims that RP-STS can understand; however, those claims are not likely to be directly useful in the RP application. Instead, the RP-STS would be responsible for transforming another trusted set of claims into claims that are understood in the RPs domain.

Figure 14illustrates this scenario. When Joe tries to access the RP without a token, he will log in at the IP-STS in his own domain (Domain B). The request will ask for claims that the RP understands, in this case RPClaim, so that the IP-STS knows to issue a token that the RP can use. When the RP-STS receives this token it transforms the claims into RP-specific claims. For this federated scenario to work, there must be trust between the RP-STS and the IP-STS, and they must agree on a set of claims that the IP-STS should issue for its users that are to be granted access to the RP.

fig14.gif

Figure 14 Claims Transformation in a Federated Scenario

Wrap-Up

The Geneva Framework is a very welcome utility for those interested in building a custom STS and who do not need a fully featured STS platform such as Geneva Server. Building a custom STS is not a trivial task, even with the Geneva Framework, and it is always recommended that you use a fully featured STS if possible to reduce exposure.

Regardless of the platform, the flow of communication for active and passive STS implementations remains the same, as do the ideas behind claims transformation. Some additional concepts related to STS implementations include identity delegation and step-up authentication. You can access samples and documentation related to these and other concepts in the Geneva Framework SDK.

Michele Leroux Bustamante is Chief Architect of IDesign Inc., Microsoft Regional Director for San Diego, and a Microsoft MVP for Connected Systems. Her latest book is Learning WCF. Reach her at mlb@idesign.netor visit idesign.net. Michele blogs at dasblonde.net.