Today Microsoft hosted the Architecture Day. This is an interesting event where architects from different companies come together to talk about different topics (similar to the Regional Architect Forum). In this opportunity I proposed to do a presentation about Identity related to some work we did with a customer on Microsoft “Geneva”. So together with Sebastian Renzi (who was the PM in that project) we did a one hour presentation covering the basis of claim based identity and a demo of the work we did in this customer.

The presentation started by telling a story about a typical company that created its first application. This app used Windows Authentication so life was easy :). However business grew over time and they ended up with multiple applications, each one with its own identity repository, different authentication methods, support users accessing from intranet, internet, extranet, cloud, and so on and so forth. I grab this diagram from Stuart Kwan presentation from the Genevea Product Team (so thanks Stuart for the cool representation).

image

Then we went through the problems from different perspectives: the department who is in charge of security, the end user and the architect. (I wish I had the time to translate it to English but you can imagine…)

image image
image  

If you think about these problems, many of them can be solved if you follow this principle:

Externalize from the application logic the following responsibilities:

  • the process of authentication
  • the retrieval of attributes that will be used later for authorization

This is exactly what claim based identity is about. We setup an analogy between how an event registration works under the same principles of credentials, STS, claims and resources (kudos to Eugenio Pace who originally did this analogy in his PDC presentation).

image

Now, if I have to start a company I certainly would create my STS and applications and will use claim based identity. However, in the real world we know that the landscape is much more complex and there are existing applications with identity silos running everyday. Any disruptive change will be a huge mess for everyone. So this is the roadmap we established together with this customer (which is one of the biggest insurance company here in Argentina):

image

We decided to tackle authentication first and try to remove the identity silos in an organic fashion. Since they had many applications (some of them using SQL Server, some others AD, some others a custom mechanism) we wanted to rely on users to do the migration as opposed to a huge migration from IT. This also allowed IT to debug the user database. The following figure shows how the consolidation of identity would happen through time. It will work as fast as users will do its first login and create the mapping with the new repository. This works well when you have lots of apps using a database as the user repository.

image

Note: this is not based on real data, it tries to give you an idea of how it works over time (credits to Johnny Halife).

We did a demo on how this works and people were interested in this approach because it is not disruptive.

I posted the presentation in Spanish and you can download it from here

Some useful resources

Identity Development Training Kit: http://snipurl.com/identitytk
“Geneva” Download: http://snipurl.com/genevadownload
Channel9 Identity: http://channel9.msdn.com/identity/
Blog Vittorio Bertocci: http://snipurl.com/vibro

Couple of months ago Ezequiel posted a summary of a very interesting article published on the Identity issue of the Architecture Journal. This article talked about different patterns on the federated identity world. Last week we had an interesting requirement to solve in a project and this article came to my mind. Specifically one of the scenarios this article points out is when you don’t want the consumer to have knowledge about the relying party STS or you don’t want the client to “see” the token from that STS. The figure below illustrates this scenario. In this diagram, the relying party (service) will receive a token from STS A and will call the STS B to obtain the token.

This might be helpful when you can’t change the consumer side of the equation. This lead me to introduce the federated blog engine and how we leveraged this in that project…

The Federated Blog Engine

Let’s say we want to implement a blog engine where users can access through federated identity. My blog engine supports the passive profile federation, so when someone access it will get redirected to its IP STS, get authenticated, post the token to the website and voila! We can create new blog posts under our organization identity.

So far nothing new here. Now let’s say that we want to be able to post through Windows Live Writer. This is a rich client that runs on your desktop that you can’t change. On the other side the blog engine will have to expose the MetaWeblog API. Every operation of this API receives the user and password like the code below:

string NewPost(string blogId, string username, string password, Post post, bool publish);

In this case, the token on the client is a UsernameToken (not the WS-Security one, but think about the analogy). We will send that token (through Https) to the remote MetaWeblog API.

NewPost("mwoloski", "DOMAIN\matias", "mypassword", post, true)

When the message gets to the service we can intercept it and call the STS that will validate the credentials and will issue a SAML token for the service. The following piece of code shows how to make such request to a Geneva Server Beta 2 using the UserNameMixed endpoint. This endpoint will authenticate the user against AD.

private static ClaimsIdentityCollection GetToken(string username, string password, Uri stsUrl, X509Certificate2 signatureCertificate, Uri relyingPartyIdentifier, X509Certificate2 decryptingCertificate){    var binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);    binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;    binding.Security.Message.EstablishSecurityContext = false;

    var credentials = new ClientCredentials();    credentials.UserName.UserName = username;    credentials.UserName.Password = password;    var client = new WSTrustClient(binding, new EndpointAddress(stsUrl), TrustVersion.WSTrust13, credentials);

    var request = new RequestSecurityToken();    request.RequestType = "http://schemas.microsoft.com/idfx/requesttype/issue";    request.AppliesTo = new EndpointAddress(relyingPartyIdentifier);    var token = client.Issue(request) as GenericXmlSecurityToken;

    var claims = token.ToClaimsIdentityCollection(TrustVersion.WSTrust13, signatureCertificate, decryptingCertificate);

    return claims;}

var token = GetToken("matias",         "password",         new Uri("https://genevaserverurl/Trust/13/UsernameMixed"),        CertificateUtility.GetCertificate(StoreName.TrustedPeople, StoreLocation.LocalMachine, "CN=Geneva Signing Certificate…"),        new Uri("http://hostname/someservice"),        CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=hostname"))

 
In the Geneva Server console we configured a new relying party providing the encrypting certificate and the identifier (http://hostname/someservice). If you noticed the code above we are sending those parameters so Geneva Server can execute the rules configured for that relying party and the token gets encrypted with the certificate.
 
image
 
Then we have configured a rule that will output the name, groups and UPN of the user that is being authenticated. Those attributes will be taken from the AD store but if we had a SQL where we stored user attributes or ADLDS
 
image
 
Finally you can see below a console app that is exercising the code above. Here is what Geneva Server returns. Notice the name, group and upn claims.
image
 

This post had a lot of visits so I have updated it to work with Geneva Beta 2

   1: public static ClaimsIdentityCollection ToClaimsIdentityCollection(this GenericXmlSecurityToken originalToken, TrustVersion trustVersion, X509Certificate2 signature, X509Certificate2 encryption)

   2: {

   3:     var tokenReader = new StringReader(originalToken.TokenXml.OuterXml);

   4:     var reader = XmlReader.Create(tokenReader);

   5:  

   6:     var privateKeyToken = new X509SecurityToken(encryption);

   7:     var issuerKeyToken = new X509SecurityToken(signature);

   8:     var tokens = new List<SecurityToken>();

   9:     tokens.Add(privateKeyToken);

  10:     tokens.Add(issuerKeyToken);

  11:     SecurityTokenResolver outOfBandTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(new ReadOnlyCollection<SecurityToken>(tokens), false);

  12:  

  13:     var handlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();

  14:     var samlHandler = handlers[typeof(SamlSecurityToken)] as Saml11SecurityTokenHandler;

  15:     samlHandler.ContainingCollection[typeof(EncryptedSecurityToken)].Configuration.ServiceTokenResolver = outOfBandTokenResolver;

  16:     var issuerRegistry = new ConfigurationBasedIssuerNameRegistry();

  17:     issuerRegistry.AddTrustedIssuer(signature.Thumbprint, signature.Subject);

  18:     samlHandler.Configuration.IssuerNameRegistry = issuerRegistry;

  19:  

  20:     var serializer = new SecurityTokenSerializerAdapter(handlers,

  21:         SecurityVersion.WSSecurity11,

  22:         trustVersion,

  23:         trustVersion == TrustVersion.WSTrust13 ? SecureConversationVersion.WSSecureConversation13 : SecureConversationVersion.WSSecureConversationFeb2005,

  24:         false,

  25:         null,

  26:         null,

  27:         null);

  28:  

  29:     var samlSecurityToken = serializer.ReadToken(reader, outOfBandTokenResolver);

  30:     reader.Close();

  31:  

  32:     var claims = handlers.ValidateToken(samlSecurityToken);

  33:  

  34:     return claims;

  35: }

 

During the last couple of months I’ve been helping the Microsoft DPE team (namely Vittorio and Donovan) building the Identity Development Training Kit. It’s been great to work with such knowledgeable guys like them and with one of the best frameworks I’ve ever developed with: Microsoft Geneva Framework. Identity Training Kit

The training kit covers a lot of interesting scenarios related to claim-based identity. Here is the shortcut list (if you want a full explanation of each one, read Vittorio’s post)

  • Lab: Web Sites and Identity:
    • Exercise 1: Enabling claims based access for an ASP.NET Web Application by generating a local STS
    • Exercise 2: Customizing the Credentials Accepted by a Local STS
    • Exercise 3: Accepting Tokens from a Geneva Server STS
    • Exercise 4: Accepting Tokens from Live ID
    • Exercise 5: Accepting Tokens from .NET Access Control Service
    • Exercise 6: Invoking a WCF Service on the Backend via Delegated Access
  • Lab: Enhancing an ASP.NET Membership Provider Website with Identity Provider Capabilities
  • Lab: Web Services and Identity
    • Exercise 1: Using Geneva Framework for Handling Authentication and Authorization in a WCF Service
    • Exercise 2: Accepting Tokens from a Geneva Server STS
    • Exercise 3: Accepting Tokens from .NET Access Control Service
    • Exercise 4: Invoking a WCF Service on the Backend via Delegated Access

We made sure that all of the exercises followed the best practices of developing with Geneva Framework. Building this training kit was a big effort and I would like to mention the great team that helped creating this:  Ariel “lutz” Neisen, Jonathan “passive” Cisneros, Ezequiel “checklist” Sculli and Sebastian “pattern” Iacomuzzi

I invite you to take a look at the training kit and open your mind with the new possibilities the Geneva Framework brings into the table.

UPDATE: the code has been updated to work with WIF RTM. Thanks Nico!

Providing the federation metadata for your STS will be very useful when a relying party want to establish a trust relationship with your STS. For instance, the Geneva Framework provides a FedUtil.exe tool that allows you to point to this metadata file and configure the relying party changing the microsoft.identityModel section (read more about the metadata format here: http://www.oasis-open.org/committees/download.php/30005/ws-federation-1.2-spec-ed-09.doc)

The metadata is signed with the STS private key, which make sense because you don’t want someone else publishing a metadata file and claiming that it’s your STS metadata. That means that you will need some code in order to generate that signature based on the metadata content.

Well I have good news for you. Microsoft Geneva Framework provides a couple of useful classes (like MetadataSerializer) to generate the metadata.
Disclaimer: this code generates a simple version of federation metadata for an IP passive STS (it does not include WS-Trust endpoints for active profile for instance).

var stsUri = new Uri(“https://login.mysts.com/FederationPassive”);
string destFolder = @”d:\Temp\”;
string signingCertificateSubjectName = “CN=localhost“;
var claimsOffered = new DisplayClaim[]
{
    CreateDisplayClaim(”http://schemas.xmlsoap.org/claims/Group”, false, “Group”, string.Empty),
    CreateDisplayClaim(“http://schemas.xmlsoap.org/claim/Issuer”, false, “Issuer”, string.Empty),
    CreateDisplayClaim(“http://schemas.xmlsoap.org/claim/Email”, false, “Email”, string.Empty),
    CreateDisplayClaim(“http://schemas.xmlsoap.org/claim/FirstName”, false, “FirstName”, string.Empty),
    CreateDisplayClaim(“http://schemas.xmlsoap.org/claim/LastName”, false, “LastName”, string.Empty),
    CreateDisplayClaim(“http://schemas.xmlsoap.org/claim/CostCenter”, false, “CostCenter”, string.Empty),
    CreateDisplayClaim(“http://schemas.xmlsoap.org/claim/Phone”, false, “Phone”, string.Empty)
};

CreatePassiveStsMetadata(stsUri, signingCertificateSubjectName, claimsOffered, destFolder);

The code above shows the usage for a sample STS. Download the code from here