{"id":635,"date":"2006-11-02T13:20:46","date_gmt":"2006-11-02T21:20:46","guid":{"rendered":"\/?p=635"},"modified":"2006-11-02T14:21:11","modified_gmt":"2006-11-02T22:21:11","slug":"information-cards-supported-on-community-server","status":"publish","type":"post","link":"https:\/\/www.identityblog.com\/?p=635","title":{"rendered":"Information Cards supported on Community Server"},"content":{"rendered":"<p>Armand du Plessis at <a href=\"http:\/\/dotnet.org.za\/armand\/\">Impersonation Falure<\/a>&nbsp;writes about his work to add&nbsp;Information Card support to his Community Server:<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>A couple of days ago I enabled experimental Windows Cardspace support on <a href=\"http:\/\/dotnet.org.za\/\">http:\/\/dotnet.org.za\/<\/a>. I mentioned that I&#39;ll post the source code and controls but with Tech-Ed Africa and some other work I never got around to posting it.<\/p>\n<p>So now the updated Community Server files is available <a href=\"http:\/\/dotnet.org.za\/files\/folders\/source\/entry70912.aspx\">here<\/a> and the source code for both the Community Server controls and the underlying ASP.NET controls available <a href=\"http:\/\/dotnet.org.za\/files\/folders\/source\/entry70925.aspx\">here<\/a>.<\/p>\n<p>To enable Community Server to make use of Information Cards for authentication the following steps are required :<\/p>\n<ul>\n<li>Install and configure your site with a SSL certificate. (Make sure it&#39;s a certificate issued by a Certification Authority trusted by popular browsers so you don&#39;t make the same mistake as me. See <a href=\"http:\/\/dotnet.org.za\/armand\/archive\/2006\/10\/18\/Windows-CardSpace-Support.aspx\">this<\/a> post for more info)<\/li>\n<li>Grant access to the certificate&#39;s private key to your application pool user. Easiest method to do this is using the winhttpcertcfg.exe utility.\n<ul>\n<li><strong>winhttpcertcfg -g -c CertLocation -s SubjectStr -a Account<\/strong><\/li>\n<\/ul>\n<\/li>\n<li>Add your certificate&#39;s thumbprint to your web.config appSettings section so the Token processor helper class can find it :\n<ul>\n<li \/>\n<li>The thumbprint can be obtained through the MMC Certificates snap-in.<\/li>\n<\/ul>\n<\/li>\n<li>Unzip the updated Community Server files over the CS web files. The following files will be replaced so make sure you&#39;ve backed them up before this step :\n<ul>\n<li>\\Themes\\default\\Masters\\master.ascx<\/li>\n<li>\\Themes\\default\\Skins\\Skin-EditProfile.ascx<\/li>\n<li>\\login.aspx<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>How it works is relatively straigth forward, kudos to the design of the Cardspace web integration and the Community Server SDK. A quick explanation :<\/p>\n<p>The source consists of four core controls :<\/p>\n<ol>\n<li><strong>Adp.CardSpace.InformationCardRequest <\/strong>&#8211; 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 <strong>InformationCardSubmit<\/strong> control, or as a standalone in a form body.<\/li>\n<li><strong>Adp.CardSpace.InformationCardSubmit <\/strong>&#8211;<strong>&nbsp; <\/strong>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&#39;s <strong>OnTokenReady<\/strong> event which is fired when a postback triggered by the ICS happens.<\/li>\n<li><strong>Adp.CommunityServer.Controls.Association &#8211; <\/strong>A Community Server control used in the profile section to allow a user to associate an Information Card with his\/her account.<\/li>\n<li><strong>Adp.CommunityServer.Controls.CardSpaceLogin &#8211; <\/strong>A Community Server control used to authenticate the user using his Information Card instead of the usual username\/password.<\/li>\n<\/ol>\n<p>The claim requirements is expressed through the Claims property on the <strong><em>Adp.Cardspace.InformationCardRequest<\/em><\/strong> 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.<\/p>\n<p>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)&nbsp;<\/p>\n<div class=\"csharpcode\">\n<div class=\"csharpcode\">\n<pre class=\"alt\"><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">CS:Head<\/span> <span class=\"attr\">runat<\/span><span class=\"kwrd\">=\"Server\"<\/span><span class=\"kwrd\">><\/span><\/pre>\n<pre><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">meta<\/span> <span class=\"attr\">http-equiv<\/span><span class=\"kwrd\">=\"Content-Type\"<\/span> <span class=\"attr\">content<\/span><span class=\"kwrd\">=\"text\/html; charset=UTF-8\"<\/span> <span class=\"kwrd\">\/><\/span><\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">CS:Style<\/span> <span class=\"attr\">id<\/span><span class=\"kwrd\">=\"UserStyle\"<\/span> <span class=\"attr\">runat<\/span><span class=\"kwrd\">=\"server\"<\/span> <span class=\"attr\">visible<\/span> = <span class=\"kwrd\">\"true\"<\/span> <span class=\"kwrd\">\/><\/span><\/pre>\n<pre><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">CS:Style<\/span> <span class=\"attr\">id<\/span><span class=\"kwrd\">=\"s2\"<\/span> <span class=\"attr\">runat<\/span><span class=\"kwrd\">=\"server\"<\/span> <span class=\"attr\">visible<\/span> = <span class=\"kwrd\">\"true\"<\/span> <span class=\"attr\">Href<\/span><span class=\"kwrd\">=\"..\/style\/Common.css\"<\/span> <span class=\"kwrd\">\/><\/span><\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">CS:Style<\/span>  <span class=\"attr\">runat<\/span><span class=\"kwrd\">=\"server\"<\/span> <span class=\"attr\">Href<\/span><span class=\"kwrd\">=\"..\/style\/common_print.css\"<\/span> <span class=\"attr\">media<\/span><span class=\"kwrd\">=\"print\"<\/span> <span class=\"kwrd\">\/><\/span><\/pre>\n<pre><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">CS:Script<\/span> <span class=\"attr\">id<\/span><span class=\"kwrd\">=\"s\"<\/span> <span class=\"attr\">runat<\/span><span class=\"kwrd\">=\"server\"<\/span>  <span class=\"kwrd\">\/><\/span><\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">ADP:InformationCardRequest<\/span> <span class=\"attr\">ID<\/span><span class=\"kwrd\">=\"_xmlToken\"<\/span> <span class=\"attr\">runat<\/span><span class=\"kwrd\">=\"server\"<\/span> <span class=\"attr\">Claims-Capacity<\/span><span class=\"kwrd\">=\"4\"<\/span><span class=\"kwrd\">><\/span><\/pre>\n<pre><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">ADP:ClaimDto<\/span> <span class=\"attr\">ClaimType<\/span><span class=\"kwrd\">=\"http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/claims\/privatepersonalidentifier\"<\/span> <span class=\"attr\">Required<\/span><span class=\"kwrd\">=\"true\"<\/span> <span class=\"kwrd\">\/><\/span><\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">ADP:ClaimDto<\/span> <span class=\"attr\">ClaimType<\/span><span class=\"kwrd\">=\"http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/claims\/emailaddress\"<\/span> <span class=\"attr\">Required<\/span><span class=\"kwrd\">=\"true\"<\/span> <span class=\"kwrd\">\/><\/span><\/pre>\n<pre><span class=\"kwrd\"><\/span><span class=\"html\">ADP:InformationCardRequest<\/span><span class=\"kwrd\">><\/span><\/pre>\n<pre class=\"alt\"><span class=\"kwrd\"><\/span><span class=\"html\">CS:Head<\/span><span class=\"kwrd\">><\/span><\/pre>\n<\/div>\n<p>&nbsp;Where the Identity Selector trigger is required the <strong><em>Adp.Cardspace.InformationCardSubmit <\/em><\/strong>control is placed. The sole responsibilty of this control is to invoke the Identity Selector and raise an <strong>OnTokenReady <\/strong>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&nbsp;token)<\/p>\n<div class=\"csharpcode\">\n<pre class=\"alt\"><span class=\"kwrd\">< <\/span><\/span><span class=\"html\">ADP:InformationCardSubmit<\/span> <span class=\"attr\">CssClass<\/span> = <span class=\"kwrd\">\"CommonTextButtonBig\"<\/span> <span class=\"attr\">runat<\/span><span class=\"kwrd\">=\"server\"<\/span> <span class=\"attr\">id<\/span><span class=\"kwrd\">=\"csSubmit\"<\/span> <span class=\"kwrd\">\/><\/span><\/pre>\n<\/div>\n<p>&nbsp;That&#39;s all that&#39;s required to invoke the ICS. To decrypt and extract the token using the very useful <strong>TokenProcessor<\/strong> from the Microsoft samples the following code is required&nbsp;to hookup and handle the <strong>OnTokenReady<\/strong> event.<em>&nbsp;(This code is in the above mentioned CardSpaceLogin control, a composite control&nbsp;utilizing the InformationCardSubmit control and other default Community Server Controls)&nbsp;<\/em><\/p>\n<div class=\"csharpcode\">\n<pre class=\"alt\"><span class=\"kwrd\">protected<\/span> <span class=\"kwrd\">override<\/span> <span class=\"kwrd\">void<\/span>  AttachChildControls()<\/pre>\n<pre>{<\/pre>\n<pre class=\"alt\">submit = FindControl(<span class=\"str\">\"csSubmit\"<\/span>) <span class=\"kwrd\">as<\/span> InformationCardSubmit;<\/pre>\n<pre>message = FindControl(<span class=\"str\">\"csMessage\"<\/span>) <span class=\"kwrd\">as<\/span> StatusMessage;<\/pre>\n<pre class=\"alt\">&nbsp;<\/pre>\n<pre>submit.OnTokenReady += <span class=\"kwrd\">new<\/span> EventHandler<tokeneventargs>(submit_OnTokenReady);<\/tokeneventargs><\/pre>\n<pre class=\"alt\"><\/pre>\n<pre><span class=\"kwrd\">if<\/span> ((submit == <span class=\"kwrd\">null<\/span>) || (message == <span class=\"kwrd\">null<\/span>))<\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">throw<\/span> <span class=\"kwrd\">new<\/span> CSException(CSExceptionType.SkinNotSet);<\/pre>\n<pre>}<\/pre>\n<\/div>\n<p>The <strong>Token<\/strong> helper class takes care of decrypting and extracting all the tokens from the postback. (The token helper class is available in the samples on <a href=\"http:\/\/wcs.netfx3.com\/\" class=\"broken_link\">http:\/\/wcs.netfx3.com<\/a>)<\/p>\n<p>After breaking out the tokens we can access them through the indexed Claims property. All the claims we expressed in the <strong>InformationCardRequest<\/strong> control above is available for use in your code.&nbsp;&nbsp;In the sample below the token&#39;s unique id is extracted and assigned to an extended profile attribute in Community Server.<\/p>\n<div class=\"csharpcode\">\n<pre class=\"alt\"><span class=\"kwrd\">void<\/span> submit_OnTokenReady(<span class=\"kwrd\">object<\/span> sender, TokenEventArgs e)<\/pre>\n<pre>{<\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">try<\/span> {<\/pre>\n<pre>Token token = <span class=\"kwrd\">new<\/span> Token(e.TokenValue);<\/pre>\n<pre class=\"alt\"><\/pre>\n<pre><span class=\"kwrd\">if<\/span>(context.User.Email !=<\/pre>\n<pre class=\"alt\">token.Claims[System.IdentityModel.Claims.ClaimTypes.Email]) {<\/pre>\n<pre><\/pre>\n<pre class=\"alt\">DisplayMessage(ResourceManager.GetString(<span class=\"str\">\"Association_EmailMismatch\"<\/span>,<\/pre>\n<pre>CSUtil.CsResourceFilename), <span class=\"kwrd\">false<\/span>);<\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">return<\/span>;<\/pre>\n<pre>}<\/pre>\n<pre class=\"alt\">&nbsp;<\/pre>\n<pre>context.User.SetExtendedAttribute(CSUtil.CsExtendedAttributeName,<\/pre>\n<pre class=\"alt\">token.UniqueID);<\/pre>\n<pre><\/pre>\n<pre class=\"alt\">Users.UpdateUser(context.User);<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\">DisplayMessage(<\/pre>\n<pre>ResourceManager.GetString(<span class=\"str\">\"Association_Success\"<\/span>,<\/pre>\n<pre class=\"alt\">CSUtil.CsResourceFilename),<span class=\"kwrd\">true<\/span>);<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\">}<\/pre>\n<pre><span class=\"kwrd\">catch<\/span> (Exception e1) {<\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">string<\/span> displayMessage = ResourceManager.GetString(<span class=\"str\">\"Association_GenericException\"<\/span>,<\/pre>\n<pre>CSUtil.CsResourceFilename);<\/pre>\n<pre class=\"alt\">&nbsp;<\/pre>\n<pre>CSException e2 = <span class=\"kwrd\">new<\/span> CSException(CSExceptionType.UnknownError,<\/pre>\n<pre class=\"alt\">displayMessage, e1);<\/pre>\n<pre><\/pre>\n<pre class=\"alt\">e2.Log();<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\">DisplayMessage(displayMessage, <span class=\"kwrd\">false<\/span>);<\/pre>\n<pre>}<\/pre>\n<pre class=\"alt\">}<\/pre>\n<\/div>\n<p>Some limitations in this implementation is that it currently don&#39;t detect whether or not the browser supports Infocards. Also triggering the Identity Selector through script currently don&#39;t seem to be supported by the Firefox Identity Selector plug-in.<\/p>\n<p>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.<\/p>\n<p><strong><em>Links:<\/em><\/strong><\/p>\n<ul>\n<li><a href=\"http:\/\/www.communityserver.org\/\">Community Server<\/a><\/li>\n<li><a href=\"http:\/\/wcs.netfx3.com\/\" class=\"broken_link\">Windows Cardspace<\/a><\/li>\n<\/ul>\n<\/div>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Armand&#39;s cool code takes InfoCards forward in Africa<\/p>\n","protected":false},"author":68,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16,19,6,7],"tags":[],"_links":{"self":[{"href":"https:\/\/www.identityblog.com\/index.php?rest_route=\/wp\/v2\/posts\/635"}],"collection":[{"href":"https:\/\/www.identityblog.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.identityblog.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.identityblog.com\/index.php?rest_route=\/wp\/v2\/users\/68"}],"replies":[{"embeddable":true,"href":"https:\/\/www.identityblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=635"}],"version-history":[{"count":0,"href":"https:\/\/www.identityblog.com\/index.php?rest_route=\/wp\/v2\/posts\/635\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.identityblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=635"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.identityblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=635"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.identityblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}