ユーザー アカウントを Windows クレームから SAML クレームに移行する
ユーザー アカウントを Windows クレームから SAML クレームに移行する
最近、忙しい仕事の合間に、興味深いことがありました。それというのも、Windows クレームから始めたユーザーが SAML クレームの使用に切り替えようとしている話です。 切り替えること自体はもっともな話ですが、1 つだけ問題があります。それは、アカウントを Windows クレームから SAML クレームに移行する標準的な方法がないということです。 幸いにも、SharePoint 製品グループは 2010 年 8 月の CU でフックを追加して、MigrateUsers メソッドでユーザーのカスタム コードを実行できるようにしました。 この API のドキュメント全編と付属のコード サンプルをまもなく入手できます。このサンプルは Bryan P. と Raju S. の両氏に寄るもので、私のサンプルはそれを基にしています。 両氏は新しい API (実際には IMigrateUserCallback というインターフェイス) について、とても充実した内容のドキュメントを執筆しているので、ここではその API については詳しく説明しません。 新しい公開情報へのリンクができ次第、この投稿を更新します。
それでは、いつものように、まず、自作の移行クラスのコードを貼り付けます。その後で、注目して欲しい点についていくつか説明します。
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 クレーム ユーザーのみを変換します。
いずれのクレーム ユーザーであるかを特定できたら、次は、クレームがユーザー用またはグループ用のどちらであるかを調べます。 ただし、通常とは異なる点が 1 つあります。 それは、現在のユーザーが Windows クレーム グループであっても、このメソッドに渡される isGroup パラメーターは false を返すということです。 つまり、現在の "エンティティ" がユーザーまたはグループのどちらであるかの確認は自分で行う必要があります。 したがって、クレーム値を調べて、それがユーザーであれば、ドメイン\ユーザー形式に、そうでなければグループで、SID 形式にします。
エンティティの種類がわかれば、必要なクレームの種類がわかります。 ユーザーの場合は、ID クレームを作成する必要があります。 ここで 1 つ必要な処理として、Web アプリケーションで使用されている SPTrustedIdentityTokenIssuer の名前を把握する必要があります。 その名前を取得するコードも書こうと思えば書けますが、サンプルでそこまでする必要はないと思うので、このクラスのコンストラクターに正しい名前を強制的に渡すことにします。 そこで、ユーザーのログイン名 (ドメイン名の後に続く部分) を受け取ります。今回、電子メール アドレスは常に <loginname@contoso.com> です。 読者の皆様はそれぞれの組織に合わせて、適切な電子メール アドレスにしてください。 これを上記のコードで使用して、ユーザーの ID クレームを作成します。これが戻り値になります。つまり、この例では vbtoys\darrins アカウントが変換されます。 (文章を事前に終了したことが文章校正機能で検出されません)。
グループの場合は、付与された SID を受け取って、NTAccount クラスを使用してグループのフレンドリ名を取得します。 その名前を使用して新しい役割クレームを作成し、そこからエンコードされた値をグループの移行先として取得します。 (文章校正機能が実行されていない?!?)
もう 1 つ注意する点があります。それは、ユーザーの場合もグループの場合も、すべての要素を自動的に移行するわけではないということです。 場合によっては移行しないものもあります。サービス アカウントや、ビルトイン アカウントなどがそうです。移行するかしないかは個々の要件によって異なります。 ただし、この移行メソッドの優れている点は、必要に応じて何回でも移行を実行できることです。 ユーザーのサブセットだけを移行することも、サブセットをまとめて一括で移行することも、時間と共に徐々に移行することも、その他どのような方法で移行することもできます。 たとえば、データベースに含まれるユーザーをすべて移行するとします。 この場合、データベースをクエリしてユーザーのリストを取得します。次に、各ユーザーを移行コードで呼び出すたびに、そのユーザーがデータベースから取得したユーザーのリストに含まれているかどうかを調べます。 もちろん、これは 1 つの例です。
Bryan と Raju の両氏が執筆した SDK ドキュメントについては深く触れませんが、どうしてもクラスの呼び出し方についてだけは説明しようと思います。そうでないと、このままでは中途半端です。 今回、私は WinForm アプリケーションのコードを記述して、前述のようにカスタム アセンブリのプロジェクト参照を追加しました。 これによって、ビルドもデバッグも非常に簡単に行えるようになりました。 その後、次のようなコードを使用して、クラスを呼び出して移行を行います。
//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」をご覧ください。