Lots of folks have talked to me in the past about federating SharePoint with Windows Live. On the surface it seems like a pretty good idea – Windows Live has millions of users, everyone logs in with their email address, which is something we use a lot as an identity claim, it’s a big scalable service, and we have various instructions out there for how to do it – either directly or via ACS (Access Control Service). So why might I be so grumpy about using it with SharePoint? Well, for those of you that have tried it before you know – when you federate with Windows Live you never get a user’s email address back as a claim. All you get is a special Windows Live identifier that is called a PUID. As far as I know, “PUID” should stand for “Practically GUID”, because that’s pretty much what it looks like and about how useful it is.
For example, if you DO federate with Windows Live, how do you add someone to a site? You have to get their PUID, and then add the PUID to a SharePoint group or permission level. Do you seriously know anyone that knows what their PUID is (if you are such a person, it’s time to find something else to do with your free time). Even if you did magically happen to know what your PUID is, how useful do you think that is if you’re trying to grant users rights to different site collections? Do you really think anyone else could pick you out of a PUID lineup (or people picker, as the case may be)? Of course not! And thus my frustration with it grows.
I actually thought that we might have a shot here at a more utopian solution with ACS. ACS is really great in terms of providing out of the box hooks to several identity providers like Windows Live, Google, Yahoo, and Facebook. With Facebook they even sprinkle a little magic on it and actually use OAuth to authenticate and then return a set of SAML claims. Very cool! So why don’t they do that with Windows Live as well? Windows Live supports OAuth now so it seems like there’s an opportunity for something valuable to finally happen. Well despite wishing it were so, the ACS folks have not come to the rescue here. And therein lies the point of this preamble – I finally decided to just write one myself, and that is the point of this posting.
So why do we care about OAuth? Well, contrary to the PUID you get when federating directly with Windows Live, OAuth support in Windows Live allows you to get a LOT more information about the user, including – wait for it – their email address. So the plan of attack here is basically this:
So…all the source code is attached to this posting, but there’s still some configuration to do, and you will have to recompile the application with the app ID and secret that you get from Windows Live, but other than doing that copy and paste there really isn’t any code you need to write to get going. Now lets walk through everything you need to use it.
You will need to create a certificate that will use to sign your SAML tokens. There’s nothing special about the certificate you use to sign certificates, other than you need to make sure you have the private key for it. In my case I have Certificate Services installed in my domain so I just opened the IIS Manager and selected the option to create a Domain Certificate. I followed the wizard and before you know it I had a new certificate complete with private key. For this project, I created a certificate called livevbtoys.
As I’ll explain in the next section, when requests initially come into the STS the user is an anonymous user. In order to use that certificate to sign SAML tokens then we need to grant the IIS process access to the private key for that certificate. When an anonymous request comes in the IIS process identity is Network Service. To give it rights to the key you need to:
Note that if you don’t do this correctly, when you try running the application you may get an error that says something like “keyset does not exist”. That just means that IIS process did not have sufficient rights to the private key, so it could not use it to sign the SAML token.
Installing the application in this sense really just means creating an ASP.NET application in IIS, copying the bits, and making sure the latest version of WIF is installed. Once you get it configured and working on one server of course, you would want to add one or more additional servers to make sure you have a fault tolerant solution. But I’ll just walk through the configuration needed on the single server.
I won’t go into how you create an ASP.NET application in IIS. You can do with Visual Studio, in the IIS Manager, etc.
NOTE: If you use the code that’s provided here and just open the project in Visual Studio, it will complain about the host or site not existing. That’s because it’s using the name from my server. The easiest way to fix this is just to manually edit the WindowsLiveOauthSts.sln file and change the https values in there to ones that actually exist in your environment.
Once it’s actually created there are a few things you want to make sure you do.
That should be all of the configuration needed in IIS.
The attached zip file includes a Visual Studio 2010 project called WindowsLiveOauthSts. Once IIS is configured and you’ve updated the WindowsLiveOauthSts.sln file as describe above, you should be able to open the project successfully in Visual Studio. One of the first things you’ll need to do is to update the CLIENT_ID and CLIENT_SECRET constants in the PassiveSTS.aspx.cs class. You get these when you create a new Windows Live application. While I’m not going to cover that step-by-step (because there are folks at Windows Live who can help you with it), let me just point you to the location where you can go to create your Windows Live app: https://manage.dev.live.com/Applications/Index?wa=wsignin1.0. Also, when you create your application, make sure you set the Redirect Domain to the location where your custom STS is hosted, i.e. https://myserver.foo.com.
Now that you have your ID and secret here’s what needs to be updated in the application:
There’s one other thing worth pointing out here – in the CustomSecurityTokenService.cs file you have the option of setting a variable called enableAppliesToValidation to true and then providing a list of Urls that can use this custom STS. In my case I have chosen not to restrict it in any way, so that variable is false. If you do want to lock down your custom STS then you should change that now. Once all of these changes have been made you can recompile the application and it’s ready to go.
One other note here – I also included a sample ASP.NET application that I used for testing while I was building this. It’s in a project called LiveRP. I’m not really going to cover it in here; suffice to say it’s there if you want to try testing things out. Just remember to change the thumbprint for the STS token signing certificate as described above.
At this point everything is configured and should be working for the custom STS. The only thing left to do really is to create a new SPTrustedIdentityToken issuer in SharePoint and configure a new or existing web application to use it. There are a few things you should know about configuring the SPTrustedIdentityTokenIssuer though; I’m going to give you the PowerShell that I used to create mine and then explain it:
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\livevbtoys.cer")
New-SPTrustedRootAuthority -Name "SPS Live Token Signing Certificate" -Certificate $cert
$map = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming
$map2 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/id" -IncomingClaimTypeDisplayName "WindowsLiveID" -SameAsIncoming
$map3 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/full_name" -IncomingClaimTypeDisplayName "FullName" -SameAsIncoming
$map4 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/first_name" -IncomingClaimTypeDisplayName "FirstName" -SameAsIncoming
$map5 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/last_name" -IncomingClaimTypeDisplayName "LastName" -SameAsIncoming
$map6 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/link" -IncomingClaimTypeDisplayName "Link" -SameAsIncoming
$map7 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/gender" -IncomingClaimTypeDisplayName "Gender" -SameAsIncoming
$map8 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/locale" -IncomingClaimTypeDisplayName "Locale" -SameAsIncoming
$map9 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/updated_time" -IncomingClaimTypeDisplayName "WindowsLiveLastUpdatedTime" -SameAsIncoming
$map10 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/account" -IncomingClaimTypeDisplayName "AccountName" -SameAsIncoming
$map11 = New-SPClaimTypeMapping -IncomingClaimType "http://blogs.technet.com/b/speschka/claims/accesstoken" -IncomingClaimTypeDisplayName "WindowsLiveAccessToken" -SameAsIncoming
$realm = "https://spslive.vbtoys.com/_trust/"
$ap = New-SPTrustedIdentityTokenIssuer -Name "SpsLive" -Description "Window Live oAuth Identity Provider for SAML" -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map,$map2,$map3,$map4,$map5,$map6,$map7,$map8,$map9,$map10,$map11 -SignInUrl "https://spr200.vbtoys.com/WindowsLiveOauthSts/PassiveSTS.aspx" -IdentifierClaim "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
Here are the things worth noting:
That’s pretty much it – once it’s set up you are still using the out of the box people picker and claims providers so you won’t have any lookup capabilities, as you would expect. You grant rights to people with the email addresses that they use to sign into Windows Live. You could actually extend this example and also use the Azure claims provider I blogged about here: http://blogs.technet.com/b/speschka/archive/2012/02/11/the-azure-custom-claim-provider-for-sharepoint-project-part-1.aspx. That means you would be using this STS to enable you to authenticate with Windows Live and get some real SAML claims back, and then using the Azure custom claims provider project to add those authenticated users into your Azure directory store and the people picker to choose them.
The pictures tell it all, so here’s what it looks like when you first hit the SharePoint site and authenticate with Windows Live:
When you first sign in it will ask you if it’s okay to share your information with the custom STS application. There’s nothing to concerned with here – that’s standard OAuth permissions happening. Here’s what that looks like; note that it shows the data I’m asking for in the STS – you could ask for an entirely different set of data if you wanted. You just need to look at the Window Live OAuth SDK to figure out what you need to change and how:
Once you accept, you get redirected back to the SharePoint site. In this example I am using the SharePoint Claims web part I blogged about here: http://blogs.technet.com/b/speschka/archive/2010/02/13/figuring-out-what-claims-you-have-in-sharepoint-2010.aspx. You can see all the claims I got from Windows Live via OAuth that I now have as SAML claims thanks to my custom STS, as well as the fact that I’m signed in with my Windows Live email address that I created for this project (from the sign in control, top right corner):
This is very timely and useful. People have asked me about the usefulness about the ACS based solution.
I too didn't have a very good answer to the PUID issue.
Given that the PUID is almost useless in the real world, perhaps it's time that ACS used OAuth with it's existing Windows Live support, so that instead of having to have a separate membership provider for Windows Live, you can just tick the Windows Live box in ACS and use a single trusted auth provider for FaceBook, WindowsLive, Google and Yahoo? How hard can it be?
As an alternative, you can also take a look at SocialConnekt for SharePoint (socialconnekt.codeplex.com), with which you can not only integrate Windows LiveID as an authentication mechanism (as Steve does, not as ACS), but also Yahoo and Facebook. The code source for the OAuth Windows LiveID provider can also be leveraged to develop other social authentication provider such as LinkedIn, Twitter, etc and plug them into the SocialConnekt Identity Server.
i'm a girl and my real name is Jayla Johnson and is steve a boy or a girl because i think he is a boy... am i right is he a boy...or am i wrong and he i (quote) she a girl? *wierd freaking out noises*
Great blog and brilliant solution to a very annoying problem!
I hope you don't mind that I heavily referenced your solution in my own blog "SharePoint hosted Apps with SAML authentication" (nearbaseline.com.au/blog) leveraging your solution to solve that particular problem in SharePoint 2013.
Let me know if you have a problem with me redistributing sections (only) of your code.
No problem @Martin, I post to share. :-)
One small change due to recent Microsoft changes - at or about line 111 of PassiveSTS.aspx.cs, you need to be more specific in the string parsing:
int startInt = token.IndexOf("access_token\":") + 14 + 1; //start after the quotes
this is because you now can get back more than one field in the JSON response and access_token may not be the first one.
I get an error after I want to login with Live ID....
I redirect to the right site - but there is this error:
Compiler Error Message: CS0246: The type or namespace name 'CustomSecurityTokenService' could not be found (are you missing a using directive or an assembly reference?)
May someone can help me?
The action '' (Request.QueryString['wa']) is unexpected. Expected actions are: 'wsignin1.0' or 'wsignout1.0'.