Home / My Disclaimer / Who am I? / Search... / Sign in

// SAML

Windows Azure Active Directory Federation In Depth (Part 2)

by Steve Syfuhs / December 07, 2012 10:02 PM

In my last post I talked a little bit about the provisioning and federation processes for Office 365 and Windows Azure Active Directory (WAAD). This time around I want to talk a little bit about how the various pieces fit together when federating an on premise Active Directory environment with WAAD and Office 365. You can find lots of articles online that talk about how to configure everything, but I wanted to dig a little deeper and show you why everything is configured the way it is.

Out of the box a Windows Azure Active Directory tenant manages users for you. You can create all your users online without ever having to configure anything on premise. This works fairly well for small businesses and organizations that are wanting to stop managing identities on premise altogether. However, for more advanced scenarios organizations will want to synchronize their on-premise Active Directory with WAAD. Getting this working revolves around two things: the users, and the domain.

First off, lets take a quick look at the domain. I’m using the Microsoft Online Services Module for PowerShell to query for this information. I’m going to use my domain as an example: syfuhs.net.

PS C:\Users\Steve\Desktop> Get-MsolDomain -DomainName syfuhs.net | fl *

Authentication : Managed
Capabilities   : Email, OfficeCommunicationsOnline
IsDefault      : True
IsInitial      : False
Name           : syfuhs.net
RootDomain     :
Status         : Verified

The important thing to look at is the Authentication attribute. It shows Managed because I haven’t configured federation for this domain.

If we then take a look at a user we see some basic directory information that we entered when the user was created. I’ve removed a bit of the empty fields but left an important one, the ImmutableId field.

PS C:\Users\Steve\Desktop> Get-MsolUser -UserPrincipalName steve@syfuhs.net | fl *

DisplayName                 : Steve Syfuhs
FirstName                   : Steve
ImmutableId                 :
LastName                    : Syfuhs
OverallProvisioningStatus   : Success
UserPrincipalName           : steve@syfuhs.net
ValidationStatus            : Healthy

The Immutable ID is a unique attribute that distinguishes a user in both on-premise Active Directory and Windows Azure Active Directory. Since I haven’t configured federation this value is blank.

Skip ahead a few pages after running the Convert-MsolDomainToFederated cmdlet and my domain is magically federated with my local Active Directory. If I re-run the first command we’ll see the Authentication attribute set to Federated. However, running the second command doesn’t return an Immutable ID and if I tried logging in through ADFS I get an error. What gives?

If we look at the token that is passed from ADFS to WAAD after sign in we see that there is actually a claim for an Immutable ID. This ID is what is used to determine the identity of the user, and if Office 365 has no idea who has that value it can’t trust that identity.

This particular problem is solved through directory synchronization using the DirSync service. DirSync is configured to get all users from Active Directory and add them to Windows Azure Active Directory. It synchronizes most attributes configured for a user including the objectGUID attribute. This attribute is synchronized to the ImmutableID attribute in WAAD. It’s the anchor that binds an on-premise user with a cloud user.

Two questions tend to arise from this process:

  1. Why not just use the UPN for synchronization?
  2. Why do you need to synchronize in the first place?

Both questions are fairly simple to answer, but the answers depend on one another. You cannot synchronize against a UPN because a user’s UPN can easily change. You need a value that will never change across the lifetime of a user account (hence the name “immutable”). You need the value to stay constant because synchronization will happen often. You need to synchronize any time a value changes in the on-premise Active Directory. Examples of changes include address changes or name changes. Changing your name can often result in changing your UPN.

It’s preferred to keep these attributes up to date in both systems because then applications can trust that they are getting the right values when requested from either system. This still begs the question though, why do you need to synchronize in the first place? Some people may ask this because it’s theoretically possible to provision new users as they first sign into an application. If the user doesn’t exist when they log in just create them. Simple.

The problem of course is that certain systems require knowledge of the user before the user ever logs in. A perfect example is Exchange. Imagine if a user is on vacation while the transition to Office 365 occurs. If the user doesn’t log in until they get back, that means they wouldn’t have received any email while they were away. Admittedly, not receiving a few weeks of email might be the preferred scenario for some, but I digress.

So we have to configure DirSync. Skip ahead a few more pages and DirSync executed and synchronized all my users. If we take a look back at my account we now see a value for the immutable ID:

PS C:\Users\Steve\Desktop> Get-MsolUser -UserPrincipalName steve@syfuhs.net | fl *

DisplayName                 : Steve Syfuhs
FirstName                   : Steve
ImmutableId                 : lHh/rEL830q6/mStDnD4uw==
UserPrincipalName           : steve@syfuhs.net
ValidationStatus            : Healthy

At this point I should now be able to log in.

If I navigate to https://portal.microsoftonline.com I’m redirected to https://login.microsoftonline.com and prompted for credentials. However, as soon as I type in my username it prompts telling me I have to go else where to sign in.

image

The sign in screen is smart enough to parse the domain name from my user and lookup the Authentication type tied to that domain. If the domain is configured as Federated the sign in page is told to redirect to ADFS. If we return back to that first PowerShell command we’ll see the authentication is set to Federated. This was set by the Convert-MsolDomainToFederated  command. Two things happened when it was called.

First, ADFS was configured to allow sending tokens to Windows Azure Active Directory. Second, WAAD was configured to receive tokens from ADFS.

We can take a look at exactly what was configured in WAAD by running more PowerShell.

PS C:\Windows\system32> Get-MsolDomainFederationSettings -DomainName syfuhs.net

ActiveLogOnUri         : << adfs server and username mixed endpoint >>
FederationBrandName    : syfuhs.net
IssuerUri              : urn:syfuhs:net
LogOffUri              : << adfs signout url >>
MetadataExchangeUri    : << adfs server mex endpoint >>
NextSigningCertificate :
PassiveLogOnUri        :
https://login.syfuhs/adfs/ls/
SigningCertificate     : MIICzDCCAbSgA.....sh37NMr5gpFGrUnnbFjuk9ATXF1WZ

I’ve stripped out a few things to make it a little more readable. The key is that PassiveLogOnUri field. That is the URL passed back to the sign in page and is what is used to compose a WS-Federation signin request.

If I click the link I’m redirected to ADFS and if the computer I’m using is a member of the same domain as ADFS I shouldn’t be prompted for credentials. After Windows Authentication does it’s thing ADFS determines that WAAD sent us because the wtrealm URL parameter is set to urn:federation:MicrosoftOnline which is WAAD's Audience URI.

When Convert-MsolDomainToFederated was called, ADFS was instructed to create a Relying Party Trust for WAAD. That trust had a set of claims issuance rules that query Active Directory for various things like a user’s objectGUID and UPN. These values are formatted, bundled into a SAML token, and signed with the ADFS signing key. The token is then POST’ed back to WAAD.

The SigningKey field we saw in the Get-MsolDomainFederationSettings command is the public key to the ADFS signing key. It was configured when Convert-MsolDomainToFederated was called. It is used to verify that the token received from ADFS is valid.  If the token is in fact valid the domain is located based on the Issuer URI and UPN, and the user is located in the domain. If a user is found then WAAD will create a new token for the user and issue it to whichever service initially requested login, which in our case is https://portal.microsoftonline.com.

From this point on any time I browse to an Office 365 service like Exchange, I’m redirected back to https://login.microsoftonline.com, and if my session is still valid from earlier, a new token is issued for Exchange. Same with SharePoint and Dynamics, Windows Intune, and any other application I’ve configured through Windows Azure Active Directory – even the Windows Azure management portal.

Federation with Office 365 through Windows Azure Active Directory is a very powerful feature and will be a very important aspect of cloud identity in the near future. While federation may seem like a complex black box, if we start digging into the configuration involved we start to learn a lot about the all the various moving parts, and hopefully realize its not too complex.

The Importance of Elevating Privilege

by Steve Syfuhs / August 28, 2011 04:00 PM

The biggest detractor to Single Sign On is the same thing that makes it so appealing – you only need to prove your identity once. This scares the hell out of some people because if you can compromise a users session in one application it's possible to affect other applications. Congratulations: checking your Facebook profile just caused your online store to delete all it's orders. Let's break that attack down a little.

  • You just signed into Facebook and checked your [insert something to check here] from some friend. That contained a link to something malicious.
  • You click the link, and it opens a page that contains an iframe. The iframe points to a URL for your administration portal of the online store with a couple parameters in the query string telling the store to delete all the incoming orders.
  • At this point you don't have a session with the administration portal and in a pre-SSO world it would redirect you to a login page. This would stop most attacks because either a) the iframe is too small to show the page, or b) (hopefully) the user is smart enough to realize that a link from a friend on Facebook shouldn't redirect you to your online store's administration portal. In a post-SSO world, the portal would redirect you to the STS of choice and that STS already has you signed in (imagine what else could happen in this situation if you were using Facebook as your identity provider).
  • So you've signed into the STS already, and it doesn't prompt for credentials. It redirects you to the administration page you were originally redirected away from, but this time with a session. The page is pulled up, the query string parameters are parsed, and the orders are deleted.

There are certainly ways to stop this as part of this is a bit trivial. For instance you could pop up an Ok/Cancel dialog asking "are you sure you want to delete these?", but for the sake of discussion lets think of this at a high level.

The biggest problem with this scenario is that deleting orders doesn't require anything more than being signed in. By default you had the highest privileges available.

This problem is similar to the problem many users of Windows XP had. They were, by default, running with administrative privileges. This lead to a bunch of problems because any application running could do whatever it pleased on the system. Malware was rampant, and worse, users were just doing all around stupid things because they didn't know what they were doing but they had the permissions necessary to do it.

The solution to that problem is to give users non-administrative privileges by default, and when something required higher privileges you have to re-authenticate and temporarily run with the higher privileges. The key here is that you are running temporarily with higher privileges. However, security lost the argument and Microsoft caved while developing Windows Vista creating User Account Control (UAC). By default a user is an administrator, but they don't have administrative privileges. Their user token is a stripped down administrator token. You only have non-administrative privileges. In order to take full advantage of the administrator token, a user has to elevate and request the full token temporarily. This is a stop-gap solution though because it's theoretically possible to circumvent UAC because the administrative token exists. It also doesn't require you to re-authenticate – you just have to approve the elevation.

As more and more things are moving to the web it's important that we don't lose control over privileges. It's still very important that you don't have administrative privileges by default because, frankly, you probably don't need them all the time.

Some web applications are requiring elevation. For instance consider online banking sites. When I sign in I have a default set of privileges. I can view my accounts and transfer money between my accounts. Anything else requires that I re-authenticate myself by entering a private pin. So for instance I cannot transfer money to an account that doesn't belong to me without proving that it really is me making the transfer.

There are a couple ways you can design a web application that requires privilege elevation. Lets take a look at how to do it with Claims Based Authentication and WIF.

First off, lets look at the protocol. Out of the box WIF supports the WS-Federation protocol. The passive version of the protocol supports a query parameter of wauth. This parameter defines how authentication should happen. The values for it are mostly specific to each STS however there are a few well-defined values that the SAML protocol specifies. These values are passed to the STS to tell it to authenticate using a particular method. Here are some most often used:

Authentication Type/Credential Wauth Value
Password urn:oasis:names:tc:SAML:1.0:am:password
Kerberos urn:ietf:rfc:1510
TLS urn:ietf:rfc:2246
PKI/X509 urn:oasis:names:tc:SAML:1.0:am:X509-PKI
Default urn:oasis:names:tc:SAML:1.0:am:unspecified

When you pass one of these values to the STS during the signin request, the STS should then request that particular type of credential. the wauth parameter supports arbitrary values so you can use whatever you like. So therefore we can create a value that tells the STS that we want to re-authenticate because of an elevation request.

All you have to do is redirect to the STS with the wauth parameter:

https://yoursts/authenticate?wa=wsignin1.0&wtrealm=uri:myrp&wauth=urn:super:secure:elevation:method

Once the user has re-authenticated you need to tell the relying party some how. This is where the Authentication Method claim comes in handy:

http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod

Just add the claim to the output identity:

protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
{
    IClaimsIdentity ident = principal.Identity as IClaimsIdentity;
    ident.Claims.Add(new Claim(ClaimTypes.AuthenticationMethod, "urn:super:secure:elevation:method"));
    // finish filling claims...
    return ident;
}

At that point the relying party can then check to see whether the method satisfies the request. You could write an extension method like:

public static bool IsElevated(this IClaimsPrincipal principal)
{
    return principal.Identity.AuthenticationType == "urn:super:secure:elevation:method";
}

And then have a bit of code to check:

var p = Thread.CurrentPrincipal as IClaimsPrincipal;
if (p != null && p.IsElevated())
{
    DoSomethingRequiringElevation();
}

This satisfies half the requirements for elevating privilege. We need to make it so the user is only elevated for a short period of time. We can do this in an event handler after the token is received by the RP.  In Global.asax we could do something like:

void Application_Start(object sender, EventArgs e)
{
    FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived 
        += new EventHandler<SessionSecurityTokenReceivedEventArgs> (SessionAuthenticationModule_SessionSecurityTokenReceived);
}
void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
{
    if (e.SessionToken.ClaimsPrincipal.IsElevated())
    {
        SessionSecurityToken token = new SessionSecurityToken(e.SessionToken.ClaimsPrincipal, e.SessionToken.Context, e.SessionToken.ValidFrom, e.SessionToken.ValidFrom.AddMinutes(15));
        e.SessionToken = token;
    }
}

This will check to see if the incoming token has been elevated, and if it has, set the lifetime of the token to 15 minutes.

There are other places where this could occur like within the STS itself, however this value may need to be independent of the STS.

As I said earlier, as more and more things are moving to the web it's important that we don't lose control of privileges. By requiring certain types of authentication in our relying parties, we can easily support elevation by requiring the STS to re-authenticate.

SAML Protocol Extension CTP for Windows Identity Foundation

by Steve Syfuhs / May 15, 2011 04:00 PM

Earlier this morning the Geneva (WIF/ADFS) Product Team announced a CTP for supporting the SAML protocol within WIF.  WIF has supported SAML tokens since it's inception, however it hasn't supported the SAML protocol until now.  According to the team:

This WIF extension allows .NET developers to easily create claims-based SP-Lite compliant Service Provider applications that use SAML 2.0 conformant identity providers such as AD FS 2.0.

This is the first I've seen this CTP, so I decided to jump into the Quick Start solution to get a feel for what's going on.  Here is the solution hierarchy:

image

There isn't much to it.  We have the sample identity provider that generates a token for us, a relying party application (service provider), and a utilities project to help with some sample-related duties.

In most cases, we really only need to worry about the Service Provider, as the IdP probably already exists.  I think creating an IdP using this framework is for a different post.

If we consider that WIF mostly works via configuration changes to the web.config, it stands to reason that the SAML extensions will too.  Lets take a look at the web.config file.

There are three new things in the web.config that are different from a default-configured WIF application.

First we see a new configSection declaration:

<section name="microsoft.identityModel.saml" type="Microsoft.IdentityModel.Web.Configuration.MicrosoftIdentityModelSamlSection, Microsoft.IdentityModel.Protocols"/>

This creates a new configuration section called microsoft.identityModel.saml.

Interestingly, this doesn't actually contain much.  Just pointers to metadata:

<microsoft.identityModel.saml metadata="bin\App_Data\serviceprovider.xml">
    <identityProviders>
        <metadata file="bin\App_Data\identityprovider.xml"/>
    </identityProviders>
</microsoft.identityModel.saml>

Now this is a step away from WIF-ness.  These metadata documents are consumed by the extension.  They contain certificates and endpoint references:

<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:6010/IdentityProvider/saml/redirect/sso"/>

I can see some extensibility options here.

Finally, an HTTP Module is added to handle the token response:

<add name="Saml2AuthenticationModule" type="Microsoft.IdentityModel.Web.Saml2AuthenticationModule"/>

This module works similarly to the WSFederationAuthenticationModule used by WIF out of the box.

It then uses the SessionAuthenticationModule to handle session creation and management, which is the same module used by WIF.

As you start digging through the rest of the project, there isn't actually anything too surprising to see.  The default.aspx page just grabs a claim from the IClaimsidentity object and adds a control used by the sample to display SAML data.  There is a signout button though which calls the following line of code:

Saml2AuthenticationModule.Current.SignOut( "~/Login.aspx" );

In the Login.aspx page there is a sign in button that calls a similar line of code:

Saml2AuthenticationModule.Current.SignIn( "~/Default.aspx" );

All in all, this SAML protocol extension seems to making federating with a SAML IdP fairly simple and straightforward.

Redirecting to SAML Relying Party using ADFS v2 Query String

by Steve Syfuhs / February 21, 2011 04:00 PM

A quickie, but a goodie. 

In an earlier post on setting Salesforce.com as a SAML Relying Party to ADFS, I talked about how I felt a little dumb because I couldn’t figure out how to get ADFS to post the token to Salesforce.  The reason I felt that way was because with WS-Federation there is a URL parameter that is designed to tell the STS which relying party requested the token.  Notsomuch with SAML.

Turns out with ADFS there is such a parameter.  By default if you pass in ?loginToRp=[rpIdentifier] to the IdpInitiatedSignOn.aspx page, ADFS will look for a relying party based on the parameter.

If you are unsure of what identifier to use, you can go to the relying party properties, and check out the Identifiers tab.  It will accept any of the identifiers in the list:

image

As an aside, if you don’t like that URL parameter name, you can go into the IdpInitiatedSignOn.aspx.cs file and update line 21 to whichever you feel is appropriate:

const string RpIdentityQueryParameter = "loginToRp";

Then you compile the site, and redeploy.

You are properly securing ADFS by compiling the site’s source code, right? Smile

Salesforce.com Single Sign On using ADFS v2

by Steve Syfuhs / February 14, 2011 04:00 PM

For the last few years ObjectSharp has been using Salesforce.com to help manage parts of the business.  As business increased, our reliance on Salesforce increased.  More and more users started getting added, and as all stories go, these accounts became one more burden to manage.

This is the universal identity problem – too many user accounts for the same person.  As such, one of my internal goals here is to simplify identity at ObjectSharp.

While working on another internal project with Salesforce i got to thinking about how it manages users.  It turns out Salesforce allows you to set it up as a SAML relying party.  ADFS v2 supports being a SAML IdP.  Theoretically we have both sides of the puzzle, but how does it work?

Well, first things first.  I checked out the security section of the configuration portal:

image

There was a Single Sign-On section, so I followed that and was given a pretty simple screen:

image

There isn’t much here to setup.  Going down the options, here is what I came up with:

SAML Version

I know from previous experience that ADFS supports version 2 of the SAML Protocol.

Issuer

What is the URI of the IdP, which in this case is going to be ADFS?  Within the ADFS MMC snap-in, if you right click the Service node you can access the properties:

image

In the properties dialog there is a textbox allowing you to change the Federation Service Identifier:

image

We want that URI.

Within Salesforce we set the Issuer to the identifier URI.

Identity Provider Certificate

Salesforce can’t just go and accept any token.  It needs to only be able to accept a token from my organization.  Therefore I upload the public key used to sign my tokens from ADFS.  You can access that token by going to ADFS and selecting the Certificates node:

image

Once in there you can select the signing certificate:

image

Just export the certificate and upload to Salesforce.

Custom Error URL

If the login fails for some reason, what URL should it go to?  If you leave it blank, it redirects to a generic Salesforce error page.

SAML User ID Type

This option is asking what information we are giving to Salesforce, so it can correlate that information to one of their internal ID’s.  Since for this demo I was just using my email address, I will leave it with Assertion contains User’s salesforce.com username.

SAML User ID Location

This option is asking where the above ID is located within the SAML token.  By default it will accept the nameidentifier but I don’t really want to pass my email as a name so I will select user ID is in an Attribute element.

Now I have to specify what claim type the email address is.  In this case I will go with the default for ADFS, which is http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress.

On to Active Directory Federation Services

We are about half way done.  Now we just need to tell ADFS about Salesforce.  It’s surprisingly simple.

Once you’ve saved the Salesforce settings, you are given a button to download the metadata:

image

Selecting that will let you download an XML document containing metadata about Salesforce as a relying party.

Telling ADFS about a relying party is pretty straightforward, and you can find the detailed steps in a previous post I wrote about halfway through the article.

Once you’ve added the relying party, all you need to do is create a rule that returns the user’s email address as the above claim type:

image

Everything should be properly configured at this point.  Now we need to test it.

When I first started out with ADFS and SAML early last year, I couldn’t figure out how to get ADFS to post the token to a relying party.  SAML is not a protocol that I’m very familiar with, so I felt kinda dumb when I realized there is an ADFS URL you need to hit.  In this case it’s https://[adfs.fqdn]/adfs/ls/IdpInitiatedSignOn.aspx.

It brings you to a form page to select which application to post a token to:

image

Select your relying party and then go.

It will POST back to an ADFS endpoint, and then POST the information to the URL within the metadata provided earlier.  Once the POST’ing has quieted down, you end up on your Salesforce dashboard:

image

All in all, it took about 10 minutes to get everything working.

// About

Steve is a renaissance kid when it comes to technology. He spends his time in the security stack.