Dynamics CRM 2011 : カスタム ASPX ページとのシングルサインオン


みなさん、こんにちは。

今日は開発者向けの内容として、カスタム ASPX ページからの
シングルサインオンのサンプル解説をお届けします。

概要

Microsoft Dynamics CRM 2011 では ISV フォルダ配下のカスタム
ASPX ページをサポートしないため、カスタム ASPX ページは別途
カスタム Web サイトに配置する必要があります。

Windows 統合認証を利用する場合問題ありませんが、クレーム
認証を利用する場合、Microsoft Dynamics CRM 2011 とカスタム
Web サイト間のシングルサインオンを行うためには工夫が必要です。

チュートリアルのコード解説

SDK には上記シナリオをカバーするチュートリアルが提供されて
いますが、今回はその詳細を解説します。チュートリアルにある
手順はすべて完了しており、コードも動作していることとします。

Default.aspx.cs ファイル

チュートリアルで提供されるサンプルのトップページにアクセスすると
Default.aspx.cs ファイルの Page_Load が呼ばれます。このコード
では一番初めに以下のコードでクレームの取得を試みます。

IClaimsIdentity claimsIdentity = ((IClaimsPrincipal)(Thread.CurrentPrincipal)).Identities[0];

この時点でアプリケーションは設定した AD FS 2.0 にクライアントを
リダイレクトします。クライアントは AD FS 2.0 に対して認証を終えた後
アプリケーションにクレームを提供します。

次に LINQ クエリを利用してクレームより UPN を取得します。

string upn = (from c in claimsIdentity.Claims
                                where c.ClaimType == System.IdentityModel.Claims.ClaimTypes.Upn
                                select c.Value).FirstOrDefault();

その次のコードで Microsoft Dynamics CRM  2011 の組織サービス
を作成するために、CrmConnect クラスをインスタンス化しています。
ここで重要なポイントは画面にアクセスしているユーザーの権限を
利用してサービスを作成しているのではなく、コードに埋め込まれた
ユーザー情報を利用してサービスを作成している点です。必ず
利用したい組織の IFD アドレスを利用してください。

CrmConnect crmConnect = new CrmConnect(
                new Uri(“<IFD 組織サービス URL>”),
                new Uri(“<IFD 探索サービス URL>”),             
                “<CRM ユーザー名>”,
                “<パスワード>”);

最後に DoCrmStuff メソッドを呼び出し、引数に UPN を渡します。

CrmInfo loggedInUser = crmConnect.DoCrmStuff(upn);

CRMConnect.cs ファイル

コンストラクタ部分で組織サービスを作成しています。ここで利用
される認証情報は、コードに埋め込まれたユーザー情報です。

DoCrmStuff メソッド

一番初めに WhoAmIRequest を実行しています。これは画面に
アクセスしているユーザーを確認しているわけではなく、組織サービス
作成用に埋め込まれたユーザーの情報を取得しています。
また取得している内容はユーザーの ID ではなく、組織 ID です。

Guid orgId = ((WhoAmIResponse)_orgServiceProxy.Execute(new WhoAmIRequest())).OrganizationId;

次のコードで、画面にアクセスしているユーザーの情報を、UPN を
利用して取得しています。最後に取得した userId が、現在画面に
アクセスしているユーザーの systemuserId です。

RetrieveUserIdByExternalIdRequest request = new RetrieveUserIdByExternalIdRequest();
request.ExternalId = “C:” + upn;
request.OrganizationId = orgId;

RetrieveUserIdByExternalIdResponse response = (RetrieveUserIdByExternalIdResponse)_discServiceProxy.Execute(request);
Guid userId = response.UserId;

次のコードでは、取得した ID を利用して、画面にアクセスしている
ユーザーの部署 ID を取得します。これはサンプルのため全列を
取得していますが、実際には必要最小限の列だけ取得してください。
この部署 ID は画面に結果を出すためだけに利用されます。

Entity su = _orgServiceProxy.Retrieve(“systemuser”, userId, new ColumnSet(true));
EntityReference bizRef = (EntityReference)su[“businessunitid”];
Guid bizId = bizRef.Id;

次のコードでは組織サービスの CallerId を設定することで偽装を
行っています。これによりハードコードされた資格情報ではなく、
画面にアクセスしているユーザーの資格情報で組織サービスを
実行しています。

// 取引先企業レコードクラスの生成
Entity account = new Entity();
account.LogicalName = “account”;
account[“name”] = “On Behalf ” + DateTime.Now.ToLongTimeString();

// 現在の CallerId の保存。ハードコードされた資格情報です。
Guid originalCallerId = _orgServiceProxy.CallerId;
// 画面にアクセスしているユーザーの ID を CallerId に設定。
_orgServiceProxy.CallerId = userId;

// 取引先企業レコードの作成
Guid accountId;
try
{
    accountId = _orgServiceProxy.Create(account);
}
finally
{
    // CallerId を元に戻す
    _orgServiceProxy.CallerId = originalCallerId;
}

まとめ

シングルサインオンを考えた場合、現在アクセスしているユーザーの
認証情報をどのように渡すかを考えがちですが、このサンプルでは
ユーザーの認証情報を利用せずに組織サービスを生成し、呼び出す
箇所で偽装を利用することにより、目的を達成しています。

ただし、先に Microsoft Dynamics CRM 2011 で認証されていても
カスタム ASPX ページにアクセスした際 AD FS 2.0 にリダイレクト
される点が重要です。ここで同じ AD FS 2.0 を利用しておくことで
ユーザーが認証情報を再度入力する必要がなくなります。

‐ Dynamics CRM サポート 中村 憲一郎

Comments (8)

  1. Kata より:

    いつも参考にさせていただいています。

    この内容はDynamicsCRM 2013ではサポートされないのでしょうか。

    最新のSDKのサンプルコードには含まれていないようです。

  2. コメントありがとうございます。

    ISV フォルダは Microsoft Dynamics CRM 2013 以降サポートされないため、Web リソースをご利用いただくか、完全に新規に Web サイトを立てた連携が必要となります。Web サイトを分ける場合ドメイン名も異なりますので、Web リソースの利用をまずはご検討ください。

    尚、Web リソースでは HTML と Silverlight がサポートされますが、Aspx ページはサポートされてませんのでご注意ください。

    中村 憲一郎

  3. Kata より:

    ご回答ありがとうございます。

    2013以降はサポートされていないのですね。

    Webリソースでログインユーザを取得する方法を検討いたします。

  4. コメントありがとうございます。

    Web リソースでは HTML、Silverlight ともに GetGlobalContext を利用して実行コンテキストを取得することで、現在のユーザーやロールなどが取得できます。ご参考まで。

    msdn.microsoft.com/…/gg328541(v=crm.6).aspx

    blogs.msdn.com/…/dynamics-crm-2011-silverlight-web-resource-for-multi-org.aspx

    中村 憲一郎

  5. Kata より:

    ありがとうございます。

    ご提示いただいたサイトを参考に、HTMLで実行コンテキストを取得しようとしていましたが、

    以下の箇所でうまく取得できませんでした。

     if (typeof Xrm != "undefined")

    Xrmがundefinedになってしまうのですが、「ClientGlobalContext.js.aspx」の参照以外に必要な設定があるのでしょうか。

    お忙しいところ度々恐れ入りますが、お心当たりがありましたらご教示いただけないでしょうか。

  6. Takaya Kawano より:

    コメントいただきありがとうございます。

    SDK で参考となりそうなサンプルコードをご紹介します。

    blogs.msdn.com/…/dynamics-crm-2011-rest-jscript.aspx

    こちらのソリューションをインポートいただき、

    登録されたHTMLファイルを表示して、「Start」ボタンが正常に動作するかご確認ください。

    サンプルコードが正常に動作する場合、オリジナルのソースと比較ください。

    サンプルコードでも動作しない場合、HTML を表示する際の URL が適切かご確認ください。

    – 河野 高也

  7. Kata より:

    ご回答ありがとうございます。

    Xrm.Pageを指定する際に「window.parent」が無いため取得できませんでした。

    上記記載したら正常にユーザ情報を取得できました。

    お手数をおかけいたしました。

    今後も様々なページを参考にさせていただきます。

  8. Takaya Kawano より:

    解決されたとのこと、安心いたしました。

    今後もみなさんのお役に立てるような情報を配信していきますので

    是非コメントいただければと思います。

    – 河野 高也

Skip to main content