ASP.NET Under the Hood
LANGUAGES:
VB.NET | C#
ASP.NET
VERSIONS: 2.0
ASP.NET Meets CardSpace
Create a Rich Login Experience with IE 7 and Windows
CardSpace
By Michele Leroux Bustamante
Greetings ASP.NET architects and developers! This
installment of ASP.NET Under the Hood explains how you can incorporate Windows
CardSpace into your authentication and authorization model.
Q. How can I create a CardSpace login experience for my
users, while still supporting traditional login and integrating this with my existing
ASP.NET membership and roles provider implementation?
A. Windows CardSpace is a client technology that is part
of the .NET Framework 3.0. It is used for creating, managing, and sharing
digital identities in a secure and reliable manner. You can think of CardSpace
as an identity selector that securely stores informational claims about a user,
making it easy for that same user to send this information to a trusted Web
site for authentication purposes. But it isn t just an identity selector
CardSpace also makes it easier for users to identify the target site where
claims are sent by authenticating the site and presenting its credentials for
user approval. In addition, users can review the claims that the site has demanded,
and explicitly allow or disallow sending that information.
In this article I ll provide a brief introduction to
CardSpace. Then I ll jump into the details for how you can enable your ASP.NET Web
sites for CardSpace as a login alternative. If you re new to CardSpace I
recommend you read the articles listed at http://wcs.netfx3.com/content/Articles.aspx.
They ll help provide a foundation on the technology if you haven t explored
this part of the .NET Framework 3.0 release yet, as well as get you up to speed
on the specifics of CardSpace.
Information Cards and CardSpace: A Brief Tour
Cards refer to informational claims about a subject the
user that is to be given access to a Web site, Web service, or application
(known as the Relying Party or RP). Claims might include your name, address,
phone number, birth date, or any other information that might prove useful to
identify you. Different RPs may demand different sets of claims to authenticate
and authorize callers.
Two types of information cards exist: personal cards and
managed cards. Personal cards are self-issued cards that can be created
directly in the CardSpace user interface. Managed cards are obtained from a
third-party provider that is willing to assert that a set of claims really do
relate to you. CardSpace can store both types of cards, and creates or obtains
a security token containing the claims represented by those cards. That s the
ultimate goal to reliably create a security token that carries claims to identify
the user. The CardSpace user interface is accessible from the Digital
Identities icon in the Control Panel, as shown in Figure 1.
Figure 1: You can create and manage
cards from Digital Identities in the Control Panel. This option is installed
with .NET Framework 3.0 on XP/SP2.
When you select Digital Identities it launches a hardened
CardSpace user interface where you can safely create personal cards, import and
export cards, protect cards with a pin, and perform other functions related to
card management.
Personal cards can contain a limited set of claims, most
of which are shown in Figure 2. You may create one or more personal cards based
on the type of information you share with different sites. For example, I have
two cards one that contains my business e-mail, Web site, and related
information, and another for my personal e-mail, Web log, and related
information I might share. Personal cards work well for sites that I would
normally identify myself to with a username and password.
Figure 2: Creating a new personal
card with CardSpace.
When you create a self-issued card using CardSpace you
actually create two things: the information card and a separate record with
your actual claims. This distinction is important because the actual information
card does not contain the value of each claim. It is the responsibility of the
identity provider to store and protect the claims and issue tokens for those
claims based on a requested information card. In the case of self-issued cards
it just happens that a local identity provider exists inside the CardSpace environment
to do just that.
Managed cards may contain similar claims, but most likely
have custom claims that are required by the card issuer. For example, a bank
may vouch for your account number and an airline may vouch for your frequent
flyer number. The card issuer is entirely responsible for defining what claims
their managed cards represent.
In the case of managed cards, my bank may issue a card for
me to install in CardSpace, but the actual claims are stored remotely with the
bank s identity provider. When a managed card is selected in the CardSpace
interface, CardSpace makes a call to the managed identity provider to request a
token containing the required claims.
Identity Metasystem Participants and Browser Flow
Before I show you how to support CardSpace from your
ASP.NET Web sites, I ll explain the flow between participants in the Identity
Metasystem and the Browser experience.
There are several key participants:
- Relying
Party (RP). This is the target site that relies on a specific set of claims
to authenticate calls. In the context of this article, your ASP.NET Web site
would be the RP.
- Subject.
This is the user described by a set of claims. For example, the user logging in
to your Web site.
- Identity
Provider (IP). This party is responsible for generating a token that
includes a set of claims describing the subject. They are the holder of those
claims, and must keep them secure. They must sign the token to prove that they
are the party that supplied the claims.
- Windows
CardSpace. For Windows machines, CardSpace provides local storage for personal
and managed information cards that represent a list of claims. As I mentioned,
the card does not contain the actual claim values. For personal cards CardSpace
supplies a local IP that securely stores the actual claims. Thus, in cases
where personal cards are supported by the target site, CardSpace acts as both
identity selector and IP.
Figure 3 illustrates the interaction between each
participant, assuming personal cards (from CardSpace) are supported. Users
browse to a site that returns a login page supporting information cards. When
the user hits the login using CardSpace button, IE 7 hands off the request to
CardSpace and waits for a signed and encrypted token to be returned.
The hardened CardSpace user interface appears presenting
the user with cards that satisfy the claims required by the target site. If
they previously have selected a card for the site, that card will be
highlighted.
Figure 3: Interaction between user,
browser, relying party, and CardSpace for self-issued cards.
After the user selects a card to send to the site,
CardSpace sends a request to its local IP for a token containing the required
claims. The token is encrypted and signed by the local IP before CardSpace returns
it to the browser. Ultimately the token is posted to the RP via SSL.
The browser essentially calls GetToken on the CardSpace
API and waits for a signed and encrypted token to be returned. The entire
exchange with the user for creating or managing their cards through the
CardSpace user interface, for requesting the token from the IP, and for
encrypting that token is heavily locked down. This is illustrated by the shaded
area in the diagram. No malicious code can easily be injected into this
exchange.
Let s Log In with CardSpace!
With that brief introduction to CardSpace, let s talk
about the requirements for invoking the CardSpace user interface from an
ASP.NET page. Here is a list of basic requirements:
1) Your
Web site must be SSL-enabled.
2) A
recent build of IE 7 is required for a browser experience with CardSpace.
3) Your
ASP.NET pages can use the <object> tag or XHTML syntax to trigger the
CardSpace experience.
4) When
the security token is posted to the Web site, you are responsible for
processing the claims inside the token and using them to authenticate calls.
Figure 4 illustrates the use of the <object> tag to
launch the CardSpace user interface. The <object> tag can be placed
inside the header or in the <form> tag. When the ImageButton posts back
to the server the information card object is instantiated, using parameters as
input. The Windows desktop is locked down at this point, with the CardSpace UI
presented. After the user selects a card, CardSpace processes the request and
returns a signed and encrypted token to the browser. This token is posted to
the server as a form parameter by the name xmlTokenEncrypted per the <object>
tag name shown in Figure 4. Figure 5 illustrates how we achieve the same result
with XHTML.
<form name="formCardSpaceLoginOBJECT"
method="post"
id="formCardSpaceLoginOBJECT" runat="server">
...
<object
type="application/x-informationCard"
name="xmlTokenEncrypted"
id="xmlTokenEncrypted">
<param
name="tokenType"
value="urn:oasis:names:tc:SAML:1.0:assertion"/>
<param
name="issuer"
value="http://schemas.microsoft.com/ws/2005/05/identity/issuer/self"/>
<param
name="requiredClaims"
value="http://schemas.microsoft.com/ws/2005/05/identity/
claims/privatepersonalidentifier http://schemas.microsoft.com/ws/2005/05/identity/
claims/emailaddress"/>
</object>
...
<asp:ImageButton
ID="submitInformationCard" runat="server"
ImageUrl="CardSpaceLogin.jpg" />
</form>
Figure 4: Invoking
CardSpace with the <object> tag.
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ic=
"http://www.identityselectors.org/2006/10">
...
<body>
<form
name="formCardSpaceLoginXHTML" method="post"
id="formCardSpaceLoginXHTML" runat="server">
...
<ic:informationCard
name="xmlTokenEncrypted"
style="behavior:url(#default#informationCard)"
issuer="http://schemas.microsoft.com/ws/2005/05/identity/issuer/self"
tokenType="http://docs.oasis-open.org/wss/
oasis-wss-saml-token-profile-1.1#SAMLV1.1">
<ic:add
claimType="http://schemas.microsoft.com/ws/2005/05/identity/
claims/privatepersonalidentifier" optional="false"
/>
<ic:add
claimType="http://schemas.microsoft.com/ws/2005/05/identity/
claims/emailaddress" optional="false" />
</ic:informationCard>
...
<asp:ImageButton
ID="submitInformationCard"
ImageUrl="CardSpaceLogin.jpg" runat="server"
/>
</form>
</body>
</html>
Figure 5: Invoking
CardSpace with XHTML.
In both cases, the syntax of the <object> tag and
the XHTML code specified the following:
- What format of security token does the Web site support?
The <object> tag requires a SAML 1.0 token, and the XHTML code requires a
SAML 1.1 token.
- Which claims are required by the site for
authentication? In both cases, private personal identifier (PPID) and e-mail
address claims are required. These are two of the standard set of claims
supported by self-issued cards.
- Which identity provider (also called a security
token issuer) is trusted by the Web site? In both cases, self-issued tokens are
supported which implies the local CardSpace IP on Windows operating systems.
For managed cards, a specific IP might have been required to issue signed
tokens.
During postback you can access the issued SAML token
through the Request object:
string token = Request.Form["xmlTokenEncrypted"] as
string;
Now the question is, what do you do with this token?
Processing the Token
The token string is in the form of an <EncryptedData>
section. It is encrypted with the public key portion of the site s SSL
certificate. The code to decrypt it, therefore, must have access to the site s private
key. Specifically, the ASP.NET account will need permissions to access the
private key from the certificate store.
The code to decrypt the token is lengthy and a topic in and
of itself, so I ll let you look at the code sample for those details. After the
token is decrypted, what you ll find is that you are working with a SAML token
that has a set of claims inside. The claims are exactly those you requested (see
Figures 4 and 5). In this example the claims include a personal private identifier
(PPID) and an e-mail address but there is a complete list of valid claims in
the CardSpace specification, and this can be extended for managed cards.
Once you have decrypted the token and verified that it
includes the claims you requested, it is time to authenticate.
Associating Cards with User Accounts
Users typically log in to a Web site with a username and a
password. Both the username and password are required to authenticate. A site
that supports information cards is really stating that it supports
authentication against a set of claims. As mentioned, those claims might be a
username, e-mail address, birth date, or some other information. But anyone can
discover this information and create a card with the same data, so before we
can authenticate these claims we need to know that the claims came from a
trusted source. If it were a managed card, the token would be signed with the
trusted identity provider s private key. In the case of self-issued tokens, we
need to look at alternative ways to establish trust.
One approach is to have the card associated with the user
account. That implies that the user must log in with their username and
password prior to selecting a card to send to the site for the first time. Once
logged in the user can select a card, which sends the security token to the
site. If the claims posted with the card include the user s e-mail address,
this can be compared to the logged in user to verify the card matches the user.
In addition, the personal private identifier of the card can be stored and used
to associate that specific card with the user s account:
MembershipUser user = Membership.GetUser
(this.User.Identity.Name);
if (user.Email == emailClaim)
{
user.Comment = ppidClaim;
Membership.UpdateUser(user);
}
The PPID is a special type of claim. This is a unique
identifier for a particular card sent to a particular site. Because a card can
be used for multiple sites, CardSpace generates a PPID for every site to which a
card is sent. In short, the PPID represents the relationship between the
relying party and the information card.
With the PPID of the card associated with their account, a
user no longer has to provide their username and password to log in. When they
log in with the CardSpace option, instead of processing username and password
credentials, you can look up the user account by the e-mail address claim, and
then verify that the PPID of the posted token matches the PPID stored in the
user account (see Figure 6).
MembershipUser authenticatedUser = null;
MembershipUserCollection matchingUsers =
Membership.FindUsersByEmail(emailClaim);
if (matchingUsers.Count == 0)
{
// error
}
foreach (MembershipUser user in matchingUsers)
{
if (user.Comment ==
ppidClaim)
{
authenticatedUser =
user;
}
}
if (authenticatedUser == null)
{
//error
}
FormsAuthentication.RedirectFromLoginPage(emailClaim, false);
Figure 6: With the
PPID of the card associated with their account, a user no longer has to provide
their username and password to log in.
The call to RedirectFromLoginPage handles generating an
authentication ticket for the user, and redirecting to the originally requested
page just like the ASP.NET Login control would do with the username and
password.
Creating a Dual Purpose Login Page
The code sample accompanying this article includes a login
page that uses the ASP.NET Login control for traditional login, and the <object>
tag for those who have already associated their information cards with their
account (see end of article for download details). One of the challenges with
this is making sure that the <object> tag is only invoked when the user
clicks the CardSpace login button. Because we can t have two active <form>
tags in an ASP.NET page, I had to learn a little bit more about <object>
tags, how they are instantiated, and how to control that instantiation with JavaScript.
First, I placed the <object> tag declaration in the
header section of the HTML page. I also had to use the declare attribute of
the tag to indicate this was only a declaration, so that the CardSpace object
would not be instantiated until it is referenced by the CardSpace submit
button:
<object declare id="informationCard"
type="application/x-informationCard"
name="informationCard" >
...
</object>
Next, I created a JavaScript function,
SelectInformationCard, that would instantiate the CardSpace object, and put the
value it returns into a hidden text field:
<script type="text/javascript"
language="javascript">
function
SelectInformationCard()
{
var infoCardObject
=document.getElementById(
"informationCards");
var hiddenToken =
document.getElementById(
"hiddenXmlToken");
hiddenToken.value =
infoCardObject.value;
}
</script>
Within the <form> tag I arranged the Login control
and my CardSpace image button, along with the hidden text field (the latter two
are shown here):
<asp:ImageButton ID="cardSpaceSubmit"
runat="server"
ImageUrl="infocardlogin.jpg" />
<input id="hiddenXmlToken" type="hidden"
name="hiddenXmlToken" />
Then I associated the client-side function,
SelectInformationCard, to the ASP.NET ImageButton server control:
if (!this.IsPostBack)
{
this.cardSpaceSubmit.Attributes.Add("onclick",
"SelectInformationCard();");
}
This last step makes it possible for the server control to
invoke a client-side function prior to completing the postback. Of course, the
postback includes the hidden text field, which will contain the encrypted
token!
Conclusion
Allowing personal cards to be associated with a user s
login credentials can simplify their login experience significantly. Instead of
trying to remember their username and password every time they hit your site
they can log in once, associate an information card with their account, and in the
future go to CardSpace to log in with a few simple clicks. Hopefully this
article has provided you with enough of a teaser to inspire you to look at
CardSpace for this purpose.
The code for this article and related sample code is based
on the July CTP of .NET Framework 3.0. If you have additional questions on this
or other ASP.NET topics, drop me a line at mailto:underthehood@aspnetpro.com.
Thanks for reading!
C# and VB.NET code
examples are available for download.
Michele Leroux
Bustamante is Chief Architect at IDesign Inc., Microsoft Regional Director
for San Diego, Microsoft MVP for XML Web services, and a BEA Technical
Director. At IDesign Michele provides training, mentoring, and high-end
architecture consulting services, specializing in scalable and secure .NET
architecture design, globalization, Web services, and interoperability with
Java platforms. She is a board member for the International Association of
Software Architects (IASA), a frequent conference presenter, conference chair
of SD s Web Services track, and a frequently published author. She is currently
writing a book for O Reilly on the Windows Communication Foundation. Reach her
at http://www.idesign.net or http://www.dasblonde.net.