次の方法で共有


エンタープライズ アプリケーション用に JSON Web Token (JWT) で発行されるクレームをカスタマイズする

Microsoft ID プラットフォームでは、Microsoft Entra アプリケーション ギャラリー内のほとんどの事前統合済みアプリケーションとカスタム アプリケーションでのシングル サインオン (SSO) がサポートされています。 ユーザーが OIDC プロトコルを使って Microsoft ID プラットフォーム経由でアプリケーションに対する認証を行うと、Microsoft ID プラットフォームはアプリケーションにトークンを送信します。 アプリケーションはトークンを検証し、ユーザー名とパスワードの入力を求める代わりに、そのトークンを使ってユーザーをサインインさせます。

OIDC と OAuth アプリケーションで使われるこれらの JSON Web Token (JWT) には、ユーザーに関する クレーム と呼ばれる情報が含まれています。 要求とは、そのユーザーに発行するトークンの中にあるユーザーに関する ID プロバイダーが提示した情報を指します。 OIDC の応答では、通常、クレーム データは ID プロバイダーによって JWT の形式で発行される ID トークンに含まれます。

クレームを表示または編集する

ヒント

この記事の手順は、開始するポータルによって若干異なる場合があります。

アプリケーションに対して JWT で発行されたクレームを表示または編集するには:

  1. クラウド アプリケーション管理者以上として Microsoft Entra 管理センターにサインインします。
  2. [ID]>[アプリケーション]>[エンタープライズ アプリケーション]>[すべてのアプリケーション] に移動します。
  3. アプリケーションを選択し、左側のメニューで [シングル サインオン] を選択し、[属性とクレーム] セクションで [編集] を選択します。

アプリケーションでは、さまざまな理由でクレームのカスタマイズが必要になる場合があります。 たとえば、アプリケーションで、別の一連のクレーム URI やクレーム値が必要な場合です。 [属性とクレーム] セクションを使用すると、アプリケーションに対してクレームを追加または削除できます。 ユース ケースに基づいて、アプリケーションに固有のカスタム クレームを作成することもできます。

次の手順では、定数値を割り当てる方法について説明します。

  1. 変更するクレームを選択します。
  2. 組織に従って [ソース属性] に引用符を付けずに定数値を入力してから、[保存] を選びます。

属性の概要には、定数値が表示されます。

特別なクレームの変換

特別なクレームの変換関数を使用できます。

機能 説明
ExtractMailPrefix() メール アドレスまたはユーザー プリンシパル名からドメイン サフィックスを除去します。 この関数は、ユーザー名の最初の部分のみを抽出します。 たとえば、joe_smith@contoso.com の代わりに joe_smith となります。
ToLower() 選択した属性の文字を小文字に変換します。
ToUpper() 選択した属性の文字を大文字に変換します。

アプリケーション固有のクレームを追加する

アプリケーション固有の要求を追加するには:

  1. [ユーザー属性とクレーム] で、[新しいクレームの追加] を選択して [ユーザー クレームの管理] ページを開きます。
  2. クレームの [名前] を入力します。 値は、URI パターンに厳密に従う必要はありません。 URI パターンが必要な場合は、[名前空間] フィールドに追加することができます。
  3. クレームの値が取得される [ソース] を選択します。 ソース属性のドロップダウンからユーザー属性を選択するか、または要求として生成する前にユーザー属性に変換を適用することができます。

要求の変換

ユーザー属性に変換を適用するには、次の手順を行います。

  1. [要求の管理] で、要求ソースとして [変換] を選択して、 [変換の管理] ページを開きます。
  2. 変換ドロップダウンから関数を選択します。 選択した関数に応じて、変換で評価するパラメーターと定数値を指定します。
  3. [ソースを複数値として扱います] は、変換をすべての値に適用するか、または最初の値のみに適用するかを示します。 既定では、複数値クレームの最初の要素に変換が適用されます。 このチェックボックスをオンにすると、すべてに適用されます。 このチェックボックスは、複数値の属性に対してのみ有効になります。 たとえば、「 user.proxyaddresses 」のように入力します。
  4. 複数の変換を適用するには、[変換の追加] を選びます。 要求には、最大 2 つの変換を適用できます。 たとえば、最初に user.mail のメール プレフィックスを抽出できます。 次に、文字列を大文字にします。

次の関数を使用して、要求を変換できます。

機能 説明
ExtractMailPrefix() メール アドレスまたはユーザー プリンシパル名からドメイン サフィックスを除去します。 この関数は、ユーザー名の最初の部分のみを抽出します。 たとえば、joe_smith@contoso.com の代わりに joe_smith となります。
Join() 2 つの属性を結合することで、新しい値を作成します。 必要に応じて、2 つの属性の間に区切り記号を使用できます。 NameID の要求の変換で、変換入力にドメイン部分がある場合、Join() 関数は特定の動作をします。 入力からドメイン部分を削除した後、区切り記号および選択されたパラメーターを結合します。 たとえば、変換の入力が joe_smith@contoso.com、区切り記号が @、パラメーターが fabrikam.com の場合、この入力の組み合わせでは joe_smith@fabrikam.com という結果になります。
ToLowercase() 選択した属性の文字を小文字に変換します。
ToUppercase() 選択した属性の文字を大文字に変換します。
Contains() 入力が指定した値と一致する場合、属性または定数を出力します。 一致しない場合は、別の出力を指定できます。
たとえば、値がユーザーのメール アドレスで、そこに @contoso.com というドメインが含まれる場合、そのクレームは出力し、それ以外の場合はユーザーのプリンシパル名を出力したいとします。 この関数を実行するには、次の値を構成します。
Parameter 1 (入力) : user.email
Value: "@contoso.com"
Parameter 2 (出力): user.email
Parameter 3 (一致しない場合の出力): user.userprincipalname
EndWith() 入力が指定した値で終わっている場合、属性または定数を出力します。 一致しない場合は、別の出力を指定できます。
たとえば、ユーザーの従業員 ID が 000 で終わっている場合は従業員 ID を値とする要求を出力し、それ以外の場合は拡張属性を出力したいものとします。 この関数を実行するには、次の値を構成します。
Parameter 1 (入力) : user.employeeid
: "000"
Parameter 2 (出力): user.employeeid
Parameter 3 (一致しない場合の出力): user.extensionattribute1
StartWith() 入力が指定した値で始まっている場合、属性または定数を出力します。 一致しない場合は、別の出力を指定できます。
たとえば、国またはリージョンが US で始まっている場合はユーザーの従業員 ID を値とする要求を出力し、それ以外の場合は拡張属性を出力したいものとします。 この関数を実行するには、次の値を構成します。
Parameter 1 (入力) : user.country
: "US"
Parameter 2 (出力): user.employeeid
Parameter 3 (一致しない場合の出力): user.extensionattribute1
Extract() - 一致の後 指定した値との一致より後の部分文字列を返します。
たとえば、入力の値が Finance_BSimon で、一致する値が Finance_ の場合、クレームの出力は BSimon です。
Extract() - 一致の前 指定した値との一致より前の部分文字列を返します。
たとえば、入力の値が BSimon_US で、一致する値が _US の場合、クレームの出力は BSimon です。
Extract() - 一致の間 指定した値との一致より前の部分文字列を返します。
たとえば、入力の値が Finance_BSimon_US、1 番目の一致する値が Finance_、2 番目の一致する値が _US の場合、クレームの出力は BSimon です。
ExtractAlpha() - プレフィックス 文字列のプレフィックスのアルファベット部分を返します。
たとえば、入力の値が BSimon_123 の場合、BSimon が返されます。
ExtractAlpha() - サフィックス 文字列のサフィックスのアルファベット部分を返します。
たとえば、入力の値が 123_Simon の場合、Simon が返されます。
ExtractNumeric() - プレフィックス 文字列のプレフィックスの数字部分を返します。
たとえば、入力の値が 123_BSimon の場合、123 が返されます。
ExtractNumeric() - サフィックス 文字列のサフィックスの数字部分を返します。
たとえば、入力の値が BSimon_123 の場合、123 が返されます。
IfEmpty() 入力が null または空の場合、属性または定数を出力します。
たとえば、特定のユーザーの従業員 ID が空の場合に、拡張属性に格納されている属性を出力したいとします。 この関数を実行するには、次の値を構成します。
Parameter 1 (入力): user.employeeid
Parameter 2 (出力): user.extensionattribute1
Parameter 3 (一致しない場合の出力): user.employeeid
IfNotEmpty() 入力が null または空ではない場合、属性または定数を出力します。
たとえば、特定のユーザーの従業員 ID が空でない場合に、拡張属性に格納されている属性を出力したいとします。 この関数を実行するには、次の値を構成します。
Parameter 1 (入力): user.employeeid
Parameter 2 (出力): user.extensionattribute1
Substring() - 固定長 指定した位置にある文字から始まる文字列要求の種類の一部が抽出され、指定した文字数が返されます。
SourceClaim - 実行する必要がある変換のクレーム ソース。
StartIndex - このインスタンス内の substring の 0 から始まる開始文字位置。
Length - substring の文字の長さ。
次に例を示します。
sourceClaim - PleaseExtractThisNow
StartIndex - 6
Length - 11
出力: ExtractThis
Substring() - EndOfString 指定した位置にある文字から始まる文字列要求の種類の一部が抽出され、指定した開始インデックスから要求の残りが返されます。
SourceClaim - 変換のクレーム ソース。
StartIndex - このインスタンス内の substring の 0 から始まる開始文字位置。
次に例を示します。
sourceClaim - PleaseExtractThisNow
StartIndex - 6
出力: ExtractThisNow
RegexReplace() RegexReplace() 変換は、入力パラメーターとして次を受け入れます。
- パラメーター1:正規表現入力としてのユーザー属性
- ソースを複数値として信頼するオプション
‐正規表現パターン
‐置換パターン。 置換パターンには、正規表現出力グループを指す参照、および追加の入力パラメーターと共に、静的テキスト形式を含めることができます。

他の変換が必要な場合は、Microsoft Entra ID のフィードバック フォーラムSaaS アプリケーション カテゴリで、アイデアをお送りください。

正規表現ベースのクレーム変換

次の画像は、変換の第 1 レベルの例を示したものです。

Screenshot of the first level of transformation.

次の表では、変換の第 1 レベルに関する情報を示します。 表に示されているアクションは、前の画像のラベルに対応しています。 クレーム変換ブレードを開くには、[編集] を選びます。

アクション フィールド 説明
1 Transformation クレーム変換に正規表現ベースのクレーム変換メソッドを使うには、[変換] オプションから RegexReplace() オプションを選びます。
2 Parameter 1 正規表現変換の入力。 たとえば、admin@fabrikam.com のようなユーザー メール アドレスを含む user.mail。
3 Treat source as multivalued 一部の入力ユーザー属性は、複数値のユーザー属性になれます。 選んだユーザー属性で複数の値がサポートされている場合やユーザーが変換に複数値を使う場合は、[ソースを複数値として扱います] をオンにする必要があります。 オンにした場合は、すべての値が正規表現の照合に使われ、オフにした場合は、最初の値のみが使われます。
4 Regex pattern "パラメーター 1" として選ばれたユーザー属性の値に対して評価される正規表現。 たとえば、ユーザーのメール アドレスからユーザーの別名を抽出する正規表現は、(?'domain'^.*?)(?i)(\@fabrikam\.com)$ と表します。
5 Add additional parameter 複数のユーザー属性を変換に使用できます。 その場合、属性の値は正規表現の変換出力とマージされます。 最大 5 つの追加パラメーターがサポートされています。
6 Replacement pattern 置換パターンは、正規表現の結果に対するプレースホルダーを含むテキスト テンプレートです。 {group-name} のように、すべてのグループ名を中かっこで囲む必要があります。 たとえば、管理者は他のドメイン名 (例: xyz.com) と共にユーザーの別名を使い、国名をそれとマージしたいとします。 このケースでは、置換パターンは {country}.{domain}@xyz.com になります。{country} は入力パラメーターの値であり、{domain} は正規表現の評価からのグループ出力です。 このようなケースでは、予想される結果は US.swmal@xyz.com になります。

次の画像は、変換の 2 番目のレベルの例を示したものです。

Screenshot of second level of claims transformation.

次の表では、変換の 2 番目のレベルに関する情報を示します。 表に示されているアクションは、前の画像のラベルに対応しています。

アクション フィールド 説明
1 Transformation 正規表現ベースのクレーム変換は、第 1 の変換に限定されず、第 2 レベルの変換としても使用できます。 その他のいかなる変換方法も、最初の変換として使用できます。
2 Parameter 1 RegexReplace() が第 2 レベルの変換として選ばれている場合、第 1 レベルの変換の出力が第 2 レベルの変換の入力として使わされます。 変換を適用するには、第 2 レベルの正規表現式が、第 1 の変換の出力と一致する必要があります。
3 Regex pattern 正規表現パターンは第 2 レベルの変換の正規表現です。
4 Parameter input 第 2 レベルの変換に対するユーザー属性の入力。
5 Parameter input パラメーターが不要になった場合、管理者は選んだ入力パラメーターを削除できます。
6 Replacement pattern 置換パターンは、正規表現の結果グループ名、入力パラメーター グループ名、静的テキスト値のプレースホルダーを含むテキスト テンプレートです。 {group-name} のように、すべてのグループ名を中かっこで囲む必要があります。 たとえば、管理者は他のドメイン名 (例: xyz.com) と共にユーザーの別名を使い、国名をそれとマージしたいとします。 このケースでは、置換パターンは {country}.{domain}@xyz.com になります。{country} は入力パラメーターの値であり、{domain} は正規表現の評価からのグループ出力です。 このようなケースでは、予想される結果は US.swmal@xyz.com になります。
7 Test transformation RegexReplace() 変換は、"パラメーター 1" に選ばれたユーザー属性の値が [正規表現パターン] テキスト ボックスで指定されている正規表現と一致する場合にのみ評価されます。 一致しない場合は、既定のクレーム値がトークンに追加されます。 入力パラメーター値に対して正規表現を検証するには、変換ブレード内でテスト エクスペリエンスを使用できます。 このテスト エクスペリエンスはダミー値でのみ動作します。 追加の入力パラメーターを使うと、実際の値ではなく、パラメーターの名前がテスト結果に追加されます。 テスト セクションにアクセスするには、[テスト変換] を選びます。

次の図は、変換のテストの例を示したものです。

Screenshot of testing the transformation.

次の表では、変換のテストに関する情報を示します。 表に示されているアクションは、前の画像のラベルに対応しています。

アクション フィールド 説明
1 Test transformation [閉じる] または [X] ボタンを選ぶと、テスト セクションが非表示になり、[テスト変換] ボタンがブレードに再びレンダリングされます。
2 Test regex input 正規表現テストの評価に使われる入力を受け入れます。 正規表現ベースのクレーム変換が第 2 レベルの変換として構成されている場合、第 1 の変換の予想される出力を値として指定します。
3 Run test テスト正規表現の入力を指定し、正規表現パターン置換パターン入力パラメーターを構成したら、[テストの実行] を選んで式を評価できます。
4 Test transformation result 評価が成功した場合、テスト変換の出力は [Test transformation result] (テスト変換の結果) ラベルに表示されます。
5 Remove transformation 第 2 レベルの変換は、[変換を削除する] を選ぶことで削除できます。
6 Specify output if no match 正規表現と一致しない "パラメーター 1" に対して正規表現の入力値が構成されている場合、変換はスキップされます。 このようなケースでは、代替ユーザー属性を構成できます。[一致しない場合は出力を指定する] をオンにすると、それがクレームのトークンに追加されます。
7 Parameter 3 一致するものがなく、[一致しない場合は出力を指定する] がオンになっているときに、代替ユーザー属性を返す必要がある場合は、ドロップダウンを使って代替ユーザー属性を選択できます。 このドロップダウンは、[パラメーター 3 (一致しない場合は出力)] に対して使用できます。
8 Summary ブレードの下部には、簡単なテキストで変換の意味を説明するフォーマットの概要が表示されます。
9 Add 変換の構成設定を検証したら、[追加] を選んでクレーム ポリシーにそれを保存できます。 [要求の管理] ブレードで、[保存] を選択して変更内容を保存します。

RegexReplace() 変換は、グループ要求変換でも使用できます。

変換の検証

[追加] または [テストの実行] を選択した後に次の条件が発生すると、メッセージによって追加情報が提供されます。

  • ユーザー属性が重複する入力パラメーターが使用された。
  • 使われていない入力パラメーターが見つかりました。 定義された入力パラメーターは、置換パターン テキストでそれぞれ使用される必要があります。
  • 指定されたテスト正規表現入力が、指定された正規表現と一致しません。
  • 置換パターンのグループのソースが見つからない。

条件に基づいてクレームを出力する

ユーザーの種類とユーザーが属するグループに基づいて、要求のソースを指定することができます。

ユーザーの種類は次のとおりです。

  • 任意 - すべてのユーザーが、アプリケーションへのアクセスを許可されます。
  • メンバー: テナントのネイティブ メンバー
  • すべてのゲスト: Microsoft Entra ID を使用する、または使用しない外部の組織からアクセスするユーザー。
  • Microsoft Entra ゲスト: ゲスト ユーザーは、Microsoft Entra ID を使用する別の組織に属しています。
  • 外部のゲスト: ゲスト ユーザーは、Microsoft Entra ID のない外部組織に属します。

ユーザーの種類が役立つのは、クレームのソースが、ゲストとアプリケーションにアクセスする従業員とで異なる場合です。 ユーザーが従業員である場合は NameID を user.email から取得するように指定できます。 ユーザーがゲストの場合は、NameID は user.extensionattribute1 から取得されます。

要求条件を追加するには、次の手順を行います。

  1. [要求の管理] で、要求条件を展開します。
  2. ユーザーの種類を選択します。
  3. ユーザーが属するグループを選択します。 特定のアプリケーションに対するすべての要求で、最大 50 個の一意のグループを選択できます。
  4. クレームの値が取得される [ソース] を選択します。 ソース属性のドロップダウンからユーザー属性を選択するか、または要求として生成する前にユーザー属性に変換を適用することができます。

条件を追加する順序は重要です。 Microsoft Entra はまず、すべての条件をソース Attribute で評価し、クレームでどの値を出力するかを決定するためにすべての条件をソース Transformation で評価します。 Microsoft Entra ID は、同じソースで上から下まで条件を評価します。 クレームによって、クレームの式と一致する最後の値が出力されます。 IsNotEmptyContains などの変換は、制限のように機能します。

たとえば、Britta Simon は Contoso テナントのゲスト ユーザーです。 Britta は、同様に Microsoft Entra ID を使用する別の組織に属しています。 Fabrikam アプリケーションが次のように構成されている場合、Britta が Fabrikam にサインインしようとすると、Microsoft ID プラットフォームで条件が評価されます。

最初に、Microsoft ID プラットフォームにより、Britta のユーザーの種類がすべてのゲストかどうかが確認されます。 種類が [すべてのゲスト] であるため、Microsoft ID プラットフォームは、クレームのソースを user.extensionattribute1 に割り当てます。 次に、Microsoft ID プラットフォームでは、Britta のユーザーの種類が Microsoft Entra ゲストかどうかを確認します。 種類が [すべてのゲスト] であるため、Microsoft ID プラットフォームは、クレームのソースを user.mail に割り当てます。 最終的に、クレームは Britta の user.mail の値を使って出力されます。

もう 1 つの例として、Britta Simon が次の構成を使用してサインインしようとする場合を考えてみます。 Microsoft Entra はまず、すべての条件をソース Attribute で評価します。 Britta のユーザーの種類が [Microsoft Entra ゲスト] の場合、クレームのソースは user.mail です。 次に、変換が Microsoft Entra ID によって評価されます。 Britta はゲストであるため、user.extensionattribute1 がクレームの新しいソースです。 Britta は [Microsoft Entra ゲスト] であるため、user.othermail がこのクレームの新しいソースです。 最終的に、クレームは Britta の user.othermail の値を使って出力されます。

最後の例として、Britta の user.othermail が構成されていない場合、または空の場合にどうなるかを考えます。 どちらの場合も、条件エントリは無視され、クレームは user.extensionattribute1 にフォールバックします。

セキュリティに関する考慮事項

トークンを受信するアプリケーションは、改ざんできないクレーム値に依存します。 クレームのカスタマイズによってトークンの内容を変更すると、この前提は通用しなくなる可能性があります。 アプリケーションは、悪意のあるアクターによって作成されたカスタマイズからアプリケーションを保護するためにトークンが変更されたことを明示的に確認する必要があります。 次のいずれかの方法で不適切なカスタマイズから保護します。

これを行わない場合、Microsoft Entra ID は AADSTS50146 エラー コードを返します。

カスタム署名キーを構成する

マルチテナントのアプリでは、カスタム署名キーを使用するべきです。 アプリ マニフェストには acceptMappedClaims を設定しないでください。 Azure portal でアプリをセットアップすると、アプリ登録オブジェクトとサービス プリンシパルがテナントに作成されます。 そのアプリでは Azure グローバル サインイン キーを使用します。このキーではトークンのクレームをカスタマイズできません。 トークンにカスタム クレームを使用するには、証明書からカスタム サインイン キーを作成してサービス プリンシパルに追加します。 テスト目的で、自己署名証明書を使用してもかまいません。 カスタム署名キーを設定した後、アプリケーションのコードでトークン署名キーを検証する必要があります。

次の情報をサービス プリンシパルに追加します。

証明書からエクスポートした PFX ファイルから、base-64 でエンコードした秘密キーと公開キーを抽出します。 “Sign” に使用する keyCredentialkeyIdpasswordCredentialkeyId に一致することを確認します。 証明書の拇印のハッシュを取得することで、customkeyIdentifier を生成できます。

Request

Note

まず、Microsoft Entra 管理センターのアプリ登録ブレードから、新しく作成されたアプリのサービス プリンシパル ロック構成を無効にしてから、サービス プリンシパルの PATCH を実行すると、400 Bad Request が発生します。

次の例は、カスタム署名キーをサービス プリンシパルに追加する HTTP PATCH 要求の形式を示しています。 keyCredentials プロパティの “key” の値は、読みやすいように短縮してあります。 この値は base-64 でエンコードしてあります。 秘密キーでは、プロパティの “usage” (用途) は Sign です。 公開キーでは、プロパティの “usage” (用途) は Verify です。

PATCH https://graph.microsoft.com/v1.0/servicePrincipals/f47a6776-bca7-4f2e-bc6c-eec59d058e3e

Content-type: servicePrincipals/json
Authorization: Bearer {token}

{
    "keyCredentials":[
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=", 
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "X509CertAndPassword",
            "usage": "Sign",
            "key":"MIIKIAIBAz.....HBgUrDgMCERE20nuTptI9MEFCh2Ih2jaaLZBZGeZBRFVNXeZmAAgIH0A==",
            "displayName": "CN=contoso"
        },
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "e35a7d11-fef0-49ad-9f3e-aacbe0a42c42",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "AsymmetricX509Cert",
            "usage": "Verify",
            "key": "MIIDJzCCAg+gAw......CTxQvJ/zN3bafeesMSueR83hlCSyg==",
            "displayName": "CN=contoso"
        }

    ],
    "passwordCredentials": [
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
            "keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
            "endDateTime": "2022-01-27T19:40:33Z",
            "startDateTime": "2020-04-20T19:40:33Z",
            "secretText": "mypassword"
        }
    ]
}

PowerShell でカスタム署名キーを設定する

PowerShell で MSAL Public Client Application のインスタンスを作成しAuthorization Code Grant フローで Microsoft Graph に対する委任権限アクセス トークンを取得します。 このアクセス トークンを使用して Microsoft Graph を呼び出し、サービス プリンシパルに対してカスタム署名キーを設定します。 カスタム署名キーを設定した後、アプリケーションのコードでトークン署名キーを検証する必要があります。

このスクリプトを実行するには、次のものが必要です。

  • アプリケーションのサービス プリンシパルのオブジェクト ID。Azure portal の [Enterprise Applications]\(エンタープライズ アプリケーション\) の目的のアプリケーションの項目の [Overview]\(概要\) ブレードで確認できます。
  • ユーザーをサインインさせ、Microsoft Graph を呼び出すアクセス トークンを取得するためのアプリの登録。 Azure portal の [App registrations]\(アプリの登録)\ の目的のアプリケーションの項目の [Overview]\(概要\) ブレードで、このアプリのアプリケーション (クライアント) ID を取得します。 アプリを登録するには、次のものを設定する必要があります。
    • [モバイル アプリケーションとデスクトップ アプリケーション] プラットフォーム構成に一覧表示されている "http://localhost" のリダイレクト URI。
    • [API permissions] (API のアクセス許可) で、Microsoft Graph によって委任されたアクセス許可 Application.ReadWrite.AllUser.Read (これらのアクセス許可には管理者の同意を与える必要があります)。
  • ログインして Microsoft Graph アクセス トークンを取得するユーザー。 このユーザーは、次の Microsoft Entra 管理者ロールのどれかを持っている必要があります (サービス プリンシパルの更新に必要です)。
    • クラウド アプリケーション管理者
    • アプリケーション管理者
    • グローバル管理者
  • アプリケーションのカスタム署名キーに設定する証明書。 自己署名証明書を作成する方法と、信頼できる証明機関から証明書を取得する方法があります。 スクリプトでは、証明書に含まれる次のものを使用します。
    • 公開キー (通常 .cer ファイル)
    • PKCS#12 形式の秘密キー (.pfx ファイル)
    • 秘密キーのパスワード (.pfx ファイル)

重要

Microsoft Entra ID では他の形式をサポートしていないため、秘密キーは PKCS#12 形式である必要があります。 誤った形式を使った場合、証明書情報を保持する keyCredentials の存在するサービス プリンシパルを Microsoft Graph で PATCH すると、"Invalid certificate: Key value is invalid certificate" (無効な証明書: キー値が無効な証明書です) というエラーが発生する場合があります。

$fqdn="fourthcoffeetest.onmicrosoft.com" # this is used for the 'issued to' and 'issued by' field of the certificate
$pwd="mypassword" # password for exporting the certificate private key
$location="C:\\temp" # path to folder where both the pfx and cer file will be written to

# Create a self-signed cert
$cert = New-SelfSignedCertificate -certstorelocation cert:\currentuser\my -DnsName $fqdn
$pwdSecure = ConvertTo-SecureString -String $pwd -Force -AsPlainText
$path = 'cert:\currentuser\my\' + $cert.Thumbprint
$cerFile = $location + "\\" + $fqdn + ".cer"
$pfxFile = $location + "\\" + $fqdn + ".pfx"
 
# Export the public and private keys
Export-PfxCertificate -cert $path -FilePath $pfxFile -Password $pwdSecure
Export-Certificate -cert $path -FilePath $cerFile

$ClientID = "<app-id>"
$loginURL       = "https://login.microsoftonline.com"
$tenantdomain   = "fourthcoffeetest.onmicrosoft.com"
$redirectURL = "http://localhost" # this reply URL is needed for PowerShell Core 
[string[]] $Scopes = "https://graph.microsoft.com/.default"
$pfxpath = $pfxFile # path to pfx file
$cerpath = $cerFile # path to cer file
$SPOID = "<service-principal-id>"
$graphuri = "https://graph.microsoft.com/v1.0/serviceprincipals/$SPOID"
$password = $pwd  # password for the pfx file
 
 
# choose the correct folder name for MSAL based on PowerShell version 5.1 (.Net) or PowerShell Core (.Net Core)
 
if ($PSVersionTable.PSVersion.Major -gt 5)
    { 
        $core = $true
        $foldername =  "netcoreapp2.1"
    }
else
    { 
        $core = $false
        $foldername = "net45"
    }
 
# Load the MSAL/microsoft.identity/client assembly -- needed once per PowerShell session
[System.Reflection.Assembly]::LoadFrom((Get-ChildItem C:/Users/<username>/.nuget/packages/microsoft.identity.client/4.32.1/lib/$foldername/Microsoft.Identity.Client.dll).fullname) | out-null
  
$global:app = $null
  
$ClientApplicationBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientID)
[void]$ClientApplicationBuilder.WithAuthority($("$loginURL/$tenantdomain"))
[void]$ClientApplicationBuilder.WithRedirectUri($redirectURL)
 
$global:app = $ClientApplicationBuilder.Build()
  
Function Get-GraphAccessTokenFromMSAL {
    [Microsoft.Identity.Client.AuthenticationResult] $authResult  = $null
    $AquireTokenParameters = $global:app.AcquireTokenInteractive($Scopes)
    [IntPtr] $ParentWindow = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle
    if ($ParentWindow)
    {
        [void]$AquireTokenParameters.WithParentActivityOrWindow($ParentWindow)
    }
    try {
        $authResult = $AquireTokenParameters.ExecuteAsync().GetAwaiter().GetResult()
    }
    catch {
        $ErrorMessage = $_.Exception.Message
        Write-Host $ErrorMessage
    }
     
    return $authResult
}
  
$myvar = Get-GraphAccessTokenFromMSAL
if ($myvar)
{
    $GraphAccessToken = $myvar.AccessToken
    Write-Host "Access Token: " $myvar.AccessToken
    #$GraphAccessToken = "eyJ0eXAiOiJKV1QiL ... iPxstltKQ"
    
 
    #  this is for PowerShell Core
    $Secure_String_Pwd = ConvertTo-SecureString $password -AsPlainText -Force
 
    # reading certificate files and creating Certificate Object
    if ($core)
    {
        $pfx_cert = get-content $pfxpath -AsByteStream -Raw
        $cer_cert = get-content $cerpath -AsByteStream -Raw
        $cert = Get-PfxCertificate -FilePath $pfxpath -Password $Secure_String_Pwd
    }
    else
    {
        $pfx_cert = get-content $pfxpath -Encoding Byte
        $cer_cert = get-content $cerpath -Encoding Byte
        # Write-Host "Enter password for the pfx file..."
        # calling Get-PfxCertificate in PowerShell 5.1 prompts for password
        # $cert = Get-PfxCertificate -FilePath $pfxpath
        $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxpath, $password)
    }
 
    # base 64 encode the private key and public key
    $base64pfx = [System.Convert]::ToBase64String($pfx_cert)
    $base64cer = [System.Convert]::ToBase64String($cer_cert)
 
    # getting id for the keyCredential object
    $guid1 = New-Guid
    $guid2 = New-Guid
 
    # get the custom key identifier from the certificate thumbprint:
    $hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
    $hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($cert.Thumbprint))
    $customKeyIdentifier = [System.Convert]::ToBase64String($hash)
 
    # get end date and start date for our keycredentials
    $endDateTime = ($cert.NotAfter).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
    $startDateTime = ($cert.NotBefore).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
 
    # building our json payload
    $object = [ordered]@{    
    keyCredentials = @(       
         [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid1
            startDateTime = $startDateTime 
            type = "X509CertAndPassword"
            usage = "Sign"
            key = $base64pfx
            displayName = "CN=fourthcoffeetest" 
        },
        [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid2
            startDateTime = $startDateTime 
            type = "AsymmetricX509Cert"
            usage = "Verify"
            key = $base64cer
            displayName = "CN=fourthcoffeetest"   
        }
        )  
    passwordCredentials = @(
        [ordered]@{
            customKeyIdentifier = $customKeyIdentifier
            keyId = $guid1           
            endDateTime = $endDateTime
            startDateTime = $startDateTime
            secretText = $password
        }
    )
    }
 
    $json = $object | ConvertTo-Json -Depth 99
    Write-Host "JSON Payload:"
    Write-Output $json
 
    # Request Header
    $Header = @{}
    $Header.Add("Authorization","Bearer $($GraphAccessToken)")
    $Header.Add("Content-Type","application/json")
 
    try 
    {
        Invoke-RestMethod -Uri $graphuri -Method "PATCH" -Headers $Header -Body $json
    } 
    catch 
    {
        # Dig into the exception to get the Response details.
        # Note that value__ is not a typo.
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
        Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
    }
 
    Write-Host "Complete Request"
}
else
{
    Write-Host "Fail to get Access Token"
}

トークン署名キーを承認する

要求のマッピングが有効なアプリでは、OpenID Connect メタデータ要求appid={client_id} を追加して、トークン署名キーを検証する必要があります。 次の例は、使う必要がある OpenID Connect メタデータ ドキュメントの形式を示しています。

https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration?appid={client-id}

アプリケーション マニフェストを更新する

シングル テナントのアプリでは、アプリケーション マニフェストacceptMappedClaims プロパティを true に設定できます。 apiApplication リソースの種類に記載されているとおりです。 プロパティを設定することで、カスタム署名キーを指定せずに、アプリケーションでクレーム マッピングが使用できます。

警告

マルチテナント アプリでは acceptMappedClaims プロパティを true に設定しないでください。悪意のある者がアプリのクレームマッピング ポリシーを作成することを許可してしまう場合があります。

要求されたトークンの対象ユーザーは Microsoft Entra テナントの検証済みドメイン名を使用する必要があります。つまり、(アプリケーション マニフェスト内で identifierUris によって表される) Application ID URI を例えば https://contoso.com/my-api または、(単に既定のテナント名を使用して) https://contoso.onmicrosoft.com/my-api に設定する必要があります。

検証済みのドメインを使用していない場合、Microsoft Entra ID は AADSTS501461 エラー コードを、"_AcceptMappedClaims は、アプリケーション GUID と一致するトークン対象ユーザー、またはテナントの検証済みドメイン内の対象ユーザーでのみサポートされます。 リソース識別子を変更するか、アプリケーション固有の署名キーを使います。

クレームの詳細オプション

同じクレームを SAML トークンとして公開するには、OIDC アプリケーションに対してクレームの詳細オプションを構成します。 また、SAML2.0 と OIDC の両方の応答トークンに同じクレームを使用するアプリケーションについても同様です。

クレームの詳細オプションは、[要求の管理] ブレードの [クレームの詳細オプション] の下にあるチェックボックスをオンにすることで構成します。

次のステップ