Using Simple STS and managed cards with the simple WPF sample

Well, what a alliterative title :-)

I've been asked in several occasions how to use managed cards, and specifically the simple STS sample, together with the surprisingly popular WPF smartclient sample. It is not especially difficult: few changes in the configuration and you're all set. The only nuisances arise from the fact that when you set up a full end to end CardSpace scenario sample on a single machine you are basically trying to sing, play the guitar and the drums at the same time: setting up SSL for RPs and IPs, tweaking the hosts file for mapping website names to IPs, setting up certificates and permissions, making sure that web proxies and ISA will not sabotage your "artificial" connectivity, setting up virtual directories for CRLs and logotypes... those are all things that need to be done. In this case we can make some serious semplification by not adding any virtual directory, since all moving parts live in a dedicated process (RPs and STS in their own console app, the client in the WPF app). That would mean no logotypes and no CRL, though. While for the sake of the example we can go around the former, the latter has the potential of upsetting WCF big time; we'll how to mitigate that. Just remember that logotypes and CRL would be something you don't want to give up in production, here we are simply trying to see CardSpace in action. In this post I am making the assumption that you set up the simple STS at the address , and that it is secured by a certificate with the appropriate subject.

Step 1 - Modify MeteoService for accepting tokens associated to managed cards

First things first. If we want to use managed cards, we must have an RP in the picture that requires their usage. I picked for this MeteoService ("Meteo", BTW, is a prefix that in Italian and various other languages is used in association with weather). In WCF terms, this means that we need to use a binding expressive enough to describe the features we want to mandate in the token we'll receive: this is routinely accomplished by using wsFederationHttpBInding.
Let's open the App.Config of the MeteoService project, and modify the system.serviceModel/services section as shown below:

<service name="MeteoService.Meteo"

     behaviorConfiguration="MeteoServiceBehavior">

<!--<endpoint

  address="MeteoEndpoint"

  contract="MeteoService.IMeteo"

  binding="wsHttpBinding"

  bindingConfiguration="MeteoBinding"

          >-->

<endpoint

  address="MeteoEndpoint"

  contract="MeteoService.IMeteo"

  binding="wsFederationHttpBinding"

  bindingConfiguration="fedBinding"

>

   <identity>

   <certificateReference

        findValue="www.test.fabrikam.com"

        storeLocation="LocalMachine"

        storeName="My"

        x509FindType="FindBySubjectName" />

   </identity>

 </endpoint>

 <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />

 </service>

   

We didn't make much of a change: we simply substituted wsHttpBinding with wsFederationHttpBinding, and changed the binding configuration reference name (for simplifying things on the client side; more about it later).
Now we have to provide the binding configuration. Always in the App.Config file, let's add the following in the section system.serviceModel/bindings:

<wsFederationHttpBinding>

 <binding name="fedBinding">

   <security mode="Message" >

     <message issuedKeyType="AsymmetricKey">

       <claimTypeRequirements>

         <add claimType="https://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"/>

     </claimTypeRequirements>

     <issuer address="https://www.test.contoso.com:7000/sample/trust/selfissuedsaml/sts"/>

   </message>

  </security>

  </binding>

 </wsFederationHttpBinding>

Here there's more to say. The green part defines the claims we want to receive in the token (hint: in a real system, we probably want to ask for the PPID claim too). The light blue part defines the URI of the STS that our RP decided to trust: in this case we are referring to the selfissued cards-backed managed cards endpoint, so remember to create your sample managed cards accordingly (or change this endpoint reference if you are using different card types). The orange part is very important for using the simple STS correctly (thank you Lucas! When do you start blogging? :-)), and determines the kind of key used.

Step 2 - Modify the client configuration for matching the new service requirements

That's truly straightforward, it mirrors exactly what we've done in step 1. Under system.serviceModel/client you replace the endpoint MeteoCLient with the following:

<endpoint

  name="MeteoClient"

  address="https://localhost:4127/MeteoService/MeteoEndpoint"

  contract="MeteoService.IMeteo"

  binding="wsFederationHttpBinding"

  bindingConfiguration="fedBinding"

  behaviorConfiguration="MyClientBehavior">

  <!--<endpoint

 name="MeteoClient"

 address="https://localhost:4127/MeteoService/MeteoEndpoint"

 contract="MeteoService.IMeteo"

 binding="wsHttpBinding"

 bindingConfiguration="myBinding"

 behaviorConfiguration="MyClientBehavior">-->

  <identity>

    <certificateReference

        findValue='www.test.fabrikam.com'

        storeLocation='LocalMachine'

        storeName='My'

        x509FindType='FindBySubjectName' />

  </identity>

</endpoint>

And you add the following under system.serviceModel/bindings:

<wsFederationHttpBinding>

  <binding name="fedBinding">

  <security mode="Message">

  <message issuedKeyType="AsymmetricKey">

  <issuer address="https://www.test.contoso.com:7000/sample/trust/selfissuedsaml/sts"/>

    <claimTypeRequirements>

  <add claimType="https://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"/>

         </claimTypeRequirements>

       </message>

     </security>

   </binding>

 </wsFederationHttpBinding>

All the rest stays the same, including our magical caching behavior

SimpleCardSpaceTokenClientCredentials.

We are practically all set! There's only one last tactical thing to do:

Tactical step - disable the CRL check on the certificate used for signing the issued token

In this class of samples it's fairly common to disable the CRL check, in order to keep the configuration clutter to a manageable level. That is usually applied in the configuration, namely in the elements that describe certificates associated to endpoints. When you use an issued token, however, you have the problem that the certificate used for signing it is assigned to another endpoint (the STS) so controlling the check on it via configuration is pretty tricky in this version of WCF. The quick & dirty alternative is disabling the CRL check via code. Again, on a production system this step would not be necessary since you'd want a CRL available (or, if your policy states otherwise, this would be reflected in your certificates). The modification is fairly painless (thank you Caleb! When do you start blogging?:-)), you just add the orange line in the program.cs file from the MeteoService project:

class Program

{

  static void Main(string[] args)

  {

     ServiceHost sh = new ServiceHost(typeof(Meteo), new

       Uri("https://localhost:4127/MeteoService"));

   // added

     sh.Credentials.IssuedTokenAuthentication.RevocationMode =

      X509RevocationMode.NoCheck;

  sh.Open();

  Console.WriteLine("Service listening...");

  Console.WriteLine("Press <Enter> to finish");

  Console.ReadLine();

  sh.Close();

   }

}

You're all set: now when you will use the WPF client for getting meteo information you'll see that you'll be prompted for a managed card. Don't be scared if when you retrieve the claim values for preview in the identity selector you don't see anything, it's simply that the simple STS does not emit the display token (which is necessary for showing the claim values in the selector) but if you don't get any error message your "true" token has been issued and is ready to be sent to the RP.

Happy richclient+managedcards experimenting!