Azure Active Directory の SSO 開発 (Identity and Access Tool 編)


Visual Studio 2013 を使用した SSO 開発については「Azure Active Directory の SSO 開発 (Visual Studio 2013 編)」を参照してください。(この投稿は、古い情報です。)

環境 :
Office 365 Enterprise
Windows Azure Active Directory (AAD) Developer Preview
Visual Studio 2010 (または Visual Studio 2012)
Windows Azure SDK for .NET – June 2012
Windows Identity Foundation (または Identity and Access Tool)

こんにちは。

今回は、「Azure Active Directory と事前準備」 で構築した Azure Active Directory の環境と SSO をおこなう Web アプリケーション (Relying Party, RP) を構築します。これまで、Office 365 に格納されたユーザー情報を使ってシングル サインオン (SSO) をしたいと思ってもブラックボックスでしたが、Windows Azure Active Directory と統合されると、公開された方法 (サポートされた方法) を使って、Office 365 を使っていた中小規模の企業などで Office 365 との SSO も簡単に構成できるようになります。

なお、セッションでも紹介したように、現在の Developer Preview では、Windows Azure Active Directory (AAD) の Web SSO として WS-Federation のみが提供されていますので、今回は WS-Federation (および、SAML トークン) を使用します。今後の更新情報など、是非、Watch しておいてください。
また、今回は .NET (Windows Identity Foundation) を使った手順を示しますが、前回 説明したように、Java、PHP など他言語からの利用も視野に入っています。Java、PHP を使用したサンプル コードは、WindowsAzure/azure-sdk-for-java-samples (GitHub)WindowsAzure/azure-sdk-for-php-samples (GitHub) にありますので、是非 参考にしてください。

補足 : ここで紹介する内容の前半部分は、以下に解説されています。
[Windows Azure] How to implement single sign-on with Windows Azure Active Directory – ASP.NET Application
https://www.windowsazure.com/en-us/develop/net/how-to-guides/web-sso/

 

https (SSL) によるホスト

Windows Azure Active Directory による WebSSO では、Web アプリケーション (RP) は、https (SSL) でホストする必要があります。このため下記の通り、いつもの手順で、SSL を構成します。(既にご存じの方は、ここは読み飛ばしてください。)

まず、証明書を作成します。今回は、開発用 (テスト用) の証明書を作成します。
Visual Studio コマンド プロンプトを起動し、下記の通りコマンドを入力します。この際、パスワードを入力する画面が表示されるので、任意のパスワードを入力します。(公開キーの入った .cer ファイルと、秘密キーの入った .pvk ファイル、および、証明書交換用の .pfx ファイルが作成されます。)

makecert -r -pe -n “CN=tsmatsuz-test1.cloudapp.net” -sky exchange “tsmatsuz-test1.cloudapp.net.cer” -sv “tsmatsuz-test1.cloudapp.net.pvk”
pvk2pfx -pvk “tsmatsuz-test1.cloudapp.net.pvk” -spc “tsmatsuz-test1.cloudapp.net.cer” -pfx “tsmatsuz-test1.cloudapp.net.pfx” -pi <password>

rem — なんちゃって CA の作成
makecert -r -pe -n “CN=My Root Authority” -ss CA -sr CurrentUser -a sha1 -sky signature -cy authority -sv CA.pvk CA.cer
rem — なんちゃって server 証明書の作成
makecert -pe -n “CN=tsmatsuz-test1.cloudapp.net” -a sha1 -sky Exchange -eku 1.3.6.1.5.5.7.3.1 -ic CA.cer -iv CA.pvk -sp “Microsoft RSA SChannel Cryptographic Provider” -sy 12 -sv tsmatsuz-test1.cloudapp.net.pvk tsmatsuz-test1.cloudapp.net.cer
pvk2pfx -pvk tsmatsuz-test1.cloudapp.net.pvk -spc tsmatsuz-test1.cloudapp.net.cer -pfx tsmatsuz-test1.cloudapp.net.pfx -pi <password>

Windows Azure の管理ポータルを開き、上記で作成された .pfx ファイルを Hosted Service の Certificates フォルダにアップロードします。(この際、パスワードの入力が必要です。)

ポータル上に登録された証明書を選択すると、(ポータルのプロパティ ウィンドウに) thumbprint の文字列が表示されるので、この値をコピーしておきます。

つぎに、Windows Azure に配置するプロジェクト側 (Visual Studio の Cloud プロジェクト) に、この証明書を使用するように設定します。

Visual Studio を起動し、[Windows Azure Cloud Service] のプロジェクトを新規作成します。(今回は、ASP.NET MVC 4 Web Role を追加します。)

Visual Studio の Cloud プロジェクトの Role フォルダにある Web Role のプロパティ画面を表示し、[Certificates] タブを選択して、下図の通り、証明書の設定を追加します。この際、[Name] 欄には、上記の makecert コマンドで指定した名前 (今回の場合、CN=tsmatsuz-test1.cloudapp.net) を指定し、[Thumbprint] 欄には、上記でコピーした thumbprint の文字列を設定します。

つぎに、[Endpoint] タブを選択して、下図の通り、https の Input エンドポイントを追加します。この際、[SSL Certificate Name] 欄として、上記で登録した証明書を選択します。

 

WIF による Web SSO の構成

では、Windows Azure Active Directory (今回の場合は、Office 365) との Web SSO を構成していきましょう。

この構成は、最新の .NET Framework 4.5 と Identity and Access Tool を使って構成できますが、本執筆時点で、.NET Framework 4.5 が Windows Azure の (正確には、Hosted Services の Guest OS) にまだ対応していないため、今回は、.NET Framework 4 (Visual Studio 2010) と、以前の WIF の FedUtil.exe ユーティリティを使用します。(残念ですが。。。なお、localhost に Web アプリケーションをホストするなら、VS 2012 + .NET 4.5 でも行けますのでお試しください !)

補足 : Identity and Access Tool を使用する場合は、[Use a business identity provider] を選択して、STS metadata document に、下記の metadata の Url を設定します。

まず、上記で作成した Web プロジェクトで Microsoft.IdentityModel.dll (%programfiles%\Reference Assemblies\Microsoft\Windows Identity Foundation\v3.5\Microsoft.IdentityModel.dll) を参照追加します。(さらに、追加された dll のプロパティ画面を開き、[ローカル コピー] を True に設定しておきます。)

つぎに、Web プロジェクトを右クリックして、[Add STS reference] を選択します。(下図)

前回 (Windows Azure Active Directory と事前準備) で環境構築をした際、tenant id や AppPrincipalID を取得することができました。Web アプリケーションから SSO をおこなう際は、前回取得したこれらの Id 情報を使用して接続します。

まず、表示されるダイアログで、下図の通り、[Application URI] 欄に以下のどちらかの値を設定し、[Next] ボタンを押して先に進みます。Windows Azure Active Directory のサーバーでは、この識別子を使って対象のテナントの Service Principal (前回作成したオブジェクト) に接続します。

spn:<AppPrincipalID of Service Principal>@<realm>
spn:<AppPrincipalID of Service Principal>@<tenant id>

補足 : [Next] ボタンを押すと警告 (ID1007: The application is not hosted on a secure https connection) が表示されますが、[Yes] ボタンを押して先に進んでください。

次に表示されるウィザード (画面) で、STS の path として、以下の URL を入力して [Next] ボタンを押します。

https://accounts.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml?realm=<your tenant dns>
https://login.microsoftonline.com/<your tenant dns>/federationmetadata/2007-06/federationmetadata.xml
(2013/02 変更 : こちら を参照)

例えば、Office 365 で使用しているテナントの DNS が demo.onmicrosoft.com の場合、下記の URI になります。

https://accounts.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml?realm=demo.onmicrosoft.com
https://login.microsoftonline.com/demo.onmicrosoft.com/federationmetadata/2007-06/federationmetadata.xml
(2013/02 変更 : こちら を参照)

次のウィザードで、[Disable certificate chain validation]、[No encryption] を選択して、完了します。(これにより、構成内容が、Web プロジェクトの Web.config に反映されます。)

次に、設定された Web.config の <wsFederation /> 要素に、下記 (太字) の通り、reply 属性を追加しておいてください。(従来の Windows Azure ACS を使用した場合には不要だった作業です。今回は、上記の通り Service Principal の識別子を使っているため必要です。)

<microsoft.identityModel>
  <service>
    . . .
    <federatedAuthentication>
      <wsFederation
        passiveRedirectEnabled=”true”
        issuer=”https://accounts.accesscontrol.windows.net/8efc5af6-7103-4daf-91e7-b7da07b24621/v2/wsfederation”
        issuer=”https://login.microsoftonline.com/8efc5af6-7103-4daf-91e7-b7da07b24621/v2/wsfed”
        realm=”spn:8ea2fe64-9b46-4858-a58a-85843e12abbf@8efc5af6-7103-4daf-91e7-b7da07b24621″
        requireHttps=”false”
        reply=”https://tsmatsuz-test1.cloudapp.net/”/>
      . . .

また、.NET Framework 4 以降を使用している場合は、下記の通り、Web.config に構成を追加しておきます。

. . .
<system.web>
  <httpRuntime requestValidationMode="2.0" />
  . . .

以上で、SSO の構成は完了しましたが、当然、Claim の取得も可能です。

例えば、以下では、Windows Azure Active Directory (今回の場合、Office 365) に登録されているユーザー名 (FirstName, LastName) を取得して、ページ上に表示します。

. . .
using Microsoft.IdentityModel;
using Microsoft.IdentityModel.Claims;

public ActionResult Index()
{
  string username = string.Empty;
  if(User.Identity.IsAuthenticated)
  {
    IClaimsIdentity ci = (IClaimsIdentity)this.User.Identity;
    string firstname = (from c in ci.Claims
      where c.ClaimType == @"http://schemas.xmlsoap.org/claims/FirstName"
      select c.Value).SingleOrDefault();
    string lastname = (from c in ci.Claims
      where c.ClaimType == @"http://schemas.xmlsoap.org/claims/LastName"
      select c.Value).SingleOrDefault();
    username = firstname + " " + lastname;
  }
  ViewBag.Message = "Hello ! " + username;

  return View();
}

上記の Web アプリケーションを Windows Azure に発行します。(発行方法の手順詳細は省略します。)

 

動作確認

発行した Web アプリケーションに接続すると、認証されていない状態のため、Windows Azure Active Directory に飛ばされ、最終的に下図の Office 365 の SignIn の画面が表示されます。

上図で Office 365 のテナントへのログイン ID とパスワードを入力すると、リダイレクトされて、Web アプリケーションに戻ってきます。(必要な情報が SAML トークンとして POST されます。) Web アプリケーション側では、WIF のハンドラーにより、渡された SAML トークンの検証がおこなわれ、問題なければ Web アプリケーションのページを表示します。

表示される Web アプリケーションのページでは、上記のプログラム コードの通り、渡された Claim からユーザー名などの属性情報を取得できます。(下図)

当然ですが、上記のブラウザーを使って SharePoint Online のサイト (チーム サイトなど) に遷移すると、ログイン画面 (Office 365 の SignIn 画面) は表示されず、そのまま SharePoint Online のサイトが表示されます。また、逆に、SharePoint Online のサイトにログインした後で、上記の Web アプリケーションに遷移した場合も、Office 365 の SignIn 画面は表示されず、SharePoint Online のサイトに遷移できます。

 

複数のテナント (tenant) への対応

上記の方法で 1 つ憂慮すべき点は、Service Principal を指定しているところからもお分かりの通り、特定の tenant (今回の場合、Office 365 の tenant) としか連携できないという点です。例えば、ISV が、連携製品として Web アプリケーションを提供する場合、特定の tenant しか連携できないとか、プログラムを書き換えて発行しなおす、といった状況では、とても製品として提供はできないでしょう。

こんなとき、Windows Azure Active Directory では共通の基盤を使用しているため、デモでお見せしたように、Multi-Tenant への対応も可能です。(すみません、デモを失敗したので、「デモでお見せしようと思ったように」の誤りですが  . . .)
これについては、Vittorio が「Single Sign On with Windows Azure Active Directory: a Deep Dive」で解説しています。

では、実際に、上記の認証の流れを、カスタムにプログラミングしてみてみましょう。(Multi-Tenant への対応は、下記を応用すれば、すぐに対応できます。) なお、以降の通り、現時点では、かなりの部分を自力でプログラミングする必要があるので注意してください。

まず、以降のコードを作成する前に、あらかじめ、上記で作成した Web アプリケーションのプロジェクトの Web.config を開き、下記 (太字) の通り、passive リダイレクトを抑制しておきます。(ここが true だと、認証されていない場合に強制的にリダイレクトされてしまいます。)

<microsoft.identityModel>
  <service>
    . . .
    <federatedAuthentication>
      <wsFederation
        passiveRedirectEnabled=”false”
        . . .

補足 : 認証前でもページが表示されるよう、念のため、その他の構成 (authorization 要素、authentication 要素など) も確認しておきましょう。

ページ (今回の場合、.cshtml) 上に、下記の通り、Windows Azure Active Directory (今回は Office 365) の SignIn 処理に飛ばすためのリンクを設定します。(今回は、Razor を使って記述します。)
下記で、第 1 引数 (wtrealm) は前回作成した Windows Azure Active Directory の spn を指定し、第 2 引数 (wreply) は reply されるアドレス (つまり、この Web アプリケーションの URL) を指定します。

. . .
<a href=”@string.Format(@”https://accounts.accesscontrol.windows.net/v2/wsfederation?wa=wsignin1.0&wtrealm={0}&wreply={1}”,
  HttpUtility.UrlEncode(“spn:8ea2fe64-9b46-4858-a58a-85843e12abbf@8efc5af6-7103-4daf-91e7-b7da07b24621”),
  HttpUtility.UrlEncode(@”https://tsmatsuz-test1.cloudapp.net/”))”>Log in !</a>
. . .

上記の設定で、利用者 (エンドユーザー) がこの Web アプリケーションを表示すると、いきなり Office 365 の SignIn 画面には飛ばされず、下図の通り、まず、ログインのためのリンクが表示されます。

エンドユーザー (利用者) がこのリンクをクリックすると、Windows Azure Active Directory の指定された tenant (上記の spn から tenant を識別) にログインするためのログイン画面が表示され、ログイン (SignIn) に成功すると、必要な情報を SAML トークンに設定して、上記の reply のサイト (この Web アプリケーション) に戻ってきます。

さて、WIF では、IdP が返す この SAML トークンのチェックを Saml2SecurityTokenHandler クラスがおこなっていて、このクラスは、既定では、Multi-tenancy に対応していません。
そこで、以降の手順で、このクラスを継承した独自のクラスを作成し、構成 (.config) を編集して、このカスタム クラスを使うように構成します。

まず、プロジェクトにクラスを新規作成し、カスタムな Saml2SecurityTokenHandler クラスを下記の通り実装します。

. . .
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Tokens.Saml2;
. . .

public class CustomSaml2SecurityTokenHandler
  : Saml2SecurityTokenHandler
{
  protected override void ValidateConditions(
    Saml2Conditions conditions,
    bool enforceAudienceRestriction)
  {
    // check audience myself . . .
    //base.ValidateConditions(conditions, enforceAudienceRestriction);
    base.ValidateConditions(conditions, false);

    // If enforceAudienceRestriction is true,
    //   check audience using conditions.AudienceRestrictions,
    //   and if not valid, throw an exception !
    Skip code ...
  }
}
. . .

上記の ValidateConditions メソッドで第 2 引数を false にしておくと、Audience のチェックはおこなわず、開発者自身が Audience チェックをおこなうことができます。
なお、ここを false にしない場合は、WIF が audience の確認 (今回の場合、この Web アプリケーションで使用可能な Service Principal の確認) をおこなうため、Web.config を開き、下記 (太字) の通り、許可する Audience として追加しておく必要があります。(今回は不要です。)

<microsoft.identityModel>
  <service>
    <audienceUris>
      . . .
      <add value=”spn:8ea2fe64-9b46-4858-a58a-85843e12abbf@8efc5af6-7103-4daf-91e7-b7da07b24621″ />
    </audienceUris>
    . . .

最後に、既定のハンドラーを使わず、上記で作成した CustomSaml2SecurityTokenHandler クラスをハンドラーとして使用するため、Web.config に下記の通り追記します。

. . .
<microsoft.identityModel>
  <service>
    <securityTokenHandlers>
      <remove type=”Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>
      <add type=”MvcWebRole1.CustomSaml2SecurityTokenHandler”/>
    </securityTokenHandlers>
    . . .

上記の変更で、この Web アプリケーションは、最初に構築したアプリケーション同様、Windows Azure Active Directory の tenant と Web SSO が実現できます。つまり、上記コードの通り、SSO の対象となる tenant の Service Principal の名前 (spn) さえ分かっていれば、プログラム コードを使って、動的に対象の tenant にログインさせて連携することができます。

ただし、WS-Federation を使用しているため、サーバー間で、事前に、相互の信頼関係の設定が必要ですので注意してください。具体的には、「Azure Active Directory と事前準備」 の手順で紹介したように、事前に、連携する Web アプリケーション (アドレス) を登録する必要があります。 

Comments (0)

Skip to main content