Converting Claims to Windows Tokens and User Impersonation

In a domain environment it is really useful to switch user contexts in a web application.  This could be if you are needing to log in with credentials that have elevated permissions (or vice-versa) or just needing to log in as another user.

It’s pretty easy to do this with Windows Identity Foundation and Claims Authentication.  When the WIF framework is installed, a service is installed (that is off by default) that can translate Claims to Windows Tokens.  This is called (not surprisingly) the Claims to Windows Token Service or (c2WTS).

Following the deploy-with-least-amount-of-attack-surface methodology, this service does not work out of the box.  You need to turn it on and enable which user’s are allowed to impersonate via token translation.  Now, this doesn’t mean which users can switch, it means which users running the process are allowed to switch.  E.g. the process running the IIS application pools local service/network service/local system/etc (preferably a named service user other than system users).

To allow users to do this go to C:\Program Files\Windows Identity Foundation\v3.5\c2wtshost.exe.config and add in the service users to <allowedCallers>:

<windowsTokenService>
  <!--
      By default no callers are allowed to use the Windows Identity Foundation Claims To NT Token Service.
      Add the identities you wish to allow below.
    -->
  <allowedCallers>
    <clear/>
    <!-- <add value="NT AUTHORITY\Network Service" /> -->
    <!-- <add value="NT AUTHORITY\Local Service" /> –>
    <!-- <add value="nt authority\system" /> –>
    <!-- <add value="NT AUTHORITY\Authenticated Users" /> -->
  </allowedCallers>
</windowsTokenService>

You should notice that by default, all users are not allowed.  Once you’ve done that you can start up the service.  It is called Claims to Windows Token Service in the Services MMC snap-in.

That takes care of the administrative side of things.  Lets write some code.  But first, some usings:

using System;
using System.Linq;
using System.Security.Principal;
using System.Threading;
using Microsoft.IdentityModel.Claims;
using Microsoft.IdentityModel.WindowsTokenService;

The next step is to actually generate the token.  From an architectural perspective, we want to use the UPN claims type as that’s what the service wants to see.  To get the claim, we do some simple LINQ:

IClaimsIdentity identity = (ClaimsIdentity)Thread.CurrentPrincipal.Identity;
string upn = identity.Claims.Where(c => c.ClaimType == ClaimTypes.Upn).First().Value;

if (String.IsNullOrEmpty(upn))
{
    throw new Exception("No UPN claim found");
}

Following that we do the impersonation:

WindowsIdentity windowsIdentity = S4UClient.UpnLogon(upn);

using (WindowsImpersonationContext ctxt = windowsIdentity.Impersonate())
{
    DoSomethingAsNewUser();

    ctxt.Undo(); // redundant with using { } statement
}

To release the token we call the Undo() method, but if you are within a using { } statement the Undo() method is called when the object is disposed.

One thing to keep in mind though.  If you do not have permission to impersonate a user a System.ServiceModel.Security.SecurityAccessDeniedException will be thrown.

That’s all there is to it.

Implementation Details

In my opinion, these types of calls really shouldn’t be made all that often.  Realistically you need to take a look at how impersonation fits into the application and then go from there.  Impersonation is pretty weighty topic for discussion, and frankly, I’m not an expert.

Converting Bootstrap Tokens to SAML Tokens

there comes a point where using an eavesdropping application to catch packets as they fly between Secure Token Services and Relying Parties becomes tiresome.  For me it came when I decided to give up on creating a man-in-the-middle between SSL sessions between ADFS and applications.  Mainly because ADFS doesn’t like that.  At all.

Needless to say I wanted to see the tokens.  Luckily, Windows Identity Foundation has the solution by way of the Bootstrap token.  To understand what it is, consider how this whole process works.  Once you’ve authenticated, the STS will POST a chunk of XML (the SAML Token) back to the RP.  WIF will interpret it as necessary and do it’s magic generating a new principal with the payload.  However, in some instances you need to keep this token intact.  This would be the case if you were creating a web service and needed to forward the token.  What WIF does is generate a bootstrap token from the SAML token, in the event you needed to forward it off to somewhere.

Before taking a look at it, let's add in some useful using statements:

using System;
using System.IdentityModel.Tokens;
using System.Text;
using System.Threading;
using System.Xml;
using Microsoft.IdentityModel.Claims;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Tokens.Saml11;

The bootstrap token is attached to IClaimsPrincipal identity:

SecurityToken bootstrapToken = ((IClaimsPrincipal)Thread.CurrentPrincipal).Identities[0].BootstrapToken;

However if you do this out of the box, BootstrapToken will be null.  By default, WIF will not save the token.  We need to explicitly enable this in the web.config file.  Add this line under <microsoft.IdentityModel><service><securityTokenHandlers>:

<securityTokenHandlerConfiguration saveBootstrapTokens="true" />

Once you’ve done that, WIF will load the token.

The properties are fairly straightforward, but you can’t just get a blob from it:

image

Luckily we have some code to convert from the bootstrap token to a chunk of XML:

SecurityToken bootstrapToken = ((IClaimsPrincipal)Thread.CurrentPrincipal).Identities[0].BootstrapToken;

StringBuilder sb = new StringBuilder();

using (var writer = XmlWriter.Create(sb))
{
     new Saml11SecurityTokenHandler(new SamlSecurityTokenRequirement()).WriteToken(writer, bootstrapToken);
}

string theXml = sb.ToString();

We get a proper XML document:

image

That’s all there is to it.

Windows Phone 7 Blogger Night

imageEarlier this week Microsoft Canada put on an event for the Windows Phone 7 RTM.  Joey Devilla has an excellent post on the event, but here is my take away.

Beautiful

First off, this interface is amazing.  It is functional, beautiful, and FAST.  Hardware acceleration is a thing of beauty.

Developer Friendly

Developing on competing platforms can be an ugly thing.  There are a number of reasons, all valid, but when it comes right down to it, sometimes the development environment just sucks.  Notsomuch with #wp7dev.  Full Visual Studio and Expression Blend integration is another thing of beauty. 

image

Silverlight development is a joy in these environments.  Oh, and the phone is ALL Silverlight.  How COOL is that?

Start to finish, 10 hours to develop a simple application.  That includes the learning curve of the IDE and Silverlight. 

The Community

Microsoft kind of dropped the ball on 5, 6, 6.1, and 6.5 for the Windows Phone.  The community was openly hostile to this.  Not too many people liked those versions.  With the introduction of 7, the criticality of the community has been high, but they have been extremely open to the possibilities this new UI brings with it.  Microsoft is touting this as a technology reset.  The community tends to agree.  Let’s hope it meets expectations when it hits the stores.

What’s Next?

Get the tools.  Try it out.  Find a local event that has a device and try and break your application.  Chances are, you’ll have more fun than you expect.

downloadTools

Build your own Directory Federation Service

This is more of a random collection of thoughts because earlier today I came to the conclusion that I need something very similar to Active Directory Federation Services, except for non-domain users.  This is relatively easy to do; all I need is to create a Secure Token Service with a user store for the back end. 

The simplest approach is to use ASP.NET Membership and Roles with SqlProvider’s wrapped up by some WIF special sauce.  Turns out Dominick Baier already did just that with StarterSTS.

The problems I have with this is that it’s a pain to manage when you start getting more than a hundred or so users.  Extending user properties is hard to do too.  So my solution is to use something that is designed for user identities… an LDAP directory.  If it’s good enough for Active Directory, it’ll be plenty useful for this situation.

Reasoning
As an aside, the reason I’m not using Active Directory in the first place is because I need to manage a few thousand well known users without CAL’s.  This would amount to upwards of a couple hundred thousand dollars in licensing costs that just isn’t in the budget.  Further, most of these users probably wouldn’t use any of our systems that use Active Directory for authentication, but nevertheless, we need accounts for them.

Also, it would be a lot easier to manage creation and modification of user accounts because there are loads of processes that have been designed to pull user data out of HR applications into LDAP directories instead of custom SQL queries.

So lets think about what makes up Active Directory Federation Services.  It has roles that provides:

  • Token Services
  • A Windows Authentication end-point
  • An Attribute store-property-to-claim mapper (maps any LDAP properties to any claim types)
  • An application management tool (MMC snap-in and PowerShell cmdlets)
  • Proxy Services (Allows requests to pass NAT’ed zones)

That’s a pretty lightweight product when you compare it to the other services in Microsoft’s Identity stack. 

We can simplify it even further by breaking down the roles we need.

Token Services

This is actually pretty easy to accomplish.  Refer back to the WIF magic sauce.

Authentication end-point

This is just (well, you know what I mean) a web page login control.  We can’t do Windows Authentication without Kerberos (or NTLM), and we can’t do Kerberos without Active Directory (technically it could be done, but you’d be crazy to try).

Attribute store-property-to-claim mapper

ADFS can connect to a bunch of different attribute stores, including custom built stores if you provide assemblies.  We only really need to map to a few LDAP properties, and make it easy to map to other properties in the future.

Application management tool

This would be to manage the mapper and a few STS settings like URI names and certificates.  This, I think, would be a relatively simple application if we designed the configuration database properly.

Proxy Services

Proxies are a pain in the butt.  Useful in general, but we don’t really need to think about this at the moment.

Some Warnings

There are some things that are worth mentioning.  We have to be really careful about what we create because we are developing a serious piece of the security infrastructure.  Yes, it is for a group of employees that won’t have much access to anything dangerous (if they need access, they’d be migrated to Active Directory), but nevertheless we are creating the main ingress point for the majority of our employees.  It also needs to be accessible from the internet.

It may sound like I think it’ll be a synch to develop this system and have it work securely, but in reality there is a lot that will need to go into it to protect the network, the employees, and the data this could possibly interact with.  It is tough to develop applications securely.  It is far harder to develop secure applications whose sole responsibility is security related.

Next Steps

The next step is to design the thing.  I know how it will exist in relation to the systems it will be used to provide identity to, but aside from that, the architecture of the thing is still unknown.  With any luck I can accomplish rough designs tomorrow on the train, on my way to visit family for the holiday.

Better yet, maybe while visiting with family. Winking smile

Vulnerabilities in Twitter’s OAuth Implementation

Earlier this week Twitter disabled Basic Authentication for clients, and switched over to their new OAuth implementation.  It turns out though that OAuth is fairly weak in a few areas, as it hasn’t really become a mature standard.  While this isn’t the end of the world, it does leave each implementer to their own devices to cover the weak points.

This is just a quick overview of the one of the WTF’s that is Twitter OAuth, but Ars Technica has a great article on this in detail.

One key point that Twitter seemed to miss entirely is how they handle client verification.  I.e. proving that the client in question is really who they say they are.  For instance, I use Sobees quite a bit, and have been playing around with MetroTwit lately too.  Twitter want’s each instance of Sobees to prove that it is Sobees.  The client application does this by getting a public/private key and passing them to the authentication mechanism.

This seems odd.  How does the application store the private key?  Most implementations will probably stick it in a config file while others might encrypt it.  Suffice to say, all applications need this private key.  It is very easy to extract text from binary structures, let alone config files, so what happens if I get another client’s private key?

Since this private key is used for identification, I could very easily stick that key into my application and pretend that I am that application.  This wouldn’t really lead to user PII being compromised, but it can easily cause harm.  Twitter’s goal for this is to reduce spam, because if they track too much spam coming from certain private keys they will revoke the key preventing the application from being able to sign the user in.

Who see’s the problem here?  What happens if my competitor steals my key and starts spamming people?  My key gets revoked, and I need to replace it.  If it’s a client application, that means updating it, testing it, deploying it, and hope that the mass downtime across every instance doesn’t lose too many customers for you.  Worse yet for those that have written iPhone apps, because that could mean weeks of delays while Apple twiddles their thumbs.

I suspect that they won’t revoke any keys once they come to their senses.  Or more likely, will revoke a key for something like TweetDeck and hear the outcry from the large user base.  After they can sign back in again, of course.

Using the ASP.NET Roles Provider with Windows Identity Foundation

Using the Windows Identity Foundation to handle user authentication and identity management can require you to drastically rethink how you will build your application.  There are a few fundamental differences between how authentication and roles will be handled when you switch to a Claims model. 

As an example if you used an STS to provide Claims to your application, you wouldn’t (couldn’t really) use the FormsAuthentication class.

Another thing to keep in mind is how you would handle Roles.  WIF sort of handles roles if you were to use <location> tags in web.config files like:

  <location path="test.aspx">
    <system.web>
      <authorization>
        <deny users="*" />
        <allow roles="admin" />
      </authorization>
    </system.web>
  </location>

WIF would handle this in an earlier part of the page lifecycle, and only allow authenticated users with a returned Role claim of admin.  This works well for some cases, but not all.

In larger applications we may want custom Roles, and the ability to map these roles to the Roles provided by the STS. 

This is by no means a place to tell you when you should use what architectural design, but a lot of times we want somewhere in the middle of these extremes…

Sometimes we just want to use the Roles class to check for role membership based on the Role claims.  From what I can find there is no RolesProvider implementation for WIF, so I wrote a very simple provider.  It is by all rights a hack.  The reason I say this is because there are quite a few methods that just can’t be implemented.  For instance, getting roles for other users is impossible, or adding a user to a role, or creating a role, deleting a role, etc.  This is all impossible because we can’t send anything back to the STS telling it what to do with the roles.

We are also limited to the scope of the roles.  I can only get the roles of the currently logged in user, nothing beyond.  So, with all the usual warnings (it works on my machine, don’t blame me if it steals your soul, etc)…

using System;
using System.Linq;
using System.Threading;
using System.Web.Security;
using Microsoft.IdentityModel.Claims;

public class ClaimsRoleProvider : RoleProvider
{
    IClaimsIdentity claimsIdentity;
    ClaimCollection userClaims;

    private void initClaims()
    {
        claimsIdentity = ((IClaimsPrincipal)(Thread.CurrentPrincipal)).Identities[0];
        userClaims = claimsIdentity.Claims;
    }

    public override string ApplicationName
    {
        get
        {
            initClaims();
            return claimsIdentity.GetType().ToString();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public override bool RoleExists(string roleName)
    {
        initClaims();

        return userClaims.Where(r => r.Value == roleName).Any();
    }

    public override bool IsUserInRole(string username, string roleName)
    {
        initClaims();

        return userClaims.Where(r => r.Value == roleName).Any();
    }

    public override string[] GetRolesForUser(string username)
    {
        initClaims();

        return userClaims.Where(r => r.ClaimType == ClaimTypes.Role).Select(r => r.Value).ToArray();
    }

    public override string[] GetAllRoles()
    {
        initClaims();

        return userClaims.Where(r => r.ClaimType == ClaimTypes.Role).Select(r => r.Value).ToArray();
    }

    #region Not implementable

    public override string[] GetUsersInRole(string roleName)
    {
        throw new NotImplementedException();
    }

    public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }

    public override void CreateRole(string roleName)
    {
        throw new NotImplementedException();
    }

    public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
    {
        throw new NotImplementedException();
    }

    public override string[] FindUsersInRole(string roleName, string usernameToMatch)
    {
        throw new NotImplementedException();
    }

    public override void AddUsersToRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }

    #endregion
}

The next step is to modify the web.config to use this provider.  I put this in a separate assembly so it could be re-used.

    <roleManager enabled="true" defaultProvider="claimsRoleProvider">
      <providers>
        <clear />
        <add name="claimsRoleProvider" type="ClaimsRoleProvider, MyAssem.Providers,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=4a27739ef3347280" />
      </providers>
    </roleManager>

One final thing to be aware of… Roles.IsUserInRole(string roleName) uses IPrincipal.Identity.Name in it’s overloaded version in lieu of a username parameter which could result in this ArgumentNullException:

Value cannot be null.
Parameter name: username

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: username
Source Error:

Line 17:         var claims = from c in claimsIdentity.Claims select c;
Line 18: 
Line 19:         bool inRole = Roles.IsUserInRole("VPN");
Line 20:         
Line 21:         foreach (var r in claims)

Since the IClaimsIdentity is getting generated based on the claims it receives, it sets the Name property to whatever claim value is associated with the http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name claim type. If one isn't present, it will be set to null.

It took way too long for me to figure that one out. :)

Working with ADFS 2 via PowerShell

Over the last few years Microsoft has made a push for all of it’s Server Solutions to have the capability of being managed via PowerShell.  Active Directory Federation Services is no different.

When we installed ADFS for the first time, the installer told us it needed PowerShell as a pre-requisite, so we get some cmdlets available to us out of the box.  Before we start playing around with them though we need to register the cmdlets to our PowerShell session. We can do with this command:

Add-PSSnapin Microsoft.Adfs.PowerShell

At this point we can now muck around with all of the available cmdlets.  For a full list of available cmdlets for ADFS check out TechNet.

Let’s take a look at our ADFS Server Properties:

Get-AdfsProperties

AcceptableIdentifiers          : {}
AddProxyAuthorizationRules     : […snip…]
AutoCertificateRollover        : True
CertificateCriticalThreshold   : 2
CertificateDuration            : 365
CertificateGenerationThreshold : 20
CertificatePromotionThreshold  : 5
CertificateRolloverInterval    : 720
CertificateSharingContainer    :
CertificateThresholdMultiplier : 1440
ClientCertRevocationCheck      : None
ContactPerson                  :
DisplayName                    : WEB1.nexus.external.test
ExtendedProtectionTokenCheck   : Allow
FederationPassiveAddress       : /adfs/ls/
HostName                       : WEB1.nexus.external.test
HttpPort                       : 80
HttpsPort                      : 443
Identifier                     : http://web1.nexus.external.test/adfs/services/trust
InstalledLanguage              : en-US
LogLevel                       : {Errors, Information, Verbose, Warnings}
MonitoringInterval             : 1440
NetTcpPort                     : 1501
NtlmOnlySupportedClientAtProxy : False
OrganizationInfo               :
PreventTokenReplays            : True
ProxyTrustId                   : 58cb3f40-0633-4d9e-b3c2-84f9bc8c2ce8
ProxyTrustTokenLifetime        : 21600
ReplayCacheExpirationInterval  : 60
SignedSamlRequestsRequired     : False
SamlMessageDeliveryWindow      : 5
SignSamlAuthnRequests          : False
SsoLifetime                    : 480

Nothing fancy there.  What about updating?

get-help Set-AdfsProperties

Yep, we can do that:

NAME
    Set-ADFSProperties
   
SYNOPSIS
    Sets the properties of the Federation Service.
   
   
SYNTAX 
    […snip…]    
   
DETAILED DESCRIPTION
    The Set-ADFSProperties cmdlet sets the global properties and configuration of the Federation Service.

Updating settings isn’t all that exciting, so what about managing Relying Parties?

Add-ADFSRelyingPartyTrust
Get-ADFSRelyingPartyTrust
Remove-ADFSRelyingPartyTrust
Enable-ADFSRelyingPartyTrust
Disable-ADFSRelyingPartyTrust
Update-ADFSRelyingPartyTrust

You can also manage things like Certificates:

Add-ADFSCertificate
Remove-ADFSCertificate
Update-ADFSCertificate

There are many more things you can do from within PowerShell.  Again, for the full list check out TechNet.

Being able to manage ADFS directly from PowerShell makes things a lot easier.  Not only for those who aren’t too keen on using MMC snap-ins, but also for the developers to automate deployment for testing and development.

Proceedings from the Crypto 2010 Conference

Originally found on Bruce Schneier’s blog.  All credit to him…

Springer-Verlag publishes the proceedings, but they're available as a free download for the next few days.

Interesting read.

Videos on Identity Foundation and ADFS

Some videos from the last PDC…

LOTS of information…

Certificates and ADFS 2.0

One of the problems with pushing all this data back and forth between Token Services and clients and Relying Parties is that some of this information really needs to encrypted.  If someone can eavesdrop on your communications and catch your token authorization they could easily impersonate you.  We don’t want that.  As such, we use certificates in ADFS for EVERYTHING.

The problem with doing things this way is that certificates are a pain in the neck.  With ADFS we need at least three certificates for each server:

  • Service Communication certificate: This certificate is used for SSL communications for web services and connections between proxies.  This is the certificate used by IIS for the Federation Service site.
  • Token Signing certificate: This certificate is used to sign all tokens passed to the client.
  • Token decryption certificate: This certificate is used for decrypting incoming tokens.  This would be the private key for the Service Communication certificate.

Managing these certificates isn’t easy.  Sometimes we can get away with just using our domain CA, other times we need 3rd party CA’s to sign them.  Microsoft has provided lots of guidance in this, but it’s not the easiest to find.  You can access it on TechNet (Certificate Requirements for Federation Servers): http://technet.microsoft.com/en-ca/library/dd807040(WS.10).aspx

Hopefully that helps.