AADC 同期した拡張属性 (拡張スキーマ) を利用する SSO アプリを作るまでの道のり
スキーマとは何か
- スキーマ (Schema) とは、AD オブジェクトのブループリントをまとめたもの。各 AD オブジェクトは、スキーマ (特にクラス) のインスタンスに過ぎない。
- スキーマは、複数の 属性 (attribute) と複数の クラス (class) から構成される。
- 属性: AD オブジェクトに付与されるプロパティ。属性には型 (e.g., 整数、文字列、真偽値) がある
- クラス: AD オブジェクトのインスタンス化に使われるインターフェイス。クラスは複数の属性を持っている。クラスの属性は、Mandatory (インスタンス化時に指定が必須) なものと、Optional なものに分類される。
- Windows 2000 以降、Active Directory のバージョンアップごとに既定のスキーマは変更されてきた。スキーマの持つバージョン情報で判別可能。
- 既定の属性一覧は https://docs.microsoft.com/ja-jp/windows/win32/adschema/attributes-all にある
例: ユーザー クラスに定義されている属性 (の一部)
参考
スキーマの拡張
基本的には既定のスキーマ (属性) で事足りるけど、組織によってはどうしても足りない属性を足したいことがある。独自の属性を足すことを、スキーマを 拡張する (extend) と言う。
拡張するとスキーマを元に戻せなくなったり、管理が煩雑になったりするので、まずは拡張する前に既存スキーマで代替できないかを考えると良い。実際にスキーマ拡張を考える時は公式ドキュメントを必ず確認する。
参考:
スキーマの確認方法
-
ADDS の役割をインストールした Windows Server に、Admin (正確には Schema Admin 権限を持つユーザ) でログインする。
-
Win + r
や cmd.exe で以下を実行する。Pop up が出てくるので [OK]。
regsvr32.exe schmmgmt.dll
-
regsvr32
は COM コンポーネントをシステムに登録する管理ツール -
schmmmgmt.dll
は名前から類推できる通り、スキーマの管理コンポーネント
-
Win + r
でmmc
を実行して、スキーマ管理コンソールを立ち上げる。 -
左上の [File] から以下の通り操作して、スキーマの一覧を表示させる。
File > Add/Remove Snap-in > choose Active Directory Schema > Add > Ok
- こんな感じの画面が見える
スキーマの拡張方法
手順としては、MMC の画面で Action (もしくは Attributes を右クリック) > New > Attribute
するだけ。
属性作成に際して、準備するべき情報がいくつかある。
キー | 意味 |
---|---|
Common Name | 属性の名前。人間フレンドリーな名前をつける |
LDAP Display Name | 内部的に使われる属性の名前。LDAP プロトコル的にはこちらを使うことになる |
X500 Object ID | 属性の ID。スコープが全世界となっていて、割当ては IANA で管理されている[1]。AD での利用目的なら、MS が発行してくれる OID を後述のツールで生成して、割り当てる |
Syntax | 属性の取りうる値。通常、Boolean / Unicode String / Numeric String / Integer / Large Integer / SID 等を使う |
参考:
CN / LDAP Display Name の名前付けベストプラクティス
- CN と LDAP Display Name を統一する
-
<prefix>-<name>
の命名規則を使う-
<prefix>
: 組織を一意に識別する文字列 (e.g., ドメイン、会社名の頭字語) -
<name>
: 十分に意味のある属性名
-
- 開発/本番などのバージョンが存在する場合、さらに
-<suffix>
を末尾に付与して区別すると良い
例) contoso-SoftSkills
Object ID (OID) の生成方法
- 公式ドキュメントで提供されているスクリプトを、
oidgen.vbs
として保存
スクリプトの中身
' oidgen.vbs
'
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
' OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
' FITNESS FOR A PARTICULAR PURPOSE.
'
' Copyright (c) Microsoft Corporation. All rights reserved
' Improvements made by Ryein C. Goddard
'
' This script is not supported under any Microsoft standard support program or service.
' The script is provided AS IS without warranty of any kind. Microsoft further disclaims all
' implied warranties including, without limitation, any implied warranties of merchantability
' or of fitness for a particular purpose. The entire risk arising out of the use or performance
' of the scripts and documentation remains with you. In no event shall Microsoft, its authors,
' or anyone else involved in the creation, production, or delivery of the script be liable for
' any damages whatsoever (including, without limitation, damages for loss of business profits,
' business interruption, loss of business information, or other pecuniary loss) arising out of
' the use of or inability to use the script or documentation, even if Microsoft has been advised
' of the possibility of such damages.
' ----------------------------------------------------------------------
Function GenerateOID()
'Initializing Variables
Dim guidString, oidPrefix
Dim guidPart0, guidPart1, guidPart2, guidPart3, guidPart4, guidPart5, guidPart6
Dim oidPart0, oidPart1, oidPart2, oidPart3, oidPart4, oidPart5, oidPart6
On Error Resume Next
'Generate GUID
Set TypeLib = CreateObject("Scriptlet.TypeLib")
guidString = TypeLib.Guid
'If no network card is available on the machine then generating GUID can result with an error.
If Err.Number <> 0 Then
Wscript.Echo "ERROR: Guid could not be generated, please ensure machine has a network card."
Err.Clear
WScript.Quit
End If
'Stop Error Resume Next
On Error GoTo 0
'The Microsoft OID Prefix used for the automated OID Generator
oidPrefix = "1.2.840.113556.1.8000.2554"
'Split GUID into 6 hexadecimal numbers
guidPart0 = Trim(Mid(guidString, 2, 4))
guidPart1 = Trim(Mid(guidString, 6, 4))
guidPart2 = Trim(Mid(guidString, 11, 4))
guidPart3 = Trim(Mid(guidString, 16, 4))
guidPart4 = Trim(Mid(guidString, 21, 4))
guidPart5 = Trim(Mid(guidString, 26, 6))
guidPart6 = Trim(Mid(guidString, 32, 6))
'Convert the hexadecimal to decimal
oidPart0 = CLng("&H" & guidPart0)
oidPart1 = CLng("&H" & guidPart1)
oidPart2 = CLng("&H" & guidPart2)
oidPart3 = CLng("&H" & guidPart3)
oidPart4 = CLng("&H" & guidPart4)
oidPart5 = CLng("&H" & guidPart5)
oidPart6 = CLng("&H" & guidPart6)
'Concatenate all the generated OIDs together with the assigned Microsoft prefix and return
GenerateOID = oidPrefix & "." & oidPart0 & "." & oidPart1 & "." & oidPart2 & "." & oidPart3 & _
"." & oidPart4 & "." & oidPart5 & "." & oidPart6
End Function
Set oShell = WScript.CreateObject ("WScript.Shell")
oShell.run "cmd /c Regsvr32 Schmmgmt.dll"
Set objFSO=CreateObject("Scripting.FileSystemObject")
outFile="C:\Users\Administrator\Desktop\oidInfo.txt"
Set objFile = objFSO.CreateTextFile(outFile,True)
'Output the resulted OID with best practice info
oidText = "Your root OID is: " & VBCRLF & GenerateOID & VBCRLF & VBCRLF & VBCRLF & _
"This prefix should be used to name your schema attributes and classes. For example: " & _
"if your prefix is ""Microsoft"", you should name schema elements like ""microsoft-Employee-ShoeSize"". " & _
"For more information on the prefix, view the Schema Naming Rules in the server " & _
"Application Specification (http://www.microsoft.com/windowsserver2003/partners/isvs/appspec.mspx)." & _
VBCRLF & VBCRLF & _
"You can create subsequent OIDs for new schema classes and attributes by appending a .X to the OID where X may " & _
"be any number that you choose. A common schema extension scheme generally uses the following structure:" & VBCRLF & _
"If your assigned OID was: 1.2.840.113556.1.8000.2554.999999" & VBCRLF & VBCRLF & _
"then classes could be under: 1.2.840.113556.1.8000.2554.999999.1 " & VBCRLF & _
"which makes the first class OID: 1.2.840.113556.1.8000.2554.999999.1.1" & VBCRLF & _
"the second class OID: 1.2.840.113556.1.8000.2554.999999.1.2 etc..." & VBCRLF & VBCRLF & _
"Using this example attributes could be under: 1.2.840.113556.1.8000.2554.999999.2 " & VBCRLF & _
"which makes the first attribute OID: 1.2.840.113556.1.8000.2554.999999.2.1 " & VBCRLF & _
"the second attribute OID: 1.2.840.113556.1.8000.2554.999999.2.2 etc..." & VBCRLF & VBCRLF & _
"Here are some other useful links regarding AD schema:" & VBCRLF & _
"Understanding AD Schema" & VBCRLF & _
"http://technet2.microsoft.com/WindowsServer/en/Library/b7b5b74f-e6df-42f6-a928-e52979a512011033.mspx " & _
VBCRLF & VBCRLF & _
"Developer documentation on AD Schema:" & VBCRLF & _
"http://msdn2.microsoft.com/en-us/library/ms675085.aspx " & VBCRLF & VBCRLF & _
"Extending the Schema" & VBCRLF & _
"http://msdn2.microsoft.com/en-us/library/ms676900.aspx " & VBCRLF & VBCRLF & _
"Step-by-Step Guide to Using Active Directory Schema and Display Specifiers " & VBCRLF & _
"http://www.microsoft.com/technet/prodtechnol/windows2000serv/technologies/activedirectory/howto/adschema.mspx " & _
VBCRLF & VBCRLF & _
"Troubleshooting AD Schema " & VBCR & _
"http://technet2.microsoft.com/WindowsServer/en/Library/6008f7bf-80de-4fc0-ae3e-51eda0d7ab651033.mspx " & _
VBCRLF & VBCRLF
objFile.Write oidText
objFile.Close
- Admin 権限を持つ cmd / powershell セッションで、
./oidgen.vbs
を実行
- デスクトップに生成される
oidInfo.txt
を開いて、2 行目にある謎の文字列 (root OID) を確認
例)
Your root OID is:
1.2.840.113556.1.8000.2554.16166.49194.xxxxx.yyyyy.zzzzz.1921813.16708071
- root OID の末尾に
.2.<unique-number>
を付与すれば、それがあなたの新属性の OID 👏
例)
1.2.840.113556.1.8000.2554.16166.49194.xxxxx.yyyyy.zzzzz.1921813.16708071.2.1
作成した属性をユーザー クラスに追加
カスタムな属性を作っても、その属性を活用するクラスがいなければ意味がないです。特に、今回はユーザー (クラスからインスタンス化されたユーザー オブジェクト) に、新しく作った属性を付与したいです。
- 今度は MMC の "class" の定義を開いて、以下の通りポチポチ
Console Root/Active Directory Schema/Classes > user > Attributes > Add...
- 追加したい属性を Optional に入れて、最後に [OK]
- 仕上げに ADDS を再起動することで、変更を反映
Windows + R > "services.msc" > Active Directory Domain Services > Restart
ユーザー オブジェクトの属性値を確認 & 設定
- Active Directory Users and Computers を開く
- Advanced Features を有効化
View > Advanced Features
- Users オブジェクトのプロパティから属性を確認
Users > "ユーザー名" > Attribute Editor
- ダブルクリックして適当に値を入れておく
ここまでで役に立ったリンクのまとめ
- https://bidhankhatri.com.np/windows/add-custom-attributes-to-active-directory/
- https://www.windowstechno.com/how-to-create-custom-attributes-in-active-directory/
翻弄された情報
-
extensionAttribute1
なるものを AD オブジェクトに追加できるという記事がちらほらあったが、これはどうも Exchange Server の機能のよう。スキーマ拡張を自動化してくれたり、既定で用意されてるバッファ用属性があったりするみたい。
https://docs.microsoft.com/en-us/exchange/recipients/mailbox-custom-attributes?view=exchserver-2019
と、ここまで来たはいいものの、ちゃんと最初から環境を作りたくなったので terraform を書いて、ADDS 構築からやりなおすことに・・・
とりあえず以下設定で Azure 上に AADS 環境を構築
- VNet の [DNS サーバー] 設定は 10.0.0.4
- AADS VM の設定
- NIC: 10.0.0.4 (Static)
- NIC の [DNS サーバー]: 168.63.129.16
- OS: Windows Server 2019
- Data Disk: Cache なしの 256 のデータディスクを 1 枚追加
まずは Data Disk を NTFS でフォーマットする
Get-Disk -Number 2 | Initialize-Disk
Get-Disk -Number 2 | New-Partition -UseMaximumSize -DriveLetter F | Format-Volume -FileSystem NTFS -NewFileSystemLabel Volume -Force
コメント:
- ディスクの指定は、パーティション作ってない最初のディスク
(Get-Disk | where NumberOfPartitions -eq 0)[0]
と迷ったけど、-Number 2
の決め打ちでいいと判断。 - ドライブレターも多分
(Get-Partition).DriveLetter
に含まれないものとか使ったほうが良いと思うけどめんどいのでF
で決め打ち
ADDS の役割をサーバーにインストール
Add-WindowsFeature -Name AD-Domain-Services, DNS -IncludeManagementTools
Import-Module ADDSDeployment
$Params = @{
DomainName = "openjny.local";
DomainNetbiosName = "OPENJNY";
ForestMode = "Win2012R2";
DomainMode = "Win2012R2";
DatabasePath = "F:\Windows\NTDS";
LogPath = "F:\Windows\NTDS";
SysvolPath = "F:\Windows\SYSVOL";
SafeModeAdministratorPassword = (ConvertTo-SecureString "<password>" -AsPlainText -Force);
InstallDns = $true;
CreateDnsDelegation = $false;
NoRebootOnCompletion = $false;
Confirm = $false;
}
Install-ADDSForest @Params
shutdown -r -t 5
管理者ユーザーを作って、RDP できるようにしておく。
$identity = "taroyamada"
$given_name = "Taro"
$surname= "Yamada"
New-ADUser `
-UserPrincipalName "$identity@openjny.local" `
-SamAccountName $identity `
-Name "$given_name $surname" `
-DisplayName "$given_name $surname" `
-GivenName $given_name `
-Surname $surname`
-Accountpassword (ConvertTo-SecureString "<password>" -AsPlainText -Force) `
-PasswordNeverExpires $true `
-Enabled $true
Add-ADGroupMember -Identity Administrators -Members $identity
Add-ADGroupMember -Identity "Remote Desktop Users" -Members $identity
せっかくなのでもうひとり追加。
$identity = "hanakoyamada"
$given_name = "Hanako"
$surname= "Yamada"
New-ADUser `
-UserPrincipalName "$identity@openjny.local" `
-SamAccountName $identity `
-Name "$given_name $surname" `
-DisplayName "$given_name $surname" `
-GivenName $given_name `
-Surname $surname`
-Accountpassword (ConvertTo-SecureString "<password>" -AsPlainText -Force) `
-PasswordNeverExpires $true `
-Enabled $true
スキーマの拡張 (ユーザークラスにカスタム属性を追加する)
-
regsvr32.exe schmmgmt.dll
を実行
-
oidgen.vbs
で OID を生成 -
MMC で属性を追加 (openjny-TestAttribute)
-
MMC で user クラスに属性を追加
-
ADDS をリスタート
Windows + R > "services.msc" > Active Directory Domain Services > Restart
Hybrid ID の事前準備
同期を始める前に色々と考慮する事項がある。属性に関しての考慮事項は以下。
- proxyAddress / userPrincipalName はディレクトリ内で一意である
- givenName / surname / sAMAccountName / displayName / mail / proxyAddresses / mailNickname / userPrincipalName が英数字等の問題を起こしづらい文字で構成されている
また、UPN (userPrincipalName) が AD と Azure AD で一致している必要がある。今回はオンプレで openjny.local
を、AAD で openjny.com
をドメイン設定しているので、このままでは同期できない。
対応方法は 2 通り。
- ADDS に代替 UPN サフィックスを追加する
- proxyAddresses (プライマリのメールアドレス) 属性に、AAD のドメインを使った UPN を設定する (+ Azure AD Connect の構成で UPN )
今回は代替 UPN サフィックスによる方法を利用してみることにする。
代替 UPN の設定
- 代替 UPN サフィックス (openjny.com) を追加
Active Directory Domains and Trusts > Properties > Alternative UPN suffixes:
- ユーザーの UPN を代替 UPN サフィックスに変更
$LocalUsers = Get-ADUser -Filter "UserPrincipalName -like '*openjny.local'" -Properties userPrincipalName -ResultSetSize $null
$LocalUsers | foreach {$newUpn = $_.UserPrincipalName.Replace("@openjny.local","@openjny.com"); $_ | Set-ADUser -UserPrincipalName $newUpn}
AAD Connect のインストール
最新版の ADDC をインストールする。
AADC のインストールウィザードでは、基本的に画面で指示された通りすいすい進めていい。ただ、Optional features の画面で Directory extension attribute sync を有効化するのを忘れないようにする。
追加したカスタム属性を Directory extentions で指定することで、拡張したスキーマ通り sync が行われるようになる。
拡張スキーム (属性) の制限
- 拡張したクラスとしては、ユーザーまたはグループオブジェクトのみ対応
- 単一値のカスタム属性の場合、文字列 / バイナリ / 整数値 / ブール値のみ対応
- 複数値のカスタム属性の場合、文字列 / バイナリのみ対応
- 複数値のカスタム属性は、Azure AD のすべての機能で使えるわけではない
- 属性値の最大長は 250 文字 (251 文字以降は削除して sync)
- sync 対象にできるカスタム属性は最大で 100 個
- "Constructed Attributes" と呼ばれる属性は sync の対象にできない
簡単にまとめると、ユーザー/グループのクラス定義を少々手直ししたくて、単一値属性を少し追加 (拡張) するくらいなら、Hybrid ID のシナリオでも利用に耐えうるという感じ。
手動同期のコマンド
# 差分
Start-ADSyncSyncCycle -PolicyType Delta
# 完全
Start-ADSyncSyncCycle -PolicyType Initial
同期処理のデバッグ
Synchronization Service > Operations
まず最初に確認すべきは、Status が "success" になっていない同期処理があるかどうか。エラーが発生していると、以下のように表示される。エラーメッセージ (この例だと "permission-issue" でググると Azure AD 技術サポートの公式ブログ記事がヒットした)。
同期された属性の値も Synchronization Service Manager から確認できる。Profile Name が "Full Synchronization" あるいは "Delta Synchronization" になっている行をクリックして、以下のいずれかを確認する。
Inbound Synchronization > Connections with Flow Updates
Outbound Synchronization > Export Attribute Flow
とてもよい参考文献
Tenant Schema Extension App
属性を拡張して AADC で最初に同期したとき、Azure AD に "Tenant Schema Extension App" という名前の Enterprise Application が登録される。
Application Type == Enterprise Applications
のフィルターがかかっている状態だと検索に載ってこないので少し注意。
AAD の [Audit logs] にも記録されているので、Target が "Tenant Schema" から始まるログを検索すると良い。
拡張した属性が同期されていることを確認する
方法1: AzureAD モジュール
Install-Module AzureAD
Connect-AzureAD
$appName = 'Tenant Schema Extension App'
$appObjId = (Get-AzureADApplication -SearchString $appName).Objectid
Get-AzureADApplication -ObjectId $appObjId | Get-AzureADApplicationExtensionProperty | fl
以下のように extension_xxxxxx_<AD の属性名>
のようなものが見えていれば OK。
DeletionTimestamp :
ObjectId : ce23d50c-f7c0-4791-bf17-d9df896b34ab
ObjectType : ExtensionProperty
AppDisplayName :
Name : extension_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_openjny_TestAttribute
DataType : String
IsSyncedFromOnPremises : true
TargetObjects : {User}
方法2: Azure AD の管理画面
-
Tenant Schema Extension App
アプリケーションの Application ID を記録 -
Groups > New group
と進み新しいグループを作成 (実際には作成しなくて良い) -
Membership type
をDynamic User
にして、Add dynamic query
を選択 -
Get custom extension properties
を押して、先程の Application ID を入力してRefresh properties
-
Choose a Property
のドロップダウンを見ると、同期された拡張属性が確認できる
方法3: Graph API
- https://developer.microsoft.com/ja-jp/graph/graph-explorer にアクセス
- 左側のメニューからサインイン
- 以下のエンドポイントへのクエリを実行
# すべてのユーザ
https://graph.microsoft.com/v1.0/users?$select=userPrincipalName,<AAD での拡張属性名>
# 特定のユーザ
https://graph.microsoft.com/v1.0/users/taroyamada@openjny.com?$select=<AAD での拡張属性名>
AAD 上の拡張属性名は、AADC によって定められた命名規則 extension_<AppID>_<属性名>
で決まるが、少しクセがある。
-
<AppID>
は、Tenant Schema Extension App
アプリケーションの Application ID から ハイフン (-) を取り除いたもの -
<属性名>
は、基本的にオンプレ AD で作成した属性名。ただ、ハイフン (-
) がアンダーバー (_
) に置換される現象が確認できている。正確な値は Synchronization Service Manager のログから追ったほうが良さそう。
OIDC の claim に拡張属性を使ってみる (が失敗)
Azure AD の OIDC 認証ライブラリ MSAL を使って、拡張属性を token の claim に含められるか検証してみる。結論から言えば、OIDC の場合 claim にオンプレ AD で同期した拡張属性を選択することは出来ず、実現可能性がかなり低そう。PoC に使ったのは公式のサンプル。
Python 3.8 の環境を用意 docker run -it -p 5000:5000 python:3.8 bash
して、README 通りの手順を実施。ここまでをやってから一旦 http://localhost:5000
にアクセス。ちゃんと login できること、Graph API で /user
が叩けることを確認。
git clone https://github.com/Azure-Samples/ms-identity-python-webapp
cd ms-identity-python-webapp
# pip install -r requirements.txt はライブラリの依存関係が壊れてて動かなかった
pip install flask flask-session msal requests werkzeug
sed -e 's/Enter_the_Application_Id_here/<新規登録したアプリの App ID>/' app_config.py
sed -e 's/Enter_the_Client_Secret_Here/<発行したシークレット>/' app_config.py
flask run --host 0.0.0.0 --port 5000
ここからが本題。Token configuration
から claim の追加ができるのだが、どうも extension_xxxx...
のような属性が見当たらない。
公式ドキュメント によると、アプリの claim 定義は json 形式のマニフェストでもかけるらしく、そこに無理やり追加すると一応追加は出来た。
しかしながら、この claim はサポートされておらず、トークンには含まれないですよという警告が表示される。
なんでこんな動作になるのか (利用できないなら追加させる理由) わからないまま、色々を調べていった結果、以下 2 つの文献に答えらしきものを発見。AD から sync されてきた拡張属性は、別のアプリ Tenant Schema Extension App
が持っている値なので、このアプリの claim には使えないということらしい。
- https://www.xtseminars.co.uk/post/azure-ad-schema-and-directory-extensions
- https://winsmarts.com/using-token-configuration-to-include-arbitrary-claims-in-id-token-or-access-token-or-samltoken-26f75ee13bf0
したがって、開発アプリでの id/access token の claim に AD から Sync されてきた拡張属性を含めたければ、こんなワークアラウンドを考慮すればよいはず。だが、こんなことはやりたくないので断念。
- 開発アプリにも拡張属性を作成する (Graph API で、
/applications/<開発アプリの AppId>/extensionProperties
に POST を投げるとできるっぽい) - AD Sync の拡張属性と、開発アプリで作成した拡張属性を定期的に Sync するバッチ処理を cron か何かで走らせる
SAML の claim に拡張属性を使ってみる
SAML の動作テストには SAML 2.0 Test Service Provider
を使った。
手順はこちらのサイトが詳しいので割愛。
一旦 SSO できるところまで作業をすすめたら、claim を編集していく。エンタープライズ アプリケーションの画面から、次のようにして claim を追加する。
Single sign-on > Attributes & Claims > Edit > Add new claim
- Name:
http://schemas.microsoft.com/identity/claims/testattribute
- Source: Attribute
- Source attribute:
extension_xxxxxx_<属性名>
[Save] すると次のような感じで claim が増える。
あとは再度 SP-initiated の認証リンクを踏んで結果を見てみるだけ。AttributeStatement
からも、追加した claim が SAML アサーションに含まれるようになったことがわかる。詳しくアサーションを見る場合は、SHOW SAML ASSERTION
を押せばよい。
結局のところ、、、
- OIDC で認証する場合は、アプリに Graph API を叩かせるのが吉
- Graph API なら、
/user
エンドポイントに?$select=extension_xxxx
パラメータ付きで GET するだけで、AADC 同期した AD 側拡張属性が取れる - 基本 MSAL を使うことになるだろうから、Bearer Token 取ってきて Graph API 叩くのも非常にお手頃。サンプルも割とある。
- AAD の API permission 機能を使えば、Garaph API 叩く時の認可もコントロールしやすい。
- Graph API なら、
- SAML で認証するときは、claim に拡張属性を単に追加してしまうだけで OK
- 設定も非常に簡単
- SAML アサーションに含まれる値をアプリ側でよしなに処理する