冴えないCustom Policyの育て方

最近認証毎の課金から月間アクティブユーザー課金になってだいぶお得になった感のあるAzure Active Directory B2Cですが、実際の利用時にはまだまだお手軽ではありません。(欲しい属性を基本のものから追加したりUIのカスタマイズ程度ならいいのですが)
お手軽ではない要因の1つというかこれが全てですが、基本的に(実際のケースで望まれるフローを満たすような)カスタマイズを行う場合はIdentity Experience Framework(IEF)を使ってカスタムポリシーを作成する必要があり、この作業が非常にわかり辛いというところです。

幸いなことに先日Azure AD B2Cのカスタムポリシーを弄るHackFestに参加する機会があり、今更ですがものすごく理解が進んだので少しでも共有するのが今回のPostになります。(やはり実践に勝るものはない)

Azure Active Directory B2Cについて

Azure AD B2C(以下AAD B2C)は簡単にいうと顧客IDアクセス管理なソリューションです。アプリやサービスで使用するIDを、顧客が持つMSアカウントやGoogle、Twitterなどを使用したり独自のIDを使うことができます。他にも機能がいろいろあって便利なので是非公式ドキュメントを参照ください。

ざっくりカスタムポリシーの概要

AAD B2Cの良いところはユーザー自身が持っているIDから好みで選べるようにIdPやソーシャルプロバイダーを選択可能にすることができたり、それぞれでばらばらのクレームを交換・変換することで、アプリケーションから見ると単一のクレームやエントリポイントを意識するだけで良くなる点です。ユーザーからみるとアプリ毎にIDを作る必要もなくSSOができるようになるといった利点もあります。

さらに良い点はサインアップ・サインイン、プロファイル編集、パスワードリセットといった処理を簡単に定義して提供することができる点です。一連の処理をユーザーフローという名前で提供されていて開発者は用途に応じたフローを定義してアプリケーションから利用できます。たとえばサインアップ時だとMFAを有効にしたりEmailでサインアップできるようにしたりなどなど。とても便利でMicrosoftも基本的にはユーザーフローを利用するように推奨しているのですが、とはいっても痒いところに手が届いてなかったりカスタムの処理を入れ込みたいケースが多いですよね。そんな時に使うのがカスタムポリシーです。カスタムポリシーはAAD B2Cの処理の根幹で、より汎化して組み込んだものがユーザーフローとして提供されてるような感じです。

あと、カスタムポリシーは実行するための基盤としてIdentity Experience Framework(IEF)を使うという感じ。IEFの定義というか細かい話はこの辺り参照。カスタムポリシーの概要はこの辺り
しかし公式ドキュメントの至らない点だと思いますけど、いきなりポリシーファイルの話から始まったり、リファレンスみたらいきなりXMLの話になったりでさっぱり構造がわからず何をしてるのかがわからないところが開発者の心を挫きます。そんな皆を助けてくれるのがazure-ad-b2c/ief-wikiです。基本的にこちらのWikiを熟読してたらこのPostは不要です。以下ではWikiから図を引用したりしつつ簡単に中身の話を書いていきます。

テクニカルプロファイル

さて重要なコンポーネントの説明です。カスタムポリシー内で処理される内容はすべてテクニカルプロファイルとして定義され、実行されます。テクニカルプロファイルではクレームの変換・入力、処理・検査(Validation)、クレームの変換・出力が主な役割になります。

クレーム交換フロー
技術プロファイルの実行

たとえばユーザー入力(Self-asserted)を検証する、既存ユーザーがいるか調べる、REST APIを呼ぶ、トークンを発行するなど1つ1つの処理がテクニカルプロファイルとして構成されます。
既にあるものを使う場合以外(独自のREST APIを呼ぶなど)はこのテクニカルプロファイルを定義していくことになります。

ユーザージャーニー(User Journey)

ユーザージャーニーは名前の通りユーザーの旅ですね。テクニカルプロファイルをどういった順番や条件で実行するかを定義したものになります。言い方を変えるとオーケストレーションです。定義した通りシーケンシャルに実行されていきます。

ユーザージャーニー

上図だと1つのユーザージャーニーに7ステップありますね。それぞれに実行するかどうかの条件を付けることができるので、例えばローカルIDでのサインインとソーシャル両方があったときにローカルサインインを選んだ場合、上記だと2つ目のステップはスキップしたりします。ユーザージャーニーはそれぞれのテクニカルプロファイルにクレームを入力し、出力されたクレームを受け取ります。出力されたクレームは後続で利用できるようにクレームバッグ(セッション)に保管できます。

後の構成要素としては「誰にいつ」ユーザージャーニーが実行されるのかという点ですね。カスタムポリシーではRelyingParty(証明書利用者)として定義します。RelyingParty(RP)ポリシーでは最終的な出力クレームや実行するユーザージャーニーを指定したりタイムアウトなどユーザージャーニーの挙動を定義したりします。

ポリシーの実行

ユーザージャーニーのふるまいを定義するので、外側からみたら1フロー1 RPになります。アプリケーションがサインアップやサインイン時にフロー(RP)を実行するのと同義です。実際の状況としてはアプリケーションそのものは複数フローを実行するケースがありますよね。サインアップ/サインイン時、パスワードリセット時、プロファイル編集時、、他にもサインアップ時も通常と、例えばお友達紹介とかキャンペーンとかシナリオ毎に挙動が変わったりするケースもありますよね。それらはRPを分けたりするので基本的にRPの数はアプリケーションの数 x シナリオ数 になったりします。(サンプルが3種類のRPだから必ず3個しかダメではありません)

最後にクレームの定義やクレーム変換の定義、UIといったコンテンツの定義などを行うBuildingBlocksとIdPなどを定義するClaimsProvidoresがあります。

これらのコンポーネントがざっくりわかれば後は実際にXMLを書いていく段階です。長かったですね。
さてポリシーの構造ですが、XMLとして定義していくことになります。実際のケースとしてはRP毎にポリシーファイル(XMLファイル)を作っていくことになるわけですが、IEFでは継承モデルを採用しているのでXMLファイルを分割してチェーン構造にすることができます。

ポリシーの継承

継承した子ポリシーでは親ポリシーの要素を上書きできます。
一般的にはTrustFrameworkBase(1000行オーバーの長大なXML)は弄らず、TrustFrameworkExtensionsでBaseを継承し、必要な部分を上書き定義していきます。ClamProvidorやユーザージャーニー毎に共通のテクニカルプロファイルなどはExtensionsに記述します。
最後にExtensionsを継承し、シナリオ毎にユーザージャーとRPを定義した各ポリシーという構造にだいたいなります。
実際にアプリケーションからはRPが定義されたポリシーを指定して実行することになります。(ポータルでRPがないポリシーファイルを実行しようとしてもエラーになります)

※現状ポリシーIDのPrefix(B2C_1A_)は固定です。

何となくイメージできましたか? サインアップなどのアプリケーションから呼び出されるシナリオ毎にRPとユーザージャーニーを定義したポリシーファイルを用意して、それらの共通となるプロバイダーなどをExtensionsに定義、実際のアプリはRPが定義されたポリシーを指定して実行です。

ここまで理解できれば後はXMLファイルに書いていくだけですね。まぁ大変なんですけど。でもXML内で使われる大きな要素は既に挙げた用語です。たとえBaseを眺めたとしても何となく読めるはずです!

弄る前の準備

さて実際にカスタムポリシーを弄ったりするわけですが、その前に事前準備をしておきます。最初にAAD B2Cテナントがないと始まらないので作成しておきます。

テナントなど用語や概念がちょっとわかり辛いですが、AAD B2Cテナントを作成すると専用の ____.onmicrosoft.com というテナントが新しくできあがります。Azure Portal上であれば普段使っているテナントと別のテナントになるので、AAD B2Cを触る場合はドキュメントにある通り操作するテナントを切り替えましょう。

予備知識

ざっくりは上述しましたが、公式ドキュメントに一通り載っていますのでこちらも参照。ですが、これだけだとつらいところがあります。特にカスタムポリシーの概念的な部分や挙動などについては初学者向けでない感があるので引用元となったWiki(中の人が書いてる)を熟読するのがいいでしょう。

公式にはない図解が多くて助かりますね。

開発環境

カスタムポリシーは基本的にXMLファイルを弄ることになるのでテキストエディタがあれば問題ありませんが、それだと苦痛しかありません。
開発を楽にしするにはVisual Studio CodeとAzure AD B2C extensionがおすすめです。

VS Codeからポリシーのアップロード、ポリシーのアウトラインやインテリセンス、定義の参照、スマートコピーや要素のヘルプ、Application Insights連携にポリシーのBuildまでできます。神。このツールを使うと某大佐みたいに訳が分からないポリシーのXMLファイルが読めるようになります。読める、読めるぞ!

※1年以上前に大御所が紹介してた。見逃してたのが不覚。

サンプル

AAD B2CチームのGitHubにいろいろ公開されています。

特にSampleは量が豊富なので、使いたいシナリオに沿ったサンプルを探して参考にするといいかと思います。あとは中の人のリポジトリにも興味深そうなサンプルが多いので参考に。
とりあえずゼロから始める(公式ドキュメントに従ってする)場合はこちらのStarter Packを使うとシンプルなので挙動をつかみ易いですね(たぶん)。
とはいえサンプル使ってもReadmeを読み損ねたり、手順漏れやミス(理解できてないと設定をミスる)があったりして一筋縄ではいかないことが多いので注意しましょう。めげずにStarter Packを使って1つでも作り上げることができたら、カスタムポリシーというかIEFをかなり理解できてるはずです。

困ったことがあったら

中の人的にはStack Overflowがいいらしいです。MSDNフォーラムでもいいと思いますけど。サービスそのものに対する要望(フィードバック)はUserVoiceに。サンプルに問題がある場合はGitHub Issuesにどうぞ。

ちなみにIEFのリリースノートがあって、こちらでサポートしてるIDプロバイダーやトークン、機能などの状況がわかります。

なんだか無駄に文章が多くなってしまったので一旦ここまで。もしかしたら次があるかもしれないし、ないかもしれない。(図を入れたい気持ちもあるけど億劫だった)

※一応構想としては2回目で1からシンプルなのを作る、3回目で開発・運用・監視周りなどのTipsという予定。。どうなることやら。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中