Saturday, July 24, 2010

WIF, ASP.NET 4.0 and Request Validation

Since the response of a WS-Federation sign-in request contains XML, the ASP.NET built-in request validation will trigger an exception. To solve this, request validation needs to be turned off for pages receiving such a response message.

Starting with ASP.NET 4.0 you can plug in your own request validation logic. This allows letting WS-Federation messages through, while applying all standard request validation to all other requests. The WIF SDK (v4) contains a sample validator that does exactly that:

public class WSFedRequestValidator : RequestValidator
{

    protected override bool IsValidRequestString(
      HttpContext context,
      string value,
      RequestValidationSource requestValidationSource,
      string collectionKey,
      out int validationFailureIndex)
    {
        validationFailureIndex = 0;


        if ( requestValidationSource == RequestValidationSource.Form &&
             collectionKey.Equals(
               WSFederationConstants.Parameters.Result,
               StringComparison.Ordinal ) )
        {
            SignInResponseMessage message =
              WSFederationMessage.CreateFromFormPost(context.Request)
               as SignInResponseMessage;

            if (message != null)
            {
                return true;
            }
        }

        return base.IsValidRequestString(
          context,
          value,
          requestValidationSource,
          collectionKey,
          out validationFailureIndex );
    }
}

Register this validator via web.config:

<httpRuntime requestValidationType="WSFedRequestValidator" />


IdentityModel
Saturday, July 24, 2010 8:14:36 AM UTC  #   
 Tuesday, June 22, 2010

Modifying the SL/WIF Integration Bits to support Issued Token Credentials

The SL/WIF integration code that ships with the Identity Training Kit only supports Windows and UserName credentials to request tokens from an STS. This is fine for simple single STS scenarios (like a single IdP). But the more common pattern for claims/token based systems is to split the STS roles into an IdP and a Resource STS (or whatever you wanna call it).

In this case, the 2nd leg requires to present the issued token from the 1st leg – this is not directly supported by the bits. But they can be easily modified to accomplish this.

The Credential
Fist we need a class that represents an issued token credential. Here we store the RSTR that got returned from the client to IdP request:

public class IssuedTokenCredentials : IRequestCredentials
{
    public string IssuedToken { get; set; }
    public RequestSecurityTokenResponse RSTR { get; set; }

    public IssuedTokenCredentials(RequestSecurityTokenResponse rstr)
    {
        RSTR = rstr;
        IssuedToken = rstr.RequestedSecurityToken.RawToken;
    }
}

The Binding
Next we need a binding to be used with issued token credential requests. This assumes you have an STS endpoint for mixed mode security with SecureConversation turned off.

public class WSTrustBindingIssuedTokenMixed : WSTrustBinding
{
    public WSTrustBindingIssuedTokenMixed()
    {
        this.Elements.Add( new HttpsTransportBindingElement() );
    }
}

WSTrustClient
The last step is to make some modifications to WSTrustClient to make it issued token aware. In the constructor you have to check for the credential type, and if it is an issued token, store it away.

private RequestSecurityTokenResponse _rstr;
public WSTrustClient( Binding binding, EndpointAddress remoteAddress, 
IRequestCredentials credentials )
    : base( binding, remoteAddress )
{
    if ( null == credentials )
    {
        throw new ArgumentNullException( "credentials" );
    }

    if (credentials is UsernameCredentials)
    {
        UsernameCredentials usernname = credentials as UsernameCredentials;
        base.ChannelFactory.Credentials.UserName.UserName = usernname.Username;
        base.ChannelFactory.Credentials.UserName.Password = usernname.Password;
    }
    else if (credentials is IssuedTokenCredentials)
    {
        var issuedToken = credentials as IssuedTokenCredentials;
        _rstr = issuedToken.RSTR;
    }
    else if (credentials is WindowsCredentials)
    { }
    else
    {
        throw new ArgumentOutOfRangeException("credentials", "type was not expected");
    }
}

Next – when WSTrustClient constructs the RST message to the STS, the issued token header must be embedded when needed:

private Message BuildRequestAsMessage( RequestSecurityToken request )
{
    var message = Message.CreateMessage(
base.Endpoint.Binding.MessageVersion ?? MessageVersion.Default,
      IssueAction,
      (BodyWriter) new WSTrustRequestBodyWriter( request ) );

    if (_rstr != null)
    {
        message.Headers.Add(new IssuedTokenHeader(_rstr));
    }

    return message;
}

HTH


IdentityModel
Tuesday, June 22, 2010 6:45:17 AM UTC  #   
 Thursday, June 10, 2010

StarterSTS 1.1

Earlier today I uploaded StarterSTS 1.1 and StarterRP 1.1 to codeplex.

I added identity delegation for internal as well as OpenID accounts and also updated StarterRP to show these features.

I also recorded an updated screencast on delegation since some of the config settings have changed since the CTP.


IdentityModel
Thursday, June 10, 2010 8:07:49 AM UTC  #   
 Wednesday, May 26, 2010

Updated StarterSTS Documentation & Identity Delegation Screencast

I recorded a short screencast describing the identity delegation feature in StarterSTS 1.1. You can watch it here.

I also uploaded an updated version of the documentation here.


IdentityModel
Wednesday, May 26, 2010 7:42:59 AM UTC  #   
 Monday, May 24, 2010

StarterSTS 1.1 CTP – ActAs Support

Due to popular demand, I added identity delegation (aka ActAs) support to StarterSTS.

To give this feature a try, first download the new bits and add a enableActAs = true to startersts.config. You then have to configure which user account is allowed to delegate, as well as the target realm to delegate to. This is done in usermappings.config, e.g.:

<userMappings xmlns="http://www.thinktecture.com/configuration/usermappings">
    <user name="middletier">
      <mappings>
        <mapping type="ActAs"
                 value="https://server/service.svc" />
      </mappings>
    </user>
  </users>
</userMappings>

Please use the forum for any feedback. thanks!


IdentityModel
Monday, May 24, 2010 12:05:19 PM UTC  #   
 Friday, May 14, 2010

A more elegant way of embedding a SOAP security header in Silverlight 4

The current situation with Silverlight is, that there is no support for the WCF federation binding. This means that all security token related interactions have to be done manually.

Requesting the token from an STS is not really the bad part, sending it along with outgoing SOAP messages is what’s a little annoying. So far you had to wrap all calls on the channel in an OperationContextScope wrapping an IContextChannel. This “programming model” was a little disruptive (in addition to all the async stuff that you are forced to do).

It seems that starting with SL4 there is more support for traditional WCF extensibility points – especially IEndpointBehavior, IClientMessageInspector. I never read somewhere that these are new features in SL4 – but I am pretty sure they did not exist in SL3.

With the above mentioned interfaces at my disposal, I thought I have another go at embedding a security header – and yeah – I managed to make the code much prettier (and much less bizarre). Here’s the code for the behavior/inspector:

public class IssuedTokenHeaderInspector : IClientMessageInspector
{
    RequestSecurityTokenResponse _rstr;
 
    public IssuedTokenHeaderInspector(RequestSecurityTokenResponse rstr)
    {
        _rstr = rstr;
    }
 
    public void AfterReceiveReply(ref Message reply, object correlationState)
    { }
 
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        request.Headers.Add(new IssuedTokenHeader(_rstr));
        
        return null;
    }
}
 

public class IssuedTokenHeaderBehavior : IEndpointBehavior
{
    RequestSecurityTokenResponse _rstr;
 
    public IssuedTokenHeaderBehavior(RequestSecurityTokenResponse rstr)
    {
        if (rstr == null)
        {
            throw new ArgumentNullException();
        }
 
        _rstr = rstr;
    }
 
    public void ApplyClientBehavior(
      ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new IssuedTokenHeaderInspector(_rstr));
    }
 
    // rest omitted
}

This allows to set up a proxy with an issued token header and you don’t have to worry anymore with embedding the header manually with every call:

var client = GetWSTrustClient();
 
var rst = new RequestSecurityToken(WSTrust13Constants.KeyTypes.Symmetric)
{
    AppliesTo = new EndpointAddress("https://rp/")
};
 
client.IssueCompleted += (s, args) =>
{
    _proxy = new StarterServiceContractClient();
    _proxy.Endpoint.Behaviors.Add(new IssuedTokenHeaderBehavior(args.Result));
 
};
 
client.IssueAsync(rst);

Since SL4 also support the IExtension<T> interface, you can also combine this with Nicholas Allen’s AutoHeaderExtension.


IdentityModel
Friday, May 14, 2010 5:01:54 AM UTC  #   
 Sunday, May 09, 2010

Thinktecture.IdentityModel: WRAP and SWT Support

The latest drop of Thinktecture.IdentityModel contains some helpers for the Web Resource Authorization Protocol (WRAP) and Simple Web Tokens (SWT).

WRAP
The WrapClient class is a helper to request SWT tokens via WRAP. It supports issuer/key, SWT and SAML input credentials, e.g.:

var client = new WrapClient(wrapEp);
var swt = client.Issue(issuerName, issuerKey, scope);

All Issue overrides return a SimpleWebToken type, which brings me to the next helper class.

SWT
The SimpleWebToken class wraps a SWT token. It combines a number of features:

  • conversion between string format and CLR type representation
  • creation of SWT tokens
  • validation of SWT token
  • projection of SWT token as IClaimsIdentity
  • helpers to embed SWT token in headers and query strings

The following sample code generates a SWT token using the helper class:

private static string CreateSwtToken()
{
    var signingKey = "wA…";
    var audience = "http://websample";
    var issuer = "http://self";
 
    var token = new SimpleWebToken(
      issuer, audience, Convert.FromBase64String(signingKey));

   
token.AddClaim(ClaimTypes.Name, "dominick");
    token.AddClaim(ClaimTypes.Role, "Users");
    token.AddClaim(ClaimTypes.Role, "Administrators");
    token.AddClaim("simple", "test");
 
    return token.ToString();
}


IdentityModel
Sunday, May 09, 2010 8:27:46 PM UTC  #   
 Saturday, May 08, 2010

Thinktecture.IdentityModel: Comparing Strings without leaking Timinig Information

Paul Hill commented on a recent post where I was comparing HMACSHA256 signatures. In a nutshell his complaint was that I am leaking timing information while doing so – or in other words, my code returned faster with wrong (or partially wrong) signatures than with the correct signature. This can be potentially used for timing attacks like this one.

I think he got a point here, especially in the era of cloud computing where you can potentially run attack code on the same physical machine as your target to do high resolution timing analysis (see here for an example).

It turns out that it is not that easy to write a time-constant string comparer due to all sort of (unexpected) clever optimization mechanisms in the CLR. With the help and feedback of Paul and Shawn I came up with this:

  • Structure the code in a way that the CLR will not try to optimize it
  • In addition turn off optimization (just in case a future version will come up with new optimization methods)
  • Add a random sleep when the comparison fails (using Shawn’s and Stephen’s nice Random wrapper for RNGCryptoServiceProvider).

You can find the full code in the Thinktecture.IdentityModel download.

[MethodImpl(MethodImplOptions.NoOptimization)]
public static bool IsEqual(string s1, string s2)
{
    if (s1 == null && s2 == null)
    {
        return true;
    }
 
    if (s1 == null || s2 == null)
    {
        return false;
    }
 
    if (s1.Length != s2.Length)
    {
        return false;
    }
 
    var s1chars = s1.ToCharArray();
    var s2chars = s2.ToCharArray();
 
    int hits = 0;
    for (int i = 0; i < s1.Length; i++)
    {
        if (s1chars[i].Equals(s2chars[i]))
        {
            hits += 2;
        }
        else
        {
            hits += 1;
        }
    }
 
    bool same = (hits == s1.Length * 2);
 
    if (!same)
    {
        var rnd = new CryptoRandom();
        Thread.Sleep(rnd.Next(0, 10));
    }
 
    return same;
}


IdentityModel
Saturday, May 08, 2010 7:51:07 PM UTC  #   
 Wednesday, May 05, 2010

Thinktecture.IdentityModel: WIF Support for WCF REST Services and OData

The latest drop of Thinktecture.IdentityModel includes plumbing and support for WIF, claims and tokens for WCF REST services and Data Services (aka OData).

Cibrax has an alternative implementation that uses the WCF Rest Starter Kit. His recent post reminded me that I should finally “document” that part of our library.

Features include:

  • generic plumbing for all WebServiceHost derived WCF services
  • support for SAML and SWT tokens
  • support for ClaimsAuthenticationManager and ClaimsAuthorizationManager
  • based solely on native WCF extensibility points (and WIF)

This post walks you through the setup of an OData / WCF DataServices endpoint with token authentication and claims support. This sample is also included in the codeplex download along a similar sample for plain WCF REST services.

Setting up the Data Service
To prove the point I have created a simple WCF Data Service that renders the claims of the current client as an OData set.

public class ClaimsData
{
    public IQueryable<ViewClaim> Claims
    {
        get { return GetClaims().AsQueryable(); }
    }
 
    private List<ViewClaim> GetClaims()
    {
        var claims = new List<ViewClaim>();
        var identity = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
 
        int id = 0;
        identity.Claims.ToList().ForEach(claim =>
            {
                claims.Add(new ViewClaim
                {
                   Id = ++id,
                   ClaimType = claim.ClaimType,
                   Value = claim.Value,
                   Issuer = claim.Issuer
                });
            });
 
        return claims;
    }
}

…and hooked that up with a read only data service:

public class ClaimsDataService : DataService<ClaimsData>
{
    public static void InitializeService(IDataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
    }
}

Enabling WIF
Before you enable WIF, you should generate your client proxies. Afterwards the service will only accept requests with an access token – and svcutil does not support that.

All the WIF magic is done in a special service authorization manager called the FederatedWebServiceAuthorizationManager. This code checks incoming calls to see if the Authorization HTTP header (or X-Authorization for environments where you are not allowed to set the authorization header) contains a token. This header must either start with SAML access_token= or WRAP access_token= (for SAML or SWT tokens respectively).

For SAML validation, the plumbing uses the normal WIF configuration. For SWT you can either pass in a SimpleWebTokenRequirement or the SwtIssuer, SwtAudience and SwtSigningKey app settings are checked.If the token can be successfully validated, ClaimsAuthenticationManager and ClaimsAuthorizationManager are invoked and the IClaimsPrincipal gets established.

The service authorization manager gets wired up by the FederatedWebServiceHostFactory:

public class FederatedWebServiceHostFactory : WebServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(
      Type serviceType, Uri[] baseAddresses)
    {
        var host = base.CreateServiceHost(serviceType, baseAddresses);
 
        host.Authorization.ServiceAuthorizationManager =
          new FederatedWebServiceAuthorizationManager();
        host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
 
        return host;
    }
}

The last step is to set up the .svc file to use the service host factory (see the sample download).

Calling the Service
To call the service you need to somehow get a token. This is up to you. You can either use WSTrustChannelFactory (for the full CLR), WSTrustClient (Silverlight) or some other way to obtain a token. The sample also includes code to generate SWT tokens for testing – but the whole WRAP/SWT support will be subject of a separate post.

I created some extensions methods for the most common web clients (WebClient, HttpWebRequest, DataServiceContext) that allow easy setting of the token, e.g.:

public static void SetAccessToken(this DataServiceContext context,
  string token, string type, string headerName)
{
    context.SendingRequest += (s, e) =>
    {
        e.RequestHeaders[headerName] = GetHeader(token, type);
    };
}

Making a query against the Data Service could look like this:

static void CallService(string token, string type)
{
    var data = new ClaimsData(new Uri("https://server/odata.svc/"));
    data.SetAccessToken(token, type);
 
    data.Claims.ToList().ForEach(c =>
        Console.WriteLine("{0}\n {1}\n ({2})\n", c.ClaimType, c.Value, c.Issuer));
}

HTH


IdentityModel
Wednesday, May 05, 2010 2:54:51 PM UTC  #   

Thinktecture.IdentityModel: Claims Debugger Visualizer

In the latest drop of Thinktecture.IdentityModel you can find a debugger visualizer for IClaimsIdentity and IClaimsPrincipal.

Have fun ;)

PS. Thanks to Mr. UI.


IdentityModel
Wednesday, May 05, 2010 12:47:42 PM UTC  #   
 Wednesday, April 14, 2010

Using an Active Endpoint to sign into a Web Application

This question comes up from time to time, so I thought I’ll document it here.

The scenario is, that you don’t want to do a passive redirect in a web app – but directly talk to an active STS endpoint to authenticate and request a token. The reasons for that could be that you need a local sign-in page in the web app – or that the token service is not publicly reachable.

The following code can be used on a login page:

protected void _btnLogin_Click(object sender, EventArgs e)
{
    // authenticate with WS-Trust endpoint
    var factory = new WSTrustChannelFactory(
        new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
        new EndpointAddress("https://sts/endpoint"));

   
factory.Credentials.UserName.UserName = _txtUserName.Text;
    factory.Credentials.UserName.Password = _txtPassword.Text;
 
    var channel = factory.CreateChannel();
 
    var rst = new RequestSecurityToken
    {
        RequestType = RequestTypes.Issue,
        AppliesTo = new EndpointAddress("https://rp/"),
        KeyType = KeyTypes.Bearer
    };
 
    var genericToken = channel.Issue(rst) as GenericXmlSecurityToken;
 
    // parse token
    var handlers = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers;
    var token = handlers.ReadToken(new XmlTextReader(
       new StringReader(genericToken.TokenXml.OuterXml)));
    var identity = handlers.ValidateToken(token).First();

   
// create session token
    var sessionToken = new SessionSecurityToken(
       ClaimsPrincipal.CreateFromIdentity(identity));
    FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
 
    Response.Redirect("~/users/default.aspx");
}


IdentityModel
Wednesday, April 14, 2010 12:51:50 PM UTC  #   
 Sunday, April 04, 2010

Thinktecture StarterSTS 1.0 RTW

Wow – I can’t tell you how happy and relieved I am to write this post ;)

I started to work with what’s now called WIF approximately two years ago – and built various security token services for customers, demos and internal use. The idea behind StarterSTS was to have a non-trivial security token service sample that demonstrates the typical tasks of an STS (where it turns out that issuing tokens is by far the smallest part) and at the same time is real world enough to be directly used in specialized situations like development STSes.

I checked-in the first public version of StarterSTS at 25th May 2009 and had 1861 download so far. Today I am announcing StarterSTS 1.0 which is feature complete (and hopefully reasonably bug-free) and finally includes documentation as well as nine new screencasts on the various feature areas.

I want to thank all beta-testers and early adopters that gave feedback along the way! Now that 1.0 is done we can think about ways to extend the STS in the future.

Codeplex Site
http://startersts.codeplex.com (main)
http://startersts.codeplex.com/releases/view/43054#DownloadId=115213 (direct)
http://startersts.codeplex.com/thread/list.aspx (forum)

Documentation
http://identity.thinktecture.com/stsce/docs/

Screencasts
Initial setup & configuration
Federating your first web application
Federating with web services
Single-Sign-On & Confirmation screen
Using the REST endpoint
Using the OpenId bridge
Tracing
Using client certificates
Using Information Cards


IdentityModel
Sunday, April 04, 2010 6:33:42 AM UTC  #   
 Tuesday, March 30, 2010

Using Silverlight to Access WIF secured WCF Services (Part 3)

In this last part of the series (see here and here) I want to show you how to use the WIF/SL integration ClaimsIdentitySessionManager to request tokens and talk to WIF secured services.

The ClaimsIdentityManager registers as an ApplicationService in SL. Once registered, it can encapsulate the process of requesting a token for a relying party, caching that token as well as setting the SOAP security header for outgoing service requests.

Registration
ClaimsIdentitySessionManager gets registered in app.xaml. Here you can specify the endpoint address of the WS-Trust token services as well as the credential type. In this sample I am using the ADFS2 Windows/Transport endpoint from my last post.

<Application.ApplicationLifetimeObjects>
    <id:ClaimsIdentitySessionManager>
        <id:ClaimsIdentitySessionManager.IdentityProvider>
            <id:WSTrustSecurityTokenService
                   Endpoint="https://server/services/trust/13/windowstransport" 
                   CredentialType="DefaultCredential" />
        </id:ClaimsIdentitySessionManager.IdentityProvider>
    </id:ClaimsIdentitySessionManager>
</Application.ApplicationLifetimeObjects>

Calling the Service
All the service interaction is abstracted by the ClaimsIdentitySessionManager. The call to InvokeAsync does a few things:

  • checks if a token has already been obtained for the service endpoint
    • if not, requests the token and caches it
    • if a password is required, invokes a callback to the UI
  • sets the SOAP security header using the requested token

private void CallService()
{
    var factory = new ChannelFactory<StarterServiceContract>("symmetric");
    var proxy = factory.CreateChannel();
    var channel = proxy as IClientChannel;

    ClaimsIdentitySessionManager.Current.InvokeAsync(() =>
        {
            proxy.BeginGetClaims(result => ShowClaims(proxy, result), null);
        }, channel);
}


IdentityModel
Tuesday, March 30, 2010 8:18:07 AM UTC  #   
 Sunday, March 28, 2010

Requesting Tokens from ADFS2 using Silverlight and Windows Authentication

With SL4’s support for NTLM and the WIF integration bits, you can now easily request tokens from ADFS2 (or any other token service that supports Windows authentication) in single-sign-on style. Here’s the quick walk-through…

Enable the right endpoint in ADFS2
You need a WS-Trust endpoint for version 1.3 that supports transport security and Windows authentication. This endpoint needs to be enabled in the ADFS2 MMC (/trust/13/windowstransport).

Configure WSTrustClient and request the Token
Next you have to configure WSTrustClient to use this endpoint, using the Windows binding and Windows credential type:

var client = new WSTrustClient(
    new WSTrustBindingWindows(),
    new EndpointAddress("https://server/adfs/services/trust/13/windowstransport"),
    new WindowsCredentials());

From there on you can include the token to auth against other services.


IdentityModel
Sunday, March 28, 2010 3:37:27 PM UTC  #   
 Sunday, March 21, 2010

Using Silverlight to Access WIF secured WCF Services (Part 2)

This was one of my most popular blog post in the recent time (please read it first to get the necessary background information). I thought I give this another shot with the new SL/WIF integration.

There are other ways to accomplish the below things, e.g. using the SL application service or passive identity providers. I am focusing here purely on the SL initiated active STS/RP communication scenario and the raw APIs.

Requesting Tokens from within Silverlight
In my old post I had to use a custom REST endpoint in StarterSTS to request a bearer token. With the new WSTrustChannel, it is now possible to talk to a standard WS-Trust 1.3 endpoint (like the one in StarterSTS or ADFS2).

var client = new WSTrustClient(
    new WSTrustBindingUsernameMixed(),
    new EndpointAddress("https://.../issue.svc/mixed/username"),
    new UsernameCredentials("username", "password"));

You then have to construct an RST. Basically you specify the key type (bearer or symmetric) and appliesTo value.

var rst = new RequestSecurityToken(WSTrust13Constants.KeyTypes.Symmetric)
{
    AppliesTo = new EndpointAddress("https://roadie/StarterRP/")
};

The call to WSTrustClient.Issue returns an RSTR – which in turn contains the requested token and further key material. The identity kit also contains a token cache called TokenCache. You could use this class if you want to to store that token for further use.

client.IssueCompleted += (s, args) =>
{
    _cache.AddTokenToCache("myRP", args.Result);
};
 
client.IssueAsync(rst);

Using a Token to authenticate with a WCF Relying Party
Since Silverlight does not support issued token credentials, we must handcraft the SOAP security header. The identity kit includes the IssuedTokenHeader class for this purpose. The nice thing is, that this class supports symmetric proof keys as well as bearer tokens. But you still have to set this header manually on every call.

The identity kit includes its own wrapper to abstract away the header generation. I am using my own little helper here to make this process less disruptive.

public static class IssuedTokenHeaderExtensions
{
    public static void SendWithIssuedToken(this IContextChannel channel,
      RequestSecurityTokenResponse
rstr, Action action)
    {
        using (new OperationContextScope(channel))
        {
            OperationContext.Current.OutgoingMessageHeaders.Add(
              new IssuedTokenHeader(rstr));

           
action();
        }
    }
}

This allows calling a WCF service like this:

private void CallService()
{
    var factory = new ChannelFactory<StarterServiceContract>("myRP");
    var proxy = factory.CreateChannel();
    var channel = proxy as IContextChannel;
 
    channel.SendWithIssuedToken(_cache.GetTokenFromCache("myRP"), () =>
        {
            proxy.BeginGetClaims(result => ShowClaims(proxy, result), null);
        });
}

The trick here again is, that the client stack is configured for no security at all, whereas the WCF service uses a federation binding (with SecureConversation turned off).

I think this is pretty cool and solves some of the problems I had in the past. If Silverlight would only support client certificate credentials….


IdentityModel
Sunday, March 21, 2010 8:52:58 PM UTC  #   

A first Look at Silverlight and WIF Integration

At MIX, Caleb did a talk about the new Silverlight/WIF integration classes that “ship” with the latest identity training kit. Since this is a topic that comes up really frequently – I had a first look.

The integration code consists of two projects (client & server side plumbing) and can be divided into several feature areas. I will post more information on the corresponding areas when I have written more code against them.

Same claims programming model as in WIF
The integration code includes (I)ClaimsPrincipal, (I)ClaimsIdentity, Claim, ClaimCollection as well as the standard claim types.

WS-Trust and WS-Security support
This is my favourite feature! The WSTrustClient class allows requesting tokens from WS-Trust 1.3 endpoints. It supports Username/Password and Windows credentials as well as bearer and symmetric token types. The IssuedTokenHeader class makes it easier to embed the requested token in calls to backend services. The TokenCache class allows caching RSTRs to be used with the issued token header.

Bringing claims to a Silverlight UI
Another feature area deals with bringing claims into the SL UI for personalization and authorization purposes. This needs some server side plumbing (the AuthenticationService) and seems to focus on passive scenarios. The current implementation simply mirrors the user claims that are visible in the app/service backend back to the UI.

Silverlight integration
This part of the integration code makes logons and claims access more SLish by providing an SL appplication service and thus data binding access to claims.

HTH


IdentityModel
Sunday, March 21, 2010 10:23:59 AM UTC  #   
 Friday, March 05, 2010

Guide to Claims-based Identity and Access Control

RTM finally ;)

Book here.
Code here.
More info here.

Enjoy!!!


IdentityModel
Friday, March 05, 2010 12:36:46 PM UTC  #   

WIF Workshop

Mein geschätzter Kollege Vittorio Bertocci führt einen 2-Tägigen Workshop zum Thema Windows Identity Foundation in München durch. Das ist bestimmt eine gute Gelegenheit sich mal abseits vom Projektalltag mit dem Thema genauer zu beschäftigen.

Wenn danach alle (un)Klarheiten beseitigt sind, und Sie weiterführenden Informationen oder Unterstützung zur Implementierung von Claims in der Praxis benötigen – einfach Email an mich (dominick.baier (_at_) thinktecture.com). Ich helfe gerne weiter. Viel Spaß!


IdentityModel
Friday, March 05, 2010 12:28:46 PM UTC  #   
 Monday, March 01, 2010

Adding StarterSTS as a Claims Provider for ADFS2

The v1 beta of StarterSTS has an updated relying party configuration section. This allows to “plugin” the STS into ADFS2 or Sharepoint as a claims provider.

Here’s a quick walkthrough for ADFS2:

Register StarterSTS as claims provider in ADFS
This is really easy. Simply go to the ADFS2 configuration console and add a new claims provider. Then point the wizard to the StarterSTS WS-Federation metadata file (either by URL or using a file path). Afterwards you have to add some claim rules – to get started you could add a pass-through rule for the name claim.

You will also need to export the ADFS2 certificate that is used for token decryption.

Registering ADFS2 as a relying party in StarterSTS
The next step is to register ADFS2 in StarterSTS. This is done by modifying the relyingParty.config file (in the configuration sub folder). You need three things for that – the ADFS issuer URI, the physical address of the ADFS2 sign-in page and the ADFS2 token encryption certificate. The certificate could be either imported into the certificate store or you copy it to ~/App_Data/certificates.

The config entry looks similar to this:

<add realm="http://<adfsname>/adfs/services/trust"
     replyTo="https://<adfsname>/adfs/ls/">
  <certificate filename="tokendecryption.cer" />
</add>

HTH


IdentityModel
Monday, March 01, 2010 7:30:14 AM UTC  #   
 Friday, February 19, 2010

WCF, WIF and Load Balancing (and a bit of Azure)

Pablo wrote a post yesterday giving some background information on how session tokens are protected in WIF – here some additional info for WCF:

The ws* bindings in WCF establish a security session by default (via WS-SecureConversation). This has some implications, e.g.

  • You end up with a stateful service – or more important – with a stateful programming model. You have all the typical session “problems” like faulted sessions, timeout, retries etc…
  • By default SecureConversation only transmits a session identifier (like a ASP.NET session cookie) – the actual session is stored in-memory at the server. Not good for load balancing.

When you want to use WCF in a load balanced environment (e.g Azure) – you have to change the default behavior – you basically have two options:

  • Turn off SecureConversation all together. This has the advantage of being stateless (at least in that part of the communication). But this also means, that the bootstrap (SAML) token will get parsed on every request – this includes invoking the ClaimsAuthenticationManager. This might have performance implications – but depends on your scenario.
  • Force WCF into “cookie mode”. This means that the complete IClaimsPrincipal (after ClaimsAuthenticationManager has run) gets serialized and round-tripped in the SOAP header.

Turning off SecureConversation
Unfortunately WCF 3.5 does not directly allow that on the standard federation bindings. You would need to create a custom binding that uses an authentication mode of IssuedTokenOverTransport (for mixed mode) or IssuedTokenForCertificate (for message security).

In .NET 4 you can simply set establishSecurityContext to false on the standard ws-fed binding.

Cookie Mode
Forcing WCF into cookie mode requires a custom binding. The “trick” here is to set requireSecurityContextCancellation to false – which is just a fancy name for “serialize the context into the message”. Here’s the binding I am using (mixed mode security):

<customBinding>
  <binding name="federation_cookie">
    <security authenticationMode="SecureConversation"
              messageSecurityVersion="WSSecurity11
                                      WSTrust13
                                      WSSecureConversation13
                                      WSSecurityPolicy12
                                      BasicSecurityProfile10
"
              requireSecurityContextCancellation="false">
      <secureConversationBootstrap authenticationMode="IssuedTokenOverTransport"
                                   messageSecurityVersion="WSSecurity11
                                                           WSTrust13
                                                           WSSecureConversation13
                                                           WSSecurityPolicy12
                                                           BasicSecurityProfile10
">
        <issuedTokenParameters>
          <issuerMetadata address="https://…" />
        </issuedTokenParameters>
      </secureConversationBootstrap>
    </security>
   
    <textMessageEncoding />
    <httpsTransport />
  </binding>
</customBinding>

As Pablo points out in his post, the session cookie must be protected somehow. The standard WIF behavior is to the DPAPI user key. This key cannot be easily shared between nodes in a cluster (unless the nodes are all domain members and roaming profiles are activated). Another more explicit (and practical) option is to use an RSA key. Most typically you would feed your SSL certificate or the certificate used to decrypt incoming tokens into the following session token handler:

public class WebFarmSessionSecurityTokenHandler : SessionSecurityTokenHandler
{
    public WebFarmSessionSecurityTokenHandler(X509Certificate2 protectionCertificate)
        : base(CreateRsaTransforms(protectionCertificate))
    { }
 
    private static ReadOnlyCollection<CookieTransform> CreateRsaTransforms
      (X509Certificate2 protectionCertificate)
    {
        var transforms = new List<CookieTransform>()
                        {
                            new DeflateCookieTransform(),
                            new RsaEncryptionCookieTransform(protectionCertificate),
                            new RsaSignatureCookieTransform(protectionCertificate),
                        };
 
        return transforms.AsReadOnly();
    }
}

One way of wiring up the above handler would be a service host factory for the WIF enabled WCF service. If you want to put a little more work in it you can also make the handler configuration friendly (see here).

In general I’d recommend watching Hervey’s excellent talk from PDC09 about WIF in load balanced environments (e.g. Azure).

HTH


IdentityModel
Friday, February 19, 2010 7:36:26 AM UTC  #   
 Monday, February 15, 2010

Securing WCF Data Services using WIF

This questions comes up every once in a while..

Since WCF Data Services is just a normal WCF service (using the web programming model), all the typical security APIs and extensibility points apply.

That said, depending on your scenario you might have to be a little more creative for REST-style services. Here’s a quick walkthrough:

Enabling WIF in the Data Service
The easiest way to get WIF wired up is by writing a custom service host factory. You simply have to derive from DataServiceHostFactory, override CreateServiceHost and call FederatedServiceCredentials.ConfigureServiceHost before you return the host to the plumbing.

This gives you the standard WIF integration for all standard HTTP credential types (Basic, Integrated etc…) and the typical extensibility points like ClaimsAuthorizationManager.

For accepting and converting more advanced token types like SWT or SAML, you need to plugin your own token handling. I gave it a try for SWT tokens (see here for the general SWT integration story).

public class ProtectedDataServiceHostFactory : DataServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(
      Type serviceType, Uri[] baseAddresses)
    {

        var host = base.CreateServiceHost(serviceType, baseAddresses);

        host.Authorization.ServiceAuthorizationManager = new
          SimpleWebTokenAuthorizationManager(
             acsAddress,
             expectedAudience,
             acsKey);
        host.Authorization.PrincipalPermissionMode =
          PrincipalPermissionMode.Custom;

        return host;
    }
}

This uses my SWT plumbing to turn incoming SWT tokens into an IClaimsPrincipal. You could easily do the same thing for SAML (but be aware that SAML tokens can become quite big – and you typically want to transmit them using an HTTP header for this scenario).

You could now use the resulting claims for authorization as well as WCFDS interceptors, e.g.:

[QueryInterceptor("Users")]
public Expression<Func<Users, bool>> OnQueryUsers()
{
    var principal = Thread.CurrentPrincipal as IClaimsPrincipal;
    var customer = principal.GetClaimValue("http://claims/customerName");

    return user => user.Applications.ApplicationName == customer;
}

Sending a token header to the Data Service
The next step is to send a token to the Data Service. This can be achieved by handling the SendingRequest event on the DataServiceContext derived client plumbing, e.g.:

class ProviderEntitiesWithToken : ProviderEntities
{
    string _token;
    string _tokenHeader = "Authorization";
 
    public ProviderEntitiesWithToken(Uri address, string token) : base(address)
    {
        _token = token;
        SendingRequest += OnSendingRequest;
    }
 
    void OnSendingRequest(object sender, SendingRequestEventArgs e)
    {
        e.RequestHeaders[_tokenHeader] =
          SimpleWebToken.GetAuthorizationHeader(_token);
    }
}

Using the Data Service
The usage pattern is the same as without any tokens or WIF. New up your derived class, set the token and use e.g. LINQ to query the Data Service.

static void Main(string[] args)
{
    var token = RequestToken();
    var service = new ProviderEntitiesWithToken(new Uri(dataServiceAddress), token);
   
    var users = from u in service.Users
                select u;
 
    users.ToList().ForEach(u => Console.WriteLine(u.UserName));
}

HTH


IdentityModel
Monday, February 15, 2010 1:48:40 PM UTC  #   
 Monday, February 08, 2010

Integrating Simple Web Tokens (SWT) with WCF REST Services using WIF

The Simple Web Token (SWT) is a new & simple token format that was created by Microsoft, Google and others. See here for specs. The Azure platform App Fabric Access Control service e.g. uses this token type.

Why yet another token type? Well – the advantages of SWT are that it is simple to construct (form encoded key value pairs), that only simple crypto is needed (SHA256 HMACs) and that it is compact on the wire which allows easy embedding in HTTP headers or query strings.

The downsides are – it is not a widely adopted token format (current spec version is 0.9.5.1) and the lack of asymmetric signatures (e.g. X.509 based).

Since I had to do some ACS work recently, I crafted up a simple SWT integration for WCF based REST services (works in ASP.NET as well). The plumbing looks for a SWT token either on the Authorization or X-Authorization header as well as on the query string. Using the power of WIF, it is simple to transform the SWT token into an IClaimsPrincipal.

From that point on, you have all the unified identity representation benefits of WIF.

Download here.


IdentityModel
Monday, February 08, 2010 2:30:41 PM UTC  #   
 Friday, February 05, 2010

Using SAML as a Client Credential Type in WCF (updated to WIF RTM)

A reader has asked me to update the Client SAML sample to WIF RTM (for background and motivation please read here first).

The main work was in the SAML security token handler Validate method, this looks now like this:

public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
{
    if (token == null)
    {
        throw new ArgumentNullException("token");
    }       

    var samlToken = token as SamlSecurityToken;
    if (samlToken == null)
    {
        throw new ArgumentException("token");
    }
    if (samlToken.Assertion == null)
    {
        throw new ArgumentException("token");
    }
   
    var assertion = samlToken.Assertion as Saml11Assertion;
    this.ValidateConditions(samlToken.Assertion.Conditions, false);

    // extract claims from token
    var identity = new ClaimsIdentity("ClientSaml");
    ProcessStatement(assertion.Statements, identity, "Client");
   
    // call authentication and filtering logic
    IClaimsIdentity newIdentity;

    try
    {
        if (ValidateUser(identity, out newIdentity))
        {
            return new ClaimsIdentityCollection(new IClaimsIdentity[] { newIdentity });
        }
        else
        {
            throw new SecurityTokenValidationException("Authentication failed");
        }
    }
    catch (Exception ex)
    {
        throw new SecurityTokenValidationException("Security token validation failed", ex);
    }
}

You would then derive from the base handler and implement the ValidateUser method. This method does some sort of authentication based on the incoming claims and returns an IClaimsIdentity containing the claims that should get passed through to the service code, e.g.:

// sample implementation - do not use for production ;)
protected override bool ValidateUser(ClaimsIdentity id, out IClaimsIdentity newIdentity)
{
    newIdentity = null;
    var usernameClaim = id.Claims.First(c => c.ClaimType == WSIdentityConstants.ClaimTypes.Name);
    var passwordClaim = id.Claims.First(c => c.ClaimType == _passwordClaimType);
    var customerIdClaim = id.Claims.First(c => c.ClaimType == _customerIdClaimType);
   
    if (usernameClaim.Value == passwordClaim.Value)
    {
        newIdentity = new ClaimsIdentity(new Claim[]
        {
            usernameClaim,
            customerIdClaim
        }, "ClientSaml");

        return true;
    }

    return false;
}

You can find the complete source code here.


IdentityModel
Friday, February 05, 2010 6:44:39 AM UTC  #   
 Wednesday, February 03, 2010

StarterSTS V1.0 Beta 1

OK – I finally was able to carve out some time…This is the first feature complete release of the StarterSTS!

New features include:

  • client certificate support for WS-Fed and WS-Trust endpoints
  • new relying party configuration
    • allows specifying an explicit reply to address
    • allows relying parties without encryption
  • refactoring of web site / STS code.

Still no docs – sorry. Please contact me via the Codeplex forum if you have any questions.

Some brief migration remarks:

  • relying parties are now configured in relyingParties.config. Move the RP entries from certificates.config to this new config file
  • userMappings.config allows mapping client certificates to membership users
  • profile configuration has been moved to profile.config

On the todo list:

  • documentation
  • simplified installation
  • IIS InetMgr integration for all configuration aspects

What I need from you:

  • testers!
  • input and feedback
  • volunteers for completing the todos

Have fun!

download here: http://startersts.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=39891


IdentityModel
Wednesday, February 03, 2010 9:22:22 PM UTC  #   
 Monday, February 01, 2010
 Tuesday, January 05, 2010

Claims Identity Guide – Release Candidate

The last six months we were working on finalizing the P&P guide to claims based identity and access control. We finally have a release candidate!

Eugenio has all the details here. As always, feedback is welcome!

Enjoy!


IdentityModel
Tuesday, January 05, 2010 5:37:21 AM UTC  #   
 Thursday, December 24, 2009

Beware of WIF HTTP Modules and Default Configuration

Most samples I know of – as well as FedUtil generated configuration set a preCondition="managedHandler" for the WIF HTTP modules.

This means that the modules (and thus the protection of the requested resource) only kicks in for “managed” content like .aspx files. Not for static content like .xml etc.

If you like to protect static content using WIF, you have to remove the preCondition in web.config. Also add the runAllManagedModulesForAllRequests attribute to the modules section in system.webServer if you are using ASP.NET URL Authorization. Subtle security hole…


IdentityModel
Thursday, December 24, 2009 10:49:24 AM UTC  #   

WIF Configuration – Part 3: Extensibility

Some of the WIF configuration elements support extensibility. This means that you can attach arbitrary XML child elements to the configuration elements. When this is the case, the WIF configuration system creates the piece of plumbing in question using a special ctor that takes an XmlNodeList representing the custom configuration. You can then parse the XML and configure the class accordingly. Examples are:

IssuerNameRegistry

<issuerNameRegistry type="ConfigurationBasedIssuerNameRegistry, ...">
  <
trustedIssuers>
    <
add name="foo"
        
thumbprint="xxx" />
  </
trustedIssuers>
</
issuerNameRegistry>

ClaimsAuthorizationManager
(see here)

<claimsAuthorizationManager type="PolicyBasedAuthorizationManager">
  <
policy resource="Directory"
         
action="Browse">
    <
claim claimType="…"
          
claimValue="Users" />
  </
policy>
</
claimsAuthorizationManager>

SecurityTokenHandler
(see here)

<add type="Saml11SecurityTokenHandler, ...">
  <
samlSecurityTokenRequirement issuerCertificateRevocationMode="Online"
                               
issuerCertificateValidationMode="ChainTrust" />
</
add>


IdentityModel
Thursday, December 24, 2009 8:38:32 AM UTC  #   
 Wednesday, December 23, 2009

WIF Configuration – Part 2: SecurityTokenHandlerConfiguration

The workhorse of WIF are security token handler. Again token handler can be use independently of the WIF configuration system – or together.

The “stand-alone” use case
You can simply new up a token handler (e.g. the SAML 1.1 handler) in an arbitrary application.

var saml11Handler = new Saml11SecurityTokenHandler();

But a token handler needs more information to do its work (issuer name registry, audience URIs, certificate validation etc.). This information is all encapsulated in the SecurityTokenHandlerConfiguration class. You can reach into that class from the token handler’s Configuration property. Configuration is null by default and must be newed up and set manually.

Handler collections
Another option is to group a bunch of token handlers into a collection. This is useful when you have to deal with a number of in/output token types or need to chain token handlers (e.g. for encryption or compression). Collections also allow to share token handler configuration across contained handlers.

When you new up a SecurityTokenHandlerCollection you have the choice of passing in a SecurityTokenHandlerConfiguration instance, or you use a default configuration (not sure if these values are documented – use reflector ;). When you add a handler to a collection, the collection checks if the handler already has some configuration set (by checking if Configuration is not null). If this is not the case, then handler inherits the collection configuration.

var samlHandlers = new SecurityTokenHandlerCollection(new SecurityTokenHandler[]
    {
        saml11Handler,
        new Saml2SecurityTokenHandler()
    });

Another way to new up a handler collection is to use the static CreateDefaultSecurityTokenHandlerCollection method on the collection. This creates a collection with all default token handlers shipping with WIF. Again you have the option to pass in a configuration object.

Using configuration
Token handler configuration is typically an ideal candidate for configuration files. When you want to support that, you have two choices. Either copy the values from configuration, or use the configuration system to create and configure the handler.

Copying from configuration can be handy sometimes. To do that use the approach shown in my previous post to load the service configuration manually.

The WIF security token handler configuration section also has the concept of named handler collections. There is always a default token handler collection, but you can have additional ones – each with their own configuration, e.g.:

<securityTokenHandlers>
  <!--
default token handlers - inherit global configuration settings -->
 
  <
securityTokenHandlerConfiguration>
    <!--
override with local configuration -->
   
    <
audienceUris>
      <
add value="http://bar" />
    </
audienceUris>
  </
securityTokenHandlerConfiguration>
</
securityTokenHandlers>

<
securityTokenHandlers name="AccessToken">
  <!--
named token handler collection - inherit global configuration settings -->
  <
securityTokenHandlerConfiguration>
    <!--
override with local configuration -->
   
    <
audienceUris mode="Always">
      <
add value="http://custom/*" />
    </
audienceUris>
    <
tokenReplayDetection enabled="true" />
   
    <
certificateValidation>
      <
certificateValidator type="AccessCertValidation, ..."/>
    </
certificateValidation>
  </
securityTokenHandlerConfiguration>

  <
clear />
  <
add type="AccessSecurityTokenHandler, …" />
  <
add type="CompressedSecurityTokenHandler, …" />

</
securityTokenHandlers>

Programmatically, you can get to the standard token handler collection using the SecurityTokenHandlers property on ServiceConfiguration.

To get to the named token handlers, you use the SecurityTokenHandlerCollectionManager, e.g. like this:

var accessHandlers = config.SecurityTokenHandlerCollectionManager["AccessToken"];

So as a rule of thumb: when you new up handlers or collections yourself, you are responsible for programmatic configuration. When you use ServiceConfiguration, the config file settings are applied automatically.


IdentityModel
Wednesday, December 23, 2009 5:38:38 PM UTC  #   
 Tuesday, December 22, 2009

WIF Configuration – Part 1: ServiceConfiguration

WIF supports a flexible configuration system and various ways to programmatically interact with that configuration.

This flexibility comes in two ways:

  • Named configuration elements that you can selectively load (service & token handler configuration)
  • Configuration extensibility (e.g. for token handlers, issuer name registries or claims authorization)

In this first part I’ll focus on the service configuration.

The WIF configuration can have several service elements. Services can be named, the unnamed element becomes the default configuration:

<microsoft.identityModel>
  <
service>
    <!--
default configuration -->
  </
service>

  <
service name="alternateConfiguration">
    <!--
alternate configuration -->
  </
service>
</
microsoft.identityModel>

You can get a handle to the configuration by newing up a ServiceConfiguration object. The ctor allows to optionally pass in the name of the service. From there on you have an OM that represents the various configuration options.

This is useful when you build your own integration, but for WCF and ASP.NET there is already an infrastructure in place.

How to couple configuration with a relying party
By default the standard hosting plumbing uses the default service configuration, but there are various ways to make this dynamic (e.g. for different environment like dev, staging etc).

In ASP.NET you can subscribe to the ServiceConfigurationCreated event of the FederatedAuthentication class. This event gets fired during initialization and gives you the chance to load an arbitrary configuration and pass that back via the ServiceConfigurationCreatedEventArgs.
You can then access the current configuration at any point via FederatedAuthentication.ServiceConfiguration (since creating a configuration is expensive, this class takes also care of caching).

In WCF you wire up WIF with by calling FederatedServiceCredentials.ConfigureServiceHost(…). This call allows you to either pass in an instance of ServiceConfiguration or the stringified name of the service. Another option is to use the ConfigureServiceHostBehavior from configuration. Again this behavior has a parameter called serviceName.

You can then access the current configuration either by

  • finding the FederatedServiceCredentials behavior from the ServiceHost description (if you have access to the ServiceHost)
  • obtain it from a MessageProperty called ServiceConfiguration.

HTH


ASP.NET | IdentityModel | WCF
Tuesday, December 22, 2009 9:34:59 AM UTC  #   
 Wednesday, December 02, 2009

Baier & Weyer on WIF

We had the pleasure to have a chat with Richard and Carl about what’s nearest and dearest to my heart – WIF ;) Enjoy…

http://www.dotnetrocks.com/default.aspx?showNum=503


IdentityModel
Wednesday, December 02, 2009 8:21:15 PM UTC  #   
 Thursday, November 26, 2009

Thinktecture.IdentityModel v0.6

This version is compiled against WIF RTM.

Some stuff is still experimental. But feel free to play around ;)


IdentityModel
Thursday, November 26, 2009 12:28:47 PM UTC  #   
 Wednesday, November 18, 2009

IDFX to Zermatt to Geneva … to … WIF RTM!

It’s been a long way….

http://msdn.microsoft.com/en-us/evalcenter/dd440951.aspx

I love it!


IdentityModel
Wednesday, November 18, 2009 8:02:15 AM UTC  #   
 Wednesday, November 11, 2009

StarterRP v0.95 (for WIF RC)

Updated StarterRP to go with the 0.95 release of the StarterSTS.

Changes include:

  • added more SOAP endpoints to the WCF RP
    • message, mixed mode, simple (for Silverlight clients)
  • added a Silverlight client that can retrieve tokens and send them to RPs
  • added OpenID bridge test to the ASP.NET RP

Same disclaimer as here applies.


IdentityModel
Wednesday, November 11, 2009 8:06:30 AM UTC  #   
 Tuesday, November 10, 2009

StarterSTS v0.95 (for WIF RC)

I uploaded an interim release of the StarterSTS to codeplex.

This release is not fully tested – and is mainly available to provide compatibility with WIF RC. There are some new features – and I hope I have not introduced any regression bugs. Please contact me via the codeplex forum when you have questions.

Some new features:

  • added a simple HTTP and SOAP based endpoint to request token
  • added support to bridge OpenID logons to WS-Federation
    • you can specify a separate signing key for bridged authentication, so RPs can distinguish between native and bridged authentication
  • config changes to accomodate the various endpoints
    • WS-Trust (message security)
    • WS-Trust (mixed mode security)
    • simple HTTP
    • simple SOAP
    • OpenID bridge
    • WS-Federation metadata
  • did some refactoring to allow easier pluggability and customizations
    • retrieving certificates (CertificateProvider)
    • retrieving claims (ClaimsProvider)
    • analyzing an RST (PolicyOptions and PolicyScope)
    • validating the request against configured policy (PolicyValidator)
  • added optional confirmation screen after login
    • when enabled, the user has to confirm before StarterSTS issues the token
    • this is an additional countermeasure against one-click attacks

Have fun.


IdentityModel
Tuesday, November 10, 2009 6:07:02 PM UTC  #   
 Sunday, November 08, 2009

Thinktecture.IdentityModel updated for WIF RC

download here.


IdentityModel
Sunday, November 08, 2009 12:40:48 PM UTC  #   
 Wednesday, October 28, 2009

Using Silverlight to Access WIF secured WCF Services

This topic comes up quite often recently – so I hope the title is search engine friendly.

Disclaimer: At the time of this writing, the current version of Silverlight is v3 and WIF is in beta 2. Hopefully this will be a non-issue soon.

I talk a lot about claims, tokens and WIF/ADFS 2 to customers. All is good and fine and they like it. Another technology that comes up very often is Silverlight – and especially the “story” of Silverlight and WCF/WIF. Now this is not an easy question to answer.

When thinking about Silverlight and back-end security in general – there are two fundamental scenarios – short of really good names – I call them “passive” and “active”.

Passive
With passive I mean, that the browser has already established a security context with the back-end system the Silverlight .XAP uses (and typically is also hosted at). An example would be that the user first authenticates with the web application and then starts the Silverlight app from there. In this case all the authentication related work was done by browser beforehand and all back-end requests simply re-transmit authentication headers, cookies and the like.

This is not different with WIF secured ASP.NET applications. Eugenio has a good example of this here. This approach works fine while running in the browser and using “application-local” resources only.

Active
This is the scenario I really want to talk about. In this case the .XAP comes from some server down to the client (in or out-of-browser) and wants to communicate with some back-end service on a different machine. This back-end service requires an issued token from a STS.

Those of you with WCF background will say: “that’s what the federation bindings in WCF are for”. But there is no federation binding in Silverlight.

If you need to enable such a scenario, you have to use several workarounds.

Requesting a Token
Since Silverlight has no support for WS-Trust, we must find another way to request a token from a STS. Thanks to WIF this is not hard to do when you control the token service. You could add a simple REST or SOAP head that returns tokens. I wrote about this approach here.

Some remarks here:

  • Since you cannot do the proof of possession crypto in Silverlight, you need to request bearer tokens from the STS.
  • The STS roundtrip is a cross-domain request. This means that the STS needs a client access policy (see here).
  • You have to somehow authenticate with the STS. Silverlight has no support for Kerberos or client certificates. Basically you are stuck with some kind of userid/secret credential. I wrote about that here.

Sending the token to the Service
This is the slightly more complicated part. Since Silverlight has no support for issued tokens, you have to manually embed the token in the outgoing SOAP security header. This is not as scary as it sounds.

There is the so called Basic Security Profile in WS-Security which allows sending a simple security header with a timestamp and a token over SSL. This can be encapsulated in a MessageHeader derived class.

public class SecurityMessageHeader : MessageHeader
{
    string _token;
    string _nsUtility = "...";


    public SecurityMessageHeader(string token)
    {
        _token = token;
    }

    protected override void OnWriteHeaderContents(
      XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        DateTime now = DateTime.UtcNow;
        string created = XmlConvert.ToString(
          now, "yyyy-MM-ddTHH:mm:ss.fffZ");
        string expires = XmlConvert.ToString(
          now.AddMinutes(5), "yyyy-MM-ddTHH:mm:ss.fffZ");

        writer.WriteStartElement("Timestamp", _nsUtility);
        writer.WriteAttributeString("Id", _nsUtility, "_0");
        writer.WriteElementString("Created", _nsUtility, created);
        writer.WriteElementString("Expires", _nsUtility, expires);
        writer.WriteEndElement();
       
        writer.WriteNode(XmlReader.Create(
          new StringReader(_token)), false);
    }

    public override string Name
    {
        get { return "Security"; }
    }

    public override string Namespace
    {
        get { return "..."; }
    }
}

Afterwards you can attach the header to outgoing calls:

var factory = new ChannelFactory<ServiceContract>("client");
var proxy = factory.CreateChannel();

using (var scope = new OperationContextScope(proxy as IContextChannel))
{
    OperationContext.Current.OutgoingMessageHeaders.Add(
      new SecurityMessageHeader(token));
   
    proxy.BeginOperation(result =>
        {
           ...
        }, null);
}

The binding on the client side is a binding with no client credential but SSL (the binary encoder is not required and used only for performance):

<customBinding>
  <
binding name="BearerTokensOverTransport">
    <
binaryMessageEncoding />
    <
httpsTransport />
  </
binding>
</
customBinding>

On the service side, you need a binding that accepts bearer tokens over transport security, like this:

<customBinding>
  <
binding name="simple">
    <
security authenticationMode="IssuedTokenOverTransport"
             
messageSecurityVersion="WSSecurity11
                                      WSTrust13
                                      WSSecureConversation13
                                      WSSecurityPolicy12
                                      BasicSecurityProfile10
">
      <
issuedTokenParameters keyType="BearerKey" />
    </
security>
    <
binaryMessageEncoding />
    <
httpsTransport />
  </
binding>
</
customBinding>

The rest works as normal. You have to enable WIF in the service and you get your IClaimsPrincipal.

Some remarks:

  • Again this service needs a client access policy for Silverlight cross domain calls.
  • Keep in mind that these are bearer tokens. When you have a scenario that requires proof of possession, this will not work
  • The SOAP response from the service will also contain a security header. Since the client is not configured for security this header may be unexpected. Silverlight does not seem to care, but other web service stacks might. In WCF you can work around that problem by adding the ValidateMustUnderstand behavior to the client stack.

The complete code (STS extensions, Silverlight client and back-end service) is included in the next drop of the StarterSTS (version 0.95). I will upload that soon.

HTH


IdentityModel | WCF
Wednesday, October 28, 2009 8:04:00 AM UTC  #   
 Thursday, October 08, 2009

StarterSTS, WIF, Identity on Channel9

Dariusz interviewed me for Channel9. You can find the recording here.

Have fun ;)


IdentityModel
Thursday, October 08, 2009 11:15:46 AM UTC  #   
 Monday, October 05, 2009

Claims based Identity & Access Control Guide – Early drafts available

Eugenio just announced that the codeplex site is up now!

Have a look at the draft documents – feedback is always welcome!!


IdentityModel
Monday, October 05, 2009 5:47:39 AM UTC  #   
 Sunday, September 13, 2009

Restful Token Service Endpoints and Silverlight Clients

It turns out that there is no way in Silverlight to send credentials using the standard HTTP Authorize header (see here). WTF?!.

You have to use a custom HTTP header to transmit credentials in this case, e.g. X-Authorize (nice?). I have adjusted my service code to accept both headers and will update the StarterSTS bits on Codeplex.


IdentityModel
Sunday, September 13, 2009 8:11:35 AM UTC  #   
 Friday, September 11, 2009

StarterSTS Version 0.93

I just uploaded a minor update.

  • refactored ScopeOptions to PolicyOptions and added a PolicyScope class
  • CertificateProvider class abstracts physical loading of relying party encryption certificates
  • /users/restIssue.svc is a Restful token issuance endpoint – you can use a simple GET to retrieve a token (see here)

btw – this is the client code you can use to talk to the REST issuance endpoint:

public static string GetToken(
  string username, string password, string uri, string realm)
{
    using (var client = new WebClient())
    {
        var encoding = Encoding.GetEncoding("iso-8859-1");
        string encodedCreds = Convert.ToBase64String(
          encoding.GetBytes(String.Format("{0}:{1}", username, password)));
        string authHeader = string.Format("Basic {0}", encodedCreds);
        realm = HttpUtility.UrlEncode(realm);

        client.Headers.Add(HttpRequestHeader.Authorization, authHeader);

        return client.DownloadString(
          string.Format("{0}/?realm={1}", uri, realm));
    }
}


IdentityModel
Friday, September 11, 2009 5:43:51 PM UTC  #   

Adding a REST Endpoint to a WIF Token Service

Sometimes it is useful to have a really simple way to acquire a token from a token service – without having to fiddle around with WS-Federation or WS-Trust. Issuing a simple GET request against a token issuance endpoint seems to fulfill that requirement.

So I decided to a add a simple HTTP endpoint to my STS using the WCF web programming model:

[ServiceContract]
public interface IRestfulTokenServiceContract
{
    [OperationContract]
    [WebGet(UriTemplate = "/?realm={realm}")]
    XElement Issue(string realm);
}

You could provide more parameters here (like token type, lifetime etc.) but i decided to keep it simple.

For the implementation you have to decide which authentication types you want to support. Since I needed username/password authentication I used Cibrax’ excellent basic authentication extension. If you need to support client certificates, you would get the certificate details from WCF’s AuthorizationContext.

To route the GET request to the existing token issuance logic, you can create the STS using the static CreateSecurityTokenService method on the SecurityTokenServiceConfiguration class. Then you have to construct a RST and IClaimsPrincipal to describe the token request and pass that into the Issue method. Afterwards you serialize the security token back as a HTTP response and you are done.

I will incorporate that into the next drop of the StarterSTS – but for now here is the code:

public class RestfulTokenService : IRestfulTokenServiceContract
{
    public XElement Issue(string realm)
    {
        EndpointAddress epRealm;
        try
        {
            epRealm = new EndpointAddress(realm);
        }
        catch
        {
            WebOperationContext.Current.OutgoingResponse.StatusCode =
              HttpStatusCode
.BadRequest;
            return null;
        }
       
        RequestSecurityToken rst = new RequestSecurityToken
        {
            AppliesTo = epRealm,
            KeyType = KeyTypeConstants.Bearer
        };

        var sts =
          new StarterTokenServiceConfiguration().CreateSecurityTokenService();
        var rstr = sts.Issue(CreatePrincipal(), rst);

        StringBuilder sb = new StringBuilder();
        var writer = XmlWriter.Create(sb);

        var col =
SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
        col.WriteSecurityToken(writer,
          rstr.RequestedSecurityToken.SecurityToken);
        writer.Flush();

        WebOperationContext.Current.OutgoingResponse.ContentType =
          "text/xml"
;
        return XElement.Parse(sb.ToString());
    }

    private IClaimsPrincipal CreatePrincipal()
    {
        if (Thread.CurrentPrincipal == null ||
            Thread.CurrentPrincipal.Identity == null ||
            string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name))
        {
            throw new InvalidRequestException("unknown client");
        }

        var identity = new ClaimsIdentity(
            new Claim(WSIdentityConstants.ClaimTypes.Name,
                      Thread
.CurrentPrincipal.Identity.Name));

        return new ClaimsPrincipal(identity);
    }


IdentityModel
Friday, September 11, 2009 9:51:13 AM UTC  #   
 Tuesday, September 01, 2009

StarterSTS Version 0.92

I have an update to the StarterSTS up on codeplex. There is also a new screencast that details the changes from the last version.

Have fun!


IdentityModel
Tuesday, September 01, 2009 10:32:50 AM UTC  #   
 Friday, August 28, 2009

.NET Usergroup Frankfurt – WIF, ADFS 2, CardSpace 2

Am 15. September sind Christian und Ich in Frankfurt und plaudern mal nen Abend lang über unsere Erfahrungen mit Identity und Claims in verteilten Anwendungen.

Wir freuen uns schon und das sollte ein netter Abend werden.

Es sind noch Plätze frei – Anmeldung ist hier erforderlich. Vielleicht sieht man sich ja dort.


Conferences | IdentityModel
Friday, August 28, 2009 6:48:03 PM UTC  #   
 Monday, August 24, 2009

Patterns & Practices - Claims based Authentication & Authorization Guide

Summer break is over – and exciting times lie ahead.

Over the course of the next months I will be working with Eugenio, Keith, Vittorio, Matias and David. The end result will (hopefully) be a very interesting, useful and pragmatic guide to all things claims.

Eugenio already posted some details on the guide and we will be releasing interim version so you can give us feedback.

Watch this space!


IdentityModel
Monday, August 24, 2009 6:11:21 AM UTC  #   
 Wednesday, July 22, 2009

Claims Authorization in WIF Beta 2 – ASP.NET and WCF Integration

In the previous post I illustrated how the basic claims authorization infrastructure in WIF (formerly Geneva) works. In this post I want to focus more on how claims authorization behaves when integrated in WCF and ASP.NET.

ASP.NET
In addition to using the claims authorization manager manually like I showed you in the last post, you can also opt-in to per-request claims authorization (think of it as a replacement for the “classic” URL authorization module in ASP.NET / IIS). For this purpose you’ll find an HTTP module called ClaimsAuthorizationModule in the Microsoft.IdentityModel.Web namespace.

This module simply subscribes to the AuthorizeRequest processing stage and calls the configured claims authorization manager for every request. The AuthorizationContext that gets passed in the manager consists of the current IClaimsPrincipal, the request URL and the HTTP method.

If you want to do tricks like custom IClaimsPrincipal implementations, you’d either exchange the principal before you hit the claims authorization manager (in PostAuthenticateRequest) or after it (in PostAuthorizeRequest).

WCF
As usual things are a little more complex in WCF. Authorization (amongst other things) is driven by a ServiceAuthorizationManager in WCF. When you call ConfigureServiceHost, WIF puts a special version of that class, the IdentityModelServiceAuthorizationManager, in place. This class in turn calls out to the configured ClaimsAuthorizationManager. In that case the WS-Addressing To and the Action header are passed in for every request.

HTH


WCF | ASP.NET | IdentityModel
Wednesday, July 22, 2009 5:24:30 AM UTC  #   
 Friday, July 10, 2009

Defeating SSL

Not a really new paper – but definitely recommended reading.

Some lessons learned:

  • Moxie is not really attacking SSL – but uses HTTP to bypass HTTPS.
  • Switch to SSL as early as possible – but that might be too late already.
  • Users never type https:// (nor http://) – they start with plain text and hope the application is doing the right thing.
  • Fortunately (web) services are not affected. There is no human doing the http vs https decision. WCF e.g. also doesn’t like to be downgraded to plain text whenever credentials are involved. That’s a good thing in the face of such attacks.
  • Endpoint Identities (an addition to WS-Addressing) are a good thing.

I see interesting times for passive profile SSO scenarios like WS-Federation. This doesn’t mean that these technologies open new holes – it is just that the (username/password) credentials we send around are much more powerful because they can be used in multiple applications.

This also means – if you are building a passive STS – you should not solely rely on SSL to secure your tokens. Encrypt them!


IdentityModel | ASP.NET | WCF
Friday, July 10, 2009 10:09:50 AM UTC  #   
 Thursday, July 02, 2009

Identity Metasystem Interoperability Version 1.0

The IMI spec is now approved. Grats!

Read more here and get the spec here.


IdentityModel
Thursday, July 02, 2009 7:25:29 AM UTC  #   
 Wednesday, June 17, 2009

Updated Starter STS

I just uploaded a minor update to the Starter STS sample to codeplex. This release adds more options for realm checking (see the allowKnownRealmsOnly config switch) as well as Information Card issuance.

As always – feedback is welcome!

http://startersts.codeplex.com


IdentityModel | ASP.NET | WCF
Wednesday, June 17, 2009 7:21:52 AM UTC  #   
 Friday, June 05, 2009

.NET Access Control Service Talk from Troopers09

I did a talk about the ACS in May. It was interesting to present that topic to a non-Developer, non-Microsoft minded audience.

Here’s the outcome:
http://www.viddler.com/explore/TROOPERS/videos/1/

_


IdentityModel
Friday, June 05, 2009 3:45:53 AM UTC  #   
 Thursday, June 04, 2009

Writing Custom Attribute Stores for Geneva Server (B2)

This document appeard on the connect site. Interesting.

_


IdentityModel
Thursday, June 04, 2009 6:31:37 AM UTC  #   
 Thursday, May 28, 2009

Geneva Framework Quick Tip: How to access Configuration

Remember that Geneva framework is a framework – all the nice integration into WCF and ASP.NET is built on top of a public API. This also means that you can use Geneva framework for integration in arbitrary hosts and environments.

One thing you most often need is access to the Geneva framework configuration (microsoft.identityModel section) from code – and again this is very easy:

ServiceConfiguration config = new
  ServiceConfiguration(ServiceConfiguration.DefaultServiceName);

HTH


IdentityModel
Thursday, May 28, 2009 5:21:31 AM UTC  #   

Geneva Framework Quick Tip: Hosting a Security Token Service

The idea of the security token service infrastructure in Geneva is, that it is completely host agnostic. The STS itself expects a RequestSecurityToken and returns a RequestSecurityTokenResponse. It is the job of the host to translate some protocol back and forth to this technology independent representation.

The key to STS hosting (and that’s btw what the WCF WSTrustServiceContract class or the FederatedPassiveSignin web control does) is to create a token service from configuration. And this couldn’t be easier ;)

var config = new TokenServiceConfiguration();
var sts = config.CreateSecurityTokenService();

var rstr = sts.Issue(principal, rst);

 

HTH


IdentityModel
Thursday, May 28, 2009 4:50:57 AM UTC  #   
 Wednesday, May 27, 2009

Starter STS Screencasts

All two screencasts about the starter STS sample are online now:


IdentityModel
Wednesday, May 27, 2009 1:54:12 PM UTC  #   
 Tuesday, May 26, 2009

Thinktecture Security Token Service Starter Kit

I am happy to announce the “Thinktecture STS Starter Kit” sample. The STS starter kit is a compact, easy to use identity provider that is completely based on the ASP.NET provider infrastructure. It is built using the Geneva framework Beta 2 bits and is a self contained web site with passive and active endpoints (Christian has some screenshots).

The motivation behind writing this sample is twofold. First, writing a custom STS from scratch is not terribly hard – but it is also not a trivial task. In addition the full featured Geneva Server product may not fit your requirements (e.g. because your users are not stored in Active Directory). So a lot of people I spoke to mentioned that it would be nice to have a simple STS that uses membership, roles and profile and that is easy to setup and get going.

The other reason is that starter STS is not terribly complex and could be used as a learning tool on how to write custom token services. You could e.g. replace the provider plumbing with your own libraries while you go.

Some features:

  • active and passive security token service
  • supports WS-Federation, WS-Trust 1.3 (message and mixed) and SAML 1.1/2.0 tokens
  • based on the standard membership, roles and profile provider infrastructure
  • membership provider is used to authenticate users and to provide a name and email claim
  • role provider is used for authorization in the web front-end and to provider role claims
  • profile provider is used to allow users to supply profile information which gets turned into claims
  • easy administration of the provider features using the IIS7 manager
  • easy configuration – you don’t have to deal with Geneva or WCF settings directly
  • control over security policy (SSL, encryption, SOAP security)
  • dynamic web UI to allow users to maintain their profile data
  • automatic generation of a WS-Federation metadata document to allow RPs to federate using e.g. FedUtil

To make it even easier for you to setup and start using the STS, I have recorded a screencast that walks you through the installation and setup process. In the following posts I will focus more on on some of the feature areas and explain how they are used and implemented. Have fun!

Download STS Starter Kit Sample.
Download Setup&Overview Screencast


IdentityModel
Tuesday, May 26, 2009 5:54:25 AM UTC  #   
 Sunday, May 24, 2009

Use Geneva Session Management for your own needs

Geneva Framework is a Framework is a Framework.

One part of that framework is the SessionAuthenticationModule for ASP.NET. In all the typical samples this is used to convert an incoming SAML token to a cookie to establish an authentication session.

A closer look reveals, that the purpose of this module is actually serializing SessionSecurityTokens into cookies. A SessionSecurityToken in turn is a container for an IClaimsPrincipal and an additional SecurityToken (the so called bootstrap token).

This means that the SessionAuthenticationModule is a general module and API to serialize claims principals and security tokens into cookies. In addition there is an extensible architecture around how these cookies are layed out and protected. You can utilize this infrastructure whenever you need to serialize and round-trip an IClaimsPrincipal.

Where can this be useful? Let’s do this little walkthrough…

First use the Visual Studio Geneva templates to create a simple “Claims-aware ASP.Net WebSite”. This sample uses the ClaimsPrincipalHttpModule to create an IClaimsPrincipal from the standard forms authentication principal.

In the next step add a ClaimsAuthenticationManager to the web site and register it, e.g.:

public class Transformer : ClaimsAuthenticationManager
{
    public override IClaimsPrincipal Authenticate(string endpointUri, IClaimsPrincipal incomingPrincipal)
    {
        // expensive operation
        incomingPrincipal.Identities[0].Claims.Add(new
          Claim("http://claims/expensive", "expensive value"));

        return incomingPrincipal;

    }
}

The custom claims you are adding in the authentication manager might come from some remote data store and you probably want to avoid such a round-trip on every request. To optimize this, you could come up with some server-local caching strategy – or use the SessionAuthenticationModule to serialize the IClaimsPrincipal after transformation to a cookie. The module will then reconstruct the IClaimsPrincipal on subsequest requests and set it as the current principal for the ASP.NET application.

First add the session authentication module to the modules section in web.config – then add this code to the authentication manager:

private void SetSessionCookie(IClaimsPrincipal incomingPrincipal)
{
  SessionSecurityToken token = new SessionSecurityToken(incomingPrincipal);
  FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);
}

Call this method before you return the transformed principal back to Geneva.

Note: When your app is not running over SSL – you need to set the requireSsl setting for the cookie handler in web.config to false.


IdentityModel | ASP.NET
Sunday, May 24, 2009 2:04:32 PM UTC  #   
 Friday, May 22, 2009

Thinktecture WS-Federation Metadata Generator

Mr. Metadata strikes back! This time with a generator/wizard for WS-Federation Metadata language. This makes it very easy to create documents that can be consumed by Geneva Server or FedUtil.

More info here.


ASP.NET | WCF | IdentityModel
Friday, May 22, 2009 11:43:30 AM UTC  #   
 Monday, May 18, 2009

More Geneva Beta 2 Changes

Just came across this document. Interesting read.


IdentityModel
Monday, May 18, 2009 1:45:21 PM UTC  #   

Geneva Beta 2 Update: ClaimsPrincipalHttpModule

I am currently in the process of updating my Geneva code to Beta 2. There are some pretty substantial changes/additions in the new Beta – so I thought I’ll detail some of them while moving along. Today: ClaimsPrincipalHttpModule.

For a basic understanding what the module does, I recommend reading my initial post here.

Starting with Beta 2, ClaimsPrincipalHttpModule supports converting X509 client certificates to an IClaimsPrincipal. This is done by using the ctor of IClaimsIdentity that takes an X509Certificate2 which results in an authenticated identity with an authentication type set to “SSL/PCT”.

Now as always, certificate based authentication is a little different to e.g. username/password. In the strict sense a user is authenticated when you know “who he is”. For usernames/passwords authentication this means as soon as you have successfully validated the password against your data store (or put differently – as soon as the user provides a proof for his identity). Proofing identity in the certificate case basically means that the certificate is trusted and the client “knows” the corresponding private key. That’s why the ClaimsPrincipalHttpModule sets IsAuthenticated=true when the client certificate is valid.

Now Windows/IIS supports a number of certificate issuers and a user can potentially present a client cert to IIS which is “valid” but the client may still not be a valid/registered user in your system. This results (depending on your design) in different semantics for “IsAuthenticated” checks like Request.IsAuthenticated or <deny users=”?” />.

A better way would be to replace blanket authentication checks with checks for specific claims (like a “User” role or some permission).

HTH


IdentityModel | ASP.NET
Monday, May 18, 2009 6:23:27 AM UTC  #   
 Monday, May 11, 2009

Die Information Card Foundation DACH-Initiative

Mehr Infos hier

 

 


IdentityModel | Misc
Monday, May 11, 2009 2:21:01 PM UTC  #   
 Tuesday, April 07, 2009

Krise? Nein! „Service-Orientierung heute und morgen“: 5 Tage volle Power und praktisches Wissen

Sind Sie auch müde, ständig von „Krise“ und „Einschränkungen“ zu lesen? Sind Sie nicht jemand, der sich immer weiter entwickeln möchte und fit für die heutigen Problemstellungen aber auch vorbereitet für zukünftige Herausforderungen sein möchte? Wir haben da was für Sie…


Gemeinsam mit Referenten und Experten thinktecture präsentiert DevelopMentor fünf Tage voller Power, geballtem Wissen und praktischer Umsetzung mit dem „Service-Orientierung heute und morgen“-Kurs.


Dominick Baier und Christian Weyer zeigen Ihnen in gewohnt praxisorientierter Art und Weise sowohl Grundlagen und Konzepte als auch deren konkrete und pragmatische Umsetzung, alles basierend auf jahrelanger Projekterfahrung.
Erleben Sie wie Sie Service-Orientierung heute und morgen - gemischt mit dem zukunftsweisenden Themenkomplex Cloud Computing - auf Basis der Windows- und .NET –Plattform lokal und in der Cloud realisieren können. In Hands-on-Labs können Sie selbst die Ärmel hochkrempeln und gleich das Gelernte in Form von Code in Tatsachen umsetzen.


Nach diesen fünf Tagen werden Sie basierend auf diesen Themenbereichen die ersten Schritte in der Welt von Service-Orientierung alleine gehen können und vor allem vorbereitet sein für kommende Projektaufgaben:

  • Service-Orientierung
  • Cloud & Cloud Computing
  • Identitäts-Management & Claims-basierte Identität
  • Windows Communication Foundation (WCF)
  • Windows Workflow Foundation (WF)
  • Azure Services Plattform (mit Windows Azure und .NET Services)

Die folgende Auflistung gibt Ihnen einen detaillierteren Überblick über die behandelten Themen:

Tag 1

  • Service-Orientierung
  • WCF-Architektur
  • Design-by-Contract

Tag 2

  • WCF Instances, Concurrency & Session Management
  • WCF Security
  • WCF Hosting

Tag 3

  • WF Workflow Services
  • WCF REST
  • Azure-Services-Architektur

Tag 4

  • Windows Azure Development & Deployment
  • Windows Azure Storage
  • Identitäts-Management

Tag 5

  • .NET Services Access Control Service
  • .NET Services Service Bus
  • NET Services Workflow Service

Und hier noch die notwendigen Informationen für Ihre Planung:

Wann? 6.-10. Juli 2009
Wo? Häckers Kurhotel, Bad Ems
Wieviel? 3200,- € (inkl. Übernachtungen, Frühstück, Mittagessen und Abendessen)

Durchführender Veranstalter ist DevelopMentor.

 

Für Fragen, Wünsche oder Buchungsanfragen kontaktieren Sie bitte thinktecture oder DevelopMentor.

Vielen Dank.
ASP.NET | WCF | Work in Progress | IdentityModel | Conferences
Tuesday, April 07, 2009 12:02:31 PM UTC  #   

 Friday, April 03, 2009

PPID Information and Generation Examples

This article provides useful information on generating interoperable PPIDs.


IdentityModel
Friday, April 03, 2009 6:52:54 AM UTC  #   
 Thursday, April 02, 2009

Custom Principals in WCF with Geneva

WCF has an extensibility point to set your own IPrincipal implementation on Thread.CurrentPrincipal (I wrote about that here). Geneva uses this mechanism to set its IClaimsPrincipal (wrote about that here).

Since the standard “slot” for custom principals is already used by Geneva, it was unclear to me how to set your own IPrincipal after Geneva has done its work. With a little help from the Geneva team (thanks Jan) – I found a way that works.

You can replace the principal in a service authorization manager via the Properties collection on the authorization context. Voodoo.

class AuthorizationManager : IdentityModelServiceAuthorizationManager
{
    public override bool CheckAccess(OperationContext operationContext, ref Message message)
    {
        base.CheckAccess(operationContext, ref message);

        // action header to get to the request operation
        string action = operationContext.IncomingMessageHeaders.Action;

        // properties collection holds the principal that goes on Thread.CurrentPrincipal
        var properties = operationContext
                        .ServiceSecurityContext
                        .AuthorizationContext
                        .Properties;

        // retrieve current principal
        IClaimsPrincipal principal = properties["Principal"] as IClaimsPrincipal;
       
        // create custom principal
        var customPrincipal = new CustomClaimsPrincipal(principal, "some value");
       
        // set the custom principal
        properties["Principal"] = customPrincipal;
           
        return Authorize(action, customPrincipal);
    }

    private bool Authorize(string action, CustomClaimsPrincipal principal)
    {
        // do whatever authZ logic you have
        return true;
    }
}

public class CustomClaimsPrincipal : ClaimsPrincipal
{
    public CustomClaimsPrincipal(IClaimsPrincipal principal, string customValue)
      : base(principal)
    {
        CustomPropery = customValue;
    }

    public string CustomPropery { get; set; }
}

Afterwards register this class in the ServiceAuthorizationBehavior.

Be aware that this gets called on every request – so don’t put expensive operations in the custom principal creation code.


IdentityModel | WCF
Thursday, April 02, 2009 9:01:34 AM UTC  #   
 Sunday, March 29, 2009

Client Generated SAML Tokens to Interact with the Access Control Service

I recently wrote about generating SAML tokens at the client. Justin showed a similar approach at Mix to interact with the Access Control Service.


IdentityModel | WCF | ASP.NET
Sunday, March 29, 2009 5:34:35 AM UTC  #   
 Thursday, March 12, 2009

Geneva integration into ASP.NET

Geneva is integrated in ASP.NET/IIS using the standard IHttpModule extensibility mechanism. Geneva ships with three HTTP modules:

  • ClaimsPrincipalHttpModule (already wrote about it here).
  • WSFederationAuthenticationModule (implements WS-Federation authentication)
  • SessionAuthenticationModule (implements session authentication)

ClaimsPrincipalHttpModule is special – but the other two are built upon a framework for handling token based authentication in ASP.NET. To integrate into this framework, one has to derive from a base class called FederatedAuthenticationModuleBase. This implements the IHttpModule interface, subscribes to the AuthenticateRequest and EndRequest pipeline events and provides some helper methods. This base class drives the core logic of how a typical redirection and token based authentication works. For the protocol specific details, the derived class has to implement a bunch of abstract methods. This is how WS-Federation is implemented – other protocols could be realized in a similar fashion.

The core logic is as follows:

AuthenticateRequest

  • check if federated authentication is enabled
  • check if current request is a sign in request (abstract CanReadSignInRequest)
  • extract security token from request (abstract GetSecurityToken)
    • raise SecurityTokenReceived event
  • create IClaimsPrincipal from security token
    • raise SecurityTokenValidated event
  • set principal
  • create session security token
  • set session security token using the configured cookie handler
    • raise SessionSecurityTokenCreated event
  • raise SignedIn event
  • check for a return URL (abstract GetReturnUrlFromResponse)
    • do the redirect

EndRequest

  • check if federated authentication is enabled
  • if a 401 response is found, redirect to identity provider (abstract RedirectToIdentityProvider)

Now let’s have a close look what the two derived module do.

WSFederationAuthenticationModule
As stated earlier, this module deals with WS-Federation redirects and token parsing.

  • CanReadSigninRequest
    checks for the WS-Federation messages (wsignin1.0 / wsignoutcleanup1.0)
  • GetSecurityToken
    extracts the token from the STS response and uses the security token handler infrastructure to create a SecurityToken
  • GetReturnUrlFromResponse
    parses the WS-Fed context field for a return URL-
  • RedirectToIdentityProvider
    creates a SignInRequest message and redirects to the configured identity provider.

 

SessionAuthenticationModule
After the module implementing the authentication protocol has done its job, the base class creates a session token. This session token contains the original token issued from the STS (the bootstrap token) as well as a serialized version of the IClaimsPrincipal (after transformation via the ClaimsAuthenticationManager). This session token gets persisted by a cookie handler (typically into a HTTP cookie). The session authentication module uses this cookie to re-create the IClaimsPrincipal on each request.

Since the session token characteristics are a bit specific, the module builds upon the base framework and helper methods, but short-circuits the logic by overriding AuthenticateCore directly. This is what happens:

  • check if cookie is present (using the configured cookie handler)
  • recreate the SessionSecurityToken from the cookie (using the session security token handler)
  • raise SessionSecurityTokenReceived event
  • based on the outcome of the event either renew the cookie and/or set the principal
  • raise SignedIn event

HTH


ASP.NET | IdentityModel
Thursday, March 12, 2009 9:21:38 PM UTC  #   

Geneva integration into WCF

Having done quite a bit of WCF customization myself, it is fun to see how Geneva framework wires itself up into the WCF runtime.

The high-level goals are as follows:

  • route the token provisioning, serialization and authentication through the Geneva pipeline
  • make an IClaimsPrincipal available on the service side
  • allow setting issued tokens directly on a ChannelFactory

On the service side this is achieved by passing in a ServiceHost instance into FederatedServiceCredentials.ConfigureHost(). What does exactly happen inside that call?

  • replace the standard WCF ServiceCredential with a FederatedServiceCredential
    • the service credential drives the creation of a SecurityTokenManager (in this case the FederatedSecurityTokenManager)
    • this in turn creates the token provider, serializer and authenticator. In Geneva all three functionalities are inside a SecurityTokenHandler.
    • Geneva’s token manager dispatches the incoming requests to the corresponding methods of the token handler depending on the incoming token type
  • set the service certificate
    • either by copying the standard service certificate specified in the ServiceCredential.
    • or by replacing the existing one with the certificate specified in the <microsoft.IdentityModel /> configuration section
  • create token resolvers for
    • the service certificate
    • issuer certificates (if the WCF knownIssuers configuration element is set)
  • set a ClaimsAuthenticationManager (either a pass-through one, or the one specified in code/config)
  • set the PrincipalPermissionMode to Custom. This is necessary to populate Thread.CurrentPrincipal with an IClaimsPrincipal.
  • set the service authorization manager.
    • service authorization managers drive the creation of authorization policies.
    • an authorization policy in turn can parse the WCF internal claims and set Thread.CurrentPrincipal. Persisting the bootstrap token also happens here.
    • to make this all work, Geneva has its own service authorization manager (IdentityModelServiceAuthorizationManager) and its own authorization policy (Microsoft.IdentityModel.Tokens.AuthorizationPolicy).

 

On the client side things are much simpler. The main purpose of the Geneva client side plumbing is to allow more direct interaction with tokens. The standard WCF issued token client credential assumes you want to implicitly acquire a token from a WS-Trust token service.

Token provisioning is driven by so called SecurityTokenParameters. Whereas the WCF built-in IssuedSecurityTokenParameters only allow specifying the details of the token issuer, the Geneva FederatedClientCredentialsParameters instead allows setting a pre-acquired token directly.

So when you call FederatedClientCredentials.ConfigureChannelFactory<T> all that is happening is, that the standard WCF ClientCredentials get replaced by the FederatedClientCredentials class. This creates a FederatedClientCredentialsSecurityTokenManager which in turn instantiates the token serializer (via the security token handlers) and a token provider that is aware of FederatedClientCredentialsParameters.

To actually set the token on a channel, you call one of the extension methods for ChannelFactory<T>. They can be found in Microsoft.IdentityModel.Protocols.WSTrust.ChannelFactoryOperations. These extension methods take the token you pass in, create the token parameters and add them to the token parameters collection of the channel.

HTH


WCF | IdentityModel
Thursday, March 12, 2009 9:56:01 AM UTC  #   
 Tuesday, March 10, 2009

Using SAML as a Client Credential Type in WCF (with Geneva)

Disclaimer
For the motivation for this article please read this here first. I am not advocating the use of client generated SAML tokens in general, and I also know that there is not much point in the client generating claims for a service. This whole article is about replacing the UserName token with a SAML token in situations where you need extensibility points that a UserName tokens cannot give you.

As I said in my previous post, SAML is an extensible and flexible token type - but not very accessible in plain WCF. Geneva abstracts the creation and consumption of tokens in so called token handlers. All you need is a description of the token that you want to generate and then you feed this description into the appropriate token handler. I wrote an article about the token generation pipeline in Geneva here.

Even better, Geneva has some client side plumbing for WCF that lets you use the generated token for service calls in a quite straightforward fashion.

So the simple scenario is this: the client credential consists of three pieces: username, password and a customer ID (think e.g. of multi-tenant apps). The service receiving this credential could be a normal WCF service or a STS that issues tokens based on the client credential. For future extensibility a general version of this would be a credential with a user name and an unlimited number of properties (e.g. password, customer ID etc.). In a SAML token this would map to the name identifier and a number of attributes.

Client
Using Geneva you can generate a SAML token like this:

public static class ClientToken
{
  private const string _claimsUri = http://www.leastprivilege.com/claims/;

  public static SamlSecurityToken Create(string subjectName, Dictionary<string, string> properties)
  {
      ClaimsIdentity id = new ClaimsIdentity(
          from item in properties
          select new Claim(_claimsUri + item.Key, item.Value));
      id.Claims.Add(new Claim(WSIdentityConstants.ClaimTypes.NameIdentifier, subjectName));

      var description = new SecurityTokenDescriptor
      {
          Subject = id,
          TokenIssuerName = "http://self"
      };

      var handler = new Saml11SecurityTokenHandler(new SamlSecurityTokenRequirement());
      return (SamlSecurityToken)handler.CreateToken(description);
  }
}

After creating the token you can use the Geneva extension methods for ChannelFactory<T> to set the token as a client credential:

static void Main(string[] args)
{
  var props = new Dictionary<string, string>
  {
      { "password", "secret" },
      { "customerId", "42" }
  };

  var token = ClientToken.Create("dominick", props);
  var factory = new ChannelFactory<IServiceClientChannel>("*");
       
  FederatedClientCredentials.ConfigureChannelFactory<IServiceClientChannel>(factory);
  var proxy = factory.CreateChannelWithIssuedToken<IServiceClientChannel>(token);

  proxy.Operation("foo");
  proxy.Close();
}

Service
On the service side you need a corresponding token handler that “understands” the semantics of the SAML token. Geneva has a built-in handler for SAML tokens but it does not know how to authenticate the client based on the values of certain SAML attributes. Furthermore you need to make a decision which of the incoming attributes should become part of the claims identity in the service. Maybe you don’t want sensitive information like the password to flow to the service operations (maybe you want exactly that). Other customizations to the standard behavior would be to ignore audience URIs as well as signatures (since our client tokens won’t have them).

By deriving from the built-in token handler you can drive this logic while letting the base class do all the heavy lifting of token serialization and parsing:

public abstract class ClientSaml11SecurityTokenHandlerBase : Saml11SecurityTokenHandler
{
  // disable audience URI checking
  public ClientSaml11SecurityTokenHandlerBase()
      : base(new SamlSecurityTokenRequirement { AudienceUriMode = AudienceUriMode.Never })
  { }

  // extensibility point for authentication and claims filtering
  protected abstract bool ValidateUser(
      string subjectName, Dictionary<string, string> properties, ref List<string> claimsList);

  // override signature handling
  public override SecurityToken ReadToken(XmlReader reader)
  {
    Saml11Assertion assertion = this.ReadAssertion(reader);
    return new SamlSecurityToken(assertion);
  }

  public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
  {
    // call base class for token validation and serialization
    var ids = base.ValidateToken(token);
    var id = ids[0];

    // retrieve client name
    string subjectName = id.Claims.Where(
        claim => claim.ClaimType == WSIdentityConstants.ClaimTypes.NameIdentifier).First().Value;
        
    // copy attributes to dictionary
    var properties = new Dictionary<string, string>();
    id.Claims.ToList().ForEach(
        claim => properties.Add(claim.ClaimType, claim.Value));

    // call authentication and filtering logic
    var claimsToKeep = new List<string>();
    if (ValidateUser(subjectName, properties, ref claimsToKeep))
    {
      ClaimsIdentity identity = new ClaimsIdentity("ClientSAML");

      // add client name
      identity.Claims.Add(new Claim(
        WSIdentityConstants.ClaimTypes.Name, subjectName, ClaimValueTypes.String, "LOCAL"));


      // copy "allowed" attributes
      claimsToKeep.ForEach(claimType =>
        {
          string value = id.Claims.Where(claim => claim.ClaimType == claimType).FirstOrDefault().Value;
          if (!string.IsNullOrEmpty(value))
          {
            identity.Claims.Add(new Claim(claimType, value, ClaimValueTypes.String, "LOCAL"));
          }
        });

        return new ClaimsIdentityCollection(identity);
      }
        else
        {
            throw new SecurityTokenValidationException();
        }
    }
}

The authentication logic and filtering could be implemented like this:

class ClientSaml11SecurityTokenHandler : ClientSaml11SecurityTokenHandlerBase
{
    protected override bool ValidateUser(
      string subjectName, Dictionary<string, string> properties, ref List<string> claimsList)
    {
        string password = properties[_passwordClaimType];

        // sample password check – don’t just copy&paste this code ;)
        if (subjectName != password)
        {
            return false;
        }

        claimsList.Add(_customerIdClaimType);
        return true;
    }
}

After wiring up the new token handler in the WCF service you get access to the claims in the operation via IClaimsPrincipal as usual.

Configuration
The last step deals with setting up the security parameters on the binding. Since the client SAML token is much like a UserName token on steroids, we choose similar security configurations (and make the same security guarantees). You can either use message security where the client token gets encrypted with the service certificate – or mixed mode security where the transport is secured using SSL.

For mixed mode security you can use the IssuedTokenOverTransport authentication mode. The custom binding looks like this:

<customBinding>
  <
binding name="BearerTokenOverTransport">
    <
security authenticationMode="IssuedTokenOverTransport">
      <
issuedTokenParameters
        
tokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"
         
keyType="BearerKey" />
    </
security>
    <
textMessageEncoding />
    <
httpsTransport />
  </
binding>
</
customBinding>

For message security, there is no built-in binding element helper – you have to construct it via code:

public static SecurityBindingElement CreateClientTokenForCertificateBindingElement()
{
  // protection token
  var element = new SymmetricSecurityBindingElement(
      new X509SecurityTokenParameters(
          X509KeyIdentifierClauseType.Thumbprint, 
          SecurityTokenInclusionMode.Never));

  // client token
  var parameters = new IssuedSecurityTokenParameters(
      Saml11SecurityTokenHandler.OasisWssSamlTokenProfile11,
      new EndpointAddress(http://self),
      new BasicHttpBinding());
  parameters.KeyType = SecurityKeyType.BearerKey;
  parameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;

  element.EndpointSupportingTokenParameters.SignedEncrypted.Add(parameters);
  element.MessageSecurityVersion =
    MessageSecurityVersion.WSSecurity11WSTrust13
                           WSSecureConversation13
                           WSSecurityPolicy12BasicSecurityProfile10;

  return element;
}

 

You can then use this helper to construct a custom binding (see the download for the complete code).

That’s it. HTH

ClientSamlCredential.zip (450.94 KB)

 


IdentityModel | WCF
Tuesday, March 10, 2009 6:24:52 AM UTC  #   
 Monday, March 09, 2009

Custom WCF Credential Types

Every once in a while the question comes up how to extend WCF with custom credential types. It turns out that most of the time people don’t really want to invent custom tokens or credential types, but rather want to extend username/password style of credentials (e.g. username/password/customer ID). Unfortunately the UserName token does not support this type of extensibility but there are several options to accomplish this:

  • If your extensibility requirements are very simple you could try to encode all the information into the username and password fields of a UserName credential. You’d need some extra plumbing on the service side (UserNamePasswordValidator, custom IPrincipal) to decode the information again and provide normalized user information.
  • You could use SOAP headers to transmit the additional information. This has the potential to pollute your business logic with security plumbing and needs some wrapping. There are also some gotchas around adding headers on the fly, as well as protecting them.
  • You could write a full fledged custom credential that supports the extensibility you need. Unfortunately this is not the best documented area of WCF and you are mostly on your own. The WCF credential infrastructure is extremely flexible – but I wouldn’t call it an extensibility point – but rather a replacement point. You end up replacing a number of classes on the service and client side to make this happen (see here for an overview). I did that for a username/password/namevalue credential and it wasn’t a pleasant experience.
  • You could use a standard token type in WCF that already supports all the extensibility needs you might have – e.g. SAML. The problem here is that SAML and issued tokens are not very accessible through plain WCF – but Geneva makes it much easier to use them - even without a security token service. That’s the option I am going to look at in the next post.

WCF | IdentityModel
Monday, March 09, 2009 9:30:20 AM UTC  #   
 Friday, February 27, 2009

Setting Key Identifiers in Geneva

Keys used in tokens or RSTRs need to be identified somehow – common ways to do this is to use a thumbprint, a serial number or the subject key identifier.

A “Geneva” based token service will use the combination of issuer name and certificate serial number by default. This is usually fine, but you may need to change that because of interop scenarios. Metro based web services e.g. prefer the subject key identifier method.

Took me some time to figure it out – so maybe this info is useful to someone.

There are two key identifiers you may want to modify – the signing and the encrypting key. These are represented in “Geneva” using the SigningCredentials and EncryptingCredentials classes respectively. The signing credentials are supplied in the SecurityTokenServiceConfiguration whereas the encrypting credentials are specified in the GetScope method. On these classes you can set the key identifier method using the SecurityKeyIdentifier property or the constructor. You can use the following code to create a subject key identifier clause for X509 certificates:

var ski = new SecurityKeyIdentifier(
            new SecurityKeyIdentifierClause[]
            {
                new X509SecurityToken(cert).CreateKeyIdentifierClause<X509SubjectKeyIdentifierClause>()
            });

To see what other key identifier types are available, have a look at the inheritance hierarchy of the base class System.IdentityModel.Tokens.SecurityKeyIdentifierClause.

HTH


IdentityModel
Friday, February 27, 2009 9:33:49 AM UTC  #   
 Tuesday, February 10, 2009

Host Headers, SSL and WCF Metadata

One of my web servers here has a pretty common setup – a Windows machine name and a (different) DNS name (in this case dynamic DNS – but doesn’t matter). IIS has a single web site with bindings for HTTP and HTTPS. The common name of the SSL certificate matches the public DNS name. Everything looks good.

The server also hosts some WCF services and I noticed that the imports and endpoint addresses in the WSDL point to the machine name and not to the DNS name. No big deal – simply set the host header for the site via the IIS GUI and I am done. That’s what I thought at least.

And sure enough, after the configuration change my WSDL was correct and used the name configured in the host header.

Some weeks later I added some more WCF endpoints to the machine, this time I was using SSL – including an SSL WSDL/MEX endpoint. After some weird error messages I re-inspected the WSDL and everything looked fine - until I hit the WSDL document in the browser using SSL. Again imports and endpoint addresses were pointing to the machine name. What’s going on here?

After some googling I found articles about something I totally forgot about: SSL host headers. Since IIS 6 you can also set host headers for SSL site bindings. Since this option is not available via the GUI I kind of “missed” it. These two articles show the necessary steps for IIS6 and IIS7.

My applicationHost.config now looks like this for my site:

<bindings>
  <
binding protocol="http"
          
bindingInformation="*:80:www.mypublicname.com" />
  <
binding protocol="https"
          
bindingInformation="*:443:www.mypublicname.com" />
</
bindings>

HTH

(Rich: marked as answer)


WCF | IdentityModel
Tuesday, February 10, 2009 9:34:56 AM UTC  #   
 Wednesday, January 07, 2009

Live ID and Information Cards

I while ago I wrote that there is an experimental version of the Live ID login page that makes use of Information Cards linked to your Live ID account. Unfortunately this login form was only used for very specific services (hotmail only at that time IIRC).

I am happy to see that more and more sites these days use the InfoCard enabled sign in page – and more importantly - sites I actually use (e.g. MSDN, Live Mesh, Connect…). Way to go!


IdentityModel | Misc
Wednesday, January 07, 2009 5:30:19 AM UTC  #   
 Sunday, December 28, 2008

Federating with Live ID (using the Access Control Service)

There are already a number of ways today how you can federate with the Live ID service (e.g. using the Live ID SDK, OpenID or WS-Federation). Another option would be to use the Access Control Service. I can see a bunch of reasons why this may be compelling:

  • Live ID is pre-configured in the ACS. You don’t need any extra configuration steps to register your site with Live ID. It just works.
  • You can use the ACS rules engine to transform the Live ID claims to your application claims.
  • A Live ID is a low barrier entry for customers and partners to the ACS. In case they can’t federate “properly” (e.g. using Geneva or the Services Connector).

Generally, this is a good example of how the ACS can simplify security management and configuration in your application endpoints. You can simply add another authentication method to your application without needing to change anything substantial. All the heavy lifting like crypto, trust and claims configuration is done in the ACS.

This walkthrough uses the PDC bits of the ACS and Geneva framework to access Live ID logins in an ASP.NET app. This is all beta software and details are subject to change!

Step 1: Setting up ASP.NET to use the ACS
First you have to enable Geneva in ASP.NET. This involves adding the WS-Federation authentication module as well as the session authentication module. You also have to setup the service certificate and allowed audience URI. Nothing special here.

Very similar to the WCF scenario I described here, you also have to check the token and SAML issuer. For the issuer check you use the regular issuer name registry as described in my post. For the SAML issuer check you can use an extensibility point in the FAM – simply add this code to global.asax:

void WSFederationAuthenticationModule_SecurityTokenValidated(
  object sender, SecurityTokenValidatedEventArgs e)
{
    e.ClaimsPrincipal.DemandClaim(
      Microsoft.IdentityModel.Claims.ClaimTypes.SamlIssuerName,
      "http://accesscontrol.windows.net/solutionName");
}

These two customizations establish a trust relationship with your ACS. You can now start receiving tokens.

Step 2: Registering the application with the ACS
Again nothing special here. You have to create a scope for the application in your ACS as well as configure the the encrypting certificate to match the certificate you configured in step 1.

The interesting part is the rule definition. When you add a new rule, you can now select the Live ID as an input claim and map it to whatever output claim you want. Examples would be to map it to a group (which in turn can map to permissions) or to tunnel the ID to the relying party (either as-is or as a different claim). The following screenshot shows a rule that transforms the Live ID to a standard name claim:

Step 3: Triggering Live ID login
The last step is to trigger the Live ID handshake in your app. The ACS’ endpoint for federation with Live ID is

https://accesscontrol.windows.net/passivests/{solutionName}/LiveFederation.aspx

In the query string for this endpoint you have to provide the scope and the identity provider name (plus an optional reply-to address), like this:

wa=wsignin1.0&wtrealm={scope}&wreply={replyTo}&whr={identityProvider}

Unfortunately Geneva framework currently does not support the whr parameter directly, which means you have to construct the URL manually. Geneva’s SignInRequest class can help here. The following code does the redirect to the ACS and Live ID:

protected void _lnkLiveLogin_Click(object sender, EventArgs e)
{
    string homeRealm = "http://login.live.com";
    string scope = "http://myrp/default.aspx";
    string acs = "https://accesscontrol.windows.net/passivests/{solutionName}/LiveFederation.aspx";

    var request = new SignInRequestMessage(new Uri(acs), scope);
    request.Parameters.Add("whr", homeRealm);

    Response.Redirect(request.RequestUrl);
}

After all redirects have occurred you end up back in your application with a populated IClaimsPrincipal that contains the claims that you configured in your ACS scope. Adding new identity providers would be a matter of registering them with your ACS and changing the value of the home realm parameter.

 


ASP.NET | IdentityModel | WCF
Sunday, December 28, 2008 4:25:49 PM UTC  #   
 Friday, December 26, 2008

Display Tokens & Geneva

What are display tokens? In short: They allow an STS to pass some or all claims back to the client in a way that the client can read them. This differs from the “real” claims which are part of the security token and are encrypted for the relying party. A popular example of an application that consumes display claims is the CardSpace identity selector that allows you to preview the claims before they get send to the RP.

Look here in section 4.3.6 for the technical specification and here for a good discussion of use and abuse of display tokens.

In Geneva, display tokens are represented by the DisplayToken class (which is a container for DisplayClaims). The SecurityTokenService class has an overridable method called GetDisplayToken in which the DisplayToken gets constructed to be put into the RSTR (see also here). This method internally calls GetDisplayClaimsForSubject on the default ClaimsMapper that is configured on the SecurityTokenServiceConfiguration of your STS. This default claims mapper simply takes all claims found in the subject and emits them as display claims. For some standard claims the mapper already knows the display name and description – the others are emitted without further descriptions.

It seems that in the future you want to extend the ClaimsMapper class for your own display token work – for now the class does not seem to be ready for that. Another behavior of the current Geneva bits is, that display claims are enabled by default – that means if your user requests them (more on that later) all claims will be emitted in clear to the user. This may or may not be what you want. In future builds of Geneva, the display token feature will be opt-in.

But if you are building an STS with the current bits – you almost certainly want to take control over display token generation, because e.g.

  • maybe you emit claims that the user should not be able to see.
  • if you want to emit a display token and you use non-standard claims, you want to provide display names and descriptions.

 

Generating a display token
Currently the easiest way to do this is to override the above mentioned GetDisplayToken method in your STS, e.g.:

protected override DisplayToken GetDisplayToken(
  string requestedDisplayTokenLanguage, IClaimsIdentity subject)
{
    var displayClaims = new List<DisplayClaim>
    {
        new DisplayClaim(WSIdentityConstants.ClaimTypes.GivenName, "FirstName", "First Name",
            subject.GetClaimValue(WSIdentityConstants.ClaimTypes.GivenName)),
        new DisplayClaim(WSIdentityConstants.ClaimTypes.Surname, "LastName", "Last Name",
            subject.GetClaimValue(WSIdentityConstants.ClaimTypes.Surname)),
        new DisplayClaim(WSIdentityConstants.ClaimTypes.Name, "Name", "Name",
            subject.GetClaimValue(WSIdentityConstants.ClaimTypes.Email)),
    };


    return new DisplayToken(requestedDisplayTokenLanguage, displayClaims);
}

(of course – if you want to localize the claims – you should honor the requestDisplayTokenLanguage parameter)

 

Requesting and consuming a display token
The above GetDisplayToken method gets only called if a display token is requested. This is done by adding a <RequestDisplayToken /> element to the RST – either by adding this element to the additional request parameters collection on the binding or by explicitly setting the DisplayTokenLanguage property on the RequestSecurityToken class (e.g. when requesting a token using WSTrustClient).

The returned display token can be found in the RSTR on the RequestedDisplayToken property. The following code snippet shows both the request and the consumption (some details omitted):

WSTrustClient client = new WSTrustClient(
    GetStsBinding(),
    GetStsEndpoint(),
    TrustVersion.WSTrust13,
    GetStsCredentials());

RequestSecurityToken rst = new RequestSecurityToken();
rst.RequestType = WSTrust13Constants.RequestTypes.Issue;
rst.AppliesTo = new EndpointAddress(rp);
rst.TokenType = Saml11SecurityTokenHandler.OasisWssSamlTokenProfile11;
rst.DisplayTokenLanguage = "en";

RequestSecurityTokenResponse rstr;
client.Issue(rst, out rstr);

foreach (var displayClaim in rstr.RequestedDisplayToken.DisplayClaims)
{
    Console.WriteLine(string.Format("{0}: {1} ({2})",
        displayClaim.DisplayTag,
       
displayClaim.Description,
        displayClaim.DisplayValue));
}

 

HTH
ASP.NET | WCF | IdentityModel
Friday, December 26, 2008 10:44:36 AM UTC  #   
 Thursday, December 25, 2008

LeastPrivilege.IdentityModel2 Preview

I thought as a little X-Mas present – I just zip up the current version of my IdentityModel2 solution and make it available for download here. It is barely tested (besides my own use cases which were the reason why I wrote most of the code in the first place) so I thought I’d call it CTP1 and would appreciate your feedback ;)

What’s inside?

  • a bunch of extension methods (for IPrincipal, IClaimsPrincipal, IClaimsIdentity, RSACryptoServiceProvider…)
  • a custom configuration section for easy certificate loading
  • a simple claims viewer for console, WinForms and ASP.NET
  • helpers for federating with the Access Control Service

Merry Xmas!

 


ASP.NET | IdentityModel | WCF
Thursday, December 25, 2008 7:34:17 AM UTC  #   
 Tuesday, December 16, 2008

Final Release of InfoCardSelector on Codeplex

For a while I had some updates to the InfoCardSelector ASP.NET control sitting here – thanks to altair we made some minor modifications, nothing critical. I finally uploaded them to Codeplex.

However – this will be the last release of the control. It works as expected and will be soon superseded by the InfoCard control in Geneva.

Have fun!


ASP.NET | IdentityModel
Tuesday, December 16, 2008 7:14:11 AM UTC  #   
 Thursday, December 11, 2008

Federating with the .NET Access Control Service

In my previous post I showed how to migrate the .NET Access Control Service SDK “CardSpaceCalculator” sample to Geneva Framework. The way this sample is structured, it allows to authenticate with the InfoCard that is associated with your solution account to access the service via the ACS.

While this is nice for learning purposes – it limits you to this single account. In reality you want that your customers/partners federate with your ACS so you can give them access to your services. The ACS will then broker the trust and act as a rules-based claims generation engine.

It turns out that when you have the sample up and running, you are already very close to this scenario. How could this work in practice? This walkthrough basically documents the steps I did to integrate a custom STS written with the Geneva framework. This assumes you already have a working version of the SDK sample as well as a STS.

 

Step 1: Registering the partner’s STS at your Access Control Service
First you have to register the STS. This is done via the .NET Services portal. Go to your scope in advanced mode and click the Identity Issuers link. You need to specify three things:

  • A display name for the STS. This name is also used for defining rules later on
  • The STS URI
  • The STS token signing certificate

Step 2: Adding your Access Control Service to the partner’s STS known list of relying parties
The partner’s STS now has to be configured to issue tokens for the ACS. For this purpose the partner needs to know the value of the AppliesTo header field (the RP identitfier) and the public key of the ACS.

The AppliesTo header will be: “http://accesscontrol.windows.net/sts/<yoursolution>/issued_for_certificate”.

The encrypting certificate is not so obvious. It is basically the certificate that you can pull from https://accesscontrol.windows.net – but automatic browser redirects make that kinda hard (I forked mine from the custom IssuerNameRegistry I showed in my last post). You can also use this code here to download the cert.

Step 3: Updating client configuration
The next step is to update the client’s configuration to request a token from the STS before requesting the token from the ACS. This is very simple – when you use the SDK sample you will see a WCF custom binding with the name http://accesscontrol.windows.net/sts/<solutionname>/issued_for_certificate. Since this binding is configured for issued tokens but no STS is specified the CardSpace identity selector will pop up. When the partner STS issues cards, the user now only has to select the right card.

To configure a specific STS you have to add an <issuer> and <issuerMetadata> element to the binding that points to the partner’s STS WS-Trust endpoint (along with the right binding to authenticate with the STS). That’s it.

Step 4: Defining rules for the partner in the ACS
Now technically everything is set up. The last step would be to define rules in your ACS for the partner accounts. Let’s say the partner STS includes a “department” claim in the token. Now everybody in the department “Research” should have access to the “Add” operation of the calculator. The corresponding rule would look like this in the portal:

Another cool feature of the ACS rules engine is to copy input to output claims. This allows to tunnel claims from the partner’s STS to your service. You accomplish this by setting the “copy input value” option in the rules dialog.

I’d also recommend checking out Justin’s drill down talk from PDC to learn about the forward chaining capabilities of the rules engine.

HTH


ASP.NET | IdentityModel | WCF
Thursday, December 11, 2008 7:46:34 PM UTC  #   

Downloading the Certificate from an SSL Site

Sometimes this is very useful– you point the below code to a server and get the configured SSL certificate in return. After that you could import the cert into the local store or save it as a file (via the RawData property).

public static X509Certificate2 DownloadSslCertificate(string machinename, int port)
{
    using (TcpClient client = new TcpClient())
    {
        client.Connect(machinename, port);

        SslStream ssl = new SslStream(client.GetStream());
        ssl.AuthenticateAsClient(machinename);

       
        return new X509Certificate2(ssl.RemoteCertificate);
    }
}

HTH


Misc | IdentityModel
Thursday, December 11, 2008 7:30:47 PM UTC  #   

Using the .NET Access Control Service with Geneva

If you haven’t checked out the .NET Access Control Service yet – I can highly recommend it!

Justin did two talks about it at PDC:

In the 2nd talk Justin showed how to use and process claims coming from the ACS rules engine in your own services. You can find this code in the “CardSpace Calculator” sample in the ACS SDK.

The sample uses the “old” WCF plumbing to process tokens and create claims based on that. I wanted to find out what has to be done to migrate the sample to use Geneva.

First let’s have a look at what you want to accomplish with such a scenario:

  • your clients live in a different trust domain as your service
  • to federate these two domains, you do the following
    • register your client’s identity provider (Live ID, Geneva Server/Framework, other WS-Trust 1.3 compat STS) at the ACS
    • your client obtains a token from the ACS (by sending their identity token)
    • this token is used to authenticate with your service
    • your service accepts tokens from the ACS and uses their claims for identity related work

For your service this means the following:

  • accept tokens that are signed by the ACS
  • make sure the issuer of that token is your personal instance of the ACS (http://accesscontrol.windows.net/yoursolution)

In Geneva terms this boils down to the following pieces of plumbing:

  • issuer name registry that knows about the ACS issuer certificate
  • security token handler that check the SAML issuer name

Issuer Registry
There are two ways to accomplish this. Either you use the standard ConfigurationBasedIssuerNameRegistry and add the ACS issuer thumbprint to it:

<microsoft.identityModel>
  <
issuerNameRegistry type="…ConfigurationBasedIssuerNameRegistry">
    <
trustedIssuers>
      <
add name=http://accesscontrol.windows.net
          
thumbprint="416E6FA5D982B096931FBF42C4A3DCD608856C95" />
    </
trustedIssuers>
  </
issuerNameRegistry>
</
microsoft.identityModel>

Or you write a custom registry that has the ACS issuer baked in:

class AccessControlServiceIssuerRegistry : IssuerNameRegistry
{
  public override string GetIssuerName(SecurityToken securityToken)
  {
      X509SecurityToken token = securityToken as X509SecurityToken;
      if (token == null)
      {
        throw new SecurityTokenException("Token is not a X509 Security Token");
      }

      var cert = token.Certificate;
      if (cert.Thumbprint.Equals("416E6FA5D982B096931FBF42C4A3DCD608856C95", StringComparison.OrdinalIgnoreCase))
      {
        return "http://accesscontrol.windows.net";
      }

      throw new SecurityTokenException("Token not issued by access control service");
  }
}

Security Token Handler
Once you trust the issuer, you also have to make sure that the token got issued by your personal instance of the ACS. This is done by checking the SAML issuer name information in the token. This is the job of a custom security token handler – you can simply derive from the existing Saml11SecurityTokenHandler and inject this logic in the ValidateToken method.

class AccessControlServiceSaml11SecurityTokenHandler : Saml11SecurityTokenHandler
{
    string _solution;

    public AccessControlServiceSaml11SecurityTokenHandler(string solution)
      : base()
    {
        _solution = solution;
    }

    public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
    {
        var identities = base.ValidateToken(token);

        identities[0].DemandClaim(
            ClaimTypes.SamlIssuerName,
            "http://accesscontrol.windows.net/" + _solution);

        return identities;
    }
}

Bringing the pieces together
You can now wire up the two custom components using the FederatedServiceCredentials class like this:

ServiceHost host = new ServiceHost(typeof(CalculatorService));

var handlers = new SecurityTokenHandlerCollection();
handlers.Add(new AccessControlServiceSaml11SecurityTokenHandler("leastprivilege"));

FederatedServiceCredentials.ConfigureServiceHost(
    host,
    handlers,
    new AccessControlServiceIssuerRegistry(),
    TimeSpan.FromMinutes(5));

FederatedServiceCredentials.ConfigureServiceHost(host);
host.Open();

 

Another option would be to use the configuration file – but in this case we somehow have to transfer the solution name to the security token handler. Geneva security token handlers have a standard configuration extensibility hook that we can use to accomplish this (not very obvious at the beginning – but makes sense ;).

Let’s say our configuration should look like this:

<microsoft.identityModel>
  <
issuerNameRegistry type="LeastPrivilege.AccessControlServiceIssuerRegistry, Service" />

  <
securityTokenHandlers>
    <
clear />
    <
add type="LeastPrivilege.AccessControlServiceSaml11SecurityTokenHandler, Service">
      <
accessControlServiceTokenRequirement solutionName="leastprivilege" />
    </
add>
  </
securityTokenHandlers>
</
microsoft.identityModel>

 

To make the token handler aware of this sub config element, you have to add a new constructor to the token handler like this:

public AccessControlServiceSaml11SecurityTokenHandler(XmlElement customConfigElement)
    : base()
{
    if (customConfigElement.LocalName != "accessControlServiceTokenRequirement")
    {
        throw new InvalidOperationException("accessControlServiceTokenRequirement expected");
    }

    var solutionAttr = customConfigElement.Attributes["solutionName"];
    if (solutionAttr == null)
    {
        throw new InvalidOperationException("solution name expected");
    }

    _solution = solutionAttr.Value;
}

(if you also need support for the samlSecurityTokenRequirement element, you can manually call LoadSamlTokenAuthenticatorRequirement on the SecurityTokenHandlerElement class).

Here you can find the complete code – to get it working I’d suggest you first get the original SDK sample up and running. After that you have to make the necessary adjustments in my code (solution name, certificates and URIs).

HTH

 


ASP.NET | IdentityModel | WCF
Thursday, December 11, 2008 9:20:45 AM UTC  #   
 Sunday, December 07, 2008

LeastPrivilege.IdentityModel v2

Looking at the download numbers, my add-on library for System.IdentityModel was quite popular. Some days ago I started looking the code to see what could be still useful in the face of Geneva.

The good news is, that a lot of my helper classes are not necessary anymore thanks to the easier claims model in Geneva. Still I think that most of the time you have to wrap the raw IClaimsPrincipal with more domain specific functionality. Since my current project makes heavy use of Geneva I began compiling a set of classes that made my life easier while working with the Geneva framework.

Like in the first release, I added a bunch of extensions methods that make finding and demanding claims easier. This is mostly syntactic sugar because the new model is very LINQ friendly and you can easily write the queries yourself – but it makes the code easier to read IMO. At the heart of all functionality is this extension method:

public static IEnumerable<Claim> FindClaims(
  this IClaimsIdentity identity, Predicate<Claim> predicate)
{
    return from claim in identity.Claims
           where predicate(claim)
           select claim;
}

This allows layering all kinds of higher level functionality on top of both IClaimsIdentity and IClaimsPrincipal, e.g:

  • FindClaims(commonly used parameters)
    Returns a (possibly empty) list of claims.
  • DemandClaim(commonly user parameters)
    Throws a SecurityException if a specified claim is not found
  • GetClaimValue / TryGetClaimValue
    Returns the value of a specified claim

..and on top of that it is very easy to add business problem centric functionality.

This allows me to write code like this:

var principal = Thread.CurrentPrincipal.AsClaimsPrincipal();

principal.DemandClaim(
    WSAuthorizationConstants.Action,
    "Logs.Clear",
    http://accesscontrol.windows.net);

 

I will release the code once I have done more testing.


ASP.NET | IdentityModel | WCF
Sunday, December 07, 2008 4:49:10 PM UTC  #   
 Thursday, November 27, 2008

UserName Supporting Token & WCF revisited (this time with Geneva)

A while back I wrote about UserName supporting tokens in WCF and how they can be handy to create light-weight “delegation” scenarios for middle-tiers. I wanted to give the same scenario a try with a Geneva enabled relying party.

First of all – there are no basic configuration changes necessary (specifically the SecurityBindingElement – refer to my original post for details). All you have to do is to configure the Geneva “runtime” and wire it in your service host. This involves:

  • Specifying an issuer registry for the client’s certificate.
  • Add a UserNameSecurityTokenHandler that can cope with empty passwords (this also gives you the chance to add some custom claims for the user name token).

Refer to this post for details about issuer registries, and this post for UserName security token handlers.

All you then have to do is, to take all these pieces and configure the service host to use Geneva:

ServiceHost host = new ServiceHost(typeof(Service));

// add the supporting token to the binding
host.Description.Endpoints[0].Binding =

    AddUserNameSupportingTokenToBinding(host.Description.Endpoints[0].Binding);

// create security token handlers
var handlers = new SecurityTokenHandlerCollection(
    SecurityTokenHandlerCollection.DefaultHandlers);

// add handler for supporting token (empty password)
handlers.AddOrReplace(new SupportingUserNameSecurityTokenHandler());

// add the issuer name registry (simple for demo purposes)
var registry = new SimpleIssuerNameRegistry();

// configure host to use Geneva plumbing
FederatedServiceCredentials.ConfigureServiceHost(
    host,
    handlers,
    registry,
    new TimeSpan(0, 5, 0));

host.Open();

On incoming requests, Geneva will now create an IClaimsPrincipal that contains two IClaimsIdentity instances. One for the direct caller (certificate) and one for the supporting token (user name). You can now use the standard means to query both identities and their claims. Nice.

SupportingUserNameToken1.zip (39.91 KB)

 


IdentityModel | WCF
Thursday, November 27, 2008 6:47:40 AM UTC  #   
 Saturday, November 22, 2008

(SAML) Token Creation in a Geneva STS

By default, Geneva STS developers are quite shielded from the SAML creation process – you simply derive from SecurityTokenService and implement GetScope and GetOutputClaimsIdentity, and the rest gets done by the framework. But if you need more control over the generated tokens, it’s worthwhile to have a closer look.

Internally the SecurityTokenService class drives a “token information gathering” pipeline which results in the construction of a SecurityTokenDescriptor (a token neutral description) of the token to be issued. After that the descriptor is passed on to a SecurityTokenHandler that creates the security token. In the last step, the generated token is wrapped in an RSTR and sent back.

In the current bits, the STS pipeline looks like this:

  • GetScope
    Must be implemented. Determines scope specific information like signing and encrypting credentials – usually based on the AppliesTo header.
  • CreateSecurityDescriptor
    Creates a default descriptor based on the scope from step 1. This is one option to modify the descriptor manually.
  • GetSecurityTokenHandler
    C
    reates the security token handler that is later used for creating the token. The handler is determined based on the TokenType property of the RST.
  • GetIssuerName
    Returns the issuer for the token. By default the issuer from the SecurityTokenServiceConfiguration is used.
  • GetTokenLifetime
    Returns the life time of the token. By default the default life time from SecurityTokenServiceConfiguration is used (which is 10 hours).
  • GetProofToken
    Creates a ProofTokenDescriptor that describes the proof token (asymmetric, symmetric or none). By default the information from the RST and the scope are used here.
  • GetOutputClaimsIdentity
    Must be implemented. Returns the identity that describes the subject.
  • SecurityTokenHandler.CreateToken
    The token handler creates the token and returns it to the token service (more details later)
  • GetDisplayToken
    Returns the claims that should be client visible (e.g. for an identity selector)
  • GetResponse
    Creates the RSTR. This is a popular hook for looking at the generated response before sending it back.

You can override any of these methods to modify the shape of the output token. This pipeline is always the same regardless of the token type. Token specific processing is done in the security token handler.

Security token handlers also have a pipeline that drives token creation. Since they are token specific, you have more control here over the output token details. For the purpose of this post, I will describe the SAML 1.1 token creation. The details differ for other token types.

  • CreateStatements
    Creates the SAML subject, attribute and authentication statements. This method calls out to:
    • CreateSamlSubject
      Looks for a name identifier claim and uses this to create the SAML subject. Additionally if this claim has properties that describe the name format and qualifier these values will be added to the subject. The last step is to set the proof key identifier and subject confirmation method (holder of key / bearer)
    • CreateAttributeStatement
      Creates the attribute statement based on the claims from the token service.
    • CreateAuthenticationStatementFromAuthenticationInformation
      Creates the authentication statement based on the authentication information in the token descriptor. This method only gets called if such information is present – so be sure to populate the AuthenticationInformation collection on the descriptor at some earlier point.
  • CreateConditions
    Sets the token lifetime and audience URIs restrictions.
  • CreateAdvice
    Creates the SAML advice. By default no advice is created.
  • CreateAssertion
    Creates the SAML assertion based on the statements, the conditions and the advice.
  • GetSigningCredentials
    Returns the credential used to sign the token.
  • GetEncryptingCredentials
    Returns the credential used to encrypt the token. If this method returns null, the token will not be encrypted.

Again you can override any of these methods.

OK – that was a lot of information. Where would you now plug in when you want to modify token creation? You basically have two options. Either you override the methods in SecurityTokenService to shape the token descriptor that gets passed to the handler. Of, if you need more control, you derive from one of the token handlers (e.g. Saml11SecurityTokenHandler) and override some of the methods that create the token details.

If you choose to write a custom handler, you can wire up the handler to the token service by overriding the SecurityTokenService.GetSecurityTokenHandler method.

HTH


ASP.NET | WCF | IdentityModel
Saturday, November 22, 2008 3:13:18 PM UTC  #   
 Monday, November 17, 2008

Geneva HTTP Modules: ClaimsPrincipalHttpModule

Geneva ships with three HTTP modules to use with ASP.NET: ClaimsPrincipalHttpModule, SessionAuthenticationModule and WSFederationAuthenticationModule. What are they for – and when to chose which?

In this post I will focus on the simplest one of the three: ClaimsPrincipalHttpModule – in following post we will have a close look at the remaining two.

The claims principal module is your easiest entry into the claims-based world. It simply takes whatever identity is on HttpContext.User and turns that into an IClaimsPrincipal. No STS or issued tokens required. There are three main decisions made:

  • If client is using Windows authentication, create a WindowsClaimsPrincipal. This principal allows downcasting to WindowsPrincipal and WindowsIdentity (to access things like impersonation and other Windows security specific features). Furthermore it contains the Windows token details as claims (primary SID, group SIDs, SAM account name…).
  • If the client is a FormsAuth client, a claims principal holding the user name, authentication method and instant is created.
  • If RoleManager is enabled, Roles.GetRolesForUser() is called to retrieve the user’s role. These roles are transformed into claims of the “http://schemas.microsoft.com/ws/2008/06/identity/claims/role” type. Lovely.

In all cases this means, that traditional IsInRole based security (imperative or via UrlAuthorizationModule) as well IIdentity.Name continues to work while you get the benefits of claims.

The next step would be to wire up a ClaimsAuthenticationManager to add your own custom claims to the principal. This gives you a smooth migration path and co-existence between roles and claims. Nice.

One thing that’s missing IMO is the conversion of client certificates to claims. I’ll file that as a feature request.

Sample: ClaimsHttpModule.zip (8.5 KB)

(btw – this all reminds me so much of my ClaimsManagerModule I have posted in March’08 ;))

 


ASP.NET | IdentityModel
Monday, November 17, 2008 11:07:10 AM UTC  #   
 Friday, November 14, 2008

ClaimsAuthenticationManager in Geneva

One of the things that Zermatt was lacking was a uniform way to look at incoming claims (either from an STS or from auto-converted authentication information).

In Geneva we now have a piece of plumbing called the ClaimsAuthenticationManager which gets called on the first request when a token comes into your application. This gives you a chance to reject or add claims as well as create a completely different claims principal (aka claims transformation). These new claims go into the session token and subsequent requests will bypass that logic.

A simple claims authentication manager could look like this:

class ClaimsTransformer : ClaimsAuthenticationManager
{
    public override IClaimsPrincipal Authenticate(
      string endpointUri, IClaimsPrincipal incomingPrincipal)
    {
        return GetClaims(incomingPrincipal.Identity.Name,
                         incomingPrincipal.Identity.AuthenticationType);
    }

    private IClaimsPrincipal GetClaims(string name, string authenticationType)
    {
        ClaimsIdentity id = new ClaimsIdentity(new List<Claim>
        {
            new Claim(WSIdentityConstants.ClaimTypes.Name,
                name,
                ClaimValueTypes.String,
                "LeastPrivilege"),
            new Claim("http://leastprivilege/claims/customClaim",
                "customValue",
                ClaimValueTypes.String,
                "LeastPrivilege")
        }, authenticationType);

        return new ClaimsPrincipal(id);
    }
}

You register the claims auth manager e.g. in config:

<microsoft.identityModel>
  <
claimsAuthenticationManager type="LeastPrivilege.ClaimsTransformer, AutoClaims" />
</
microsoft.identityModel>

HTH


ASP.NET | IdentityModel | WCF
Friday, November 14, 2008 7:51:53 AM UTC  #   
 Thursday, November 13, 2008

Username/Password Validation with Geneva

In my previous post I mentioned that Geneva takes over parts of the WCF security system - I used the example of certificate validation. This is also true for username/password authentication.

In the case you have an existing service with a UserNamePasswordValidator - as soon as you opt-into Geneva, the validator will stop to work. This is because Geneva takes over parts of the WCF processing pipeline and injects its own token parsing and validation system.

In Geneva, so-called SecurityTokenHandlers read and validate incoming tokens. As part of the validation process, claims based on that token are created and put into the IClaimsPrincipal, which will abe vailable from your operations. There are two handlers that register for UserName tokens: WindowsUserNameSecurityTokenHandler and MembershipUserNameSecurityTokenHandler (I guess it is clear which account stores they use).

By default the Windows handler is registered and unless you have a used a username/password pair that incidentally matches a Windows account on your system, username authentication will fail.

You now have two options: using the membership handler (if you have an existing membership provider) or write your own handler, which is pretty straightforward. The following handler code makes sure that username and password are identical - nothing you should do in your production systems - but you get the idea ;)

class SimpleUserNameSecurityTokenHandler : UserNameSecurityTokenHandler
{
    public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
    {
        UserNameSecurityToken unToken = token as UserNameSecurityToken;
        if (unToken == null)
        {
            throw new ArgumentException("token");
        }

        // replace with proper password validation!
        if (unToken.UserName != unToken.Password)
        {
            throw new SecurityTokenValidationException();
        }

        ClaimsIdentity id = new ClaimsIdentity(new List<Claim>
            {
                new Claim(WSIdentityConstants.ClaimTypes.Name, unToken.UserName)
            }, "UserName");

        return new ClaimsIdentityCollection(id);
    }

    public override bool CanValidateToken
    {
        get
        {
            return true;
        }
    }
}

You have to setup the handler in config - this is currently a little cumbersome but will hopefully get easier in the future. You first have to remove the windows handler - or clear the handler collection and add your own handler to it:

<microsoft.identityModel>
  <
securityTokenHandlers>
    <
clear />
    <
add type="LeastPrivilege.SimpleUserNameSecurityTokenHandler, AutoClaims" />
  </
securityTokenHandlers>
</
microsoft.identityModel>

 

There is also a thread on MSDN where Pedro shows how to do that programmatically.

HTH


IdentityModel | WCF
Thursday, November 13, 2008 6:43:34 PM UTC  #   
 Friday, October 31, 2008

Geneva is the new WCF Security

Geneva has evolved to not only a an extension to WCF/ASP.NET for STS/token related things - it also changes how base WCF security works - to the better IMO. Let me give you an example:

Trusted certificate issuers
When doing client certificate based authentication you always had three choices for validating those certs: PeerTrust, ChainTrust and Custom. I wrote about these options in detail (here). Typically you ended up writing some custom validation because both Peer- and ChainTrust is often  not what you want (and there are also some differences when it comes to message vs transport based security - see here, here and here).

Once you opt-in to the Geneva model - you will realize that client certificates start to break. This is because Geneva has a built-in way to restrict allowed CAs to a specified list, and by default this list is enforced - and empty. The background here is, that Geneva has this concept of an "issuer registry" - basically a mechanism how to map issuers (usually certificate issuers) to a name - the name is then placed on the Issuer property of claims. There are two built-in registry classes: the SimpleIssuerNameRegistry (which simply uses the CA's subject name and has no restrictions) and the ConfigurationBasedIssuerNameRegistry (which enforces the list I mentioned above).

To specify a list of allowed issuers, you have to put something like this in config:

<microsoft.identityModel>
  <
issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, …">
    <
trustedIssuers>
      <
add name="LeastPrivilege CA"
          
thumbprint="…" />
    </
trustedIssuers>
  </
issuerNameRegistry>
</
microsoft.identityModel>

This has the effect that only certificates issued by a CA in the trustedIssuers list will be allowed "in". If you don't want that restriction - or already have other validation code down the line - you can use the simple name registry. Another option is of course to write your own registry class.

Another big simplification with Geneva comes to custom token/credential types (ever tried adding a new credential type of WCF? Even really simple things require you to write 10+ classes and a good understanding how they relate to each other). With Geneva's concept of SecurityTokenHandlers this gets much easier.

So in summary - Geneva replaces parts of the WCF security system, simplifies it and makes it easier to extend - even if you are not using a security token service. I like that.


IdentityModel | WCF
Friday, October 31, 2008 6:35:55 AM UTC  #   
 Monday, October 27, 2008

Geneva is the new Zermatt (and much more)

Starting with the PDC release, Microsoft's identity framework is now code-named "Geneva Framework". Based on that framework, there is also a product called "Geneva Server" that brings the ADFS 1.x type of functionality (and more) to the web services/WS-Trust/CardSpace world. Furthermore there is also a release called "Geneva CardSpace" which seems to be CardSpace v.Next.

You can download all the new bits here.

I already had the chance to test-drive some of the new bits and made some interesting observations - stay tuned ;)


ASP.NET | CardSpace | IdentityModel | WCF
Monday, October 27, 2008 9:45:34 PM UTC  #   
 Thursday, October 09, 2008

CardSpace is…

I often get the Question: “What is CardSpace?

While there is a whole philosophical side to CardSpace (or similar products) – the technical and pragmatic answer is:

“CardSpace is a graphical client for security token services built into Windows”

(or as Keith recently said: “home realm discovery the nice way")

Related questions are:

What is a card?

“A card is a graphical representation of the configuration details how to talk to that security token service (address, required claims, credentials and more…)”

Then what’s the difference between personal and managed cards?

“Personal cards use a local (aka personal) STS. Managed cards a third-party/remote STS”

That’s it.


CardSpace | IdentityModel
Thursday, October 09, 2008 10:21:57 PM UTC  #   
 Saturday, September 20, 2008

MSDN Article about WCF Service Authorization

Christian and I have written an article about the authorization infrastructure in WCF. It covers roles- and claims-based authorization and how to customize both. Enjoy.

http://msdn.microsoft.com/en-us/magazine/cc948343.aspx
(back online now - sorry for the confusion)


IdentityModel | WCF
Saturday, September 20, 2008 9:59:05 AM UTC  #   
 Sunday, September 14, 2008

Certificate-backed InfoCards and Service Credential Negotiation

When trying to implement certificate backed managed InfoCards you might run into this slightly misleading error message:

"There was a failure making a WS-Trust exchange with an external application. Could not retrieve token from identity provider.

Inner Exception: SOAP security negotiation failed. See inner exception for more details.
Inner Exception: The certificate 'CN=xy' must have a private key. The process must have access rights for the private key."

The real cause for this error is a bug in Windows CardSpace. You can workaround that by disabling service credential negotiation on your STS binding by setting negotiateServiceCredential to false.

Thanks to the Zermatt forum people for pointing me into the right direction!


IdentityModel
Sunday, September 14, 2008 12:16:45 PM UTC  #   
 Wednesday, September 03, 2008

Zermatt: Source Code for FormsAuth STS

I got several requests to publish the full source of the FormsAuth STS I described here. Find it here. The setup is just like the passive STS/RP samples in the SDK.

HTH

 


IdentityModel
Wednesday, September 03, 2008 10:55:48 PM UTC  #   
 Friday, August 15, 2008

Zermatt: Using Forms Authentication in a Passive STS

Since all Zermatt samples use Windows authentication to auth against an STS - the question how to use forms authentication instead popped up several times. It is easy to do that.

Basically a passive STS endpoint is an ASP.NET handler - could be a plain IHttpHandler, an .ashx or a page. All samples simply hook the Page_PreRender event to render the redirect logic. But you could also show a UI before doing that. This means you can put e.g. a login control on your issuing page and manually verify username/password credentials before issuing the token.

My sample issuing page looks like this:

<html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
    <title>Forms Authentication Sign In</title>
</
head>
<
body>
    <form id="form1" runat="server">
    <div>
        <asp:Login runat="server" ID="_login" OnAuthenticate="_login_Authenticate" />
    </div>
    </form>
</
body>
</
html>

In the Authenticate event you verify credentials somehow, and if successful, create a ClaimsIdentity and  issue the token. In my sample I additionally issue a forms auth ticket for the STS domain so that returning users don't have to re-authenticate using the form.

Another approach to make the federation token apply to more than one RP is to modify the cookie domain (if the RPs are in the same domain).

protected void _login_Authenticate(object sender, AuthenticateEventArgs e)
{
    if (ValidateUser(_login.UserName, _login.Password))
    {
        FormsAuthentication.SetAuthCookie(_login.UserName, false);

        ClaimsIdentity identity = new ClaimsIdentity(
            new Claim(System.IdentityModel.Claims.ClaimTypes.Name, _login.UserName),
            "UserName");
        ClaimsPrincipal principal = new ClaimsPrincipal(
            new ClaimsIdentityCollection(identity));

        ProcessFederationMessage(principal);
    }
}

HTH


IdentityModel
Friday, August 15, 2008 6:58:18 AM UTC  #   
 Thursday, July 24, 2008

WCF Claims to "Zermatt" Claims Migration Story

Hey - that's a short post - there is none. thanks. bye...

OK hold on - some background info.

Microsoft introduced their new claims API with .NET 3.0 as part of the System.IdentityModel assembly (with super tight integration into WCF). Needless to say that I really like the claims approach - and I have written quite a lot about it here.

Also since that day we were all waiting for that super secret identity framework that was supposed to extend the claims API and which will finally give us easier support for security token services and Information Card related technologies. Now it is in beta and is called "Zermatt". Cool. Life is good.

After some experiments and proof of concepts - it turns out life is not so good.

To enable the "Zermatt" model in WCF you basically have to call the ConfigureServiceHost method on the ExtensibleServiceCredentials class (at least that's how it works with the current bits). As soon as you enable Zermatt the usual places where security happens in WCF don't work anymore - namely ServiceSecurityContext and AuthorizationContext. Interested readers of my blog know that these classes are the entry point into the claims based world in WCF. Also if you have made any investments already into the claims model, your code relies on these classes. If they are "gone", your code is broken.

All the claims functionality found in WCF is now replaced by the Zermatt model and there is no connection whatsoever between them. You'll also find that Zermatt has its own version of a Claim class (and other structural classes too). This basically means that if you have already invested in the WCF claims model but wanna move on to Zermatt, you have to throw away all your code and start from scratch. There is no migration or co-existence story between WCF claims and Zermatt claims.

OK - the next thing I tried is how existing WCF authorization policies work together with Zermatt. The results are quite mixed. First of all external policies only work with certain credential types - and Right.Idenity claims are not supported at all.

Fortunately, there is a forum for Zermatt so I can ask some MSFT people about their take on that. Here's what I got back (I'd love to provide links to the forum posts - but unfortunately this forum is sooo cool and ajaxy that one of the most important features of the web - called URLs - don't work):

"Hi Dominick,
Deeper investigation on my part into what I suspected was a bug turned
out to be by design. The scenario you are attempting (upgrading a
legacy app that depends on the WCF claims model) is not supported in
Zermatt.

Once you opt into Zermatt's claims model, the WCF claims API does not
work anymore. The reason for this behavior is the new claims model in
Zermatt is not backwards compatible with the WCF claims API and it is
not feasible to support both the old and new models at the same time
for WCF applications.

As you have called out earlier in a separate discussion, you have to
choose between staying with the WCF API and not use Zermatt, or move
your application to Zermatt. If you do choose to migrate, any code
that depends on the WCF claims API will need to be rewritten."

Have you also spotted the word "legacy" wrt to WCF??? They must be kidding me!

Here's my answer:

"I don't understand the problem - why can't you take existing authZ
policies and transform them into a ClaimsIdentity - this would be an
easy solution for the migration problem.

Frankly - this sucks.

What do I tell my customers? Sorry for leading you into the
System.IdentityModel direction? Your code will not move forward?

You have a brand new communication framework with a brand new claims
based authZ model - now you are releasing a brand new identity
framework that just disables the technologies used before???? This is
not right.

I don't ask for a full compatibility story between S.IM and Zermat -
but i don't want to throw away all my code (or my customers code)."

Am I asking for too much? Is this a non-issue? I filed a bug for that here. If this is also important for you - feel free to vote.

 

Disclaimer: Don't get me wrong. I don't want to bash Microsoft or the Zermatt team, nor the people on the forum which are really helpful. I just think this is a wrong design decision. And I read somewhere that Microsoft is looking for feedback. So here it is.


IdentityModel
Thursday, July 24, 2008 10:06:31 AM UTC  #   
 Friday, July 18, 2008

Try "Zermatt" and give Feedback

The last week I spent some time exploring parts of the "Zermatt" framework - some things are really cool - some I have mixed feelings about.

The team is still in a quite early stage where design decisions and directions are (re-) considered. Since "Zermatt" is the main Microsoft identity framework we have to live (and work) with for the next years, take you chance to shape it!

I have already started some discussions, so feel free to contribute.


IdentityModel
Friday, July 18, 2008 7:35:37 AM UTC  #   
 Wednesday, July 09, 2008

Skiing in "Zermatt"

Today, Microsoft finally announced the first public version of their .NET identity framework code named "Zermatt". The most important things you get from this framework are:

  • APIs for the token/claims related heavy crypto lifting
  • Supporting classes for claims aware applications (including an IIdentity/IPrincipal implementation to give you a common programming model and smooth migration path)
  • ASP.NET plumbing for accepting tokens in web applications
  • ASP.NET controls for adding Information Card support to web applications
  • OM for creating Information Cards
  • Framework and base classes to write security token services (for active and passive scenarios)

If you have already started looking into claims based security, this framework extends the concepts found in System.IdentityModel and makes it much easier to exploit the full power of token/claims based security systems. See here for the official announcement.

You can download the bits and a good whitepaper (written by Keith) here:

https://connect.microsoft.com/site/sitehome.aspx?SiteID=642

Stay tuned ;)


IdentityModel
Wednesday, July 09, 2008 10:38:23 PM UTC  #   
 Wednesday, July 02, 2008

Using IdentityModel: Useful Extension Methods for Serializing Claim Sets

As a follow up to my last post - the following extension methods make it easy to manually serialize claim sets:

public static XElement Serialize(
  this ClaimSet set, IEnumerable<Type> knownTypes)
{
    DataContractSerializer dcs = new DataContractSerializer(
        set.GetType(),
        knownTypes,
        int.MaxValue,
        false,
        true,
        null);
   
    MemoryStream ms = new MemoryStream();
    dcs.WriteObject(ms, set);
    ms.Seek(0, SeekOrigin.Begin);
   
    return XElement.Load(new XmlTextReader(ms));
}

 

public static XElement Serialize(
  this IEnumerable<ClaimSet> claimSets, string rootName,
  string rootNamespace, IEnumerable<Type> knownTypes)
{
    XNamespace ns = XNamespace.Get(rootNamespace);

    return new XElement(ns + rootName,
                    from cs in claimSets
                    select cs.Serialize(knownTypes));
}


IdentityModel
Wednesday, July 02, 2008 9:13:54 PM UTC  #   

Using IdentityModel: Serializing Claim Sets

Both Claim and ClaimSet are decorated with DataContract/DataMember attributes. This means they are made for serialization. And this makes sense - maybe you want to forward a claim set (server to server) or send a claim set from server to client (UI authorization).

But you will most likely run into problems when trying to serialize a claim set using the DataContractSerializer.

Known Types
DCS needs to 'know' all types that are involved in the serialization process. This involves every type in the inheritance chain down to ClaimSet (e.g. DefaultClaimSet or my DeferredLoadClaimSet) as well as all possible resource types. You either supply the known types via attributes/config (KnownType and ServiceKnownType).

Or you supply the types when newing up the DCS manually:

DataContractSerializer dcs = new DataContractSerializer(
    typeof(ClaimSet),
    new List<Type> { typeof(DefaultClaimSet), typeof(UIClaimResource) });

 

Circular References
Typical claim sets will have circular references - e.g. when the last issuer in the chain points to himself. DCS is not made for cyclic reference - but rather object trees (at least with the default settings). When you are trying to serialize objects with cyclic references you will get the following exception : "type contains cycles and cannot be serialized if reference tracking is disabled.". In WCF traces you will see something like "message not logged because its size exceeds configured quota".

When newing up a DCS you can opt for "preserving object references". This will create ID/IDREF pairs in the serialized XML and allows for type references and thus cycles. (Aaron has an explanation of how that works).

DataContractSerializer dcs = new DataContractSerializer(
    typeof(ClaimSet),
    new List<Type> { typeof(DefaultClaimSet), typeof(UIClaimResource) },
    int.MaxValue,
    true,
    true,  // preserveObjectReferences
    null);

 

This is fine when you can control the DCS parameters. But you can't easily do that in WCF. Sowmy has a sample on how to enable reference preserving in WCF. This will solve the problem!

[OperationContract]
[ReferencePreservingDataContractFormat]
ClaimSet GetClaims();

 

3.5 SP1 to the Rescue!?
Starting with 3.5 SP1 you can enable reference preserving on a DataContract like this:

[DataContract(Namespace = "...", IsReference = true)]
public abstract class DeferredLoadClaimSet : ClaimSet

 

But there are two problems with this approach:

  • You actually need access to the DataContract to change the attribute. In the claims case - you would need to change the framework's DefaultClaimSet or your own ClaimSet-derived class.
  • Every DataContract in the inheritance chain needs the IsReference attribute - otherwise you will get the following error: "Derived types must have the same value for IsReference as the base type". Since all custom claim sets ultimately derive from ClaimSet - but this DataContract has no IsReference set, we are back to square one.

 

Conclusion
Keep these things in mind when serializing claim sets:

  • supply all involved types as known types
  • Set preserveObjectReferences to true on the DCS. The new attribute on DataContract in 3.5 SP1 is nice - but does not help with claim sets. Use the [ReferencePreservingDataContractFormat] attribute instead (find the code here).
  • Reference preserving adds ID/IDREF attributes to the resulting XML. These attributes come from a Microsoft namespace. This may be a problem for interop scenarios. If you need full control over the XML, either use the DCS extensibility points for manual serialization, or don't use the DCS at all (and use one of the alternative message generation mechanisms). Another option would be to use a more standardized serialization format for claims like a SAML token.
  • WindowsClaimSet and X509CertificateClaimSet are not marked with [DataContract] at all - they are not intended for serialization.

HTH


IdentityModel
Wednesday, July 02, 2008 8:00:28 AM UTC  #   
 Saturday, June 07, 2008

Software Architect 2008

Thanks to everyone who attended my IdentityModel talk at Software Architect.

You can have all the code I showed you during my talk - just send me a private message or leave a comment. Most of the demos are online anyways - have a look at my IdentityModel micro-site.

Questions and feedback are more than welcome. Happy identity-ing.


Conferences | IdentityModel
Saturday, June 07, 2008 4:44:43 AM UTC  #   
 Monday, May 26, 2008

OpenID Phishing Demo

Funny and educational:

http://idtheft.fun.de/


For Your Favourites | IdentityModel
Monday, May 26, 2008 8:02:32 PM UTC  #   
 Monday, May 12, 2008

Using IdentityModel: Tracing

While reading through some of the code of System.IdentityModel, I noticed that there is some diagnostics tracing going on. Just add a trace listener for the source 'System.IdentityModel' to your config file.

HTH


IdentityModel | WCF
Monday, May 12, 2008 5:28:09 PM UTC  #   
 Monday, April 28, 2008

Using IdentityModel: Converting ADFS Security Properties to Claims

This little helper might be useful when you are working with ADFS, but want to use the IdentityModel types in your app:

public static ClaimSet ToClaimSet(this SingleSignOnIdentity identity)
{
    List<Claim> claims = new List<Claim>();

    claims.Add(new Claim(identity.NameType, identity.Name, Rights.Identity));

    foreach (SecurityProperty property in identity.SecurityPropertyCollection)
    {
        string claimType = property.Uri;
        if (claimType.EndsWith("NameValue"))
        {
            claimType = property.Name;
        }

        claims.Add(new Claim(claimType, property.Value, Rights.PossessProperty));
    }

    return new DefaultClaimSet(ClaimSet.System, claims);
}


IdentityModel
Monday, April 28, 2008 5:39:21 AM UTC  #   
 Wednesday, April 16, 2008

InfoCardSelector is now on Codeplex

I finally found a new home for my ASP.NET InfoCard control:

http://www.codeplex.com/InfoCardSelector

If you feel like contributing or suggesting new features, you can contact me via this page.


ASP.NET | CardSpace | IdentityModel | WCF
Wednesday, April 16, 2008 4:02:36 PM UTC  #   
 Sunday, March 30, 2008

Using Information Cards in ASMX Web Services

As I wrote here - an Information Card token is just a string. This means that (with the help of some extra plumbing) you can seamlessly integrate cards into "legacy" technologies. Here's a sample walkthrough for ASMX web services.

To transmit the token to the service, I will use a SOAP header. So the first step is to define the header:

[XmlRoot(ElementName = "InformationCard",
    Namespace = "http://schemas.xmlsoap.org/ws/2005/05/identity")]
public class InfoCardTokenHeader : SoapHeader
{
    public string Token;
}

For metadata support, we can now annotate a web method with this header information:

[WebService(Namespace = "urn:leastprivilege")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class AsmxService : WebService
{
    public InfoCardTokenHeader InfoCardToken;

    [WebMethod]
    [SoapHeader("InfoCardToken", Direction = SoapHeaderDirection.In)]
    public string Ping()
    {
      
    }
}

The client can now use the CardSpaceSelector API (or my wrapper) to get a token manually. Afterwards the token gets transmitted using the header:

static void Main(string[] args)
{
    AsmxService proxy = new AsmxService();

    InfoCardTokenHeader token = new InfoCardTokenHeader();
    token.Token = GetInfoCardToken(proxy.Url);
    proxy.InformationCard = token;

    Console.WriteLine(proxy.Ping());
}

static string GetInfoCardToken(string targetUri)
{
    IdentitySelector selector = new IdentitySelector();
    selector.TargetUri = new Uri(targetUri);
    selector.SetTargetCertificate(targetUri);

    selector.RequiredClaims.Add(ClaimTypes.GivenName);
    selector.RequiredClaims.Add(ClaimTypes.Surname);
    selector.RequiredClaims.Add(ClaimTypes.Email);

    GenericXmlSecurityToken token = selector.GetToken();
    return token.TokenXml.OuterXml;
}

On the server side you could now retrieve the token from the header and use your favourite token decryption class to extract the claims. If you want to put in a little bit more work, you can improve the integration of that information using a SoapExtension.

The extension will check the incoming headers, extract the token and set Thread.CurrentPrincipal and Context.User to an instance of IdentityPrincipal that wraps the token generated authorization context. A corresponding extension attribute connects this logic with the web method:

[WebMethod]
[InfoCardSoapExtension(TokenRequired = true)]   
[SoapHeader("InfoCardToken", Direction = SoapHeaderDirection.In)]
public string Ping()
{
    return IdentityPrincipal.Current.ClaimSets.FindClaim(
        ClaimTypes.GivenName).Get<string>();
}

This gives the web service method seamless access to incoming claims.

 

The code for the SOAP extension is quite simple (the configuration code is omitted):

public class InfoCardSoapExtension : SoapExtension
{
  public override void ProcessMessage(SoapMessage message)
  {
    if (message.Stage == SoapMessageStage.AfterDeserialize)
    {
      foreach (SoapHeader header in message.Headers)
      {
        InfoCardTokenHeader tokenHeader =
          header as InfoCardTokenHeader;

        if (tokenHeader != null)
        {
 
        IdentityPrincipal principal;

          try
          {
            var token = new Token(tokenHeader.Token, true);
            principal = new IdentityPrincipal(token.AuthorizationContext);
          }
          catch
          {
            throw new HttpException(500, "Token validation failed");
          }

          HttpContext.Current.User = Thread.CurrentPrincipal = principal;
          return;
        }
      }

      if (_tokenRequired)
      {
        throw new HttpException(401, "Authentication required");
      }
    }
  }
}

Disclaimer: I know that this code could be written far more generic. Consider this as a proof of concept.

 

The LeastPrivilege.IdentityModel download contains the complete sample. Have fun.


ASP.NET | CardSpace | IdentityModel
Sunday, March 30, 2008 8:49:07 AM UTC  #   
 Saturday, March 22, 2008

Using IdentityModel: Some Samples

Here are some typical usage scenario of IdentityPrincipal in ASP.NET.

Simple IsInRole calls (checks for a status claim with a value of 'Gold'):

HttpContext.Current.User.IsInRole("Gold");

 

Retrieving the OrderHistory claim:

IdentityPrincipal ip = IdentityPrincipal.Current;
Claim orderHistory = ip.ClaimSets.FindClaim(
  Constants.OrderHistoryClaimType,
  Constants.ApplicationIssuerIdentityClaim);

var orders = orderHistory.Get<List<OrderDetail>>();

 

..or some authorization code from my CardSpace sample app - thanks to the unified authorization model, I can share this method across ASP.NET, ASMX and WCF:

public static IEnumerable<MessageBoard> GetBoardsForUser(
  AuthorizationContext context, bool includePublic)
{
    List<MessageBoard> boards = new List<MessageBoard>();

    foreach (Claim typeClaim in context.ClaimSets.FindClaims(
      AppClaims.UserTypeClaim,
      new ApplicationIssuerClaimSet()))
    {
        string type = typeClaim.Get<string>();
        if ("Public".Equals(type) && includePublic == false) continue;

        boards.AddRange(GetBoards(type));
    }

    return boards;
}

I have updated the source download here to include a console, WCF and ASP.NET test app that share the same authorization model.


ASP.NET | CardSpace | IdentityModel | WCF
Saturday, March 22, 2008 1:54:39 PM UTC  #   
 Thursday, March 20, 2008

Using IdentityModel: Adding ASP.NET Support Part 2 (Claims Manager)

The last step for integrating claims into ASP.NET is to write a module that loads authorization policies, creates an AuthorizationContext and persists that on Context.User/Thread.CurrentPrincipal.

My module has this simple configuration section:

<claimsManager enabled="true"
               addAuthenticationClaims="true"
               roleClaimType="urn:leastprivilege/claims/customers/status">
  <authorizationPolicies>
    <policy type="LeastPrivilege.CustomerIdAuthorizationPolicy, App_Code" />
    <policy type="LeastPrivilege.CustomerAuthorizationPolicy, App_Code" />
  </authorizationPolicies>
</claimsManager>

If addAuthenticationClaims is set to true, the policy that transforms authentication details to claims (see my last post) will be loaded before all the external policies. The roleClaimType attribute specifies the claim type that should be used for the IsInRole implementation of IdentityPrincipal. The authorizationPolicies collection specifies the claims transformation policies that should run.

The module itself subscribes to PostAuthenticateRequest, loads the policies and populates Context.User/Thread.CurrentPrincipal with the IdentityPrincipal (which in turn wraps the AuthorizationContext).

public class ClaimsManagerModule : IHttpModule
{
    public void Dispose()
    { }

    public void Init(HttpApplication context)
    {
        context.PostAuthenticateRequest += OnPostAuthenticateRequest;
    }

    private void OnPostAuthenticateRequest(object sender, EventArgs e)
    {
        // this code makes only sense when the user is authenticated
        if (!(HttpContext.Current.Request.IsAuthenticated))
        {
            return;
        }

        // make sure the module is enabled
        if (!Configuration.Enabled)
        {
            return;
        }

        HttpApplication app = sender as HttpApplication;
        HttpContext context = app.Context;

        IList<IAuthorizationPolicy> policies = ClaimsManagerModule.Policies;

        if (policies.Count != 0)
        {
            AuthorizationContext authContext =
              CreateAuthorizationContext(policies);

            IdentityPrincipal ip = new IdentityPrincipal(
              context.User.Identity, authContext);

            context.User = Thread.CurrentPrincipal = ip;
        }
    }

    private static AuthorizationContext CreateAuthorizationContext(
      IList<IAuthorizationPolicy> policies)
    {
        AuthorizationContext authContext =
            AuthorizationContext.CreateDefaultAuthorizationContext(policies);

        return authContext;
    }

    public static IList<IAuthorizationPolicy> Policies
    {
        get
        {
            List<IAuthorizationPolicy> policies = new
              List<IAuthorizationPolicy>();

            if (Configuration.AddAuthenticationClaims)
            {
                policies.Add(new AspNetAuthenticationPolicy());
            }

            foreach (PolicyType policy in
              Configuration.AuthorizationPolicies)
            {
                policies.Add(CreatePolicy(policy.Type));
            }

            return policies;
        }
    }

    private static IAuthorizationPolicy CreatePolicy(string typename)
    {
        Type type = Type.GetType(typename, true);

        if (!typeof(IAuthorizationPolicy).IsAssignableFrom(type))
        {
            throw new ConfigurationErrorsException(
              "Policy does not implement IAuthorizationPolicy");
        }

        return (IAuthorizationPolicy)Activator.CreateInstance(type);

    }

    public static ClaimsManagerSection Configuration
    {
        get
        {
            return (ClaimsManagerSection)
              WebConfigurationManager.GetSection("claimsManager");
        }
    }
}

 

Don't consider this as production ready code. There are things missing like error handling and caching. But this should get you started. With the next post I will show some usage scenarios and will also update the source download.

HTH


ASP.NET | IdentityModel
Thursday, March 20, 2008 6:54:32 AM UTC  #   
 Wednesday, March 19, 2008

Using IdentityModel: Adding ASP.NET Support Part 1 (Authentication based Claims)

Adding claims support to ASP.NET is a perfect candidate for an HTTP module. As a reminiscence to RoleManager, I called mine ClaimsManager. The job of the claims manager is this:

  • Creating claims based on the technical authentication details (Windows, Forms, client certificates etc.)
  • Invoking external claims transformation policies which then build the app specific claims based on the technical ones
  • Making the AuthorizationContext available to pages (via Thread.CurrentPrincipal/Context.User - see my previous post)

The first step is to write an IAuthorizationPolicy to map the ASP.NET authentication details to claims. This is done by inspecting Context.User.Identity and client certificates - if you use a custom identity, you would amend that code (check my previous posts about authorization policies):

// policy that adds ASP.NET authentication type specific claims
public class AspNetAuthenticationPolicy : IAuthorizationPolicy
{
    public bool Evaluate(
      EvaluationContext evaluationContext, ref object state)
    {
        HttpContext context = HttpContext.Current;
        List<ClaimSet> claimSets = new List<ClaimSet>();

        // Windows or Forms authentication
        if (context.User.Identity is WindowsIdentity)
        {
            claimSets.Add(
              new WindowsClaimSet(context.User.Identity as WindowsIdentity));
        }
        else if (context.User.Identity is FormsIdentity ||
                 context.User.Identity is GenericIdentity)
        {
            claimSets.Add(new UserNameClaimSet(context.User.Identity.Name))
        }

        // client certificate
        if (context.Request.ClientCertificate.IsPresent)
        {
            X509Certificate2 certificate = new X509Certificate2(
                context.Request.ClientCertificate.Certificate);

            claimSets.Add(new X509CertificateClaimSet(certificate));
        }

        claimSets.ForEach(set => evaluationContext.AddClaimSet(this, set));
        return true;
    }

    public System.IdentityModel.Claims.ClaimSet Issuer
    {
        get { return ClaimSet.System; }
    }

    public string Id
    {
        get
        {
          return
            "LeastPrivilege.IdentityModel.Web.AspNetAuthorizationPolicy";
        }  
    }
}

 

In the next post I will show the HTTP module, how it calls the above policy and how it chains in external policies.


ASP.NET | IdentityModel
Wednesday, March 19, 2008 7:23:49 AM UTC  #   

Using IdentityModel: IdentityPrincipal

Since V1 of .NET there is a "slot" to store authorization information about the current user: Thread.CurrentPrincipal. This data gets propagated to newly created threads and is deeply integrated into other application frameworks like ASP.NET.

To integrate claims into ASP.NET it makes sense to re-use this infrastructure.

To accomplish this the AuthorizationContext has to be wrapped by an IPrincipal implementation. I called mine IdentityPrincipal (which is part of LeastPrivilege.IdentityModel). I won't show you the source code here because this is not very exciting - but there are some things to note:

  • You can either new up the class by supplying a concrete AuthorizationContext or a list of claim sets.
  • If none of the above are specified, the class will try to use ServiceSecurityContext (for WCF support).
  • You can pass in one of the built-in IIdentity implementations (like WindowsIdentity, FormsIdentity etc). If you don't, the identity will be anoynmous (and it is assumed that you don't care about it).
  • I also created a ClaimsIdentity which simply wraps a claim and uses the resource as the Name property.
  • It features a static IdentityPrincipal.Current property which grabs the IPrincipal from Thread.CurrentPrincipal and tries to cast it to IdentityPrincipal.
  • The IsInRole implementation searches for a configurable claim type in the claim sets. Then the resource gets checked against the supplied "role name". This gives you compatibility for existing role based authorization code like ASP.NET UrlAuthorization (for simple scenarios).

The typical pattern would be:

  • Create an AuthorizationContext (or just one or more claim sets).
  • New up an IdentityPrincipal and put it on Thread.CurrentPrincipal (or Context.User for ASP.NET)
  • Call Thread.CurrentPrincipal.IsInRole (or Context.User.IsInRole) for simple checks
  • Call IdentityPrincipal.Current to get access to the claim sets and use the previously described extension methods for more advanced claims checking.

I updated the source download here to include the IdentityPrincipal as well as a console and WCF test app.

Have fun.


ASP.NET | IdentityModel | WCF
Wednesday, March 19, 2008 12:22:10 AM UTC  #   
 Tuesday, March 18, 2008

Using IdentityModel: Adding Claims Support to ASP.NET (Spoiler)

Many people asked me how to use claims based authorization in ASP.NET. While I have it working here on my machine (hey - it works on my machine!), I still need to polish the bits before I can release them. For those who want to get their hands dirty immediately - here's what you'd have to do:

  • Write an IPrincipal implementation that wraps an AuthorizationContext
  • Write an HTTP module that creates the AuthorizationContext, wraps it in the IPrincipal and puts it on Thread.CurrentPrincipal and Context.User.
  • If you need compatibility with the existing URL authorization infrastructure, define a role claim type that should be checked by IPrincipal.IsInRole
  • For more functionality, pages would grab the principal from Context.User and retrieve the AuthorizationContext. From there you can get to the claim sets to use the previously presented APIs to do authorization.

There are some additional nice to have features to implement like a permission and a corresponding attribute as well as a configurable claim type for IsInRole.

Bear with me.


ASP.NET | IdentityModel
Tuesday, March 18, 2008 7:23:35 AM UTC  #   
 Tuesday, March 11, 2008

STS? Available!

In my Post STS? Coming Soon! I linked to information about the upcoming framework for writing STSes (and more) from Microsoft. Unfortunately this is not yet available.

Along with Barry and David I am very happy to announce SharpSTS - a C# library for developing Information Card security token services.

You can find the source code on Codeplex and a demo website here. Don't expect a "click setup.exe and everything is fine" installation experience. There is still a lot of work to do. But you can get the complete source code along with installation instructions to play around. If you want to contribute or have feature ideas, leave me a comment.

Have fun!

 


CardSpace | IdentityModel | WCF
Tuesday, March 11, 2008 6:32:45 AM UTC  #   
 Tuesday, March 04, 2008

Using IdentityModel: Authorization Context and Claims Transformation outside of WCF

Here I showed you how to transform authentication specific claims to general application claims. The same model can be also used outside of WCF. I will use a client application here as an example and save ASP.NET for a later post (as this requires some extra work).

Typically, in client applications you don't need all these layers of indirection and flexibility since you will have (most likely) a single authentication type. But to prove the point that you can reuse your existing policies - here's what you would do:

  • Create a claim set for your "technical" user, e.g. from a username/password dialog, the Windows token or an inserted SmartCard
  • Map the "technical" identifier to an application identifier
  • Create the customer claims

It turns out that the only thing that is different to the WCF scenario is the initial "technical" claim set. The rest of the code stays the same.

You can create the authorization context by calling CreateDefaultAuthorizationContext on the AuthorizationContext class (and passing in the three policies described above). From that point on you can use the same authorization code as you would write in WCF.

The context creation code could look like this:

private static AuthorizationContext CreateContext()
{
    WindowsIdentity identity = WindowsIdentity.GetCurrent();

    AuthorizationContext context =
      AuthorizationContext.CreateDefaultAuthorizationContext(
        new List<IAuthorizationPolicy>()
        {
            // claim set based on Windows authentication
            new WindowsUserAuthorizationPolicy(identity),

            // mapping of authentication to application id
            new CustomerIdAuthorizationPolicy(),
           
            // application claim set
            new CustomerAuthorizationPolicy()
        });

    return context;
}

The only new code here is the policy for Windows authentication. This one is very simple:

class WindowsUserAuthorizationPolicy : IAuthorizationPolicy
{
    WindowsIdentity _identity;

    public WindowsUserAuthorizationPolicy(WindowsIdentity identity)
    {
        _identity = identity;
    }

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        evaluationContext.AddClaimSet(this, new WindowsClaimSet(_identity));

        return true;
    }

    public System.IdentityModel.Claims.ClaimSet Issuer
    {
        get { return ClaimSet.System; }
    }

    public string Id
    {
        get { return "WindowsUserAuthorizationPolicy"; }
    }
}

Now you have an AuthorizationContext. But there are some small things left to do. How do you make that context available to the rest of your app? How can you propagate this information across across thread switches. This brings us back to an old friend called Thead.CurrentPrincipal. Stay tuned.


IdentityModel
Tuesday, March 04, 2008 9:43:49 AM UTC  #   

Using IdentityModel: Simplifying Calculation of Information Card Unique IDs in WCF

The key to information card backed systems is calculating a stable unique identifier for your users based on the card claims. Typically this is done by hashing the issuer public key (plus some other information like a PPID for managed cards).

This involves the following steps:

  • Find the issuer claim set containing the issuer RSA key
  • Optionally find some other claims (e.g. a PPID)
  • Create a hash from that pieces of information

In LeastPrivilege.IdentityModel I added some helper extension methods to simplify this process. The first one extends the RSACryptoServiceProvider class and allows calculating the hash the from the key (plus optional extra information):

public static class RSAExtensions
{
    public static byte[] GetKeyHash(this RSACryptoServiceProvider rsa)
    {
        return rsa.GetKeyHash(string.Empty);
    }

    public static byte[] GetKeyHash(this RSACryptoServiceProvider rsa, string entropy)
    {
        int entropyLength = Encoding.UTF8.GetByteCount(entropy);
        RSAParameters rsaParams = rsa.ExportParameters(false);
        byte[] shaInput;
        byte[] shaOutput;

        int i = 0;
        shaInput = new byte[rsaParams.Modulus.Length +
          rsaParams.Exponent.Length + entropyLength];
        rsaParams.Modulus.CopyTo(shaInput, i);
        i += rsaParams.Modulus.Length;
        rsaParams.Exponent.CopyTo(shaInput, i);
        i += rsaParams.Exponent.Length;
        i += Encoding.UTF8.GetBytes(entropy, 0, entropy.Length, shaInput, i);

        using (SHA256 sha = SHA256.Create())
        {
            shaOutput = sha.ComputeHash(shaInput);
        }

        return shaOutput;
    }
}

 

I use the same algorithm here as in Microsoft's Token class for ASP.NET. This makes it easy to share the IDs between ASP.NET and other application types.

Another helper extends IEnumerable<ClaimSet> and simplifies retrieving the RSA claim:

public static RSACryptoServiceProvider FindIssuerRsaClaim(
  this IEnumerable<ClaimSet> claimSets)
{
    return claimSets.FindClaim(
        ClaimTypes.Rsa,
        ClaimSearchMode.Issuer).Get<RSACryptoServiceProvider>();
}

 

With these helpers you can retrieve the unique ID by using this code:

AuthorizationContext context =
    ServiceSecurityContext.Current.AuthorizationContext;
byte[] uniqueId = context.ClaimSets.FindIssuerRsaClaim().GetKeyHash();


IdentityModel | WCF
Tuesday, March 04, 2008 12:26:35 AM UTC  #   

Using IdentityModel: Claims Transformation in WCF

In the previous post I talked about claims transformation. Two authorization policies are necessary for the scenario I described. The first one maps the "technical" identity to an application identity and the second one creates application specific claims based on the application identity.

Mapping the identity
The first authorization policy grabs the first identity claim from the evaluation context and passes that to some mapping logic (omitted):

class CustomerIdAuthorizationPolicy : IAuthorizationPolicy
{
    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        string userId;
        Claim id = evaluationContext.ClaimSets.FindIdentityClaim();

        userId = Map(id);
        evaluationContext.AddClaimSet(this, new CustomerIdClaimSet(userId));
       
        return true;
    }

    public ClaimSet Issuer
    {
        get { return ClaimSet.System; }
    }

    public string Id
    {
        get { return "CustomerIdAuthorizationPolicy"; }
    }
}

The mapping logic then checks the claim type and returns the user id from some data store.

Adding the customer claims
The second policy then checks for the customer id claim and adds the necessary information to the evaluation context:

class CustomerAuthorizationPolicy : IAuthorizationPolicy
{
    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        string userId = evaluationContext.ClaimSets.FindClaim(
            Constants.CustomerIdClaimType,
            Constants.ApplicationIssuerIdentityClaim).Get<string>();

        evaluationContext.AddClaimSet(this, new CustomerClaimSet(userId));
        return true;
    }

    public ClaimSet Issuer
    {
        get { return ClaimSet.System; }
    }

    public string Id
    {
        get { return "CustomerAuthorizationPolicy"; }
    }
}

 

The last step is to to add the policies to the serviceAuthorization behavior in the right order:

<serviceAuthorization>
  <
authorizationPolicies>
    <
add policyType="LeastPrivilege.CustomerIdAuthorizationPolicy, Service" />
    <
add policyType="LeastPrivilege.CustomerAuthorizationPolicy, Service" />
  </
authorizationPolicies>
</
serviceAuthorization>

 

In the next post I will show you how to accomplish the same thing outside of WCF.


IdentityModel | WCF
Tuesday, March 04, 2008 12:04:18 AM UTC  #   
 Friday, February 29, 2008

Using IdentityModel: Authorization Policies, Context and Claims Transformation

In the previous posts I talked about claims and claim sets - but where do claim sets come from? The answer is easy - from authorization policies ;) OK - let's have a closer look.

The "container" for claim sets is a called the authorization context (defined in System.IdentityModel.Policy).

The authorization context gets created by calling CreateDefaultAuthorizationContext on the AuthorizationContext class. The input for this method is a list of objects that implement the IAuthorizationPolicy interface. This interface defines a method called Evaluate. Inside of Evaluate you create the claim sets you need and then call the AddClaimSet method on the EvaluationContext that gets passed into Evaluate. So much for the facts. How do we bring that all together?

Typically you want to distinguish between two kinds of authorization policies (and thus claim sets) in your system - I like to call them internal and external authorization policies.

An internal authorization policy is very close to the implementation details of the authentication process. WCF e.g. creates them based on the configured client credential type. These policies in turn create claim sets based on the incoming credential (Windows, certificates, usernames, SAML tokens).

External authorization policies do the application specific transformation of claims. They should not rely on any environment specific properties like ServiceSecurityContext (WCF), Context.User (ASP.NET) or Thread.CurrentPrincipal (whatever) but instead use solely the claims created by the internal policies to figure out all necessary information about the entity. This way external authorization policies can be used environment independent and can be shared between services or applications.

Let's do an example. Imagine a WCF service with multiple credential types. Regardless of the authentication type, you want to end up with a customer claim set that holds the necessary authorization information for your service. That could be done like this:

  1. WCF creates a claim set based on the incoming credential type, e.g. a WindowsClaimSet, a X509CertificateClaimSet or a claim set that holds assertions from an incoming SAML token.
  2. You create a policy that parses the WCF created claim set and transform the "technical" user identifier (e.g. Windows account name, X509 thumbprint, username) to an identifier that makes sense in your application. This identifier goes into a new claim set that gets added to the evaluation context.
  3. You create another policy that parses the application identifier from the previously added claim set and retrieves all necessary authorization information. Based on that you create a customer claim set and add it to the evaluation context.
  4. The business logic retrieves the information from the customer claim set and does authorization decisions.

If you follow this pattern you would only have to adjust the logic of the user id generation to your specific environment. The customer claim set creation policy is now easily re-usable.

In the next post I will show you some code ;)


IdentityModel | WCF
Friday, February 29, 2008 10:40:39 AM UTC  #   
 Tuesday, February 26, 2008

Using IdentityModel: Creating Custom Claim Sets

As part of LeastPrivilege.IdentityModel I wrote a claim set derived class that you can use to create your own custom claim sets. The DeferredLoadClaimSet lazily loads the claims (which potentially involves roundtrips to data stores) on demand when the claims are accessed for the first time.

You simply derive from DeferredLoadClaimSet and implement the LoadClaims method like this:

class CustomerClaimSet : DeferredLoadClaimSet
{
    string _customerName;

    public CustomerClaimSet(string customerName)
    {
        _customerName = customerName;
    }

    protected override void LoadClaims(out ClaimSet issuer, out IList<Claim> claims)
    {
        claims = CreateClaims();
        issuer = new ApplicationIssuerClaimSet(Constants.ApplicationIssuerName);
    }
}

 

The ApplicationIssuerClaimSet also derives from DeferredLoadClaimSet and can be used for custom issuers.

public class ApplicationIssuerClaimSet : DeferredLoadClaimSet
{
    string _issuerName = "Application Issuer";

    public ApplicationIssuerClaimSet()
    { }

    public ApplicationIssuerClaimSet(string issuerName)
    {
        _issuerName = issuerName;
    }

    protected override void LoadClaims(out ClaimSet issuer, out IList<Claim> claims)
    {
        claims = new List<Claim>()
        {
            new Claim(ClaimTypes.System, _issuerName, Rights.Identity),
            new Claim(ClaimTypes.System, _issuerName, Rights.PossessProperty)
        };

        issuer = this;
    }
}

 

HTH


IdentityModel
Tuesday, February 26, 2008 9:40:02 AM UTC  #   
 Sunday, February 24, 2008

Using IdentityModel: Typical Operations on Claim Sets

In the previous posts I talked about claims and claim sets. Now how do you use claim sets for authorization?

Let's take WCF as an example. In WCF you get access to the system generated claim sets via the AuthorizationContext (I have not yet explained where the AuthorizationContext comes from and how it is created - but I will in a future post). The typical code you write to access claim sets would be:

IEnumerable<ClaimSet> claimSets =
    ServiceSecurityContext.Current.AuthorizationContext.ClaimSets;

 

Once you have access to the claim sets you typically do the following operations:

  • Check if a specified claim is in one of the claim sets
  • Search for occurrences of a specified claim type in the claim sets

In addition you also want to specify the issuer of the claim you are looking for, e.g. search for the Name claim issued by 'System' or 'Windows'.

Unfortunately this simple task is a little cumbersome to achieve. Since you only have the FindClaim and ContainsClaim methods on ClaimSet itself, but not on the claim set list, you'd have to do this:

  1. Cycle through all the claim sets and inspect the issuer.
  2. If the issuer matches the one you are looking for use the issued claim set
  3. Search the claim set for the claim you are looking for

Extension methods to the rescue. In LeastPrivilege.IdentityModel I have extended IEnumerable<ClaimSet> with search operations that work across a list of claim sets:

  • ContainsClaim
  • FindClaim(s)
  • FindIdentityClaim
  • GetClaimSetsByIssuer

All these operations let you specify an issuer claim (or claim set) and the various overloads also allow to specify a claim comparer or if you want to search in issuer or issued claims.

The following code would achieve the above task (searching for the Windows account name):

Claim name = claimSets.FindClaim(ClaimTypes.Name, ClaimSet.Windows);

To get the Windows SID identity claim issued to the user, you could do this:

Claim sid = claimSets.FindIdentityClaim(ClaimSet.Windows);

...or directly convert to a SecurityIdentifier:

SecurityIdentifier sid =
    claimSets.FindIdentityClaim(ClaimSet.Windows).Get<SecurityIdentifier>();

 

This makes working with claim sets a little easier. In the next posts I will talk about how to create an AuthorizationContext yourself (e.g. to use the same programming model outside of WCF) and how authorization policies come mix in here.


IdentityModel | WCF
Sunday, February 24, 2008 11:28:24 AM UTC  #   

Using IdentityModel: Windows and X509Certificate Claim Sets

In System.IdentityModel.Claims you can find two more specialized claim sets for Windows accounts and X509 certificates called WindowsClaimSet and X509CertificateClaimSet respectively.

WCF uses these classes to create claim sets for Windows/certificate clients. But you can also use them "standalone".

The WindowsClaimSet converts the content of a Windows token to a claim set. You new up this class by passing in a WindowsIdentity. You can get one of these via network authentication, via LogonUser, or by calling WindowsIdentity.GetCurrent(). The generated claims are:

  • A SID identity claim containing the token's account SID (also available as a possess property)
  • SID possess property claims containing the group SIDs
  • Name possess property claim containing the user name

The issuer of this claim set will be always ClaimSet.Windows.

 

The X509CertificateClaimSet converts some of the attributes of an X509 certificate (and its issuers) to a claim set. Simply pass a X509Certificate2 to the constructor. The generated claims are:

  • A thumbprint claim containing the cert hash as identity and possess property.
  • The subject name as a X500DistinguishedName claim (possess property)
  • The public key of the certificate as an RSA claim (possess property)
  • Various extended name variations (if contained in the certificate). The claim set calls GetNameInfo on the certificate for DnsName, SimpleName, EmailName, UpnName and UrlName to create DNS, Name, Email, UPN and URI claims respectively.

The claim set issuer chain reflects the certificate issuer chain (by calling X509Chain.Build):

  • When the cert is self issued, the issuer will point to itself.
  • When the issuing cert is available, the issuer will be a X509CertificateClaimSet.
  • When the issuing cert is not available, the issuer will be a simple X509DistinguishedNameClaimSet containing the distinguished name of the issuer as identity and possess property.

IdentityModel
Sunday, February 24, 2008 9:07:27 AM UTC  #   
 Saturday, February 23, 2008

Using IdentityModel: Inspecting Claim Sets

The following code is useful for inspecting the contents of claim sets:

 

public static void ShowClaims(IEnumerable<ClaimSet> claimSets)
{
    int count = 0;
    foreach (ClaimSet set in claimSets)
    {
        Heading(String.Format("Claim Set #{0}", ++count), ConsoleColor.Yellow);
        ShowClaimSet(set, false);
    }
}

private static void ShowClaimSet(ClaimSet set, bool isIssuer)
{
    if (set.HasIssuer())
    {
        ShowClaimSet(set.Issuer, true);
    }

    string setType = set.GetType().Name;
   
string setName = isIssuer ? "Issuer" : "Issued";

    Heading(String.Format("\n{0} Claims ({1})\n", setName, setType),

      ConsoleColor.Green);

   
    foreach (Claim claim in set)
    {
        if (claim.Right.Equals(Rights.Identity))
        {
            Console.ForegroundColor = ConsoleColor.White;
        }

        Console.WriteLine(claim.ClaimType);
        Console.WriteLine(claim.Resource);
        Console.WriteLine(claim.Right);
        Console.WriteLine();

        Console.ResetColor();
    }
}

private static void Heading(string text, ConsoleColor color)
{
    Console.ForegroundColor = color;
    Console.WriteLine(text);
    Console.WriteLine();
    Console.ResetColor();
}


IdentityModel
Saturday, February 23, 2008 8:42:27 PM UTC  #   

Using IdentityModel: Claim Sets

In the previous post I talked about claims, what they are and how to create them. Usually a claim doesn't come on its own - but is grouped into a claim set.

To create a claim set you either derive from ClaimSet or new up a DefaultClaimSet. Which approach you choose depends on your needs. DefaultClaimSet provides a default implementation of a claim set whereas deriving from Claim allows doing your own internal data management (a little bit like deriving from GenericIdentity opposed to implementing the IIdentity interface manually). I used the Claim-derived approach in LeastPrivilege.IdentityModel e.g. to implement a claim set that does lazy loading of claims.

Regardless which approach you choose, a claim set always consists of two parts: a list of claims and an issuer.

The list of claims should contain a single identity claim - this acts as the identity of the claim set. Optionally there can be a number of possess property claims.

The issuer is also described using a claim set. The typical layout of an issuer claim set is a single identity claim that uses the System claim type (http://schemas.xmlsoap.org/ws/2005/05/identity/claims/system) and the same claim as a possess property. The value of these claims is up to the issuer.

System.IdentityModel provides two pre-defined issuer claim sets (available as static properties from the ClaimSet class):

  • ClaimSet.System
    Has a System claim type with a value of 'System' (identity and possess property).
    Used to describe claim sets that come from the 'System'.
  • ClaimSet.Windows
    Has a system claim types with a value of S-1-5 (identity and possess property).
    Used as an issuer for WindowsClaimSets.

If a claim set's issuer points to itself, you have reached the chain root (use ReferenceEquals to check this).

Typically you use these public methods from ClaimSet:

  • ContainsClaim
    Returns true/false if a specified claim can be found in the claim set
  • FindClaims
    Returns an IEnumerable<Claim> for all matches of a specifed claim type/right

LeastPrivilege.IdentityModel adds two extension methods to ClaimSet:

  • FindIdentityClaim
    Returns the identity claim of the claim set
  • HasIssuer
    Tells you if the claim set has an issuer

 

So much for the facts. In the next posts I will talk about where claim sets come from, what are typical operations you do on claim sets and how you use them for authorization.


IdentityModel
Saturday, February 23, 2008 8:26:01 PM UTC  #   
 Tuesday, February 19, 2008

Using IdentityModel: Claims

A claim is a piece of information that you want to associate with an entity (usually a user) in your system. Commonly used claims are e.g. the name of a user or his roles.

The usual course of events is, that one part of a system creates some claims and associates them with a certain context (e.g. an HTTP request or the current user of the system) and another part of that system uses this information to make decisions. Most commonly claims are used for authorization.

Again you can compare this to how roles-based authorization works (role providers, IPrincipal & IIdentity and Thread.CurrentPrincipal). But a role is a very simple claim - it only allows a binary (yes/no) decision. If you want to base more complex authorization decisions on roles (e.g. allowed to transfer money up to 5000€) you usually have to make additional round trips to your authorization store from within your code (or you have to create a TransferMoney5000 role which of course is suboptimal because it couples business details with the role name - what do you do if the limit changes to 7000€ ?).

System.IdentityModel defines a more general purpose data structure in a class called Claim (simplified version):

[DataContract(
  Namespace = "http://schemas.xmlsoap.org/ws/2005/05/identity")]
public class Claim
{
  [DataMember(Name = "ClaimType")]
  public string ClaimType;
       
  [DataMember(Name = "Resource")]
  public object Resource;

       
  [DataMember(Name = "Right")]
  public string Right;
}

 

A claim consists of three pieces of data:

  • The claim type is just a string giving this claim a unique name. You should use http:// namespace URIs like http://www.leastprivilege.com/claims/transfermoney (though this format is not a must, I ran across problems with serialization in SAML tokens if you use a different format).
  • The resource is some additional arbitrary data that you can associate with the claim. This could be simple integer like 5000 (to stick with my above example) up to complete object models (like a customer history).
  • The right describes the type of the claim. There are two commonly used values here: Identity and PossesProperty. The right becomes more important when you group claims into claim sets (something I will talk about in the next post). You can get these values from the Rights class.

The ClaimTypes class defines a bunch of standard claim types (name, email, gender, webpage...) so you don't have to remember their namespace values. To create a simple name claim, you would write code like this:

Claim name = new Claim(ClaimTypes.Name, "Alice", Rights.Identity);

 

The Claim class also features several static methods that create standard claims, e.g.:

Claim name = Claim.CreateNameClaim("Alice");

 

The static methods always create PossesProperty claims. If you need to create an identity claim, you have to manually construct the claim object.

A custom TransferMoney claim could be created like this:

Claim transferMoneyClaim = new Claim(
    "http://www.leastprivilege.com/claims/transfermoney",
    5000,
    Rights.PossessProperty);

 

LeastPrivilege.IdentityModel defines three extension methods for the Claim class:

  • Get<T> and TryGet<T> to convert the resource to a specific type.
  • IsIdentity to check if the claim is an identity claim.

 

A single claim on its own is generally not very useful. Claims typically come as part of claim sets - the topic of the next post about IdentityModel. Stay tuned.


IdentityModel | ASP.NET | WCF | Work in Progress
Tuesday, February 19, 2008 3:45:28 PM UTC  #   

Using System.IdentityModel and LeastPrivilege.IdentityModel

Michael (a reader) recently wrote:

"You posted on your blog that System.IdentityModel is not tied to WCF...I understand how the claims, rights, and resources work. And I have created an Authorization Policy that implements IAuthorizationPolicy. But how do I make it all work together?"

I spent the last couple of months building some applications that use the classes found in System.IdentityModel for identity and access control. And I really like this model.

As with most of the other features introduced in .NET 3.0, the API is meant as a foundation (compare to WCF) and is a little raw. So while writing my code I also built a companion library boldly called LeastPrivilege.IdentityModel that adds functionality that makes it easier to build claims/identity based applications.

In the next couple of posts I will do a walkthrough of System.IdentityModel, how to use the classes found there (together), how they are used in WCF, how to use them outside of WCF and what my library adds to it.

If you have any specific questions - just post them here and I can try to incorporate them. Have fun.


Work in Progress | IdentityModel
Tuesday, February 19, 2008 7:41:51 AM UTC  #