Information Cards supported on Community Server

Armand du Plessis at Impersonation Falure writes about his work to add Information Card support to his Community Server:

A couple of days ago I enabled experimental Windows Cardspace support on http://dotnet.org.za/. I mentioned that I'll post the source code and controls but with Tech-Ed Africa and some other work I never got around to posting it.

So now the updated Community Server files is available here and the source code for both the Community Server controls and the underlying ASP.NET controls available here.

To enable Community Server to make use of Information Cards for authentication the following steps are required :

  • Install and configure your site with a SSL certificate. (Make sure it's a certificate issued by a Certification Authority trusted by popular browsers so you don't make the same mistake as me. See this post for more info)
  • Grant access to the certificate's private key to your application pool user. Easiest method to do this is using the winhttpcertcfg.exe utility.
    • winhttpcertcfg -g -c CertLocation -s SubjectStr -a Account
  • Add your certificate's thumbprint to your web.config appSettings section so the Token processor helper class can find it :
    • The thumbprint can be obtained through the MMC Certificates snap-in.
  • Unzip the updated Community Server files over the CS web files. The following files will be replaced so make sure you've backed them up before this step :
    • \Themes\default\Masters\master.ascx
    • \Themes\default\Skins\Skin-EditProfile.ascx
    • \login.aspx

How it works is relatively straigth forward, kudos to the design of the Cardspace web integration and the Community Server SDK. A quick explanation :

The source consists of four core controls :

  1. Adp.CardSpace.InformationCardRequest - A very basic ASP.NET control that takes care of rendering the < object > element used to engage the Identity Selector with the desired claims the Relying Party wants from the Identity Provider. This can either be placed in the head of the page when working together with the InformationCardSubmit control, or as a standalone in a form body.
  2. Adp.CardSpace.InformationCardSubmit -  Another basic ASP.NET control that renders the required script and a button that can be used to engage the Identity Card Selector. It is meant for consumption by higer-level controls that can subscribe to it's OnTokenReady event which is fired when a postback triggered by the ICS happens.
  3. Adp.CommunityServer.Controls.Association – A Community Server control used in the profile section to allow a user to associate an Information Card with his/her account.
  4. Adp.CommunityServer.Controls.CardSpaceLogin – A Community Server control used to authenticate the user using his Information Card instead of the usual username/password.

The claim requirements is expressed through the Claims property on the Adp.Cardspace.InformationCardRequest control. This can be done programmatically or declaratively and the control added either to the page head or to a form body. Adding the control to the page head as done in the Community Server integration allows for fine grained control over when the Identity Selector is invoked without interfering with other form submit buttons on your page.

Below is an extract from master.ascx which embeds a request for two claims, email and PPID, into the page. (By default self-issued cards are accepted but this can be configured through the Issuer property on the control) 

< CS:Head runat="Server">
< meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
< CS:Style id="UserStyle" runat="server" visible = "true" />
< CS:Style id="s2" runat="server" visible = "true" Href="../style/Common.css" />
< CS:Style  runat="server" Href="../style/common_print.css" media="print" />
< CS:Script id="s" runat="server"  />
< ADP:InformationCardRequest ID="_xmlToken" runat="server" Claims-Capacity="4">
< ADP:ClaimDto ClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" Required="true" />
< ADP:ClaimDto ClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" Required="true" />
ADP:InformationCardRequest>
CS:Head>

 Where the Identity Selector trigger is required the Adp.Cardspace.InformationCardSubmit control is placed. The sole responsibilty of this control is to invoke the Identity Selector and raise an OnTokenReady event which can be consumed by other interested parties. Below is an extract from the Skin-CardspaceLogin.ascx (a Community Server control which uses the InformationCardSubmit control to obtain the encrypted token)

< ADP:InformationCardSubmit CssClass = "CommonTextButtonBig" runat="server" id="csSubmit" />

 That's all that's required to invoke the ICS. To decrypt and extract the token using the very useful TokenProcessor from the Microsoft samples the following code is required to hookup and handle the OnTokenReady event. (This code is in the above mentioned CardSpaceLogin control, a composite control utilizing the InformationCardSubmit control and other default Community Server Controls) 

protected override void  AttachChildControls()
{
submit = FindControl("csSubmit") as InformationCardSubmit;
message = FindControl("csMessage") as StatusMessage;
 
submit.OnTokenReady += new EventHandler(submit_OnTokenReady);

if ((submit == null) || (message == null))
throw new CSException(CSExceptionType.SkinNotSet);
}

The Token helper class takes care of decrypting and extracting all the tokens from the postback. (The token helper class is available in the samples on http://wcs.netfx3.com)

After breaking out the tokens we can access them through the indexed Claims property. All the claims we expressed in the InformationCardRequest control above is available for use in your code.  In the sample below the token's unique id is extracted and assigned to an extended profile attribute in Community Server.

void submit_OnTokenReady(object sender, TokenEventArgs e)
{
try {
Token token = new Token(e.TokenValue);

if(context.User.Email !=
token.Claims[System.IdentityModel.Claims.ClaimTypes.Email]) {

DisplayMessage(ResourceManager.GetString("Association_EmailMismatch",
CSUtil.CsResourceFilename), false);
return;
}
 
context.User.SetExtendedAttribute(CSUtil.CsExtendedAttributeName,
token.UniqueID);

Users.UpdateUser(context.User);
 
DisplayMessage(
ResourceManager.GetString("Association_Success",
CSUtil.CsResourceFilename),true);
 
}
catch (Exception e1) {
string displayMessage = ResourceManager.GetString("Association_GenericException",
CSUtil.CsResourceFilename);
 
CSException e2 = new CSException(CSExceptionType.UnknownError,
displayMessage, e1);

e2.Log();
 
DisplayMessage(displayMessage, false);
}
}

Some limitations in this implementation is that it currently don't detect whether or not the browser supports Infocards. Also triggering the Identity Selector through script currently don't seem to be supported by the Firefox Identity Selector plug-in.

Currently the implementation on dotnet.org.za still suffers from the use of the Starfield SSL certificate which requires users to first import the Intermediate Certificate as a trusted issuer before Cardspace will accept it. This will be rectified soon.

Links:

Published by

Kim Cameron

Work on identity.

One thought on “Information Cards supported on Community Server”

Comments are closed.