將使用者帳戶從 Windows 宣告移轉到 SAML 宣告

將使用者帳戶從 Windows 宣告移轉到 SAML 宣告

在我最近從事的工作中,有許多人對於從 Windows 宣告使用者開始,然後在某個點再轉換為並開始使用 SAML 宣告,表達高度的興趣。 這個想法聽起來很合理,但問題是我們沒有將帳戶從 Windows 宣告移轉到 SAML 宣告的創新方法。 好消息是在 2010 年 8 月份累計更新的攔截程序中所新增的 SharePoint 產品群組,可讓您在 MigrateUsers 方法中執行自己的自訂程式碼。 我們即將發行關於 API 的文件以及來自 Bryan P. 與 Raju S.所設計的一些優秀作品的程式碼範例,而我的範例就是根據此範例。 他們已經為新的 API (實際上是一種介面:IMigrateUserCallback) 撰寫非常完整的文件,因此我在此不再詳述。 只要我有關於此主題之新發佈資訊的連結,就會更新此文章。

因此,我將如往常從張貼我的自訂移轉類別的程式碼開始,然後我會逐步解說我覺得有趣的部分。

 

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;

     try

     {

         switch (authType)

         {

            case SPWebApplication.AuthenticationMethod.Windows:

                //code for converting from classic Windows would be here

                Debug.WriteLine(oldUser);

                break;

            case SPWebApplication.AuthenticationMethod.Claims:

                //this is the only scenario this sample will cover

                //migrating from Windows claims to SAML claims

                Debug.WriteLine(oldUser);

                //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,

                      SPIdentifierTypes.EncodedClaim);

                //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

                      //converted

                      //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 =

                                    SPClaimProviderManager.CreateUserClaim(

                                    idClaim.Value.Split('\\')[1] + "@contoso.com",

                                    SPOriginalIssuerType.TrustedProvider,

                                    SPTrustedIdentityTokenIssuerName);

                          //get the encoded value of what the new identity

                          //claim will be

                          value = migratedUserClaim.ToEncodedString();

                      }

                   }

                   else

                   {

                      //migrating a group

                      //get the plain name of the group

                      SecurityIdentifier sid =

                          new SecurityIdentifier(idClaim.Value);

                      NTAccount groupAccount =

                          (NTAccount)sid.Translate(typeof(NTAccount));

                      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("https://schemas.microsoft.com/ws/2008/06/identity/claims/role",

                             groupName.Split('\\')[1],

                             Microsoft.IdentityModel.Claims.ClaimValueTypes.String,

                      SPOriginalIssuers.Format(

                             SPOriginalIssuerType.TrustedProvider,

                             SPTrustedIdentityTokenIssuerName));

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

                          value = migratedGroupClaim.ToEncodedString();

                      }

                   }

                }

                break;

            case SPWebApplication.AuthenticationMethod.Forms:

                //code for converting from Forms would be here

                Debug.WriteLine(oldUser);

                break;

         }

     }

     catch (Exception ex)

     {

         Debug.WriteLine(ex.Message);

     }

     return value;

  }

   }

}

 

我第一件要做的事就是檢查傳入的 SPWebApplication.AuthenticationMethod 參數值。 因為我只對於轉換宣告使用者 (Windows 轉換為 SAML) 有興趣,那是我唯一要執行程式碼的情況。 當目前的使用者為宣告使用者時,我會從取得區域 SPClaimProviderManager 的參照開始,這樣我就可以取得使用者的宣告表示法。 我這樣做的目的在於判斷使用者是否為 Windows 宣告使用者、FBA 宣告使用者或是 SAML 宣告使用者。 在此例中,我只想轉換是 Windows 宣告使用者的使用者。

 

在我判斷出我具有其中一個宣告使用者後,接下來我將嘗試瞭解該宣告是適用於使用者或群組。 您可能會注意到一件很奇怪的事。 即使目前的使用者為 Windows 宣告群組,傳遞至方法中的 isGroup 參數仍然會傳回 False。 這表示我需要自行檢查,以瞭解目前的「實體」是使用者或群組。 因此我直接查看宣告值:如果該實體是使用者,將是網域\使用者的格式;否則就是 SID 格式的群組。

現在我已知道是哪一種類型的實體,即可決定需要那種類型的宣告。 若是使用者,我需要建立身分識別宣告。 我需要知道的其中一件事,是在 Web 應用程式上使用的 SPTrustedIdentityTokenIssuer 名稱。 我應該撰寫程式碼來找出該名稱,但是我覺得這只是範例,所以不想寫,轉而要求您在我的類別之建構函式中傳遞正確的名稱。 因此我採用使用者的登入名稱 (在網域部分後面),而且為了便利起見,他們的電子郵件地址一律為: loginname@contoso.com。 如果您的組織不是採用此方法,則您需要自行判斷正確的電子郵件地址。 我使用此電子郵件與上述程式碼來為該使用者建立身分識別宣告,而且這是我傳回的值:這個值是在此例中 vbtoys\darrins 帳戶將被轉換的值。 (文法糾察隊請不要求我以介系詞結束句子)

對於群組,我採用我所取得的 SID,而且我使用 NTAccount 類別來取得此群組的易記名稱。 我使用此易記名稱來建立新角色宣告,然後從此新角色宣告取得編碼的值,以做為應該移轉的群組值。 (文法糾察隊現在應該很高興了吧?!?)

還有另一件事值得在此提出:對於使用者與群組,我並未自動嘗試和移轉所有的項目。 可能有一些您不想要移轉的項目,像是服務帳戶、內建帳戶等等;您是否要移轉端視您的需求而定。 不過,這個執行移轉的方法其好處在於您可以不限次數執行此方法。 如果您只要移轉部分使用者,或是以批次執行移轉,或過一段時間執行移轉等等,都沒有問題。 例如,如果您有一個應該要移轉所有使用者的資料庫。 您可以查詢該資料庫以取得清單,然後當每個使用者呼叫您的移轉程式碼時,即可查看該使用者是否在您從資料庫取得的使用者清單中。 在此就有一個範例。

我並不想探討 Bryan 與 Raju 已經探討太多的 SDK 文件,但是我有義務至少讓您知道要如何呼叫類別,您才不會不知所措。 我所做的就是撰寫一個 Winforms 應用程式,並將專案參照新增至我上述的自訂組件中。 這使得同時建立和除錯變得極為容易。 我呼叫類別以及執行移轉所使用的程式碼如下所示:

 

//get a reference to my web application

SPWebApplication wa = ( SPWebApplication.Lookup(new Uri("https://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

wa.MigrateUsers(muc);

 

就是這麼簡單。 若要涵蓋所有的案例,此程式碼將需要更多其他的變化,但這是一個很好的開始,而目 Bryan 與 Raju 將會對此部分的程式碼增加更多的內容。

這是翻譯後的部落格文章。英文原文請參閱 Migrating User Accounts from Windows Claims to SAML Claims