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)

    Provides a distributable policy decision point to where authorization requests are sent and policies are evaluated accordingly with the permissions being requested. For more information, see Obtaining Permissions.

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

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

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

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

1.1.1. 認可プロセス

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

  • リソース管理

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

  • ポリシーの実施

リソース管理

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

リソース管理の概要

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

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

リソースサーバーの概要

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

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

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

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

権限とポリシーの管理

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

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

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

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

For instance,to allow access to a group of resources only for users granted with a role "User Premium", you can use RBAC (Role-based Access Control).

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

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

ポリシー実施

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

PEPの概要

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

1.1.2. 認可サービス

Authorization services consist of the following RESTFul endpoints:

  • Token Endpoint

  • Resource Management Endpoint

  • Permission Management Endpoint

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

トークン・エンドポイント

OAuth2 clients (such as front end applications) can obtain access tokens from the server using the token endpoint and use these same tokens to access resources protected by a resource server (such as back end services). In the same way, Keycloak Authorization Services provide extensions to OAuth2 to allow access tokens to be issued based on the processing of all policies associated with the resource(s) or scope(s) being requested. This means that resource servers can enforce access to their protected resources based on the permissions granted by the server and held by an access token. In Keycloak Authorization Services the access token with permissions is called a Requesting Party Token or RPT for short.

For more information, see Obtaining Permissions.

保護API

The Protection API is a set of UMA-compliant endpoint-providing operations for resource servers to help them manage their resources, scopes, permissions, and policies associated with them. Only resource servers are allowed to access this API, which also requires a uma_protection scope.

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

  • リソース管理

    • Create Resource

    • Delete Resource

    • Find by Id

    • Query

  • パーミッション管理

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

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

UMAプロトコルを使用する場合、保護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. パーミッション・チケット

A permission ticket is a special type of token defined by the User-Managed Access (UMA) specification that provides an opaque structure whose form is determined by the authorization server. This structure represents the resources and/or scopes being requested by a client, the access context, as well as the policies that must be applied to a request for authorization data (requesting party token [RPT]).

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

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

For more information on permission tickets, see User-Managed Access and the UMA specification.

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. Authorization Quickstarts

In addition to the app-authz-jee-vanilla quickstart that was used as a sample application in the previous section, the Keycloakクイックスタート・リポジトリー contains other applications that make use of the authorization services described in this documentation.

The authorization quickstarts have been designed so that authorization services are displayed in different scenarios and using different technologies and integrations. It is not meant as a comprehensive set of all the possible use cases involving authorization but they should provide a starting point for users interested in understanding how the authorization services can be used in their own applications.

Each quickstart has a README file with instructions on how to build, deploy, and test the sample application. The following table provides a brief description of the available authorization quickstarts:

Table 1. Authorization Quickstarts
Name Description

app-authz-jee-servlet

Demonstrates how to enable fine-grained authorization to a Java EE application in order to protect specific resources and build a dynamic menu based on the permissions obtained from a Keycloak Server.

app-authz-jee-vanilla

Demonstrates how to enable fine-grained authorization to a Java EE application and use the default authorization settings to protect all resources in the application.

app-authz-rest-springboot

Demonstrates how to protect a SpringBoot REST service using Keycloak Authorization Services.

app-authz-springboot

Demonstrates how to write a SpringBoot Web application where both authentication and authorization aspects are managed by Keycloak.

app-authz-uma-photoz

A simple application based on HTML5+AngularJS+JAX-RS that demonstrates how to enable User-Managed Access to your application and let users to manage permissions for their resources.

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

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

  • Authorization Scopes

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

  • Policies

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

  • Permissions

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

  • Evaluate

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

  • Export Settings

    From this page, you can export the authorization settings to a JSON file.

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

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

  • Remote Resource Management

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

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. Click the Export Settings tab.

  3. On this page, click Export.

    エクスポートの設定

    エクスポートの設定

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

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

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

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

    Import Settings

    Import Settings

リソースサーバーの設定ファイルをインポートするには、 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. リソース属性

Resources may have attributes associated with them. These attributes can be used to provide additional information about a resource and to provide additional information to policies when evaluating permissions associated with a resource.

Each attribute is a key and value pair where the value can be a set of one or many strings. Multiple values can be defined for an attribute by separating each value with a comma.

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

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

4.2.3. リソース・オーナー

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

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

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

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

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

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

5. ポリシーの管理

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

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

ポリシー

Policies

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

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

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

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

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

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

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

5.1.1. 設定

  • Name

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

  • 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

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

  • 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();

    /**
     * Returns a {@link Realm} that can be used by policies to query information.
     *
     * @return a {@link Realm} instance
     */
    Realm getRealm();

    /**
     * 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

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

  • 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

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

  • 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 フィルターを使用して、パーミッションを要求するユーザーを指定できます。

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

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

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

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

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

8. 認可サービス

Keycloak Authorization Services are built on top of well-known standards such as the OAuth2 and User-Managed Access specifications.

OAuth2 clients (such as front end applications) can obtain access tokens from the server using the token endpoint and use these same tokens to access resources protected by a resource server (such as back end services). In the same way, Keycloak Authorization Services provide extensions to OAuth2 to allow access tokens to be issued based on the processing of all policies associated with the resource(s) or scope(s) being requested. This means that resource servers can enforce access to their protected resources based on the permissions granted by the server and held by an access token. In Keycloak Authorization Services the access token with permissions is called a Requesting Party Token or RPT for short.

In addition to the issuance of RPTs, Keycloak Authorization Services also provides a set of RESTful endpoints that allow resources servers to manage their protected resources, scopes, permissions and policies, helping developers to extend or integrate these capabilities into their applications in order to support fine-grained authorization.

8.1. Discovering Authorization Services Endpoints and Metadata

Keycloak provides a discovery document from which clients can obtain all necessary information to interact with Keycloak Authorization Services, including endpoint locations and capabilities.

The discovery document can be obtained from:

curl -X GET \
  http://${host}:${port}/auth/realms/${realm}/.well-known/uma2-configuration

Where ${host}:${port} is the hostname (or IP address) and port where Keycloak is running and ${realm} is the name of a realm in Keycloak.

As a result, you should get a response as follows:

{

    // some claims are expected here

    // these are the main claims in the discovery document about Authorization Services endpoints location
    "token_endpoint": "http://${host}:${post}/auth/realms/${realm}/protocol/openid-connect/token",
    "token_introspection_endpoint": "http://${host}:${post}/auth/realms/${realm}/protocol/openid-connect/token/introspect",
    "resource_registration_endpoint": "http://${host}:${post}/auth/realms/${realm}/authz/protection/resource_set",
    "permission_endpoint": "http://${host}:${post}/auth/realms/${realm}/authz/protection/permission"
}

Each of these endpoints expose a specific set of capabilities:

  • token_endpoint

    A OAuth2-compliant Token Endpoint that supports the urn:ietf:params:oauth:grant-type:uma-ticket grant type. Through this endpoint clients can send authorization requests and obtain an RPT with all permissions granted by Keycloak.

  • token_introspection_endpoint

    A OAuth2-compliant Token Introspection Endpoint which clients can use to query the server to determine the active state of an RPT and to determine any other information associated with the token, such as the permissions granted by Keycloak.

  • resource_registration_endpoint

    A UMA-compliant Resource Registration Endpoint which resource servers can use to manage their protected resources and scopes. This endpoint provides operations create, read, update and delete resources and scopes in Keycloak.

  • permission_endpoint

    A UMA-compliant Permission Endpoint which resource servers can use to manage permission tickets. This endpoint provides operations create, read, update, and delete permission tickets in Keycloak.

8.2. Obtaining Permissions

To obtain permissions from Keycloak you send an authorization request to the token endpoint. As a result, Keycloak will evaluate all policies associated with the resource(s) and scope(s) being requested and issue an RPT with all permissions granted by the server.

Clients are allowed to send authorization requests to the token endpoint using the following parameters:

  • grant_type

    This parameter is required. Must be urn:ietf:params:oauth:grant-type:uma-ticket.

  • ticket

    This parameter is optional. The most recent permission ticket received by the client as part of the UMA authorization process.

  • claim_token

    This parameter is optional. A string representing additional claims that should be considered by the server when evaluating permissions for the resource(s) and scope(s) being requested. This parameter allow clients to push claims to Keycloak. For more details about all supported token formats see claim_token_format parameter.

  • claim_token_format

    This parameter is *optional. A string indicating the format of the token specified in the claim_token parameter. Keycloak supports two token formats: urn:ietf:params:oauth:token-type:jwt and http://openid.net/specs/openid-connect-core-1_0.html#IDToken. The urn:ietf:params:oauth:token-type:jwt format indicates that the claim_token parameter references an access token. The http://openid.net/specs/openid-connect-core-1_0.html#IDToken indicates that the claim_token parameter references an OpenID Connect ID Token.

  • rpt

    This parameter is *optional. A previously issued RPT which permissions should also be evaluated and added in a new one. This parameter allows clients in possession of an RPT to perform incremental authorization where permissions are added on demand.

  • permission

    This parameter is *optional. A string representing a set of one or more resources and scopes the client is seeking access. This parameter can be defined multiple times in order to request permission for multiple resource and scopes. This parameter is an extension to urn:ietf:params:oauth:grant-type:uma-ticket grant type in order to allow clients to send authorization requests without a permission ticket. The format of the string must be: RESOURCE_ID#SCOPE_ID. For instance: Resource A#Scope A, Resource A#Scope A, Scope B, Scope C, Resource A, #Scope A.

  • audience

    This parameter is optional. The client identifier of the resource server to which the client is seeking access. This parameter is mandatory in case the permission parameter is defined. It serves as a hint to Keycloak to indicate the context in which permissions should be evaluated.

  • response_include_resource_name

    This parameter is optional. A boolean value indicating to the server whether resource names should be included in the RPT’s permissions. if false, only the resource identifier is included.

  • response_permissions_limit

    This parameter is optional. An integer N that defines a limit for the amount of permissions an RPT can have. When used together with rpt parameter, only the last N requested permissions will be kept in the RPT.

  • submit_request

    This parameter is optional. A boolean value indicating whether the server should create permission requests to the resources and scopes referenced by a permission ticket. This parameter only have effect if used together with the ticket parameter as part of a UMA authorization process.

Example of a authorization request when a client is seeking access to two resources protected by a resource server.

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "audience=${resource_server_id}" \
  --data "permission=Resource A#Scope A" \
  --data "permission=Resource B#Scope B"

Example of a authorization request when a client is seeking access to any resource and scope protected by a resource server.

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"

Example of an authorization request when a client is seeking access to a UMA protected resource after receiving a permission ticket from the resource server as part of the authorization process:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket}

If $Keycloak assessment process results in issuance of permissions, it issues the RPT with which it has associated the permissions:

Keycloak responds to the client with the RPT
HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}

The response from the server is just like any other response from the token endpoint when using some other grant type. The RPT can be obtained from the access_token response parameter. If the client is not authorized, Keycloak responds with a 403 HTTP status code:

Keycloak denies the authorization request
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

8.2.1. Client Authentication Methods

Clients need to authenticate to the token endpoint in order to obtain an RPT. When using the urn:ietf:params:oauth:grant-type:uma-ticket grant type, clients can use any of these authentication methods:

  • Bearer Token

    Clients should send an access token as a Bearer credential in an HTTP Authorization header to the token endpoint.

    Example: an authorization request using an access token to authenticate to the token endpoint
    curl -X POST \
      http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
      -H "Authorization: Bearer ${access_token}" \
      --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"

    This method is especially useful when the client is acting on behalf of a user. In this case, the bearer token is an access token previously issued by Keycloak to some client acting on behalf of a user (or on behalf of itself). Permissions will be evaluated considering the access context represented by the access token. For instance, if the access token was issued to Client A acting on behalf of User A, permissions will be granted depending on the resources and scopes to which User A has access.

  • Client Credentials

    Client can use any of the client authentication methods supported by Keycloak. For instance, client_id/client_secret or JWT.

    Example: an authorization request using an access token to authenticate to the token endpoint
    curl -X POST \
      http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
      -H "Authorization: Basic cGhvdGg6L7Jl13RmfWgtkk==pOnNlY3JldA==" \
      --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"

8.3. User-Managed Access

Keycloak Authorization Services is based on User-Managed Access or UMA for short. UMA is a specification that enhances OAuth2 capabilities in the following ways:

  • Privacy

    Nowadays, user privacy is becoming a huge concern, as more and more data and devices are available and connected to the cloud. With UMA and Keycloak, resource servers can enhance their capabilities in order to improve how their resources are protected in respect to user privacy where permissions are granted based on policies defined by the user.

  • Party-to-Party Authorization

    Resource owners (e.g.: regular end-users) can manage access to their resources and authorize other parties (e.g: regular end-users) to access these resources. This is different than OAuth2 where consent is given to a client application acting on behalf of a user, with UMA resource owners are allowed to consent access to other users, in a completely asynchronous manner.

  • Resource Sharing

    Resource owners are allowed to manage permissions to their resources and decide who can access a particular resource and how. Keycloak can then act as a sharing management service from which resource owners can manage their resources.

Keycloak is a UMA 2.0 compliant authorization server that provides most UMA capabilities.

As an example, consider a user Alice (resource owner) using an Internet Banking Service (resource server) to manage his Bank Account (resource). One day, Alice decides to open her bank account to Bob (requesting party), a accounting professional. However, Bob should only have access to view (scope) Alice’s account.

As a resource server, the Internet Banking Service must be able to protect Alice’s Bank Account. For that, it relies on Keycloak Resource Registration Endpoint to create a resource in the server representing Alice’s Bank Account.

At this moment, if Bob tries to access Alice’s Bank Account, access will be denied. The Internet Banking Service defines a few default policies for banking accounts. One of them is that only the owner, in this case Alice, is allowed to access her bank account.

However, Internet Banking Service in respect to Alice’s privacy also allows her to change specific policies for he banking account. One of these policies that she can change is to define which people are allowed to view her bank account. For that, Internet Banking Service relies on Keycloak to provide to Alice a space where she can select individuals and the operations (or data) they are allowed to access. At any time, Alice can revoke access or grant additional permissions to Bob.

8.3.1. Authorization Process

In UMA, the authorization process starts when a client tries to access a UMA protected resource server.

A UMA protected resource server expects a bearer token in the request where the token is an RPT. When a client requests a resource at the resource server without a permission ticket:

Client requests a protected resource without sending an RPT
curl -X GET \
  http://${host}:8080/my-resource-server/resource/1bfdfe78-a4e1-4c2d-b142-fc92b75b986f

The resource server sends a response back to the client with a permission ticket and a as_uri parameter with the location of a Keycloak server to where the ticket should be sent in order to obtain an RPT.

Resource server responds with a permission ticket
HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${post}/auth/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"

The permission ticket is a special type of token issued by Keycloak Permission API. They represent the permissions being requested (e.g.: resources and scopes) as well any other information associated with the request. Only resource servers are allowed to create those tokens.

Now that the client has a permission ticket and also the location of a Keycloak server, the client can use the discovery document to obtain the location of the token endpoint and send an authorization request.

Client sends an authorization request to the token endpoint to obtain an RPT
curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket}

If $Keycloak assessment process results in issuance of permissions, it issues the RPT with which it has associated the permissions:

Keycloak responds to the client with the RPT
HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}

The response from the server is just like any other response from the token endpoint when using some other grant type. The RPT can be obtained from the access_token response parameter. In case the client is not authorized to have permissions Keycloak responds with a 403 HTTP status code:

Keycloak denies the authorization request
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

8.3.2. Submitting Permission Requests

As part of the authorization process, clients need first to obtain a permission ticket from a UMA protected resource server in order to exchange it with an RPT at the Keycloak Token Endpoint.

By default, Keycloak responds with a 403 HTTP status code and a request_denied error in case the client can not be issued with an RPT.

Keycloak denies the authorization request
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

Such response implies that Keycloak could not issue an RPT with the permissions represented by a permission ticket.

In some situations, client applications may want to start an asynchronous authorization flow and let the owner of the resources being requested decide whether or not access should be granted. For that, clients can use the submit_request request parameter along with an authorization request to the token endpoint:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket} \
  --data "submit_request=true"

When using the submit_request parameter, Keycloak will persist a permission request for each resource to which access was denied. Once created, resource owners can check their account and manage their permissions requests.

You can think about this functionality as a Request Access button in your application, where users can ask other users for access to their resources.

8.3.3. Managing Access to Users Resources

Users can manage access to their resources using the Keycloak User Account Service.

My Resources

On the left side menu, the My Resources option leads to a page where users are able to:

  • Manage Permission Requests that Need my approval

    This section contains a list of all permission requests awaiting approval. These requests are connected to the parties (users) requesting access to a particular resource. Users are allowed to approve or deny these requests.

  • Manage My resources

    This section contains a list of all resources owned by the user. Users can click on a resource for more details and share the resource with others.

  • Managed Resources shared with me

    This section contains a list of all resources shared with the user.

  • Manage Your requests waiting approval

    This section contains a list of permission requests sent by the user that are waiting for the approval of another user or resource owner.

When the user choose to detail own of his resources by clicking on any resource in the "My resources" listing, he is redirect to a page as follows:

Resource Detail

From this page the users are able to:

  • Manage People with access to the resource

    This section contains a list of people with access to the resource. Users are allowed to revoke access by clicking on the Revoke button or by removing a specific Permission.

  • Share the resource with others

    By typing the username or e-mail of another user, the user is able to share the resource and select the permissions he want to grant access.

8.4. 保護API

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

  • リソース管理

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

  • パーミッション管理

    In the UMA protocol, resource servers access this endpoint to create permission tickets. Keycloak also provides endpoints to manage the state of permissions and query permissions.

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

8.4.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.5. リソースの管理

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

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

このエンドポイントは、以下の概要を説明した操作を提供します(明確にするため、パス全体が省略されています)。

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

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

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

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

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

各操作の規約の詳細については、 UMA Resource Registration API を参照してください。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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.7.1. リクエスティング・パーティー・トークンのイントロスペクション

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

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

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

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

8.7.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_id": "90ccc6fc-b296-4cd1-881e-089e1ee15957",
      "resource_name": "Hello World Resource"
    }
  ],
  "exp": 1465314139,
  "nbf": 0,
  "iat": 1465313839,
  "aud": "hello-world-authz-service",
  "active": true
}

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

{
  "active": false
}

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

No. Just like a regular access token issued by a Keycloak server, RPTs also use the JSON web token (JWT) specification as the default format.

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

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

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

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

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

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

It is targeted for resource servers that want to access the different endpoints provided by the server such as the Token Endpoint, Resource, and Permission management endpoints.

8.8.1. Maven依存関係

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

8.8.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)

    Specifies the credentials of the application. This is an object notation where the key is the credential type and the value is the value of the credential type.

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

8.8.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.8.4. ユーザー・エンタイトルメントの取得

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

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

// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();

// send the entitlement request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();

System.out.println("You got an RPT: " + rpt);

// 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();

// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();

// add permissions to the request based on the resources and scopes you want to check access
request.addPermission("Default Resource");

// send the entitlement request to the server in order to
// obtain an RPT with permissions for a single resource
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();

System.out.println("You got an RPT: " + rpt);

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

8.8.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();
ResourceRepresentation existingResource = resourceClient.findByName(newResource.getName());

if (existingResource != null) {
    resourceClient.delete(existingResource.getId());
}

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

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

System.out.println(resource);

8.8.6. Introspecting an RPT

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

// send the authorization request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize();
String rpt = response.getToken();

// introspect the token
TokenIntrospectionResponse requestingPartyToken = authzClient.protection().introspectRequestingPartyToken(rpt);

System.out.println("Token status is: " + requestingPartyToken.getActive());
System.out.println("Permissions granted by the server: ");

for (Permission granted : requestingPartyToken.getPermissions()) {
    System.out.println(granted);
}

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

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

PEPの概要

A PEP is responsible for enforcing access decisions from the Keycloak server where these decisions are taken by evaluating the policies associated with a protected resource. It acts as a filter or interceptor in your application in order to check whether or not a particular request to a protected resource can be fulfilled based on the permissions granted by these decisions.

If you are using any of the Keycloak OIDC adapters, you can easily enable the policy enforcer by adding the following property to your keycloak.json file:

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

When you enable the policy enforcer all requests sent your application are intercepted and access to protected resources will be granted depending on the permissions granted by Keycloak to the identity making the request.

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

9.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

        Completely disables the evaluation of policies and allows access to any resource. When enforcement-mode is DISABLED applications are still able to obtain all permissions granted by Keycloak through the Authorization Context

    • on-deny-redirect-to

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

    • path-cache

      Defines how the policy enforcer should track associations between paths in your application and resources defined in Keycloak. The cache is needed to avoid unnecessary requests to a Keycloak server by caching associations between paths and protected resources.

      • lifespan

        Defines the time in milliseconds when the entry should be expired. If not provided, default value is 3000. A value less than or equal to 0 can be set to completely disable the cache.

      • max-entries

        Defines the limit of entries that should be kept in the cache. If not provided, default value is 1000.

    • paths

      Specifies the paths to protect. This configuration is optional. If not defined, the policy enforcer will discover all paths by fetching the resources you defined to your application in Keycloak, where these resources are defined with a URI representing some path in your application.

      • 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

        The HTTP methods (for example, GET, POST, PATCH) to protect and how they are associated with the scopes for a given resource in the server.

        • 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

      • claim-information-point

        Defines a set of one or more claims that must be resolved and pushed to the Keycloak server in order to make these claims available to policies. See Claim Information Point for more details. * *lazy-load-paths

        Specifies how the adapter should fetch the server for resources associated with paths in your application. If true, the policy enforcer is going to fetch resources on-demand accordingly with the path being requested. This configuration is specially useful when you don’t want to fetch all resources from the server during deployment (in case you have provided no paths) or in case you have defined only a sub set of paths and want to fetch others on-demand.

9.2. Claim Information Point

A Claim Information Point (CIP) is responsible for resolving claims and pushing these claims to the Keycloak server in order to provide more information about the access context to policies. They can be defined as a configuration option to the policy-enforcer in order to resolve claims from different sources, such as:

  • HTTP Request (parameters, headers, body, headers, etc)

  • External HTTP Service

  • Static values defined in configuration

  • Any other source by implementing the Claim Information Provider SPI

When pushing claims to the Keycloak server, policies can base decisions not only on who a user is but also by taking context and contents into account, based on who, what, why, when, where, and which for a given transaction. It is all about Contextual-based Authorization and how to use runtime information in order to support fine-grained authorization decisions.

9.2.1. Obtaining information from the HTTP Request

Here are several examples showing how you can extract claims from an HTTP request:

keycloak.json
"policy-enforcer": {
    "paths": [
      {
        "path": "/protected/resource",
        "claim-information-point": {
          "claims": {
            "claim-from-request-parameter": "{request.parameter['a']}",
            "claim-from-header": "{request.header['b']}",
            "claim-from-cookie": "{request.cookie['c']}",
            "claim-from-remoteAddr": "{request.remoteAddr}",
            "claim-from-method": "{request.method}",
            "claim-from-uri": "{request.uri}",
            "claim-from-relativePath": "{request.relativePath}",
            "claim-from-secure": "{request.secure}",
            "claim-from-json-body-object": "{request.body['/a/b/c']}",
            "claim-from-json-body-array": "{request.body['/d/1']}",
            "claim-from-body": "{request.body}",
            "claim-from-static-value": "static value",
            "claim-from-multiple-static-value": ["static", "value"],
            "param-replace-multiple-placeholder": "Test {keycloak.access_token['/custom_claim/0']} and {request.parameter['a']} "
          }
        }
      }
    ]
  }

9.2.2. Obtaining information from an External HTTP Service

Here are several examples showing how you can extract claims from an external HTTP Service:

keycloak.json
"policy-enforcer": {
    "paths": [
      {
        "path": "/protected/resource",
        "claim-information-point": {
          "http": {
            "claims": {
              "claim-a": "/a",
              "claim-d": "/d",
              "claim-d0": "/d/0",
              "claim-d-all": ["/d/0", "/d/1"]
            },
            "url": "http://mycompany/claim-provider",
            "method": "POST",
            "headers": {
              "Content-Type": "application/x-www-form-urlencoded",
              "header-b": ["header-b-value1", "header-b-value2"],
              "Authorization": "Bearer {keycloak.access_token}"
            },
            "parameters": {
              "param-a": ["param-a-value1", "param-a-value2"],
              "param-subject": "{keycloak.access_token['/sub']}",
              "param-user-name": "{keycloak.access_token['/preferred_username']}",
              "param-other-claims": "{keycloak.access_token['/custom_claim']}"
            }
          }
        }
      }
    ]
  }

9.2.3. Static Claims

keycloak.json
"policy-enforcer": {
    "paths": [
      {
        "path": "/protected/resource",
        "claim-information-point": {
          "claims": {
            "claim-from-static-value": "static value",
            "claim-from-multiple-static-value": ["static", "value"],
          }
        }
      }
    ]
  }

9.2.4. Claim Information Provider SPI

The Claim Information Provider SPI can be used by developers to support different claim information points in case none of the built-ins providers are enough to address their requirements.

For example, to implement a new CIP provider you need to implement org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory and ClaimInformationPointProvider and also provide the file META-INF/services/org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory in your application`s classpath.

Example of org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory:

public class MyClaimInformationPointProviderFactory implements ClaimInformationPointProviderFactory<MyClaimInformationPointProvider> {

    @Override
    public String getName() {
        return "my-claims";
    }

    @Override
    public void init(PolicyEnforcer policyEnforcer) {

    }

    @Override
    public MyClaimInformationPointProvider create(Map<String, Object> config) {
        return new MyClaimInformationPointProvider(config);
    }
}

Every CIP provider must be associated with a name, as defined above in the MyClaimInformationPointProviderFactory.getName method. The name will be used to map the configuration from the claim-information-point section in the policy-enforcer configuration to the implementation.

When processing requests, the policy enforcer will call the MyClaimInformationPointProviderFactory.create method in order to obtain an instance of MyClaimInformationPointProvider. When called, any configuration defined for this particular CIP provider (via claim-information-point) is passed as a map.

Example of ClaimInformationPointProvider:

public class MyClaimInformationPointProvider implements ClaimInformationPointProvider {

    private final Map<String, Object> config;

    public ClaimsInformationPointProvider(Map<String, Object> config) {
        this.config = config;
    }

    @Override
    public Map<String, List<String>> resolve(HttpFacade httpFacade) {
        Map<String, List<String>> claims = new HashMap<>();

        // put whatever claim you want into the map

        return claims;
    }
}

9.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.4. 認可クライアント・インスタンスを取得するためAuthorizationContextを使用する

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

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

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

9.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つの主な機能があります。

  • Obtain permissions from the server using a permission ticket, if you are accessing a UMA protected resource server.

  • Obtain permissions from the server by sending the resources and scopes the application wants to access.

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

9.5.1. Handling Authorization Responses from a UMA-Protected Resource Server

If a resource server is protected by a policy enforcer, it responds to client requests based on the permissions carried along with a bearer token. Typically, when you try to access a resource server with a bearer token that is lacking permissions to access a protected resource, the resource server responds with a 401 status code and a WWW-Authenticate header.

HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${post}/auth/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"

See UMA Authorization Process for more information.

What your client needs to do is extract the permission ticket from the WWW-Authenticate header returned by the resource server and use the library to send an authorization request as follows:

// prepare a authorization request with the permission ticket
var authorizationRequest = {};
authorizationRequest.ticket = ticket;

// send the authorization request, if successful retry the request
Identity.authorization.authorize(authorizationRequest).then(function (rpt) {
    // onGrant
}, function () {
    // onDeny
}, function () {
    // onError
});

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

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

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

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

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

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

The keycloak-authz.js library provides an entitlement function that you can use to obtain an RPT from the server by providing the resources and scopes your client wants to access.

Example about how to obtain an RPT with permissions for all resources and scopes the user can access
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
});
Example about how to obtain an RPT with permissions for specific resources and scopes
authorization.entitlement('my-resource-server', {
    "permissions": [
        {
            "id" : "Some Resource"
        }
    ]
}).then(function (rpt) {
    // onGrant
});

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

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

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

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

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

9.5.3. Authorization Request

Both authorize and entitlement functions accept an authorization request object. This object can be set with the following properties:

  • permissions

    An array of objects representing the resource and scopes. For instance:

    var authorizationRequest = {
       "permissions": [
           {
               "id" : "Some Resource",
               "scopes" : ["view", "edit"]
           }
       ]
    }
  • metadata

    An object where its properties define how the authorization request should be processed by the server.

    • response_include_resource_name

      A boolean value indicating to the server if resource names should be included in the RPT’s permissions. If false, only the resource identifier is included. * *response_permissions_limit

      An integer N that defines a limit for the amount of permissions an RPT can have. When used together with rpt parameter, only the last N requested permissions will be kept in the RPT

  • submit_request

    A boolean value indicating whether the server should create permission requests to the resources and scopes referenced by a permission ticket. This parameter will only take effect when used together with the ticket parameter as part of a UMA authorization process.

9.5.4. RPTの取得

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

var rpt = authorization.rpt;

9.6. TLS/HTTPSの設定

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

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

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

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