Federated Authentication with Sitecore and the Windows Identity Foundation


UPDATE : There is a new version of the module here:  https://marketplace.sitecore.net/en/Modules/ADFSAuthenticator.aspx

 

Over the past few months I’ve done some work integrating Sitecore with multiple Federated Authentication systems like Ping Identity, ADFS and some home grown ones.  The way Federated Authentication works is instead of logging directly into an application the application sends the user to another system for authentication. Once that system authenticates the user an encrypted token, typically SAML, is passed back to the requesting application containing credentials and other information, known as claims.

Getting everything working with the Windows Identity Foundation proved to be more challenging than some of the other API’s I worked with. I’d like to thank Owain Jones, Kern Herskind Nightingale and Ivan Sharamok for their help and suggestions that made this all work.

Here is the source and update file for this solution. There is also this sample web.config.

Step 1: Setting up your development environment for claims based authentication.

This tutorial is already written so I’m just going to point to that. I suggest you set up a basic website and get claims Authentication working there before you go and try integrating it with Sitecore.

http://www.codeproject.com/Articles/278940/Claim-based-Authentication-and-WIF-Part-2

Step 2: Add Roles to Sitecore

Login To Sitecore and create the following roles :

Extranet/Registered Users

Sitecore/Author

Assign Sitecore Author to the Sitecore Client Authoring Role so they can login to the system.

Step 3: Modify the mock STS to send the roles

After you have completed that tutorial modify the STS project and change the code in CustomSecurityTokenService.cs that writes out the claims to include two roles that exist in your Sitecore system.

protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)

{

if (null == principal)

{

throw new ArgumentNullException("principal");

}

ClaimsIdentity outputIdentity = new ClaimsIdentity();

// Issue custom claims.

// TODO: Change the claims below to issue custom claims required by your application.

// Update the application's configuration file too to reflect new claims requirement.

outputIdentity.Claims.Add(new Claim(System.IdentityModel.Claims.ClaimTypes.Name, principal.Identity.Name));

outputIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Registered Users"));

outputIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Author"));

return outputIdentity;

}

Step 4: Install the FedAuthenticator update package.

Login to Sitecore as an admin

Browse to /sitecore/admin/updateinstallationwizard.aspx

Install the update file found here.

Step 5 : Using Visual Studio or FedUtil.exe update the web.config of your sitecore solution to point to your STS like you did in the tutorial found under Step 1.

see : http://www.codeproject.com/Articles/278940/Claim-based-Authentication-and-WIF-Part-2

Step 6: Modify the web.config file.

Under the Modules Section move the Authentication Modules so they fire after Nexus and replace the Session Module with the one in the FedAuthenticator Module.

<add type=”Sitecore.Nexus.Web.HttpModule,Sitecore.Nexus” name=”SitecoreHttpModule” />

      <addname=“WSFederationAuthenticationModule” type=”Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ preCondition=”managedHandler” />

      <addname=“SessionAuthenticationModule” type=”FedAuthenticator.Authentication.WSSessionAuthenticationModule, FedAuthenticator”/>

<add type=”Sitecore.Resources.Media.UploadWatcher, Sitecore.Kernel” name=”SitecoreUploadWatcher” />

Change the Location information inside of the web.config file so it looks like the following:

</system.webServer>

<location path=”sitecore modules/Shell/FedAuthenticator/sso.aspx”>

<system.web>

<authorization>

<deny users=”?”/>

</authorization>

</system.web>

</location>

<system.web>

<!–<authorization>

<deny users=”?” />

</authorization>–>

<!– Continue to run Sitecore without script validations –>

If you now try to hit sitecore modules/Shell/FedAuthenticator/sso.aspx the user should be logged into Sitecore with the Author Role.

Step 7: Create a secured page in Sitecore.

Under the Home Item create a new Sample Item and name it ‘secured’.

Set the permissions up to break inheritance for Extranet/Everyone then grant read access and enable enheritance for the Extranet/Register Users role.

Step 8 : Test authentication to the front end of the website.

Log out of Sitecore:

Clear your cookies to remove the pre-existing token.

Browse to http://yourwebsite/secured

You should be redirected to the STS token issuer. Once you log in you will be brought back to your website and should see the secured item.

It may be helpful to add this code to your sample layout.aspx page so you can see the users information.

<div><%=Sitecore.Context.User.Name %></div>

<div>Is Virtual? <%=Sitecore.Context.User.RuntimeSettings.IsVirtual %></div>

<div>Roles:</div>

<%

foreach (var role in Sitecore.Context.User.Roles)

{

%>

<div><%=role.Name %></div>

<%

}

%>

Code Review

Ideally this solution would have had two processors and nothing else.

The TokenRequestor looks to see if access is denied to an item and sends the user to the STS with a request for a token if the user is not already authenticated.

The UserResolver looks for a token in a cookie, if it exists and the user is not authenticated we log the user in a virtual user.

That’s all I expected to need when I first wrote this but I was having trouble persisting user information.  This led us to the Sitecore support portal and we found we needed a custom authentication provider and we had to overwrite the WSSessionModule to get this to work.

The root of the problem is three fold:

  1. Both Sitecore and the Windows Identity Foundation are fighting over the threads user identity located at HttpContext.Current.Request.User.
  2. The Windows Identity Foundation does not allow you to just request and parse a token just using the API. It forces you to use the http modules. If I could do this without the modules there would be a lot less code.  This is the approach I took when integrating Ping Identity and it was much easier but my Ping Identity code only works with Ping Identity and this solution should work with a lot of other identity providers, including Ping Identity.
  3. The Sitecore Nexus API is obfuscated and I had trouble figuring out where/when the Identity was being set.

So, now here’s all the ‘other’ code that was added to get the two systems to play nice.

WSSessionAuthenticationModule was added to prevent some of the Session overriding. The binding to PostAuthenticateRequest was removed from initialize module and we override the Authenticate Request method so it exits the method if we already have a Sitecore.Context.User.

The FederatedAuthenticationProvider was also added to get the role and user information to persist. The Forms Authentication Provider uses a cookie for saving the value but this cookie wasn’t persisting when we logged in using SSO so we read the Session Token instead inside of the GetCurrentUser method of the Authentication Helper.

The login method was also changed to not write out a forms cookie.

The sso.aspx page is being used to log in to Sitecore.  The user is assigned to the roles based on the Sitecore Domain. That is why the page currently lives under the sitecore modules folder.

Things that could use improvement

  1. Currently the user is logged in on every request when a token exists. I’d like to be able to just parse the token the first time it’s sent from the STS and log the user in once but that didn’t work out.
  2. Single Sign Out is not yet implemented.
  3. This solution is currently only supporting virtual users.
Advertisements

About Kevin Buckley
.Net web developer with a lot of experience in CMS. Currently working at Sitecore as Solutions Engineer.

10 Responses to Federated Authentication with Sitecore and the Windows Identity Foundation

  1. Great blog post. As WIF becomes part of .net 4.5 this subject will be very relevant.

  2. Pingback: Custom Clones Listing, Specialized Treelist, Fed Authenticator, Field Fallback, Image Extension and the Icon Selector « Sitecore Shared Source Weblog

  3. Pingback: Custom Clones Listing, Specialized Treelist, Fed Authenticator, Field Fallback, Image Extension and the Icon Selector | CMS News Today

  4. Ivan Sharamok says:

    Wow! This is awesome, Kevin! Thanks for putting it all together.

  5. James Walford says:

    Hi Kevin,

    Thanks for this. We’re looking at using this module, with a few tweaks. I’ve seen the VIrtual Users Group webcast you gave (unfortunately I couldn’t participate live as the time zone is a little awkward!) and have some questions.

    Firstly, would you envisage any problem with running this alongside the CRM integration module to Microsoft Dynamics? We’d like our employees verified by our AD and our customers/contacts stored in our CRM (they will be logging in to our extranet for personalised services).

    Secondly, our organisational structure means that for us it makes more sense to handle most role assignment in Sitecore itself (we’ve actually built a front end interface to do this, rather than have local administrators go into the Sitecore client to assign various pre-defined privileges). For this we’d like to persist our users in Sitecore, but verify them (and extract some minimal data – username, name, email, organisation) using ADFS. This obviously doesn’t fit with the virtual users model you use, where privileges are assigned in the AD and mapped to Sitecore roles. We also persist some personalisation details (site settings) in Sitecore for our users.

    We’re therefore looking at matching the username supplied in the token from ADFS with a concrete Sitecore user (we’ll generate one if the user isn’t found already).

    Can you see any immediate drawbacks in this?

    Thanks in advance!

    • This should work but you are correct, you should not use virtual users you should use regular sitecore users at login.

      I’m not to familar with the CRM piece but if just a membership provider it should be fine. You may just have to get the domain right at login.

  6. Ariel says:

    You rock, Kevin

  7. Joey Uhl says:

    Hello Kevin,

    The link to download the source from trac.sitecore.net appears to be broken. Could you please repost the source?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: