2014年12月22日月曜日

[AD FS]プライバシーに考慮したID連携設定

2か月連続でお世話になりましたCLR/HさんのイベントCLR/H Tokyo vol.7で「ID連携における仮名」の話をしてきました。
(数日前まで登壇の事実を忘れていたので事前準備・告知など全くできず・・・)

当日の資料はこちら



当日行ったデモの内容を含め、少し補足しておきたいと思います。

◆仮名(カメイ)とは
仮名(カメイ/pseudonym)とは、プライバシーに考慮しつつID連携を行いたい、というユースケースに対応した仕組みです。
例えば、企業グループ内で共有しているサービスにおいては、あらかじめ信頼したIdentity Provider(IdP)で認証された、という事実だけがあれば本来個人を特定する情報(氏名やメールアドレス)は不要なはずです。(アプリケーションの動作上、もしくは運用上必要になるケースはありますが)
しかし、実際のID連携のシナリオでは「なんとなく」様々な属性が連携されており、ID連携をしている複数のサービス間でユーザ情報の名寄せが出来てしまったりするケースが散見されます。
エンタープライズシナリオにおいては問題になることはあまりありませんが、複数のService Provider(SP)が存在し、かつ運営主体が別個であるコンシューマシナリオやセンシティブな情報を扱うシナリオ(例えば医療情報などを扱うSPを含むシナリオ)ではユーザ情報の名寄せは問題となることがあります。

そんな時、サービス毎にユニークな名前(ハンドルネームのようなイメージ)をIdPが自動的に発行することで名寄せを防ぎます。このユニークな名前のことを「仮名」と呼びます。
また、仮名には、
・永続的な仮名
・一時的な仮名
があります。

永続的な仮名は同じSPに対しては何度ログインし直しても毎回同じ仮名が発行されますので、SP側でデータを持つ場合でも継続してサービスを使うことが出来ます。
一方で一時的な仮名はSPに対してログインする度に異なる仮名が発行されるので、同じサービス内でのID情報(前回のログイン時に行った振る舞いなど)を紐づけられる心配はありません。


◆ID連携プロトコルにおける仮名
スライドではSAMLを例に紹介しましたが、ws-federationやSAML、OpenID Connectなどの各種ID連携プロトコルにおいて仮名が実装されています。(PPID/Private Personal Identifierとか呼んだりしています)

SAMLにおいてはNameID Formatで表現しており、
・永続的仮名では「urn:oasis:names:tc:SAML:2.0:nameid-format:persistent」
・一時的仮名では「urn:oasis:names:tc:SAML:2.0:nameid-format:transient」
が使われます。


◆AD FSでの仮名のサポート
これまであまり話題に上りませんでしたが、AD FSでも当然仮名を扱うことが出来ます。

ずいぶん前の記事ですが、このあたりでこっそりと紹介されています。

Technet
 When to Use a Custom Claim Rule
 http://technet.microsoft.com/en-us/library/ee913558.aspx
 - Example: How to issue a PPID claim based on an LDAP attribute

MSDN blog
 Name Identifiers in SAML assertions
 http://blogs.msdn.com/b/card/archive/2010/02/17/name-identifiers-in-saml-assertions.aspx


簡単に解説すると、AD FSにはビルトインで「_OpaqueIdStore」というIDストアが定義されており、そこから適切なNameID Format(persistent/transient)をプロパティとしてつけてクレームを発行する、という手順になります。

以下に設定例を紹介します。
(基本はMSDN blogの手順です)


◆永続的仮名を発行する場合
対象のRelying Partyのクレームルール(要求変換規則)に以下の2つのルールを定義します。

1._OpaqueIdStoreからIDの払い出し
 以下のカスタムルールを直接記載します。
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
 => add(store = "_OpaqueIdStore", types = ("http://mycompany/internal/persistentId"), query = "{0};{1};{2}", param = "ppid", param = c.Value, param = c.OriginalIssuer);




2.払い出された値をNameIDとして発行する
 GUIで設定可能です。
 ・[入力方向の要求の種類]に1で発行した際のtypeを指定します
 ・[出力方向の名前IDの形式]に[永続ID]を指定します


実際に払い出されるSAML AssertionをみるとNameID Formatに「urn:oasis:names:tc:SAML:2.0:nameid-format:persistent」が設定されていて、不必要な属性(名前やメールアドレスなど)が発行されていないことがわかります。
<samlp:Response ID="_8b9add32-95c9-47ae-b0f7-fe8719b14207"
                Version="2.0"
                IssueInstant="2014-12-20T07:57:32.137Z"
                Destination="https://sp.example.com/acs"
                Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
                InResponseTo="dlmfilinoelgaclpmbbiiknifkjngebcocfoocan"
                xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                >
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://idp.example.local/adfs/services/trust</Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </samlp:Status>
    <Assertion ID="_f9880ee1-5236-4a03-911a-dc41d4d6e589"
               IssueInstant="2014-12-20T07:57:32.137Z"
               Version="2.0"
               xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
               >
        <Issuer>http://idp.example.local/adfs/services/trust</Issuer>
        <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
                <ds:Reference URI="#_f9880ee1-5236-4a03-911a-dc41d4d6e589">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                    <ds:DigestValue>qtaUKLYlHQjHAszsestllzzSlwKG/GnfxBTM0LALHmM=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>KC2HtMYzjIQ...snip...bhQ3Dg3QBlpcmiA==</ds:SignatureValue>
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>MIIC+jCC...snip...E94b3S4cuw==</ds:X509Certificate>
                </ds:X509Data>
            </KeyInfo>
        </ds:Signature>
        <Subject>
            <NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">Eh1as1gTWtagxAk+ECEuTnu/dzUS2fyOnx3ER/NMCeg=</NameID>
            <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData InResponseTo="dlmfilinoelgaclpmbbiiknifkjngebcocfoocan"
NotOnOrAfter="2014-12-20T08:02:32.137Z"
Recipient="https://sp.example.com/acs"
/>
            </SubjectConfirmation>
        </Subject>
        <Conditions NotBefore="2014-12-20T07:57:32.121Z"
                    NotOnOrAfter="2014-12-20T08:57:32.121Z"
                    >
            <AudienceRestriction>
                <Audience>sp.example.com</Audience>
            </AudienceRestriction>
        </Conditions>
        <AttributeStatement>
            <Attribute Name="http://custom/identity/claims/age">
                <AttributeValue>I am 25 years old.</AttributeValue>
            </Attribute>
        </AttributeStatement>
        <AuthnStatement AuthnInstant="2014-12-20T07:57:31.839Z"
                        SessionIndex="_f9880ee1-5236-4a03-911a-dc41d4d6e589"
                        >
            <AuthnContext>
                <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
            </AuthnContext>
        </AuthnStatement>
    </Assertion>
</samlp:Response>


発行されているのは、
・発行元(Issuer):SPがあらかじめ信頼したIdPのEntityID
・識別子(NameID):仮名
・年齢(age):I am 25 years old.(カスタムスキーマを設定して年齢だけ渡すルールを別途書いています)
・認証情報(AuthnContextClassRef):urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport(パスワードで認証されたことを示します)
といった情報くらいです。
サービスは「あらかじめ信頼したIdP」で「パスワードで認証された」ユーザで「18歳以上(25歳という属性より)」であることがわかるので、ログインを許可しコンテンツを利用させることが出来る、と判断することが出来ます。
また、発行されたNameIDは前回同じユーザがログインした時のものと同じ値なので、サービス側で保持している情報との紐づけも可能となります。


◆一時的仮名を発行する場合
同じく、対象のRelying Partyのクレームルール(要求変換規則)に以下の2つのルールを定義します。

1._OpaqueIdStoreからIDの払い出し
 以下のカスタムルールを直接記載します。
c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
 && c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant"]
 => add(store = "_OpaqueIdStore", types = ("http://mycompany/internal/sessionid"), query = "{0};{1};{2};{3};{4}", param = "useEntropy", param = c1.Value, param = c1.OriginalIssuer, param = "", param = c2.Value);




2.払い出された値をNameIDとして発行する
 GUIで設定可能です。
 ・[入力方向の要求の種類]に1で発行した際のtypeを指定します
 ・[出力方向の名前IDの形式]に[一時ID]を指定します



実際に払い出されるSAML AssertionをみるとNameID Formatに「urn:oasis:names:tc:SAML:2.0:nameid-format:transient」が設定されていて、不必要な属性(名前やメールアドレスなど)が発行されていないことがわかります。(先の永続IDに発行されたAssertionとNameID部分だけが異なります)
<NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">luV8SsaKfGB+vn3IpxhsUL1M/EekpM5E4S20YhWp1Go=</NameID>


こちらも同じく発行されているのは、
・発行元(Issuer):SPがあらかじめ信頼したIdPのEntityID
・識別子(NameID):仮名
・年齢(age):I am 25 years old.(カスタムスキーマを設定して年齢だけ渡すルールを別途書いています)
・認証情報(AuthnContextClassRef):urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport(パスワードで認証されたことを示します)
といった情報くらいです。
サービスは「あらかじめ信頼したIdP」で「パスワードで認証された」ユーザで「18歳以上(25歳という属性より)」であることがわかるので、ログインを許可しコンテンツを利用させることが出来る、と判断することが出来ます。
また、発行されたNameIDは前回同じユーザがログインした時のものとは異なる値なので、サービス側では前回ログインしたユーザと今回ログインしてきたユーザが同じユーザであることが判別できないので、サービス内部でのユーザの紐づけは出来ません。


◆仮名を使う場合の注意点
せっかく仮名を使ったとしても、他にユーザを一意にする属性(メールアドレスなど)をAssertionの中に含めてしまうと仮名を使う意味が全くなくなってしまうので注意が必要です。
(おそらくディレクトリ同期したユーザの情報とAD FSが発行するクレームの紐づけをする必要があるが故にではありますが)悪い例として、Office365のID連携ではNameIDは永続的仮名を使うのですが、別途IDP Emailという属性でメールアドレスを設定する必要があるので、実は仮名の使い方としては意味がありません。

アプリケーションとのID連携を設計する際は、必要とされるプライバシー要件を十分に考慮して利用するNameIDのタイプや連携する属性を検討しましょう。

2014年12月14日日曜日

[Office365/AzureAD]OpenAMとのID連携②

前回のポストの続きです。
今回は予告した通りID連携を、カスタムドメインの作成~SSO設定、OpenAMのIdP/SP/CoT(Circle of Trust)定義の順に実際に設定していきます。

◆OpenAM/IdP(Identity Provider)設定

今回の構成はOpenAM上のユーザでOffice365へログオンしたいので、OpenAMをIdentity Provider(IdP)として設定する必要があります。

尚、実際にはOffice365とOpenAMの間にAzureADが挟まっており、Office365/portal.office.com⇒(ws-federation)⇒AzureAD/login.microsoftonline.com⇒(SAML2.0)⇒OpenAMという流れになります。

前回も掲載した図を厳密に書くと以下のようになります。


早速設定を始めます。
OpenAMのインストールを終了し、管理コンソールの[共通タスク]より[ホストアイデンティティープロバイダの作成]をクリックし、IdP定義を作成します。


ここでの設定項目は署名に使う鍵とトラストサークルの2点だけです。
以下を設定します。
・署名鍵:test(実験なので。実際はちゃんとした証明書を使ってください)
・トラストサークル:新しいトラストサークルに追加、トラストサークル名「例)MSO365」



◆OpenAM/RP(Relying Party)設定

次はOffice365をOpenAMにRPとして設定します。
Office365はSAML2.0のメタデータを公開しているので、それをベースにRP設定をします。

まずは以下のURLにアクセスし、メタデータをダウンロードします。
https://nexus.microsoftonline-p.com/federationmetadata/saml20/federationmetadata.xml
※私はいつもIEで上記URLを開き、ファイルメニューの名前を付けて保存よりXMLファイルを保存しています。

早速ダウンロードしたメタデータをOpenAMにインポートと行きたいのですが、インポート前にXMLファイル内の最初のが余分なので削除しておきます。

以下を削除します。


メタデータの用意が出来たら、OpenAMの管理コンソールの[共通タスク]より[リモートサービスプロバイダを登録]をクリックし、先ほどのメタデータをベースにRP設定を行います。
以下を設定します。
・メタデータ:ファイル⇒先ほどのメタデータファイル(federationmetadata.xml)
・トラストサークル:先ほどIdP作成時に作ったCoT(MSO365)
・属性マッピング:表明内の名前⇒IDPEmail、ローカル属性名⇒mail



これでOpenAM側の設定は完了なので、OpenAMのIdP設定(IdPメタデータ)を出力しておきます。
以下のURLよりメタデータが取得できます。
http://:8080/OpenAM-11.0.0/saml2/jsp/exportmetadata.jsp?realm=/&entityid=http://:8080/OpenAM-11.0.0
※realmやポートなどは環境によって異なります。


次はこのIdPメタデータを使ってOffice365/AzureAD側の設定を行います。


◆Office365/AzureADのカスタムドメインの認証設定を行う

ここではOffice365で使うカスタムドメインの認証をOpenAMとのFederationで行う様に設定を行います。
※ドメインの追加はOffice365の管理ポータルからでもAzureの管理ポータルからでも構いません。
※カスタムドメインを追加する手順は省略します。

具体的には、PowerShellの「Set-MsolDomainAuthentication」コマンドレットに以下のパラメータを付けて設定をします。
※当然ですがコマンドレット実行前に「Connect-MsolService」でAzureADへ接続しておいてください。

パラメータ設定する値設定例
DomainNameカスタムドメイン名example.com
FederationBrandNameブランド名(任意の値)eIdentity
AuthenticationFederated固定Federated
PassiveLogOnUriIdPメタデータ内のタグ内のLocation属性の値
※Binding属性の値が「urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST」のもの
http://openam.example.com:8080/OpenAM-11.0.0/SSOPOST/metaAlias/idp
SigningCertificateIdPメタデータ内のタグの中身MIICQDCCAakCBEeNB0swDQYJ….
IssuerUriIdPメタデータ内のタグ内のentityID属性の値http://openam.example.com:8080/OpenAM-11.0.0
ActiveLogOnUriIdPメタデータ内のタグ内のLocation属性の値
※Binding属性の値が「urn:oasis:names:tc:SAML:2.0:bindings:SOAP」のもの
※httpsでないと設定できないのでhttpsで設定(ブラウザを使ったアクセスではこの設定は使わないので、ダミーのURLでもよいのでとにかくhttpsのURLを設定すればOK)
https://openam.example.com:8080/OpenAM-11.0.0/SSOSoap/metaAlias/idp
LogOffUriIdPメタデータ内のタグ内のLocation属性の値
※Binding属性の値が「urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect」のもの
http://openam.example.com:8080/OpenAM-11.0.0/IDPSloRedirect/metaAlias/idp
PreferredAuthenticationProtocol利用するID連携プロトコル(SAMLP)SAMLP


実際のコマンドは以下のように実行します。
$dom = "example.com"
$url = "http://openam.example.com:8080/OpenAM-11.0.0/SSOPOST/metaAlias/idp"
$cert = "MIICQDCCAakCBEeNB0swDQYJKoZIhvcNAQEEBQAwZzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC1NhbnRhIENsYXJhMQwwCgYDVQQKEwNTdW4xEDAOBgNVBAsTB09wZW5TU08xDTALBgNVBAMTBHRlc3QwHhcNMDgwMTE1MTkxOTM5WhcNMTgwMTEyMTkxOTM5WjBnMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLU2FudGEgQ2xhcmExDDAKBgNVB.............Fcfu2/PeYoAdiDAcGy/F2Zuj8XJJpuQRSE6PtQqBuDEHjjmOQJ0rV/r8mO1ZCtHRhpZ5zYRjhRC9eCbjx9VrFax0JDC/FfwWigmrW0Y0Q=="
$entity = "http://openam.example.com:8080/OpenAM-11.0.0"
$ecp="https://openam.example.com:8080/OpenAM-11.0.0/SSOSoap/metaAlias/idp"
$logout = "http://openam.example.com:8080/OpenAM-11.0.0/IDPSloRedirect/metaAlias/idp"

Set-MsolDomainAuthentication -DomainName $dom -FederationBrandName eIdentity -Authentication Federated -PassiveLogOnUri $url -SigningCertificate $cert -IssuerUri $entity -ActiveLogOnUri $ecp -LogOffUri $logout -PreferredAuthenticationProtocol SAMLP



ちなみに設定結果は「Get-MsolDomainFederationSettings」コマンドレットで確認できます。




今回はここまでです。
次回はAzureAD上のユーザとOpenAM上のユーザの紐づけを行うためのプロビジョニング時の工夫について解説します。(単純に初期状態のディレクトリ同期だとImmutableIdでの紐づけがうまく行かないのでカスタマイズが一部必要になります)



2014年11月19日水曜日

[MIM]Microsoft Identity Manager 2015 CTP1が公開されました

既に各所で情報が出ていますが、Forefront Identity Manager(FIM)の次期バージョンであるMicrosoft Identity Manager 2015(MIM2015)のCTP1が正式に公開されました。

Active Directory Team Blog:Microsoft Identity Manager Public Preview is now available!


新機能は既にTechEd Europeなどでも解説されている通り、以下の通りです。
※各種画像は公式blogより転載

◆特権アカウント管理(Privileged Access Management/PAM)

 Active Directory上のアカウントに限定ではありますが、ユーザに対して期間限定で特権を割り当てることが可能になります。
 具体的にはKerberosのチケットのTTLをコントロールしたグループへの参加をさせる形となります。


◆Azure Active Directory(AzureAD)の多要素認証(MFA)を使ったセルフサービスパスワードリセット(SSPR)
 これまでカスタムでSSPRの認証ゲートを組み込んでいましたが、製品としてAzureのMFAに対応したPhone Gateが実装されてきました。
 パスワードを忘れた場合などのリセットをする際の認証に、これまでの秘密の質問だけでなくPhone Factorが使えるようになったので、管理者の負荷を下げることが出来るかもしれません。


◆ストアアプリでのCertificate Manager(CM)の提供
 Certificate Manager(CM)でのスマートカード発行がこれまでのWebベースからストアアプリでも出来るようになりました。タブレット端末で使うときなどは重宝するかも知れません。


◆最新プラットフォームのサポート

 ようやく、以下のプラットフォームに対応しました。
  • Windows Server 2012 R2
  • SharePoint 2013
  • SQL Server 2014
  • Exchange 2013
  • Visual Studio 2013


connectサイトからダウンロードできるので、早々に試してみようと思います。

ダウンロードサイト:




2014年11月18日火曜日

[AADSync]フルパスワード同期を強制的に実行する

先日Azure Active Directory Synchronization Services(AADSync)にもパスワード同期機能が実装された、という話を書きました。
 http://idmlab.eidentity.jp/2014/11/aadsync.html

しかし、ディレクトリ同期ツール(DirSync)にあって、AADSyncにない機能があり、その一つがパスワードの強制同期機能です。

DirSyncではフォーラムのFAQに書かれているように'Set-FullPasswordSync'コマンドレットを実行してサービスを再起動すればパスワードの強制同期が出来ました。

 フォーラムURL:
  http://social.technet.microsoft.com/wiki/contents/articles/18096.dirsync-password-sync-frequently-asked-questions.aspx

 パスワードの強制同期方法(PowerShell)
Import-Module DirSync
Set-FullPasswordSync
Restart-Service FIMSynchronizationService



一方でAADSyncには先にポストしたPowerShellコマンドレット一覧を見ても'Set-FullPasswordSync'が見当たりません。

MSDNフォーラムで色々と情報を探していたんところ、MirosoftのMarkus VilcinskasがTechnet Wikiに書いてくれました。かなり強引な方法ですので、いずれちゃんとしたコマンドレットが用意される気がしますが。

 Technet Wiki - How to Use PowerShell to Trigger a Full Password Sync in Azure AD Sync
  http://social.technet.microsoft.com/wiki/contents/articles/28433.how-to-use-powershell-to-trigger-a-full-password-sync-in-azure-ad-sync.aspx

$adConnector  = "mydomain.local"
$aadConnector = "mytenant.onmicrosoft.com - AAD"

Import-Module ADSync
$c = Get-ADSyncConnector -Name $adConnector
$p = New-Object Microsoft.IdentityManagement.PowerShell.ObjectModel.ConfigurationParameter "MicrosoftSynchronize.ForceFullPasswordSync", String, ConnectorGlobal, $null, $null, $null
$p.Value = 1
$c.GlobalParameters.Remove($p.Name)
$c.GlobalParameters.Add($p)
$c = Add-ADSyncConnector -Connector $c
 
Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $false
Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $true



ちなみに各コネクタの名称はSynchronization Service Managerで確認できます。(TypeがActive Directory Domain ServicesとなっているものがオンプレミスADコネクタ、Windows Azure Active Directory (Microsoft)となっているの*.onmicrosoft.com -ADという名前のものがAzureADコネクタです)
さっそく実行してみると、イベントログにパスワード同期が実行されたことが記録されます。


基本的に2分に一回パスワードは同期されますし、ネットワーク障害などで更新が出来なかったときはリトライがされるので大きな問題になることは少ないとは思いますが、メンテナンス時など強制的に全同期をしておきたい時もあると思いますので、そのような際はこのコマンドを使えば良いですね。


[Office365/AzureAD]OpenAMとのID連携①

先日告知させて頂いた通り、今月末にCLR/HさんのイベントでID連携のプロトコル周りの話をします。

イベントのために、手元にこんな環境を用意してみました。

プロビジョニング)
 ・AADSyncを使い、オンプレミスのAD DS上のアカウントをAzureAD/OpenDJ/GoogleAppsへID情報を同期します。
 ・AzureADからGoogleAppsへプロビジョニングを行います。
フェデレーション)
 ・AzureADをIdPとしてOffice365/GoogleApps/カスタムアプリといったSPへそれぞれws-federation/SAML2.0/OpenID Connectを使ってフェデレーションします。
 ・AzureADをSPとしてオンプレミスにAD FSを使ったIdPを構築し、ws-federationで接続します。また、先ほどのOffice365等のAzureADのSPの認証をAzureADを経由してAD FSで認証、というマルチプロトコルのフェデレーションのチェインを行います。
 ・並行してOpenAMをIdPとしてOffice365/GoogleAppsをSPとしてSAML2.0でフェデレーションします。


実際の動きはイベントでお見せするとして、構築方法など細かい話を少しずつ書いていこうと思います。

最初は図の右下部分のOffice365とOpenAMのID連携(SSO)について書いていきます。




完成するとこんな感じで動きます。

1. Office365のポータル(http://portal.office.com/)へアクセスするとログイン画面が表示されます。


2. OpenAMと連携するように構成したドメインのユーザのメールアドレスを入力するとOpenAMへリダイレクトされます。



この時、Office365からOpenAMに向けてSAML2.0の認証リクエストが発行されます。

ポイントはNameID Policyがpersistentとなっているあたりです。IdP(OpenAM)はSP(Office365)向けに永続(固定)のNameIDを渡してあげる必要がある、ということです。実際はOffice365のユーザDBとなるAzure Active Directory(AzureAD)に作成するユーザのImmutableIdという属性の値と一致した値をNameIDには指定します。OpenAM(のユーザDBであるOpenDJ)とAzureADでユーザを同期しておく必要があるので、Forefront Identity Manager(FIM)などのID管理ソリューションを使ってユーザを作成します。(今回はAAD Syncを改造しています。当然非サポートです)このあたりは次回以降で別途解説します。
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    ID="_996b8521-70a0-49b1-809c-c98aba209315"
                    IssueInstant="2014-11-17T14:20:32Z"
                    Version="2.0"
                    AssertionConsumerServiceIndex="0"
                    >
    <saml:Issuer>urn:federation:MicrosoftOnline</saml:Issuer>
    <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" />
</samlp:AuthnRequest>



3. OpenAMへログインします。


認証されるとOpenAMは2で生成されたSAML認証要求に対応する応答メッセージ(SAML Assertion)を生成、ブラウザを経由してOffice365へHTTP/POSTします。
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                ID="s20964a4b3df745e7880a0f3415b3215d3f5b2946c"
                InResponseTo="_996b8521-70a0-49b1-809c-c98aba209315"
                Version="2.0"
                IssueInstant="2014-11-17T14:20:51Z"
                Destination="https://login.microsoftonline.com/login.srf"
                >
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://openam.example.net:8080/OpenAM-11.0.0</saml:Issuer>
    <samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
        <samlp:StatusCode xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                          Value="urn:oasis:names:tc:SAML:2.0:status:Success"
                          />
    </samlp:Status>
    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    ID="s250501aa5c251e616bc9cba9076bfc828a65b086d"
                    IssueInstant="2014-11-17T14:20:51Z"
                    Version="2.0"
                    >
        <saml:Issuer>http://openam.example.net:8080/OpenAM-11.0.0</saml:Issuer>
        <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
                <ds:Reference URI="#s250501aa5c251e616bc9cba9076bfc828a65b086d">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                    <ds:DigestValue>9WyD3at9dL87t4dley8SYe/pxLk=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>
Yz43rxDLhDYs1QK0xj29qqVC19ND248iqa9fbgpg6WbJbDqh5Piq0Hyff8YgGnUmOY6vkJG4AMkR
....snip....
t7hjVQqcVvERxydS6xk=
</ds:SignatureValue>
            <ds:KeyInfo>
                <ds:X509Data>
                    <ds:X509Certificate>
MIICQDCCAakCBEeNB0swDQYJKoZIhvcNAQEEBQAwZzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNh
....snip....
cGy/F2Zuj8XJJpuQRSE6PtQqBuDEHjjmOQJ0rV/r8mO1ZCtHRhpZ5zYRjhRC9eCbjx9VrFax0JDC
/FfwWigmrW0Y0Q==
</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </ds:Signature>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
                         NameQualifier="http://openam.example.net:8080/OpenAM-11.0.0"
                         SPNameQualifier="urn:federation:MicrosoftOnline"
                         SPProvidedID="kenshinu"
                         >kenshinu</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData InResponseTo="_996b8521-70a0-49b1-809c-c98aba209315"
NotOnOrAfter="2014-11-17T14:30:51Z"
Recipient="https://login.microsoftonline.com/login.srf"
/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2014-11-17T14:10:51Z"
                         NotOnOrAfter="2014-11-17T14:30:51Z"
                         >
            <saml:AudienceRestriction>
                <saml:Audience>urn:federation:MicrosoftOnline</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2014-11-17T14:20:51Z"
                             SessionIndex="s20d7f191b8306bb263961ed4056b918f749a60501"
                             >
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute Name="IDPEmail">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:type="xs:string"
 >kenshinu@o365.hoge.net</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>



4. Office365へログインします。


うまくいけばシングルサインオンされます。



今回はここまでです。

次回から、以下の流れで順に解説する予定なのでお楽しみに!

第2回)Office365/OpenAMのID連携設定
 カスタムドメインの作成~SSO設定、OpenAMのIdP/SP/CoT(Circle of Trust)定義を行います。

第3回)ユーザのプロビジョニング設定
 AADSyncを使ってAzureAD/OpenDJへオンプレミスAD上のユーザを同期します。

2014年11月15日土曜日

[告知]CLR/H AD+IDスペシャルディ

今月末の11月29日(土)にCLR/Hさんのイベント「AD+IDスペシャルディ〜ハンズオンもあるよ!?」が品川の日本マイクロソフト本社で開催されます。

申し込みURL
 http://clrh.connpass.com/event/9464/

今回はセッションのトラックとハンズオントラックで 2部屋に分かれて開催され、私は「プロトコルから見るID連携」と題してws-federation/SAML/OpenID Connectの解説をAzure ADと外部IdP(AD FS/OpenAMの予定)やアプリケーション(Office365/GoogleApps/OWIN OpenID Connect Middlewareを使って実装したカスタムアプリ)の実際の動きをトレースしながら解説しようと思います。

以下がセッションスケジュールです。クラウドとのID連携の話やAzure IaaS上でのActive Directory設計の話、AD FSのクレームルールの解説など濃いセッションが予定されているので、ご興味のある方はどうぞ。

セッションスピーカー時間
開場-12:30-13:00
クラウド時代におけるID基盤MSいたくらさん13:00-13:50
AD設計の基礎から読み解くIaaS AD阿部さん14:00-14:50
LT & おやつタイム-15:00-16:00
ADFSクレームルール言語Deep Dive国井さん16:00-16:50
プロトコルから見るID連携富士榮17:00-17:50

2014年11月13日木曜日

[AADSync]PowerShellコマンドレット一覧

ディレクトリ同期ツール(DirSync)でもPowerShellモジュールが用意されていましたが、当然Azure Active Directory Synchronization Services(AADSync)にも用意されています。

個々の詳しい内容は機会があれば紹介したいと思いますが、とりあえずモジュール名と使えるコマンドレット名の一覧を書いておきます。

◆モジュール名
Get-Module -ListAvailableを実行すると「ADSync」という名前であることがわかります。
(ディレクトリ同期ツールでは「DirSync」でした)

Directory: C:\Program Files\Microsoft Azure AD Sync\Bin

ModuleType Version    Name    ExportedCommands
---------- -------    ----    ----------------
Binary     1.0.0.0    ADSync  {Get-ADSyncConnector, New-ADSyncConnector, Add-ADSyncConne...


◆コマンドレット一覧
先ほどのADSyncをVerboseモードでインポートすると一覧が取得できます。

PS C:\Users\Administrator> Import-Module ADSync -Verbose
VERBOSE: Loading module from path 'C:\Program Files\Microsoft Azure AD Sync\Bin\ADSync\ADSync.psd1'.
VERBOSE: Loading 'Assembly' from path 'C:\Program Files\Microsoft Azure AD
Sync\Bin\Microsoft.CredentialManagement.OnPremisesPasswordReset.Shared.dll'.
VERBOSE: Loading 'Assembly' from path 'C:\Program Files\Microsoft Azure AD
Sync\Bin\Microsoft.MetadirectoryServices.AADPasswordReset.Types.dll'.
VERBOSE: Loading 'Assembly' from path 'C:\Program Files\Microsoft Azure AD
Sync\Bin\Microsoft.CredentialManagement.OnPremisesPasswordReset.Library.dll'.
VERBOSE: Loading 'Assembly' from path 'C:\Program Files\Microsoft Azure AD Sync\Bin\Microsoft.ServiceBus.dll'.
VERBOSE: Loading 'Assembly' from path 'C:\Program Files\Microsoft Azure AD Sync\Bin\Newtonsoft.Json.dll'.
VERBOSE: Loading module from path 'C:\Program Files\Microsoft Azure AD
Sync\Bin\ADSync\Microsoft.IdentityManagement.PowerShell.Cmdlet.dll'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnector'.
VERBOSE: Exporting cmdlet 'New-ADSyncConnector'.
VERBOSE: Exporting cmdlet 'Add-ADSyncConnector'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncConnector'.
VERBOSE: Exporting cmdlet 'Add-ADSyncConnectorAnchorConstructionSettings'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncConnectorAnchorConstructionSettings'.
VERBOSE: Exporting cmdlet 'Add-ADSyncConnectorHierarchyProvisioningMapping'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnectorHierarchyProvisioningDNComponent'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnectorHierarchyProvisioningMapping'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnectorHierarchyProvisioningObjectClass'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncConnectorHierarchyProvisioningMapping'.
VERBOSE: Exporting cmdlet 'Add-ADSyncConnectorAttributeInclusion'.
VERBOSE: Exporting cmdlet 'Add-ADSyncConnectorObjectInclusion'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncConnectorAttributeInclusion'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncConnectorObjectInclusion'.
VERBOSE: Exporting cmdlet 'Disable-ADSyncConnectorPartition'.
VERBOSE: Exporting cmdlet 'Disable-ADSyncConnectorPartitionHierarchy'.
VERBOSE: Exporting cmdlet 'Enable-ADSyncConnectorPartition'.
VERBOSE: Exporting cmdlet 'Enable-ADSyncConnectorPartitionHierarchy'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnectorPartition'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnectorPartitionHierarchy'.
VERBOSE: Exporting cmdlet 'Update-ADSyncConnectorPartition'.
VERBOSE: Exporting cmdlet 'Add-ADSyncRunStep'.
VERBOSE: Exporting cmdlet 'Get-ADSyncRunProfile'.
VERBOSE: Exporting cmdlet 'New-ADSyncRunProfile'.
VERBOSE: Exporting cmdlet 'Add-ADSyncRunProfile'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncRunProfile'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncRunStep'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnectorTypes'.
VERBOSE: Exporting cmdlet 'Get-ADSyncGlobalSettings'.
VERBOSE: Exporting cmdlet 'Set-ADSyncGlobalSettings'.
VERBOSE: Exporting cmdlet 'Add-ADSyncGlobalSettingsParameter'.
VERBOSE: Exporting cmdlet 'Get-ADSyncGlobalSettingsParameter'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncGlobalSettingsParameter'.
VERBOSE: Exporting cmdlet 'Get-ADSyncConnectorParameter'.
VERBOSE: Exporting cmdlet 'Set-ADSyncConnectorParameter'.
VERBOSE: Exporting cmdlet 'Get-ADSyncAADPasswordResetConfiguration'.
VERBOSE: Exporting cmdlet 'Get-ADSyncAADPasswordSyncConfiguration'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncAADPasswordResetConfiguration'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncAADPasswordSyncConfiguration'.
VERBOSE: Exporting cmdlet 'Set-ADSyncAADPasswordResetConfiguration'.
VERBOSE: Exporting cmdlet 'Set-ADSyncAADPasswordSyncConfiguration'.
VERBOSE: Exporting cmdlet 'Set-MIISADMAConfiguration'.
VERBOSE: Exporting cmdlet 'Get-ADSyncSchema'.
VERBOSE: Exporting cmdlet 'Set-ADSyncSchema'.
VERBOSE: Exporting cmdlet 'Update-ADSyncConnectorSchema'.
VERBOSE: Exporting cmdlet 'Set-ADSyncAADPasswordSyncState'.
VERBOSE: Exporting cmdlet 'Set-ADSyncServerConfiguration'.
VERBOSE: Exporting cmdlet 'Get-ADSyncServerConfiguration'.
VERBOSE: Exporting cmdlet 'Get-ADSyncRule'.
VERBOSE: Exporting cmdlet 'New-ADSyncRule'.
VERBOSE: Exporting cmdlet 'Add-ADSyncRule'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncRule'.
VERBOSE: Exporting cmdlet 'Add-ADSyncAttributeFlowMapping'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncAttributeFlowMapping'.
VERBOSE: Exporting cmdlet 'Add-ADSyncJoinConditionGroup'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncJoinConditionGroup'.
VERBOSE: Exporting cmdlet 'New-ADSyncJoinCondition'.
VERBOSE: Exporting cmdlet 'Add-ADSyncScopeConditionGroup'.
VERBOSE: Exporting cmdlet 'Remove-ADSyncScopeConditionGroup'.
VERBOSE: Exporting cmdlet 'New-ADSyncScopeCondition'.
VERBOSE: Importing cmdlet 'Add-ADSyncAttributeFlowMapping'.
VERBOSE: Importing cmdlet 'Add-ADSyncConnector'.
VERBOSE: Importing cmdlet 'Add-ADSyncConnectorAnchorConstructionSettings'.
VERBOSE: Importing cmdlet 'Add-ADSyncConnectorAttributeInclusion'.
VERBOSE: Importing cmdlet 'Add-ADSyncConnectorHierarchyProvisioningMapping'.
VERBOSE: Importing cmdlet 'Add-ADSyncConnectorObjectInclusion'.
VERBOSE: Importing cmdlet 'Add-ADSyncGlobalSettingsParameter'.
VERBOSE: Importing cmdlet 'Add-ADSyncJoinConditionGroup'.
VERBOSE: Importing cmdlet 'Add-ADSyncRule'.
VERBOSE: Importing cmdlet 'Add-ADSyncRunProfile'.
VERBOSE: Importing cmdlet 'Add-ADSyncRunStep'.
VERBOSE: Importing cmdlet 'Add-ADSyncScopeConditionGroup'.
VERBOSE: Importing cmdlet 'Disable-ADSyncConnectorPartition'.
VERBOSE: Importing cmdlet 'Disable-ADSyncConnectorPartitionHierarchy'.
VERBOSE: Importing cmdlet 'Enable-ADSyncConnectorPartition'.
VERBOSE: Importing cmdlet 'Enable-ADSyncConnectorPartitionHierarchy'.
VERBOSE: Importing cmdlet 'Get-ADSyncAADPasswordResetConfiguration'.
VERBOSE: Importing cmdlet 'Get-ADSyncAADPasswordSyncConfiguration'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnector'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnectorHierarchyProvisioningDNComponent'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnectorHierarchyProvisioningMapping'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnectorHierarchyProvisioningObjectClass'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnectorParameter'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnectorPartition'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnectorPartitionHierarchy'.
VERBOSE: Importing cmdlet 'Get-ADSyncConnectorTypes'.
VERBOSE: Importing cmdlet 'Get-ADSyncGlobalSettings'.
VERBOSE: Importing cmdlet 'Get-ADSyncGlobalSettingsParameter'.
VERBOSE: Importing cmdlet 'Get-ADSyncRule'.
VERBOSE: Importing cmdlet 'Get-ADSyncRunProfile'.
VERBOSE: Importing cmdlet 'Get-ADSyncSchema'.
VERBOSE: Importing cmdlet 'Get-ADSyncServerConfiguration'.
VERBOSE: Importing cmdlet 'New-ADSyncConnector'.
VERBOSE: Importing cmdlet 'New-ADSyncJoinCondition'.
VERBOSE: Importing cmdlet 'New-ADSyncRule'.
VERBOSE: Importing cmdlet 'New-ADSyncRunProfile'.
VERBOSE: Importing cmdlet 'New-ADSyncScopeCondition'.
VERBOSE: Importing cmdlet 'Remove-ADSyncAADPasswordResetConfiguration'.
VERBOSE: Importing cmdlet 'Remove-ADSyncAADPasswordSyncConfiguration'.
VERBOSE: Importing cmdlet 'Remove-ADSyncAttributeFlowMapping'.
VERBOSE: Importing cmdlet 'Remove-ADSyncConnector'.
VERBOSE: Importing cmdlet 'Remove-ADSyncConnectorAnchorConstructionSettings'.
VERBOSE: Importing cmdlet 'Remove-ADSyncConnectorAttributeInclusion'.
VERBOSE: Importing cmdlet 'Remove-ADSyncConnectorHierarchyProvisioningMapping'.
VERBOSE: Importing cmdlet 'Remove-ADSyncConnectorObjectInclusion'.
VERBOSE: Importing cmdlet 'Remove-ADSyncGlobalSettingsParameter'.
VERBOSE: Importing cmdlet 'Remove-ADSyncJoinConditionGroup'.
VERBOSE: Importing cmdlet 'Remove-ADSyncRule'.
VERBOSE: Importing cmdlet 'Remove-ADSyncRunProfile'.
VERBOSE: Importing cmdlet 'Remove-ADSyncRunStep'.
VERBOSE: Importing cmdlet 'Remove-ADSyncScopeConditionGroup'.
VERBOSE: Importing cmdlet 'Set-ADSyncAADPasswordResetConfiguration'.
VERBOSE: Importing cmdlet 'Set-ADSyncAADPasswordSyncConfiguration'.
VERBOSE: Importing cmdlet 'Set-ADSyncAADPasswordSyncState'.
VERBOSE: Importing cmdlet 'Set-ADSyncConnectorParameter'.
VERBOSE: Importing cmdlet 'Set-ADSyncGlobalSettings'.
VERBOSE: Importing cmdlet 'Set-ADSyncSchema'.
VERBOSE: Importing cmdlet 'Set-ADSyncServerConfiguration'.
VERBOSE: Importing cmdlet 'Set-MIISADMAConfiguration'.
VERBOSE: Importing cmdlet 'Update-ADSyncConnectorPartition'.
VERBOSE: Importing cmdlet 'Update-ADSyncConnectorSchema'.


基本はGUIツール(構成ウィザード、ルールエディタ、同期マネージャ)で出来ることはPowerShellで出来そうですね。