將使用者帳戶從 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