2016年5月30日月曜日

Office365のSAML脆弱性に見るマルチテナントSP実装時の注意点

こんにちは、富士榮です。

しばらく前に世間を騒がせたOffice365のSAML SP実装に関する脆弱性の話が色々と解説されているので、ちょっと動きを細かく見ていきたいと思います。

 騒動の元ネタ
  The road to hell is paved with SAML Assertions
  http://www.economyofmechanism.com/office365-authbypass.html

 OAuth.jpでのnov氏による解説記事
  Office 365 SAML Implementation Vulnerability
  http://oauth.jp/blog/2016/05/14/office-365-saml-implementation-vulnerability/

 John Bradley氏による解説
  Azure AD security issue
  http://www.thread-safe.com/2016/05/azure-ad-security-issue.html

 Internet2での解説
  Scoped User Identifiers
  https://spaces.internet2.edu/display/InCFederation/2016/05/08/Scoped+User+Identifiers


まぁ、起きていた事象と根本的な原因はIdPが発行したクレームを無条件に信じてしまっていたことにより他のテナントのユーザになりすましてしまうことが出来たよ、ということなので、ちゃんとVerifyしようよ、という話になっています。


◆何が起きていたのか再現してみる

と、言ってもすでにOffice365の脆弱性は修正済みなので、起きていたであろうことをAD FSとGoogle Appsを使って再現してみました。

AttackerとVictimの2つのIdPをAzure ADが収容して、共通のアプリケーションを利用する、という構図をGoogle AppsとAD FSを使って再現したのが以下の図のようなシステム構成になります。


Azure AD相当のAD FSが各IdPから渡ってきたEmailアドレスをストレートにNameIDに変換してアプリケーション(Google Apps)へ渡してしまうので、VictimにもAttackerにも同じメールアドレスのユーザが存在するとAttackerもGoogle Appsへログインできてしまいます。
(もちろん実際のOffice365/Azure ADではもう少し複雑な動きのはずですが、解説のためものすごく簡略化しています)

◆実際の動作

まず、各IdPに同じメールアドレスを持ったユーザを作成します。これは簡単ですね。Active Directoryのユーザとコンピュータからユーザのメールアドレス属性を編集してあげるだけです。

この状態でGoogle AppsへアクセスするとAzure ADに相当するAD FS(今回はHUBと呼びます)へリダイレクトされ、IdPの選択をするホームレルムディスカバリ画面が表示されます。これは、Office365の場合、メールアドレスのドメインパートで自動的に振り分けるような仕組みになっていますよね。


まずは正常系です。
ここでvictimを選択するとvictim側のAD FSへ再度リダイレクトされ、victim側のユーザでの認証が行われます。


もちろんここでログインすると問題なくGoogle Appsへアクセスできます。


今度は先ほどのIdP選択画面でattackerを選択してみましょう。
同じくattackerのログイン画面が表示されるので、attackerのユーザでログインしてみます。


すると、意図しないユーザであるにも関わらずGoogle Appsへのログインができてしまいます。

右上のユーザ名を見るとvictimのユーザとしてログインできていることがわかります。

これが問題です。


◆構成を見てみる

では、この環境がどのように構成されているのか見ていきましょう。

まずはHUBとなるAD FSの構成です。

Relying Partyには当然Google Appsが構成されています。

HUBとなっているので、IdPから渡ってくるEmailアドレス属性をNameIDへマッピングして出力を行うクレーム・ルールが設定されています。


次に、HUBのIdP(Claim Provider)設定を見てみます。マルチテナントで構成されているので当然victimおよびattackerがIdPとして登録されています。

そして、各IdPのクレーム・ルールを見ると単純に各IdPから渡ってくるEmailアドレスをパススルーしています。ここが大きな問題です。


取り敢えず問題は置いておいて、次に行きます。

次は各IdP側のRP設定を見ていきます。
当然、victim側にもattacker側にもRPとしてHUBが登録されています。

こちらがvictim側です。

こちらがattacker側です。

この辺りは特に不思議なところはありません。
クレーム・ルールも共通で以下の通り、ADのEmailアドレスをそのまま発行しています。



構成はこれで終わりです。
次はSAML Tracerを使って動きを見てみます。

◆SAML Assertionの中身の確認

まず、正常パターンです。victimで認証されてSAML ResponseがHUBへ返ります。


属性ステートメントにメールアドレス属性が正しく入っていることがわかります。

同様にattackerも見てみます。


先のルールだとattackerからもメールアドレス属性をそのまま発行することになるので、HUBへのSAML Responseにはメールアドレスが入ります。これは正常な動きです。

では、attackerからのResponseを受けたHUBがGoogle Appsへ返すSAML Responseを見てみます。


いけませんね。NameIDにvictimのメールアドレスが入ってしまっています。

Google Appsから見るとこのResponseはあくまでHUBから返ってきており、AssertionのIssuer(HUB)および署名(HUBのAD FS Token Sign)の検証が出来てしまうので、正しいAssertionだと認識してしまい、ログインが完了してしまいます。

◆どうやってなりすましを防ぐか?

では、ここからが対策です。
要するにHUBが配下のIdPから飛んでくるクレームを無条件に上位のアプリケーションへ発行してしまっているのが問題なので、フィルタリングを入れておきたいと思います。

具体的には、victimから飛んでくるメールアドレスはvictimの、attackerから飛んでくるメールアドレスはattackerの固有のドメインパートを持っている、という暗黙の前提の通りになっているかどうか?を確認し、正しければスルーしますし、異なっていたらフィルタリングしてしまいます。


AD FSにおいて、この設定はClaim Providerのクレーム・ルール設定で行います。

以下がvictim側の設定です。


次にattacker側の設定です。


この状態における実際のAssertionはどうなっているでしょうか?

まずは正常系(victim)です。メールアドレスがvictimorg.xyzで終わっているのでスルーされてAssertionに値が入ります。


しかし、attacker側ではメールアドレスがattackerorg.xyzで終わることが期待されるところにvictimorg.xyzが入ってきているのでフィルタされ、Assertionに値が入りません。

こうなるとGoogle Appsへのログインは失敗し、なりすましはできなくなりました。


◆対策とまとめ

結局のところは、「外部のIdPとフェデレーションを行う際はIdPの信頼性の担保が出来ているかどうかを確認すべし!」という話なんですが、「じゃあ、どうやって?」というところで例えばメールアドレスを使うOffice365やGoogle Appsなんかの場合は、暗黙の前提となっているドメインパートに正しい値が入ってくるであろう、という部分を排除してきっちりとフィルタリングをするという対策が必要になりますし、他の属性を使う場合でも、その属性に入ってくる値は当該のIdPで正しさが保証されているものなのか?を中間IdPやRP側でも確認をすることは必須である、ということが出来ます。

オンプレミスのActive Directoryの信頼関係でも同じですが、技術的につながるからと言って無条件につなぐと当然セキュリティ・ホールが出来上がるので、文字通り「信頼」をするためには必要な対策をちゃんとしましょう、ということです。

また、これはSAMLでもws-federationでもOpenID Connectでも全く同じことですので、うちのサービスはSAMLじゃないから大丈夫、と言ってスルーしないでください。



参考までに、ですがAD FSでは外部IdPから発行されたクレームを無条件にパススルーしようとすると以下のワーニングが表示されます。


ワーニングにはちゃんと意味があるので、みなさん従いましょうね。

2016年5月18日水曜日

[Azure AD Connect]Synchronization Rules Editorが大幅改善

こんにちは、富士榮です。

コンスタントにバージョンアップを続けるAzure AD Connectですが、これまで同期ルールがUserもGroupもDeviceも同列にずらずらと出てきてしまい、どのルールを編集すると何が起きるのか?の把握が非常に困難でした。

このUIについて、しばらく前から改善要求を挙げていたのですが、直近の1.1.180へのバージョンアップでSynchronization Rules Editorのユーザ・インターフェイスが大幅に改善、かなり使いやすくなりました。

◆以前の課題

先に書いた通り、ずらずらと同期ルールが並んでおり、どのルールを編集すると何が変わるのかがよくわかりませんでした。


◆Version 1.1.180での改善

対象のコネクタ、オブジェクトタイプ、属性等によってフィルタリングができるようになり、例えば「オンプレミスのADのユーザのメールアドレスを変更すると、どの同期ルールが適用されるのか?」といった影響範囲の把握が楽になりました。



例えば、オンプレミスのAD上のsAMAccountName属性が変更された場合に影響があるルールを特定したければ、
・Connector : オンプレミスのAD
・Connector Object Type : User
・Connector Attribute : sAMAccountName
という条件を設定すると以下のように関連するルールが出てきます。



特に実際の本番環境ではデフォルトのルールだけでは運用できないケースも多く、例えばAzure AD Connectのバージョンアップ時に新しいマッピングが追加されたりすることもあるので、カスタマイズの範囲や影響度合いをしっかり把握することは重要です。
今回のエンハンスはそのような環境においては非常に便利なので、上手に活用していきたいですね。

2016年5月16日月曜日

[Azure AD]SAMLアサーションへのカスタム属性マッピングがサポート

こんにちは、富士榮です。

全国7000万人のSAMLフリークの方に朗報です!!

ついに、Azure Active Directory(Azure AD)が発行するSAML Assertionにカスタム属性をマッピングすることが出来るようになりました。

 公式Blogでのアナウンス
  #AzureAD now supports custom unique IDs in SAML tokens for gallery apps
  https://blogs.technet.microsoft.com/ad/2016/05/13/azuread-now-supports-custom-unique-ids-in-saml-tokens-for-gallery-apps/


これで何がうれしいか?というと、例えばSAML AssertionのこれまではnameIdentifierにuserPrincipalNameやmail属性など限定的な属性しかマッピングできなかったが故に例えば、Google AppsのカスタムドメインとAzure ADのカスタムドメイン名をきっちり合わせておかないとSSOできなかったり、特に複数のSaaSアプリケーションを契約していて各SaaSアプリのnameIdentifierが異なる形式だったときに不具合が起きたり、、ということが解消するんです!



 ちょっと視点は異なりますが、以前Google AppsへのSSO時のSAML Assertionのマッピングのワークアラウンドについて書きました。この辺りもカスタム属性マッピングで解消できるポイントの一つです。
  [Azure AD]Google AppsとのSSO設定でのポイント
  http://idmlab.eidentity.jp/2016/02/azure-adgoogle-appssso.html



早速見ていきましょう。

◆準備1)Azure AD Connectで拡張属性の同期ルールを設定する

まずは、Azure AD上のextensionAttributeに値をセットしてあげないといけません。今回はオンプレミスのActive Directory上の属性をAzure AD Connectを使って同期することにします。

変更が必要なのは、
 オンプレAD⇒Metaverse
 Metaverse⇒Azure AD
の同期ルールです。今回は、オンプレADの「説明」属性をAzure ADのextensionAttribute1へ同期することにしたので、まずはAzure AD ConnectのSync Rules Editorを開き、以下の通りルールを作成(編集)します。

方向ルール名Flow TypeTarget AttributeSource AttributeApply OnceMerge Type
InboundIn from AD - User CommonDirectextensionAttribute1descriptionチェックなしUpdate
OutboundOut to AAD - User IdentityDirectextensionAttribute1extensionAttribute1チェックなしUpdate


※本番環境では既存のルールを編集するのではなく、追加ルールを新規作成することをお勧めします。

こちらがオンプレADの説明属性をMetaverseのextensionAttribute1へ同期するInboundルールです。

次にこちらがMetaverseのextensionAttribute1をAzure ADのextensionAttribute1へ同期するOutboundルールです。


◆準備2)オンプレADに属性値をセットする

同期ルールの設定が出来たので、対象の属性(今回は「説明」)に最終的にSAML AssertionのnameIdentifierに入れたい値を設定します。
テストをGoogle Appsでやりたいので、このユーザのuserPrincipalNameとはドメイン名の異なるメールアドレスを説明属性に設定しました。
ついでにmail属性をnameIdentifierへマッピングするテストもしてみたいので、メール属性に説明属性とは異なる値を入れてみます。
これで、マッピングを変えればAzure ADに設定をしていないドメインのGoogle Appsへ、かつnameIdentifierへマッピングする属性をメールと説明で変えれば別のユーザとしてログインできるようになるはずです。


ちなみにこちらがuserPrincipalNameです。先のドメイン名とは異なることがわかります。Azure ADへのログインはこの名前で行います。

実際にこれで同期が完了するとAzure AD上のオブジェクトの状態は以下のようになります。
Azure AD ConnectのConnector Spaceで確認すると、userPrincipalName、mail、extensionAttribute1の値がそれぞれ異なっていることがわかります。


◆準備3)SAML Assertionへの属性マッピングを変更する

いよいよAzure AD上のアプリケーション向けのSAML Assertionに含める属性のマッピング変更を行います。今回はGoogle Appsを例に解説をします。

アプリケーションをひらき、属性メニューからSingle Sign Onを見ると初期状態は以下のようにnameIdentifierにはuserPrincipalName属性のマッピングがされています。

このままだと、Azure AD上のuserPrincipalNameがそのままGoogle Appsへ渡るので、Azure ADとGoogle Appsのドメイン名が異なると動きません。

と、いうことで、ここを先に設定したextensionAttribute1にマッピング変更を行いたいと思います。

nameIdentifier属性の編集ボタンをクリックし、マッピングする属性としてextensionAttribute1を選択します。以前はここで拡張属性を設定することが出来ませんでしたが、今回のアップデートで選択できるようになりました。
※尚、mail属性とのマッピングは以前から出来ていたのですが、少なくとも私の環境ではマッピング変更を行っても実際のAssertionの中身を見ても正しくマッピングがされていませんでした。今回のアップデートでこの部分も解消されていました。



これで準備は完了です。

◆テスト1)Azure ADとは異なるドメインのGoogle AppsへSSOする

通常通り、Google AppsへアクセスするとAzure ADへリダイレクトされるので、Azure AD上のuserPrincipalName(今回だとGoogle Appsとは異なるユーザ名)でログインします。
※当然事前にGoogle Apps側にSSO設定をしています。


すると、異なるドメインにも関わらずGoogle Appsへサインオンできました!
ログインユーザ名を見るとオンプレADの「説明」属性に設定したユーザ名になっていることがわかります。


◆テスト2)SAML Assertionの中身を見てみる

正常にサインオンできたので、SAML Tracerを使って実際にどんなAssertionが発行されているのかを確認してみます。
想定通り、extensionAttribute1に入れた値がNameIDにマッピングされており、Assertionに含まれていることがわかります。


◆テスト3)別の属性にマッピングを変更して別ユーザとしてサインオンしてみる

先ほどはextensionAttribute1に入れた値をnameIdentifierにマッピングしましたが、メール属性にも
別のメールアドレスを設定してあったのを思い出してください。
追加のテストとして、このメール属性をマッピングしてみます。うまくいけば、別のユーザとしてGoogle Appsへサインオンできるはずです。

やり方は簡単ですね。Azure ADのアプリケーションの設定で属性マッピングをmailに変更するだけです。


この状態で先ほどと同じAzure ADユーザでGoogle Appsへサインオンすると想定通り、別のユーザとして扱われました。


◆まとめ

今回は、同じGoogle Appsを使ってテストをしましたが、このアップデートで例えば以下のことが実現でき、Azure ADのSAML対応アプリ連携の可能性がぐっと広がりました。

  • Azure ADとは異なるドメインのSaaSアプリケーションへSSOができる
    • これまではuserPrincipalNameにAzure ADのドメイン名が含まれてしまったので、アプリケーション側のドメイン名とAzure ADのドメイン名を一致させる必要があった。
  • オンプレのアプリケーションなど、従業員番号などメールアドレス形式以外のnameIdentifier属性を要求するアプリケーションとのSSOがやりやすくなった
    • これまでもExtractMailPrefix()関数でuserPrincipalnameのドメイン名を除いた値を使うことはできたが、必ずしもアプリケーションが要求する値がuserPrincipalNameのローカルパートになっているとは限らず、アプリケーション側でのID変更などが必要だった。


2016年5月8日日曜日

[Azure AD]トラブルシューティングに見るAzure AD参加の裏側

こんにちは、富士榮です。

ゴールデンウィークも終わりですね。

と、いうことで今回は今年の私のゴールデンウィークの7割を奪ったAzure Active Directory(Azure AD)へのデバイス登録時のトラブルと、トラブルシューティングの中で見えてきたAzure AD DRS(Device Registration Service)の裏側の仕組みの話です。


◆何が起きていたのか?

4月の終わりから5月の頭にかけてAzure AD DRSの一部機能で障害が発生しており、
Windows 10デバイスをAzure ADへ参加させた後のサインイン時のPIN作成でエラー 0x801c03ed が出る
という状況になっていました。

こんなエラーが出ます。


どうやらみなさん困っていたようで、各所に情報が出始めていました。

 (未解決) PIN setup on Azure AD joined machine fails.が、現在も発生
 Error 0x801c03ed during PIN create/change


エラーコードだけを見ているとデバイス参加時に多要素認証が必要な設定になっているにも関わらず、多要素認証を実施しなかった等が原因で対策としては一旦Azure ADから切り離して再参加する、と書いてあるのですが、多要素認証を要求する設定をしていないにもかかわらずこのエラーがでたり、多要素認証を実施してもエラーがでたり、そもそも再参加しても状況が改善しない、という状態でした。

 エラー時のリファレンス
 Microsoft Passport errors during PIN creation


◆トラブルシューティングとして何をする/したのか

先に書いたように今回はトラブルシューティングをしても一向に解決しなかったので、中の人に泣きついた結果障害が発覚して収束したんですが、トラブルシューティングの過程を残しておくことも今後の役に立つと思ったので少し残しておきます。

1.イベントログを確認する

 ユーザがデバイスを登録する際、クライアント側のイベントログに様々な情報が記録されます。関連するのは、主にUser Device Registrationで、必要に応じてAADについても見ることになります。(両方とも、アプリケーションとサービスログ->Microsoft->Windowsの配下にあります)

 エラーが発生しているときは、User Device RegistrationのAdminログにID:301のエラーが発生していました。

 NGC KeyをAzure DRSへ登録する際にInsufficient privilegesが出ていますので、先の多要素認証が正常に実行されていない時と同じエラーだと判断されたようです。

 この前後のログを見ると、Azure DRSへNGCを登録する際の動きを推測することが出来ます。

 流れは、
 1.Azure DRSのエンドポイントを検出する
 2.対象ユーザが関連付けされているデバイスをAzure ADディレクトリから探し出す
 3.クライアントで生成した鍵ペアより公開鍵を登録する
 となっています。
 (細かくは省きますが、OOBEでのセットアップ時(WinPE)かどうか判別したり、レジストリからNGC関連の情報を読み取ろうとしたり、と前処理では他にも色々とやっています)

 順番に見ていきます。

 1のAzure DRSのエンドポイントの検出です。ここは障害が発生している間もうまく動いていました。検出は以下の2つのXMLドキュメントを使ってクライアント・コンフィグレーションをAzureから取得するところからスタートします。
  https://clientconfig.microsoftonline-p.net/FPURL.xml
  https://clientconfig.microsoftonline-p.net/fplist.xml
ここで主にやっているのは、通常のテナント(MicrosoftOnline.com)なのか、中国用テナント(partnet.microsoftonline.com)なのかの判別をして、必要なIdPのURLを取得するところです。

 この後、ユーザのドメイン名からDRSや関連するエンドポイントを検出し、その結果がイベントログに記録されます。
 DRSのエンドポイントと、Azure AD上でのリソースURI、OAuth関連のエンドポイントが検出されています。



 2のAzure ADに登録されたデバイスとの関連付けについてはイベントログには現れませんが、前段でAzure ADへの参加をした時にAzure AD上に登録されたデバイスからのNGC登録要求でないとAzure DRSは受付けません。デバイスの登録状態はAzure ADのPowerShellコマンドレッド(新しい奴)もしくはGraph APIで状態の確認ができます。

 Get-MsolDevice -Allで一覧を取得した結果はこんな感じです。このDeviceTrustTypeに「Azure AD Joined」とあるのがAzure AD参加したデバイスです。※ちなみにオンプレADに参加したデバイスをAzure ADへ同期すると「Domain Joined」となります。また、Intuneで管理されている状態だとDeviceTrustLevelがCompliantに、単純にデバイスが登録されただけの状態だとAuthenticatedになります。


 最後にクライアント側で生成した鍵をAzure ADへ登録するところで先ほどは「Insufficient privilege」と言われてエラーになっていましたが、正常に登録できると「Microsoft Passport key was successfully registered」というメッセージが出ます。


 なお、今回トラブルシューティングをする上では、さらに細かい情報を取得する必要があったため、User Device Registrationのデバッグログを有効にしました。
 有効にするには、イベントログのデバッグおよびトレースを有効化した上で、User Device RegistrationのDebugログを有効にします。


 デバッグログを有効化することで膨大なログ(PIN登録部分だけで1000件近く)が出ますが、より細かい状態を把握できます。
 今回のケースだとID:502で以下の3つのエラーが記録されていました。
・XMLのパースエラー(エンドポイントのディスカバリ時のエラー)
・NGCコンテナの作成エラー
・NGC登録時にサーバーエラー(400)
 後半2つは最初のエラーに起因するものだと思われるので、一番の原因はディスカバリだった、ということですね。ちなみに事象が解消した現在でもfplist.xmlにDRS要素はないので、fplist.xmlのパース処理自体に問題があった、ということだと思います。

 イベントログはこんな感じです。


2.Azure ADへのクライアント登録の状態からWindows 10とAzure ADの関連を知る

 これは今回のトラブル解消には全く関係ありませんでしたが、イベントログを見て行く過程でAADのイベントログにこんな情報が出ていました。(User Device Registrationではなく、AAD側のログ)

 この辺りを見ると、Azure ADの共通テナント(https://login.microsoftonline.com/common)上にAAD.BrokerPlugin用のクライアントがマルチテナント構成で登録されていることがわかります。
※この画面では、クライアントID「dd762716-544d-4aeb-a526-687b73838a22」が見えますが、他にも「a40d7d7d-59aa-447e-a655-679a4107e548」などが登録されています。

 仕組みとしては、Windows 10のネイティブアプリケーションであるMicrosoft.AAD.BrokerPluginがAzure ADの情報にアクセスするために、共通のクライアントがAzure AD上に登録されており、そのクライアントを使ってAzure ADとやり取りをしているようです。Edgeを使ったデバイス->ブラウザのシングルサインオンにおけるPRT(Primary Refresh Token)からアクセストークンの取得でも活用されているので、知っておいて損はありません。
 実際の動きはFiddlerでも見ることが出来ますが、無理やりブラウザを使ってリクエストを投げてみるとクライアントがどのような名前で登録されているか、くらいはわかります。

 例えば、DRSへのアクセストークンを取得したい場合は、
 https://login.microsoftonline.com/common/oauth2/authorize?
  response_type=code%20token&
  client_id=dd762716-544d-4aeb-a526-687b73838a22&
  redirect_uri=ms-appx-web%3A%2F%2FMicrosoft.AAD.BrokerPlugin%2Fdd762716-544d-4aeb-a526-687b73838a22&
  resource=urn:ms-drs:enterpriseregistration.windows.net
 を投げるとクライアントのDisplayNameは空白で、多要素認証を要求していることがわかります。
 (実際は多要素認証に回答してもそのまま固まりますが)

 同様にアカウント設定画面での操作は、
 https://login.microsoftonline.com/common/oauth2/authorize?
  response_type=code%20token&
  client_id=a40d7d7d-59aa-447e-a655-679a4107e548&
  redirect_uri=ms-appx-web%3A%2F%2FMicrosoft.AAD.BrokerPlugin%2Fa40d7d7d-59aa-447e-a655-679a4107e548&
  resource=https%3A%2F%2F<ドメイン名>
 を投げるとクライアントが「Accounts Control UI」という名前で登録されていることがわかります。
 (こちらはBad Requestになります)

 このあたりはトラブルシューティングにはあんまり役に立ちませんが、内部の動きを知っておくのは良いことだと思います。


3.PIN生成時の通信をFilddlerでキャプチャする

 この辺りも基本的なところなので、押さえておきたいところです。
 Jairoのblog(翻訳版はこちら)を見ると、PIN登録時に「https://account.live.com/aadngc」へアクセスする、とありますが実際の動きはどうなっているのかを確認してみましょう。
 
 Fiddlerのセットアップや基本的な操作方法については割愛しますが、ポイントは以下の2点です。
 ・ブラウザ以外のセッションもキャプチャする
 ・HTTPSの復号を有効にする

 特にポイントになるのは、Windowsアプリケーションからの通信をキャプチャするという部分で、具体的にはFiddlerの左上のWinConfigをクリックして必要なアプリケーションを選択して保存を行います。

 画面の中にアカウントや職場または学校アカウントなどが関連するのでチェックが入っているか確認しておきましょう。


 この状態でPINのセットアップを行うと、以下のようなキャプチャが取得できます。

<リクエスト>
GET https://account.live.com/aadngc?uiflavor=win10&mkt=ja-JP&hasngc=0&platform=Windows10&scid=4&ctc=0&uiflavor=Win10 HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: ja
cxh-osVersionInfo: {"platformId":0,"majorVersion":10,"minorVersion":0,"buildNumber":14332}
hostApp: CloudExperienceHost
client-request-id: 872a9ff6-a81d-0000-0cad-2d871da8d101
cxh-protocol: ms-cxh
cxh-cxid: NGC
cxh-preferredLanguage: ja
cxh-correlationId: 872a9ff6-a81d-0000-0cad-2d871da8d101
cxh-source: ms-cxh://NTHAADNGCONLY/
cxh-osPlatform: CloudExperienceHost.Platform.DESKTOP
cxh-platform: CloudExperienceHost.Platform.DESKTOP
cxh-isRTL: false
cxh-colors: themeAccent=#0078d7;themeAccentLight1=#429ce3;themeAccentLight2=#76b9ed;themeAccentLight3=#a6d8ff;themeAccentDark1=#005a9e;themeAccentDark2=#004275;themeAccentDark3=#002642;themeTextApplication=#000000;themeTextSystem=#ffffff;
cxh-host: NTHAADNGCONLY
cxh-hostAppVersion: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; MSAppHost/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 Safari/537.36 Edge/14.14332
Accept-Encoding: gzip, deflate
Host: account.live.com
Connection: Keep-Alive
Cookie: mkt=ja-JP; DID=5737

 こうやって見ると、CXH(Cloud eXperience Host)が内部的には健在なことがわかりますね。レスポンスはHTMLが返ってきているので、CXH内での画面表示はHTMLであることがわかります。

 その後、https://auth.gfx.msへのアクセスが続いた後、最終的にhttps://account.live.com/API/ReportClientEventへ以下のJSONがPOSTされます。
 {
  "pageApiId":"Account_AAD_NGC_Provisioning",
  "clientDetails":[],
  "userAction":"",
  "source":"PageView",
  "clientTelemetryData":{
   "category":"PageLoad",
   "pageName":"Account_AAD_NGC_Provisioning",
   "eventInfo":{
    "timestamp":1462676178361,
    "perceivedPlt":2641,
    "networkLatency":1874,
    "networkType":null,
    "precaching":null,
    "bundleVersion":null,
    "appVersion":null,
    "deviceYear":null,
    "isMaster":null,
    "bundleHits":null,
    "bundleMisses":null
   }
  },
  "uiflvr":13,
  "uaid":"872a9ff6a81d00000cad2d871da8d101",
  "scid":100185,
  "hpgid":"Account_AAD_NGC_Provisioning"
 }

 そして、最後に
  https://enterpriseregistration.windows.net/EnrollmentServer/key/?api-version=1.0
 に対して公開鍵をPOSTします。
 {
  "kngc":"UlNBMQAI...snip...tFNEC+U/BbJ+WU0pKD1tAOINB2w==",
  "ak":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
 }

 こんな感じです。


 尚、同様にFiddlerを使ってAzure ADへ参加する際の通信の流れやMicrosoft Passportの流れもキャプチャすることが出来ます。

 例えば、Azure ADへ参加する時は、

  • https://login.microsoftonline.com/WebApp/CloudDomainJoin/4へGET
  • https://login.microsoftonline.com/common/.well-known/openid-configurationでOAuth関連のエンドポイント取得
  • https://login.microsoftonline.com/common/oauth2/authorizeへclient_id:01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9で認可要求
 という流れになります。

 このあたりの細かい話は別途まとめてお話ししたいですね。


4.NGC(Next Generation Credential)のプロビジョニング状態を確認する

 デバイスがAzure ADやオンプレミスのADへ参加しているかどうか、MDMでの管理状態はどうなっているのか、およびNGCがプロビジョニングされているかどうかを簡単にチェックするにはdsregcmd.exeを使います。

 使い方としては、dsregcmd /statusとたたくだけです。
 出力結果は2つのパートに分かれており、デバイスの状態およびユーザの状態を示します。(Windows 10 1511.10586.xxxの場合。14332だともっと項目が増えています)

セクション項目説明
Device StateAzureAdJoinedAzure ADに参加しているかどうか
AzureAdDeviceIdAzure ADに登録されているデバイスのID
AzureAdThumprintAzure ADに登録されているデバイス証明書の拇印
AzureAdIdPAzure ADのIdP
AzureAdTenantIdAzure ADのテナントID
AzureAdTenantNameAzure ADのテナント名
AzureAdMdmUrlIntuneのURL
AzureAdSettingsUrlIntuneのURL
DomainJoinedオンプレADドメインに参加しているかどうか
DomainNameオンプレADドメイン名
User StateNgcSetNGCがプロビジョニングされているかどうか
NgcKeyIdNGCのキーID
WorkplaceJoinedワークプレイスジョインしているかどうか
WamDefaultSetWebSSOに関する状態
WamDefaultAuthorityデフォルトで利用されるWebSSOのオーソリティ
WamDefalutIdデフォルトで利用されるWebSSOのID
WamDefalutGUIDデフォルトで利用されるWebSSOのGUID


特徴的なのは、Workplace Joinはあくまでユーザ単位なので、User State側に分類されているところでしょうか。
例えば、オンプレミスADへドメイン参加した状態でデバイス情報をAzure ADへ同期するとAzureAdJoinedおよびDomainJoinedの両方がYesになります。

参考)Build 14332系でのdsregcmd /statusの結果
 Device StateにEnterpriseJoinedという謎の項目が増えていたり、DRS関係の情報が出てきます。

 User Stateこちらはあんまり変わりません。


5.TPMをクリアする

 これは、TPMが搭載されているマシンを使っている場合に限りますが、キーペアがTPM上に保存される以上、Azure AD DRS上に登録された公開鍵とTPMコンテナ内の秘密鍵の紐づけがおかしくなってしまったらTPMをクリアするのも一つの手になるかも知れません。(根拠はありません。そういう事態に陥ったことはないので)

 とりあえず手順だけを書いておくと、ファイル名を指定して実行(Windowsキー+R)で「tpm.msc」を実行してTPMのクリアを選択して実行するだけです。

再起動が要求されます。

ここで再起動すると起動画面でTPMのクリアが行われます。(手順はデバイスによって異なります)
ちなみにAcerのPCではボリュームUPボタンを押すとクリアされました。

注)ここでTPMをクリアすると当然のことながらマイクロソフトアカウントやローカルアカウントでのログイン時のPINがすべて使えなくなります。パスワードがわからないとPCへログインすらできなくなりますので、慎重に実施する必要があります。同じく、EFSやBitLockerなどに関しても要注意です。


まぁ、色々と書きましたが、トラブルシュートの基本は状態の把握だと思うので、イベントログや通信のキャプチャなどは覚えておいて損はないですね。


おまけ)
ちなみにPIN設定をキャンセルしようとすると以下の画面が出て、頑張って設定させようとしてきます。一旦キャプチャしたいのでスキップしたかったんですけどね。。こういう場合はあえてエラー状態を作っておくと先に進めます。(メッセージの焦った感じがウケます)