Recently in .NET Category

A question that has been coming up a lot lately is how does one send a SAML bearer token to downstream WCF service? In each of the recent cases, a front-end app was being presented with a token that it needed to convert to SAML before calling the back-end service. To do this, the Web app would send the incoming token or some other credential to an STS, get the SAML token back, and include it in its request to the next service as shown in the following sketch:

token_translation2.png

To create such a system using .NET requires certain config on the client and server, so I'll enumerate what's required on each. At the end of this post, you'll find links to other blog entries w/ more detail and a link to download a sample project.

Web Service Client


Web Service

  • Use the WS2007FederationHttpBinding binding w/ transport security (as in the client)
  • Like in the binding of the client, set the Message.IssuedKeyType to SecurityKeyType.BearerKey
  • Make sure it's expecting the assertion to be signed by the cert of the STS (by wiring up an IssuerNameRegistry that will check)
  • Configure the audience restriction to be the same one included in the SAML assertion
If you're self-hosting your WCF service on Windows 7, check out this write up from Aviad P. about using netsh to configure HTTPS. (This was the part of all this that took the longest for me. Grr!)

If after reading the above, things aren't quite clear yet, check out these blog posts for more details:


If you're still stuck, have a look at this sample (licensed under the GNU GPL), leave a comment here, and/or email me.

Here's the scenario: You're creating a .NET app that uses active federation to get a token from an STS and submit it to a downstream service. That other service might be another STS or it might be a Web service written in .NET or some other language (doesn't matter). The token that you're getting from the STS is a bearer token. You have some code like this:

private static void CallWebService(SecurityToken token)
{
    var factory = GetServiceChannelFactory<IFoobarService>();
    var channel = factory.CreateChannelWithIssuedToken(token);

    var order = channel.DoFoo();
}

When the call to DooFoo is made, you get an error like this:

The signing token Generic XML token:
   validFrom: 01/07/2012 09:33:36
   validTo: 01/07/2012 10:03:36
   InternalTokenReference: Saml2AssertionKeyIdentifierClause( Id = 'U8ovpOcJlJFu7udUreVI_4I69vj' )
   Token Element: (Assertion, urn:oasis:names:tc:SAML:2.0:assertion)
 has no keys. The security token is used in a context that requires it to perform cryptographic operations, but the token contains no cryptographic keys. Either the token type does not support cryptographic operations, or the particular token instance does not contain cryptographic keys. Check your configuration to ensure that cryptographically disabled token types (for example, UserNameSecurityToken) are not specified in a context that requires cryptographic operations (for example, an endorsing supporting token).

To fix this, do two things:

  1. Make sure the binding you're using for the service (not the STS, that doesn't matter) is WS2007FederationHttpBinding not WS2007HttpBinding or WSHttpBinding.
  2. On that binding, set Security.Message.IssuedKeyType to SecurityKeyType.BearerKey.

Error goes away and now you can fix the next problem ;-)

So, what was the deal? The token you had in hand was a bearer token, meaning there is no requirement on the presenter when submitting the token to prove that it was indeed the entity that got the token from the STS; however, in its default configuration, WCF is trying to do just that. Because the token doesn't have a proof key in it (the cryptographic key the error is talking about), WCF can't compute the digital signature it thinks it should send along.

Alternatively, if you really do want to prove to the RP Web service that you were the one who got the token from the STS, ask for a Holder of Key (HoK) assertion. You can do this by changing the TokenType in the RST, but your STS will have to support this.

If you have questions on this, leave a comment below or shoot me a mail.

Note that this code is only intended for demo and debugging purposes. It doesn't verify the signature of the security token in the RSTR and is not intended to be used in production scenarios.

If you need to convert a RequestSecurityTokenResponse to a ClaimsIdentity, here's one way:

private static ClaimsIdentity GetClaimsIdentity(RequestSecurityTokenResponse rstr)
{
var rstrXml = rstr.RequestedSecurityToken.SecurityTokenXml;
var xnm = new XmlNamespaceManager(rstrXml.OwnerDocument.NameTable);

xnm.AddNamespace(Saml11Constants.Prefix, Saml11Constants.Namespace);

var attributeStatement = rstrXml.SelectSingleNode("saml:AttributeStatement", xnm);
var attributes = attributeStatement.SelectNodes("saml:Attribute", xnm);
var claims = new List<Claim>();

for (var i = 0; attributes != null && i < attributes.Count; i++)
{
var attribute = attributes[i];
var claimType = attribute.Attributes["AttributeNamespace"].Value + attribute.Attributes["AttributeName"].Value;
var value = attribute.SelectSingleNode("saml:AttributeValue/text()", xnm).Value;

claims.Add(new Claim(claimType, value ?? ""));
}

var subject = attributeStatement.SelectSingleNode("saml:Subject/saml:NameIdentifier/text()", xnm).Value;

claims.Add(new Claim(ClaimTypes.Name, subject));

return new ClaimsIdentity(claims);
}

It assumes that the assertion has an AttributeStatement in it, that that has Attribute elements, that the assertion isn't encrypted, etc. If that isn't necessarily true in your case, adjust as needed. (This code, as all code on my Web site, is licensed under the GNU Public License v. 2.)
The other day, I was looking through some code of a RP that a colleague wrote. He was mapping the claims to properties on a user class. The property names were very dissimilar to those of the claim types. This got me to thinking. What is needed by RP developers, in general, is a simple user class w/ dynamic properties and a way to map claims in an IClaimsPrincipal to them. Looking for an opportunity to learn more about .NET 4, I coded up the following little framework (I use that term loosely here) that uses the new dynamic language features of C# to do exactly this.

Before diving into the various classes and interfaces, have a look at the following snippet which shows how you might use this framework and the problem it's trying to solve:

public static void Main()
{
    var claims = new[]
    {
        new Claim("foo", "3"),
        new Claim("foo_bar", "true"),
        new Claim("foo_baz", "Ted"),
        new Claim("http://schemas.travisspencer.com/2010/05/test/claims/shoesize", "11"),
        new Claim("http://schemas.travisspencer.com/2010/05/test/claims/haircolor", "blond"),
        new Claim("Age", "16"),
    };
    var identity = new ClaimsIdentity(claims);
    dynamic user = new MyGoodUser(identity);

    Console.WriteLine("Foo = {0}", user.Foo);
    Console.WriteLine("FooBar = {0}", user.FooBar);
    Console.WriteLine("FooBaz = {0}", user.FooBaz);
    Console.WriteLine("ShoeSize  = {0}", user.ShoeSize);
    Console.WriteLine("HairColor = {0}", user.HairColor);
    Console.WriteLine("Age = {0}", user.Age);

    Console.ReadLine();
}

In this snippet, we have some claim types (e.g., foo_baz, http://.../shoesize, etc.), but you can see that the RP developer really wants a nice programming model -- a user object w/ Pascal-cased properties. This is provided by the MyGoodUser class.  This class is intended to be an RP-specific class that derives from a User class that is provided in the framework (described below); it would be created and put on the thread's principal by a custom HTTP module that uses the IClaimsIdentity created by WIF.

The object model of the framework is shown in the following figure.

UserObjectModel2.gif

With these, you can create your own user class (e.g., MyGoodUser) and mappers that will provide you with a nice programming model in your RP regardless of what comes over in the claims. Here is the User class in its entirety:

public class User : DynamicObject
{
    private readonly ClaimsIdentity identity;
    private readonly List<IClaimsIdentityMapper> mappers;

    public User(ClaimsIdentity identity)
        : this(identity, new NullClaimsIdentityMapper())
    {
    }

    public User(ClaimsIdentity identity, params IClaimsIdentityMapper[] mappers)
        : this(identity, false, mappers)
    {
    }

    public User(ClaimsIdentity identity, bool includeNullMapper, params IClaimsIdentityMapper[] mappers)
    {
        if (mappers == null || mappers.Length == 0)
        {
            throw new ArgumentNullException("mappers");
        }

        this.identity = identity;
        this.mappers = new List<IClaimsIdentityMapper>(mappers);

        if (includeNullMapper)
        {
            this.mappers.Add(new NullClaimsIdentityMapper());
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {           
        result = null;

        foreach (var mapper in mappers)
        {
            var claimType = mapper.Map(binder.Name);
            var c = identity.Claims.Where(x => x.ClaimType == claimType);

            if (c != null && c.Count() == 1)
            {
                result = c.ElementAt(0).Value;
                break;
            }
        }

        return result != null;
    }

    private class NullClaimsIdentityMapper : IClaimsIdentityMapper
    {
        public string Map(string name)
        {
            return name;
        }
    }
}

The important part is the overridden TryGetMember method. That is fired every time a property on a User object is accessed for which there is no static definition. In it, the collection of mappers transpose the property name to a value that is used to look up a claim of that type. If one is found, its value is returned; otherwise, party at run-time :-)

The mappers are pretty simple because they do very little. Here's the one that maps property names to URLs:

public class UrlClaimsIdentityMapper : IClaimsIdentityMapper
{
    public string Map(string name)
    {
        return "http://schemas.travisspencer.com/2010/05/test/claims/" + name.ToLowerInvariant();
    }
}

The derived user class is also pretty trivial:

public class MyGoodUser : User
{
    public MyGoodUser(ClaimsIdentity identity)
        : base(identity, true, new UnderScoreClaimsIdentityMapper(),
            new UrlClaimsIdentityMapper(),
            new AddressClaimsIdentityMapper())
    {
    }
}

I can imagine that claim types will often be hierarchical and the RP developer would like a programming model such as this:

Console.WriteLine("Address - Line 1 = {0}", user.Address.Line1);
Console.WriteLine("Address - Line 2 = {0}", user.Address.Line2);
Console.WriteLine("City = {0}", user.Address.City);
Console.WriteLine("State = {0}", user.Address.State);
Console.WriteLine("Zip Code = {0}", user.Address.ZipCode);

For that, I will refer you to ElasticObject by Anoop Madhusudanan.

I hope this gets some creative juices flowing. If you have questions or thoughts, feel free to leave a comment here or contact me.
In early 2007, I started using WCF on a daily basis while it and Visual Studio 2008 were still in beta.  It was great to get the jump on that technology, but it was really hard to find information when I bumped up against bugs or uncertainties.  Now, two years later, I find myself in the same boat again, but this time with Geneva.  Right now there isn't much info coming out of Redmond, but this is the time I need it not in 11 months when this stuff RTMs.  For this reason, I decided to start collecting all the useful sources of information that I've found related to Geneva framework, server, and Cardspace.

Sources of Information to Get Started

Before you do anything, check out these documents and videos:


Obscure Information

Once you've read and reread the above like 50 times, and you're totally desperate for more info, check out these feeds:


Bloggers Talking About Geneva


 
I'll update this list as I find more.  If you have some pearls, please post a comment with a link.