The November 2009 CTP of ACS integrates with Active Directory Federation Server v2. ACS can act as a bridge between enterprise identity and REST web services.
The runtime flow is pretty simple (shown below).
Viola. You have a REST web service that integrates with AD FS v2 via OAuth WRAP and SWT.
Mini AD FS setup (for this scenario only)
There is some setup required to enable this scenario (other than acquiring an ACS Service Namespace). For starters, you’ll need an AD FS v2 server. Since this requires a domain, I’ve provided a service that replicates the basic token issuing behavior of AD FS (at the bottom of this post). The only relying party trusted by this service is ACS.
To setup the service, you’ll need to update the App.config file. Update the “signingCertName” to a cert in your LocalMachine / Personal cert store. Also update the “serviceNamespace” to your ACS service namespace.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="signingCertName" value="CN=localhost"/> <add key="stsBaseAddress" value="localhost/miniadfs"/> <add key="stsPath" value="Trust/13/Windows"/> <add key="serviceNamespace" value="justinpdcdemo"/> <add key="acsHostname" value="accesscontrol.windows.net"/> </appSettings> </configuration>
You’ll also have to setup SSL for your IIS install (http://learn.iis.net/page.aspx/144/how-to-setup-ssl-on-iis-70/)
You’ll also need to install the WIF RC. Available here: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=defd2019-a61f-4327-9332-6a4b6103527a#tm
From there, you should be able to run the service.
Fed Metadata Setup with ACS
After you have the mini ADFS service running, you’ll want to use the Fed Metadata it publishes to create an issuer in ACS. Also in the sample below is some code that shows you how to programmatically do that.
If you’d rather use a tool, you can use the Management Browser (http://code.msdn.microsoft.com/acmbrowser).
Simply create a new Issuer, select FedMetadata from the Algorithm drop down, and set the URL of the fed metadata server. In the miniADFS server, that URL is https://localhost/LocalADFSv2/FederationMetadata/2007-06/FederationMetadata.xml
Creating a Scope & Rule for the new Issuer
Next, you’ll want to create a scope and a rule that refers to that issuer. The sample at the bottom of this post uses a scope with an applies_to URI of http://localhost/samltest. You can use the Management Browser to create one.
With the scope in place, we can create a rule. All rules require the name of the Issuer and a claim type in the antecedent. When you create an Issuer using Fed Metadata, the Issuer name is fixed in the Fed Metadata. My MiniADFS server uses an issuer name of https://localhost/miniadfs/Trust/13/Windows. It also spits out claims of type http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name.
With that data, you can create a Passthrough rule. Passthrough rules basically countersign the input claims. In this case, a passthrough rule would countersign any http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name claim issued by the issuer https://localhost/miniadfs/Trust/13/Windows. The consequent of the rule can be of any type you choose. To keep the token compact, I’ll use a claim type of “name”.
You can set all this up using the management browser, as shown below.
Acquiring A SAML Token
With the Issuer, Scope, and Rule setup, let’s get a SAML token using WIF (the RC). The code for doing this is in the SAMLClient project from the code sample in this post. The WIF code is pretty straightforward:
private static string GetSAMLToken() { WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(new WindowsWSTrustBinding(SecurityMode.TransportWithMessageCredential), new EndpointAddress(new Uri(samlUrl))); trustChannelFactory.TrustVersion = TrustVersion.WSTrust13; try { RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue, WSTrust13Constants.KeyTypes.Bearer); rst.AppliesTo = new EndpointAddress(acsUrl); rst.TokenType = Microsoft.IdentityModel.Tokens.SecurityTokenTypes.Saml2TokenProfile11; WSTrustChannel channel = (WSTrustChannel)trustChannelFactory.CreateChannel(); GenericXmlSecurityToken token = channel.Issue(rst) as GenericXmlSecurityToken; string tokenString = token.TokenXml.OuterXml; return tokenString; } finally { trustChannelFactory.Close(); } }
Using the SAML token to get a SWT
Next, you can use the SAML token to request a SWT from ACS:
private static string SendSAMLTokenToACS(string samlToken) { try { WebClient client = new WebClient(); client.BaseAddress = acsUrl; NameValueCollection parameters = new NameValueCollection(); // ensure the applies_to URI is created in your ACS // service namespace parameters.Add("applies_to", "http://localhost/samltest"); parameters.Add("wrap_SAML", samlToken); byte[] responseBytes = client.UploadValues("", parameters); string response = Encoding.UTF8.GetString(responseBytes); return response .Split('&') .Single(value => value.StartsWith("wrap_token=", StringComparison.OrdinalIgnoreCase)) .Split('=')[1]; } catch (WebException wex) { string value = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd(); throw; } }
Viola! That’s all there is.
Here’s the full code sample – Let me know any feedback you have…