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

// Active Directory

Windows Azure Pack Authentication Part 1

by Steve Syfuhs / January 29, 2014 10:17 PM

Recently Microsoft released their on-premise Private Cloud offering called Windows Azure Pack for Windows Server.

Windows Azure Pack for Windows Server is a collection of Windows Azure technologies, available to Microsoft customers at no additional cost for installation into your data center. It runs on top of Windows Server 2012 R2 and System Center 2012 R2 and, through the use of the Windows Azure technologies, enables you to offer a rich, self-service, multi-tenant cloud, consistent with the public Windows Azure experience.

Cool!

There are a fair number of articles out there that have nice write ups on how it works, what it looks like, how to manage it, etc., but I’m not going to bore you with the introductions. Besides, Marc over at hyper-v.nu has already written up a fantastic collection of blog posts and I couldn’t do nearly as good a job introducing it.

Today I want to look at how Windows Azure Pack does authentication.

Architecture

Before we jump head first into authentication we should take a look at how Windows azure Pack works at an architectural level. It’s important to understand all the pieces that depend on authentication. If you take a look at the TechNet articles you can see there are a number of moving parts.

The primary components of Windows Azure Pack are broken down into services. Depending on how you want it all to scale you can install the services on one server or multiple servers, or multiple redundant servers. There are 7+1 primary services, and 5+ secondary services involved.

The primary services are:

To help simplify some future samples I’ve included the base URLs of the services above. Anything public-ish facing has its own subdomain, and the related backend APIs are on the same domain but a different port (the ports coincide with the default installation). Also, these are public endpoints – be kind please!

The Secondary services are for resource providers which are things like Web Sites, VM Cloud, Service Bus, etc. While the secondary services are absolutely important to a private cloud deployment and perhaps “secondary” is an inappropriate adjective, they aren’t necessarily in scope when talking about authentication. Not at this point at least. Maybe in a future post. Let me know if that’s something you would like to read about.

Admin Portal

The Admin Portal is a UI surface that allows administrators to manage resource providers like Web Sites and VM Clouds. It calls into the Admin API to do all the heavy lifting. The Admin API is a collection of Web API interfaces.

The Admin Portal and the Admin API are Relying Parties of the Admin Authentication Site. The Admin Authentication Site is a STS that authenticates users using Windows Auth.

adminauth

During initial authentication the Admin Portal will redirect to the STS and request a WS-Federation-wrapped JWT (JSON Web Token – pronounced “jot”). Once the Admin Portal receives the token it validates the token and begins issuing requests to the Admin API attaching that unwrapped JWT in an Authorization header.

This is how a login would flow:

  1. Request admin-cloud.syfuhs.net
  2. No auth – redirect to adminauth-cloud.syfuhs.net
  3. Do Windows Auth and mint a token
  4. Return the JWT to the Admin Portal
  5. Attach the JWT to the session

It’s just a WS-Fed passive flow. Nothing particularly fancy here besides using a JWT instead of a SAML token. WS-Federation is a token-agnostic protocol so you can use any kind of token format so long as both the IdP and RP understand it. A JWT looks something like this:

Header: {
    "x5t": "3LFgh5SzFeO4sgYfGJ5idbHxmEo",
    "alg": "RS256",
    "typ": "JWT"
},
Claims: {
    "upn": "SYFUHS-CLOUD\\Steve",
    "primarysid": "S-1-5-21-3349883041-1762849023-1404173506-500",
    "aud": "
http://azureservices/AdminSite",
    "primarygroupsid": "S-1-5-21-3349883041-1762849023-1404173506-513",
    "iss": "
http://azureservices/WindowsAuthSite",
    "exp": 1391086240,
    "group": [
        "SYFUHS-CLOUD\\None",
        "Everyone",
        "NT AUTHORITY\\Local account and member of Administrators group",
        "SYFUHS-CLOUD\\MgmtSvc Operators",
        "BUILTIN\\Administrators",
        "BUILTIN\\Users",
        "NT AUTHORITY\\NETWORK",
        "NT AUTHORITY\\Authenticated Users",
        "NT AUTHORITY\\This Organization",
        "NT AUTHORITY\\Local account",
        "NT AUTHORITY\\NTLM Authentication"
    ],
    "nbf": 1391057440
}, Signature: “…”

Actually, that’s a bit off because its not represented as { Header: {…}, Claims: {…} }, but that’s the logical representation.

If we look at the token there are some important bits. The UPN claim is the user identifier; the AUD claim is the audience receiving the token; the ISS claim is the issuer of the token. This is pretty much all the Admin Portal needs for proper authentication. Since this is an administrators portal it should probably do some authorization checks too though. The Admin Portal uses the UPN and/or group membership claims to decide whether a user is authorized.

If we quickly take a look at the configuration databases, namely the Microsoft.MgmtSvc.Store database, we can see a table called [mp].[AuthorizedAdminUsers]. This table lists the principals that are currently authorized to log into the Admin Portal. Admittedly, we probably don’t want to go mucking around the database though so we can use PowerShell to take a look.

PS C:\Windows\system32> Get-MgmtSvcAdminUser -Server localhost\sqlexpress
SYFUHS-CLOUD\MgmtSvc Operators
SYFUHS-CLOUD\Steve

My local user account and the MgmtSvc Operators group matches the claims in my token, so I can log in. Presumably its built so I just need a UPN or group claim matched up to let me in, but I must confess I haven’t gotten to testing that yet. Surely there’s documentation on TechNet about it… Winking smile

As an aside, it looks like PowerShell is the only way to modify the admin user list currently, so you can use Windows groups to easily manage authorization.

So anyway, now we have this token attached to the user session as part of the FedAuth cookie. I’m guessing they’ve set the BootstrapToken BootstrapContext to be the JWT because this token will have to always be present behind the scenes while the users session is still valid. However, in order for the Admin Portal to do anything it needs to call into the Admin API. Here’s the cool part: the JWT that is part of the session is simply attached to the request as an Authorization header (snipped for clarity).

GET https://admin-cloud.syfuhs.net:30004/subscriptions?skip=0&take=1 HTTP/1.1
Authorization: Bearer eyJ0eXAiOi...2Pfl_q3oVA
x-ms-principal-id: SYFUHS-CLOUD%5cSteve
Accept-Language: en-US
Host: admin-cloud.syfuhs.net:30004
Connection: Keep-Alive

The response is just a chunk of JSON:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
x-ms-request-id: 3a96aabb91e7403b968a8aa9b569ad5f.2014-01-30T04:42:02.8142310Z
X-Powered-By: ASP.NET
Date: Thu, 30 Jan 2014 04:42:04 GMT
Content-Length: 1124

{
   "items":[
      {
         "SubscriptionID":"386dd878-64b8-41a7-a02a-644f646e2df8",
         "SubscriptionName":"Sample Plan",
         "AccountAdminLiveEmailId":"steve@syfuhs.net",
         "ServiceAdminLiveEmailId":null,
         "CoAdminNames":[

         ],
         "AddOnReferences":[

         ],
         "AddOns":[

         ],
         "State":1,
         "QuotaSyncState":0,
         "ActivationSyncState":0,
         "PlanId":"Samplhr1gggmr",
         "Services":[
            {
               "Type":"sqlservers",
               "State":"registered",
               "QuotaSyncState":0,
               "ActivationSyncState":0,
               "BaseQuotaSettings":[…snip…]
            },
            {
               "Type":"mysqlservers",
               "State":"registered",
               "QuotaSyncState":0,
               "ActivationSyncState":0,
               "BaseQuotaSettings":[…snip…]
            }
         ],
         "LastErrorMessage":null,
         "Features":null,
         "OfferFriendlyName":"Sample Plan",
         "OfferCategory":null,
         "Created":"2014-01-30T03:21:43.533"
      }
   ],
   "filteredTotalCount":1,
   "totalCount":1
}

At this point (or rather, before it returns the response *cough*) the Admin API needs to authenticate and authorize the incoming request. The service is somewhat RESTful so it looks to the headers to check for an Authorization header (because the HTTP spec suggests that’s how it be done, REST blah blah blah, et al Open-mouthed smile).

The authorization header states that it has a Bearer token, which basically means the caller has already proven they are who they say they are based on the fact that they hold a token from a trusted STS (hence “bearer”). In other words they don’t have to do anything else. That token is the key to the kingdom.

Yet another aside: bearer tokens are sometimes considered insecure because anyone who has a copy of one could impersonate the user. With that being said, it’s better to use a token than say send the users password with each request.

Now at this point I can’t say for certain how things work internally as I don’t have any access to the source (I *could* use Reflector but that’s cheating), but since it’s Web API I could guess that they’re using a DelegatingHandler or something similar to do the verification. Vittorio actually has a great sample on how this could be done via what he’s calling Poor Mans Delegation/ActAs. It’s the same principle – receive token on web login, validate token so user can actually log in, keep token, want to call authenticated web service, still have token, stick token in header, web service authorizes token, done. Not too shabby.

Conclusion

So at this point we’ve seen how the Admin Portal authenticates users and how it securely calls its backend web services. Next time we’ll look at how the Tenant Portal does it (SPOILERS: it does it the same way!). Ahem -- more specifically, we’ll look at how the Tenant Portal is configured so it can actually trust the token it receives. From there we can take a look at how other IdPs can be configured for log in, and if we’re really wanting to be daring we could build our own custom STS for log in (it’s a wee-bit more complicated than you might think).

Whitepaper: Active Directory from on-premises to the cloud

by Steve Syfuhs / January 14, 2013 04:44 PM

A new whitepaper was released last Friday (Jan 11/2013) that discusses all the various options for dealing with identity in cloud, on-premise, and hybrid environments: Active Directory from on-premises to the cloud.

It takes a look at how Windows Azure Active Directory is making a play for cloud identity, as well as how it works with hybrid/on-premise scenarios.

Here’s the overview:

Identity management, provisioning, role management, and authentication are key services both on-premises and through the (hybrid) cloud. With the Bring Your Own Apps (BYOA) for the cloud and Software as a Service (SaaS) applications, the desire to better collaborate a la Facebook with the “social” enterprise, the need to support and integrate with social networks, which lead to a Bring Your Own Identity (BYOI) trend, identity becomes a service where identity “bridges” in the cloud talk to on-premises directories or the directories themselves move and/or are located in the cloud.

Active Directory (AD) is a Microsoft brand for identity related capabilities. In the on-premises world, Windows Server AD provides a set of identity capabilities and services and is hugely popular (88% of Fortune 1000 and 95% of enterprises use AD). Windows Azure AD is AD reimagined for the cloud, designed to solve for you the new identity and access challenges that come with the shift to a cloud-centric, multi-tenant world.

Windows Azure AD can be truly seen as an Identity Management as a Service (IDMaaS) cloud multi-tenant service. This goes far beyond taking AD and simply running it within a virtual machine (VM) in Windows Azure.

This document is intended for IT professionals, system architects, and developers who are interested in understanding the various options for managing and using identities in their (hybrid) cloud environment based on the AD foundation and how to leverage the related capabilities. AD, AD in Windows Azure and Windows Azure AD are indeed useful for slightly different scenarios. This document is part of a series of documents on the identity and security features of Windows Azure AD/Office 365 (see the links below for the other available documents in the series).

This is a pretty good paper. It documents a lot of the internal details of how all the various services play together in a central location, as well as sheds light on some publically-known, if not publically documented, methods of user provisioning.

Below is a list of great resources referenced in the document.

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.

Introduction to Windows Azure Active Directory Federation Part 1

by Steve Syfuhs / November 30, 2012 12:19 AM

Earlier this week Microsoft released some interesting numbers regarding Windows Azure Active Directory (WAAD) authentication.

Since the inception of the authentication service on the Windows Azure platform in 2010, we have now processed 200 BILLION authentications for 50 MILLION active user accounts. In an average week we receive 4.7 BILLION authentication requests for users in over 420 THOUSAND different domains.

[…] To put it into perspective, in the 2 minutes it takes to brew yourself a single cup of coffee, Windows Azure Active Directory (AD) has already processed just over 1 MILLION authentications from many different devices and users around the world.  Not only are we processing a huge number of authentications but we’re doing it really fast!  We respond to 9,000 requests per second and in the U.S. the average authentication takes less than 0.7 seconds.

Whoa.

Now, some people may be wondering what this is all about. Where are all these requests coming from? What domains? Who? Huh? What? It’s actually pretty straightforward: 99.99999999% of all these requests are coming from Office 365 and Dynamics CRM.

Windows Azure Active Directory started as the authentication service for Office 365. The service is built on the Microsoft Federation Gateway, which is the foundation for Windows Live/Microsoft accounts. As the platform matured Microsoft opened the system to allow more applications to authenticate against the service. It has since transitioned into it’s proper name Windows Azure Active Directory.

The system at it’s core is simply a multitenant directory of users. Each tenant is tied to at least one unique domain. Each tenant can then allow applications to federate. This is basically how Office 365 works. When you create a new Office 365 account, the provisioning system creates a new tenant in WAAD and ties it to a subdomain of onmicrosoft.com, so you would for instance get contoso.onmicrosoft.com. Once the tenant is created the provisioning system then goes off to the various services you’ve selected like Exchange, SharePoint, CRM, etc and starts telling them to create their various things necessary for service. These services now know about your WAAD tenant.

This is all well and good, but you’re now using contoso.onmicrosoft.com, and you would rather use a different domain like contoso.com for email and usernames. Adding a domain to Office 365 requires telling both WAAD and the various services that a new domain is available to use in the tenant. Now WAAD has two domains associated with it.

Now we can create users with our custom domain contoso.com, but there’s like a thousand users and you have Active Directory locally. It would be much better if we could just log into Office 365 using our own Active Directory credentials, and it would be so much nicer on the administrator if he didn’t have to create a thousand users. This calls for federation between WAAD and AD through Active Directory Federation Services (too. many. AD-based. names!).

Things get a little more complicated here. Before looking at federation between WAAD and AD we should take a look at how authentication normally works in Office 365.

First a user will try to access an application like SharePoint. SharePoint doesn’t see a session for the user so it redirects the user to login.microsoftonline.com, which is the public face of Windows Azure Active Directory. The user enters their credentials managed through your WAAD tenant, and is then redirected back to SharePoint with a token. SharePoint consumes the token and creates a session for the user. This is a standard process called passive federation. The federation is between SharePoint and WAAD. SharePoint and the various other services trust login.microsoftonline.com (and only login.microsoftonline.com) to issue tokens, so when a user has a token issued by login.microsoftonline.com its understood that the user has been authenticated and is now trusted. Clear as mud, right?

Allowing authentication via your on premise Active Directory complicates things a little. This involves creating a trust between Windows Azure Active Directory and your Active Directory through a service called Active Directory Federation Services. A trust is basically a contract that states WAAD will understand and allow tokens received from ADFS. With this trust in place, any authentication requests to WAAD through login.microsoftonline.com will be passed to your ADFS server. Once your ADFS server authenticates you, a token is generated and sent back to login.microsoftonline.com. This token is then consumed, and a new token is generated by login.microsoftonline.com and issued to whichever service asked for you to log in. Remember what I said above: Office 365 services only trust tokens issued by login.microsoftonline.com. Everything flows through WAAD.

That was a pretty high-level discussion of how things work, but unfortunately it’s missing a few key pieces like DirSync. In my next post I’ll dive much deeper into the inner workings of all these bits and pieces explaining how Windows Azure Active Directory federates with your on premise Active Directory.

Adjusting the Home Realm Discovery page in ADFS to support Email Addresses

by Steve Syfuhs / July 12, 2011 04:00 PM

Over on the Geneva forums a question was asked:

Does anyone have an example of how to change the HomeRealmDiscovery Page in ADFSv2 to accept an e-mail address in a text field and based upon that (actually the domain suffix) select the correct Claims/Identity Provider?

It's pretty easy to modify the HomeRealmDiscovery page, so I thought I'd give it a go.

Based on the question, two things need to be known: the email address and the home realm URI.  Then we need to translate the email address to a home realm URI and pass it on to ADFS.

This could be done a couple ways.  First it could be done by keeping a list of email addresses and their related home realms, or a list of email domains and their related home realms.  For the sake of this being an example, lets do both.

I've created a simple SQL database with three tables:

image

Each entry in the EmailAddress and Domain table have a pointer to the home realm URI (you can find the schema in the zip file below).

Then I created a new ADFS web project and added a new entity model to it:

image

From there I modified the HomeRealmDiscovery page to do the check:

//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------

using System;

using Microsoft.IdentityServer.Web.Configuration;
using Microsoft.IdentityServer.Web.UI;
using AdfsHomeRealm.Data;
using System.Linq;

public partial class HomeRealmDiscovery : Microsoft.IdentityServer.Web.UI.HomeRealmDiscoveryPage
{
    protected void Page_Init(object sender, EventArgs e)
    {
    }

    protected void PassiveSignInButton_Click(object sender, EventArgs e)
    {
        string email = txtEmail.Text;

        if (string.IsNullOrWhiteSpace(email))
        {
            SetError("Please enter an email address");
            return;
        }

        try
        {
            SelectHomeRealm(FindHomeRealmByEmail(email));
        }
        catch (ApplicationException)
        {
            SetError("Cannot find home realm based on email address");
        }
    }

    private string FindHomeRealmByEmail(string email)
    {
        using (AdfsHomeRealmDiscoveryEntities en = new AdfsHomeRealmDiscoveryEntities())
        {
            var emailRealms = from e in en.EmailAddresses where e.EmailAddress1.Equals(email) select e;

            if (emailRealms.Any()) // email address exists
                return emailRealms.First().HomeRealm.HomeRealmUri;

            // email address does not exist
            string domain = ParseDomain(email);

            var domainRealms = from d in en.Domains where d.DomainAddress.Equals(domain) select d;

            if (domainRealms.Any()) // domain exists
                return domainRealms.First().HomeRealm.HomeRealmUri;

            // neither email nor domain exist
            throw new ApplicationException();
        }
    }

    private string ParseDomain(string email)
    {
        if (!email.Contains("@"))
            return email;

        return email.Substring(email.IndexOf("@") + 1);
    }

    private void SetError(string p)
    {
        lblError.Text = p;
    }
}

 

If you compare the original code, there was some changes.  I removed the code that loaded the original home realm drop down list, and removed the code to choose the home realm based on the drop down list's selected value.

You can find my code here: http://www.syfuhs.net/AdfsHomeRealm.zip

Adding ADFS as an Identity Provider in ACS v2

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

Ever have one of those days where you swear that you've written something, but can't find it?  I could have sworn that I wrote this article before.  Ah well.

--

It makes a lot of sense to use ACS to manage Identity Providers.  It also makes sense to use Active Directory for letting users sign in to your cloud application.  Therefore we would hope that ACS and ADFS play nicely together.  It turns out they do.  in a previous post I talked about federating ACS and ADFS, where ACS is an identity provider to ADFS.  Now lets reverse it.  We want users to be redirected to ACS, then to ADFS to sign in.

First things first.  Lets log into our ACS namespace and navigate to the Identity Provider section, and then Add an Identity Provider:

image

From there we want to select what type of provider to use, and in this case we will select WS-Federation:

image

We are now provided with a form to fill out.  There are five properties: Display Name, WS-Federation metadata, Login Link text, Image Url, and Email domain names.

Display name is fairly straightforward.  What do you want the internal name of this IdP to be?

Next we need to provide a link to the Federation Metadata document that ADFS provides.  The path is https://adfs.domain.com/FederationMetadata/2007-06/FederationMetadata.xml.

Then we give it a public name, such as "ObjectSharp Internal Users".

If we want to use an image instead if showing text, we can provide a path to the image.

Finally we are asked for a semicolon separated list of email domains.  This may seem a bit confusing at first.  Basically, it allows us to filter out the IdP from the Home Realm Discovery page, and requires that the user enter in their email address.  That way, instead of seeing the "ObjectSharp Internal Users" link, we are provided a text box, where we need to enter an email address like ssyfuhs@objectsharp.com.  ACS will then look up the domain in their list, and if there is a reference to it, it will redirect to the IdP.

This takes care of the ACS bit.  just like in the previous post, you need to tell the other IdP about the other.  So we need to tell ADFS that ACS will be calling.  This is pretty simple.  We just need to add a relying party to ADFS using the ACS metadata.  You can find the ACS metadata under Application Integration:

image

There isn't much to federating ADFS to ACS and vice-versa.

Custom Management Accounts for Windows Azure Access Control Service

by Steve Syfuhs / April 27, 2011 04:00 PM

When you start working with Windows Azure in your spare time there are quite a few things that you miss.

I knew that it was possible to manage Windows Azure with multiple accounts, but since I was the only one logging into my instance, I never bothered to look into it.  Well as it turns out, I needed to be able to manage Azure from a separate Live ID.  It's pretty simple to do.  You get into your subscription, navigate to User Management under the Hosted Services tab, and then you add a new Co-Admin.

Turns out that you can't manage ACS this way though.  You don't have access to the namespaces as the Co-Admin.  Crap.  That's really what I wanted to manage with the separate account.  After a minute of swearing at the control panel, I logged into ACS with my original account and looked around.

Portal Administrators

Aha!  It was staring me right in the face:

image

There is a full MSDN article on how to deal with Portal Administrators.

Upon clicking the link you are given a list of current administrators.  I wanted to add one.

When you add an administrator you are given a list Identity Providers to choose from.  Interesting.

image

This means that I can manage this ACS namespace using any IdP that I want.  I already have ADFS created as an IdP, so I'm going to use it.  Getting Single Sign-On is always a bonus.

It asks for a claim type.  When the ACS management portal receives a token, it will look for this claim type and compare it's value to the Identity claim value.  If it matches the value, you are authorized to manage the namespace.  I chose email address.  It seemed simple enough.  To log in I just navigate to https://syfuhs2.accesscontrol.windows.net/ and then gives me the default Home Realm Discovery page:

image

I've already preconfigured ACS to redirect any email addresses with the objectsharp.com domain to our ADFS instance.  Once I click submit it redirects to ADFS, I authenticate using Windows Authentication, and then I'm back at the ACS Control Panel.  The next time I go to log in, a cookie will be there and the Home Realm Discovery page will see that I logged in with ADFS last time, so it will list that option first:

image

It just so happens that ObjectSharp is Awesome.

Now how cool is that?

Creating a Claims Provider Trust in ADFS 2

by Steve Syfuhs / April 25, 2011 04:00 PM

One of the cornerstones of ADFS is the concept of federation (one would hope anyway, given the name), which is defined as a user's authentication process across applications, organizations, or companies.  Or simply put, my company Contoso is a partner with Fabrikam.  Fabrikam employees need access to one of my applications, so we create a federated trust between my application and their user store, so they can log into my application using their internal Active Directory.  In this case, via ADFS.

So lets break this down into manageable bits. 

First we have our application.  This application is a relying party to my ADFS instance.  By now hopefully this is relatively routine.

Next we have the trust between our ADFS and our partner company's STS.  If the company had ADFS installed, we could just create a trust between the two, but lets go one step further and give anyone with a Live ID access to this application.  Therefore we need to create a trust between the Live ID STS and our ADFS server.

This is easier than most people may think.  We can just use Windows Azure Access Control Services (v2).  ACS can be set up very easily to federate with Live ID (or Google, Yahoo, Facebook, etc), so we just need to federate with ACS, and ACS needs to federate with Live ID.

Creating a trust between ADFS and ACS requires two parts.  First we need to tell ADFS about ACS, and second we need to tell ACS about ADFS.

To explain a bit further, we need to make ACS a Claims Provider to ADFS, so ADFS can call on ACS for authentication.  Then we need to make ADFS a relying party to ACS, so ADFS can consume the token from ACS.  Or rather, so ACS doesn't freak out when it see's a request for a token for ADFS.

This may seem a bit confusing at first, but it will become clearer when we walk through the process.

First we need to get the Federation Metadata for our ACS instance.  In this case I've created an ACS namespace called "syfuhs2".  The metadata can be found here: https://syfuhs2.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml.

Next I need to create a relying party in ACS, telling it about ADFS.  To do that browse to the Relying party applications section within the ACS management portal and create a new relying party:

image

Because ADFS natively supports trusts, I can just pass in the metadata for ADFS to ACS, and it will pull out the requisite pieces:

image

Once that is saved you can create a rule for the transform under the Rule Groups section:

image

For this I'm just going to generate a default set of rules.

image

This should take care of the ACS side of things.  Next we move into ADFS.

Within ADFS we want to browse to the Claims Provider Trusts section:

image

And then we right-click > Add Claims Provider Trust

This should open a Wizard:

image

Follow through the wizard and fill in the metadata field:

image

Having Token Services that properly generate metadata is a godsend.  Just sayin'.

Once the wizard has finished, it will open a Claims Transform wizard for incoming claims.  This is just a set of claims rules that get applied to any tokens received by ADFS.  In other words, what should happen to the claims within the token we receive from ACS?

In this case I'm just going to pass any claims through:

image

In practice, you should write a rule that filters out any extraneous claims that you don't necessarily trust.  For instance, if I were to receive a role claim with a value "Administrator" I may not want to let it through because that could give administrative access to the user, even though it wasn't explicitly set by someone managing the application.

Once all is said and done, you can browse to the RP, redirect for authentication and will be presenting with this screen:

image

After you've made your first selection, a cookie will be generated and you won't be redirected to this screen again.  If you select ACS, you then get redirected to the ACS Home Realm selection page (or directly to Live ID if you only have Live ID).

Plugging Application Authentication Leaks in ADFS

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

When you set up ADFS as an IdP for SAML relying parties, you are given a page that allows you to log into the relying parties.  There is nothing particularly interesting about this fact, except that it could be argued that the page allows for information leakage.  Take a look at it:

image

There are two important things to note:

  • I'm not signed in
  • I can see every application that uses this IdP

I'm on the fence about this one.  To some degree I don't care that people know we use ADFS to log into Salesforce.  Frankly, I blogged about it.  However, this could potentially be bad because it can tell an attacker about the applications you use, and the mechanisms you use to authenticate into them.

This is definitely something you should consider when developing your threat models.

Luckily, if you do decide that you don't want the applications to be visible, you can make a quick modification to the IdpInitiatedSignOn.aspx.cs page.

There is a method called SetRpListState:

protected void SetRpListState( object sender, EventArgs e )
{
    RelyingPartyDropDownList.Enabled = OtherRpRadioButton.Checked;
    ConsentDropDownList.Enabled = OtherRpRadioButton.Checked;
}

To get things working I made two quick modifications.  First I added the following line of code to that method:

OtherRpPanel.Visible = this.IsAuthenticated;

Then I added a line to the Page_Init method:

SetRpListState(null, null);

Now unauthenticated users just see this:

image

And authenticated users see everything as expected:

image

You could extend this further and add some logic to look into the App Settings in the web.config to quickly and easily switch between modes.

Windows Domain Authentication on Windows Phone 7

by Steve Syfuhs / March 02, 2011 04:00 PM

One of the projects that’s been kicking around in the back of my head is how to make Windows Phone 7 applications able to authenticate against a Windows domain.  This is a must have for enterprise developers if they want to use the new platform.

There were a couple ways I could do this, but keeping with my Claims-shtick I figured I would use an STS.  Given that ADFS is designed specifically for Active Directory authentication, I figured it would work nicely.  It should work like this:

image

Nothing too spectacularly interesting about the process.  In order to use ADFS though, I need the correct endpoint.  In this case I’m using

https://[external.exampledomain.com]/adfs/services/Trust/13/usernamemixed

That takes care of half of the problem.  Now I actually need to make my application call that web service endpoint. 

This is kind of a pain because WP7/Silverlight don’t support the underlying protocol, WS-Federation.

Theoretically I could just add that endpoint as a service reference and build up all the pieces, but that is a nightmare scenario because of all the boiler-plating around security.  It would be nice if there was a library that supported WS-Federation for the phone.

As it turns out Dominick Baier came across a solution.  He converted the project that came from the Identity training kit initially designed for Silverlight.  As he mentions there were a few gotchas, but overall it worked nicely.  You can download his source code and play around.

I decided to take it a step further though.  I didn’t really like the basic flow of token requests, and I didn’t like how I couldn’t work with IPrincipal/IIdentity objects.

First things first though.  I wanted to start from scratch, so I opened the identity training kit and looked for the Silverlight project.  You can find it here: [wherever you installed the kit]\IdentityTrainingKitVS2010\Labs\SilverlightAndIdentity\Source\Assets\SL.IdentityModel.

Initially I thought I could just add it to a phone project, but that was a bad idea; there were too many build errors.  I could convert the project file to a phone library, but frankly I was lazy, so I just created a new phone library and copied the source files between projects.

There were a couple references missing, so I added System.Runtime.Serialization, System.ServiceModel, and System.Xml.Linq.

This got the project built, but will it work?

I copied Dominick’s code:

WSTrustClient _client;

private void button1_Click(object sender, RoutedEventArgs e)
{
    _client = GetWSTrustClient(
https://[...]/adfs/services/Trust/13/usernamemixed,
new UsernameCredentials("username", "password")); var rst = new RequestSecurityToken(WSTrust13Constants.KeyTypes.Bearer) { AppliesTo = new EndpointAddress("[…]") }; _client.IssueCompleted += client_IssueCompleted; _client.IssueAsync(rst); } void client_IssueCompleted(object sender, IssueCompletedEventArgs e) { _client.IssueCompleted -= client_IssueCompleted; if (e.Error != null) throw e.Error; var token = e.Result; button2.IsEnabled = true; } private WSTrustClient
GetWSTrustClient(string stsEndpoint, IRequestCredentials credentials) { var client = new WSTrustClient(new WSTrustBindingUsernameMixed(),
new EndpointAddress(stsEndpoint), credentials); return client; }

To my surprise it worked.  Sweet.

This left me wanting more though.  In order to access any of the claims within the token I had to do something with the RequestSecurityTokenResponse (RSTR) object.  Also, how do I make this identity stick around within the application?

The next thing I decided to do was figure out how to convert the RSTR object to an IClaimsIdentity.  Unfortunately this requires a bit of XML parsing.  Talk about a pain.  Helper class it is:

public static class TokenHandler
{
    private static XNamespace ASSERTION_NAMESPACE 
= "urn:oasis:names:tc:SAML:1.0:assertion"; private const string CLAIM_VALUE_TYPE
= "http://www.w3.org/2001/XMLSchema#string"; // bit of a hack public static IClaimsPrincipal Convert(RequestSecurityTokenResponse rstr) { return new ClaimsPrincipal(GetClaimsIdentity(rstr)); } private static ClaimsIdentity GetClaimsIdentity(RequestSecurityTokenResponse rstr) { XDocument responseDoc = XDocument.Parse(rstr.RequestedSecurityToken.RawToken); XElement attStatement = responseDoc.Element(ASSERTION_NAMESPACE + "Assertion")
.Element(ASSERTION_NAMESPACE + "AttributeStatement"); var issuer = responseDoc.Root.Attribute("Issuer").Value; ClaimCollection claims = new ClaimCollection(); foreach (var c in attStatement.Elements(ASSERTION_NAMESPACE + "Attribute")) { string attrName = c.Attribute("AttributeName").Value; string attrNamespace = c.Attribute("AttributeNamespace").Value; string claimType = attrNamespace + "/" + attrName; foreach (var val in c.Elements(ASSERTION_NAMESPACE + "AttributeValue")) { claims.Add(new Claim(issuer, issuer, claimType,
val.Value, CLAIM_VALUE_TYPE)); } } return new ClaimsIdentity(claims); } }

Most of this is just breaking apart the SAML-goo.  Once I got all the SAML assertions I generated a claim for each one and created a ClaimsIdentity object.  This gets me a step closer to how I wanted things, but keeping the identity around within the application is still up in the air.  How can I keep the identity for the lifetime of the application?  I wanted something like Thread.CurrentPrincipal but the phone platform doesn’t let you access it.

There was a class, TokenCache, that was part of the original Silverlight project.  This sounded useful.  it turns out it’s Get/Add wrapper for a Dictionary<>.  It’s almost useful, but I want to be able to access this cache at any time.  A singleton sort of solves the problem, so lets try that.  I added this within the TokenCache class:

public static TokenCache Cache
{
    get
    {
        if (_cache != null)
            return _cache;

        lock (_sync)
        {
            _cache = new TokenCache();
        }

        return _cache;
    }
}

private static TokenCache _cache;
private static object _sync = new object();

 

now I can theoretically get access to the tokens at any time, but I want to make the access part of the base Application object.  I created a static class called ApplicationExtensions:

public static class ApplicationExtensions
{
    public static IClaimsPrincipal 
GetPrincipal(this Application app, string appliesTo) { if (!TokenCache.Cache.HasTokenInCache(appliesTo)) throw new ArgumentException("Token cannot be found to generate principal."); return TokenHandler.Convert(TokenCache.Cache.GetTokenFromCache(appliesTo)); } public static RequestSecurityTokenResponse
GetPrincipalToken(this Application app, string appliesTo) { return TokenCache.Cache.GetTokenFromCache(appliesTo); } public static void
SetPrincipal(this Application app, RequestSecurityTokenResponse rstr) { TokenCache.Cache.AddTokenToCache(rstr.AppliesTo.ToString(), rstr); } }

 

It adds three extension methods to the base Application object.  Now it’s sort of like Thread.CurrentPrincipal.

How does this work?  When the RSTR is returned I can call:

Application.Current.SetPrincipal(rstr);
 

Accessing the identity is two-part.

If I just want to get the identity and it’s claims I can call:

var principal = Application.Current.GetPrincipal("https://troymcclure/webapplication3/");

IClaimsIdentity ident = principal.Identity as IClaimsIdentity;
 

If I want to reuse the token as part of web service call I can get the token via:

var token = Application.Current.GetPrincipalToken(https://troymcclure/webapplication3/);
 

There is still quite a lot to do in order for this to be production ready code, but it does a pretty good job of solving all the problems I had with domain authentication on the Windows Phone 7 platform.

// About

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