1. 概要

Keycloakはきめ細かい認可ポリシーをサポートし、以下のような異なるアクセス・コントロール機構を組み合わせることができます。

  • 属性ベースのアクセス・コントロール(ABAC)

  • ロールベースのアクセス・コントロール(RBAC)

  • ユーザーベースのアクセス・コントロール(UBAC)

  • コンテキストベースのアクセス・コントロール(CBAC)

  • ルールベースのアクセス・コントロール

    • Javascriptを使用

    • JBoss Droolsを使用

  • 時間ベースのアクセス・コントロール

  • ポリシー・プロバイダー・サービス・プロバイダー・インターフェイス(SPI)によるカスタム・アクセス・コントロール機構(ACMs)のサポート

Keycloakは管理UIとRESTful APIのセットに基づいており、保護されるリソースとスコープのアクセス許可を作成し、そのアクセス許可を認可ポリシーに関連づけ、アプリケーションやサービスで認可判断を行うために必要な手段を提供します。

保護されたリソースへのアクセスを許可するかどうかを判定するために、リソースサーバー(保護されたリソースを処理するアプリケーションまたはサービス)は、通常、何らかの情報に依存しています。RESTfulベースのリソースサーバーの場合、通常、その情報はセキュリティトークンから取得されます。そのトークンは、通常、サーバーへのリクエストごとにベアラートークンとして送信されます。ユーザーを認証するためにセッションに依存するWebアプリケーションの場合、通常、その情報はユーザーのセッションに格納され、リクエストごとにそこから取得されます。

多くの場合、リソースサーバーはロールベースのアクセス・コントロール(RBAC)に基づいて認可判断のみを行います。ロールベースのアクセス・コントロールでは、保護されたリソースにアクセスしようとするユーザーに付与されたロールが、同リソースにマップされたロールに対してチェックされます。ロールは非常に有用でアプリケーションで使用されますが、以下のようないくつかの制限もあります。

  • リソースとロールは密結合されており、ロールへの変更(アクセス・コンテキストの追加、削除、変更など)は複数のリソースに影響を与える可能性があります。

  • セキュリティ要件の変更は、反映するにはアプリケーション・コードに大幅な変更が必要となるでしょう。

  • アプリケーションのサイズによっては、ロール管理が困難になり、エラーを起こしやすくなる可能性があります。

  • これは最も柔軟なアクセス・コントロール機構ではありません。ロールは、誰であるかを表すものではなく、コンテキスト情報が欠けています。ロールが付与されているということは、少なくともいくらかのアクセス権を持っている、ということを表すだけです。

今日、ユーザーは異なるローカルポリシーの異なる地域におり、異なるデバイスを使用し、情報共有のニーズが高い異種環境を考慮する必要があります。Keycloak認可サービスは以下を提供し、アプリケーションやサービスの認可機能を向上させるのに役立つでしょう。

  • きめ細かい認可ポリシーと異なるアクセス・コントロール機構を使用したリソース保護

  • 一元的なリソース、アクセス許可、およびポリシー管理

  • 一元的なポリシー決定点

  • 一連のRESTベースの認可サービスに基づくRESTセキュリティ

  • 認可ワークフローとUser-Managed Access

  • プロジェクト間でのコードの複製(と再デプロイ)を防止し、セキュリティ要件の変更に迅速に対応するのに役立つ基盤

1.1. アーキテクチャー

Keycloak AuthZアーキテクチャー概要

設計の観点から、認可サービスは、明確に定義された認可パターンのセットに基づいて次の機能を提供します。

  • ポリシー管理ポイント(PAP)

    リソースサーバー、リソース、スコープ、パーミッション、およびポリシーを管理するためのKeycloak管理コンソールに基づいたUIのセットを提供します。このうちの一部は、保護APIを使用してリモートでも実現できます。

  • ポリシー決定点(PDP)

    認可リクエストが送信され、リクエストが許可されることでポリシーが評価される場所に配布可能なポリシー決定点を提供します。このうちの一部は、エンタイトルメントAPIを使用してリモートでも実現されます。

  • ポリシー実施ポイント(PEP)

    異なる環境に実装を提供し、リソースサーバー側で実際に認可の決定を実施します。Keycloakには、組み込みのポリシー・エンフォーサーが用意されています。

  • ポリシー情報ポイント(PIP)

    Keycloak認証サーバーに基づいて、認可ポリシーの評価中にアイデンティティーとラインタイム環境から属性を取得できます。

1.1.1. 認可プロセス

Keycloakを使用してアプリケーションにきめ細かな権限を与える方法を、理解するために必要な手順を定義する3つの主要なプロセスは、以下のとおりです。

  • リソース管理

  • パーミッションとポリシーの管理

  • ポリシーの実施

リソース管理

リソース管理 には、何が保護されているかを定義するために必要なすべてのステップが含まれます。

リソース管理の概要

まず、保護しようとしているものをKeycloakに指定する必要があります。これは通常、Webアプリケーションまたは1つ以上のサービスのセットを表します。リソース・サーバーの詳細については、用語集を参照してください。

リソース・サーバーは、Keycloak管理コンソールを使用して管理されます。そこで、登録されたクライアント・アプリケーションをリソース・サーバーとして有効にし、保護するリソースとスコープの管理を開始できます。

リソースサーバの概要

リソースには、Webページ、RESTFulリソース、ファイルシステム内のファイル、EJBなどがあります。それらはリソースのグループ(Javaのクラスと同様)、または単一の特定のリソースを表すことができます。

例えば、すべての銀行口座を表す Bank Account リソースを持ったとして、それを使用してすべての銀行口座に共通する認可ポリシーを定義することができます。ただし、 Alice Account (顧客に属しているリソース・インスタンス)に対して特定のポリシーを定義したい場合は、オーナーだけが情報にアクセスしたり、操作を実行することができます。

リソースは、Keycloak管理コンソールまたは保護APIを使用して管理できます。後者の場合、リソースサーバーはリソースをリモートで管理できます。

スコープは、通常、リソースに対して実行できるアクションを表しますが、これに限定されるものではありません。スコープを使用して、リソース内の1つ以上の属性を表すこともできます。

権限とポリシーの管理

リソースサーバーと保護するすべてのリソースを定義したら、パーミッションとポリシーを設定する必要があります。

このプロセスには、リソースを管理するセキュリティおよびアクセス要件を実際に定義するために必要なすべての手順が含まれます。

パーミッションとポリシー管理の概要

ポリシーは、何か(リソースまたはスコープ)へのアクセスや操作を実行するために満たす条件を定義しますが、保護しているものとは結びついていません。これらは一般的なもので、パーミッションやさらに複雑なポリシーを構築するために再利用することができます。

例えば、ロール"User Premium"が付与されたユーザーに対してのみリソースのグループへのアクセスを許可するために、RBAC(ロールベースのアクセス・コントロール)を使用できます。

Keycloakには、最も一般的なアクセス・コントロール機構をカバーするいくつかの組み込みのポリシー・タイプ(およびそれぞれのポリシー・プロバイダー)が用意されています。JavaScriptやJBoss Droolsを使用して作成されたルールに基づいてポリシーを作成することもできます。

ポリシーを定義したら、パーミッションの定義を開始できます。パーミッションは、保護しているリソースと結合されます。ここでは、保護する対象(リソースまたはスコープ)と、パーミッションを許可または拒否するために満たす必要のあるポリシーを指定します。

ポリシー実施

Policy Enforcement には、リソースサーバーへの認可の決定を実際に実施するために必要な手順が含まれます。これは、認可サーバーと通信できるリソース・サーバーで Policy Enforcement Point またはPEPを有効にし、サーバーによって返された決定とパーミッションに基づいて認可データを要求し、保護されたリソースへのアクセスを制御することによって実現されます。

PEPの概要

Keycloakには、実行中のプラットフォームに応じてアプリケーションを保護するために使用できる組み込みのポリシー・エンフォーサー実装がいくつか用意されています。

1.1.2. 認可サービス

認可サービスは以下のRESTFul APIで構成されています。

  • 保護API

  • 認可API

  • エンタイトルメントAPI

これらの各サービスは、認可プロセスに関わるさまざまなステップをカバーする特定のAPIを提供します。

保護API

保護APIは、リソースサーバーがリソースとスコープを管理するのに役立つ細かい一連の操作を提供する、 UMA準拠 のエンドポイントです。リソースサーバーだけがこのAPIにアクセスできますが、 uma_protection スコープも必要です。

保護APIによって提供される操作は、次の2つの主要なグループに分けられます。

  • リソース管理

    • リソースの作成

    • リソースの削除

    • IDで検索

    • 全検索

    • フィルタで検索(例えば、名前、タイプ、またはURIで検索)

  • パーミッション管理

    • パーミッション・チケットの発行

デフォルトでは、リモートリソース管理が有効になっています。Keycloak管理コンソールを使用して変更することができ、コンソールからのリソース管理のみを許可できます。

UMAプロトコルを使用する場合、保護APIによるパーミッション・チケットの発行は、認可プロセス全体の重要な部分です。次のセクションで説明するように、これらはクライアントによって要求されたパーミッションを表し、要求されているリソースとスコープに関連付けられたパーミッションとポリシーの評価中に付与されたすべてのパーミッションを持つ最終的なトークンを取得するためにサーバーに送信されます。

より詳細な情報は保護APIを参照してください。

認可API

認可APIは、アクセス・トークンとパーミッション・チケットをリクエスティング・パーティー・トークン(RPT)と交換する単一の操作を提供する UMA準拠 のエンドポイントです。

RPTには、クライアントに付与されたすべてのパーミッションが含まれており、保護されたリソースにアクセスするためにリソースサーバーを呼び出す目的で使用できます。

RPTを要求する際に、以前に発行したRPTを提供することもできます。この場合、結果として得られるRPTは、以前のRPTのパーミッショとパーミッション・チケット内の新しいパーミッションの結合で構成されます。

認可APIの概要

詳細については、認可APIを参照してください。

1.1.3. エンタイトルメントAPI

エンタイトルメントAPIは、RPTを発行するための1-leggedプロトコルを提供します。認可APIとは異なり、エンタイトルメントAPIはアクセストークンのみを要求します。

このAPIから、ユーザー(特定のリソースサーバーによって管理されるリソースに基づいた)のすべてのエンタイトルメントまたはパーミッション、または1つ以上のリソースのセットに対するエンタイトルメントのみを取得できます。

エンタイトルメントAPIの概要

より詳細な情報はエンタイトルAPIを参照してください。

1.2. 用語

先に進む前に、Keycloak認可サービスで紹介されたこれらの用語と概念を理解することが重要です。

1.2.1. リソース・サーバー

OAuth2の用語では、リソース・サーバーは保護されたリソースをホスティングし、保護されたリソースへのリクエストを受け入れてレスポンスを返すことができます。

通常、リソース・サーバーは、保護されたリソースへのアクセスを許可するかどうかを決定するために、何らかの情報に依存しています。RESTfulベースのリソース・サーバーの場合、大抵、その情報はセキュリティー・トークンに格納され、一般的に、サーバーへのすべてのリクエストと一緒にベアラー・トークンとして送信されます。セッションを利用してユーザーを認証するWebアプリケーションは、その情報をユーザーのセッションに格納し、リクエストごとにそこから取得します。

Keycloakでは、 confidential クライアント・アプリケーションはリソース・サーバーとして動作できます。このクライアントのリソースとそれぞれのスコープは、一連の認可ポリシーによって保護、管理されます。

1.2.2. リソース

リソースは、アプリケーションと組織の資産の一部です。これは、1つ以上のエンドポイントのセット(HTMLページなどの古典的なWebリソースなど)です。認可ポリシーの用語では、リソースは保護される object です。

すべてのリソースには、単一のリソースまたはリソースのセットを表すことができる一意の識別子があります。例えば、すべての銀行口座に対して一連の認可ポリシーを表し定義する Banking Account Resource を管理することができます。ただし、 Alice’s Banking Account と呼ばれる別のリソースを持つこともできます。これは、単一の顧客が所有する単一のリソースを表し、独自の一連の認可ポリシーを持つことができます。

1.2.3. スコープ

リソースのスコープは、リソース上で実行可能な限定されたアクセスの範囲です。認可ポリシーの用語では、スコープは論理的にリソースに適用できる、潜在的に多くの verbs の1つです。

通常は、特定のリソースで何ができるかを示します。スコープの例としては、表示、編集、削除などです。ただし、リソースによって提供される特定の情報に関連付けることもできます。この場合、プロジェクト・リソースとコスト・スコープを持つことができます。コスト・スコープは、ユーザーがプロジェクトのコストにアクセスするための特定のポリシーとパーミッションを定義するために使用されます。

1.2.4. パーミッション

シンプルでとても一般的なパーミッションを考えてみましょう。

パーミッションは、保護されるオブジェクトと、アクセスが許可されるかどうかを判断するために評価されなければならないポリシーとを関連付けます。

  • X CAN DO Y ON RESOURCE Z

    • ここでは、X、Y、Zは以下を意味します。

      • X 1つ以上のユーザー、ロール、またはグループ、またはそれらの組み合わせを表します。クレームとコンテキストを使うこともできます。

      • Y 実行するアクション(書き込み、表示など)を表します。

      • Z "/accounts"などの保護されたリソースを表します。

Keycloakは、単純なルールから非常に複雑なルールベースの動的なパーミッションまで、幅広いパーミッション戦略を構築するための豊富なプラットフォームを提供します。柔軟性を提供し、次のことに役立ちます。

  • コードのリファクタリングとパーミッション管理のコストを削減

  • より柔軟なセキュリティー・モデルをサポートし、セキュリティー要件の変更に容易に対応できます

  • ランタイムに変更を加えます。アプリケーションは、保護されているリソースとスコープについてのみに関係し、それらがどのように保護されるかには関係ありません。

1.2.5. ポリシー

ポリシーは、オブジェクトへのアクセスを許可するために必要な条件を定義します。パーミッションとは異なり、保護されるオブジェクトを指定するのではなく、特定のオブジェクト(リソース、スコープ、またはその両方)へのアクセスを満たす条件を指定します。ポリシーは、リソースを保護するために使用できるさまざまなアクセス・コントロール・メカニズム(ACM)に強く関連しています。ポリシーを使用すると、属性ベースのアクセス・コントロール(ABAC)、ロールベースのアクセス・コントロール(RBAC)、コンテキストベースのアクセス・コントロール、またはこれらの任意の組み合わせのための戦略を実装できます。

Keycloakは、"ポリシーのポリシー"を構築して評価の動作を制御できる集約されたポリシーの概念を提供することによって、ポリシーの概念とその定義方法を活用します。特定のリソースへのアクセスを満たすすべての条件を含んだ1つの大きなポリシーを書くのではなく、Keycloak認可サービスのポリシー実装は分割統治のテクニックに従います。つまり、個々のポリシーを作成し、異なる権限でそれらを再利用し、個々のポリシーを組み合わせてより複雑なポリシーを構築することができます。

1.2.6. ポリシー・プロバイダー

ポリシー・プロバイダーは、特定のポリシー・タイプの実装です。Keycloakには、対応するポリシー・プロバイダーに基づいた組み込みのポリシーが用意されており、独自のポリシー・タイプを作成して特定の要件をサポートすることができます。

Keycloakには、独自のポリシー・プロバイダー実装をプラグイン化するために使用できるSPI(サービス・プロバイダー・インターフェイス)が用意されています。

1.2.7. パーミッション・チケット

パーミッション・チケットは、 OAuth2のUMA(User-Managed Access)プロファイル 仕様で定義された特別なタイプのトークンで、フォームが認可サーバーによって決定される不透明なストラクチャーを提供します。このストラクチャーは、クライアントによって要求されているリソースおよび(または)スコープ、および認可データのリクエスト(リクエスティング・パーティー・トークン[RPT])に適用する必要のあるポリシーを表します。

UMAでは、個人対個人の共有や個人対組織の共有をサポートするためにパーミッション・チケットが重要です。承認ワークフローにパーミッション・チケットを使用すると、単純なものから複雑なものまでさまざまなシナリオが可能になります。リソース・オーナーとリソース・サーバーは、これらのリソースへのアクセスを管理するきめ細かいポリシーに基づいてリソースを完全に制御できます。

UMAのワークフローでは、パーミッション・チケットは認可サーバーによってリソース・サーバーに発行されます。リソース・サーバーは、保護されたリソースにアクセスしようとするクライアントにパーミッション・チケットを返します。クライアントは、チケットを受信すると、チケットを認可サーバーに送り返すことによって、RPT(認可データを保持する最後のトークン)を要求することができます。

パーミッション・チケットの詳細については、認可APIおよび UMA 仕様を参照してください。

2. Getting Started

このチュートリアルをはじめる前に、Keycloakのインストールを完了し、Getting Started Guideのチュートリアルに沿って初期管理者ユーザーを作成する必要があります。これには注意事項があります。Keycloakサーバーと同じマシンで、別途WildFlyインスタンスを起動する必要があります。この別インスタンスではJavaサーブレットのアプリケーションを起動します。そのため、同じマシンで起動させる際にポートが競合しないように、異なるポートでKeycloakを起動する必要があります。コマンドラインで jboss.socket.binding.port-offset システムプロパティを使います。当プロパティの値は、Keycloakサーバーで開いた全ポートの基準値に加算される数値です。

Keycloakサーバーを起動するには下記を実行します。

Linux/Unix
$ .../bin/standalone.sh -Djboss.socket.binding.port-offset=100
Windows
> ...\bin\standalone.bat -Djboss.socket.binding.port-offset=100

WildFlyのインストールと設定方法の詳細については、Securing Applications and Services Guideチュートリアルの手順に従ってください。

インストールと両サーバーの起動後、Keycloak管理コンソールは http://localhost:8180/auth/admin/ 、WildFlyインスタンスは http://localhost:8080 でアクセス可能となります。

2.1. サーブレット・アプリケーションのセキュリティ保護

このgetting startedガイドの目的はできるだけ短時間でKeycloakの様々な認可機能を試すことができるようにすることです。本書はデフォルトのデータベースとサーバ設定に大きく依存したクイックツアーとなっています。複雑な配備オプションは本書の範囲外です。機能と設定の詳細については本書の適切な章を参照してください。

本ガイドはKeycloak認可サービスについての重要な概念を説明します。

  • クライアント・アプリケーションに対するきめ細かい認可の有効化

  • 保護されたリソースをもつリソースサーバーとしてのクライアント・アプリケーションの設定

  • 保護されたリソースへのアクセスを統括するためのパーミッションと認可ポリシーの定義

  • アプリケーションのポリシー実行の有効化

2.2. レルムとユーザーの作成

最初のステップは、そのレルムにレルムとユーザーを作成することです。レルムは次のように構成されています。

  • 単一のユーザー

  • 単一のクライアント・アプリケーション。認可サービスを有効にする必要があるリソースサーバーになります。

レルムとユーザーを作成するには、次の手順を実行します。

  1. hello-world-authz という名前のレルムを作成します。作成されると、次のようなページが表示されます。

    hello-world-authzレルム

    hello-world-authzレルム

  2. 新しく作成したレルムのユーザーを作成します。 Users をクリックします。ユーザーリストのページが開きます。

  3. 空のユーザーリストの右側にある Add User をクリックします。

  4. 新しいユーザーを作成するには、 UsernameEmailFirst NameLast Name フィールドを入力します。 User EnabledOn に切り替えて、 Save をクリックします。

    Add User

    ユーザーの追加

  5. Credentials タブをクリックして、ユーザーのパスワードを設定します。

    ユーザーのパスワード設定

    ユーザーのパスワード設定

  6. New PasswordPassword Confirmation フィールドにパスワードを入力し、 TemporaryOFF に切り替えます。

  7. Reset Password をクリックして、ユーザーのパスワードを設定します。

2.3. 認可サービスの有効化

OpenID Connectプロトコルを使用するように設定された既存のクライアント・アプリケーションで、認可サービスを有効にすることができます。新しいクライアントを作成することもできます。

新しいクライアントを作成するには、次の手順を実行します。

  1. Clients をクリックして新しいクライアント・アプリケーションの作成を開始し、 Client IDClient ProtocolRoot URL フィールドを入力します。

    クライアント・アプリケーションの作成

    クライアント・アプリケーションの作成

  2. Save をクリックします。クライアントの詳細ページが表示されます。

    クライアントの詳細

    クライアントの詳細

  3. クライアントの詳細ページで、 Authorization EnabledON に切り替えて Save をクリックします。新しい Authorization タブがクライアント用に表示されます。

  4. Authorization タブをクリックすると、次のような認可の設定ページが表示されます。

    認可の設定

    認可の設定

クライアント・アプリケーションの認可サービスを有効にすると、Keycloakはクライアントの認可設定のためのいくつかのデフォルト設定を自動的に作成します。

認可設定の詳細については、認可サービスの有効化を参照してください。

2.4. アプリケーションのビルド、デプロイ、およびテスト

app-authz-vanilla リソース・サーバー(またはクライアント)が正しく設定され、認可サービスが有効になったので、サーバーにデプロイすることができます。

デプロイするアプリケーションのプロジェクトとコードは、Keycloakクイックスタートリポジトリから入手できます。続行するには、マシンに以下をインストールし、PATHを通す必要があります。

  • Java JDK 8

  • Apache Maven 3.1.1以上

  • Git

You can obtain the code by cloning the repository at https://github.com/keycloak/keycloak-quickstarts. The quickstarts are designed to work with the most recent Keycloak release.

コードをダウンロードするには、次の手順に従います。

プロジェクトのクローン
$ git clone https://github.com/keycloak/keycloak-quickstarts

ビルドおよびデプロイをするアプリケーションは次の場所にあります

$ cd keycloak-quickstarts/app-authz-jee-vanilla

2.4.1. アダプターの設定を取得

アプリケーションをビルドおよびデプロイする前に、まずアダプターの設定を取得する必要があります。

Keycloak管理コンソールからアダプターの設定を取得するには、以下の手順を実行します。

  1. Clients をクリックします。クライアントの一覧で、 app-authz-vanilla クライアント・アプリケーションをクリックします。クライアントの詳細ページが開きます。

    クライアントの詳細

    クライアントの詳細

  2. Installation タブをクリックします。Format Optionドロップダウン・リストから、 Keycloak OIDC JSON を選択します。アダプターの設定はJSON形式で表示されます。 Download をクリックします。

    アダプターの設定

    アダプターの設定

  3. keycloak.json ファイルを app-authz-jee-vanilla/config ディレクトリーに移動します。

  4. (省略可能)デフォルトでは、ポリシー・エンフォーサーは、ユーザーがリソース・サーバー上の保護されたリソースにアクセスする許可がない場合に、 403 ステータス・コードで応答します。ただし、権限のないユーザーに対して、リダイレクトURLを指定することもできます。リダイレクトURLを指定するには、手順3で更新した keycloak.json ファイルを編集し、 policy-enforcer の設定を次のものに置き換えます。

    "policy-enforcer": {
    "on-deny-redirect-to" : "/app-authz-vanilla/error.jsp"
    }

    この変更は、保護されたリソースにアクセスするための必要な権限を持っていない場合に、ポリシー・エンフォーサーに対して、ユーザーを /app-authz-vanilla/error.jsp ページにリダイレクトするよう指定します(役に立たない 403 Unauthorized メッセージを返すのではなく)。

2.4.2. アプリケーションのビルドとデプロイ

アプリケーションをビルドしてデプロイするには、次のコマンドを実行します。

$ cd redhat-sso-quickstarts/app-authz-jee-vanilla
$ mvn clean package wildfly:deploy

2.4.3. アプリケーションのテスト

アプリケーションが正常にデプロイされた場合は、 http://localhost:8080/app-authz-vanilla でアクセスできます。Keycloakログインページが開きます。

ログインページ

ログインページ

ユーザー alice として、指定したパスワードでログインします。認証後、次のページが表示されます。

Hello World Authzメインページ

Hello World Authzメインページ

クライアント・アプリケーションの認可サービスを有効にしたときに、Keycloakで定義されたデフォルト設定は、このポリシーで保護されているリソースへのアクセスを常に許可する単純なポリシーを提供します。

まず、デフォルトのアクセス許可とポリシーを変更し、アプリケーションの応答方法をテストするか、Keycloakが提供するさまざまなポリシータイプを使用して新しいポリシーを作成します。

このアプリケーションをテストするために今できることはたくさんあります。例えば、クライアントのAuthorizationタブをクリックし、 Policies タブをクリックして、デフォルトポリシーを変更することができます。次に、リスト内の `Default Policy`をクリックします。

//デフォルト値は$evaluation.grant()です。
//$evaluation.deny()に変更したときに何が起こるかを見てみましょう。
$evaluation.deny();

さて、デモアプリケーションからログアウトして、もう一度ログインしてください。アプリケーションにアクセスできなくなりました。

アクセスが拒否されたページ

これを修正してみましょう。 Default Policy コードを変更する代わりに、ポリシー・コードのテキストエリアの下にあるドロップダウン・リストを使用して、 LogicNegative に変更します。これにより、デフォルトではすべてのアクセス要求が拒否されますが、そのポリシーの結果が否定されるため、アプリケーションへのアクセスが再度有効になります。再度、この変更をテストする前に、必ずログアウトして再ログインしてください。

2.4.4. 次のステップ

追加で次のようなことができます。

  • スコープを作成し、ポリシーとアクセス許可を定義し、アプリケーション側でテストします。ユーザーがアクション(または作成したスコープで表されるもの)を実行できるでしょうか?

  • ルールベースなどの異なるタイプのポリシーを作成し、これらのポリシーを Default Permission に関連付けます。

  • 複数のポリシーを Default Permission に適用し、動作をテストします。 例えば、複数のポリシーを組み合わせて、それに応じて Decision Strategy を変更します。

  • アプリケーション内で権限を表示およびテストする方法の詳細については、認可コンテキストの取得を参照してください。

2.5. サンプル

Keycloak Authorizationは、認可サービスを迅速に開始し、開発するアプリケーションに同じ概念を適用する方法を理解するのにも役立ちます。

次のKeycloakのデモ用配布物を使用しており、ファイルシステムに適切に展開している場合は、

  • keycloak-demo-3.4.3.Final.[zip|tar.gz]

以下のディレクトリから利用可能なサンプルをチェックアウトすることができます。

cd ${KEYCLOAK_DEMO_SERVER_DIR}/examples/authz

または、GitHubから入手できます。

各サンプルには、そのサンプルをビルド、デプロイ、テストする方法を説明するREADMEファイルがあります。

各サンプルの簡単な説明は次のとおりです。

Table 1. 認可のサンプル
名前 説明

hello-world-authz-service

Keycloackサーバーから取得した権限を基に、ユーザーがそのページにアクセスできるかどうかを判定するPolicy Enforcerによって保護されたシングルページ・アプリケーションです。

photoz

HTML5 + AngularJS + JAX-RSをベースにつくられたシンプルなアプリケーションで、RESTFulベースのサービスとHTML5クライアントに対するきめ細かなアクセス許可を有効にする方法を示します。

servlet-authz

JBoss/Wildflyサーブレットアプリケーションに対するきめ細かな認可を有効にする方法を示すサーブレットベースのアプリケーションです。

3. リソースサーバーの管理

OAuth2の仕様によれば、リソース・サーバーは保護されたリソースをホストし、保護されたリソースへのリクエストを受け入れて応答することができるサーバーです。

Keycloakでは、リソース・サーバーに保護されたリソースに対してきめ細かい認可を与えるための豊富なプラットフォームが用意されており、異なるアクセス制御の仕組みに基いた認可決定を行うことができます。

きめ細かいパーミッションをサポートするクライアント・アプリケーションを設定することができます。その際に、概念的にクライアント・アプリケーションをリソース・サーバーに変換します。

3.1. クライアント・アプリケーションの作成

Keycloak認可サービスを有効にするための最初の手順は、リソースサーバーにするクライアント・アプリケーションを作成することです。

クライアント・アプリケーションを作成するには、次の手順を実行します。

  1. Clients をクリックします。

    Clients

    クライアント

  2. このページで、 Create をクリックします。

    クライアントの作成

    クライアントの作成

  3. クライアントの Client ID を入力します。例えば、 my-resource-server

  4. アプリケーションの Root URL を入力します。例えば

    http://${host}:${port}/my-resource-server
  5. Save をクリックします。クライアントが作成され、クライアントの設定ページが開きます。次のようなページが表示されます。

    クライアントの設定

    クライアントの設定

3.2. 認可サービスの有効化

OIDCクライアント・アプリケーションをリソースサーバーに変えて、きめ細かい認可を有効にするには、 Authorization EnabledON にして Save をクリックします。

認可サービスの有効化

認可サービスの有効化

クライアントに新しいAuthorizationタブが表示されます。 Authorization タブをクリックすると、次のようなページが表示されます。

リソースサーバーの設定

リソースサーバーの設定

Authorizationタブには、アプリケーションのリソースを実際に保護するために従わなければならないさまざまなステップを補う追加のサブタブが含まれています。各タブは、このドキュメントの特定のトピックで個別に補足されています。ここではそれぞれについて簡単に説明します。

  • Settings

    リソースサーバーの一般設定。このページの詳細については、リソースサーバーの設定のセクションを参照してください。

  • Resource

    このページから、アプリケーションのリソースを管理できます。

  • Scope

    このページから、スコープを管理できます。

  • Policies

    このページから、認可ポリシーを管理し、許可を得るために必要な条件を定義することができます。

  • Permissions

    このページから、保護されたリソースとスコープの権限を、作成したポリシーとリンクさせることにより管理できます。

  • Evaluate

    このページでは、認可リクエストのシミュレート、および定義した権限と認可ポリシーの評価結果を表示できます。

3.2.1. リソースサーバーの設定

リソースサーバー設定ページでは、ポリシーの強制モードの設定や、リモートリソース管理の許可、認可構成の設定のエクスポートができます。

  • Policy Enforcement Mode

    サーバーに送信された認可要求を処理するときに、ポリシーがどのように強制されるかを指定します。

    • Enforcing

      (default mode) Requests are denied by default even when there is no policy associated with a given resource.

    • Permissive

      Requests are allowed even when there is no policy associated with a given resource.

    • Disabled

      すべてのポリシーの評価を無効にし、すべてのリソースへのアクセスを許可します。

  • Allow Remote Resource Management

    リソースサーバーによってリソースをリモート管理できるかどうかを指定します。falseの場合、リソースは管理コンソールからのみ管理できます。

  • Export Settings

    認可構成の設定をJSONファイルにエクスポートできます。 Export をクリックするとダウンロード用のJSON設定がすべて表示されます。設定ファイルには、リソースサーバーに対して定義されているすべてのもの(保護されたリソース、スコープ、アクセス許可、およびポリシー)が含まれています。

3.3. デフォルト設定

リソース・サーバーを作成すると、Keycloakは新しく作成したリソース・サーバーのデフォルト設定を作成します。

デフォルト設定は次の通りです。

  • アプリケーションのすべてのリソースを表すデフォルトの保護されたリソース。

  • このポリシーで保護されているリソースへのアクセスを常に許可するポリシー。

  • デフォルトのポリシーに基づいてすべてのリソースへのアクセスを管理するパーミッション。

デフォルトの保護されたリソースは default resource と呼ばれ、 Resources タブに移動すると表示できます。

デフォルト・リソース

デフォルト・リソース

このリソースは Type 、すなわち urn:my-resource-server:resources:defaultURI /* を定義します。ここで、URIフィールドは、このリソースがアプリケーションのすべてのパスを表すことをKeycloakが示すワイルドカード・パターンで定義します。つまり、アプリケーションのポリシー適用を有効にすると、アクセス権を付与する前に、リソースに関連付けられているすべてのパーミッションが検査されます。

前述の Type は、デフォルトのリソースまたは同じタイプを使用して作成したリソースに適用させるタイプ付きリソース・パーミッションを作成するために使用できる値を定義します。

デフォルトのポリシーは、 only from realm policy と呼ばれ、 Policies タブに移動すると表示できます。

デフォルト・ポリシー

デフォルト・ポリシー

このポリシーは、ポリシーで保護されているリソースへのアクセスを常に許可する条件を定義したJavaScriptベースのポリシーです。このポリシーをクリックすると、次のようにルールが定義されていることが分かります。

// デフォルトでは、このポリシーに関連する全てのパーミッションを付与します。
$evaluation.grant();

最後に、デフォルトのパーミッションは、 default permission と呼ばれ、 Permissions タブに移動すると表示できます。

デフォルト・パーミッション

デフォルト・パーミッション

このパーミッションはリソースベースのパーミッションで、特定のタイプのすべてのリソースに適用される1つ以上のポリシーのセットを定義します。

3.3.1. デフォルト設定の変更

デフォルトの設定を変更するには、デフォルトのリソース、ポリシー、またはパーミッションの定義を削除し、独自の定義を作成します。

デフォルトのリソースは、 /* パターンを使用してアプリケーション内のリソースまたはパスにマップされる URI で作成されます。独自のリソース、権限、ポリシーを作成する前に、デフォルト設定が自分の設定と矛盾しないことを確認してください。

デフォルト設定では、アプリケーションのすべてのパスに対応するリソースを定義します。独自のリソースにパーミッションを書き込もうとしている場合は、 Default Resource を削除するか、 URI フィールドをアプリケーション内の特定のパスに変更してください。それ以外の場合は、デフォルト・リソース(デフォルトでは常にアクセスを許可する)に関連付けられたポリシーにより、Keycloakは保護されたリソースへのアクセスを許可します。

3.4. 認可設定のエクスポートおよびインポート

リソースサーバー(またはクライアント)の構成設定をエクスポートおよびダウンロードできます。また、リソースサーバーの既存の設定ファイルをインポートすることもできます。設定ファイルのインポートとエクスポートは、リソースサーバーの初期設定を作成したり、既存の設定を更新する場合に役立ちます。設定ファイルには次の定義が含まれています。

  • 保護されたリソースとスコープ

  • ポリシー

  • パーミッション

3.4.1. 設定ファイルのエクスポート

設定ファイルをエクスポートするには、次の手順を実行します。

  1. Resource Server Settings ページに移動します。

    リソースサーバーの設定

    リソースサーバーの設定

  2. このページのエクスポート設定のセクションで、 Export をクリックします。

    エクスポートの設定

    エクスポートの設定

設定ファイルはJSON形式でエクスポートされ、テキストエリアに表示されます。そこからコピーして貼り付けることができます。 また、 Download をクリックし、設定ファイルをダウンロードして保存することもできます。

3.4.2. 設定ファイルのインポート

リソースサーバーの設定ファイルをインポートするには、 Select file をクリックして、インポートしたい設定ファイルを選択します。

4. リソースとスコープの管理

リソース管理は簡単かつ一般的です。リソースサーバーを作成したら、保護するリソースとスコープの作成を開始できます。リソースおよびスコープは、 Resource タブおよび Scope タブにそれぞれナビゲートすることで管理できます。

4.1. リソースの表示

Resource ページには、リソースサーバーに関連付けられているリソースの一覧が表示されます。

リソース

Resources

リソースリストには、次のような保護されたリソースに関する情報が表示されます。

  • タイプ

  • URI

  • オーナー

  • 関連スコープ(存在する場合)

  • 関連するパーミッション

このリストから、パーミッションを作成したいリソースに対して Create Permission をクリックして、パーミッションを直接作成することもできます。

リソースに対するパーミッションを作成する前に、そのパーミッションに関連付けたいポリシーを定義済みであることを確認してください。

4.2. リソースの作成

リソースの作成は簡単で一般的です。主な関心事は、作成するリソースの粒度です。言い換えれば、1つ以上のリソースのセットを作成することができ、それらを定義する方法はパーミッションを管理するために重要なことです。

新しいリソースを作成するには、リソース・リストの右上にある Create をクリックします。

リソースの追加

リソースの追加

Keycloakでは、リソースは、次のようなさまざまなタイプのリソースに共通する細かい情報のセットを定義します。

  • Name

    このリソースを説明する、人間が読める形式で一意な文字列。

  • Type

    1つ以上のリソースのセットのタイプを一意に識別する文字列。タイプは、異なるリソース・インスタンスをグループ化するために使用される string です。例えば、自動的に作成されるデフォルト・リソースのデフォルトのタイプは、urn:resource-server-name:resources:default です。

  • URI

    リソースのロケーション/アドレスを提供するURI。HTTPリソースの場合、URIは通常、これらのリソースを提供するために使用される相対パスです。

  • Scopes

    リソースに関連付ける1つ以上のスコープ。

4.2.1. タイプ付きのリソース

リソースのタイプ・フィールドは、さまざまなリソースをグループ化するために使用できます。そのため、共通のパーミッションのセットを使用して保護することができます。

4.2.2. リソース・オーナー

リソースはオーナーを持ちます。デフォルトでは、リソースはリソース・サーバーによって所有されています。

ただし、リソースはユーザーと関連付けることもできるため、リソース・オーナーに基づいてパーミッションを作成できます。例えば、リソース・オーナーだけが特定のリソースを削除または更新することができます。

4.2.3. リモートでリソースを管理する

リソース管理は、保護APIを介しても公開され、リソース・サーバーがリソースをリモートで管理できます。

保護APIを使用すると、リソース・サーバーを実装して、ユーザーが所有するリソースを管理できます。この場合、リソースを特定のユーザーに属するものとして設定するためのユーザー識別子を指定できます。

Keycloakは、リソース・サーバーがリソースを完全に制御できるようにします。将来的には、特にUMAプロトコルを使用している場合に、ユーザーが自分のリソースを制御したり、認可リクエストを承認したり、パーミッションを管理できるようにする必要があります。

5. ポリシーの管理

前の章で述べたように、ポリシーはオブジェクトへのアクセスを与えられる前に満たすべき条件を定義します。

リソース・サーバーに関連付けられたポリシーを閲覧するには、リソース・サーバーの設定画面上の Policy タブをクリックします。

ポリシー

Policies

このタブでは、ポリシーの閲覧、作成、変更を行うことができます。

新規ポリシーを作成するには、ポリシーのリストの右上の Create policy ドロップダウン・リストからポリシー・タイプを選択します。それぞれのポリシー・タイプの詳細については本章で説明します。

5.1. ユーザー・ベース・ポリシー

1人以上のユーザーの集合がオブジェクトへのアクセスを許可されるパーミッションの条件を定義するために、このタイプのポリシーを使用することができます。

新しいユーザー・ベース・ポリシーを作成するには、ポリシーリストの右上隅にあるドロップダウン・リストから User を選択します。

ユーザー・ベース・ポリシーの追加

ユーザー・ベース・ポリシーの追加

5.1.1. 設定

  • Name

    A human-readable and unique string identifying the policy. A best practice is to use names that are closely related to your business and security requirements, so you can identify them more easily.

  • Description

    A string containing details about this policy.

  • Users

    このポリシーによってアクセス権が与えられるユーザーを指定します。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

5.2. ロール・ベース・ポリシー

1つ以上のロールの集合がオブジェクトへのアクセスを許可されるパーミッションの条件を定義するために、このタイプのポリシーを使用することができます。

デフォルトでは、このポリシーに追加されたロールは、Requiredとして指定されず、アクセスを要求するユーザーにこれらのロールのいずれかが付与されている場合に、ポリシーはアクセスを許可します。ただし、特定のロールを強制したい場合は、Requiredとして特定のロールを指定できます。レルムまたはクライアントのロールにかかわらず、RequiredのロールとRequiredではないロールを組み合わせることもできます。

ロールのポリシーは、オブジェクトへのアクセスを許可するのに特定のロールを強制する必要がある、より限定されたロールベースのアクセス・コントロール(RBAC)が必要な場合に役立ちます。例えば、ユーザーがクライアント・アプリケーション(ユーザーの代理として動作している)がユーザーのリソースにアクセスできるようにするのにユーザーが同意する必要があることを強制できます。Keycloakクライアント・スコープ・マッピングを使用して同意ページを有効にしたり、Keycloakサーバーからアクセス・トークンを取得するときに明示的にスコープを指定したりすることもできます。

新しいロール・ベース・ポリシーを作成するには、ポリシーリストの右上隅にあるドロップダウンリストから Role を選択します。

ロール・ベース・ポリシーの追加

ロール・ベース・ポリシーの追加

5.2.1. 設定

  • Name

    ポリシーを説明する、人が判読可能で一意の文字列。ベストプラクティスは、ビジネス要件とセキュリティ要件に密接に関連する名前を使用することです。そうすることで簡単に識別することができます。

  • Description

    A string containing details about this policy.

  • Realm Roles

    このポリシーによって、どの realm ロールが許可されるかを指定します。

  • Client Roles

    このポリシーで許可される client ロールを指定します。このフィールドを有効にするには、最初に Client を選択する必要があります。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

5.2.2. ロールを必須として定義する

ロールベース・ポリシーを定義するとき、特定のロールを Required と指定することができます。こうすることで、 全て必須 ロールを付与されたユーザーにのみアクセス権を与えることができます。レルムロールとクライアントロールの両方にこの設定を適用することができます。

必須ロールの例

Example of Required Role

ロールを必須と指定するには、そのロールの Required チェックボックスをチェックします。

複数のロールがポリシーに定義されており、そのうちのいくつかが必須の場合にこの機能は有用です。より細かいロールベース・アクセス・コントロール(RBAC)のためにレルムロールとクライアントロールを組み合わせることが可能です。例えば、あるクライアントに適用されるポリシーがある場合、そのクライアントに関連付けられた特定のクライアントロールを必須とすることができます。また、特定のレルムロールを持つ場合のみアクセスを許可することもできます。1つのポリシーに両方のアプローチを適用することもできます。

5.3. JavaScriptベースポリシー

このポリシーは、JavaScriptを使用可能にする条件を定義するために使うことができます。これはKeycloakによってサポートされるルール・ベースのポリシータイプの1つであり、評価APIに基づいて任意のポリシーを柔軟に作成できます。

新しいJavaScriptベースポリシーを作成するには、ポリシーリストの右上隅にあるドロップダウン・リストから JavaScript を選択します。

JavaScriptポリシーの追加

JavaScriptポリシーの追加

5.3.1. 設定

  • Name

    ポリシーを説明する、人が判読可能で一意の文字列。ベストプラクティスは、ビジネス要件とセキュリティ要件に密接に関連する名前を使用することです。そうすることで簡単に識別することができます。

  • Description

    A string containing details about this policy.

  • Code

    このポリシーの条件を指定するJavaScriptコード。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

5.3.2. サンプル

コンテキストから取得した属性で条件を定義するために、属性ベース・アクセス・コントロール(ABAC)を使用するJavaScriptベースポリシーの簡単な例です。

var context = $evaluation.getContext();
var contextAttributes = context.getAttributes();

if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
    $evaluation.grant();
}

ロール・ベース・アクセス・コントロール(RBAC)を使用することもできます。以下の例では、ユーザーが keycloak_user レルム ロールを与えられているかどうかを調べています。

var context = $evaluation.getContext();
var identity = context.getIdentity();

if (identity.hasRealmRole('keycloak_user')) {
    $evaluation.grant();
}

または、ユーザが my-client-role クライアント ・ロールを与えられているかどうかを確認できます。my-clientはクライアント・アプリケーションのクライアントIDです。

var context = $evaluation.getContext();
var identity = context.getIdentity();

if (identity.hasClientRole('my-client', 'my-client-role')) {
    $evaluation.grant();
}

いくつかのアクセス・コントロール機構の組み合わせを使用することもできます。 以下の例は、同じポリシー内でロール(RBAC)とクレーム/属性(ABAC)のチェックをどのように使用できるかを示しています。この場合は、ユーザーが admin ロールを与えられているか、または、keycloak.org ドメインの電子メールを持っているかどうかを調べています。

var context = $evaluation.getContext();
var identity = context.getIdentity();
var attributes = identity.getAttributes();
var email = attributes.getValue('email').asString(0);

if (identity.hasRealmRole('admin') || email.endsWith('@keycloak.org')) {
    $evaluation.grant();
}
独自のルールを作成するときは、 $evaluation オブジェクトが org.keycloak.authorization.policy.evaluation.Evaluation を実装するオブジェクトであることに注意してください。このインターフェイスからアクセスできるものの詳細については、評価APIを参照してください。

5.4. ルールベースのポリシー

このタイプのポリシーでは、ルール評価環境である Drools を使用してパーミッションの条件を定義できます。これはKeycloakでサポートされている ルールベース のポリシー・タイプの1つであり、評価APIに基づいたポリシーを柔軟に作成できます。

新しいルールベースのポリシーを作成するには、ポリシーリストの右上隅にあるドロップダウン・リストで、 Rule を選択します。

ルールポリシーの追加

ルールポリシーを追加

5.4.1. 設定

  • Name

    ポリシーを説明する、人が判読可能な一意の文字列。ビジネス要件とセキュリティ要件に密接に関連する名前を使用することを強くお勧めします。そうすることで簡単に識別することができます。

  • Description

    このポリシーの詳細を示す文字列。

  • Policy Maven Artifact

    ルールが定義されているアーティファクトを指し示すMavenのgroupId-artifactId-version(GAV)。GAVを提供したら、 Resolve をクリックして、 ModuleSession フィールドの両方を読み込むことができます。

    • Group Id

      アーティファクトのgroupId。

    • Artifact Id

      アーティファクトのartifactId。

    • Version

      アーティファクトのversion。

  • Module

    このポリシーで使用されるモジュール。ルールがロードされる特定のセッションを選択するためのモジュールを提供する必要があります。

  • Session

    このポリシーで使用されるセッション。セッションは、ポリシーの処理時に評価するすべてのルールを提供します。

  • Update Period

    アーティファクトの更新をスキャンする間隔を指定します。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

5.4.2. サンプル

認証されたユーザーがリクエストされたリソースのオーナーである場合にのみ、GRANTに評価される条件を定義するために属性ベースのアクセス・コントロール(ABAC)を使用するDroolsベースのポリシーの簡単な例を次に示します。

import org.keycloak.authorization.policy.evaluation.Evaluation;
rule "Authorize Resource Owner"
    dialect "mvel"
    when
       $evaluation : Evaluation(
           $identity: context.identity,
           $permission: permission,
           $permission.resource != null && $permission.resource.owner.equals($identity.id)
       )
    then
        $evaluation.grant();
end

アイデンティティから属性を取得し、それに応じて条件を定義するために、ABAC(属性ベースのアクセス・コントロール)の別のバリアントを使用することもできます。

import org.keycloak.authorization.policy.evaluation.Evaluation;
rule "Authorize Using Identity Information"
    dialect "mvel"
    when
       $evaluation : Evaluation(
           $identity: context.identity,
           identity.attributes.containsValue("someAttribute", "you_can_access")
       )
    then
        $evaluation.grant();
end

org.keycloak.authorization.policy.evaluation.Evaluation インターフェイスからアクセスできるものの詳細については、<< _ policy_evaluation_api, 評価 API >>を参照してください。

5.5. タイムベース・ポリシー

このタイプのポリシーを使用して、パーミッションの時間条件を定義することができます。

新しいタイム・ベース・ポリシーを作成するには、ポリシーリストの右上隅にあるドロップダウン・リストから Time を選択します。

タイムポリシーの追加

タイムポリシーの追加

5.5.1. 設定

  • Name

    ポリシーを説明する、人が判読可能で一意の文字列。ベストプラクティスは、ビジネス要件とセキュリティ要件に密接に関連する名前を使用することです。そうすることで簡単に識別することができます。

  • Description

    A string containing details about this policy.

  • Not Before

    アクセスを許可 しない 時間を定義します。現在の日付/時刻がこの値よりも後の場合にのみ許可が与えられます。

  • Not On or After

    アクセスを許可 しない 時間を定義します。 現在の日付/時刻がこの値より前の場合にのみ、許可が与えられます。

  • Day of Month

    アクセスを許可する月の日を定義します。また、日付の範囲を指定することもできます。この場合、その月の現在の日が指定された2つの値の間にあるまたは等しい場合にのみ許可が与えられます。

  • Month

    アクセスを許可する月を定義します。また、月の範囲を指定することもできます。この場合、現在の月が指定された2つの値の間にあるまたは等しい場合にのみ許可が与えられます。

  • Year

    アクセスを許可する年を定義します。また、年の範囲を指定することもできます。この場合、現在の年が指定された2つの値の間にあるまたは等しい場合にのみ許可が与えられます。

  • Hour

    アクセスを許可する時間を定義します。また、時間の範囲を指定することもできます。この場合、現在の時間が指定された2つの値の間にあるまたは等しい場合にのみ許可が与えられます。

  • Minute

    アクセスを許可する分を定義します。また、分の範囲を指定することもできます。この場合、現在の分が指定された2つの値の間にあるまたは等しい場合にのみ許可が与えられます。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

アクセスは、すべての条件が満たされている場合にのみ許可されます。Keycloakは、各条件の結果に基づいて AND を実行します。

5.6. 集約されたポリシー

前述のとおり、Keycloakではポリシーのポリシーを構築できます。これはポリシー集約と呼ばれる概念です。 ポリシー集約を使用すると、既存のポリシーを再利用してより複雑なポリシーを構築し、認可リクエストの処理中に評価されるポリシーとのアクセスをさらに分離することができます。

新しい集約されたポリシーを作成するには、ポリシーリストの右上隅にあるドロップダウン・リストで Aggregated を選択します。

集約されたポリシーの追加

集約されたポリシーの追加

Confidential Resource というリソースがあり、 keycloak.org ドメインと特定の範囲のIPアドレスからアクセスできるユーザーがいるとします。両方の条件で単一のポリシーを作成できます。ただし、このポリシーのドメイン部分を再利用して、元のネットワークに関係なく動作するパーミッションに適用したいかもしれません。

ドメインとネットワークの両方の条件に対して個別のポリシーを作成し、これらの2つのポリシーの組み合わせに基づいて第3のポリシーを作成することができます。集約されたポリシーを使用すると、他のポリシーを自由に組み合わせて、新しい集約ポリシーを任意のパーミッションに適用できます。

集約されたポリシーを作成する場合は、ポリシー間で循環参照または依存関係を導入していないことに注意してください。循環依存が検出された場合、ポリシーを作成または更新することはできません。

5.6.1. 設定

  • Name

    ポリシーを説明する、人が判読可能な一意の文字列。ビジネス要件とセキュリティ要件に密接に関連する名前を使用することを強くお勧めします。そうすることで、それらが実際に何を意味するのか簡単に識別することができます。

  • Description

    このポリシーの詳細を示す文字列。

  • Apply Policy

    ポリシーに関連付ける1つ以上のポリシーのセットを定義します。

  • Decision Strategy

    このパーミッションのための決定戦略。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

5.6.2. 集約されたポリシーの決定戦略

集約されたポリシーを作成する際には、各ポリシーの結果に基づいて最終的な決定をするために使用される決定戦略を定義することもできます。

  • Unanimous

    The default strategy if none is provided. In this case, all policies must evaluate to a positive decision for the final decision to be also positive.

  • Affirmative

    この場合、最終決定が肯定的であるために、 少なくとも1つ のポリシーが、肯定的な決定に評価されなければなりません。

  • Consensus

    この場合、肯定的決定の数は否定的決定の数よりも大きくなければなりません。肯定的な決定と否定的な決定の数が同じであれば、最終的な決定は否定的になります。

5.7. クライアント・ベース・ポリシー

このポリシーは、1つ以上のクライアントが、ある対象へアクセスすることを可能にする条件を定義するために使うことができます。

新しいクライアント・ベース・ポリシーを作成するには、ポリシー・リストの右上隅にあるドロップダウン・リストから Client を選択します。

クライアント・ベース・ポリシーの追加

クライアント・ベース・ポリシーの追加

5.7.1. 設定

  • Name

    A human-readable and unique string identifying the policy. A best practice is to use names that are closely related to your business and security requirements, so you can identify them more easily.

  • Description

    A string containing details about this policy.

  • Clients

    このポリシーによってアクセス権が与えられるクライアントを指定します。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

5.8. グループ・ベース・ポリシー

このポリシーは、1つ以上のグループ(およびそれらの階層)が、ある対象へアクセスすることを可能にする条件を定義するために使うことができます。

新しいグループ・ベース・ポリシーを作成するには、ポリシー・リストの右上隅にあるドロップダウン・リストから Group を選択します。

グループ・ベース・ポリシーの追加

グループ・ベース・ポリシーの追加

5.8.1. 設定

  • Name

    ポリシーを説明する、人が判読可能で一意の文字列。ベストプラクティスは、ビジネス要件とセキュリティ要件に密接に関連する名前を使用することです。そうすることで簡単に識別することができます。

  • Description

    A string containing details about this policy.

  • Groups Claim

    グループ名および/またはパスを保持するトークン内のクレームの名前を指定します。通常、認可リクエストは、以前に一部のユーザーに代わって動作するクライアントに発行されたIDトークンまたはアクセストークンに基づいて処理されます。トークンには、このポリシーがユーザーの所属するグループを取得する場所からのクレームが含まれている必要があります。

  • Groups

    パーミッションを評価するときに、このポリシーにより実施されるグループを選択できます。 グループを追加した後、 Extend to Children チェックボックスをオンにすることで、子グループへのアクセスを拡張できます。マークされていない場合、アクセス制限は選択したグループにのみ適用されます。

  • Logic

    The Logic of this policy to apply after the other conditions have been evaluated.

5.8.2. 子グループへのアクセスの拡張

デフォルトでは、グループをポリシーに追加したとき、選択されたグループのみにアクセス制限が適用されます。

このアクセス制限を、選択したグループだけでなく、その子グループにも適用したい場合があるかもしれません。その場合、 Extend to Children のチェックボックスをチェックすることで、任意のグループへのアクセス権をその子グループにまで拡大適用することができます。

子グループへのアクセスの拡張

Extending Access to Child Groups

上の例では、 IT グループとその子グループに属する任意のユーザーに対してアクセス権が付与されます。

5.9. 肯定ロジックと否定ロジック

ポリシーには肯定または否定のオプションを付与できます。これにより、ポリシー適用の結果を反転させることができます。

例えば、特定のロールを与えられて いない ユーザーのみアクセスを許可したいとします。この場合、まずそのロールを使ったロールベース・ポリシーを作成し、 LogicNegative にセットします。Positive のままにしておくと、ポリシーはその定義通りに適用されます。

5.10. ポリシー評価API

JavaScriptまたはJBoss Droolsを使用してルールベースのポリシーを作成する場合、Keycloakは、パーミッションを与える必要があるかどうかを判断するのに役立つ情報を提供する評価APIを提供します。

このAPIは、次のような情報へのアクセスを提供するいくつかのインターフェイスで構成されています。

  • 要求しているパーミッション

  • クレーム/属性を取得できるパーミッションを要求しているアイデンティティー

  • ランタイム環境および実行コンテキストに関連付けられたその他の属性

主なインタフェースは org.keycloak.authorization.policy.evaluation.Evaluation で、次のコントラクトを定義します。

public interface Evaluation {

    /**
     * Returns the {@link ResourcePermission} to be evaluated.
     *
     * @return the permission to be evaluated
     */
    ResourcePermission getPermission();

    /**
     * Returns the {@link EvaluationContext}. Which provides access to the whole evaluation runtime context.
     *
     * @return the evaluation context
     */
    EvaluationContext getContext();

    /**
     * Grants the requested permission to the caller.
     */
    void grant();

    /**
     * Denies the requested permission.
     */
    void deny();
}

認証リクエストを処理する際、Keycloakは、ポリシーを評価する前に Evaluation インスタンスを作成します。このインスタンスは、各ポリシーに渡され、アクセスが GRANTDENY かを判断します。

ポリシーは、 Evaluation インスタンスで grant() または deny() メソッドを呼び出すことでこれを判断します。デフォルトでは、 Evaluation インスタンスの状態は拒否されています。つまり、ポリシーが明示的に grant() メソッドを呼び出してポリシー評価エンジンに許可を与える必要があることを示す必要があります。

評価APIの詳細については、 JavaDocs を参照してください。

5.10.1. 評価コンテキスト

評価コンテキストは、評価中にポリシーに有用な情報を提供します。

public interface EvaluationContext {

    /**
     * Returns the {@link Identity} that represents an entity (person or non-person) to which the permissions must be granted, or not.
     *
     * @return the identity to which the permissions must be granted, or not
     */
    Identity getIdentity();

    /**
     * Returns all attributes within the current execution and runtime environment.
     *
     * @return the attributes within the current execution and runtime environment
     */
    Attributes getAttributes();
}

このインターフェイスから、ポリシーは以下を取得できます。

  • 認証された Identity

  • 実行コンテキストとランタイム環境に関する情報

Identity は、認可リクエストとともに送信されたOAuth2アクセス・トークンに基づいて作成され、このコンストラクトはオリジナルのトークンから抽出されたすべてのクレームにアクセスできます。例えば、 Protocol Mapper を使用してカスタム・クレームをOAuth2アクセス・トークンに含める場合、ポリシーからこのクレームにアクセスして、条件を作成することもできます。

EvaluationContext は、実行およびランタイム環境の両方に関連する属性へのアクセスも提供します。今のところ、いくつかの組み込み属性しかありません。

Table 2. 実行属性およびランタイム属性
名前 説明 タイプ

kc.time.date_time

現在の日付と時刻

String。フォーマット MM/dd/yyyy hh:mm:ss

kc.client.network.ip_address

クライアントのIPv4アドレス

String

kc.client.network.host

クライアントのホスト名

String

kc.client.id

クライアントID

String

kc.client.user_agent

'User-Agent' HTTPヘッダーの値

String[]

kc.realm.name

レルムの名前

String

6. パーミッションの管理

パーミッションは、保護されているオブジェクトとアクセスを許可するかどうかを決定するために評価されなければならないポリシーを関連付けます。

保護したいリソースを作成し、それらのリソースを保護するために使用するポリシーを作成したら、権限の管理を開始できます。権限を管理するには、リソース・サーバーを編集するときに Permissions タブをクリックします。

パーミッション

権限

主な2つのタイプのオブジェクトを保護するパーミッションを作成できます。

  • Resources

  • Scopes

パーミッションを作成するには、パーミッションのリストの右上隅にあるドロップダウン・リストから、作成するパーミッション・タイプを選択します。次のセクションでは、これら2種類のオブジェクトについて詳しく説明します。

6.1. リソースベースのパーミッションの作成

リソースベースのパーミッションは、1つ以上の認可ポリシーのセットを使用して保護する1つ以上のリソースのセットを定義します。

新しいリソースベースのパーミッションを作成するには、パーミッション・リストの右上隅にあるドロップダウン・リストで Resource-based を選択します。

リソースベースのパーミッションの追加

リソースベースのパーミッションの追加

6.1.1. 設定

  • Name

    A human-readable and unique string describing the permission. A best practice is to use names that are closely related to your business and security requirements, so you can identify them more easily.

  • Description

    パーミッションに関する詳細を含む文字列。

  • Apply To Resource Type

    指定されたタイプのすべてのリソースにパーミッションを適用するかどうかを指定します。このフィールドを選択すると、保護するリソースタイプを入力するよう求められます。

    • Resource Type

      保護するリソース・タイプを定義します。定義されている場合、このパーミッションはそのタイプに一致するすべてのリソースに対して評価されます。

  • Resources

    保護する1つ以上のリソースのセットを定義します。

  • Apply Policy

    パーミッションに関連付ける1つ以上のポリシーのセットを定義します。

  • Decision Strategy

    パーミッションのための決定戦略

6.1.2. タイプ付きリソースのパーミッション

リソース・パーミッションは、特定のタイプのすべてのリソースに適用されるポリシーを定義するためにも使用できます。この形式のリソース・ベースのパーミッションは、共通のアクセス要件と制約を共有するリソースを持つ場合に役立ちます。

多くの場合、アプリケーション内のリソースは、カプセル化したデータまたは提供する機能に基づいて分類(またはタイプ指定)できます。例えば、金融アプリケーションは、それぞれが特定の顧客に属する異なる銀行口座を管理することができます。それらは異なる銀行口座であるが、銀行組織によって全体的に定義される共通のセキュリティ要件および制約を共有します。タイプされたリソース・パーミッションを使用して、以下のようなすべての銀行口座に適用する共通ポリシーを定義することができます。

  • オーナーのみが自分のアカウントを管理できます。

  • オーナーの国や地域からのアクセスのみを許可します。

  • 特定の認証方法を強制します。

タイプ付きリソースのパーミッションを作成するには、新しいリソース・ベースのパーミッションを作成するときに、Apply to Resource Typeをクリックします。 Apply to Resource TypeOn に設定すると、保護するタイプと、指定したタイプのすべてのリソースへのアクセスを制御するために適用されるポリシーを指定できます。

タイプ付きリソースのパーミッションの例

タイプ付きリソースのパーミッションの例

6.2. スコープベースのパーミッションの作成

スコープベースのパーミッションは、1つ以上の認可ポリシーのセットを使用して保護する1つ以上のスコープのセットを定義します。リソースベースのパーミッションとは異なり、このパーミッションのタイプを使用して、リソースだけでなく、それに関連付けられたスコープのパーミッションを作成し、リソースを管理するパーミッションとそれらに対して実行可能なアクションを定義する際に、より詳細な情報を提供します。

新しいスコープベースのパーミッションを作成するには、パーミッション・リストの右上隅にあるドロップダウン・リストで Scope-based を選択します。

スコープベースのパーミッションの追加

スコープベースのパーミッションの追加

6.2.1. 設定

  • Name

    A human-readable and unique string describing the permission. A best practice is to use names that are closely related to your business and security requirements, so you can identify them more easily.

  • Description

    パーミッションに関する詳細を含む文字列。

  • Resource

    選択したリソースに関連付けられているものにスコープを制限します。選択されていない場合は、すべてのスコープを使用できます。

  • Scopes

    保護する1つ以上のスコープのセットを定義します。

  • Apply Policy

    パーミッションに関連付ける1つ以上のポリシーのセットを定義します。

  • Decision Strategy

    パーミッションのための決定戦略

6.3. ポリシー決定戦略

ポリシーにパーミッションを関連付けるときに、決定戦略を定義して、関連付けされたポリシーの結果を評価して最終的なアクセスを判断する方法を指定できます

  • Unanimous

    The default strategy if none is provided. In this case, all policies must evaluate to a positive decision for the final decision to be also positive.

  • Affirmative

    この場合、最終的に 少なくとも1つの ポリシーの判定結果が肯定と判定される必要があります。

  • Consensus

    この場合、肯定判定数は否定判定数よりも多くなければならない。肯定と否定の判定数が等しい場合、最終的に否定と判定されます。

7. ポリシーの評価とテスト

ポリシーを設計する際に、認可リクエストをシミュレートして、ポリシーの評価方法をテストすることができます。

リソース・サーバーを編集するときに Evaluate タブをクリックすると、ポリシー評価ツールにアクセスできます。そこで、さまざまな入力を指定して、実際の認可リクエストをシミュレートし、ポリシーの効果をテストすることができます。

ポリシー評価ツール

7.1. アイデンティティー情報の提供

Identity Information フィルターを使用して、パーミッションを要求するユーザーを指定できます。

Entitlement をクリックして、選択したユーザーのすべてのパーミッションを取得することもできます。

7.2. コンテキスト情報の提供

Contextual Information フィルターを使用して、評価コンテキストに追加の属性を定義し、ポリシーがこれらの同じ属性を取得できるようにすることができます。

7.3. パーミッションの提供

Permissions フィルターを使用して、認可リクエストを作成できます。1つ以上のリソースとスコープのセットに対するパーミッションを要求できます。すべての保護されたリソースとスコープに基づいて認可リクエストをシミュレートする場合は、 Resources または Scopes を指定せずに Add をクリックします。

目的の値を指定したら、 Evaluate をクリックします。

8. 認可サービス

Keycloak認可サービスは、OAuth2のUser-Managed Access(UMA)プロファイルに基づいています。

このセクションでは、アプリケーションとサービスのきめ細かな認可を可能にするために対話できる、さまざまなRESTfulエンドポイントについて説明します。

8.1. 保護API

保護APIは、UMA準拠のエンドポイントのセットを提供します。

  • Resource Registration

    このエンドポイントを使用すると、リソースサーバーはリソースをリモートで管理し、ポリシー・エンフォーサーが保護を必要とするリソースをサーバーに問い合わせできるようになります。

  • Permission Registration

    UMAプロトコルでは、リソースサーバーはこのエンドポイントにアクセスし、パーミッション・チケットを発行します。

このAPIの重要な要件は、保護APIトークン(PAT)と呼ばれる特別なOAuth2アクセストークンを使用して、リソースサーバー だけ がエンドポイントにアクセスできることです。 UMAでは、PATはスコープ uma_protection を持つトークンです。

8.1.1. PATとは何か、そしてそれをどのように取得するか

保護APIトークン (PAT)は、 uma_protection として定義されたスコープを持つ特殊なOAuth2アクセストークンです。リソースサーバーを作成すると、Keycloakは対応するクライアント・アプリケーションのロール uma_protection を自動的に作成し、クライアントのサービス・アカウントに関連付けます。

uma_protection ロールで付与されたサービス・アカウント

uma_protectionロールで付与されたサービス・アカウント

リソースサーバーは、Keycloakから他のOAuth2アクセストークンと同様にPATを取得できます。たとえば、次のようにcurlを使用します。

curl -X POST \
 -H "Content-Type: application/x-www-form-urlencoded" \
 -d 'grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}' \
 "http://localhost:8080/auth/realms/${realm_name}/protocol/openid-connect/token"

上記の例では、 client_credentials グラントタイプを使用してサーバーからPATを取得しています。その結果、サーバーは次のような応答を返します。

{
 "access_token": ${PAT},
 "expires_in": 300,
 "refresh_expires_in": 1800,
 "refresh_token": ${refresh_token},
 "token_type": "bearer",
 "id_token": ${id_token},
 "not-before-policy": 0,
 "session_state": "ccea4a55-9aec-4024-b11c-44f6f168439e"
}
Keycloakは、さまざまな方法でクライアント・アプリケーションを認証できます。わかりやすくするため、ここでは client_credentials グラント・タイプが使用されています。これには client_idclient_secret が必要です。サポートされている認証方法の使用を選択することができます。

8.1.2. リソースの管理

リソースサーバーは、UMA準拠のエンドポイントを使用して、リモートでリソースを管理できます。

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set

This endpoint provides registration operations outlined as follows (entire path omitted for clarity):

  • リソースセットの説明を作成する: POST /resource_set

  • リソースセットの説明を読み込む: GET /resource_set/{_id}

  • リソースセットの説明を更新する: PUT /resource_set/{_id}

  • リソースセットの説明を削除する: DELETE /resource_set/{_id}

  • リソースセットの説明を表示する: GET /resource_set

  • フィルターを使用して、リソースセットの説明を表示する: GET /resource_set?filter=${filter}

各操作の規約の詳細については、 UMAリソースセットの登録 を参照してください。

8.1.3. パーミッション・リクエストの管理

UMAプロトコルを使用するリソースサーバーは、特定のエンドポイントを使用してパーミッション・リクエストを管理できます。このエンドポイントは、パーミッション・リクエストを登録し、パーミッション・チケットを取得するためのUMA準拠のフローを提供します。

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission

パーミッション・チケットは、パーミッション・リクエストを表す特殊なセキュリティ・トークン・タイプです。 UMA仕様では、パーミッション・チケットは次のとおりです。

認可サーバーからリソースサーバー、リソースサーバーからクライアント、最終的にはクライアントから認可サーバーに伝達され、認可サーバーが認可データの要求に適用する正しいポリシーを評価できるようにする相関ハンドル。

パーミッション・チケットのサポートは制限されています。完全なUMAプロトコルでは、リソースサーバーは、リソースオーナー(要求されているリソースを所有するユーザー)が第三者によるリソースへのアクセスを他の方法で承認することができる認可フローをサポートするためにサーバーにパーミッション・リクエストを登録することができます。これは、UMA仕様の主な機能の1つを表します。リソースオーナーは、独自のリソースとそれらを管理するポリシーを制御できます。現在のところ、KeycloakのUMA実装のサポートは、この点で非常に制限されています。例えば、システムはサーバー上にパーミッション・チケットを保存せず、基本的にはUMAを使用してAPIセキュリティーを提供し、認可サービスをベースにしています。将来、UMAやその他のユースケースの完全なサポートが計画されています。

ほとんどの場合、このエンドポイントを直接処理する必要はありません。Keycloakは、リソースサーバーのUMAを有効にするポリシー・エンフォーサーを提供し、認可サーバーからパーミッション・チケットを取得し、このチケットをクライアント・アプリケーションに戻し、最後にリクエスティング・パーティ・トークン(RPT)に基づいて認可決定を実施することができます。

Keycloakからパーミッション・チケットを取得するプロセスは、クライアントがリソースにアクセスするために必要な許可なく保護されたリソースにアクセスしようとしたときに、パーミッション・チケットが取得される通常のクライアント・アプリケーションではなくリソースサーバーによって実行されます。パーミッション・チケットの発行は、UMAを使用する際の重要な側面です。これにより、リソースサーバーは次のことが可能になります。

  • リソースサーバーによって保護されているリソースに関連付けられたデータをクライアントから抽出します。

  • Keycloakの認可リクエストに登録します。これは、後からワークフローを使用して、リソースの所有者の承認に基づいてアクセスを許可します。

  • リソースサーバーを認可サーバーから切り離し、異なる認証サーバーを使用してリソースを保護および管理できます。

クライアントの賢明な点として、パーミッション・チケットには重要な側面もあります。

  • クライアントは、認可データが保護されたリソースにどのように関連付けられているかを知る必要はありません。パーミッション・チケットは、クライアントにとって完全に不透明です。

  • クライアントは、異なるリソースサーバー上のさまざまな認可サーバーによって保護されたリソースにアクセスできます。

これらは、UMAの他の側面が、特にプライバシーとリソースへのアクセス制御されたユーザーに関するパーミッション・チケットに強く基づいたUMAのメリットのほんの一部です。

8.2. 認可API

認可APIは、サーバーから認可データを取得するためのUMA準拠のエンドポイントを提供します。ここで、認可データは、要求されているリソースに関連するすべてのパーミッションおよび認可のポリシーの評価結果を表します。

保護APIとは異なり、どんなクライアント・アプリケーションでも認可APIエンドポイントにアクセスできます。これには、認可APIトークン(AAT)と呼ばれる特殊なOAuth2アクセストークンが必要です。UMAでは、AATは uma_authorization スコープ付きのトークンです。

8.2.1. AATとは何か、そしてそれをどのように取得するか

認可APIトークン(AAT)は、 uma_authorization というスコープを持つ特別なOAuth2アクセス・トークンです。ユーザーを作成すると、Keycloakは自動的に uma_authorization というロールをユーザーに割り当てます。 uma_authorization ロールは、デフォルトのレルム・ロールです。

デフォルト・ロールuma_authorization

デフォルトロールuma_authorization

AATを使用すると、クライアント・アプリケーションはサーバーにユーザーのパーミッションを問い合わせることができます。

クライアント・アプリケーションは、他のOAuth2アクセス・トークンと同様にKeycloakからAATを取得できます。通常、クライアント・アプリケーションは、Keycloakでユーザーが正常に認証された後にAATを取得します。デフォルトでは、 authorization_code グラント・タイプはユーザーの認証に使用され、サーバーは代わりにクライアント・アプリケーションにOAuth2アクセス・トークンを発行します。

以下の例では、リソース・オーナー・パスワード・クレデンシャル・グラント・タイプを使用してAATをリクエストしています。

curl -X POST \
-H "Authorization: Basic aGVsbG8td29ybGQtYXV0aHotc2VydmljZTpwYXNzd29yZA==" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'username=${username}&password=${user_password}&grant_type=password' \
"http://localhost:8080/auth/realms/${realm_name}/protocol/openid-connect/token"

その結果、サーバーの応答は次のようになります。

{
"access_token": ${AAT},
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": ${refresh_token},
"token_type": "bearer",
"id_token": ${id_token},
"not-before-policy": 0,
"session_state": "3cad2afc-855b-47b7-8e4d-a21c66e312fb"
}

8.2.2. 認可データとトークンの要求

UMAプロトコルを使用するクライアント・アプリケーションは、特定のエンドポイントを使用して、リクエスティング・パーティー・トークン(RPT)と呼ばれる特別なセキュリティー・トークンを取得できます。このトークンは、要求されているリソースに関連するパーミッションおよび認可ポリシーの評価の結果として、ユーザーに付与されたすべてのパーミッションで構成されます。RPTを使用すると、クライアント・アプリケーションはリソースサーバーで保護されたリソースにアクセスできます。

UMA準拠の認可APIエンドポイント
http://${host}:${port}/auth/realms/${realm_name}/authz/authorize

RPTを要求するときは、次の2つのことを指定する必要があります。

パーミッション・チケットは、ベアラートークンとしてAATを使用してリクエストを認証するために、AATが Authorization ヘッダーに含まれているかどうかを示すパラメーターとして、HTTPリクエストに追加されます。

curl -X POST
 -H "Authorization: Bearer ${AAT}" -d '{
 "ticket" : ${PERMISSION_TICKET}
}' "http://localhost:8080/auth/realms/hello-world-authz/authz/authorize"

その結果、サーバーの応答は次のようになります。

{"rpt":"${RPT}"}

8.3. エンタイトルメントAPI

エンタイトルメントAPIは、サーバーから認可データを取得するための1-leggedプロトコルを提供します。ここで、認可データは、要求されているリソースに関連するすべてのパーミッションおよび認可ポリシーの評価の結果を表します。

Authorization API とは異なり、エンタイトルメントAPIはUMA準拠ではなく、パーミッション・チケットを必要としません。

このAPIの目的は、有効なOAuth2アクセストークンを所有しているクライアントが、ユーザーに代わって必要な認可データを取得できる、認可データを取得するためのより軽量なAPIを提供することです。

8.3.1. エンタイトルメントの要求

クライアント・アプリケーションは、特定のエンドポイントを使用して、リクエスティング・パーティー・トークン(RPT)と呼ばれる特別なセキュリティ・トークンを取得できます。このトークンは、要求されているリソースに関連する権限および認可ポリシーの評価の結果として、ユーザーのすべてのエンタイトルメント(または権限)で構成されます。RPTを使用すると、クライアント・アプリケーションはリソース・サーバーで保護されたリソースにアクセスできます。

エンタイトルメントAPIエンドポイント
http://${host}:${port}/auth/realms/${realm_name}/authz/entitlement/{client_id}

Keycloakでリソースサーバーとして機能するクライアント・アプリケーションを識別するために、上記の client_id パラメーターを指定する必要があります。評価の範囲を特定のリソースサーバーによって管理されるリソース、スコープおよび権限に制限するには、クライアント識別子を指定する必要があります。

エンタイトルメントAPIには次の2種類があります。

  • HTTP GET を使用して、特定のユーザーが所有するリソース、および(または)リソースサーバー自体が所有、管理する一般的なリソースに基づくすべてのエンタイトルメントを取得します。

  • HTTP POST を使用して、エンタイトルメントのリクエストと共に送信される1つ以上のリソースとスコープのセットに基づくエンタイトルメントを取得します。

どちらを使用するかは、ユースケースとKeycloakに登録したリソースの量によって異なります。 GET は、サーバーからのエンタイトルメントを取得する簡単な方法を提供しますが、ユーザーに関連するリソースが多すぎる場合には、適切ではない可能性があります。この場合は、 POST メソッドが推奨されます。

エンタイトルメントAPIエンドポイントは、ユーザーの識別情報を表すリクエスト内のアクセス・トークンと、ユーザーの代理として認可データにアクセスするための同意を期待します。アクセス・トークンは、HTTP Authorization ヘッダーを使用してベアラー・トークンとして送信する必要があります。

エンタイトルメントAPIエンドポイントを正常に呼び出すと、サーバーによって付与されたすべての権限を持つRPTが取得されます。

エンタイトルメントの取得

特定のユーザーのエンタイトルメントを取得する最も簡単な方法は、HTTP GETリクエストを使用することです。たとえば、次のようにcurlを使用します。

curl -X GET \
 -H "Authorization: Bearer ${access_token}" \
 "http://${host}:${port}/auth/realms/${realm_name}/authz/entitlement/{client_id}"

その結果、サーバーの応答は次のようになります。

{
 "rpt": ${RPT}
}

このメソッドを使用してエンタイトルメントを取得すると、サーバーは、ユーザーまたはリソース・サーバー自体が所有するリソースに関連付けられている権限および認可ポリシーの評価に基づいて、ユーザーの すべて のエンタイトルメントを要求元のクライアントに応答します。例えば、次のリソースのKeycloakで定義されている権限があるとします。

  • Main Page

  • Alice Bank Account

  • Bob Bank Account

Main Page はアプリケーションの共通リソースで、リソースサーバー自体が所有しています。アプリケーションのランディング・ページまたはメインページを表します。一方、 Alice Bank Account は、ユーザー alice が所有者であるリソースです。別のユーザー bob が所有している Bob Bank Account についても同様です。

ユーザー alice のエンタイトルメントを取得するとき、サーバーはリソースの Main PageAlice Bank Account に関連するすべての権限を評価します。これらのリソースを表す権限のセットを使用してRPT(実際に権限が与えられた場合)を返します。

特定のリソースのセットに対するエンタイトルメントの取得

エンタイトルメント・エンドポイントを使用して、1つ以上のリソースのセットに対するユーザーのエンタイトルメントを取得することもできます。たとえば、次のようにcurlを使用します。

curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${access_token}" -d '{
 "permissions" : [
 {
 "resource_set_name" : "Alice Bank Account"
 }
 ]
}' "http://${host}:${port}/auth/realms/${realm_name}/authz/entitlement/{client_id}"

その結果、サーバーの応答は次のようになります。

{
 "rpt": ${RPT}
}

GETバージョンとは異なり、サーバーは、要求されているリソースに関連付けられている権限および許可ポリシーの評価中に付与された権限を保持するRPTで応答します。

アクセスするスコープを指定することもできます。たとえば、次のようにcurlを使用します。

curl -X POST -H "Authorization: Bearer ${access_token}" -d '{
    "permissions" : [
        {
            "resource_set_name" : "Alice Bank Account",
            "scopes" : [
                "withdraw"
            ]
        }
    ]
}' "http://${host}:${port}/auth/realms/${realm_name}/authz/entitlement/{client_id}"

8.3.2. エンタイトルメント・リクエスト・メタデータ

エンタイトルメントを要求するとき、クライアント・アプリケーションは、メタデータ情報をリクエストに関連付けさせて、パーミッションの取得方法を定義することができます。

curl -X POST -H "Authorization: Bearer ${access_token}" -d '{
    "metadata" : {
        "include_resource_name" : false
    },
    "permissions" : [
        ...
    ]
}' "http://${host}:${port}/auth/realms/${realm_name}/authz/entitlement/{client_id}"
エンタイトルメントAPIエンドポイントでは、HTTP POSTを使用しているときにエンタイトルメント・リクエストに沿ってメタデータを渡すことしかできません。

次のセクションでは、エンタイトルメント・リクエストに含めることができるさまざまな情報を、メタデータとして使用する方法とタイミングについて説明します。

8.3.3. リソースの名前をレスポンスに含めるかどうかを決定する

include_resource_name
curl -X POST -H "Authorization: Bearer ${access_token}" -d '{
    "metadata" : {
        "include_resource_name" : false
    },
    "permissions" : [
        ...
    ]
}' "http://${host}:${port}/auth/realms/${realm_name}/authz/entitlement/{client_id}"

クライアントは、 include_resource_name を使用して、サーバーによって付与された各パーミッションにリソースの名前を含めるかどうかを決定できます。このオプションを使用すると、RPTのサイズを縮小し、クライアントとサーバー間の通信を最適化できます。

デフォルトでは、RPT内のパーミッションには、単一のパーミッションごとに付与されたリソースのIDと名前の両方が含まれています。このオプションは、リソース・サーバーがリソースのIDに基づいてのみリソースをマップできる場合に特に便利です。

8.3.4. RPT内のパーミッションの数を制限する

limit
curl -X POST -H "Authorization: Bearer ${access_token}" -d '{
    "metadata" : {
        "limit" : 10
    },
    "permissions" : [
        ...
    ]
}' "http://${host}:${port}/auth/realms/${realm_name}/authz/entitlement/{client_id}"

クライアントは、 limit を使用して、サーバーから返されるRPT内で予想されるパーミッションの数を指定できます。制限オプションは次のように動作します。

  • 以前に発行されたRPTを 使用せず にリクエストが送信された場合、 permissions クレームのリソース/スコープに基づいて、 limit パーミッションのみが返されます。

  • 以前に発行されたRPTを 使用して リクエストが送信された場合、以前に発行されたRPTのパーミッションが limit に達していない場合にのみ、 permissions クレームのリソース/スコープに関連付けられたパーミッションが優先されます。以前に発行されたRPTからの権限に対して十分な空きがある場合、サーバーはそこに定義されている最初のパーミッションを含めます。

このオプションを使用すると、クライアントはRPTのサイズを制御し、サーバーによって付与された最後の権限のみを保持できます。クライアントが以前に発行されたRPTを送信することができ、新しい権限(別名: Incremental Authorization)を求めている場合にのみ意味があります。

8.4. リクエスティング・パーティ・トークン

Requesting party token(RPT)は JSON web signature(JWS) でデジタル署名された JSON web token(JWT) です。RPTは、Keycloakによって発行されたOAuth2アクセストークンをベースとして、ユーザーの代わりに動作する特定のクライアントに組み込まれます。

RPT をデコードすると、次のようなペイロードが得られます:

{
  "authorization": {
      "permissions": [
        {
          "resource_set_id": "d2fe9843-6462-4bfc-baba-b5787bb6e0e7",
          "resource_set_name": "Hello World Resource"
        }
      ]
  },
  "jti": "d6109a09-78fd-4998-bf89-95730dfd0892-1464906679405",
  "exp": 1464906971,
  "nbf": 0,
  "iat": 1464906671,
  "sub": "f1888f4d-5172-4359-be0c-af338505d86c",
  "typ": "kc_ett",
  "azp": "hello-world-authz-service"
}

このトークンの permissions クレームから、サーバーによって与えられる全てのパーミッションを取得できます。

パーミッションは保護されたリソース/スコープに直接関連していますが、アクセス・コントロール・メソッドからは完全に独立していることに注意して下さい。

8.4.1. リクエスティング・パーティー・トークンのイントロスペクション

場合によっては、リクエスティング・パーティー・トークン(RPT)をイントロスペクトして、その有効性をチェックしたり、トークン内の権限を取得して、リソース・サーバー側で認可の決定を行うことがあります。

トークンのイントロスペクションが役立つ2つの主な使用例があります。

  • クライアント・アプリケーションがトークンの有効性を問い合わせて、同じまたは追加の権限を持つ新しいトークンを取得する必要がある場合

  • リソース・サーバー側で認可の決定を実施する場合、特に組み込みのポリシー・エンフォーサーがアプリケーションに適合しない場合

8.4.2. RPTに関する情報の取得

トークン・イントロスペクションは基本的に、RPTに関する情報を取得するための OAuth2トークン・イントロスペクション 準拠のエンドポイントです。

http://${host}:${port}/auth/realms/${realm_name}/protocol/openid-connect/token/introspect

このエンドポイントを使用してRPTをイントロスペクションするには、次のようにしてサーバーにリクエストを送信します。

curl -X POST \
    -H "Authorization: Basic aGVsbG8td29ybGQtYXV0aHotc2VydmljZTpzZWNyZXQ=" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d 'token_type_hint=requesting_party_token&token=${RPT}' \
    "http://localhost:8080/auth/realms/hello-world-authz/protocol/openid-connect/token/introspect"
上記のリクエストは、HTTP BASICを使用し、クライアントのクレデンシャル(クライアントIDとシークレット)を渡してトークンのイントロスペクションを試みるクライアントを認証しますが、Keycloakでサポートされている他のクライアント認証方式を使用することもできます。

イントロスペクション・エンドポイントには2つのパラメータが必要です。

  • token_type_hint

    このパラメーターの値として requesting_party_token を使用します。これは、RPTをイントロスペクションすることを示します。

  • token

    このパラメーターの値として、認可処理中にサーバーから返されたトークン文字列を使用します。

その結果、サーバーの応答は次のようになります。

{
  "permissions": [
    {
      "resource_set_id": "90ccc6fc-b296-4cd1-881e-089e1ee15957",
      "resource_set_name": "Hello World Resource"
    }
  ],
  "exp": 1465314139,
  "nbf": 0,
  "iat": 1465313839,
  "aud": "hello-world-authz-service",
  "active": true
}

RPTがアクティブでない場合、代わりにこのレスポンスが返されます。

{
  "active": false
}

8.4.3. RPTをイントロスペクションするたびにサーバーを呼び出す必要がありますか?

いいえ、両方のエンタイトルメントAPIは、RPTのデフォルトの形式として JSON web token(JWT) 仕様を使用します。

リモート・イントロスペクション・エンドポイントを呼び出さずにこれらのトークンを検証する場合は、RPTをデコードしてローカルでその有効性を問い合わせることができます。トークンをデコードすると、トークン内の権限を使用して認可の決定を行うこともできます。

これは本来、ポリシー・エンフォーサーが行うことです。次のことを確認してください。

  • RPTのシグネチャーを検証する(レルムの公開鍵に基づいて)

  • expiat 、および_aud_のクレームに基づいてトークンの有効性を問い合わせる

8.5. 認可クライアントJava API

要件に応じて、リソース・サーバーはリソースをリモートで管理したり、プログラムでパーミッションをチェックしたりすることもできます。Javaを使用している場合は、認可クライアントAPIを使用してKeycloak認可サービスにアクセスできます。

これは、保護API、認可API、エンタイトルメントAPIなど、サーバーが提供するさまざまなAPIにアクセスするリソース・サーバーを対象としています。

8.5.1. Maven依存関係

<dependencies>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-authz-client</artifactId>
        <version>${KEYCLOAK_VERSION}</version>
    </dependency>
</dependencies>

8.5.2. 設定

クライアントの設定は、 keycloak.json ファイルで次のように定義されています。

{
  "realm": "hello-world-authz",
  "auth-server-url" : "http://localhost:8080/auth",
  "resource" : "hello-world-authz-service",
  "credentials": {
    "secret": "secret"
  }
}
  • realm (required)

    レルムの名前。

  • auth-server-url (required)

    KeycloakサーバーのベースURL。 他のすべてのKeycloakページとRESTサービス・エンドポイントは、これから派生しています。通常、https://host:port/authという形式です。

  • resource (required)

    アプリケーションのクライアントID。各アプリケーションには、アプリケーションを識別するために使用されるクライアントIDがあります。

  • credentials (required) アプリケーションのクレデンシャルを指定します。これは、キーがクレデンシャル・タイプであり、値がクレデンシャル・タイプの値であるオブジェクトの表記法です。

設定ファイルは通常、クライアントの keycloak.json ファイルを見つける際のデフォルトのローケーションであるアプリケーションのクラスパスにあります。

8.5.3. 認可クライアントの作成

クラスパスに keycloak.json ファイルがあることを考慮して、次のように新しい AuthzClient インスタンスを作成することができます。

    // create a new instance based on the configuration defined in a keycloak.json located in your classpath
    AuthzClient authzClient = AuthzClient.create();

8.5.4. ユーザー・エンタイトルメントの取得

ユーザー・エンタイトルメントを取得する方法の例を示します。

// create a new instance based on the configuration defined in keycloak-authz.json
AuthzClient authzClient = AuthzClient.create();

// obtain an Entitlement API Token to get access to the Entitlement API.
// this token is an access token issued to a client on behalf of an user
// with a uma_authorization scope
String eat = getEntitlementAPIToken(authzClient);

// send the entitlement request to the server to
// obtain an RPT with all permissions granted to the user
EntitlementResponse response = authzClient.entitlement(eat).getAll("hello-world-authz-service");
String rpt = response.getRpt();

// now you can use the RPT to access protected resources on the resource server

1つ以上のリソースのセットに対してユーザー・エンタイトルメントを取得する方法の例を示します。

// create a new instance based on the configuration defined in keycloak-authz.json
AuthzClient authzClient = AuthzClient.create();

// obtain an Entitlement API Token to get access to the Entitlement API.
// this token is an access token issued to a client on behalf of an user
// with a uma_authorization scope
String eat = getEntitlementAPIToken(authzClient);

// create an entitlement request
EntitlementRequest request = new EntitlementRequest();
PermissionRequest permission = new PermissionRequest();

permission.setResourceSetName("Hello World Resource");

request.addPermission(permission);

// send the entitlement request to the server to obtain an RPT
// with all permissions granted to the user
EntitlementResponse response = authzClient.entitlement(eat).get("hello-world-authz-service", request);
String rpt = response.getRpt();

// now you can use the RPT to access protected resources on the resource server

8.5.5. 保護APIを使用したリソースの作成

// create a new instance based on the configuration defined in keycloak-authz.json
AuthzClient authzClient = AuthzClient.create();

// create a new resource representation with the information we want
ResourceRepresentation newResource = new ResourceRepresentation();

newResource.setName("New Resource");
newResource.setType("urn:hello-world-authz:resources:example");

newResource.addScope(new ScopeRepresentation("urn:hello-world-authz:scopes:view"));

ProtectedResource resourceClient = authzClient.protection().resource();
Set<String> existingResource = resourceClient.findByFilter("name=" + newResource.getName());

if (!existingResource.isEmpty()) {
    resourceClient.delete(existingResource.iterator().next());
}

// create the resource on the server
RegistrationResponse response = resourceClient.create(newResource);
String resourceId = response.getId();

// query the resource using its newly generated id
ResourceRepresentation resource = resourceClient.findById(resourceId).getResourceDescription();

8.5.6. RPTのイントロスペクション

    AuthzClient authzClient = AuthzClient.create();
    String rpt = getRequestingPartyToken(authzClient);
    TokenIntrospectionResponse requestingPartyToken = authzClient.protection().introspectRequestingPartyToken(rpt);

    if (requestingPartyToken.getActive()) {
        for (Permission granted : requestingPartyToken.getPermissions()) {
            // iterate over the granted permissions
        }
    }

9. ポリシー・エンフォーサー

ポリシー実施ポイント(PEP)は設計パターンとなり、さまざまな方法で実装できます。Keycloakは、さまざまなプラットフォーム、環境、およびプログラミング言語に対してPEPを実装するために必要なすべての手段を提供します。Keycloak認可サービスは、RESTfulなAPIを提供し、一元的な認可サーバーを使用してきめ細かな認可を行うための、OAuth2認可機能を活用します。

PEPの概要

9.1. Keycloak アダプター・ポリシー・エンフォーサー

Keycloak OIDCアダプターを使用している場合は、アプリケーションの認可の決定を行うことができます。

Keycloakアプリケーションのポリシーの適用を有効にすると、対応するアダプターはアプリケーションへのすべてのリクエストをインターセプトし、サーバーから取得した認可の決定を行います。

ポリシー適用は、アプリケーションのパスと、Keycloak管理コンソールを使用してリソースサーバー用に作成したリソースに強く関連しています。デフォルトでは、リソースサーバーを作成すると、Keycloakはリソースサーバーのデフォルト設定を作成し、ポリシー適用を即時に有効化することができます。

デフォルト設定では、認証されたユーザーが保護対象のリソースサーバーと同じレルムに属している場合、アプリケーション内のすべてのリソースにアクセスできます。

9.1.1. ポリシー適用の設定

アプリケーションのポリシー適用を有効にするには、 keycloak.json ファイルに次のプロパティーを追加します。

keycloak.json
{
  "policy-enforcer": {}
}

または、保護されているリソースを手動で定義する場合は、以下のようにもう少し詳細化します。

{
  "policy-enforcer": {
    "user-managed-access" : {},
    "enforcement-mode" : "ENFORCING"
    "paths": [
      {
        "path" : "/someUri/*",
        "methods" : [
          {
            "method": "GET",
            "scopes" : ["urn:app.com:scopes:view"]
          },
          {
            "method": "POST",
            "scopes" : ["urn:app.com:scopes:create"]
          }
        ]
      },
      {
        "name" : "Some Resource",
        "path" : "/usingPattern/{id}",
        "methods" : [
          {
            "method": "DELETE",
            "scopes" : ["urn:app.com:scopes:delete"]
          }
        ]
      },
      {
        "path" : "/exactMatch"
      },
      {
        "name" : "Admin Resources",
        "path" : "/usingWildCards/*"
      }
    ]
  }
}

各設定オプションの説明は次のとおりです。

  • policy-enforcer

    ポリシーが実際にどのように実施されるのかを定義する設定オプションと、保護したいパス(任意)を指定します。指定されていない場合、ポリシー・エンフォーサーは、保護されているリソースサーバーに関連付けられているすべてのリソースをサーバーに問い合わせます。この場合、保護するパスと一致するURIプロパティを持つリソースが適切に設定されていることを確認する必要があります。

    • user-managed-access

      アダプターがUMAプロトコルを使用することを指定します。指定されている場合、アダプターはサーバーにパーミッション・チケットを問い合わせ、UMA仕様に従ってクライアントに戻します。指定されていない場合、アダプターはサーバーに送信されたリクエスティング・パーティー・トークン(RPT)に基づいてパーミッションを適用します。

    • enforcement-mode

      ポリシーの適用方法を指定します。

      • ENFORCING

        (default mode) Requests are denied by default even when there is no policy associated with a given resource.

      • PERMISSIVE

        Requests are allowed even when there is no policy associated with a given resource.

      • DISABLED

        ポリシーの評価を完全に無効にし、任意のリソースへのアクセスを許可します。

    • on-deny-redirect-to

      サーバーから"access denied"のメッセージを取得したときに、クライアント・リクエストがリダイレクトされるURLを定義します。デフォルトでは、アダプターは403 HTTPステータスコードで応答します。

    • paths

      保護するパスを指定します。

      • name

        指定されたパスに関連付けられるサーバー上のリソースの名前。ポリシー・エンフォーサーは、 path と組み合わせて使用すると、リソースの URI プロパティーを無視し、代わりに指定したパスを使用します。 * path

        (必須)アプリケーションのコンテキストパスに関連するURI。このオプションを指定すると、ポリシー・エンフォーサーは、同じ値の URI を持つリソースをサーバーに問い合わせます。現在、パスマッチングのための最も基本的なロジックがサポートされています。有効なパスの例は次のとおりです。

        • Wildcards: /*

        • Suffix: /*.html

        • Sub-paths: /path/*

        • Path parameters: /resource/{id}

        • Exact match: /resource

        • Patterns: /{version}/resource, /api/{version}/resource, /api/{version}/resource/*

      • methods 保護するHTTPメソッド(GET、POST、PATCHなど)と、サーバー内の特定のリソースのスコープにどのように関連付けられているかを示します。 +[/'']

        • method

          HTTPメソッドの名前。

        • scopes

          メソッドに関連付けられたスコープを持つ文字列の配列。スコープを特定のメソッドに関連付けると、保護されたリソース(またはパス)にアクセスしようとするクライアントは、そのリストに指定されたすべてのスコープにアクセス権を与えるRPTを提供する必要があります。例えば、スコープ create を持つメソッド POST を定義した場合、RPTにはパスへのPOSTを実行したときに create スコープへのアクセスを許可するパーミッションが含まれていなければなりません。

        • scopes-enforcement-mode

          メソッドに関連付けられたスコープの強制モードを参照する文字列。値は ALL または ANY にすることができます。 ALL の場合、そのメソッドを使用してリソースにアクセスするには、すべての定義されたスコープを付与する必要があります。 ANY の場合は、そのメソッドを使用してリソースにアクセスするために、少なくとも1つのスコープを付与する必要があります。デフォルトでは、強制モードは ALL に設定されています。

      • enforcement-mode

        ポリシーの適用方法を指定します。

        • ENFORCING

          (default mode) Requests are denied by default even when there is no policy associated with a given resource.

        • DISABLED

          パスのポリシーの評価を無効にします。

9.1.2. ベアラー・トークンを使用したステートレス・サービスの保護

アダプターが bearer-only の設定オプションで設定されている場合、ポリシー・エンフォーサーは、ベアラー・トークンのパーミッションに基づいて、保護されたリソースへのアクセス・リクエストが許可または拒否されるかどうかを決定します。

  1. ベアラー・トークンとしてRPTを渡すHTTP GETの例

GET /my-resource-server/my-protected-resource HTTP/1.1
Host: host.com
Authorization: Bearer ${RPT}
...

この例では、アプリケーションの keycloak.json ファイルは次のようになります。

ベアラーのみの設定オプションでのWEB-INF/keycloak.jsonの例
...
"bearer-only" : true,
...
認可レスポンス

クライアントが、保護されたリソースにアクセスするためのパーミッションがないベアラー・トークンを持つリソース・サーバーにアクセスしようとすると、リソース・サーバーは 401 ステータスコードと WWW-Authenticate ヘッダーで応答します。 WWW-Authenticate ヘッダーの値は、リソース・サーバーで使用されている認可プロトコルによって異なります。

次に、認可プロトコルとしてUMAを使用しているリソース・サーバーからのレスポンスの例を示します。

HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="photoz-restful-api",as_uri="http://localhost:8080/auth/realms/photoz/authz/authorize",ticket="${PERMISSION_TICKET}"

また、リソース・サーバーがエンタイトルメント・プロトコルを使用している場合の別の例を以下に示します。

HTTP/1.1 401 Unauthorized
WWW-Authenticate: KC_ETT realm="photoz-restful-api",as_uri="http://localhost:8080/auth/realms/photoz/authz/entitlement"

クライアントがサーバーからレスポンスを受け取ると、ステータス・コードと WWW-Authenticate ヘッダーを調べて、KeycloakサーバーからRPTを取得します。

9.1.3. 認可コンテキストの取得

ポリシーの施行が有効になっている場合、サーバーから取得したパーミッションは org.keycloak.AuthorizationContext で利用できます。このクラスは、パーミッションを取得し、特定のリソースまたはスコープに対してアクセス権が付与されているかどうかを確認するために使用できるいくつかのメソッドを提供します。

サーブレット・コンテナ-内の認可コンテキストの取得

    HttpServletRequest request = ... // 取得javax.servlet.http.HttpServletRequest
    KeycloakSecurityContext keycloakSecurityContext =
        (KeycloakSecurityContext) request
            .getAttribute(KeycloakSecurityContext.class.getName());
    AuthorizationContext authzContext =
        keycloakSecurityContext.getAuthorizationContext();
KeycloakSecurityContext を得る方法の詳細については、アダプターの設定を参照してください。Keycloakでサポートされているサーブレット・コンテナーのいずれかを使用してアプリケーションを起動している場合は、上記の例でコンテキストを取得できます。

認可コンテキストを使用すると、サーバーによって行われて返された決定を、より詳細に制御できます。たとえば、リソースまたはスコープに関連付けられたパーミッションに応じて、アイテムを表示または非表示にする動的なメニューを作成することができます。

if (authzContext.hasResourcePermission("Project Resource")) {
    // user can access the Project Resource
}

if (authzContext.hasResourcePermission("Admin Resource")) {
    // user can access administration resources
}

if (authzContext.hasScopePermission("urn:project.com:project:create")) {
    // user can create new projects
}

AuthorizationContext は、Keycloak認可サービスのメイン機能の1つです。上記の例から、保護されたリソースはそれらを管理するポリシーに直接関連付けられていないことが分かります。

次のような、ロールベースのアクセス制御(RBAC)を使用した同様のコードを考えてみましょう。

if (User.hasRole('user')) {
    // user can access the Project Resource
}

if (User.hasRole('admin')) {
    // user can access administration resources
}

if (User.hasRole('project-manager')) {
    // user can create new projects
}

どちらの例も同じ要件に対応していますが、異なる方法で対応しています。RBACでは、ロールはリソースに対するアクセスのみを 暗黙的に 定義します。Keycloakを使用すると、RBAC、属性ベースのアクセス制御(ABAC)、その他のBACバリアントのいずれを使用していても、リソースに直接フォーカスした管理しやすいコードを作成できます。与えられたリソースまたはスコープに対するパーミッションを持っているかどうかです。

セキュリティ要件が変更され、プロジェクト・マネージャーに加えて、PMOが新しいプロジェクトを作成できるようになったとします。

セキュリティ要件は変更されますが、Keycloakを使用すると、新しい要件を満たすためにアプリケーションコードを変更する必要はありません。アプリケーションがリソースとスコープの識別子に基づいていれば、認可サーバー内の特定のリソースに関連付けられているパーミッションまたはポリシーの設定を変更するだけで済みます。この場合、 Project Resource および(または)スコープ urn:project.com:project:create に関連するパーミッションとポリシーが変更されます。

9.1.4. 認可クライアント・インスタンスを取得するためAuthorizationContextを使用する

AuthorizationContext は、以下のようにアプリケーションに設定された認可クライアントAPIへの参照を取得するためにも使用できます。

    ClientAuthorizationContext clientContext = ClientAuthorizationContext.class.cast(authzContext);
    AuthzClient authzClient = clientContext.getClient();

場合によっては、ポリシー・エンフォーサーによって保護されたリソース・サーバーが、認可サーバーによって提供されるAPIにアクセスする必要があります。取得した AuthzClient インスタンスで、リソース・サーバーはリソースを作成したり、プログラムで特定のパーミッションをチェックするためにサーバーとやりとりすることができます。

9.1.5. JavaScriptの統合

Keycloakサーバーには、ポリシー・エンフォーサーによって保護されたリソース・サーバーと対話するために使用できるJavaScriptライブラリが付属しています。このライブラリはKeycloak JavaScriptアダプターに基づいています。これを統合すると、クライアントはKeycloakサーバーからアクセス権を取得できます。

次の script タグをWebページに含めることで、実行中のKeycloakサーバー・インスタンスからこのライブラリを入手できます。

<script src="http://.../auth/js/keycloak-authz.js"></script>

これを実行すると、次のように KeycloakAuthorization インスタンスを作成できます。

var keycloak = ... // obtain a Keycloak instance from keycloak.js library
var authorization = new KeycloakAuthorization(keycloak);

keycloak-authz.js ライブラリには2つの主な機能があります。

  • Keycloakポリシー・エンフォーサーによって保護されたリソース・サーバーからのレスポンスを処理し、リソース・サーバー上の保護されたリソースにアクセスするために必要な権限を持つリクエスティング・パーティー・トークン(RPT)を取得します。

    • この場合、ライブラリは、リソース・サーバーが使用している認可プロトコル(エンタイトルメント)を処理できます。

  • エンタイトルメントAPIを使用してKeycloakサーバーから権限を取得します。

いずれの場合も、リソース・サーバーとKeycloak認可サービスの両方との対話を容易にし、クライアントがリソース・サーバー上の保護されたリソースにアクセスするベアラー・トークンとして使用できる権限を持つトークンを取得できます。

リソース・サーバーからの認可レスポンスの処理

リソース・サーバーがポリシー・エンフォーサーによって保護されている場合、リソース・サーバーは、ベアラートークンベアラー・トークンとともに送信される権限に基づいてクライアント・リクエストに応答します。通常、保護されたリソースにアクセスするための権限がないベアラー・トークンを使用してリソース・サーバーにアクセスしようとすると、リソース・サーバーは 401 ステータスコードと WWW-Authenticate ヘッダーで応答します。

WWW-Authenticate ヘッダーの値は、リソース・サーバーで使用されている認可プロトコルによって異なります。使用中のプロトコルが何であれ、 KeycloakAuthorization インスタンスを使用して次のようにレスポンスを処理できます。

var wwwAuthenticateHeader = ... // extract WWW-Authenticate Header from the response in case of a 401 status code
authorization.authorize(wwwAuthenticateHeader).then(function (rpt) {
    // onGrant callback function.
    // If authorization was successful you'll receive an RPT
    // with the necessary permissions to access the resource server
}, function () {
    // onDeny callback function.
    // Called when the authorization request is denied by the server
}, function () {
    // onError callback function. Called when the server responds unexpectedly
});

authorize 関数は完全に非同期で、サーバーからの通知を受け取るためのいくつかのコールバック関数をサポートしています。

  • onGrant: 関数の第1引数。認可が成功し、サーバーが要求された権限でRPTを返した場合、コールバックはRPTを受け取ります。

  • onDeny: 関数の第2引数。サーバーがリクエストを拒否した場合にのみ呼び出されます。

  • onError: 関数の第3引数。サーバーが予期せず応答する場合にのみ呼び出されます。

ほとんどのアプリケーションは、 onGrant コールバックを使用して401応答後にリクエストをリトライする必要があります。以降のリクエストには、RPTをリトライのためのベアラー・トークンとして含める必要があります。

エンタイトルメントの取得

keycloak-authz.jsライブラリには、エンタイトルメントAPIを使用してサーバーからRPTを取得するために使用できる entitlement 関数が用意されています。

authorization.entitlement('my-resource-server-id').then(function (rpt) {
    // onGrant callback function.
    // If authorization was successful you'll receive an RPT
    // with the necessary permissions to access the resource server
});

entitlement を使用する場合は、アクセスするリソース・サーバーの client_id を指定する必要があります。

entitlement 関数は完全に非同期で、サーバーからの通知を受け取るためのコールバック関数をいくつかサポートしています。

  • onGrant: 関数の第1引数。認可が成功し、サーバーが要求された権限でRPTを返した場合、コールバックはRPTを受け取ります。

  • onDeny: 関数の第2引数。サーバーがリクエストを拒否した場合にのみ呼び出されます。

  • onError: 関数の第3引数。サーバーが予期せず応答する場合にのみ呼び出されます。

RPTの取得

ライブラリによって提供されている認可関数を使用してRPTをすでに取得している場合は、認可オブジェクトから次のようにRPTを得ることができます(前述のいずれかの手法で初期化されているものとします)。

var rpt = authorization.rpt;

9.1.6. TLS/HTTPSの設定

サーバーでHTTPSを使用する場合は、アダプターが次のように設定されていることを確認してください。

keycloak.json
{
  "truststore": "トラストストアへのパス",
  "truststore-password": "トラストストアのパスワード"
}

上記の設定により、認可クライアントでTLS/HTTPSが有効になり、HTTPSスキームを使用してリモートからKeycloakサーバーにアクセスできるようになります。

Keycloakサーバーのエンドポイントにアクセスする際は、TLS/HTTPSを有効にすること強くおすすめします。