Saturday, April 23, 2016

Microsoft 70-486: Design and implement claims-based authentication across federated identity stores

Exam Objectives


Implement federated authentication by using Azure Access Control Service; create a custom security token by using Windows Identity Foundation; handle token formats (for example, oAuth, OpenID, Microsoft Account, Google, Twitter, and Facebook) for SAML and SWT tokens

Quick Overview of Training Materials


Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications - Objective 5.3
MSDN - A Guide to Claims-Based Identity and Access Control (2e)
MSDN - Windows Identity Foundation
MSDN - How to Authenticate with Azure Active Directory Access Control
MSDN - ACS How To's
MSDN - WIF Code Sample Index
Google Identity Platform - OpenID Connect
Federate with Windows Live using OAuth and SAML
Facebook Developer Console
Google Developer Console
Using Windows Azure ACS in MVC 5 Application Using VS 2013
Write a custom security token and handler in WIF
PluralSight - Windows Azure Access Control Service (a bit dated, but not bad)
PluralSight - Claims-based Identity for Windows: The Big Picture (Paid)
PluralSight - Identity and Access Control in ASP.NET 4.5 (Paid)
PluralSight - Introduction to Identity and Access Control in .NET 4.5 (Paid)
Dominik Baier - Claims and Tokens become the standard Model (Video)

Consolidated Code Samples on GitHub

Setting up Claims-Based Identity examples


The code samples that come with A Guide to Claims-Based Identity and Access Control (2e) provide working samples of many of the concepts relevant to setting up claims based identity and identity federation, including working with Azure Access Control Service (ACS).  But the aging code and the complexity of the subject made the process more difficult than the typical "Download, build, enjoy" cycle I'd been heretofore spoiled with.  This code made me work for it, but the payoff was worth it.

The project was originally set up in Visual Studio 2010 to use a full IIS install, but fortunately the migration from 2010 to 2013 and from IIS Web Server to IIS Express was automatic.  I imagine 2012 and 2015 are just as painless.  I did run into an issue migrating the f-Shipping project in module 3, because it is an MVC2 project.  Luckily StackOverflow provided an answer on how to get it opened, and it ran fine after that.



The applications are already configured to use certificates included in the demo files, but they have to be installed in the local machine for them to be used (this was all new territory for me when I started).   I learned this the hard way when I got a "Cannot find the X.509 cert" error the first time I tried to run them. They can be installed by the Dependency Checker tool that comes with the project files.

The projects themselves also have to be reconfigured a bit:
  • SSL Enabled = True (Url Scheme error)
  • Change project Url (requires running VS as Administrator): Right click on project, Properties => Web => Project Url = https://localhost/<project name>  (StackOverflow)




To use ssl without specifying a port, we have to bind an IIS cert to port 443 (source):
  • use "netsh http show sslcert > c:\ssl.txt" to grab the existing certs (44300-44399)
  • use "netsh http add sslcert ipport=0.0.0.0:443 certhash=<your cert hash> appid=<your app id with curly braces>" to bind the certificate
Hanselman also has a post that was helpful: Working with SSL.  Note that you MUST run Visual Studio as an administrator, or the https version of the application won't load and you'll get a "Connection Refused" error.  

The federation sample (6-FederationAndAcs) was tricky but ultimately very useful for learning how all the federation pieces fit together.  Once I figured out what actually needed to be changed, it wasn't much configuration to get an ACS service up and running.  I wasn't ever able to get Google to work as an identity provider, but it seems the issues I was having is something between ACS and Google and I'm not the only one.  But Facebook and Windows Live Id both worked as expected.  The How-To's article on MSDN has useful links to details instructions on the individual components, the overall process went something like this:

  • Create a new ACS namespace in Azure.  It's under Active Directory in the management console (manage.windowsazure.com), The first screen is directories, and the second is Access Control Namespaces.  The link will take you to a separate management console just for ACS.
  • Add identity providers.  Windows Live is preconfigured.  Facebook and Google require a Client Id and Client Secret, which come from their respective developer consoles.
  • Add a relying party.  For this sample, "name" can be whatever (I used "adatum"), Realm is the federation provider ("https://localhost/Adatum.FederationProvider.6/"), return url is the token processing page ("https://localhost/Adatum.FederationProvider.6/Federation.aspx").  I left the token format as SAML 2.0
  • ACS needs to sign the tokens with a certificate known to the Federation Provider.  I used the one for localhost (access MMC, Certificates, Personal, and export to a .pfx file).  Upload the certificate to ACS under the relying party, and include the thumbprint in the Web.config file under the <IssuerNameRegistry> element (as a "trusted issuer")
  • Configure claim rules under "Rule Groups".  
I did get a weird exception once: "ID4148: The Saml2SecurityToken is rejected because the SAML2:Assertion's NotOnOrAfter condition is not satisfied."  Turned out it was because the system clock was not set right.  When I duel boot into Linux, it resets the clock, then when I get back into Windows it's always off by like 7 hours.  Once the clock was set correctly, no more exception.

Nothing I tried helped with getting Google working as an Identity Provider.  I'm no longer getting the super vague "HTTP Response 500 something broke" message, now I just get this equally helpful bullshit:

I don't know if the problem is with Google (sending back the wrong stuff somehow) or with ACS (not processing what Google gives them correctly). Or maybe something is configured wrong, I don't know, because their aren't a whole lot that needs to be configured. The other two providers work fine so, guess I'll just avoid Google for now.  Which really sucks, because my current employer is all Google and this would be a total dealbreaker for them adopting ACS. Dammit...

I forgot to enable the "Google+ API" on the Google side of things, and the unhelpfulness of the error messages didn't make figuring it out any easier.  I enabled the API and got the same damn error for a while after, apparently it takes some time to propagate those kinds of changes.  After a while, though, I did FINALLY see a successful Google log in, whoohoo! Maybe if I'd fully read the instructions to begin with, I wouldn't have struggled with it so badly. It doesn't help that other versions of the instructions are so out of date...


Windows Live ID is preconfigured already in Azure ACS as a provider, so there was nothing to do to make that work.  Facebook was pretty easy to set up, only needed to follow the instruction.  Apparently Facebook hasn't changed enough in the last five years to give ACS any grief.

Module 7 deals with integrating multiple partner IdP's with ACS.  I managed to get every piece working except logout.  Something about the way IIS Express is configured, I keep getting this stupid error:


I tried changing the enabled authentication options, both through Visual Studio and through the IIS Express config file.  Tried giving the ANONYMOUS LOGON user account full rights to the project directory.  Even created a dummy user account and enabling "basic authentication".  Nothing behaved the way it was supposed to.  Cookies kept getting super donked up too, which just added to the frustration.  Finally decided to cut my losses and move on.

... ok so I couldn't move on, and I think I figured it out.  So stupid... return URL in ACS needed to have "FederationResult" appended to the end.  Was poking around the setup program and figured it out.  Shakin my damn head...


The last piece of the "Federating with Multiple Partners and ACS" module was the enrollment of new partners.  I kept getting a "WebException: (400) Bad Request" exception, with a status of "ProtocolError".  Turned out I didn't provide the right password for the management service account.  I tried to add a partner with a social IdP but it blew up and I'm way past done with this module lol.  On the plus side, it means that the ACS Setup project probably works fine... just needs the right credentials.


Using ACS in new VS 2012/13 projects


The MSDN article How to Authenticate with Azure Active Directory Access Control explains how you would create a new relying app in Visual Studio 2012 using the Identity and Access Tool, and the blog post Using Windows Azure ACS in MVC 5 Application Using VS 2013 explains how to do it in Visual Studio 2013 (and, presumably, beyond).  The two approaches are different because after VS 2012, most of the capabilities of the Identity and Access Tool were baked into the framework (but not quite all of them...).

I was able to get an instance of the "Elegant" approach in VS 2013 working with relatively little trouble, just had to address a crypto issue (solution described on Stack Overflow).  Setting up ACS was dead simple, just added a relying party with a "realm" equal to https://localhost:44301/, add Google as the IdP, and generate the default passthrough claim rules, and BAM, working auth.  My wife happened to have her account already logged on, so she's the lucky winner for this screenshot:



The version in Visual Studio 2012 was basically the same deal.  One big plus of using the identity tools was that, after supplying the management service password, VS will configure the Relying Party and transform rules for you.  I still got the same weird crypto exception, and solved it the same way.  Also got quite a bit of complaining about which frameworks weren't configured in the project or the web server (IIS Express), but ultimately it wasn't that difficult it working:


I thought the quickie page he cooked up to display the claims was kind of cool as well:



Federated Authentication with Azure ACS


So after slogging through the various tutorials and demos on claims based identity, identity federation, ACS, WIF, and whatnot, I think I have a decent handle on how this works.  I think a couple of quick definition will be helpful here:

  • user, principal, client - the person using the application, generally with a web browser. 
  • relying party (RP) - this is the application that is using claims for authentication
  • identity provider (IdP) - this is the service creating the claims for the user, stipulating a collection of attributes about that user.  Sometimes called a Security Token Service (STS)
  • federation provider (FP)- a service that acts as a liaison between a relying party and one or more identity providers.  ACS is a federation provider.  FPs take in claims returned by an IdP, transform them, and return the transformed claims to the RP.
I see the little box and line drawing in every article on the subject, and I'll include one too, but I think seeing the actual traffic produced by the login process is as illustrative as anything.  In the Claims Guide module 7 example, this is the process when we click on "Adatum" in the Fabrikam Shipping landing page:

  1. user clicks on "Adatum", but is not authenticated (no cookies), so they are redirected to ACS
  2. the application has set a number of query string parameters:
    • wa - "action", in this case "wsignin1.0"
    • wtrealm - identifies which relying party is applicable
    • wctx - context
  3. which identity provider to use is configured in ACS.  In this case there is only one IdP, so ACS redirects straight to it (the simulated issuer for Adatum on localhost).  A reply url is included in the query string.
  4. the request is redirected to SimulatedWindowsAuthentication.aspx, which pretends to get claims from AD.  
  5. the claims are posted back to ACS using the "reply" url from 3.  These claims are specific to the IdP and may not be what the relying party (Fabrikam) understands.
  6. the claims are transformed into claims the RP expects and posted to the url configured for the RP in ACS.  The user is logged in and given authorization based on these claims.
  7. the user proceeds to their destination, now with authentication cookies.


I used the code for module 6 to demonstrate using Google as the IdP.  The process is similar:

  1. user is unauthenticated
    1a. home realm discovery.  Unlike the version in module 7, this one doesn't have a built in mechanism to know which IdP to use.  Select "Google" and proceed to ACS
  2. ACS redirects user to chosen IdP, in this case Google
  3. 3 and 4 are all about the IdP.  Google asks me to choose and account (I have three on this machine), and log in.  If I needed to approve of scopes, that would also appear in the process.
  4. browser is redirected back to ACS. Google returns openid info in the query string (rather than a POST body as above).  ACS parses and transforms the openid claims into claims the RP understands.
  5. The claims are posted to the reply url configured in ACS
  6. user is logged in and redirected to the resource they requested originally.

And here is the obligatory diagram:


Configuring the IdP in ACS is pretty straightforward.  WS-Federation based IdP's (like those for Litware and Adatum in the Guide) are just a matter of picking a name, uploading the FederationMetadata.xml, and ensuring you are using the right signing certificate.  Google and Facebook are just a matter of adding the client id and client secret (and remember to enable the Google+ API in the Google Developer Console).  The ACS How To's include detailed instructions on setting them up.

The key elements to configuring the relying party application (RP) is the realm and the return url.  The realm is the unique identifier for the RP.  When the RP calls ACS for authentication, it will pass this value as the wtrealm parameter.  The return url is where the claims are posted.  This will be the part of your application that can process the claims and log in the user.


Create custom token with WIF


To create a custom token and handler using WIF, I'm following the walkthrough I found on MSDN.  For this exercise, I decided to start with my existing projects and tweak them for the desired result.  The main thing was that I didn't want to have to create a lot of infrastructure just to fire the custom token (to test the handler), but I still wanted a realistic workflow.  So I took the module 1 code from the Guide for Single Sign On and figured out the seams where I could inject my custom token.

The code behind for "SimulatedWindowsAuthentication.aspx" has a method "HandleSignInRequest" that does just that.  It was calling WIF code to generate the token, but I was able to bogart the process and use my own token instead of the SAML2 token the framework would have created.  One thing to note, in the walkthrough he says the custom token was "wrapped within a WS-Trust 1.3 envelope" but didn't really explain what that meant.  Basically, it just means that the custom token xml he provides needs to go in the <trust:RequestedSecurityToken> element.

[2 days later]
So, after spending the better part of my weekend dicking around with this shit, I've decided to cut my loses, share what I learned and move on.  This is about to make blood shoot out of my eyes.

I was able to apply most of what he says to do in the walkthrough.  The STS was returning the custom token, it was being validated, all that was great.  But the user wasn't being logged in.  I'm sure it's something I didn't configure, some method I didn't override.  But no matter what I tried, I ran into the same thing: The claims were parsed but the user was being kicked back to the STS every time.  There were actually two places that contained the logic for returning the token, so if I only modified the first one, the second one would return the old SAML token and the user would be authenticated.

It certainly didn't help that IIS Express was acting flakey as hell...

When I finally got too frustrated with that monkey business I switched gears and tried to exactly recreate what he does for the walkthrough, but he gives no info on what he does with his fake STS so that was another quick dead end.

The last thing I tried was to look through the WIF SDK for an example, and voila! There it was.  Simple console app with a WCF echo service but hey, if it would work I'd be happy.  Unfortunately, I was never able to get it work right.  I kept getting hung up on certificate issues.  I'm not often one to admit defeat but I think the value in thrashing on this is rapidly diminishing.  So... moving on.

[30 minutes later...]
So I was working on the next section, and stumbled on yet more sample code for WIF while looking for a SWT token handler.  And wouldn't you know it, this one actually works.  Looks like they adapted the console application into a MVC3 project.  You enter a username and password and get a SWT token back with your claims. Cool. Here are the demo page and the underlying token xml:



My git repo is getting a bit jumbled, I may need to reorganize.  The above sample is in the "WIF Samples/Custom Token" directory, or you can get it directly from MSDN: WIF Code Sample Index.


Handle token formats for SAML and SWT


WIF handles a number of token formats out of the box, here is a list of the subclasses of "SecurityTokenHandler" to give you an idea:
SAML2 is used by ACS, so I saw plenty of that while working through the federation demos.  For other token formats, you would have to create a custom handler... good luck with that.  I think I've thoroughly beat this subject to death...



No comments:

Post a Comment