ACS SAML / ADFS v2 Sample

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).

image

  1. At runtime, the client app requests a SAML bearer token from AD FS v2. The easiest way to do this is with Windows Identity Foundation (WIF).
  2. The client app POSTs the SAML token to ACS over SSL. ACS uses configurable rules to calculate the claims in a Simple Web Token (SWT), creates a SWT, signs it, and returns it to the client app. The protocol for this exchange is OAuth WRAP.
  3. Next, the client packages the SWT in the HTTP Authorization header and sends it to the REST web service along with whatever payload the REST web service requires.
  4. Once the REST web service receives the token & payload, it validates the token and checks the claims in the token. The REST web services allows or denies access based on the outcome.

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 (https://learn.iis.net/page.aspx/144/how-to-setup-ssl-on-iis-70/)

You’ll also need to install the WIF RC. Available here: https://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 (https://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

image

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 https://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 https://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 https://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.

image

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();
    }
}

The only trick is to ensure you are using the Bearer key type (Yes, you can use WIF to request a Bearer token).

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", "https://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…

Comments

  • Anonymous
    November 14, 2009
    Will WIF be updated in the future to include support for SWT and OAuth WRAP or will a framework be created for working w/ these protocols in a more natural and seamless way?

  • Anonymous
    November 15, 2009
    Travis, We are investigating that now...

  • Anonymous
    December 04, 2009
    Hi Justin, my question is ... how the ACS can trust the saml bearer token? It is able to check the signature? How? If, at the moment, this is not supported, you plan to support it in the future? Thanks in advance

  • Anonymous
    December 08, 2009
    Yes, ACS checks the signature of the SAML token. The signing cert can be embedded in WS-Fed metadata (ACS can read it), or you can upload the X509 yourself.

  • Anonymous
    January 14, 2010
    The sample uses Wrap 0.8 ACS has Wrap0.9 endpoints do you have the updated sample?

  • Anonymous
    February 26, 2010
    Hi Justin, I have a problem trying to create the Issuer with FedMetadata Algorithm. Studying the code of the ACMBrowser apparently is necessary set an IssuerName and a Security to create the issuer, but I can not find what is the security type required to configure correctly the issuer. I try with this modification in the last code of the ACMBrowser, in the ConversionHelper class: public static Issuer ToIssuer(this IssuerXml issuerXml)        {            Issuer issuer = new Issuer();            issuer.InitializeResource(issuerXml);            if (string.IsNullOrEmpty(issuerXml.FedMetadataUri))            {                issuer.IssuerName = issuerXml.IssuerName;                Security security = new Security();                security.Algorithm = issuerXml.Algorithm;                security.CurrentKey = issuerXml.CurrentKey;                security.PreviousKey = issuerXml.PreviousKey;                issuer.Security = security;            }            else            {                // the IssuerName and Security fields cannot be specified along with FedMetadata ****This is incorrect apparently                //MY CHANGES                //issuer.IssuerName = null;                //issuer.Security = null;                issuer.IssuerName = issuerXml.Handle;  //To obtain a name for the issuer                Security security = new Security();                security.Algorithm = issuerXml.Algorithm;   //This set "FedMetadata" in the security.Algorithm                security.CurrentKey = issuerXml.CurrentKey; //This set nothing because issuerXml.CurrentKey is empty                security.PreviousKey = issuerXml.PreviousKey;  //This set nothing because issuerXml.PreviousKey is empty                issuer.Security = security;                //MY CHANGES            }            issuer.FederationMetadata200706 = FederationMetadata(issuerXml.FedMetadataUri);            return issuer;        } But this is the new message error "The Algorithm request parameter value 'FedMetadata' is invalid for the following reason: the provided algorithm type 'FedMetadata' is not supported" Then I need to know what is the correct security type for this. Can you help me, please?

  • Anonymous
    March 23, 2010
    Hi Justin, Interesting post. In my application scenario... assume i have a web role which trusts token only from ACS. I want to configure ACS to trust the tokens from various issuers running on different partner locations. So the flow is like

  1. When someone tries to access a web application deployed on azure (web role). Web role redirects user to ACS with Whr querystring attribute to request a token.
  2. ACS redirects to appropriate identity provider depending on Whr parameter (How to do this?)
  3. IP authenticates user and creates a SAML token which is then posted back to ACS
  4. ACS extracts the claims and transforms it as per the aplication requirement Do we have any sample / tutorial on how to perform this? Regards Badal
  • Anonymous
    March 26, 2010
    we have a major application, built in Sharepoint 2010 RC, that authenticates users with Active Directory using a web form.  the code also leverages a couple of AD attributes to redirect the user to the right sharepoint site depending on what organization they are coming from... in AD they set up an OU with different sub OUs for each org and somehow they authenticate and figure out which site the user should go to based on this custom web form installed into sharepoint 2010. I know 2010 supports Claims auth. I know you guys have adfs20 that bolts onto AD How do i think about re-architecting this solution so i can offload user account management to each organization? if i install ADFS20 on these AD servers do i federate with BPOS somehow? then each company can get a slice of BPOS they can manage thier accounts we can then translate BPOS roles or groups to whatever application roles or groups they are using? thanks.

  • Anonymous
    October 10, 2010
    With ACS we can have only one Identity providers for Windows Live ID, Yahoo, Google etc. We want to know about how many ADFS 2.0 Identity providers can be added to ACS? Is this allows us to configure multiple ADFS 2.0 Identity Providers as we want to build a claims aware application which uses both ADFS and custom STS for providing the claims. Please provide us some information in this regard... Thanks, VDeevi.

  • Anonymous
    October 10, 2010
    With ACS we can have only one Identity providers for Windows Live ID, Yahoo, Google etc. We want to know about how many ADFS 2.0 Identity providers can be added to ACS? Is this allows us to configure multiple ADFS 2.0 Identity Providers as we want to build a claims aware application which uses both ADFS and custom STS for providing the claims. Please provide us some information in this regard... Thanks, VDeevi.

  • Anonymous
    October 11, 2010
    ACS v2 does support multiple ADFS 2.0 IdPs. not sure about what's the upper limit it supports ... Justin coluld you please tell?