Export (0) Print
Expand All
1 out of 1 rated this helpful - Rate this topic

Using and Applying CardSpace: A New Scheme for Establishing Identity

This chapter is excerpted from Programming .NET 3.5: Build N-Tier Applications with WPF, AJAX, Silverlight, LINQ, WCF, and More by Jesse Liberty, Alex Horovitz, published by O'Reilly Media

Until now, identifying oneself on the Web has been a source of irritation, annoyance, security concerns, and risk. Web sites often require users to provide unique login IDs and passwords, and you may also have to supply some arbitrary level of personal identification. Because some sites contain information that may be of great value, or engage in transactions that may involve exchanging significant amounts of money, it is often in your interest to ensure that the passwords you use are secure. But unfortunately, at the present time there is no good, easy way to create secure passwords for all the sites that require them. By definition, a good password should be difficult for either a human or a computer algorithm to guess, and thus a good password will be difficult to remember. The usual solution to this is to write down all your passwords, which immediately makes them vulnerable to discovery.

Microsoft's first attempt at solving this problem was Passport. The idea behind Passport was that you would have a single identity with only a single password to remember. The problem with this approach, of course, is that you may not wish to have the same identity on every web site you visit. Also, many web users prefer to limit the information they give out to the absolute minimum required to perform the transactions they want on a given web site-and with good reason. All of us have experienced the tsunami of junk mail that can result from simply visiting the wrong web site.

A better solution, Microsoft determined, would be to allow users to create a number of "identity cards," each of which could provide its own level of validity, verifiability, reliability, and personal data. For example, you might choose to create a highly secure identity that reveals your most valuable information and provides the most verifiable and valid data, a day-to-day identity that provides a more limited amount of true information about you, an even more basic identity that reveals only a few personal details, and a false identity to use on casual web sites where you do not wish your true identity to be revealed.

Finally, you can imagine having certain special cards that represent trusted relationships between you and institutions with which you do ongoing business, such as your bank, brokerage firm, or employer.

Microsoft's solution to this problem is CardSpace.

About Windows CardSpace

The Windows CardSpace software ships with Microsoft's .NET 3.5 Framework. CardSpace functions as both an identity selector (a platform service for user-centric identity management) and an identity provider (a producer of assertions about the authenticity of an identity). It creates and stores references to a user's digital identities and allows the user to present his identity of choice in the form of an information card. Information cards appear on the screen very much like credit cards or other ID cards.

Microsoft has worked hard to ensure that CardSpace provides a consistent user experience through which users can easily select and use an identity on sites where CardSpace is accepted. CardSpace conforms to the Laws of Identity (see the upcoming sidebar "Kim Cameron's Laws of Identity in Brief") and provides the foundation for a unified, secure, privacy-protecting, interoperable identity layer for the Internet, which you as a developer can leverage today with relative ease.

Kim Cameron's Laws of Identity in Brief

Kim Cameron's Identityblog (http://www.identityblog.com) defines seven laws of identity:

  1. User Control and Consent: Digital identity systems must only reveal information identifying a user with the user's consent.

  2. Limited Disclosure for Limited Use: The solution which discloses the least identifying information and best limits its use is the most stable, long-term solution.

  3. The Law of Fewest Parties: Digital identity systems must limit disclosure of identifying information to parties having a necessary and justifiable place in a given identity relationship.

  4. Directed Identity: A universal identity metasystem must support both "omnidirectional" identifiers for use by public entities and "unidirectional" identifiers for private entities, thus facilitating discovery while preventing unnecessary release of correlation handles.

  5. Pluralism of Operators and Technologies: A universal identity metasystem must channel and enable the interworking of multiple identity technologies run by multiple identity providers.

  6. Human Integration: A unifying identity metasystem must define the human user as a component integrated through protected and unambiguous human-machine communications.

  7. Consistent Experience Across Contexts: A unifying identity metasystem must provide a simple consistent experience while enabling separation of contexts through multiple operators and technologies.

CardSpace allows you, as a user, to create personal (self-issued) information cards for yourself. An information card can contain one or more of 14 fields of identity information. For more secure transactions, users will use managed identity cards, typically issued by a third-party identity provider. These cards are different in that the providers-such as employers, financial institutions, or government agencies-make the claims on the user's behalf.

When CardSpace-enabled applications or information card-aware web sites wish to obtain information about a user, they ask the user for an identity card. At that point, CardSpace switches the display to the CardSpace service, which displays the user's stored identities on the screen (as illustrated in Figure 14.1, "Selecting an identity"). The user selects the card to use, at which point the CardSpace software contacts the issuer of the identity to obtain a digitally signed XML token that contains the requested information. It is important to note that the user chooses which identity to provide before the identity is validated.

Figure 14.1. Selecting an identity

Selecting an identity

Built on top of the web services protocol stack, CardSpace leverages an open set of XML-based protocols. These include WS-Security, WS-Trust, WS-MetadataExchange, and WS-SecurityPolicy. As a direct result, any technology or platform that supports WS-* protocols can integrate with CardSpace.

To accept information cards, a web site developer only needs to declare an HTML OBJECT tag specifying the claims the web site requires from the user. Additionally, the site developer will need to implement code to process the returned token and to extract the claim values.

Identity providers who want to issue tokens must provide a means by which a user can obtain a managed card. They must also provide a Security Token Service (STS) that handles WS-Trust requests, including the return of an appropriate encrypted and signed token. Identity providers not wishing to build their own STS can obtain one from a variety of vendors, including BMC, Siemens, Sun, and Microsoft.

The basic interaction for a client is captured in Figure 14.2, "Client using a token from a managed provider".

Figure 14.2. Client using a token from a managed provider

Client using a token from a managed provider

CardSpace and the Identity Metasystem on which it is based are token format-agnostic. Therefore, CardSpace does not compete directly with other Internet identity architectures. In some ways, these approaches to identity can be seen as complementary. As of this writing, CardSpace information cards can be used to sign into OpenID providers, Windows Live ID accounts, Security Assertion Markup Language (SAML) identity providers, and other kinds of services.

Understanding the Identity Metasystem

The main goal of the Identity Metasystem is to allow people to have a set of different identities, each of which may reveal more or less information than the others.

It was designed as an interoperable identity-delivery vehicle based on multiple underlying technologies. It allows for multiple implementations as well as multiple providers.

With this approach, customers can continue to use their existing identity-infrastructure investments. Then, when the time comes, they can choose the identity technology that works best for them and can easily migrate from their old technology to a better and newer technology without sacrificing interoperability.

By the nature of its design, the Identity Metasystem has three roles:

Identity provider

The identity provider is an entity that issues an identity (in this case, in the form of an information card). With CardSpace, anyone can become an identity provider-you've just become one yourself!

Just as in real life, however, your word might not be good enough to seal a transaction. Each identity provider comes with an established level of trust, and interactions are governed accordingly.

Relying party

Similarly, anyone can be a relying party. The name comes from the dependency on a third party (the identity provider) to validate the claims made by identity tokens. The tokens contain the claims requested by the relying party and validated by the identity provider.

Subject

The subject is most likely a person but might also be a device of some sort, such as a phone or a server. It is the entity about which claims are being made and validated.

The Identity Metasystem is built on a foundation of claims-based identities. The validation of an identity provider enables a relying party to assume that these assertions (claims) about the subject are true.

In the case of .NET 3.5, you rely on CardSpace to deliver claims to requesting parties and establish your own self-issued claims in the form of information cards. These cards currently support the following fields:

  • First Name

  • Last Name

  • Email Address

  • Street

  • City

  • State

  • Postal Code

  • Country/Region

  • Home Phone

  • Other Phone

  • Mobile Phone

  • Date of Birth

  • Gender

  • Web Page

One of the best ways to understand Windows CardSpace is to walk through a use-case scenario as a CardSpace user. In this scenario, you will create a self-issued card and see what it means to use this card on a web site. Along the way, you'll take a look at some of the key issues surrounding the very meaning of identity.

What You Need for Our CardSpace Examples

If you already have version 3.5 of the .NET Framework installed, or if you are running Windows Vista, you are good to go.

Otherwise, you'll need to download and install the Microsoft .NET Framework 3.5 from http://www.microsoft.com/downloads/. This will also install Windows CardSpace.

Once that's done, open the Windows Control Panel and confirm that there is an icon for Windows CardSpace. You should see something like Figure 14.3, "CardSpace successfully installed". (If you are in Classic View, the icon will be the same but the view will be a little different.)

Figure 14.3. CardSpace successfully installed

CardSpace successfully installed

CardSpace on Board, Ready to Create My Identity

If you don't already have one, to begin you'll need to create a CardSpace information card. Double-click on "Windows CardSpace" in the Windows Control Panel to launch CardSpace.

You will notice a task list running down the righthand side of the CardSpace control panel. Click on the "Add a card" link, and you should be presented with a window similar to the one shown in Figure 14.4, "Adding a card".

Figure 14.4. Adding a card

Adding a card

In Windows CardSpace, there are two kinds of "identity providers": cards can be "self-issued," with individuals making claims about themselves, or they can be supplied by a "managed" card provider, which supports claims made by one party about another. This distinction reflects the fact that different transactions require different levels of security. For example, if John Smith wants to get his dry cleaning back, he can identify himself by saying, "Hi, I'm John Smith." But if he wants to buy a plane ticket, he must provide a form of identification that has been issued by a trusted third party, such as a state or national government agency.

The driver's license or passport required by the Transport Security Administration are examples of managed cards provided by government agencies. Other examples of managed-card providers might include financial institutions, employers, and even businesses devoted to making assertions and claims about their customers that they are prepared to back financially.

For this example, you'll create a self-issued card. When you click on the "Create a Personal card" link, you should be presented with a screen similar to the one in Figure 14.5, "Creating a personal card". On this screen you will provide information about yourself, to whatever level of detail you like.

Figure 14.5. Creating a personal card

Creating a personal card

You are free to send this information via this card to one or more requesters. A requester can be any web site seeking identification from you.

It's important to remember that once you send your card to a requester, you have no control over how that information is used. Therefore, it is probably a good idea to set up various cards, each providing differing amounts of information, so that you can choose exactly how much to reveal to a given web site. In this manner, you can disclose details in proportion to your level of trust of the requester.

Once you have filled out and saved your cards, you will be able to preview each one (as shown in Figure 14.6, "Card preview").

Figure 14.6. Card preview

Card preview

Using Your Card

Microsoft's Kim Cameron (the author of the Seven Laws of Identity) has a web site where you can test your newly created card. Open up your browser and go to http://www.identityblog.com. Click on the login button in the upper-right corner. You should see a page that looks like Figure 14.7, "CardSpace login page at www.identityblog.com".

Click on the "With an Information Card" link. This will bring you to the standard information page typically shown to users who have not previously identified themselves using CardSpace. This screen, shown in Figure 14.8, "Do you want to send a card to this site?", contains information about www.identityblog.com and asks you whether you want to send in a card to the site. This is one of the two decisions you will make as a user when interacting with a web site via CardSpace.

The information about the site, including the trusted authority that is verifying the site, is designed to offer you information to help you decide whether you want to continue, and what your level of trust is in terms of what card to supply. If you decide that the site is trustworthy and that you wish to present a card, click on the "Yes, choose a card to send" link. A screen like the one in Figure 14.9, "Sending a card" will appear.

Figure 14.7. CardSpace login page at www.identityblog.com

CardSpace login page at www.identityblog.com

Figure 14.8. Do you want to send a card to this site?

Do you want to send a card to this site?

Figure 14.9. Sending a card

Sending a card

Note that the selection of cards for you to send is provided locally and not by the requester. The requester is given only the card that you select and therefore has only as much information about you as you choose to provide.

After you submit your card, you should get an email (if you have provided an address on the card) asking you to verify the submission. Assuming all goes as expected, you are now a registered user of Kim Cameron's Identityblog. This blog is a very good resource for understanding the issues that Windows CardSpace is meant to address.

The next thing you are going to do is build a sample ASP.NET application to process an information card.

Setting Up Your Machine for the CardSpace Examples

To ensure that you can successfully run your application, you will need to spend a little time setting up your computer.

IIS7

First, make sure IIS7 is installed (see the previous chapter for details).

If you're running Windows Vista, you'll also need to ensure that IIS 6.0 compatibility support is installed with IIS7. Otherwise, there is a chance that the certificates will not work correctly.

To ensure IIS6 compatibility, open the Control Panel and double-click "Programs and Features." Within the menu on the left, click on "Turn Window features on or off" (Figure 14.10, "Ensuring IIS6 compatibility"). This will bring up a dialog box with that title. Navigate to and expand "Internet Information Services," then expand "Web Management Tools" and check and optionally expand "IIS 6 Management Compatibility," also shown in Figure 14.10, "Ensuring IIS6 compatibility".

Figure 14.10. Ensuring IIS6 compatibility

Ensuring IIS6 compatibility

With IIS7 installed and IIS6 compatibility ensured, point your browser to http://tinyurl.com/2kp4x4.

You'll want to download this sample, called "Introduction to CardSpace with Internet Explorer 7.0, August, Update," to a folder where you can find it later. Unzip the contents in that folder and then run the install script as the Administrator. This will install the sample certificates for the examples you are going to build.

About the certificates

The certificates installed by the script are for demonstration purposes only. The root certificate authority (CA) certificate is stored as an .sst (Microsoft Serialized Certificate Store) file. The web site certificates are all stored as .pfx files. The certificates are used for two categories of scenarios: browser scenarios and Windows Communication Foundation (WCF) scenarios.

The sample certificates are High-Assurance (HA) certificates that have embedded logo images in them. HA certificates come from a CA that has performed additional steps to verify the identity of the subject for whom the certificate is issued. In Internet Explorer 7.0, these HA certificates cause the address bar to change to green when the details are verified.

\etc\hosts

To ensure that you can see the address bar confirmation of the installed sample certificates, you need to make sure that your localhost (IP address 127.0.0.1) is correctly mapped to the certificate domains. To do this, run the Notepad application as the Administrator and open the hosts file (typically located at C:\windows\system32\drivers\etc\hosts).

Add the following entries:

127.0.0.1 www.adatum.com adatum.com
127.0.0.1 www.contoso.com contoso.com
127.0.0.1 www.fabrikam.com fabrikam.com

If you have everything installed correctly, navigating to https://www.fabrikam.com should produce a page like Figure 14.11, "A green address bar means success" in Internet Explorer 7.0-the address bar is green, but you'll have to take our word for it!

Configuring IIS for Your Application

If you want to add Windows CardSpace support to a web site, there are certain things you need to do. One of these involves making sure your site is able to use the Secure Sockets Layer (SSL); you can do this from the IIS Administration application with the easy-to-use GUI.

Using IIS7, you'll need to check that everything is properly configured prior to creating your test application:

  1. Make sure you have created a dedicated directory, such as C:\3.5 \CardSpaces.

  2. Launch the IIS Manager from the Administrative Tools section of the Control Panel.

  3. Expand the Connections tree until you can see "Default Web Site."

  4. Right-click on "Default Web Site" and select "Add Virtual Directory."

    Figure 14.11. A green address bar means success

    A green address bar means success
  5. Name the alias directory CardSpaces and specify the path to your dedicated directory (C:\3.5 \CardSpaces).

  6. Right-click on "Default Web Site" again and select "Add Application."

  7. Name the application CardSpaceExample and specify the same path you used for the virtual directory.

Creating a Sample ASP.NET Application

Launch Visual Studio 2008 as the Administrator, select File → New Web Site, and create a new ASP.NET Web Site (as shown in Figure 14.12, "Creating the CardSpaces web application"). You will want to locate the site in your dedicated directory (C:\3.5 \CardSpaces) and select Visual C# as the language. Also make sure you have selected .NET Framework 3.5 in the drop-down list in the top-right corner.

The first thing to do with your new application is add a new ASP.NET folder called App_Code. Inside this folder, you'll add two classes from Microsoft (available at http://tinyurl.com/2ql3le). To complete the upcoming exercise, you'll use specific sections of code from each. Take the time to download them now.

Figure 14.12. Creating the CardSpaces web application

Creating the CardSpaces web application
Tip
To follow along as we explore the Microsoft classes and what they are helping with in this chapter's example, you may want to open the TokenProcessor.cs file in your Visual Studio 2008 environment now. The relevant sections of code will be pointed out in the text.

When you run your application, and you are sure a CardSpace card has been submitted, you're going to make a call to initialize a new Token from the identityToken you've gathered from the HTTP request:

Token aToken = new Token(identityToken);

The Token class constructor uses the decryptToken() method to decrypt the XML data that you passed into the constructor. This is, as you will see, the gateway to the other activities you might want to perform. Before anything else can happen, you must be able to successfully decrypt the Token:

private static byte[] decryptToken(string xmlToken)

You'll use an XmlReader to iterate through the XML data:

XmlReader reader = new XmlTextReader(new StringReader(xmlToken));

Because of the strict nature of XML elements, very little flexibility exists. Thus, you'd like to be able to fail quickly (using an ArgumentException) if you come across an invalid token.

To start, you need to find the EncryptionMethod element. Its Algorithm attribute tells you the encryption method of the token:

if (!reader.ReadToDescendant(XmlEncryptionStrings.EncryptionMethod,
    XmlEncryptionStrings.Namespace))
   throw new ArgumentException("Cannot find token EncryptedMethod.");
encryptionAlgorithm =
    reader.GetAttribute(XmlEncryptionStrings.Algorithm).GetHashCode();

Next, look for the EncryptionMethod attribute for the transient key, again getting the value of its Algorithm attribute. This is stored as its hash code:

if (!reader.ReadToFollowing(XmlEncryptionStrings.EncryptionMethod,
    XmlEncryptionStrings.Namespace))
   throw new ArgumentException("Cannot find key EncryptedMethod."); m_
keyEncryptionAlgorithm =
    reader.GetAttribute(XmlEncryptionStrings.Algorithm).GetHashCode()

You'll find the thumbprint of the certificate (which you need for decryption) in the next element, KeyIdentifier:

if (!reader.ReadToFollowing(WSSecurityStrings.KeyIdentifier,
    WSSecurityStrings.Namespace))
   throw new ArgumentException("Cannot find Key Identifier.");
reader.Read();
thumbprint = Convert.FromBase64String(reader.ReadContentAsString());

The CipherValue element contains the symmetric key in its encrypted form:

if (!reader.ReadToFollowing(XmlEncryptionStrings.CipherValue,
    XmlEncryptionStrings.Namespace))
   throw new ArgumentException("Cannot find symmetric key.");
reader.Read();
symmetricKeyData =
    Convert.FromBase64String(reader.ReadContentAsString());

The CipherValue also contains the actual encrypted token:

if (!reader.ReadToFollowing(XmlEncryptionStrings.CipherValue,
    XmlEncryptionStrings.Namespace))
   throw new ArgumentException("Cannot find encrypted security token."); reader.Read(
);
securityTokenData =
    Convert.FromBase64String(reader.ReadContentAsString());

Finally, close the reader to free up resources:

reader.Close();

Windows CardSpace ensures the encryption of the security token. With .NET 3.5, encryption is currently supported by one of two symmetric algorithms: AES and Triple DES. Use the encryption algorithm URI as a lookup:

SymmetricAlgorithm alg = null;
X509Certificate2 certificate = FindCertificate(thumbprint );

foreach( int i in Aes )
   if (encryptionAlgorithm == i)
   {
      alg= new RijndaelManaged();
      break;
   }
if ( null == alg )
   foreach (int i in TripleDes)
   if (encryptionAlgorithm == i)
   {
      alg = new TripleDESCryptoServiceProvider(); break;
   }
if (null == alg)
   throw new ArgumentException(
       "Could not determine Symmetric Algorithm"
   );

To get the symmetric key, decrypt it with the private key:

alg.Key=(certificate.PrivateKey as
    RSACryptoServiceProvider).Decrypt(symmetricKeyData,true);

Once you are finished with the discovery process, you know what algorithm has been used, so you can decrypt the token using the correct algorithm:

int ivSize = alg.BlockSize / 8;
byte[] iv = new byte[ivSize];

Buffer.BlockCopy(securityTokenData, 0, iv, 0, iv.Length);

alg.Padding = PaddingMode.ISO10126;
alg.Mode = CipherMode.CBC;
ICryptoTransform decrTransform = alg.CreateDecryptor(alg.Key, iv);

byte[] plainText =
    decrTransform.TransformFinalBlock(securityTokenData, iv.Length,
    securityTokenData.Length iv.Length);

decrTransform.Dispose(); return plainText;

Thankfully, .NET 3.5 simplifies the deserialization of the decrypted Token through the WSSecurityTokenSerializer and facilitates its authentication through the use of the SamlSecurityTokenAuthenticator. The Token class supports SAML tokens out of the box. If you require a different token type, you simply need to provide an Authenticator to support the type in question.

Once the authenticator has validated the token, the Token class extracts the claims into a usable form:

public Token(String xmlToken)
{
   byte[] decryptedData = decryptToken(xmlToken);
   XmlReader reader = new XmlTextReader(new StreamReader(new
       MemoryStream(decryptedData), Encoding.UTF8));
   m_token =
       (SamlSecurityToken)
       WSSecurityTokenSerializer.DefaultInstance.ReadToken(
           reader, null);

   SamlSecurityTokenAuthenticator authenticator =
       new SamlSecurityTokenAuthenticator(
           new List<SecurityTokenAuthenticator>
           (
              new SecurityTokenAuthenticator[]{
                 new RsaSecurityTokenAuthenticator(),
                     new X509SecurityTokenAuthenticator() }),
                     MaximumTokenSkew
           );

   if (authenticator.CanValidateToken(m_token))
   {
      ReadOnlyCollection<IAuthorizationPolicy> policies =
          authenticator.ValidateToken(m_token);
      m_authorizationContext =
          AuthorizationContext.CreateDefaultAuthorizationContext(
              policies);
      FindIdentityClaims();
   }
   else
   {
      throw new Exception("Unable to validate the token.");
   }
}

As you can see, the Token class exposes several properties that simplify the extraction of claims from the security token:

IdentityClaims

A System.IdentityModel.Claims.ClaimsSet of the identity claims in the token.

AuthorizationContext

A System.IdentityModel.Policy.AuthorizationContext generated from the token.

UniqueID

The UniqueID (IdentityClaim) of the token. By default, the PPID and the issuer's public key are hashed together to generate a UniqueID. To use a different field, add a line like this:

<add name="IdentityClaimType" value=
     value="http://schemas.xmlsoap.org/ws/2005/05/identity/
     claims/privatepersonalidentifier" />

replacing the value with the URI for your unique claim.

Claims

A read-only String collection of the claims in the token. Provides support for the indexed claims accessor:

securityToken.Claims[ClaimsTypes.PPID]
IssuerIdentityClaim

The issuer's identity claim (most likely, the public key of the issuing authority).

In this example, you're going to get some of the claims, grab some of the decrypted data, and display it back in your return page. Go ahead and create that page now. Right-click on your web site in the Solution Explorer, select "Add New Item," and add a Web Form called Results.aspx (see Figure 14.13, "Adding the Results.aspx web form to your project"). This is the page you'll use to display the decrypted information you were able to gather from the CardSpace interaction with the user.

Figure 14.13. Adding the Results.aspx web form to your project

Adding the Results.aspx web form to your project

Next, you need to add two references to your web site. Right-click on your CardSpaces web site icon and select "Add Reference" from the drop-down menu. You will need to add System.Identity.Model and System.Identity.Model.Selectors from the .NET tab, as seen in Figure 14.14, "Adding the Systems.IdentityModel components".

Figure 14.14. Adding the Systems.IdentityModel components

Adding the Systems.IdentityModel components

To continue with your project housekeeping, you're going to add a little information to your Web.config file. You need to identify the certificate subject, the store name, and the store location to use when attempting to process the Windows CardSpace authentication. In this case, you'll use the Fabrikam certificate that you installed earlier in this chapter.

Add the following appSettings element to your Web.config file:

<appSettings>
   <add key="CertificateSubject" value="www.fabrikam.com"/>
   <add key="StoreName" value="My"/>
   <add key="StoreLocation" value="LocalMachine"/>
   <add key="IdentityClaimType"
        value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/

   <add key="MaximumClockSkew" value="60"/>
</appSettings>

This will allow you to utilize the Fabrikam cert you loaded into IIS to decrypt the card's claims.

Next, remove the Default.aspx component from your web project. To do this, right-click on Default.aspx and select "Delete." Replace this page with a regular HTML page called Default.htm (see Figure 14.15, "Adding Default.htm").

Figure 14.15. Adding Default.htm

Adding Default.htm

Here's the complete listing for Default.htm:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>Programming .NET 3.5 :: CardSpaces Demo</title>
</head>
<body>
   <form method="post" action="Results.aspx">
   <div>
      <object type="application/x-informationcard" name="identityToken">
         <param name="tokenType"
             value="urn:oasis:names:tc:SAML:1.0:assertion" />
         <param name="issuer"
             value="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" />
         <param name="requiredClaims" value ="
             http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
             http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
             http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality
             http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country
             http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth
             http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
             http://schemas.xmlsoap.org/ws/2005/05/identity/claims/
                    privatepersonalidentifier"/>
      </object>

      <input type="submit" name="SignInButton"
          value="Authenticate using CardSpace!" />
   </div>
   </form>
</body>
</html>

Embedded in this HTML document is the line <object type="application/x-informationcard" name="identityToken">. This is the object that does the work of calling Windows CardSpace. In this example you're binding its activation to a Submit button because the object is attached to the form. It will direct the results to your Results.aspx page. A quick look at the parameters of the object shows how you will interact with CardSpace.

The first parameter sets up the token type:

<param name="tokenType"
    value="urn:oasis:names:tc:SAML:1.0:assertion" />

The next parameter is where you identify the issuer:

<param name="issuer"
    value="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" />

In this case, you're willing to accept a self-signed certificate as opposed to one that you created and distributed.

Last, you list all the claims that you require your users to provide:

<param name="requiredClaims" value ="
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/
           privatepersonalidentifier"/>

You'll be able to access these values after decryption. Once you have a Token, you can simply extract the claims like this:

aToken.Claims[ClaimTypes.GivenName]

In this example, you'll get back a string for the user's first name.

The complete specification for these parameters is as follows:

<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright &#169; 2006-2007 Microsoft Corporation, Inc. All rights reserved.
-->

<xs:schema
    targetNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"
    xmlns:tns="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
    blockDefault="#all" version="0.1">
   <xs:import namespace="http://www.w3.org/XML/1998/namespace"
       schemaLocation="http://www.w3.org/2001/xml.xsd" />
   <xs:simpleType name="StringMaxLength255MinLength1">
      <xs:restriction base="xs:string">
         <xs:maxLength value="255" />
         <xs:minLength value="1" />
      </xs:restriction>
   </xs:simpleType>
   <xs:simpleType name="Base64BinaryMaxSize1K">
      <xs:restriction base="xs:base64Binary">
         <xs:maxLength value="1024" />
      </xs:restriction>
   </xs:simpleType>
   <!--
   Gender claims are serialized as follows: 0-Unspecified, 1-Male, 2-Female
   -->
   <xs:simpleType name="GenderType">
      <xs:restriction base="xs:token">
         <xs:enumeration value="0" />
         <xs:enumeration value="1" />
         <xs:enumeration value="2" />
      </xs:restriction>
   </xs:simpleType>
   <!--
   Standard claim types defined by the information card model
   -->
   <xs:element name="givenname" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="surname" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="emailaddress" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="streetaddress" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="locality" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="stateorprovince" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="postalcode" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="country" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="primaryphone" type="tns:StringMaxLength255MinLength1" />
   <xs:element name="dateofbirth" type="xs:date" />
   <xs:element name="privatepersonalidentifier" type="tns:Base64BinaryMaxSize1K" />
   <xs:element name="gender" type="tns:GenderType" />
   <xs:element name="webpage" type="tns:StringMaxLength255MinLength1" />
</xs:schema>

Run your application now. To properly connect to the site, change the URL Visual Studio automatically created to https://www.fabrikam.com/CardSpaces/Default.aspx.

You should get a Windows CardSpace request to supply a card, similar to the one in Figure 14.16, "The data to be sent is marked with an asterisk (*)". Notice that the claims listed as being required by the site are the same ones that you listed in the requiredClaims parameter.

Figure 14.16. The data to be sent is marked with an asterisk (*)

The data to be sent is marked with an asterisk (*)

More likely than not, you got a blank page when you submitted the card. This is OK, because you have not written the results component yet. You'll do that next.

Processing the Information Card

As discussed previously, you're going to grab the following information from the CardSpace information card:

  • First Name

  • Last Name

  • Email Address

  • City

  • Country/Region

  • Site-specific card ID

In this example, you'll display the information in two ways. To begin with, you're going to fill in a number of asp:Labels on your page with the decrypted values that you retrieve from the card.

Your .aspx file will contain these lines:

The Identity Card provided contains the following information:
<br />
<br />
Name:      <asp:Label ID="FirstName" runat="server" Text=""/>
           <asp:Label ID="LastName" runat="server" Text="" /><br />
City:      <asp:Label ID="City" runat="server" Text=""/><br />
Country:   <asp:Label ID="Country" runat="server" Text=""/><br />
Email:     <asp:Label ID="Email" runat="server" Text=""/><br />
Unique ID: <asp:Label ID="UID" runat="server" Text=""/><br />

As you can see, this is very straightforward. In your .aspx.cs code, you'll set these values in the following manner:

Token aToken = new Token(identityToken);

FirstName.Text = aToken.Claims[ClaimTypes.GivenName];
LastName.Text = aToken.Claims[ClaimTypes.Surname];
City.Text = aToken.Claims[ClaimTypes.Locality];
Country.Text = aToken.Claims[ClaimTypes.Country];
Email.Text = aToken.Claims[ClaimTypes.Email];
UID.Text = aToken.UniqueID;

The next thing you'll want to do is leverage TokenHelper.cs to iterate through the set of claims and write them out longhand (so to speak). While it may seem a bit redundant, this emphasizes that there is more than one approach to accessing the decrypted claims.

To accomplish this, you're going to add an asp:Literal element to your .aspx file:

<asp:Literal ID="ResultsLiteral" runat="server" />

At runtime, you'll use code to build up an HTML table that will get inserted into this element's Text property. To start with, you'll define the top of the table and the headers as follows:

ResultsLiteral.Text += "<table border=\"1\" width=\"640\"><tr>
    <th width=\"200\">Type</th><th width=\"240\">Resource</th></tr>";

Next, you'll instantiate a new TokenHelper using the identityToken passed in by CardSpace. As when you instantiated a Token object using Microsoft's TokenProcessor class, this instantiation will handle the decryption for you:

TokenHelper tokenHelper = new TokenHelper(identityToken);

Now it is simply a matter of iterating over each Claim in the TokenHelper's IdentityClaims collection and building the rows of the table:

foreach (Claim aClaim in tokenHelper.IdentityClaims)
{
   ResultsLiteral.Text += "<tr>";
   ResultsLiteral.Text += "<td width=\"200\">" +
       aClaim.ClaimType + "</td>";
   ResultsLiteral.Text += "<td width=\"240\">" +
       aClaim.Resource.ToString() + "</td>";
   ResultsLiteral.Text += "</tr>";
}

Finally, when you've run out of claims, you need to close out the HTML table:

   ResultsLiteral.Text += "</table>";
}

Now add the complete listings to your project.

Please note that you need to make sure you are not validating the incoming request (i.e., set ValidateRequest="false"), as the request comes across with the card as embedded XML and will cause the validation engine to kick it back. Here is the complete listing for Results.aspx:

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
   <title>Programming .NET 3.5 :: CardSpaces Results</title>
   <style type="text/css">
      .cardspaceTable
      {
         font-family: Verdana;
         font-size: x-small;
         font-weight: normal;
      }
   </style>
</head>
<body>

   <form id="identityForm" runat="server">
   <div class="cardspaceTable">
      The Identity Card provided contains the following information:
      <br />
      <br />
      Name: <asp:Label ID="FirstName" runat="server" Text=""/>
            <asp:Label ID="LastName" runat="server" Text="" /><br />
      City: <asp:Label ID="City" runat="server" Text=""/><br />
      Country: <asp:Label ID="Country" runat="server" Text=""/><br />
      Email: <asp:Label ID="Email" runat="server" Text=""/><br />
      Unique ID: <asp:Label ID="UID" runat="server" Text=""/><br />
      <br /><br />In the form of these decrypted claims:</br>
      <asp:Literal ID="ResultsLiteral" runat="server" />
   </div>
   </form>

</body>
</html>

And here's the complete listing for Results.aspx.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using Microsoft.IdentityModel.TokenProcessor;
using Microsoft.IdentityModel.Samples;
using System.IdentityModel.Claims;
using System.IdentityModel.Tokens;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Results : System.Web.UI.Page
{
   protected void Page_Load(object sender, EventArgs e)
   {
      String identityToken;
      identityToken = Request.Params["identityToken"];

      if (identityToken == null || identityToken == "")
      {
         identityToken = "Oops! Someone forgot to tell us who they were...";
      }
      else
      {
         Token aToken = new Token(identityToken);

         FirstName.Text = aToken.Claims[ClaimTypes.GivenName];
         LastName.Text = aToken.Claims[ClaimTypes.Surname];
         City.Text = aToken.Claims[ClaimTypes.Locality];
         Country.Text = aToken.Claims[ClaimTypes.Country];
         Email.Text = aToken.Claims[ClaimTypes.Email];
         UID.Text = aToken.UniqueID;

         ResultsLiteral.Text += "<table border=\"1\" width=\"640\"><tr>
             <th width=\"200\">Type</th><th width=\"240\">Resource</th></tr>";

         TokenHelper tokenHelper = new TokenHelper(identityToken);

         foreach (Claim aClaim in tokenHelper.IdentityClaims)
         {
            ResultsLiteral.Text += "<tr>";
            ResultsLiteral.Text += "<td width=\"200\">" +
                aClaim.ClaimType + "</td>";
            ResultsLiteral.Text += "<td width=\"240\">" +
                aClaim.Resource.ToString() + "</td>";
            ResultsLiteral.Text += "</tr>";
         }

         ResultsLiteral.Text += "</table>";

      }
   }
}

Assuming all went well, you should be able to run the application now. Don't forget to use SSL by specifying https:// instead of http://, as in https://www.fabrikam.com/CardSpaceExample/Default.htm . If you don't use SSL, you'll get the following exception: "The page you are trying to access is secured with Secure Sockets Layer (SSL)."

Also, if you interact directly with the browser page that opens up when you run the application in Visual Studio, instead of changing the URL from localhost to www.fabrikam.com, you will get the following stack trace:

at Microsoft.IdentityModel.TokenProcessor.Token.decryptToken(
String xmlToken)
in c:\\3.5\\CardSpaces\\App_Code\\TokenProcessor.cs:line 364\r\n
at Microsoft.IdentityModel.TokenProcessor.Token..ctor(String xmlToken)
in c:\\3.5\\CardSpaces\\App_Code\\TokenProcessor.cs:line 145\r\n
at Results.Page_Load(Object sender, EventArgs e)
in c:\\3.5\\CardSpaces\\Results.aspx.cs:line 31\r\n
at System.Web.Util.CalliHelper.EventArgFunctionCaller(
IntPtr fp, Object o, Object t, EventArgs e)\r\n
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(
Object sender, EventArgs e)\r\n
at System.Web.UI.Control.OnLoad(EventArgs e)\r\n   at System.Web.UI.Control.
LoadRecursive()\r\n   at System.Web.UI.Page.ProcessRequestMain(
Boolean includeStagesBeforeAsyncPoint,
Boolean includeStagesAfterAsyncPoint)

This is a fancy way of saying that the web site could not identify the encryption you were using (in no small part because you weren't actually using encryption).

On the other hand, if you hit the correct URL through SSL, you should get a page that looks like the one in Figure 14.17, "A successful run".

CardSpace provides the identification and authentication required for web-based transactions, while allowing the end user to select exactly how much information to provide to a given web site. It is expected that a typical web user will create a small number of specific identities: perhaps one fake identity to avoid junk email, one with minimal identification for casual membership, one with typical identification for shopping, and finally one with strong identification for commercial transactions, banking, and so forth. As CardSpace gains wider acceptance, we can anticipate that institutions such as banks and brokerage houses will begin to issue individualized cards. Over time, there may be an ebb and flow between individualized and more generalized cards.

One of the key aspects that will govern the success of CardSpace and the Identity Metasystem will be user acceptance. That is, users will have to find the technology compelling, valuable, trustworthy, and easy to use and understand.

Figure 14.17. A successful run

A successful run

Traditionally, this has been a hard problem when it comes to security tokens and transactions. You only have to go to your local grocery store to see how difficult it is for a new technology to gain acceptance. Wait a while, and you're sure to see someone write out a check rather than using a debit or credit card. More often than not, the check-writers are older people who, when asked, will tell you they have never used a debit card because checks are "so convenient." They simply don't find the debit card compelling. Many who do find credit/debit cards compelling don't find them trustworthy, especially when they're used over the Internet. Identity systems that are both compelling and trustworthy are usually not easy to use and easy to understand. Whether CardSpace will meet all these needs and gain sufficient acceptance remains an open question at the time of this writing.

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.