Identity

Secure Your ASP.NET Apps And WCF Services With Windows CardSpace

Michèle Leroux Bustamante

This article discusses:

  • Windows CardSpace and information cards
  • Web browsers and identity selectors
  • Security tokens
  • Integration with WSFederationHttpBinding and ASP.NET membership
This article uses the following technologies:
.NET Framework 3.0

Code download available at:CardSpace2007_04.exe(462 KB)
Browse the Code Online

Contents

Windows CardSpace and Information Cards
Personal Cards
Managed Cards
Browsers and Identity Selectors
Object and XHTML Parameters
Processing the Security Token
Associating Cards with an Account
Integrating Windows CardSpace with WCF
Conclusion

In May 2005, Microsoft introduced its vision for an identity metasystem that would reduce the complexities and risks associated with managing and exchanging digital identities. This vision-discussed in the article "Microsoft's Vision for an Identity Metasystem" explains interactions based on interoperability standards such as WS-Security, WS-Trust, WS-MetadataExchange, WS-SecurityPolicy, and other WS-* protocols. These protocols enable applications and services to communicate their security requirements via security policy and to transfer digital identities safely and securely. The identity metasystem vision describes a simple and consistent experience for users to identify themselves to applications and services while also identifying the target site to the user in order to reduce risks associated with sending private information to unauthorized or malicious sites.

Windows CardSpace™ (formerly known as "InfoCard"), released with Windows Vista™ and the Microsoft® .NET Framework 3.0, plays an important role in this identity metasystem. Windows CardSpace replaces traditional username and password authentication with a tool that helps users better manage their digital identities and helps shield users from various forms of identity attack such as phishing.

In this article, I will start by reviewing the roles of each party in the identity metasystem, introducing Windows CardSpace, and discussing both personal and managed information cards. Then I'll dig into some scenarios involving both ASP.NET Web applications and Windows Communication Foundation services-explaining how to integrate Windows CardSpace as an authentication mechanism for each scenario.

This article assumes you have some experience with ASP.NET and the Windows Communication Foundation, as well as familiarity with Windows CardSpace features. For a detailed overview of Windows CardSpace, I recommend reading the article "Introducing Windows CardSpace" by David Chappell. You can get additional background from Keith Brown's two columns on the subject titled "A First Look at InfoCard" and "A Deeper Look at InfoCard".

Windows CardSpace and Information Cards

In the identity metasystem, there are three key participants: the relying party (RP), the subject, and the identity provider (IP). The RP can be anything (though typically it is an application or a service) that accepts tokens to execute a given task, such as signing-in and presenting membership details. For the purpose of this article, I will demonstrate how a subject can utilize the Windows CardSpace identity selector to choose and present the appropriate credentials to be used for authentication.

The subject is a person who wishes to safely present information (such as identification information) to the RP. This information is communicated in the form of a security token which is issued by an IP such as a bank, employer, government, and so forth.

The IP is responsible for issuing the security token on behalf of the subject, vouching for the subject's information described by the claims held in the token. The IP is normally implemented as a Security Token Service (STS), a Web service endpoint that implements WS-Trust protocol to issue, renew, validate, or cancel security tokens describing a subject.

Figure 1 Identity Metasystem Participants

Figure 1** Identity Metasystem Participants **(Click the image for a larger view)

Figure 1 illustrates the relationship between the three parties. The RP relies on a particular type of security token to authorize calls. The IP authenticates the subject and issues to the subject a security token in the format required by the RP. The subject then relays that token, which contains claims on behalf of the subject, to the RP. The separation of these roles, and the interoperability protocols used to communicate between them, are part of the identity metasystem credo. Each participant can be implemented on a different technology or platform, so long as they comply with the appropriate Web and WS-* protocols to facilitate interoperable communications.

In the context of this identity metasystem, Windows CardSpace has two roles. First, it is a client technology used for creating, managing, and selecting digital identities in a secure and consistent manner. (In the latter capacity, Windows CardSpace serves as an identity selector.) Second, it has a local IP for personal digital identities and can generate security tokens for those identities.

A digital identity is represented as an information card. Windows CardSpace allows users to create personal cards or to import managed cards issued by other IPs. Users can later select a card when an RP requires that users authenticate themselves with one. The user can only select cards that satisfy the requirements of the RP-or, alternatively, select a personal card and add the necessary claims on the fly-and the associated IP issues the security token containing the appropriate subject claims.

Cards are issued by an IP to describe the claims that the IP is able to vouch for, on behalf of an authenticated subject. Each card represents important information about the IP that issued it, including the following:

  • The URL (or URLs) of the IP's STS, which issues security tokens. This way, when the user selects a card to authenticate to an RP, Windows CardSpace knows where to request the security token containing the appropriate claims.
  • The types of claim associated with the card. Since the IP issues the card, it gets to define what claims the card represents. The RP specifies the claims that it requires and only cards representing these claims will be enabled for a user to select.
  • The types of security token that the IP can issue. The RP indicates which tokens it supports, so only cards that support these tokens will be enabled for selection.

A card issued by an IP can be serialized as a signed XML document with a .crd file extension. The .crd file contains an <InformationCard> section with this and other pertinent information for Windows CardSpace. Figure 2 shows an example of a signed, managed card imported into Windows CardSpace.

Figure 2 Serialized Version of a Managed Information Card

<dsig:Signature xmlns:dsig="https://www.w3.org/2000/09/xmldsig#">
  <dsig:SignedInfo>...</dsig:SignedInfo>
  <dsig:SignatureValue>...</dsig:SignatureValue> 
  <dsig:KeyInfo>...</dsig:KeyInfo>
  <dsig:Object Id="_Object_InfoCard">
    <ic:InformationCard xmlns:ds="https://www.w3.org/2000/09/xmldsig#" 
xmlns:ic="https://schemas.xmlsoap.org/ws/2005/05/identity" 
xmlns:mex="https://schemas.xmlsoap.org/ws/2004/09/mex" 
xmlns:wsa="https://www.w3.org/2005/08/addressing" 
xmlns:wsid="https://schemas.xmlsoap.org/ws/2006/02/addressingidentity" 
xmlns:wst="https://schemas.xmlsoap.org/ws/2005/02/trust" xml:lang="en-us">
      <ic:InformationCardReference>
        <ic:CardId>https://www.thatindigogirl.com/card/
            ED18504F-40B9-5A58-C200-761DC886DF29</ic:CardId> 
        <ic:CardVersion>1</ic:CardVersion> 
      </ic:InformationCardReference>
      <ic:CardName>thatindigogirl</ic:CardName> 
      <ic:CardImage MimeType="image/png">[base64 encoded image]
          </ic:CardImage> 
      <ic:Issuer>https://www.thatindigogirl.com/tokenissuer.svc</ic:Issuer> 
      <ic:IssuerName>That Indigo Girl</ic:IssuerName> 
      <ic:TimeIssued>2006-12-29T22:32:17Z</ic:TimeIssued> 
      <ic:TimeExpires>9999-12-31T23:59:59.9999999Z</ic:TimeExpires> 
      <ic:TokenServiceList>
        <ic:TokenService>
          <wsa:EndpointReference>
            <wsa:Address>https://www.thatindigogirl.com/sts/tokenissuer.svc

                </wsa:Address> 
            <wsa:Metadata><mex:Metadata><mex:MetadataSection>
                  <mex:MetadataReference><wsa:Address>
                        https://www.thatindigogirl.com/sts/mex</wsa:Address> 
                  </mex:MetadataReference>
            </mex:MetadataSection></mex:Metadata></wsa:Metadata>
            <wsid:Identity>
              <ds:KeyInfo><ds:X509Data>
                  <ds:X509Certificate>[base64 encoded 
                       certificate of the IP]</ds:X509Certificate> 
              </ds:X509Data></ds:KeyInfo>
            </wsid:Identity>
          </wsa:EndpointReference>
          <ic:UserCredential>
            <ic:UsernamePasswordCredential>
              <ic:DisplayCredentialHint>Please enter your 
                   password</ic:DisplayCredentialHint>
              <ic:Username>thatindigogirl</ic:Username> 
            </ic:UsernamePasswordCredential>
          </ic:UserCredential>
        </ic:TokenService>
      </ic:TokenServiceList>
      <ic:SupportedTokenTypeList>
        <wst:TokenType>urn:oasis:names:tc:SAML:1.0:assertion
            </wst:TokenType> 
      </ic:SupportedTokenTypeList>
      <ic:SupportedClaimTypeList>
        <ic:SupportedClaimType Uri=
            "https://schemas.xmlsoap.org/ws/2005/05/identity/ 
                claims/personalprivateidentifier">
          <ic:DisplayTag>PPID</ic:DisplayTag> 
          <ic:Description>Unique identifier for the card</ic:Description> 
        </ic:SupportedClaimType>
        ...other claim types
      </ic:SupportedClaimTypeList>
      <ic:PrivacyNotice>https://www.thatindigogirl.com/PrivacyPolicy.txt 
      </ic:PrivacyNotice> 
    </ic:InformationCard>
  </dsig:Object>
</dsig:Signature>

There are two types of card: personal and managed. Personal cards (sometimes referred to as self-issued cards) are created by the user within Windows CardSpace and are issued by the local Windows CardSpace IP. Managed cards can be issued by any other IP and must be explicitly imported into Windows CardSpace.

The interaction between the subject, the RP, cards and associated IPs, and Windows CardSpace is shown in Figure 3. When a Web site or service (the RP) requires a token issued by Windows CardSpace, it specifies the claims it needs. The client application (a browser or a Web service client) invokes Windows CardSpace (1), passing this information along. Windows CardSpace uses this information to present the appropriate cards that can satisfy those claims to the user (2). When the user selects a card (3), Windows CardSpace authenticates the user using a method defined by the IP, calling the appropriate IP as referenced by the card (4) to have a security token issued containing the claims requested by the RP (5). However, it is up to the IP to determine which claims are included in the token (this could be a superset or subset of those in the RP's policy). Ultimately, a signed and encrypted security token is passed back to the application or Web browser (6), which forwards it to the RP (7).

Figure 3 How Cards Are Selected and Used to Issue Security Tokens

Figure 3** How Cards Are Selected and Used to Issue Security Tokens **(Click the image for a larger view)

Cards are stored and secured on the local machine in a file that is encrypted twice, protected by a machine key, your Windows login, and optionally a pin number you supply to secure access to the card. If you use multiple computers, you can export your cards to an encrypted data file and then import them on another machine that you trust.

Personal Cards

Personal cards are created through the Windows CardSpace Control Panel. When you create a personal card, you are in effect creating two things: a set of claims representing some personal information, and a card that lists those claims. Essentially the local Windows CardSpace IP issues personal cards representing the claims you entered and safely stores your claims waiting for a request for a security token. Figure 4 illustrates how a personal card indicates to the Windows CardSpace IP which claims to put into a requested security token.

Figure 4 Generate a Security Token from a Personal Card

Figure 4** Generate a Security Token from a Personal Card **(Click the image for a larger view)

When you create a personal card, you can only enter information for some or all of a predefined set of 15 claims, such as first and last name, e-mail address, and mailing address information. Claims are represented by a URI from the WS-Identity namespace, schemas.xmlsoap.org/ws/2005/05/identity. Figure 5 lists the URI for the claims that a personal card can store (the URIs are abbreviated for clarity).

Figure 5 Claims Supported by Personal Cards

https://schemas.xmlsoap.org/.../identity/claims/privatepersonalidentifier
https://schemas.xmlsoap.org/.../identity/claims/name
https://schemas.xmlsoap.org/.../identity/claims/givenname
https://schemas.xmlsoap.org/.../identity/claims/surname
https://schemas.xmlsoap.org/.../identity/claims/emailaddress
https://schemas.xmlsoap.org/.../identity/claims/streetaddress
https://schemas.xmlsoap.org/.../identity/claims/locality
https://schemas.xmlsoap.org/.../identity/claims/stateorprovince
https://schemas.xmlsoap.org/.../identity/claims/postalcode
https://schemas.xmlsoap.org/.../identity/claims/country
https://schemas.xmlsoap.org/.../identity/claims/homephone
https://schemas.xmlsoap.org/.../identity/claims/otherphone
https://schemas.xmlsoap.org/.../identity/claims/mobilephone
https://schemas.xmlsoap.org/.../identity/claims/dateofbirth
https://schemas.xmlsoap.org/.../identity/claims/gender
https://schemas.xmlsoap.org/.../identity/claims/webpage

Creating personal cards is not much different from creating a username and password for a site. Web sites and Web services can associate personal cards with your user account so you can use Windows CardSpace to select your identity with a few mouse clicks, instead of typing in your username and password. A unique identifier, based on the card's personal private identifier (PPID), is used to associate a card with an account. This identifier is unique to each card and RP combination. That is, if the same card is used for multiple RPs, each RP will receive a distinct PPID to protect the privacy of the user's usage patterns.

Managed Cards

Unlike personal cards, managed cards can represent any claims the IP wishes to assert about a subject (the actual card data is stored within the IP's systems, not on the local machine). You can't create managed cards in the Windows CardSpace interface because the local Windows CardSpace IP can only issue cards for a fixed set of claims. Any IP can issue managed cards representing the claims for which they can generate security tokens. In fact, since a relationship must exist between the RP and the IP, it may be that the RP and IP are owned by the same enterprise.

For example, if you have an account with a bank that knows your account number and type, the IP might issue a card that indicates a security token can be issued with those claims. To avoid the risks associated with username and password login to the account, the managed card can be installed into Windows CardSpace so that the user can select it when authenticating to banking sites. This implies that the bank associated the card with your account when it issued the card, or that an additional step to associate the card once installed is required.

When the user selects this card to authenticate to the banking RP, only compatible managed cards that can satisfy these claims can be selected. Managed cards do not contain the actual claim values, but Windows CardSpace knows where to find the IP to issue the encrypted token containing these claims. Figure 6 illustrates how the managed card indicates to the managed IP what to put into the requested security token.

Figure 6 Generate a Security Token from a Managed Card

Figure 6** Generate a Security Token from a Managed Card **(Click the image for a larger view)

Each RP and IP that have a relationship should also agree on the claims to be included in security tokens. These claims can be identified by unique URIs. Consider these Create/Read/Update/Delete (CRUD) claims for example:

https://www.thatindigogirl.com/2006/06/claims/create
https://www.thatindigogirl.com/2006/06/claims/read
https://www.thatindigogirl.com/2006/06/claims/update
https://www.thatindigogirl.com/2006/06/claims/delete

An application or service could potentially use these claims to do claims-based authorization against features and resources.

Though managed cards are secured by the local machine and can be exported to other machines, the actual claims are stored at the IP and never leave the IP without being wrapped in an encrypted security token. The IP encrypts the security token with the public key of the RP so that nothing-not even Windows CardSpace-can view the claims inside the token. (If the user wants to preview the claims that are about to be sent to the RP, an extra and optional display token can be requested. This is encrypted in such a way that Windows CardSpace can decrypt it and display it to the user.)

Browsers and Identity Selectors

Other identity selectors are being built to perform the same function that Windows CardSpace does in Windows. Windows CardSpace or any other identity selector can be used to select personal or managed cards to satisfy an authentication request.

For Web applications to support personal or managed card authentication, they must first provide a Web page with an object tag or an XHTML binary behavior describing their information card requirements. Browsers that support these tags and have an information card extension will be able to launch the appropriate identity selector on the client machine for users to select a card. As Figure 7 illustrates, there are no specific ties to Windows CardSpace as the identity selector, to Internet Explorer® as the browser, or to ASP.NET as the Web site technology. In fact, other browsers have their own extensions for handling these and other object tags and behaviors, and each operating system can have its own identity selector that supports information cards. All of these elements are platform-neutral.

Figure 7 Trigger an Identity Selector from an Object Tag or Binary Behavior

Figure 7** Trigger an Identity Selector from an Object Tag or Binary Behavior **(Click the image for a larger view)

Any Web application platform, including ASP.NET, can expose pages that include the required object tag or XHTML binary behavior to trigger identity selection. The object tag uses the MIME type application/x-informationCard as shown here:

<object id="informationCard" name="informationCard" 
        type="application/x-informationCard">
    ...
</object>

The information card binary behavior can be specified in XHTML by using a #default#informationCard behavior in the <informationCard> element.

  <ic:informationCard name="xmlToken" 
      style="behavior:url(#default#informationCard)" ... >
      ...
  </ic:informationCard>

Within these <object> and <informationCard> elements are parameters that describe a Web site's requirements for information card authentication. I'll get to those details shortly.

Although earlier versions of Internet Explorer support object tags and XHTML, only Internet Explorer 7.0 supports information cards using a MIME handler extension called Microsoft Information Card IE Helper, available from icardie.dll. (An extension adding Windows CardSpace support to Mozilla Firefox is available.) The following registry key links the MIME type for information cards to the handler:

HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/x-informationCard

This MIME handler is then linked to object tag and behavior configurations for the browser. This handler is responsible for calling the identity selector, passing parameters specified by the object tag or XHTML binary behavior. For Internet Explorer 7.0, the identity selector defaults to Windows CardSpace, indicated by the following registry entry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\InformationCard Token Provider

For the object tag syntax, the MIME handler is triggered through the InformationCardSigninHelper Class, enabled by default in the Internet Explorer 7.0 add-ons dialog as shown in Figure 8. (You can find this dialog by opening Internet Options and from the Programs tab selecting "Manage add-ons.") If this add-on is disabled, the object tag will not trigger identity selection, but this setting has no effect on XHTML syntax. The XHTML information card behavior is configured in a string entry labeled INFORMATIONCARD under the registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Default Behaviors 

Figure 8 Information Card MIME Handler in Internet Explorer 7.0

Figure 8** Information Card MIME Handler in Internet Explorer 7.0 **(Click the image for a larger view)

This behavior also triggers the MIME handler to activate the identity selector.

Unfortunately, consistently detecting browser support for information cards is not an exact science and differs across browsers. While not recommended, for Internet Explorer you can perform a preliminary check of the UserAgent looking for Internet Explorer 7.0 and .NET common language runtime (CLR) 3.0 support. Here's an example of a UserAgent string that indicates this support:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1;
.NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)

In ASP.NET, you can check possible support at the server using the UserAgent property of the Request object as follows:

string userAgent = Request.UserAgent;
if (userAgent.Contains("MSIE 7.0") &&
    userAgent.Contains(".NET CLR 3.0"))
    { Response.Write(
        "Information cards are supported, but might not be enabled."); }
else
    { Response.Write("Information cards may not be supported."); }

This approach has many shortcomings. Other browsers support Windows CardSpace besides Internet Explorer, and even in browsers that support Windows CardSpace, the MIME handler could be disabled. A better solution is to use client-side script to detect whether the browser supports Windows CardSpace and whether that support is enabled.

Internet Explorer 7.0 and the appropriate MIME handler configurations are central to triggering Windows CardSpace from object tags and XHTML. In addition to this, the Web site must be SSL-enabled to secure communications. Extended validation (EV) certificates issued by a trusted root certification authority such as VeriSign or Thawte won't require any special configuration, but if you are using test certificates, you'll need to install the test SSL certificate as a trusted root and add the site to the trusted sites list in Internet Explorer 7.0. Instructions for this are included with the code samples for this article.

Object and XHTML Parameters

As I mentioned, you can use object tags or XHTML binary behaviors to trigger an identity selector from supporting browsers. With either syntax, you must provide a base set of properties to the information card browser extension, listed in Figure 9.

Figure 9  Information Card Activation Properties

Property Description
requiredClaims (mandatory) You can indicate any of the personal claims listed in Figure 5 or custom claims from a managed IP. If any of the claims cannot be satisfied by a personal card, a managed card must be installed to satisfy the claims.
issuer (optional) Indicates the IP from which to request a security token. This defaults to the URI for personal tokens: schemas.xmlsoap.org/ws/2005/05/identity/issuer/self. Leave this setting as the default to trigger Windows CardSpace.
issuerPolicy (optional) Indicates the URL where the security policy for the IP can be found. This does not need to be set for the local Windows CardSpace IP.
tokenType (optional) If omitted, this defaults to the URI for SAML 1.0 tokens, urn:oasis:names:tc:SAML:1.0:assertion. For personal cards, you can specify either SAML 1.0 or SAML 1.1 token format: https://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1. Anything else implies a managed card.
optionalClaims (optional) You can indicate any personal or custom claims as optional. This causes Windows CardSpace to give the user the option of sending the information to the site.
privacyVersion (optional) Specifies the privacy policy version. If this changes, the user is notified and given a chance to review any changes to the privacy policy.

Using the object tag, you configure these properties as in Figure 10. Each <param> represents one of the information card properties by name. The values for requiredClaims and optionalClaims are space-delimited lists of claim URIs. You could optionally omit the issuer and tokenType parameters if the defaults are acceptable to your application.

Figure 10 Object Tag Syntax

<object id="informationCards" name="informationCards" 
  type="application/x-informationCard" >
  <param name="issuer" 
    value="https://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self"/>
  <param name="tokenType" value="urn:oasis:names:tc:SAML:1.0:assertion"/>
  <param name="requiredClaims" value="https://schemas.xmlsoap.org/ws/
        2005/05/identity/claims/privatepersonalidentifier 
    https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"/>
  <param name="optionalClaims" value="https://schemas.xmlsoap.org/ws/
        2005/05/identity/claims/dateofbirth"/>
</object>

Using XHTML you configure information card properties as shown in Figure 11. In this case, attributes are used to specify the behavior style, issuer, and tokenType. Each claim is specified with an <add> instruction indicating the claim URI and whether it is optional. At least one claim must be specified.

Figure 11 Binary Behavior Syntax

<ic:informationCard name="informationCards"
  style="behavior:url(#default#informationCard)"
  issuer="https://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self"
  tokenType="https://docs.oasis-open.org/wss/
      oasis-wss-saml-token-profile-1.1#SAMLV1.1">
  <ic:add claimType="https://schemas.xmlsoap.org/ws/2005/05/
       identity/claims/privatepersonalidentifier" optional="false" />
  <ic:add claimType="https://schemas.xmlsoap.org/ws/2005/05/
       identity/claims/emailaddress" optional="false" />
  <ic:add claimType="https://schemas.xmlsoap.org/ws/2005/05/
       identity/claims/dateofbirth" optional="true" />
</ic:informationCard>

In any case, when a Submit button is selected on a page that includes an information card trigger, the browser invokes the MIME handler and passes the parameters to the identity selector. If a card is selected, the signed and encrypted token is posted to the site in a form parameter named for the <object> or <informationCard> identifier. In Figures 10 and 11, the identifier is informationCards.

If, for some reason, information cards are disabled by the browser, or if the site is not SSL-enabled, the form parameter collection will not include an informationCards item. If Windows CardSpace is launched and the user cancels for any reason, including if the parameters are invalid and cause an error loading Windows CardSpace, the informationCards form parameter is posted as an empty string. In other words, there is nothing to do unless the informationCards form parameter includes an <encryptedData> element.

Using either syntax for <object> or <informationCard>, you can trigger Windows CardSpace from any ASP.NET page of your choice, but there are a few additional steps required to ensure that Windows CardSpace is only invoked for specific Submit buttons on the page. ASP.NET pages have a single active <form> object, so if you slap the <object> or <informationCard> tag inside the only <form> object, any button that posts back to the server will trigger Windows CardSpace, like it or not.

To avoid this, you can include the information card object in the HTML header section and explicitly invoke it using script when the appropriate button is clicked. Figure 12 shows a simple ASP.NET page that includes the <object> tag in the header, along with a SelectInformationCard function that activates the object and puts the return value into a hidden input field. Inside the <form> tag is a standard ASP.NET Login control and an ImageButton.

Figure 12 Explicitly Invoke the Object Tag

<%@ Page Language="C#" AutoEventWireup="true" 
    CodeFile="Login.aspx.cs" Inherits="Login" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="https://www.w3.org/1999/xhtml" >
<head runat="server">
  <title>Login</title>
  <!--Declaration of information card object -->
  <object declare id="informationCards" name="informationCards" 
    type="application/x-informationCard" > ... </object>

  <script type="text/javascript" language="javascript">
  function SelectInformationCard()
  {
    var infoCardObject =document.getElementById("informationCards");
    var hiddenToken = document.getElementById("hiddenXmlToken");
    hiddenToken.value = infoCardObject.value;
  }
  </script>
</head>
<body>
  <form id="standardLogin" name="standardLogin" method="post" 
        runat="server">
    <asp:Login ID="Login1" runat="server" />
    <asp:ImageButton ID="cardSpaceSubmit" runat="server" 
        ImageUrl="cardspacelogin.jpg"  
        OnClientClick="SelectInformationCard()" 
        OnClick="CardSpaceLogin" />
    <input id="hiddenXmlToken" type="hidden" name="hiddenXmlToken" 
           value="empty"/> 
  </form>
</body>
</html>

When the Login control submits, Windows CardSpace is not invoked since the object tag is in the header section. When the ImageButton submits, Windows CardSpace is invoked because the OnClientClick attribute calls SelectInformationCard. You could also create a custom ASP.NET control that emits the object tag and associated script. The important thing is to distinguish each Submit button so that Windows CardSpace is only activated at the appropriate time.

Processing the Security Token

As I mentioned earlier, if Windows CardSpace is invoked, a signed and encrypted token is posted. In the case of Figure 12, the hiddenXmlToken input field will contain this <encryptedData> section if a token is successfully issued. If Windows CardSpace was activated but the user canceled, the field will contain an empty string. If Windows CardSpace could not be activated, it will contain its initial value "empty". The Windows CardSpaceLogin method is invoked if the Windows CardSpace login option is selected on this page; thus you can check the value of the hidden field and proceed from there.

The first problem you'll encounter when an encrypted token is posted back to your Web site is that ASP.NET disallows posting XML and HTML data in order to reduce vulnerability to scripting attacks. You'll receive an HttpRequestValidationException like this one:

System.Web.HttpRequestValidationException: A potentially dangerous 
Request.Form value was detected from the client 
(informationCards="<enc:EncryptedData T...").

You can disable this feature for the entire site by adding the following to the <system.web> section of your web.config:

<pages validateRequest="false"/>

This is one of those cases where I would recommend you set this only for those pages that will receive a postback with a security token. Fortunately, you can set this per page as follows:

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Login.aspx.cs" Inherits="Login" 
         ValidateRequest="false" %>

The next problem you'll run into is that token-processing code is not built into ASP.NET. You must manually process the <encryptedData> element, decrypt the token, validate the token signature, and pull out the claims before you can perform any authentication or authorization. Fortunately, Microsoft provided an example TokenProcessor class with the Windows CardSpace samples that ship with the Windows SDK for Windows Vista and the .NET Framework 3.0 (referenced at msdn2.microsoft.com/aa967562.aspx). I have included a slightly modified version of this TokenProcessor in the code sample for this article.

To use the TokenProcessor class with your ASP.NET applications, all you have to do is construct the type with the <encryptedData> element and access the claims that were passed in the security token. For example, this code looks for the PPID, emailaddress, and dateofbirth claims required by the object tag discussed earlier:

using Microsoft.IdentityModel.TokenProcessor;

string token = Request.Form["hiddenXmlToken"] as string;
if (!String.IsNullOrEmpty(token)) {
  Token tokenProcessor = new Token(token);
  string ppid = tokenProcessor.Claims[ClaimTypes.PPID];
  string emailaddress = tokenProcessor.Claims[ClaimTypes.Email];
  string dateofbirth = tokenProcessor.Claims[ClaimTypes.DateOfBirth];
}

From a very high level, the TokenProcessor works as follows. The token is encrypted using the Web site SSL certificate. The TokenProcessor uses the thumbprint of this certificate to find the associated private key, defaulting to the My/LocalMachine store. The Web application host identity (typically ASPNET or NETWORK SERVICE) must be granted access to this private key or the decryption will fail. The decrypted result is then converted into a SamlToken and validated to ensure that the contents of the token have not been tampered with since the token was created. Once validated, a reference to the token and its claims are available to your code as shown earlier.

For personal cards, the key used to sign the SAML token is not known to your application since it is generated on the fly when the card is used for the first time at your site. Thus, you can't check the signature for personal cards against a trusted public key. You can, however, rely on a hash of the PPID if you previously associated the card with a user account.

For managed cards, since a relationship exists between the RP and IP, you should add an additional step to the RP's token processing code to validate that the token has been signed by an IP you accept. You can do this by using the public key of the IP to validate the signature.

Associating Cards with an Account

Now that I've explained how to trigger Windows CardSpace from ASP.NET, and how to process the resulting security token, you might be wondering what you should do with the claims inside the token. This is influenced by the type of card you require at the Web site: personal or managed.

Sites that support personal cards largely do so to provide users with an improved login experience. The types of claims supported, as I've discussed, are limited-although the associated demographic information could be useful to the site. That said, these claims won't remove the need for role-based authorization. One way you can get the best of both worlds is to allow users to associate a personal card with their existing account and use the card to look up the user's roles when they log in with it.

Figure 13 illustrates the interaction between the user, the Web site, and Windows CardSpace to achieve this goal. The user can create the personal card ahead of time and then log in to an existing account to associate the card. It is also possible to create the card during the association step if a card that satisfies the site's requirements doesn't already exist. Once a personal card is selected to associate with the site, the resulting security token is posted to the site for processing. The claims contained in the security token must be sufficient to look up the user account when a user logs in with the card.

Figure 13 Associate a Personal Card with a Web Site Account

Figure 13** Associate a Personal Card with a Web Site Account **(Click the image for a larger view)

The following code associates a card with the current user account only if the e-mail address claim supplied with the token matches the e-mail of the logged-in user:

MembershipUser user = Membership.GetUser(this.User.Identity.Name);
if (user.Email == emailaddressClaim) {
    user.Comment = ppidClaim;
    Membership.UpdateUser(user);
}

This code uses the Comment field of the user record to associate the card's PPID with the user account. The PPID claim is unique to the card and the RP it is sent to, thus uniquely identifying the user. (Note, though, that the PPID can only be relied on if the token's signature is first verified and validated cryptographically.)

When the user logs in using the personal card, the e-mail address claim can be used to look up the user account using the ASP.NET Membership API. A matching PPID in the comment field indicates the correct user has been found, as shown here:

MembershipUserCollection matchingUsers = 
    Membership.FindUsersByEmail(emailaddressClaim);
if (matchingUsers.Count > 0) {
    foreach (MembershipUser user in matchingUsers) {
        if (user.Comment == ppid) {
            authenticatedUser = user;
            break;
        }
    }
}

Having found the user account, the usual steps to create an authentication ticket for the user can be completed. A simple call to RedirectFromLoginPage can facilitate this:

FormsAuthentication.RedirectFromLoginPage(
    authenticatedUser.UserName, true);

Interestingly, this also authenticates the user in the traditional way for the duration of the ASP.NET session, which means that traditional role-based security checks will also work across the application.

Managed cards introduce a slightly different workflow for associating cards to accounts. The distribution of managed cards to end users can be handled in a number of ways, one of which could be to allow users to request a card after logging in to the site. The card is then imported to Windows CardSpace for later use from the site's login page. Figure 14 illustrates this flow of communication.

Since managed cards can contain literally any set of claims deemed valuable to the IP and RP, they may even have more meaning to the authorization process. A set of claims received by an RP might indicate a list of rights to the application. In this case, the ASP.NET membership and role provider may be bypassed altogether since it relies on role-based security and has no notion of claims.

Figure 14 Request and Import a Managed Card to Log In

Figure 14** Request and Import a Managed Card to Log In **(Click the image for a larger view)

Integrating Windows CardSpace with WCF

Browser-based applications are natural candidates for integrating with Windows CardSpace authentication. Web services can also require Windows CardSpace authentication such that client applications invoke Windows CardSpace to issue security tokens in a similar way.

In the case of Windows Communication Foundation, this is done by configuring service endpoints to use WSFederationHttpBinding. This generates a security policy for the service, included in the Web Service Description Language (WSDL) document that indicates it requires personal tokens. When SvcUtil generates a Windows Communication Foundation proxy from this WSDL, matching client endpoints are generated that use an equivalent WSFederationHttpBinding configuration. Client applications use this proxy to construct a channel to call the service, and the proxy handles calls to Windows CardSpace to gather a security token satisfying the claims of the target service. The resulting interaction looks much like that in Figure 3, where the RP is the Windows Communication Foundation service instead of a Web application, and the client application is the Windows Communication Foundation client and proxy instead of a browser.

WSFederationHttpBinding allows you to expose Windows Communication Foundation services over HTTP that rely on an issued token from an IP. The IP can be Windows CardSpace, which implies a personal or managed card must be supplied to find the appropriate IP to issue the actual token. The IP can also be explicitly configured, which means that the token request does not go through Windows CardSpace. For the purpose of this discussion I'll focus only on the Windows CardSpace configuration.

The parameters required of WSFederationHttpBinding will look very similar to the requirements of the object tag or XHTML configuration used to trigger Windows CardSpace from a Web page. You must specify an issuer, a token type, and a list of required or optional claims. The issuer must be set to schemas.xmlsoap.org/ws/2005/05/identity/issuer/self to trigger Windows CardSpace; the token format can be any format supported by a personal or managed card. The claims can likewise be personal or managed claims. These settings will determine whether a personal or managed card can satisfy the request for a security token.

Figure 15 shows a complete <system.serviceModel> section for a simple Windows Communication Foundation service that exposes a WSFederationHttpBinding endpoint. The <wsFederationHttpBinding> section describes the properties I just discussed for the binding configuration. In this case, SAML 1.1 tokens are required to contain a PPID and e-mail address claim. The service must also provide a certificate to facilitate secure exchanges with clients, and this certificate is specified in the <serviceBehavior> section within the <serviceCertificate> element.

Figure 15 Service Config to Trigger Windows CardSpace

<system.serviceModel>
  <services>
    <service name="HelloIndigo.HelloIndigoService" 
        behaviorConfiguration="serviceBehavior">
    <endpoint address="https://localhost:8000/HelloIndigo" 
        contract="HelloIndigo.IHelloIndigoService" 
        binding="wsFederationHttpBinding" 
        bindingConfiguration="wsFed" />
    </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" negotiateServiceCredential="false" >
            <claimTypeRequirements>
              <add claimType="https://schemas.xmlsoap.org/ 
                    ws/2005/05/identity/claims/privatepersonalidentifier"
                    isOptional="false"/>
              <add claimType="https://schemas.xmlsoap.org/ 
            ws/2005/05/identity/claims/emailaddress" isOptional="false"/>
            </claimTypeRequirements>
            <issuer address=
          "https://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" />
          </message>
        </security>
      </binding>
    </wsFederationHttpBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior name="serviceBehavior" >
        <serviceCredentials>
          <issuedTokenAuthentication 
            allowUntrustedRsaIssuers="true" />
          <serviceCertificate findValue="RPKey" 
            storeLocation="LocalMachine" storeName="My" 
            x509FindType="FindBySubjectName" />
        </serviceCredentials>
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

The allowUntrustedRsaIssuers setting in the <issuedTokenAuthentication> element is important when relying on personal cards. By default this setting is false. However, it must be set to true for personal cards since the resulting token is signed with an unknown private key. For managed cards, this isn't required since the service will likely install the public key of any IP you accept into the Trusted People certificate store. In the case of managed cards, the signature of the issued token is checked against this list of trusted public keys. Custom authorization options also exist.

The generated client configuration used to initialize the proxy is equivalent to the service configuration with a few exceptions. The client requires access to the service public key to encrypt the token and its communications to the service. Fortunately, SvcUtil generates a base64-encoded version of the public key with the client endpoint configuration under <identity> to avoid the step of installing the public key into the client machine certificate store. This configuration is shown in Figure 16. The <wsFederationHttpBinding> section is collapsed in this illustration because it is equivalent to Figure 15. The client proxy is initialized with this information when constructed and uses it to determine how to acquire the security token to authenticate to the service. In fact, the actual code to invoke the service can be as simple as this:

HelloIndigoContractClient proxy = new HelloIndigoContractClient();
string s = proxy.HelloIndigo("Hello");

Figure 16 Client Configuration for WSFederationHttpBinding

<system.serviceModel>
  <bindings>
    <wsFederationHttpBinding>...</wsFederationHttpBinding>
  </bindings>
  <client>
    <endpoint address="https://localhost:8000/HelloIndigo" 
        binding="wsFederationHttpBinding"      
        bindingConfiguration="wsFed"
        contract="Client.localhost.HelloIndigoContract" 
        name="wsFed">
      <identity>
        <certificate encodedValue="base64 encoded public key" />
      </identity>
    </endpoint>
  </client>
</system.serviceModel>

Windows CardSpace is triggered by Windows Communication Foundation at the client because the issuer setting tells it to use the personal token provider. The user is presented with the identity selection interface with only cards satisfying the required claims in the binding presented. Managed cards are required when the token type or required claims cannot be satisfied by personal cards.

One area where Windows Communication Foundation significantly differs from ASP.NET in regards to Windows CardSpace authentication is in how claims are processed at the server. Unlike with ASP.NET, the security token issued through Windows CardSpace is packaged as part of the security headers in the SOAP message sent to the service. Before the service operation is invoked, this security token is decrypted and validated, and its claims extracted into the service security context. These extracted claims are added to an abstraction known as a ClaimSet, which contains the list of claims and information about the issuer of the claims. In the case of personal cards, the claims are self-issued, which means that you won't be authorizing the public key of the issuer. That's why it is important to associate the card's PPID claim (which is unique and kept secret) with an account in the system. You can check the claim sets attached to the AuthorizationContext and look for a PPID claim to find a match, and then check the values of other expected claims for further authorization, as shown in Figure 17.

Figure 17 Access Claims through the AuthorizationContext

AuthorizationContext authContext = 
    ServiceSecurityContext.Current.AuthorizationContext;

DateTime? birthDate = null;
string ppid = null;

foreach (ClaimSet cs in authContext.ClaimSets)
{
    IEnumerable<Claim> claims = cs.FindClaims(ClaimTypes.PPID, 
        Rights.PossessProperty);

    ppid = ValidatePPID(claims);
    if (ppid!=null)
    {
        claims = cs.FindClaims(ClaimTypes.DateOfBirth, 
            Rights.PossessProperty);
        foreach (Claim c in claims)
            birthDate = Convert.ToDateTime(c.Resource);
    }
}
if (birthDate == null)
    throw new FaultException("Missing date of birth claim.");
if (birthDate.Value.AddYears(13) > DateTime.Now)
    throw new FaultException(
        "User is too young to access this operation.");

The code in Figure 17 checks for PPID and date-of-birth claims from any ClaimSet-assuming that the token was issued by a personal card-then checks for a date-of-birth claim to verify the age of the caller. One or more sets of claims may be attached to the AuthorizationContext as different security tokens are extracted from the message and processed by service authorization policies. If the issuer is known and can be identified, it would be possible to select the correct ClaimSet from a particular issuer before processing claims.

Managed cards yield an extended set of possibilities since the claims have an identifiable issuer. The issuer is also described by a ClaimSet that often includes an identity claim with the public key of the IP you accept. You can search for an identity claim and check that it is a valid RSA claim as follows:

ClaimSet csIssuer = cs.Issuer;
IEnumerable<Claim> issuerClaims = csIssuer.FindClaims(
    ClaimTypes.Rsa, Rights.Identity);
foreach (Claim c in issuerClaims)
{
    System.Security.Cryptography.RSACryptoServiceProvider rsa = 
        c.Resource as RSACryptoServiceProvider;
    if (rsa != null)
    {
        ... // claim exists; check the public key to identify the IP
    }
}

Once you're sure you have the right ClaimSet, you can perform claims-based security checks. For example, if the claims are based on the CRUD claims mentioned earlier, you can check for create, read, update, and delete claims for appropriate operations. In this way, managed cards not only make it easier for a user to select his identity, but they also facilitate the generation of a rich set of claims identifying the user's rights. Service developers can focus on claims-based authorization checks instead of traditional role-based security checks. A complete sample that illustrates claims-based security can be downloaded from msdn.microsoft.com/msdnmag/code07.aspx.

Conclusion

Integrating Windows CardSpace with your ASP.NET applications and Windows Communication Foundation services improves the end-user experience by providing a simple and consistent identity selection process for authentication to trusted applications and services. While personal and managed cards provide an equivalent login experience, managed cards have the advantage of enabling an IP to supply a specific set of claims that applications and services can use to better identify the user's rights in their system. The topics discussed in this article and implemented in the sample code for this article will help you on your way to triggering the Windows CardSpace experience from ASP.NET or Windows Communication Foundation. Enjoy!

Michèle Leroux Bustamante is a Chief Architect for IDesign Inc., a Microsoft Regional Director and MVP for Connected Systems, and an internationally known speaker and author. Michele contributed to the design and implementation of Windows CardSpace during its early beta stages. She recently completed the book Learning WCF (O'Reilly, 2007; book blog: www.thatindigogirl.com). Reach her at www.idesign.net or visit her main blog at www.dasblonde.net.