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"),
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/");
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...