Zulfiqar's weblog

Middleware, security & random .Net

Archive for February, 2009

Part5: ACS Federation with LiveID

Posted by zamd on February 13, 2009

Out of box ACS supports live.com as a trusted identity issuer which means we can use a token issued by live.com to login into ACS. Here I will show how can you achieve this using passive (browser based) federation.

Inside Application AuthenticateRequest method of Global.asax I added following code redirect my web app to ACS to get a new token.

protected void Application AuthenticateRequest(object sender, EventArgs e)

{

    var fam = HttpContext.Current.ApplicationInstance.Modules["WSFederationAuthenticationModule"] as WSFederationAuthenticationModule;

    fam.SignedIn += new EventHandler(fam SignedIn);

 

    var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;

    if (identity != null)

        return;

 

    fam.Realm = "http://zamd.net/";

    fam.Reply = "http://localhost:50037/WebForm1.aspx";

    fam.Issuer = @"https://accesscontrol.windows.net/passivests/Eval01/livefederation.aspx";

    string homeRealmSts = @"http://login.live.com";

 

    String uniqueId = Guid.NewGuid().ToString();

    SignInRequestMessage signInMsg = fam.CreateSignInRequest(uniqueId, fam.Realm, false);

    signInMsg.Parameters.Add("whr", homeRealmSts);

 

    // Redirect to the ACS passive STS for token issuance

    Response.Redirect(signInMsg.RequestUrl);

}

Because here I specified live.com as my home realm, ACS will redirect me to live.com and actual login will take place there. After the succesful login, live.com will redirect me back to ACS with a token (issued by live.com). As ACS trusts this token, issued by live.com. It then runs it’s claims transformation logic (based on the claims issued by live.com) to generate a final token (issued by ACS). ACS then redirects the browser back to the Reply URI (my web app) along with final SAML token. Once back in my app, WSFederationAuthenticationModule, will see this new token and after verifying the issuer etc, it will use it to log me into my application.

Inside Application Start method, I [mis]configured various bits to make it work on test environment.

protected void Application Start(object sender, EventArgs e)

{

    FederatedAuthentication.ServiceCertificate = GetACSCert();

 

    FederatedAuthentication.IssuerNameRegistry = new TrustAllRegistry();

 

    var saml11Handler = FederatedAuthentication.SecurityTokenHandlers[typeof(SamlSecurityToken)] as Saml11SecurityTokenHandler;

    if (saml11Handler != null)

        saml11Handler.SamlSecurityTokenRequirement.AudienceUriMode = System.IdentityModel.Selectors.AudienceUriMode.Never;

}

 

Posted in .NET Services | Leave a Comment »

Part4: ACS Federation with Sql Server Data Services

Posted by zamd on February 11, 2009

Today I will show you how use a token issued by ACS to login into SDS using it’s SOAP API. Again two step process:

Step 1: Get a token from ACS (using UserName/Passoword) for SDS.

 var binding = new WSHttpBinding(“userNameForCert”);

 //ACS(STS) signing certificate…       

var certData = GetACSCertificate();

//only public key cert. use to secure communication.

var acsCert = new X509Certificate2(certData);

var identity = new X509CertificateEndpointIdentity(acsCert);

var epa = new EndpointAddress(new Uri(http://accesscontrol.windows.net/sts/mssds.com/username for certificate feb2005″), identity); 

var trustVersion = TrustVersion.WSTrustFeb2005;

var clientCredentials = new ClientCredentials();

clientCredentials.UserName.UserName = SolutionUserName;

clientCredentials.UserName.Password = SolutionPassword;

 

WSTrustClient client = new WSTrustClient(binding, epa, trustVersion, clientCredentials);

RequestSecurityToken rst = new RequestSecurityToken(RequestTypeConstants.Issue, KeyTypeConstants.Symmetric);

rst.AppliesTo = new EndpointAddress(https://data.database.windows.net/v1″);

RequestSecurityTokenResponse rstr;

var samltok = client.Issue(rst, out rstr);

Here is the binding configuration I used for talking to ACS:

  <binding name=userNameForCert>

    <security mode=Message>

      <message clientCredentialType=UserName negotiateServiceCredential=false

        establishSecurityContext=false />

    </security>

  </binding>

 

Step 2: Forward this token to SDS when creating a new container.

I have generated the SDS proxy (and other classes) by simply doing an “Add Service Reference” from inside visual studio. SDS metadata is exposed at: https://database.windows.net/soap/v1/

 

var sdsBinding = new CustomBinding(“sitka”);

var sdsClient = new SDS.SitkaSoapServiceClient(sdsBinding,

    new EndpointAddress(https://data.database.windows.net/soap/v1/zurich&#8221;));

FederatedClientCredentials.ConfigureChannelFactory(sdsClient.ChannelFactory);

var sdsProxy = sdsClient.ChannelFactory.CreateChannelWithIssuedToken(samltok);

var authorityScope = new SDS.Scope();

authorityScope.AuthorityId = “zamd01″;

 

var c1 = new SDS.Container();

c1.Id = “NewContainerId”;

sdsProxy.Create(authorityScope, c1);

Console.WriteLine(“New container is created…”);

 

SDS binding looks like this:

  <binding name=sitka>

    <security authenticationMode=IssuedTokenOverTransport>

      <issuedTokenParameters>

        <issuer address=http://dummy binding=basicHttpBinding/>

      </issuedTokenParameters>

    </security>

    <httpsTransport/>

  </binding>

And here is a snapshot of my SDS account highlighting the newly created container.

 

Posted in .NET Services | Leave a Comment »

Part3: Explicit ACS federation

Posted by zamd on February 4, 2009

In last post, I have shown you how to federate ACS with a custom STS. All the token acquisition (from my local STS) and forwarding (to ACS) magic was done by WSFederationHttpBinding and you never see the intermediate token (issued by your local STS). There are scenarios where you want more explicit control over this intermediate token. In this post I will show some techniques to get hold of this intermediate token and thus control its lifetime & forwarding etc.

Step 1: Get the token from our local STS.

private static SecurityToken GetTokenFromLocalSTS()

{

    var localSTSBinding = new WSHttpBinding("AnnonyForCertificate");

 

    //only public key cert. use to secure communication.

    var localSTSCert = new X509Certificate2(@"MyCustomSTSPublicKey.cer");

    var localSTSIdentity = new X509CertificateEndpointIdentity(localSTSCert);

    var localSTSAddress = new EndpointAddress(new Uri("http://localhost:9000/STS&quot;), localSTSIdentity);

 

    WSTrustClient client = new WSTrustClient(localSTSBinding, localSTSAddress,TrustVersion.WSTrustFeb2005, new ClientCredentials());

    RequestSecurityToken rst = new RequestSecurityToken(RequestTypeConstants.Issue);

    rst.AppliesTo = new EndpointAddress("http://accesscontrol.windows.net/sts/eval01/saml for certificate/");

 

   

    RequestSecurityTokenResponse rstr;

    var token = client.Issue(rst, out rstr);

    client.Close();

    return token;

}

My local STS is configured to issue token to all annonymous callers. Here is the binding:

<binding name="AnnonyForCertificate">

  <security mode="Message">

    <message clientCredentialType="None" negotiateServiceCredential="false" establishSecurityContext="false"/>

  </security>

</binding>

Step 2: Forward this token to ACS along with Issue request.

 

private static void FederateMyCustomSTS With ACS()

{

    var intermediateToken = GetTokenFromLocalSTS();

 

    // we got token from my our local STS. Forward this token to ACS with Issue request

    var acsCert = GetACSCertificate();

    var acsIdentity = new X509CertificateEndpointIdentity(acsCert);

    var acsAddress = new EndpointAddress(new Uri("http://accesscontrol.windows.net/sts/eval01/saml for certificate"), acsIdentity);

 

    var acsBinding = new CustomBinding("AnySamlForCertificate");

 

    var acsClient = new WSTrustClient(acsBinding, acsAddress, TrustVersion.WSTrust13, new ClientCredentials());

    acsClient = acsClient.SetIssuedToken(intermediateToken);

 

    RequestSecurityToken rstACS = new RequestSecurityToken(RequestTypeConstants.Issue);

    rstACS.AppliesTo = new EndpointAddress("http://zamd.net/&quot;);

 

    var finalToken = acsClient.Issue(rstACS) as GenericXmlSecurityToken;

 

    // dump SAML.

    var rpCert = new X509Certificate2(@"zamdnetprivatekeycert.pfx", "a");

    var saml = ExtractSAMLAssertion(finalToken, rpCert);

}

The ACS binding is as follows:

<binding name="AnySamlForCertificate">

  <security authenticationMode="IssuedTokenForCertificate"

    messageSecurityVersion="WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"

    requireSignatureConfirmation="false">

    <issuedTokenParameters>

      <issuer address="http://dummy" binding="basicHttpBinding"/>

    </issuedTokenParameters>

  </security>

  <httpTransport/>

</binding>

With the above code I get back following SAML assertion (containing only one claim).

<saml:AttributeStatement xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">

  <saml:Subject>

    <saml:SubjectConfirmation>

      <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:holder-of-key</saml:ConfirmationMethod>

      <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=Root Agency</X509IssuerName>

                  <X509SerialNumber>53391460269745460375752793295988585963</X509SerialNumber>

                </X509IssuerSerial>

              </X509Data>

            </o:SecurityTokenReference>

          </KeyInfo>

          <e:CipherData>

            <e:CipherValue>laW9NYJ3NHh+M3c6U1Nq/FADoAWsVc2/JZHYIHJ/qWF536ecpA12NI5orlyvzJ9D+gAK98ZsyouHm1rvQPrttpATQtilrkkyvwKK6JRQb4Ji9th8QGxA+9Yc8yKXlS+rn+lQhdGjYwH8PVxb38IlyJFydtJDMtsJID1OiXagp/w=</e:CipherValue>

          </e:CipherData>

        </e:EncryptedKey>

      </KeyInfo>

    </saml:SubjectConfirmation>

  </saml:Subject>

  <saml:Attribute AttributeName="action" AttributeNamespace="http://docs.oasis-open.org/wsfed/authorization/200706/claims">

    <saml:AttributeValue>that’s done</saml:AttributeValue>

  </saml:Attribute>

</saml:AttributeStatement>

 

I hope you will find this post useful. In the next post, I will show how to federate ACS with Geneva Server.  Stay tuned…

Posted in .NET Services | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.