Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
將使用者帳戶從 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