How to authenticate with ADSF in Silverlight 5 Application

This article uses sample from http://hashtagfail.com/post/11094642160/wcf-wif-silverlight-active-federation as start point and gives an example how to modify that sample to setup ADSF as STS token service for Silverlight 5 to authenticate against. ADSF returns saml token to Web Application that hosting SL5 application, and is decrypted and then get user Claims back to Silverlight Application for later WCF calls from Silverlight Application.

1. We start with Sample from http://hashtagfail.com/post/11094642160/wcf-wif-silverlight-active-federation - download and setup the sample. This sample uses its own in-process STS service. We are going to replace the STS service with ADSF as STS token service.

 2. Remove the project IdentityProviderAndSts from the sample solution.

3. Add ADSF STS token service

See the attached document for examples how to add ADSF STS token service in a project. Note the attached doc is a separated example on how to add ADSF STS token service to MVC Web Application. It is referenced here for the screen shots in the document how to add ADSF STS Service Reference - the stesp are the same. You can ignore the MVC part which is unrelated to this topic.

4. Deploy cleintaccesspolicy.xml to the root of the web site for ADSF, otherwise cross domain calls will be blocked.

Below is an example. Tighten teh security as you need,

 <?xml version="1.0" encoding="utf-8"?>
<access-policy>
   <cross-domain-access>
     <policy>
       <allow-from http-methods="*" http-request-headers="*">    
         <domain uri="*"/>
 <domain uri="http://*" />
 <domain uri="https://*" />
       </allow-from>    
       <grant-to>    
         <resource path="/" include-subpaths="true"/>
  <socket-resource port="4502-4530" protocol="tcp" />
       </grant-to>
     </policy>
   </cross-domain-access>
</access-policy>

5. If you see error regarding audienceUri , you will need to modify the web.config as below:

 

Error:

ID1032: At least one 'audienceUri' must be specified in the SamlSecurityTokenRequirement when the AudienceUriMode is set to 'Always' or 'BearerKeyOnly'.Either add the valid URI values to the AudienceUris property of SamlSecurityTokenRequirement,  or turn off checking by specifying an AudienceUriMode of 'Never' on the SamlSecurityTokenRequirement.

 

Resolve this error by adding (or changing) this in web.config. Note it is the Service tag that does not have any name in it. (there are other service tags with name= in web.config, those are generated by when adding the ADSF STS reference and so cannot be changed.)

 

Note: in this sample below, https://sqlbackend.contoso.com/FibonacciFederatedAuth/ is the web application hosting the Silverlight Application.

And, SQLReports.contoso.com is the ADSF server.

 

<microsoft.identityModel>

<service>

     
<audienceUris mode="Never">

       
<add value=https://sqlbackend.contoso.com/FibonacciFederatedAuth/ />

     
</audienceUris>

     
<federatedAuthentication>

       
<wsFederation passiveRedirectEnabled="false"
issuer="https://sqlreports.contoso.com/adfs/services/trust/13/usernamemixed"
realm="https://sqlbackend.contoso.com/FibonacciFederatedAuth"
requireHttps="true" />

       
<cookieHandler requireSsl="true" />

     
</federatedAuthentication>

     
<applicationService>

       
<claimTypeRequired>

         
<!--Following are the claims offered by STS 'http://localhost/IdentityProviderAndSts'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.-->

         
<claimType type=http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name optional="true" />

         
<claimType type=http://schemas.microsoft.com/ws/2008/06/identity/claims/role optional="true" />

       
</claimTypeRequired>

     
</applicationService>

     
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

       
<trustedIssuers>

         
<add thumbprint="E189797A491467A5B1DB027D1F5EFBB97B1D0476" name="http://SQLReports.contoso.com/adfs/services/trust" />

       
</trustedIssuers>

     
</issuerNameRegistry>

     
<certificateValidation certificateValidationMode="None"/>

 </service>

</microsoft.identityModel>

 

comment out
<!--federatedServiceHostConfiguration name="FibonacciService.FibonacciService" /--> if exists.

 

6. Decrypt the raw token returned by ADSF in a helper project.

Take the sample solution as an example,  we need to change the code in tokenProcessor.cs (in SL.IdentityModel.Server project):

 private SecurityToken ReadXmlToken(string
tokenXml)      
{
using (StringReader strReader = new StringReader(tokenXml))          
{

                using (XmlReader reader=XmlReader.Create(strReader))

                {

                    X509Certificate2 cert = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=DefaultApplicationCertificate");

                   SecurityTokenHandlerCollection handlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();

           

                    List<SecurityToken>tokens = new List<SecurityToken>();

 

                    tokens.Add(new X509SecurityToken(cert));

 

                    SecurityTokenResolver serviceResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(new ReadOnlyCollection<SecurityToken>(tokens), true);

 

                   
                    handlers.Configuration.ServiceTokenResolver = serviceResolver;

                   handlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add(new Uri("https://sqlreports.contoso.com/adfs/services/trust/13/usernamemixed"));

                    var registry = new ConfigurationBasedIssuerNameRegistry();

                   registry.AddTrustedIssuer("Thumbprint", "http://SQLReports.contoso.com/adfs/services/trust");

                    handlers.Configuration.IssuerNameRegistry = registry;

                    var samlToken = handlers.ReadToken(reader);

                    return samlToken;

                }
}

 

 

7. If you are considering passing the raw token xml returned by ADSF to Silverlight application for further options such as passing the raw token with the WCF calls and let remote WCF service decrypt the raw token to get User Claims out of it, below is how you can add the raw token into cache and then retrieve it in Silverlight Application. Note we cannot decrypt the token inside Silverlight project.

In ClaimsIdentitySessionManager.cs file (project SL.IdentityModel), modify the following code:

private void trustClient_IssueCompleted( object sender, IssueCompletedEventArgs e )

        {

            if ( null == e.Error)

            {

               
//jason added

               
RequestSecurityTokenResponse rstr = e.Result;

               
string appliesTo;

 

               
if (null == rstr.AppliesTo || null == rstr.AppliesTo.Uri)

                {

                   
throw new ArgumentException("No appliesTo in RequestSecurityTokenResponse");

               
}

 

               
appliesTo = rstr.AppliesTo.Uri.AbsoluteUri;

               
_tokenCache.AddTokenToCache(rstr.AppliesTo.Uri.AbsoluteUri, rstr);

               
//jason added ends

               
ClaimsIdentitySessionManager.Current.SetSessionCookieAsync( e.Result.RequestedSecurityToken.RawToken );

            }

            else if ( null != SignInComplete )

            {

               
SignInComplete( sender, new SignInEventArgs( null, e.Error ) );

            }

        }

 

        //jason added

        public RequestSecurityTokenResponse getRSTRFromTokenCache(string appliesTo)

        {

            return _tokenCache.GetTokenFromCache(appliesTo);

        }

        //jason added ends

 

Retrieve the raw token in SL5 application from the cache, such as mainpage.xaml.cs:

            if (ClaimsIdentitySessionManager.Current.User.ClaimsIdentity.IsAuthenticated)

            {
RequestSecurityTokenResponse rsts=ClaimsIdentitySessionManager.Current.getRSTRFromTokenCache("https://sqlbackend.contoso.com/FibonacciFederatedAuth/");

               
RequestedSecurityToken token = rsts.RequestedSecurityToken;

            }

 

PS. ADSF Raw token xml Example:

 

<xenc:EncryptedData
Type=\"http://www.w3.org/2001/04/xmlenc#Element\"
xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\"><xenc:EncryptionMethod
Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"
/><KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><e:EncryptedKey
xmlns:e=\"http://www.w3.org/2001/04/xmlenc#\"><e:EncryptionMethod
Algorithm=\"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p\"><DigestMethod
Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\" /></e:EncryptionMethod><KeyInfo><o:SecurityTokenReference
xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"><X509Data><X509IssuerSerial><X509IssuerName>CN=DefaultApplicationCertificate</X509IssuerName><X509SerialNumber>56811571836600510090139452222342497478</X509SerialNumber></X509IssuerSerial></X509Data></o:SecurityTokenReference></KeyInfo><e:CipherData><e:CipherValue>yQQxlmji+Czxpnban/MX6rD40I4NJU728KtHqBl1cFz7dQXvokqNZYklY0V6MK9k8ICtfTOYe7t8dQOwYOYQ/SuVFrGeXGgVAibT8DN4DpZmlVHgFIXHcL7XVIdTrFYYwVdrNrkrvnT+DxCTx8oCUR1ddbrqPBwchwqYCy6UPmDjUj2p0Wwftse/fcMUmoVObGr79PxqKFp02HrVX481Fpoov5HKBaT0AGUH/ziniwCgeM6p2XBn3JC3JmiCQzFukKNpJtzWXJH0xc6eEZr57NxybZ2+zvYa85uKiJGIUahgu+CjR6Z3dNDaPZ5LbPFM8UiELEtNZvfaZJPqkD2u1A==</e:CipherValue></e:CipherData></e:EncryptedKey></KeyInfo><xenc:CipherData><xenc:CipherValue>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</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData>"