2015年2月26日木曜日

[AADSync]新バージョンがリリース(1.0.485.0222)

新しいバージョン(1.0.485.0222)がリリースされています。

今回のアップデートでは以下が更新されています。
  • Password Sync honors the cloudFiltered attribute used by attribute filtering. Filtered objects will no longer be in scope for password synchronization.
  • In rare situations where the topology had very many domain controllers, password sync doesn't work.
  • "Stopped-server" when importing from the Azure AD Connector after device management has been enabled in Azure AD/Intune.
  • Joining Foreign Security Principals (FSPs) from multiple domains in same forest causes an ambiguous-join error.
特に大きな機能追加もなく、不具合修正が中心ですね。

残念ながら今回もAzure Active DirectoryからオンプレADへのDevice情報の書き戻しもサポートされません。(AzureADのDevice Registration ServiceがAndroidをサポートしたので、この機能が一番欲しいです。まだDirSyncを手放せない最大の理由です)





2015年2月7日土曜日

[Windows10/AAD]クラウド・ドメイン参加を試す

Windows 10からの新機能としてAzure Active Directory(AzureAD)のアカウントでPCにログインできる「クラウド・ドメイン参加(Cloud Domain Join)」があります。

先日リリースされたTechnical Preview Build 9926からクラウド・ドメイン参加が出来るようになっている様なので試してみます。

◆準備事項
 クラウド・ドメイン参加するためには、AzureADのテナント側で「デバイスの登録(Device Registration)」を有効にしておく必要があります。
 管理ポータルからAzureADの構成メニューを開き、デバイスの登録より「ワークプレース参加の有効化」を行います。


◆PC側の設定
 早速設定していきます。
 PCのキッティング時(OOBE)からAzureADアカウントでログインさせることも可能らしいのですが、何故かうまく行かなかったので、一旦別のマイクロソフトアカウントでPCにログインします。
 スタートメニューから[Settings]を開き、[システム]、[バージョン情報]の順で画面を開きます。



すると、[クラウドに接続する]というリンクが存在するので、迷わずクリックすると「クラウド体験ホスト」というウィンドウが起動してきます。

しばらくするとサインイン画面になります。


ここでおもむろにAzureADのアカウント(onmicrosoft.comのアカウント)を入れると、見慣れたAzureADのサインイン画面が表示されます。


正常にサインインしたら、クラウド体験ホストを閉じてPCを再起動します。

PCが起動してきたらサインイン画面で「別のユーザ」を選択します。

「他のユーザ」を選択するとAzureADへのサインイン画面となるのでAzureADのIDとパスワードを入力してサインインします。


うまく行くとデスクトップが立ち上がってきます。


スタートメニューに表示される名前もちゃんとAzureADから取得できています。

とりあえずここまでです。
単にPCへのログインだけなので、これでOffice365などPCへのログインで使ったAzureADアカウントでログインするアプリケーションへのシングルサインオンが出来るか?というと「できません」。
あくまでPCへAzureADのアカウントでログインするだけです。



やっぱりブラウザを立ち上げると再度ログインする必要があります。。。


まだ管理面は見れていないので、AzureAD側で何が出来るかは今後見ていく必要がありそうです。

ちなみにクラウド接続がうまく行くと、AzureADのユーザプロファイルから該当アカウントのデバイス情報が見れます。
デバイス紛失などの場合はここで無効化などできるはずです。


[Office365/ADFS/AAD]クラウドIDのアクセス制御にAD FSを利用する

タイトルだけを見ると一体何をしようとしているのか良くわからないと思いますが、Office365フォーラムに質問が上がっていたので、こんなケースもあるかも知れないなぁ、ということで動きを検証してみました。


◆実現したい環境の概要
・Office365をクラウドID(Azure Active Directory上のユーザ)で使いたい
 ※ローカルのActive Directoryユーザを使いたくない
・Azure Active DirectoryだとクライアントIPやブラウザ種別などでアクセス制御が出来ないのでActive Directory Federation Services(AD FS)のクレームルールでの制御を行いたい

いざ実現しようとすると色々と課題があります。



そこで、Office365(AzureAD)⇒AD FS(アクセス制御用)⇒AzureAD(認証用)というフェデレーションの連鎖をさせて実現できるか確認してみます。

こんな環境です。


かなりややこしい構成です。



◆結果は、、、、曲がりなりにも動いた!
まずは結論から。
「一応」動きました。。。。が、ユーザビリティに少々難ありかと。(ある程度工夫で何とかなりますが)

フローを追って確認してみます。
①Office365にアクセスする
 まずはOffice365にアクセスします。https://portal.office.comへブラウザでアクセスし、ログイン画面を表示させます。



②AD FSのドメイン名のユーザ(ダミー)をログインIDに入れる
 Office365(AzureAD)のレルム・ディスカバリ機能でAD FSへリダイレクトされます。



③AD FSのレルム選択画面でAzureADを選択する
 あらかじめAD FSに外部IdPを設定してあるとローカルのAD DSで認証するか、外部IdP(今回はAzureAD)で認証するかを選択できます。ここでAzureADを選択すると再度AzureADのログイン画面へ遷移します。


 ※ちなみにAzureADからAD FSへの遷移はajaxで制御されています。通常フローだとAzureADのログイン画面に入れたユーザ名がそのままAD FSに引き継がれるので便利なのですが、AD FSのログイン画面で別のユーザ名(AzureADのonmicrosoft.comユーザ)を入れる必要があるので、アドレスバーに表示されるURLのGETパラメータのusername=xxxという部分を手動で消してあげる必要があります。この部分の省力化方法は後で紹介します。


④AzureADユーザ(onmicrosoft.comユーザ)で認証する
 今度はAD FSにリダイレクトするためのダミーユーザではなく、AzureAD上の実ユーザでログインするため、ユーザ名にonmicrosoft.comドメインのユーザ名を入力します。するとAzureAD上の自分のテナントの認証画面へ遷移します。



⑤ログインする
 自分のテナントのログイン画面に遷移したらクラウドIDでログインします。



⑥AzureAD⇒AD FS⇒Office365(のIdPであるAzureAD)へ戻る
 認証が終わるとAzureADでAssertionが発行され、AD FSへ戻されます。次にAD FSはAzureADから受け取ったAssertionをOffice365(のIdPであるAzureAD)向けのAssertionに変換・発行し直してAzureADへ戻し、AzureADでの認証プロセスが完了します。
 この時、Office365のIdPとしてのAzureADはAD FSのユーザで認証されますが、前段階ですでにクラウドID(onmicrosoft.comユーザ)でログオンしていますので、すでに認証済みとして扱われ、改めてログインし直すか聞かれます。ここでログインし直す選択をするとログアウトからやり直すので、永遠に2重ログイン状態を繰り返してしまいますので、AD FSユーザでのログインはあくまでアクセス制御のためと割り切って、クラウドIDでのログイン継続を選択します。



⑦Office365へのログイン
 ライセンスを付与していないので画面ショットは単なるプロファイル表示画面になっていますが、無事にOffice365へアクセスできます。




これで一連の流れは完了です。
ここまで出来れば、AD FSの部分でアクセス制御ルールを設定してあげればOKです。上記フローの⑥の部分でアクセス制御が挟まるので、アクセス拒否されるとこんな画面が出てきます。




◆どうやって実現するか?
まずは環境設定です。
AzureAD、AD FSそれぞれに下記の設定を行います。

対象設定箇所設定内容設定方法
AzureADアプリケーション設定Office365を登録Office365の設定を行えば自動的に設定される
AD FSを登録ws-federationで連携するWebアプリケーションとして登録する
ドメイン設定AD FSとID連携するドメインを設定Office365のPowerShellで設定する
ユーザ設定ダミーユーザ(AD FS連携用ユーザ)PowerShellなどで登録する
実ユーザ(ログインするユーザ)PowerShellなどで登録する
AD FSRP設定Office365(AzureAD)を登録Office365のPowerShellで設定する
IdP設定AzureADを登録AzureADのFederationMetadataを使って登録する



順番に設定内容を見ていきます。
・AzureAD/アプリケーション設定
 Office365は自動的に登録されるので、AD FSを登録します。
 AzureADのアプリケーション設定で「組織で開発中のアプリケーションを追加」します。


 アプリケーションの種類は「WEBアプリケーションやWEB API」を選択します。


 以下の通りサインオンURLとアプリケーションID/URIを設定します。
 ・サインオンURL:AD FSのPassiveログインURL
 ・アプリケーションID/URI:AD FSのサービスID



・AzureAD/ドメイン設定
 こちらは通常のOffice365でAD FSとID連携用ドメインを設定する手順で設定を行います。

・AzureAD/ユーザ設定
 ・ダミーユーザ(AD FS連携用ユーザ)
  このユーザは実際にOffice365を利用するためのユーザではないので適当に作成すればOKです。
  作成した後、Get-MsolUserコマンドレットなどでImmutableIdおよびUserPrincipalNameの値を確認、メモしておきます。実際にログインに使うAzureAD上のユーザのSAML Assertionの中にこのダミーユーザのImmutableIdとUserPrincipalNameの値が必要となるためです。

 ・実ユーザ(ログインするユーザ。onmicrosoft.comユーザ)
  このユーザで実際にOffice365を使います。先にも書いたように、AzureADでこのユーザを認証した後、AD FSにSAML Assertionを渡すのですが、AD FSでこのユーザの属性(クレーム)と先に作成したダミーユーザのImmutableIdとUserPrincipalNameを一致させることで紐づけ(Federation)をさせます。
  そのため、このユーザの属性にダミーユーザのImmutableIdとUserPrincipalNameを設定します。
  今回は名にImmutableId、姓にUserPrincipalNameを設定しました。(この属性がOffice365のプロファイルに表示されてしまうので、本来はスキーマを拡張して利用者に見えない属性を使った方が良いと思います)



  また、このユーザでAzureAD上に登録してあるアプリケーションとしてのAD FSへアクセスするために、先に登録したAD FS(アプリケーション)へのアクセス権を割り当てます。



・AD FS/RP設定
 Office365とのID連携設定をすると自動的にRPとして「Microsoft Office 365 Identity Platform」が登録されるので、こちらのクレームルールを変更します。
 もともとあるのはActive Directoryから属性をとってきてNameID、ImmutableId、UserPrincipalNameを発行するルールなので、潔くすべて削除します。
 そして、以下の3つのルールを設定します。


 ・NameID発行(AzureADのユーザの名に入っているImmutableIdの値を発行)

c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"]
 => issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Issuer = c.Issuer, Value = c.Value, ValueType = c.ValueType, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");

 ・UserPrincipalName発行(AzureADのユーザの姓に入っているUserPrincipalNameの値を発行)

c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"]
 => issue(Type = "http://schemas.xmlsoap.org/claims/UPN", Issuer = c.Issuer, Value = c.Value, ValueType = c.ValueType);

 ・ImmutableId発行(AzureADのユーザの名に入っているImmutableIdの値を発行)

c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"]
 => issue(Type = "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID", Issuer = c.Issuer, Value = c.Value, ValueType = c.ValueType);

 アクセス制御をする場合はここで設定をしておきます。


・AD FS/IdP設定
 次にAD FSのIdPとしてAzureADを登録します。
 AzureADがFederationMetadataを公開しているので、URIを設定するだけで簡単に設定できます。
 設定するURIは「https://login.windows.net/[テナントID]/federationmetadata/2007-06/federationmetadata.xml」です。AzureADのアプリケーション設定のページでエンドポイントは確認できます。


 次に、AzureADから取得した属性(クレーム)を受け取る設定です。特に何も考えずにすべての属性をパススルーします。


 こんなルールです。

c:[]
 => issue(claim = c);



これですべての設定が完了しました。
先のフロー通りに動きます。


◆ちょっとした工夫
画面遷移を紹介しましたが、何度もレルムを選択したりするのは、かなり不便です。
そこで、最初のOffice365⇒AD FSへのレルム選択を自動化するために以下のURLをユーザにBookmarkしてもらうといきなりAD FSのログイン画面にたどり着きますので、かなり画面遷移がすっきりします。先の画面遷移の③からいきなり始まりますので、username=xxxをアドレスバーから手動で消す必要もなくなります。

 ブックマークするURL
  https://login.microsoftonline.com/login.srf?wa=wsignin1.0&wreply=https:%2F%2Fportal.office.com%2F&whr=example.net

◆Assertionの中身
細かい話ですが、ログインまでの間で以下のようなAssertionが飛んでおり、各ポイントで必要に応じて処理をします。
・AzureAD(実ユーザでログイン)⇒AD FS
<Subject>
   <NameID+Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">ixxxxxxxxxxxxxxxxx0ZM</NameID>
   <SubjectConfirmation+Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"+/>
</Subject>

<AttributeStatement>
   <Attribute+Name="http://schemas.microsoft.com/identity/claims/tenantid">
      <AttributeValue>2cxxxxxxxxxxxxxxxxxxxxxbfff</AttributeValue>
   </Attribute>
   <Attribute+Name="http://schemas.microsoft.com/identity/claims/objectidentifier">
      <AttributeValue>baxxxxxxxxxxxxxxxxxxxba2ac2</AttributeValue>
   </Attribute>
   <Attribute+Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
      <AttributeValue>nobunagao@xxxx.onmicrosoft.com</AttributeValue>
   </Attribute>
   <Attribute+Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">
      <AttributeValue>nobunagao@example.net</AttributeValue>
   </Attribute>
   <Attribute+Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
      <AttributeValue>QDibxxxxxxxxxfIENg==</AttributeValue>
   </Attribute>
   <Attribute+Name="http://schemas.microsoft.com/identity/claims/displayname">
      <AttributeValue>ADFS/AADテスト</AttributeValue>
   </Attribute>
   <Attribute+Name="http://schemas.microsoft.com/identity/claims/identityprovider">
      <AttributeValue>https://sts.windows.net/2c6xxxxxxxxx1bfff/</AttributeValue>
   </Attribute>
</AttributeStatement>



・AD FS⇒AzureAD(ダミーユーザ情報)
 クレーム変換ルールでImmutableId、UPNに必要な値が代入されています。
<saml:AttributeStatement>
   <saml:Subject>
      <saml:NameIdentifier+Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">QDxxxxxxNg==</saml:NameIdentifier>
      <saml:SubjectConfirmation>
         <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
      </saml:SubjectConfirmation>
   </saml:Subject>
   <saml:Attribute+AttributeName="UPN"+AttributeNamespace="http://schemas.xmlsoap.org/claims">
      <saml:AttributeValue>nobunagao@example.net</saml:AttributeValue>
   </saml:Attribute>
   <saml:Attribute+AttributeName="ImmutableID"+AttributeNamespace="http://schemas.microsoft.com/LiveID/Federation/2008/05">
      <saml:AttributeValue>QDxxxxxxNg==</saml:AttributeValue>
   </saml:Attribute>
</saml:AttributeStatement>





いかがでしょうか?
色々とトリッキーなことをしているので、実用性は?ですがクラウドIDを使う場合にアクセス制御をしたい、という要件はあると思います。
今後はAzureAD側でのアクセス制御が実装されてくる日が来るかも知れませんね。

2015年2月5日木曜日

[FIM]カスタム管理エージェントのトレースログを出力する

久しぶりにForefront Identity Manager(FIM)の話題です。
ID管理システムを構築する際、管理対象のすべてのシステムを製品に含まれる管理エージェントでまかなえることは稀だと思います。
FIMの場合、カスタムで管理エージェントを開発するためのECMA2というフレームワークが提供されており、各種システムとの柔軟な接続性を確保することができます。

カスタムで管理エージェントを開発する際、避けて通れないのがデバッグとトレース(ロギング)です。
デバッグについては別途紹介したいと思いますので、今回はトレースについてのポイント(TIPS)を少し紹介します。

トレースを行う方法も色々とあると思いますが、最近はプリセットのアダプタ群も対応しているEvent Tracing for Windows(ETW)を使うのが主流です。
(昔はMicrosoft.MetadirectoryServices.Loggingなんていうのもありましたが、最近はあまり使っていないような・・・。一応今でもあります、念のため)

 ETWトレース
  https://msdn.microsoft.com/ja-jp/library/vstudio/ms751538(v=vs.100).aspx
 Microsoft.MetadirectoryServices.Logging
  https://msdn.microsoft.com/en-us/library/microsoft.metadirectoryservices.logging.logging.aspx


ETWを使う場合、アプリケーション構成ファイル(hogehoge.exe.config)にSourceとListenerを記載すればモジュールに手を入れることなく、イベントログやテキストファイルなどへ柔軟にトレースを出力することが出来ます。
この時に注意すべきなのが、管理エージェントをFIM Sync(miisserver.exe)のプロセス内で動かすのか、別プロセスとして動かすのかによって使われるアプリケーション構成ファイルが異なる、ということです。


ここで「Run this management agent in a separate process」にチェックが入っているとFIM Sync(miisserver.exe)ではなく、独立したプロセス(dllhost.exe)で管理エージェントが実行されます。つまり、この場合はmiisserver.exeではなくdllhost.exeが使うアプリケーション構成ファイルにETWの設定をする必要があるのです。


それぞれの実行プロセスと構成ファイルは以下の通りです。

管理エージェント実行方法実行プロセス名アプリケーション構成ファイル
FIM Sync内miisserver.exeC:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Bin\miisserver.exe.config
別プロセスdllhost.exeC:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\dllhost.exe.config




尚、設定する内容は同じなので、両方に同じことを書いておけばどちらのモデルで実行してもログの取り忘れはなくなるので、とりあえず両方に設定しておくのが良いかも知れません。



以下、具体的な設定方法です。

◆管理エージェント側
<必要な準備>
①#define TRACEを定義するか、コンパイルオプションに/d:TRACEを付けていること
②System.Diagnosticsをusingで定義
③TraceSourceオブジェクトインスタンスを生成

こんな感じで書きます。
#define TRACE
using System;
using Microsoft.MetadirectoryServices;
using System.Diagnostics;

namespace FimSync_Ezma
{
    public class EzmaExtension :
    IMAExtensible2CallExport,
    IMAExtensible2CallImport,
    IMAExtensible2GetSchema,
    IMAExtensible2GetCapabilities,
    IMAExtensible2GetParameters
    {
        // trace
        TraceSource traceSource = new TraceSource("sampleMA",SourceLevels.All);

※testma部分がアプリケーション構成ファイル内のSource Nameになります。SourceLevelについてはお好みで。

<トレース出力の例>
実際にトレースを出力したい箇所では以下のように書きます。
traceSource.TraceEvent(TraceEventType.Information, 0, "hogehoge");
traceSource.Flush();



◆アプリケーション構成ファイル側
テキストファイルに出力する例です。
initializeDataに対象ファイル名を記載します。
<system.diagnostics>      
   <sources>
       <source name="sampleMA" switchValue="All">
           <listeners>
               <add name="sampleMA"
                    type="System.Diagnostics.TextWriterTraceListener"
                    initializeData="c:\Logs\sampleMA_dllhost.log">
               <filter type="" />
               </add>
               <remove name="Default"/>
           </listeners>
       </source>
   </sources>
</system.diagnostics>





switchValueで出力レベルが変更できますので、開発中やデバッグ中は構成ファイル側でログレベルを上げておいて、平常時はレベルを落とすことで性能やディスク容量への影響を減らすことが出来ますので、うまく調整をしていきましょう。