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 月 CU 的挂接中添加了 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。 这意味着我需要自我检查来搞清楚当前“实体”是用户还是组。 因此我只需看一下声明值 — 采用 ___domain\user 格式的是用户,采用 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 以查看原文