Migrating User Accounts from Windows Claims to SAML Claims

In the work I’ve been busy with lately I’ve had a lot of interest from folks that are interested in starting out as Windows claims users, and then at some point switching over and start using SAML claims.  Sounds reasonable enough, but the problem is that we don’t have an out of the box way to migrate accounts from Windows claims to SAML claims.  The good news is the SharePoint product group added in the hooks in the August 2010 CU to let you run your own custom code in the MigrateUsers method.  We have a whole document on the API coming out soon along with a code sample that was a result of some great work by Bryan P. and Raju S., and my sample is based on that.  They’ve done a very good job of documenting the new API (actually an interface – IMigrateUserCallback) so I won’t try and do that in great detail here.  As soon as I have a link to the newly published info on this I will update this posting with it.

So, as usual, I’m going to start out just by pasting in the code of my custom migration class, and then I’ll walk through the parts that I think are interesting.


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Diagnostics;

using System.Security;

using System.Security.Principal;

//add references to Microsoft.SharePoint and Microsoft.IdentityModel for these

using Microsoft.SharePoint;

using Microsoft.SharePoint.Administration;

using Microsoft.SharePoint.Administration.Claims;

using Microsoft.IdentityModel.Claims;



namespace MigrateUserSample


   public class MigrateTest : IMigrateUserCallback



       public string SPTrustedIdentityTokenIssuerName { get; set; }



       public MigrateTest(string TrustedIdentityTokenIssuerName)


          SPTrustedIdentityTokenIssuerName = TrustedIdentityTokenIssuerName;




       public string ConvertFromOldUser(string oldUser,

              SPWebApplication.AuthenticationMethod authType, bool isGroup)


          string value = string.Empty;




              switch (authType)


                 case SPWebApplication.AuthenticationMethod.Windows:

                     //code for converting from classic Windows would be here



                 case SPWebApplication.AuthenticationMethod.Claims:

                     //this is the only scenario this sample will cover

                     //migrating from Windows claims to SAML claims



                     //get the claim provider manager

                     SPClaimProviderManager cpm = SPClaimProviderManager.Local;


                     //create a claim from the identifier so we can see if the

                     //original issuer came from Windows

                     SPClaim idClaim = cpm.ConvertIdentifierToClaim(oldUser,



                     //this is a Windows claims user, and we are going to

                     //convert to a SAML claims user

                     if (idClaim.OriginalIssuer == “Windows”)


                        //windows claims users will be in the format domain\user;

                        //windows claims groups will be in the SID format

                        if (idClaim.Value.Contains(“\\”))


                           //migrating a user


                           //you will want to check the identity of the user here

                           //there may be some Windows claims accounts you don’t want to

                           //convert yet, and there will also be service accounts that

                           //are passed in that you may not want to convert either; 

                           //ideally you would just read from a data source to determine

                           //which users you should convert, and then check the identity

                           //here to see if it’s one of the users that should be



                           //in this case, I’m only converting one user – darrins

                           if (idClaim.Value == “contoso\\darrins”)


                               //I’m getting an identity claim here, grabbing the

                               //part after the “domain\”, and appending the email

                               //suffix to it, so it becomes darrins@contoso.com

                               SPClaim migratedUserClaim =


                                         idClaim.Value.Split(‘\\’)[1] + “@contoso.com”,




                               //get the encoded value of what the new identity

                               //claim will be

                               value = migratedUserClaim.ToEncodedString();





                           //migrating a group


                           //get the plain name of the group

                           SecurityIdentifier sid =

                               new SecurityIdentifier(idClaim.Value);

                           NTAccount groupAccount =



                           string groupName = groupAccount.ToString();


                           //only interested in migrating the Portal People group

                           if (groupName.ToLower() == “contoso\\portal people”)


                               //create a new role claim

                               SPClaim migratedGroupClaim =

                                  new SPClaim(http://schemas.microsoft.com/ws/2008/06/identity/claims/role”,







                               //get the encoded value of what the new role claim will be

                               value = migratedGroupClaim.ToEncodedString();






                 case SPWebApplication.AuthenticationMethod.Forms:

                     //code for converting from Forms would be here





          catch (Exception ex)





          return value;






The first thing I’m doing is checking the value of the SPWebApplication.AuthenticationMethod parameter that was passed in.  Since I’m only interested in converting claims users (Windows to SAML), that’s the only situation in which I have code to execute.  When the current user is a claims user, I start out by getting a reference to the local SPClaimProviderManager so I can get a claim representation of the user.  I do that so I can determine if the user is a Windows claim user, FBA claims user, or SAML claims user.  In my case I only want to convert users that are Windows claims users. 


After I’ve determined I have one of those, the next thing I try to figure out is whether the claim is for a user or group.  Here’s one of the weird things that you may notice.  Even when the current user is a Windows claims group, the isGroup parameter that is passed into the method returns false.  That means that I need to check myself to figure out if the current “entity” is a user or group.  So I just look at the claim value – if it’s a user, it will be in the format domain\user; otherwise it’s a group, which will be in a SID format.

Now that I know which type of entity it is, I can determine which type of claim is needed.  For a user, I need to create an identity claim.  One of the things that requires is for me to know the name of the SPTrustedIdentityTokenIssuer that is being used on the web application.  I could have written code to figure that out, but instead I went the route of “hey this is a sample, sue me for being lazy” and force you to pass in the correct name in the constructor for my class.  So I take the user’s login name (after the domain part) and for my purpose their email address will always be loginname@contoso.com.  If your organization is not that way then you’ll need your own means to determine the correct email address.  I use it with the code above to create an identity claim for that user, and that’s the value that I return – that’s what in this case, the vbtoys\darrins account will be converted to.  (grammar police don’t bug me about ending my sentence in a preposition)

For groups, I take the SID that I’ve been given and I use the NTAccount class to get the friendly name of the group.  I use that to create a new role claim, and then pull the encoded value from that as the value to which the group should be migrated.  (grammar police happy now, yes?!?)

One other thing worth noting there – for both the users and groups, I don’t automatically try and migrate everything.  There are some things you may not want to migrate, like service accounts, built in accounts, etc.; whether you will or not depends on your requirements.  What’s neat about this method of doing the migration though is that you can do it as many times as you want.  If you want migrate just a subset of users, or do it in batches, or over time, or whatever – you can do that.  For example, you might have a database that has all the users you’re supposed to migrate.  You could query that to get the list and then as each user is called in your migration code, you could check to see if it’s in the list of users you got from your database.  Just one example there.

Okay, so I don’t want to get into the SDK documentation that Bryan and Raju worked on too much, but I do feel compelled to at least let you know how your class gets invoked so I don’t leave you hanging here.  What I did was just write a winforms application and add a project reference to my custom assembly I’ve described above.  That made it extremely easy to build and debug together.  The code that I use then to invoke my class and do a migration looks something like this:


//get a reference to my web application

SPWebApplication wa = SPWebApplication.Lookup(new Uri(http://foo”));


//this is the name of my trusted identity token issuer

string SPTrustedIdentityTokenIssuerName = “ADFSProvider”;


//create an instance of the custom migrate user callback class

MigrateUserSample.MigrateTest mt =

new MigrateUserSample.MigrateTest(SPTrustedIdentityTokenIssuerName);


//create an interface reference to it

IMigrateUserCallback muc = mt as IMigrateUserCallback;


//migrate the users with it



That’s it.  There will be many other variations of this needed to cover all scenarios, but this is a pretty good start, and Bryan and Raju will be adding significantly more to this body of work.


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