Geneva Framework

A Better Approach For Building Claims-Based WCF Services

Michele Leroux Bustamante

Code download available from the MSDN Code Gallery

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

This article discusses:

  • Implementing security with the Geneva Framework
  • WCF security
  • Claims-based security
  • Security Token Services
This article uses the following technologies:
Windows Communication Foundation

Contents

Why Claims-Based Security?
Security Token Services
Support for Claims-Based Security
WCF Services, before the Geneva Framework
Issued Tokens and WSFederationHttpBinding
Enable the Geneva Framework for WCF Services
Demanding Claims
Configuring <microsoft.identityModel>
Hooking the Geneva Framework with IIS Hosting
From WCF to the Geneva Framework
Migrate Applications to the Geneva Framework

The "Geneva" Framework , formerly called "Zermatt," is the code name for the new framework for building claims-based applications and services, and for implementing federated security scenarios. Features include the plumbing to build a custom Security Token Service (STS); a mechanism to require federated authentication from ASP.NET applications; and an object model that facilitates claims-based authorization for ASP.NET applications and Windows Communication Foundation (WCF) services.

The Geneva Framework also includes features that support Windows CardSpace such as managed information card issuance and ASP.NET controls that simplify the creation of a Windows CardSpace login experience. (Read more about Windows CardSpace in " Identity: Secure Your ASP.NET Apps and WCF Services with Windows CardSpace ".) Clearly, the Geneva Framework spans the breadth of security features, but at its core is claims-based security.

While WCF has always had native support for a claims-based security model, the Geneva Framework enhances this experience by simplifying access to claims at run time and providing a mechanism to support claims-based authorization in a manner that is consistent with the role-based authorization principals already available in the Microsoft .NET Framework. ASP.NET applications utilize the Geneva Framework for claims-based authorization features compatible with existing ASP.NET login controls that enforce role-based security. In this article I will focus on the value of implementing a claims-based security model, describe how to approach claims-based WCF services using the Geneva Framework, and discuss how this compares to the way in which WCF handles claims-based security without the Geneva Framework.

Before you continue reading, I recommend that you take a look at the Geneva Framework white paper for developers, written by Keith Brown and Sesha Mani. This will provide you with an overview of the features in the Geneva Framework, as well as some background on claims-based security concepts, and explain how to enable these features in ASP.NET applications and WCF services, with an emphasis on the former. In addition, you can learn more about WCF and claims-based security in Keith Brown’s Security Briefs column published in September 2007.

Why Claims-Based Security?

Why do you want to move to a claims-based security model? Before you consider implementing a solution with the Geneva Framework you must know the answer to this question. It is true that role-based security is often sufficient if you assume that the definition of application roles never changes and that only a single authentication mechanism will map a security principal to those roles. But it helps to design applications and services so that they aren't tied to a particular credential type or to a particular set of roles. This is one of the value propositions of a claims-based security model.

Decoupling applications and services from roles allows the name and meaning of roles to change without affecting the system. Authenticated users can be assigned a more granular artifact for authorization—a claim. Claims can be assigned based on the authenticated user, as shown in Figure 1 , or assigned based on the authenticated user's roles, as shown in Figure 2 .

fig01a.gif

Figure 1 Assigning Claims Based on the Authenticated User

fig02a.gif

Figure 2 Assigning Claims Based on the Authenticated User’s Roles

The latter still supports a model where authorization is performed based on claims, while using roles as a way to group claims more easily behind the scenes. From this perspective, claims-based security has properties similar to permission-based security, although claims are guaranteed by a trusted issuer, which has added security benefits. (Note that Figures 1 and 2 illustrate the use of the assignment of a name claim for the authenticated user and the assignment of several custom permission claims—Create, Read, Update, and Delete.)

Authorizing access based on claims is most useful when the association between a claim and the functionality or resources to which it grants rights does not change (at least not frequently). Meanwhile, the rules for how users and roles are assigned claims can change freely without impacting authorization logic. For example, the Delete claim is likely to be required by all delete operations in the system, while the Administrators role may not always grant that claim if a new Super­Users role is introduced.

A claims-based security model can also help applications and services support multiple credential types. A simple (and common) example is an application that relies on Windows credentials for internal users on the same domain, and custom username and password accounts for external users outside of the domain. Supporting multiple credential types can complicate the authentication process and related authorization code. ASP.NET applications that support multiple credential types add complexity in terms of login support, configuration, and initialization of roles for each credential type.

WCF services also require additional work to support different credential types in terms of behavior configuration for the different credentials, and proper initialization of the AuthorizationContext. If ASP.NET applications and WCF services can receive a credential that carries required claims (be they roles or otherwise), authorization efforts can be normalized to a common set of rules regardless of how the user was authenticated.

Ideally, an STS would handle authentication of the different credential types and handle the generation of a security token that carries those claims. This token, likely a SAML (Security Assertion Markup Language) token, can then be used to authenticate to the service based on its digital signature—and the claims it yields can be used to authorize access.

Federated security scenarios are also a natural fit for claims-based security. In a federated security scenario users are authenticated by their own security domain and a token is issued by that domain to be used to authenticate to another domain.

Security Token Services

An STS plays an important role in a claims-based security scenario—whether or not it's a federated scenario. To authorize access based on claims, a trusted set of claims must be available to the application. An STS can issue a security token with the requested claims after authenticating the user. The application need only trust the security token—which usually means trusting its digital signature. Figure 3 illustrates two applications (relying parties)—a WCF service and an ASP.NET application—that trust SAML tokens issued by an STS. The high-level flow of communication is as follows:

fig03b.gif

Figure 3 Relying Party Trusting Tokens Issued by an STS

  1. Users authenticate to the STS.
  2. The STS assigns claims for the authenticated user and builds a SAML token to carry those claims (as SAML attributes). The STS signs the token with its private key (IPKey) and encrypts it for the application using the public key (RPKey) provided with the request.
  3. The client app or browser presents the token to the app (relying party). The token is passed with the message in the WCF scenario and passed as a cookie in the ASP.NET scenario. If the token signature is trusted (IPKey), the claims within are trusted for authorization.

If multiple credential types are to be supported by an application or service, the STS can handle the authentication step for each credential type and issue a security token carrying claims appropriate for each authenticated user. Once again, the application need only trust the security token—and is blissfully unaware of the credential types that the STS supported to authenticate each user. Figure 4 illustrates an STS that accepts Windows, username and password, certificate, or SAML tokens for authentication—and generates appropriate claims for the authenticated user.

fig04b.gif

Figure 4 An STS Authenticating Multiple Credential Types

Figures 3 and 4 illustrate scenarios where an STS is employed within the same security domain. In a federated scenario, a trust relationship is established between two or more security domains so that users can authenticate to the domain that manages their credentials while still being granted access to resources in another domain.

Federation reduces many risks related to identity management. It removes the need to maintain user credentials across multiple applications or domains—which helps to reduce risks associated with provisioning and deprovisioning accounts across domains such as forgetting to delete an account in multiple places. Password synchronization when multiple copies of an account aren't managed will also cease to be a problem. In addition to these benefits, federation also facilitates Single Sign-On (SSO) scenarios since users can log in to one application and be granted access to another (possibly across security domains) without having to authenticate again. Figure 5 illustrates a federated scenario for a Web application. The flow is as follows:

  1. User browses to the Web application in Domain B and is authenticated by the STS in Domain B.
  2. The STS issues a SAML token for the user, which is returned as a cookie to the browser.
  3. User browses to the Web application in Domain A, passing the SAML token as a cookie.
  4. The token signature is trusted by the STS in Domain A because of the trust relationship with the STS in Domain B.
  5. The STS in Domain A issues a new SAML token for the user, with claims relevant to Domain A. This token is returned as a cookie to the browser.

fig05.gif

Figure 5 A Federated Scenario Illustrating Trust between Domains
(Click the image for a larger view)

The trust relationship between the STS in Domain A and the STS in Domain B means that the former will accept tokens issued by the latter as proof of authentication. Claims issued by Domain B may include user information (username, e-mail address, and so forth) and rights that are understood by Domain A (that is Domain­AReadOnly). Domain A may convert these partner claims to claims meaningful to the application hosted by Domain A—for example, granting the Read claim.

Claims issued by an STS are open-ended, which means there are many potential configurations to these scenarios involving delegation of authentication and federation—but this should provide you with a fundamental understanding of why claims-based security is useful and how those claims might be issued. Now I will move on to some implementation details for WCF services and ASP.NET applications.

Support for Claims-Based Security

The Geneva Framework has many features, as discussed in the white paper I mentioned earlier. You can use the Geneva Framework to build a custom STS without writing all of the plumbing to expose WS-Trust endpoints or build SAML tokens that carry claims. With this framework you can also issue managed Information Cards to support identity selectors such as Windows CardSpace on the Windows platform. You can more easily support Windows CardSpace login in ASP.NET applications, and you can leverage integrated claims-based support for WCF services and ASP.NET applications.

The primary goal of the Geneva Framework is to make it easier to build claims-based applications. This is done with claims-based extensions to the existing role-based security model common to all .NET-based apps, with hooks that process security tokens to extract claims for each respective runtime to interact with, and in the case of ASP.NET, with a mechanism for triggering calls to an STS that can issue tokens carrying the required claims of the application.

WCF Services, before the Geneva Framework

WCF services were designed to support claims-based security from the beginning. When a message is sent to a service operation, each security token supplied with the message is converted to a set of claims accessible through the ServiceSecurityContext for the executing operation. If the security token is a Windows or UserName token, developers would typically rely on the security principal attached to the request thread to authorize calls using classic role-based security. If the security principal is a certificate or SAML token, the claims become more meaningful and developers are likely to access the AuthorizationContext to evaluate claims.

Consider an example in which a WCF service exposes Create, Read, Update, and Delete (CRUD) operations and expects to authorize calls based on the user's CRUD rights to the application. The DeleteSomething operation requires the authenticated caller to have delete rights, indicated by a custom permission claim like those shown in Figures 1 and 2 . The code to search the Authorization­Context for the Delete claim is shown in Figure 6 . The code traverses the claim sets in the AuthorizationContext looking for this claim. If it isn't found in any of the trusted claim sets, a Security­Exception is thrown. The code to search the AuthorizationContext this way is cumbersome, to say the least. The Geneva Framework provides an alternate approach to evaluating claims that greatly simplifies claims-based authorization in WCF.

Figure 6 WCF AuthorizationContext for a Permission Claim

public string DeleteSomething() {
    AuthorizationContext authContext = 
      ServiceSecurityContext.Current.AuthorizationContext;

    bool foundClaim = false;
    foreach (ClaimSet cs in authContext.ClaimSets) {
        Claim claim = new Claim("https://schemas.contoso.com/samples/
          2008/09/claims/permission","Delete", Rights.PossessProperty);

        if (cs.ContainsClaim(claim)) {
            foundClaim = true;
            break;
        }

    }

    if (!foundClaim)
        throw new SecurityException(
          "Access is denied. Required claims not satisfied.");

    return String.Format("DeleteSomething() called by user {0}", 
      System.Threading.Thread.CurrentPrincipal.Identity.Name);
}

Issued Tokens and WSFederationHttpBinding

WCF supplies federation bindings to support scenarios in which the WCF service expects a token issued by an STS. Typically this implies a SAML token, although this is not a strict requirement. WSFederationHttpBinding is the original standard binding that supports issued tokens, and WS2007FederationHttpBinding is an update to this binding supporting the final release of the WS-* protocols underlying the binding. For the purpose of this discussion, I will use WSFederationHttpBinding to configure WCF service endpoints that require a SAML 1.1 token issued by a custom STS built with the Geneva Framework.

For this example the service contract, ICrudService, has four service operations, as shown in Figure 7 . These operations are indicative of CRUD operations, and the service implementation will rely on CRUD permission claims like those shown inFigures 1 and 2 to authorize access to each operation.

Figure 7 WCF Service Contract Exposing CRUD Operations

[ServiceContract(Namespace="https://www.contoso.com/samples/2008/09")]
public interface ICrudService
{
  [OperationContract]
  string CreateSomething();

  [OperationContract]
  string ReadSomething();

  [OperationContract]
  string UpdateSomething();

  [OperationContract]
  string DeleteSomething();
}

Figure 8 illustrates a sample WCF configuration with a single service exposing a WSFederationHttpBinding endpoint and its associated behavior configuration. The binding configuration includes settings indicating the required token format (SAML 1.1), required Claim types (name and permission claim), and the STS WS-Trust endpoint address and metadata exchange address. This configuration provides enough information for clients to generate a proxy that is capable of authenticating to the STS to retrieve the SAML token, and using that token to authenticate to the WCF service.

Figure 8 WCF Configuration with a WSFederationHttpBinding Endpoint

<system.serviceModel>
  <services>
   <service name="ClaimsBasedServices.CrudService" 
    behaviorConfiguration ="serviceBehavior">
    <endpoint contract="ClaimsBasedServices.ICrudService" binding=
     "wsFederationHttpBinding" bindingConfiguration="wsFed"/>
      <endpoint contract="IMetadataExchange" binding="mexHttpBinding"
          address="mex"/>
   </service>
  </services>
  <bindings>
   <wsFederationHttpBinding>
    <binding name="wsFed" >
      <security mode="Message">
        <message issuedTokenType="https://docs.oasis-open.org/wss/
          oasis-wss-saml-token-profile-1.1#SAMLV1.1" >
          <claimTypeRequirements>
            <add claimType="https://schemas.xmlsoap.org/ws/2005/05/
              identity/claims/name" isOptional="false"/>
            <add claimType="https://schemas.contoso.com/samples/2008/09/
              claims/permission" isOptional="false"/>
          </claimTypeRequirements>
           <issuer address="https://localhost:51213/TokenIssuer/Service.svc" />
           <issuerMetadata address="https://localhost:51213/TokenIssuer/
              Service.svc/mex" />
        </message>
      </security>
    </binding>
   </wsFederationHttpBinding>
  </bindings>
  <behaviors>
   <serviceBehaviors>
    <behavior name="serviceBehavior">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceCredentials>
        <issuedTokenAuthentication allowUntrustedRsaIssuers="false">
          <knownCertificates>
            <add findValue="IPKey" storeLocation ="LocalMachine"
             storeName="TrustedPeople" x509FindType "FindBySubjectName"/>
          </knownCertificates>
        </issuedTokenAuthentication>
        <serviceCertificate findValue="RPKey" storeLocation=
         "LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
      </serviceCredentials>
      <serviceAuthorization principalPermissionMode="None" />
    </behavior>
   </serviceBehaviors>
  </behaviors>
</system.serviceModel>

The service behavior configuration has some settings worth pointing out. Inside <serviceCredentials>, the <issuedToken­Authentication> section indicates how the SAML token should be authenticated. This configuration indicates that only trusted issuers are allowed, which means that the SAML token must be signed by a known certificate. The known certificate in this scenario has the subject name IPKey. The STS will use IPKey to sign the SAML token; thus, any claims contained within the SAML token will be trusted. This section is still relevant when the Geneva Framework is enabled, even though the Geneva Framework also has a configuration for specifying trusted issuers.

The <serviceAuthorization> section influences the type of security principal attached to the request thread after authentication takes place. Normally, for an issued token scenario, you would configure this to "Custom," which requires you to specify a custom authorization policy (a type that implements IAuthorizationPolicy). The authorization policy is responsible for creating the security principal (the IPrincipal type) for the request thread and for attaching any relevant claims to the AuthorizationContext. This is set to None in this case because it will no longer be useful once the WCF service is Geneva Framework-enabled.

Enable the Geneva Framework for WCF Services

A claims-based security model based on Geneva Framework features can be achieved with just a few simple steps. The first step is to add a reference to the Microsoft.Identity assembly—the core assembly belonging to the Geneva Framework. Next, the ServiceHost for each WCF service must be initialized for the Geneva Framework runtime features, which includes registering a list of trusted token issuers to the ServiceHost. The end result of configuring this framework is that a security principal is attached to the request thread for each call—carrying a collection of claims from trusted issuers for authorization.

FederatedServiceCredentials is a derivative of the Service­Credentials type that exposes a static method to initialize the Service­Host instance for the Geneva Framework. Figure 9 illustrates where the code to initialize the ServiceHost fits in the context of initialization.

Figure 9 Initialize the ServiceHost for Geneva Framework

ServiceHost host = new ServiceHost(typeof(Services.RelyingParty));
try
{
  FederatedServiceCredentials.ConfigureServiceHost(host, new 
                                      TrustedIssuerNameRegistry());
  host.Open();
  Console.ReadLine();
}
finally
{
  if (host.State != CommunicationState.Faulted)
    host.Close();
  else
    host.Abort();
}

public class TrustedIssuerNameRegistry : IssuerNameRegistry
{
    public override string GetIssuerName(SecurityToken securityToken)
    {
        X509SecurityToken x509Token = securityToken as X509SecurityToken;
        if (x509Token != null)
        {
            if (x509Token.Certificate.SubjectName.Name == "CN=IPKey")
            {
                return x509Token.Certificate.SubjectName.Name;
            }
        }
        throw new SecurityTokenException("Token signature is not trusted
                                         by the issuer name registry. ");
    }
}

The ConfigureServiceHost method is called before the ServiceHost instance is opened. This method performs the following key actions. It reads the <microsoft.identityModel> configuration section to initialize aspects of the runtime such as token handlers, trusted issuers, and maximum clock skew for token validity. Then it sets the principalPermissionMode (see Figure 8 ) to Custom and adds a custom authorization policy (IAuthorizationPolicy type) named ServiceAuthorizationPolicy. ServiceAuthorizationPolicy is responsible for creating the ClaimsPrincipal type and initializing Thread.CurrentPrincipal. It also removes other authorization policies and clears the claim sets added to the AuthorizationContext for the request. That's because the Geneva Framework expects you to rely on the ClaimsPrincipal to evaluate claims going forward, rather than using the AuthorizationContext.

The code in Figure 9 passes an implementation of the IssuerName­Registry type to ConfigureServiceHost, which eliminates the need to specify this type in the <microsoft.identityModel> configuration section. The override for GetIssuerName is responsible for checking the signing token against a list of trusted issuers. This example uses a hardcoded trusted issuer name, IPKey. Later I will discuss elements of the <microsoft.identityModel> section as it relates to configuring the Geneva Framework for WCF services.

Demanding Claims

Once the service is Geneva Framework-enabled, a ClaimsPrincipal instance will be attached to each request thread, carrying claims for the authenticated user. To authorize access to application code and resources, you can traverse the collection of claims for a particular Claim type and value. The following code accesses the Claims collection exposed by the ClaimsIdentity type, searching for the role claim with a Uri value for the Administrators role:

ClaimsIdentity identity =     Thread.CurrentPrincipal.Identity as ClaimsIdentity;
if (!identity.Claims.Exists(c=>
    c.ClaimType=="https://schemas.microsoft.com/ws/2006/04/identity/
    claims/role" && c.Value=="https://schemas.contoso.com/
    samples/2008/09/roles/administrators"))
throw new SecurityException("Access is denied.");

The Claims collection may carry claims from different issuers, so it is possible to check for a claim from a particular issuer. This is usually an unnecessary step, however, since once it is established that the issuer is trusted, it shouldn't matter who issued the claim when authorizing access.

Although direct access to the Claims collection through the ClaimsIdentity instance is convenient, the ClaimsPrincipal provides an IsInRole implementation that can be used to demand role claims as follows:

if !Thread.CurrentPrincipal.IsInRole
    ("https://schemas.contoso.com/samples/2008/09/roles/administrators"))
  throw new SecurityException("Access is denied.");

This approach assumes that the STS issues role claims with the appropriate values relevant to the application. The role claim in the Geneva Framework is indicated by the following Uri by default: "https://schemas.microsoft.com/ws/2006/04/identity/claims/role." The actual role can be any string, but in this case it's a custom Uri indicating an application role: "https://schemas.contoso.com/samples/2008/09/roles/administrators."

While IsInRole is a convenient way to perform claims-based security checks, it is also possible to perform classic permission demands using PrincipalPermission and PrincipalPermission­Attribute. These both rely on an IPrincipal type attached to the request thread—in this case a ClaimsPrincipal will do the trick.

Programmatic demands can be performed dynamically:

PrincipalPermission p = new PrincipalPermission(null,
    "https://schemas.contoso.com/samples/2008/09/roles/administrators",
    true);
    p.Demand();

Demand executes an IsInRole check against the thread's Claims­Principal and throws an exception if the demand can't be satisfied—or, put another way, if the specified role claim is not found. A collection of PrincipalPermission instances can be grouped into a PermissionSet to check for one of several roles being satisfied.

An even more elegant solution, of course, is to apply the Principal­PermissionAttribute to service operations as follows:

[PrincipalPermission(SecurityAction.Demand, Role = 
    "https://schemas.contoso.com/samples/2008/09/roles/administrators")]
    public string CreateSomething()

This attribute constructs the PrincipalPermission type and performs the same demand, but it does so before executing the operation to which it is applied. The beauty of this model is its declarative nature—developers can see the roles required by their service operations. This attribute can also be stacked so that more than one role will satisfy the permission demand.

Configuring <microsoft.identityModel>

The Geneva Framework relies on a new configuration section to initialize its environment: <microsoft.identityModel>. As discussed in the white paper mentioned earlier, this configuration section is used by Geneva Framework features for ASP.NET and WCF applications—but in this section I'll focus on core elements relevant to Geneva Framework-enabled WCF services.

To enable support for this new section, the following must appear in your app.config or web.config (depending on the hosting model for your WCF services):

<configSections>
    <section name="microsoft.identityModel" 
      type="Microsoft.IdentityModel.Configuration.
      MicrosoftIdentityModelSection,
      Microsoft.IdentityModel, 
      Version=0.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</configSections>

The <microsoft.identityModel> configuration section does not have any required elements, but you can supply any of the core settings to provide declarative initialization of the elements listed in Figure 10 .

Figure 10 Initialize the ServiceHost for Geneva Framework

Name Description
audienceUris Indicate the allowed audience Uris for SAML token processing. Refers to a feature of the SAML token that can restrict where the token can be used by providing a specific Uri. If this is present in the SAML token, the service can check it against its list of allowed Uris to verify that the token was intended for one of those trusted Uris. Prevents malicious use of tokens.
issuerNameRegistry Used to declaratively indicate the issuerNameRegistry type that will be used to validate token signatures.
maxClockSkew Provides control over the valid time window for a token to prevent replay attacks.
securityTokenHandlers Used to customize token handler type for issued tokens. For example, there's a SAML 1.1 and SAML 2.0 handler. In this section you can customize the settings for the token handler or replace the token handler. A customization might be to provide alternate role claim types.

An example of the configuration section to initialize these values is shown in Figure 11 . When the issuerNameRegistry type is specified in configuration, initialization of the service host shown in Figure 9 would change to the following:

FederatedServiceCredentials.ConfigureServiceHost(host);

Figure 11 Core Geneva Framework Features for WCF

<microsoft.identityModel>
  <issuerNameRegistry type="Services.TrustedIssuerNameRegistry,
    Services"/>
  <SecurityTokenHandlers>
    <remove type="Microsoft.IdentityModel.Tokens.Saml11.
      Saml11SecurityTokenHandler, Microsoft.IdentityModel,Version=0.4.1.0, 
      Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <add type="Microsoft.IdentityModel.Tokens.Saml11.
      Saml11SecurityTokenHandler, Microsoft.IdentityModel,
      Version=0.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      <samlSecurityTokenRequirement audienceUriMode="Never">
        <nameClaimType value="https://schemas.contoso.com/ws/2005/05/
          claims/name"/>        
        <roleClaimTypes>
          <add value="https://schemas.contoso.com/samples/2008/09/claims/
          permission"/>
        </roleClaimTypes>
      </samlSecurityTokenRequirement>
    </add>
  </SecurityTokenHandlers>
</microsoft.identityModel>

As for the token handlers, you can either create a custom security­TokenHandler or use this section to initialize features for an existing token handler—the latter of which is shown in Figure 11 . In this example, the SAML 1.1 token handler is initialized with custom name and role claim types (recall from the earlier white paper that the role claim type collection is likely to become a single value rather than a collection in a future release of the Geneva Framework). The role claim type specified here is "schemas.contoso.com/samples/2008/09/claims/permission", which means that the STS can issue permission claims like those indicated in Figure 1 or 2 —and the WCF service can execute permission demands for the specified permission using the classic role-based security methods discussed earlier.

Hooking the Geneva Framework with IIS Hosting

Depending on your experience level with WCF, you may or may not be familiar with the mechanism for custom ServiceHost initialization when services are hosted in IIS, which you'll need to know so that you can enable the Geneva Framework for the ServiceHost. To hook ServiceHost initialization, you provide a custom ServiceHostFactory type in the @ServiceHost directive as follows:

<%@ ServiceHost Factory="ClaimsBasedServices.
    ClaimsBasedServiceHostFactory"
    Service="ClaimsBasedServices.CrudService" %>

In this example, the ClaimsBasedServiceHostFactory type is responsible for constructing the ServiceHost instance for the specified service type. You can either construct the ServiceHost type directly in the factory and initialize it for Geneva Framework services prior to passing the instance to the runtime, or you can create a custom ServiceHost type and override the InitializeRuntime method to supply custom code prior to opening the service channel. The latter is shown in Figure 12 .

Figure 12 Enable Geneva on IIS-Hosted WCF Services

public class ClaimsBasedServiceHostFactory: ServiceHostFactory
{
        public ClaimsBasedServiceHostFactory()
        {
        }

        public override System.ServiceModel.ServiceHostBase CreateServiceHost(
                                   string constructorString, Uri[] baseAddresses)
        {
            Type t = Type.GetType(string.Format("{0}, {1}", constructorString, 
                constructorString.Substring(0, constructorString.IndexOf("."))));
            return new ClaimsBasedServiceHost(t, baseAddresses);
        }

        protected override System.ServiceModel.ServiceHost CreateServiceHost(
                                           Type serviceType, Uri[] baseAddresses)
        {
            return new ClaimsBasedServiceHost(serviceType, baseAddresses);
        }
}

public class ClaimsBasedServiceHost: ServiceHost
{
        public ClaimsBasedServiceHost(object singletonInstance, params Uri[]
                           baseAddresses): base(singletonInstance, baseAddresses)
        {
        }

        public ClaimsBasedServiceHost(Type serviceType, params 
                          Uri[] baseAddresses) : base(serviceType, baseAddresses)
        {
        }

        protected override void InitializeRuntime()
        {
            FederatedServiceCredentials.ConfigureServiceHost(this, new 
                                                    TrustedIssuerNameRegistry());
            base.InitializeRuntime();
        }
}

From WCF to the Geneva Framework

There are some common questions that are likely to surface when you enable the Geneva Framework for your WCF services—particularly if you are a seasoned WCF developer who has already implemented claims-based solutions with pre-Geneva Framework techniques. One question you'll likely have relates to why the Geneva Framework doesn't use the ClaimSet and Claim type from the System.IdentityModel.Claims namespace. The answer is simplicity. In classic WCF, to authorize callers based on their claims you must traverse the collection of ClaimSet instances in the Authorization­Context (shown earlier), which is a cumbersome programming model. The Geneva Framework improves upon this model by removing some of the complexity related to the ClaimSet and adding necessary features to the Claim type.

The ClaimSet type groups claims by issuer. This model has some limitations such as the inability to merge two ClaimSet instances if the issuers are different. It isn't possible to inspect a single collection of all claims. The Geneva Framework, on the other hand, exposes a single collection of claims through ClaimsIdentity that can be inspected during authorization. Once the runtime has established that claims from a particular issuer can be trusted (because the issuer is trusted), it is the Claim type and value that matters to authorization code—not the issuer.

The collection of claims produced by the Geneva Framework use a new Claim type from the Microsoft.IdentityModel.Claims namespace. This Claim type has an Issuer property, so you can still perform a LINQ query over the claims collection to gather all claims from a particular issuer, if you really want to.

You'll most likely also want to know why the Issuer property for a claim is a simple String type instead of a ClaimSet. The Issuer property in WCF is a recursive property—each issuer is defined by a ClaimSet, which may have an issuer defined by another ClaimSet, and so on up to the root (self-signed) issuer. Not only is this a difficult programming model to work with, but this chain is not truly important at run time once you have established that you trust the immediate issuer during token authentication. For this reason, the Geneva Framework changed the Issuer property to be a string representation of the issuer. It is still the token signature that is used to establish trust—the string is merely a way to describe the issuer in a friendly manner.

You may also be surprised to see that the Authorization­Context is cleared when the Geneva Framework is enabled. Claims-based security features of WCF rely specifically on the AuthorizationContext, which provides access to available claim sets for the request, extracted from trusted security tokens. Unfortunately, the AuthorizationContext has no meaning outside of WCF services, which bifurcates the claims programming model.

The goal of the Geneva Framework is to make it easier to support claims-based security in all .NET-based applications, while leveraging existing facets of .NET security. By assigning a ClaimsPrincipal to the request thread, existing role-based security implementations can be easily migrated to claims-based security. In addition, this provides a consistent experience for WCF services and ASP.NET applications. Another benefit of working with security principals is that when new threads are created, they are initialized with the same security principal as the originating thread. AuthorizationContext, on the other hand, is not automatically passed to new threads.

As a result, the Geneva Framework clears the Authorization­Context under the assumption that if you enable the Geneva Framework for your WCF services, you are no longer relying on claim sets in the AuthorizationContext to perform claims-based security checks. And, therefore, WCF services that currently leverage custom authorization policies to populate the AuthorizationContext and to create the security principal for the request thread must be migrated when the Geneva Framework is enabled.

Migrate Applications to the Geneva Framework

After reading the aforementioned white paper for developers and this article, you should have a good understanding of the requirements for building claims-based WCF services and ASP.NET applications using the Geneva Framework. Let me summarize the impact of this on both WCF and ASP.NET.

To enable the Geneva Framework for your WCF services requires, at a minimum, the following steps: exposing an endpoint for the service using one of the federated security bindings; initializing the ServiceHost for the Geneva Framework; providing a list of trusted issuers; configuring the role claim type according to your claims-based security model; and applying permission demands to operations to authorize calls against role claims. WCF services that are already claims-based will require changes, since claims will be accessible directly through the security principal attached to the request thread, no longer through the AuthorizationContext.

ASP.NET applications can leverage the Geneva Framework for implementing federated security scenarios that delegate authentication to an STS, and to initialize the request thread with claims from trusted issuers—accessible through ClaimsPrincipal and ClaimsIdentity instances. Applications that are already role-based will expect claims that match those roles during the move to a claims-based scheme, but new applications have the option of working with more granular claims such as permissions discussed in this article. In either case, the ASP.NET login controls and other role-based security permission demands will look to the Claims­Principal attached to the request thread to authorize calls. In a future article, I will dive deeper into the Geneva Framework to explore building a custom STS for your claims-based and federated security scenarios.

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.net or visit idesign.net . Michele blogs at dasblonde.net .