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のセットを提供します。このうちの一部は、Protection APIを使用してリモートでも実現できます。

  • ポリシー決定点(PDP)

    認可リクエストが送信され、リクエストが許可されることでポリシーが評価される場所に配布可能なポリシー決定点を提供します。詳細については、パーミッションの取得を参照してください。

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

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

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

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

1.1.1. 認可プロセス

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

  • リソース管理

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

  • ポリシーの実施

リソース管理

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

リソース管理の概要

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

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

リソースサーバーの概要

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

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

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

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

権限とポリシーの管理

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

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

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

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

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

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

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

ポリシー実施

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

PEPの概要

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

1.1.2. 認可サービス

認可サービスは以下のRESTFulエンドポイントで構成されています。

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

  • リソース管理エンドポイント

  • パーミッション管理エンドポイント

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

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

OAuth2クライアント(フロントエンド・アプリケーションなど)は、トークン・エンドポイントを使用してサーバーからアクセストークンを取得し、これらのトークンを使用してリソースサーバーによって保護されたリソース(バックエンド・サービスなど)にアクセスできます。同様に、Keycloak認可サービスは、要求されているリソースまたはスコープに関連するすべてのポリシーの処理に基づいてアクセストークンを発行できるように、OAuth2の拡張機能を提供します。つまり、リソースサーバーは、サーバーによって付与され、アクセストークンによって保持されているアクセス許可に基づいて、保護されたリソースへのアクセスを強制できます。Keycloak認可サービスでは、アクセス権を持つアクセストークンはリクエスティング・パーティー・トークンまたはRPTと呼ばれます。

詳細については、パーミッションの取得を参照してください。

Protection API

Protection APIUMA準拠 のエンドポイントのセットであり、リソースサーバーがリソース、スコープ、パーミッション、およびそれらに関連付けられたポリシーを管理する上で役立つ操作を提供します。リソースサーバーだけがこのAPIにアクセスできますが、 uma_protection スコープも必要です。

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

  • リソース管理

    • Create Resource

    • Delete Resource

    • Find by Id

    • Query

  • パーミッション管理

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

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

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

より詳細な情報はProtection 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. パーミッション・チケット

パーミッション・チケットは、UMA(User-Managed Access)仕様で定義された特別なタイプのトークンで、その形式が認可サーバーによって決定されるOpaque構造体を提供します。この構造体は、クライアントによって要求されているリソースおよび/またはスコープ、アクセス・コンテキスト、および認可データ(リクエスティング・パーティ・トークン[RPT]を要求する)に適用する必要のあるポリシーを表します。

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

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

パーミッション・チケットの詳細については、User-Managed Accessおよび 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

https://github.com/keycloak/keycloak-quickstarts のリポジトリーをクローンして、コードを入手することができます。このクイックスタートはKeycloakの最新リリースで動作するように設計されています。

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

プロジェクトのクローン
$ 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. 認可のクイックスタート

前のセクションでサンプル・アプリケーションとして使用されていた app-authz-jee-vanilla クイックスタートに加えて、Keycloakクイックスタート・リポジトリーには、このドキュメントに記載されている認可サービスを利用する他のアプリケーションが含まれています。

認可クイックスタートは、認可サービスがさまざまなシナリオで機能し、さまざまなテクノロジーと統合を使用するように設計されています。認可を含むすべての可能なユースケースの包括的なセットではありませんが、認可サービスをどのようにして自分のアプリケーションで使用できるかを理解することに関心のあるユーザーにとっては、出発点となります。

各クイックスタートには、サンプル・アプリケーションをビルド、デプロイ、テストの方法に関する指示を含む README ファイルがあります。次の表に、使用可能な認可クイックスタートの簡単な説明を示します。

Table 1. 認可のクイックスタート
名前 説明

app-authz-jee-servlet

特定のリソースを保護し、Keycloakサーバーから取得したパーミッションに基づいて動的メニューを構築するために、Java EEアプリケーションに対するきめ細かい認可を有効にする方法を示します。

app-authz-jee-vanilla

Java EEアプリケーションに対するきめ細かな認可を有効にし、デフォルトの認可設定を使用してアプリケーション内のすべてのリソースを保護する方法を示します。

app-authz-rest-springboot

Keycloak認可サービスを使用してSpring Boot RESTサービスを保護する方法を示します。

app-authz-springboot

Keycloakによって認証および認可の両方の側面が管理されるSpring Boot Webアプリケーションの作成方法を示します。

app-authz-uma-photoz

HTML5+AngularJS+JAX-RSに基づくシンプルなアプリケーションで、アプリケーションへのUser-Managed Accessを有効にし、ユーザーにリソースのパーミッションを管理させる方法を示します。

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

    このページから、認可設定をJSONファイルにエクスポートできます。

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

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

  • Policy Enforcement Mode

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

    • Enforcing

      (デフォルトモード)特定のリソースに関連付けられたポリシーがない場合でも、デフォルトでリクエストは拒否されます。

    • Permissive

      特定のリソースに関連付けられたポリシーがない場合でも、リクエストは許可されます。

    • 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 で作成されます。独自のリソース、権限、ポリシーを作成する前に、デフォルト設定が自分の設定と矛盾しないことを確認してください。

The default configuration defines a resource that maps to all paths in your application. If you are about to write permissions to your own resources, be sure to remove the Default Resource or change its URIS fields to a more specific paths in your application. Otherwise, the policy associated with the default resource (which by default always grants access) will allow Keycloak to grant access to any protected resource.

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

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

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

  • ポリシー

  • パーミッション

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

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

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

  2. Export Settings タブをクリックします。

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

    エクスポートの設定

    エクスポートの設定

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

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

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

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

    インポート設定

    Import Settings

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

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

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

4.1. リソースの表示

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

リソース

Resources

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

  • タイプ

  • URIS

  • オーナー

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

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

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

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

4.2. リソースの作成

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

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

リソースの追加

リソースの追加

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

  • Name

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

  • Type

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

  • URIS

    URIS that provides the locations/addresses for the resource. For HTTP resources, the URIS are usually the relative paths used to serve these resources.

  • Scopes

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

4.2.1. リソース属性

リソースには属性が関連付けられている場合があります。これらの属性を使用すると、リソースに関する追加情報を提供したり、リソースに関連付けられているアクセス許可を評価するときにポリシーに追加情報を提供できます。

各属性はキーと値のペアで、値は1つ以上の文字列のセットになります。属性に複数の値を定義するには、各値をカンマで区切ります。

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

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

4.2.3. リソース・オーナー

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

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

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

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

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

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

5. ポリシーの管理

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

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

ポリシー

Policies

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

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

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

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

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

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

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

5.1.1. 設定

  • Name

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

  • Description

    このポリシーに関する詳細情報を含む文字列。

  • Users

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

  • Logic

    他の条件が評価された後に適用する、このポリシーのロジック

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

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

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

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

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

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

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

5.2.1. 設定

  • Name

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

  • Description

    このポリシーに関する詳細情報を含む文字列。

  • Realm Roles

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

  • Client Roles

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

  • Logic

    他の条件が評価された後に適用する、このポリシーのロジック

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

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

必須ロールの例

Example of Required Role

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

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

5.3. JavaScriptベースポリシー

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

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

JavaScriptポリシーの追加

JavaScriptポリシーの追加

5.3.1. 設定

  • Name

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

  • Description

    このポリシーに関する詳細情報を含む文字列。

  • Code

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

  • Logic

    他の条件が評価された後に適用する、このポリシーのロジック

5.3.2. サンプル

Checking for attributes from the evaluation context

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

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

if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
    $evaluation.grant();
}
Checking for attributes from the current identity

Here is a simple example of a JavaScript-based policy that uses attribute-based access control (ABAC) to define a condition based on an attribute obtained associated with the current identity:

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

if (email.endsWith('@keycloak.org')) {
    $evaluation.grant();
}

Where these attributes are mapped from whatever claim is defined in the token that was used in the authorization request.

Checking for roles granted to the current identity

ロール・ベース・アクセス・コントロール(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();
}
Checking for roles granted to an user

To check for realm roles granted to an user:

var realm = $evaluation.getRealm();

if (realm.isUserInRealmRole('marta', 'role-a')) {
    $evaluation.grant();
}

Or for client roles granted to an user:

var realm = $evaluation.getRealm();

if (realm.isUserInClientRole('marta', 'my-client', 'some-client-role')) {
    $evaluation.grant();
}
Checking for roles granted to a group

To check for realm roles granted to a group:

var realm = $evaluation.getRealm();

if (realm.isGroupInRole('/Group A/Group D', 'role-a')) {
    $evaluation.grant();
}
Pushing arbitrary claims to the resource server

To push arbitrary claims to the resource server in order to provide additional information on how permissions should be enforced:

var permission = $evaluation.getPermission();

// decide if permission should be granted

if (granted) {
    permission.addClaim('claim-a', 'claim-a');
    permission.addClaim('claim-a', 'claim-a1');
    permission.addClaim('claim-b', 'claim-b');
}
Checking for group membership
var realm = $evaluation.getRealm();

if (realm.isUserInGroup('marta', '/Group A/Group B')) {
    $evaluation.grant();
}
Mixing different access control mechanisms

いくつかのアクセス・コントロール機構の組み合わせを使用することもできます。 以下の例は、同じポリシー内でロール(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 を実装するオブジェクトであることに注意してください。このインターフェイスからアクセスできるものの詳細については、Evaluation APIを参照してください。

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

このタイプのポリシーでは、ルール評価環境である Drools を使用してパーミッションの条件を定義できます。これはKeycloakでサポートされている ルールベース のポリシー・タイプの1つであり、 Evaluation 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

    他の条件が評価された後に適用する、このポリシーのロジック

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

    このポリシーに関する詳細情報を含む文字列。

  • Not Before

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

  • Not On or After

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

  • Day of Month

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

  • Month

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

  • Year

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

  • Hour

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

  • Minute

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

  • Logic

    他の条件が評価された後に適用する、このポリシーのロジック

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

5.6. 集約されたポリシー

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

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

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

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

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

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

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

5.6.1. 設定

  • Name

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

  • Description

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

  • Apply Policy

    集約されたポリシーに関連付ける1つ以上のポリシーのセットを定義します。ポリシーを関連付けるには、既存のポリシーを選択するか、作成するポリシーのタイプを選択して新しいポリシーを作成します。

  • Decision Strategy

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

  • Logic

    他の条件が評価された後に適用する、このポリシーのロジック

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

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

  • Unanimous

    デフォルトの戦略。この場合、最終的に 全て のポリシー判定結果が肯定と判定される必要があります。

  • Affirmative

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

  • Consensus

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

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

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

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

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

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

5.7.1. 設定

  • Name

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

  • Description

    このポリシーに関する詳細情報を含む文字列。

  • Clients

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

  • Logic

    他の条件が評価された後に適用する、このポリシーのロジック

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

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

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

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

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

5.8.1. 設定

  • Name

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

  • Description

    このポリシーに関する詳細情報を含む文字列。

  • Groups Claim

    Specifies the name of the claim in the token holding the group names and/or paths. Usually, authorization requests are processed based on an ID Token or Access Token previously issued to a client acting on behalf of some user. If defined, the token must include a claim from where this policy is going to obtain the groups the user is a member of. If not defined, user’s groups are obtained from your realm configuration.

  • Groups

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

  • Logic

    他の条件が評価された後に適用する、このポリシーのロジック

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

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

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

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

Extending Access to Child Groups

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

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

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

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

5.10. Policy Evaluation API

JavaScriptまたはJBoss Droolsを使用してルールベースのポリシーを作成する場合、Keycloakは、パーミッションを与える必要があるかどうかを判断するのに役立つ情報を提供するEvaluation 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() メソッドを呼び出してポリシー評価エンジンに許可を与える必要があることを示す必要があります。

Evaluation 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

    デフォルトの戦略。この場合、最終的に 全て のポリシー判定結果が肯定と判定される必要があります。

  • Affirmative

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

  • Consensus

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

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

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

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

ポリシー評価ツール

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

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

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

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

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

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

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

8. 認可サービス

Keycloak認可サービスは、OAuth2やUser-Managed Accessなどのよく知られている標準をベースに構築されています。

OAuth2クライアント(フロントエンド・アプリケーションなど)は、トークン・エンドポイントを使用してサーバーからアクセストークンを取得し、これらのトークンを使用してリソースサーバーによって保護されたリソース(バックエンド・サービスなど)にアクセスできます。同様に、Keycloak認可サービスは、要求されているリソースまたはスコープに関連するすべてのポリシーの処理に基づいてアクセストークンを発行できるように、OAuth2の拡張機能を提供します。つまり、リソースサーバーは、サーバーによって付与され、アクセストークンによって保持されているアクセス許可に基づいて、保護されたリソースへのアクセスを強制できます。Keycloak認可サービスでは、アクセス権を持つアクセストークンはリクエスティング・パーティー・トークンまたはRPTと呼ばれます。

RPTの発行に加えて、Keycloak認可サービスには、保護されたリソース、スコープ、パーミッション、ポリシーをリソースサーバーが管理できるようにし、アプリケーションがきめ細かい認可をサポートするために、これらのケイパビリティーを拡張または統合するにあたって開発者にとって役立つ一連のRESTfulエンドポイントが用意されています。

8.1. 認可サービスのエンドポイントとメタデータの検出

Keycloakは、クライアントがKeycloak認可サービスと対話するために必要なすべての情報を取得するためのディスカバリー・ドキュメントを提供します。これにはエンドポイントの場所とケイパビリティーを含んでいます。

ディスカバリー・ドキュメントは以下から入手できます。

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

${host}:${port} は、Keycloakが実行されているホスト名(またはIPアドレス)とポートであり、 ${realm} はKeycloakのレルム名です。

その結果、次のようなレスポンスが得られます。

{

    // 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",
    "policy_endpoint": "http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy"
}

これらの各エンドポイントは、特定のケイパビリティーのセットを公開します。

  • token_endpoint

    urn:ietf:params:oauth:grant-type:uma-ticket グラントタイプをサポートするOAuth2準拠のトークン・エンドポイント。このエンドポイントを通じて、クライアントは、Keycloakによって許可されたすべてのパーミッションを使用して認可リクエストを送信し、RPTを取得できます。

  • token_introspection_endpoint

    クライアントがRPTのアクティブな状態を判断し、トークンに関連付けられているその他の情報(Keycloakによって付与されたパーミッションなど)を決定するため、サーバーの検索に使用できるOAuth2準拠のトークン・イントロスペクション・エンドポイント。

  • resource_registration_endpoint

    リソースサーバーが保護されたリソースとスコープを管理するために使用できるUMA準拠のリソース登録エンドポイント。このエンドポイントは、Keycloakのリソースとスコープの作成、読み取り、更新、および削除の操作を提供します。

  • permission_endpoint

    リソースサーバーがパーミッション・チケットの管理に使用できるUMA準拠のパーミッション・エンドポイント。このエンドポイントは、Keycloakのパーミッション・チケットの作成、読み取り、更新、および削除の操作を提供します。

8.2. パーミッションの取得

Keycloakからパーミッションを取得するには、認可リクエストをトークン・エンドポイントに送信します。その結果、Keycloakは要求されているリソースとスコープに関連するすべてのポリシーを評価し、サーバーによって付与されたすべてのパーミッションを持つRPTを発行します。

クライアントは、次のパラメーターを使用してトークン・エンドポイントに認可リクエストを送信できます。

  • grant_type

    このパラメーターは required です。 urn:ietf:params:oauth:grant-type:uma-ticket でなければなりません。

  • ticket

    このパラメーターは optional です。UMA認可プロセスの一環としてクライアントが受信した最新のパーミッション・チケットです。

  • claim_token

    このパラメーターは optional です。要求されているリソースとスコープのパーミッションを評価するときに、サーバーが考慮する必要がある追加の要求を表す文字列です。このパラメーターにより、クライアントはKeycloakにクレームをプッシュできます。サポートされているすべてのトークン形式の詳細については、 claim_token_format パラメーターを参照してください。

  • 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 https://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 https://openid.net/specs/openid-connect-core-1_0.html#IDToken indicates that the claim_token parameter references an OpenID Connect ID Token.

  • rpt

    このパラメーターは optional です。以前に発行されたRPTで、そのパーミッションも評価して新しいものに追加する必要があります。このパラメーターを使用すると、RPTを所有しているクライアントは、必要に応じてパーミッションが追加される追加認可を実行できます。

  • permission

    このパラメーターは optional です。クライアントがアクセスしようとしている1つ以上のリソースとスコープのセットを表す文字列です。このパラメーターは、複数のリソースとスコープに対するパーミッションを要求するために複数回定義することができます。このパラメーターは、クライアントがパーミッション・チケットなしで認可リクエストを送信できるようにするための、 urn:ietf:params:oauth:grant-type:uma-ticket グラントタイプの拡張です。文字列の形式は次のとおりでなければなりません。RESOURCE_ID#SCOPE_ID 。例: Resource A#Scope AResource A#Scope A, Scope B, Scope CResource A#Scope A

  • audience

    このパラメーターは optional です。クライアントがアクセスしようとしているリソースサーバーのクライアント識別子です。このパラメーターは permission パラメーターが定義されている場合に必須です。パーミッションが評価されるべきコンテキストを示すための、Keycloakへのヒントとして役立ちます。

  • response_include_resource_name

    このパラメーターは optional です。リソース名をRPTのパーミッションに含めるかどうかをサーバーに示すブール値です。falseの場合、リソース識別子のみが含まれます。

  • response_permissions_limit

    このパラメーターは optional です。RPTが持つことができるパーミッションの量の限界を定義する整数Nです。 rpt パラメーターと一緒に使用すると、最後に要求されたN個のパーミッションだけがRPTに保持されます。

  • submit_request

    このパラメーターは optional です。サーバーがリソースへのパーミッション・リクエストを作成する必要があるかどうかを示すブール値であり、パーミッション・チケットによって参照されるスコープです。このパラメーターは、UMA認証プロセスの一部として ticket パラメーターとともに使用される場合にのみ有効です。

  • response_mode

    This parameter is optional. A string value indicating how the server should respond to authorization requests. This parameter is specially useful when you are mainly interested in either the overall decision or the permissions granted by the server, instead of an standard OAuth2 response. Possible values are:

    • decision

      Indicates that responses from the server should only represent the overall decision by returning a JSON with the following format:

      {
          'result': true
      }

      If the authorization request does not map to any permission, a 403 HTTP status code is returned instead.

    • permissions

      Indicates that responses from the server should contain any permission granted by the server by returning a JSON with the following format:

      [
          {
              'rsid': 'My Resource'
              'scopes': ['view', 'update']
          },
      
          ...
      ]

      If the authorization request does not map to any permission, a 403 HTTP status code is returned instead.

クライアントがリソースサーバーによって保護された2つのリソースへのアクセスを求めている場合のパーミッション・リクエストの例です。

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_client_id}" \
  --data "permission=Resource A#Scope A" \
  --data "permission=Resource B#Scope B"

クライアントがリソースサーバーによって保護されたすべてのリソースとスコープへのアクセスを求めている場合のパーミッション・リクエストの例です。

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_client_id}"

認可プロセスの一環として、リソースサーバーからパーミッション・チケットを受け取った後で、クライアントがUMA保護リソースへのアクセスを求めている場合の認可リクエストの例です。

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}

$Keycloakの評価プロセスの結果、パーミッションが発行されると、そのパーミッションに関連付けられているRPTが発行されます。

KeycloakはRPTを使用してクライアントに応答します
HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}

サーバーからのレスポンスは、他のグラントタイプを使用しているときのトークン・エンドポイントからの任意のレスポンスとまったく同じです。RPTは access_token レスポンス・パラメーターから取得できます。クライアントが承認されていない場合、Keycloakは次のように 403 HTTPステータスコードで応答します。

Keycloakの認可リクエストの拒否
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

8.2.1. クライアントの認証方式

クライアントは、RPTを取得するためにトークン・エンドポイントで認証する必要があります。 urn:ietf:params:oauth:grant-type:uma-ticket グラントタイプを使う際に、クライアントは以下の認証方式のどれかを使用できます。

  • ベアラートークン

    クライアントは、トークン・エンドポイントにHTTP Authorizationヘッダーのベアラー・クレデンシャルとしてアクセストークンを送信する必要があります。

    例:アクセストークンを使用してトークン・エンドポイントで認証する認可リクエスト
    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"

    この方法は、クライアントがユーザーに代わって動作している場合に特に便利です。この場合、ベアラトークンは以前にKeycloakにより、ユーザーの代わりに(またはそれ自体のために)動作しているクライアントに発行されたアクセストークンです。パーミッションは、アクセストークンによって表されるアクセス・コンテキストを考慮して評価されます。例えば、アクセストークンがユーザーAの代わりに動作するクライアントAに発行された場合、ユーザーAがアクセスするリソース及びスコープに応じてパーミッションが与えられます。

  • クライアント・クレデンシャル

    クライアントは、Keycloakでサポートされているクライアント認証方式を使用できます。たとえば、client_id / client_secretまたはJWTです。

    Example: an authorization request using client id and client secret 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.2.2. Pushing Claims

When obtaining permissions from the server you can push arbitrary claims in order to have these claims available to your policies when evaluating permissions.

If you are obtaining permissions from the server without using a permission ticket (UMA flow), you can send an authorization request to the token endpoint as follows:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "claim_token=ewogICAib3JnYW5pemF0aW9uIjogWyJhY21lIl0KfQ==" \
  --data "claim_token_format=urn:ietf:params:oauth:token-type:jwt" \
  --data "client_id={resource_server_client_id}" \
  --data "client_secret={resource_server_client_secret}" \
  --data "audience={resource_server_client_id}"

The claim_token parameter expects a BASE64 encoded JSON with a format similar to the example below:

{
    "organization" : ["acme"]
}

The format expects one or more claims where the value for each claim must be an array of strings.

Pushing Claims Using UMA

For more details about how to push claims when using UMA and permission tickets, please take a look at Permission API

8.3. User-Managed Access

Keycloak認可サービスは、User-Managed Accessまたは略すとUMAに基づいています。UMAは、以下の方法でOAuth2機能を強化する仕様です。

  • プライバシー

    現在、クラウドに接続するデータやデバイスが増えているため、ユーザーのプライバシーは大きな問題になっています。UMAとKeycloakを使用すると、リソースサーバーは、ユーザーが定義したポリシーに基づいてパーミッションが与えられているユーザーのプライバシーに関するリソースの保護方法を向上させるように機能を強化できます。

  • Party-to-Party認可

    リソースオーナー(例えば、通常のエンドユーザー)は、そのリソースへのアクセスを管理し、他の関係者(例えば、通常のエンドユーザー)がこれらのリソースにアクセスすることを認可することができます。これは、完全に非同期に、UMAリソースオーナーが他のユーザーへのアクセスを同意することを許可された状態で、ユーザーに代わって動作するクライアント・アプリケーションに同意が与えられるOAuth2とは異なります。

  • リソース共有

    リソースオーナーは、リソースへのアクセス許可を管理し、特定のリソースにアクセスできるユーザーとその方法を決定できます。Keycloakは、リソースオーナーがリソースを管理できる共有管理サービスとして機能します。

Keycloakは、大部分のUMA機能を提供するUMA 2.0準拠の認可サーバーです。

たとえば、インターネット・バンキング・サービス(リソースサーバー)を使用して自分の銀行口座(リソース)を管理するユーザーAlice(リソースオーナー)を考えてみましょう。ある日、アリスはアカウンティング・プロフェッショナルのボブ(依頼者)に銀行口座を開設することに決めました。しかし、BobはAliceのアカウントを表示(スコープ)するためのアクセス権しか持つべきではありません。

リソースサーバーとして、インターネット・バンキング・サービスはアリスの銀行口座を保護できなければなりません。そのため、Keycloakリソース登録エンドポイントを使用して、Aliceの銀行口座を表すサーバーにリソースを作成します。

この時点で、BobがAliceの銀行口座にアクセスしようとすると、アクセスは拒否されます。インターネット・バンキング・サービスは、銀行口座のいくつかのデフォルト・ポリシーを定義しています。そのうちの1つは、オーナー(この場合はアリス)のみが自分の銀行口座にアクセスできることです。

しかし、インターネット・バンキング・サービスは、アリスのプライバシーに関して、彼女が銀行口座の特定のポリシーを変更することも可能にします。彼女が変更できるこれらのポリシーの1つは、誰が自分の銀行口座を見ることができるかを定義することです。そのために、インターネット・バンキング・サービスは、Keycloakを利用して、個人が選択できるスペースとアクセスが許可されている操作(またはデータ)をAliceに提供します。Aliceはいつでも、アクセス権を取り消したり、Bobに追加の許可を与えることができます。

8.3.1. 認可プロセス

UMAでは、クライアントがUMAで保護されたリソースサーバーにアクセスしようとすると、認可プロセスが開始されます。

UMAで保護されたリソースサーバーは、トークンがRPTであるリクエスト内のベアラートークンを想定しています。クライアントがパーミッション・チケットなしでリソースサーバーにリソースを要求すると、次のようになります。

クライアントは、RPTを送信せずに保護されたリソースを要求します
curl -X GET \
  http://${host}:8080/my-resource-server/resource/1bfdfe78-a4e1-4c2d-b142-fc92b75b986f

リソースサーバーは、RPTを取得するためにチケットが送られるべきKeycloakサーバーの場所とともに、パーミッション ticketas_uri パラメーターを持つレスポンスをクライアントに返します。

リソースサーバーはパーミッション・チケットを返します
HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${post}/auth/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"

パーミッション・チケットは、Keycloak Permission APIによって発行される特別なタイプのトークンです。これらは、要求されるパーミッション(例えば、リソースおよびスコープ)、ならびにリクエストに関連する他の情報を表します。リソースサーバーのみがこれらのトークンを作成できます。

クライアントはパーミッション・チケットとともにKeycloakサーバーの場所も持っているので、クライアントはディスカバリー文書を使用してトークン・エンドポイントの場所を取得し、認可リクエストを送信できます。

クライアントは、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}

$Keycloakの評価プロセスの結果、パーミッションが発行されると、そのパーミッションに関連付けられているRPTが発行されます。

KeycloakはRPTを使用してクライアントに応答します
HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}

サーバーからのレスポンスは、他のグラントタイプを使用しているときのトークン・エンドポイントからの任意のレスポンスとまったく同じです。RPTは access_token レスポンス・パラメーターから取得できます。パーミッションを得るためにクライアントが認可されていない場合、Keycloakは次のように 403 HTTPステータスコードで応答します。

Keycloakの認可リクエストの拒否
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

8.3.2. パーミッション・リクエストの送信

認可プロセスの一環として、クライアントはKeycloakトークン・エンドポイントでRPTと交換するために、まずUMAで保護されたリソースサーバーからパーミッション・チケットを取得する必要があります。

クライアントがRPTを発行できない場合、デフォルトでKeycloakは 403 HTTPステータスコードと request_denied エラーで応答します。

Keycloakの認可リクエストの拒否
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

このようなレスポンスは、Keycloakがパーミッション・チケットによって表されるパーミッションを持つRPTを発行できないことを意味します。

状況によっては、クライアント・アプリケーションが非同期認可フローを開始して、要求されているリソースオーナーにアクセスを許可するかどうかを決定させたい場合があります。そのために、次のようにクライアントは submit_request リクエスト・パラメーターをトークン・エンドポイントへの認可リクエストとともに使用できます。

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"

submit_request パラメーターを使用すると、Keycloakは、アクセスが拒否された各リソースに対して、パーミッション・リクエストを永続化します。作成されると、リソースオーナーは自分のアカウントを確認し、パーミッション・リクエストを管理できます。

この機能は、アプリケーション内の Request Access ボタンとして考えることができます。このボタンは、ユーザーが他のユーザーにリソースへのアクセスを求めることを可能にします。

8.3.3. ユーザーリソースへのアクセスの管理

Users can manage access to their resources using the Keycloak User Account Service. To enable this functionality, you must first enable User-Managed Access for your realm. To do so, open the realm settings page in Keycloak Administration Console and enable the User-Managed Access switch.

My Resources

左側のメニューで、 My Resources オプションを選択すると、ユーザーは次のことができます。

  • Need my approval パーミッション・リクエストの管理

    このセクションには、承認待ちのすべてのパーミッション・リクエストの一覧が含まれています。これらのリクエストは、特定のリソースへのアクセスを要求している当事者(ユーザー)に接続されています。ユーザーはこれらのリクエストを承認または拒否することができます。

  • My resources の管理

    このセクションには、ユーザーが所有するすべてのリソースのリストが含まれています。ユーザーはリソースをクリックして詳細を表示したり、リソースを他のユーザーと共有することができます。

  • Resources shared with me の管理

    このセクションには、ユーザーと共有するすべてのリソースのリストが含まれています。

  • Your requests waiting approval の管理

    このセクションには、別のユーザーまたはリソースオーナーの承認を待っている、ユーザーから送信されたパーミッション・リクエストの一覧が含まれています。

ユーザーが "My resources" のリスト内の任意のリソースをクリックして自分のリソースの詳細を選択すると、次のようにページにリダイレクトされます。

Resource Detail

このページから、ユーザーは以下を行うことができます。

  • People with access to the resource の管理

    このセクションには、リソースにアクセスできるユーザーのリストが含まれています。 ユーザーは、 Revoke ボタンをクリックするか、特定の Permission を削除することによって、アクセスを取り消すことができます。

  • 他の人とリソースを共有する

    別のユーザーのユーザー名または電子メールを入力することにより、ユーザーはリソースを共有し、アクセスを許可するパーミッションを選択することができます。

8.4. Protection API

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

  • リソース管理

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

  • パーミッション管理

    UMAプロトコルでは、リソースサーバーはこのエンドポイントにアクセスしてパーミッション・チケットを作成します。Keycloakには、パーミッションの状態やクエリー・パーミッションを管理するためのエンドポイントも用意されています。

  • Policy API

    Keycloak leverages the UMA Protection API to allow resource servers to manage permissions for their users. In addition to the Resource and Permission APIs, Keycloak provides a Policy API from where permissions can be set to resources by resource servers on behalf of their users.

このAPIの重要な要件は、Protection 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.4.2. リソースの管理

リソースサーバーは、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 を参照してください。

Creating a Resource

To create a resource you must send an HTTP POST request as follows:

curl -v -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Tweedl Social Service",
     "type":"http://www.example.com/rsrcs/socialstream/140-compatible",
     "icon_uri":"http://www.example.com/icons/sharesocial.png",
     "resource_scopes":[
         "read-public",
         "post-updates",
         "read-private",
         "http://www.example.com/scopes/all"
      ]
  }'

By default, the owner of a resource is the resource server. If you want to define a different owner, such as an specific user, you can send a request as follows:

curl -v -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Alice Resource",
     "owner": "alice"
  }'

Where the property owner can be set with the username or the identifier of the user.

Creating User-Managed Resources

By default, resources created via Protection API can not be managed by resource owners through the User Account Service.

To create resources and allow resource owners to manage these resources, you must set ownerManagedAccess property as follows:

curl -v -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Alice Resource",
     "owner": "alice",
     "ownerManagedAccess": true
  }'
Updating Resources

To update an existing resource, send an HTTP PUT request as follows:

curl -v -X PUT \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "_id": "Alice Resource",
     "name":"Alice Resource",
     "resource_scopes": [
        "read"
     ]
  }'
Deleting Resources

To delete an existing resource, send an HTTP DELETE request as follows:

curl -v -X DELETE \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
  -H 'Authorization: Bearer '$pat
Querying Resources

To query the resources by id, send an HTTP GET request as follows:

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

To query resources given a name, send an HTTP GET request as follows:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?name=Alice
Resource

To query resources given an uri, send an HTTP GET request as follows:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?uri=/api/alice

To query resources given an owner, send an HTTP GET request as follows:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?owner=alice

To query resources given an type, send an HTTP GET request as follows:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?type=albums

To query resources given an scope, send an HTTP GET request as follows:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?scope=read

When querying the server for permissions use parameters first and max results to limit the result.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Creating Permission Ticket

To create a permission ticket, send an HTTP POST request as follows:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "resource_id": "{resource_id}",
    "resource_scopes": [
      "view"
    ]
  }
]'

When creating tickets you can also push arbitrary claims and associate these claims with the ticket:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "resource_id": "{resource_id}",
    "resource_scopes": [
      "view"
    ],
    "claims": {
        "organization": ["acme"]
    }
  }
]'

Where these claims will be available to your policies when evaluating permissions for the resource and scope(s) associated with the permission ticket.

8.4.4. Managing Resource Permissions using the Policy API

Keycloak leverages the UMA Protection API to allow resource servers to manage permissions for their users. In addition to the Resource and Permission APIs, Keycloak provides a Policy API from where permissions can be set to resources by resource servers on behalf of their users.

The Policy API is available at:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/uma-policy/{resource_id}

This API is protected by a bearer token that must represent a consent granted by the user to the resource server to manage permissions on his behalf. The bearer token can be a regular access token obtained from the token endpoint using:

  • Resource Owner Password Credentials Grant Type

  • Token Exchange, in order to exchange an access token granted to some client (public client) for a token where audience is the resource server

Associating a Permission with a Resource

To associate a permission with a specific resource you must send a HTTP POST request as follows:

curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "roles": ["people-manager"]
}'

In the example above we are creating and associating a new permission to a resource represented by resource_id where any user with a role people-manager should be granted with the read scope.

You can also create policies using other access control mechanisms, such as using groups:

curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "groups": ["/Managers/People Managers"]
}'

Or a specific client:

curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "clients": ["my-client"]
}'

Or even using a custom policy using JavaScript:

curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "condition": "if (isPeopleManager()) {$evaluation.grant()}"
}'

It is also possible to set any combination of these access control mechanisms.

To update an existing permission, send an HTTP PUT request as follows:

curl -X PUT \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{permission_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "21eb3fed-02d7-4b5a-9102-29f3f09b6de2",
    "name": "Any people manager",
    "description": "Allow access to any people manager",
    "type": "uma",
    "scopes": [
        "album:view"
    ],
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "owner": "7e22131a-aa57-4f5f-b1db-6e82babcd322",
    "roles": [
        "user"
    ]
}'
Removing a Permission

To remove a permission associated with a resource, send an HTTP DELETE request as follows:

curl -X DELETE \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{permission_id} \
  -H 'Authorization: Bearer '$access_token
Querying Permission

To query the permissions associated with a resource, send an HTTP GET request as follows:

http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy?resource={resource_id}

To query the permissions given its name, send an HTTP GET request as follows:

http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy?name=Any
people manager

To query the permissions associated with a specific scope, send an HTTP GET request as follows:

http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy?scope=read

To query all permissions, send an HTTP GET request as follows:

http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy

When querying the server for permissions use parameters first and max results to limit the result.

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

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 クレームから、サーバーによって与えられる全てのパーミッションを取得できます。

Also note that permissions are directly related with the resources/scopes you are protecting and completely decoupled from the access control methods that were used to actually grant and issue these same permissions.

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

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

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

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

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

8.5.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.5.3. RPTをイントロスペクションするたびにサーバーを呼び出す必要がありますか?

いいえ。RPTは、Keycloakサーバーが発行する通常のアクセストークンと同様に、デフォルトフォーマットとして JSON web token(JWT) の仕様を使用します。

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

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

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

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

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

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

これは、トークン・エンドポイント、リソースエンドポイント、およびパーミッション管理エンドポイントなど、サーバーが提供するさまざまなエンドポイントに、アクセスするリソースサーバーを対象としています。

8.6.1. Maven依存関係

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

8.6.2. 設定

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

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

    レルムの名前。

  • auth-server-url (必須)

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

  • resource (必須)

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

  • credentials (必須)

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

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

8.6.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.6.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.6.5. Protection 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.6.6. 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の概要

PEPは、保護されたリソースに関連するポリシーを評価することによって、これらの決定が行われるKeycloakサーバーからのアクセス決定を強制する責任があります。これらの決定によって与えられたパーミッションに基づいて、保護されたリソースへの特定の要求が満たされているかどうかをチェックするために、アプリケーションのフィルターまたはインターセプターとして機能します。

Permissions are enforced depending on the protocol you are using. When using UMA, the policy enforcer always expects an RPT as a bearer token in order to decide whether or not a request can be served. That means clients should first obtain an RPT from Keycloak before sending requests to the resource server.

However, if you are not using UMA, you can also send regular access tokens to the resource server. In this case, the policy enforcer will try to obtain permissions directly from the server.

Keycloak OIDCアダプターのいずれかを使用している場合は、 keycloak.json ファイルに次のプロパティーを追加することで簡単にポリシー・エンフォーサーを有効にできます。

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

ポリシー・エンフォーサーを有効にすると、アプリケーションに送信されたすべてのリクエストはインターセプトされ、リクエストしているアイデンティティーにKeycloakが付与したパーミッションに応じて、保護されたリソースへのアクセスが許可されます。

ポリシー適用は、アプリケーションのパスと、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

    Specifies the configuration options that define how policies are actually enforced and optionally the paths you want to protect. If not specified, the policy enforcer queries the server for all resources associated with the resource server being protected. In this case, you need to ensure the resources are properly configured with a URIS property that matches the paths you want to protect.

    • user-managed-access

      Specifies that the adapter uses the UMA protocol. If specified, the adapter queries the server for permission tickets and returns them to clients according to the UMA specification. If not specified, the policy enforcer will be able to enforce permissions based on regular access tokens or RPTs. In this case, before denying access to the resource when the token lacks permission, the policy enforcer will try to obtain permissions directly from the server.

    • enforcement-mode

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

      • ENFORCING

        (デフォルトモード)特定のリソースに関連付けられたポリシーがない場合でも、デフォルトでリクエストは拒否されます。

      • PERMISSIVE

        特定のリソースに関連付けられたポリシーがない場合でも、リクエストは許可されます。

      • DISABLED

        ポリシーの評価を完全に無効にし、任意のリソースへのアクセスを許可します。 enforcement-modeDISABLED のとき、アプリケーションは 認可コンテキストを介してKeycloakによって与えられたすべてのパーミッションを引き続き取得できます。

    • on-deny-redirect-to

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

    • path-cache

      ポリシー・エンフォーサーがアプリケーション内のパスとKeycloakで定義されているリソースとの間の関連性を追跡する方法を定義します。キャッシュは、パスと保護されたリソース間の関連付けをキャッシュすることによって、Keycloakサーバーへの不要なリクエストを回避するために必要です。

      • lifespan

        エントリーを期限切れにする時間をミリ秒単位で定義します。指定されていない場合、デフォルト値は 3000 です。0以下の値を設定すると、キャッシュを完全に無効にすることができます。

      • max-entries

        キャッシュに保持する必要があるエントリーの制限を定義します。指定されていない場合、デフォルト値は 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 URIS representing some paths in your application.

      • name

        The name of a resource on the server that is to be associated with a given path. When used in conjunction with a path, the policy enforcer ignores the resource’s URIS property and uses the path you provided instead. * 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

          (デフォルトモード)特定のリソースに関連付けられたポリシーがない場合でも、デフォルトでリクエストは拒否されます。

        • DISABLED

      • claim-information-point

        これらのクレームをポリシーで利用できるようにするために解決され、Keycloakサーバーにプッシュされなければならない1つ以上のクレームのセットを定義します。詳細については、請求情報ポイントを参照してください。

    • lazy-load-paths

      アプリケーションのパスに関連付けられたリソースに対して、アダプターがサーバーをフェッチする方法を指定します。trueの場合、ポリシー・エンフォーサーは、要求されているパスに従ってオンデマンド・リソースをフェッチします。配備中にサーバーからすべてのリソースを取得したくない場合( paths を指定しなかった場合)や、 paths のサブセットしか定義せず、要求に応じて他のものをフェッチしたい場合に、この設定は特に便利です。

9.2. クレーム情報ポイント

クレーム情報ポイント(CIP)は、クレームを解決し、それらのクレームをKeycloakサーバーにプッシュすることにより、ポリシーへのアクセス・コンテキストに関する詳細情報を提供します。さまざまなソースからの要求を解決するために、次のようなポリシー・エンフォーサーの設定オプションとして定義できます。

  • HTTPリクエスト(パラメーター、ヘッダー、ボディーなど)

  • 外部HTTPサービス

  • 設定で定義された静的な値

  • クレーム情報プロバイダーSPIを実装することによる他のソース

クレームをKeycloakサーバーにプッシュすると、ポリシーは、ユーザーが誰であるかだけでなく、コンテキストとコンテンツを考慮して決定を下すことができます(トランザクションに対して誰が、何を、いつ、どこで、どのような、に基づいて)。それはコンテキストベースの認可と、きめ細かい認可決定をサポートするためのランタイム情報の使用方法に関するすべてのものです。

9.2.1. HTTPリクエストからの情報の取得

HTTPリクエストからクレームを抽出する方法を示すいくつかの例を以下に示します。

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. 外部HTTPサービスからの情報の取得

外部HTTPサービスからクレームを抽出する方法を示すいくつかの例を以下に示します。

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. 静的なクレーム

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. クレーム情報プロバイダーSPI

ビルトインのプロバイダーでは要件を満たすことができない場合、異なるクレーム情報ポイントをサポートするために、開発者はクレーム情報プロバイダーSPIを使用することができます。

たとえば、新しいCIPプロバイダーを実装するには、 org.keycloak.adapters.authorization.ClaimInformationPointProviderFactoryClaimInformationPointProvider を実装し、アプリケーションのクラスパスに META-INF/services/org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory ファイルを提供する必要があります。

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);
    }
}

すべてのCIPプロバイダーは、上記の MyClaimInformationPointProviderFactory.getName メソッドで定義されている名前に関連付けられている必要があります。この名前は policy-enforcer 設定の claim-information-point セクションから実装への設定をマッピングするために使用されます。

リクエストを処理する際に、ポリシー・エンフォーサーは、MyClaimInformationPointProviderのインスタンスを取得するため、MyClaimInformationPointProviderFactory.createメソッドを呼び出します。呼び出されると、この特定のCIPプロバイダー用に定義された設定(claim-information-pointを経由)がマップとして渡されます。

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

  • UMAで保護されたリソースサーバーにアクセスする場合は、パーミッション・チケットを使用して、サーバーからパーミッションを取得します。

  • アプリケーションがアクセスしたいリソースとスコープを送信して、サーバーからパーミッションを取得します。

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

9.5.1. UMAで保護されたリソースサーバーからの認可レスポンスの処理

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

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

詳細については、UMAの認可プロセスを参照してください。

クライアントが行う必要があるのは、リソースサーバーから返された WWW-Authenticate ヘッダーからパーミッション・チケットを抽出し、ライブラリーを使用して次のように認可リクエストを送信することです。

// 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. エンタイトルメントの取得

keycloak-authz.js ライブラリーは、クライアントがアクセスしたいリソースとスコープを提供することによって、サーバーからRPTを取得するために使用できる entitlement 関数を提供します。

ユーザーがアクセス可能なすべてのリソースとスコープに対するパーミッションを持つ、RPTを取得する方法の例
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
});
特定のリソースとスコープに対するパーミッションを持つ、RPTを取得する方法の例
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. 認可リクエスト

authorizeentitlement の両方の関数は、認可リクエスト・オブジェクトを受け入れます。このオブジェクトは、次のプロパティーで設定できます。

  • permissions

    リソースとスコープを表すオブジェクトの配列。以下に例を示します。

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

    サーバーで認可リクエストをどのように処理するかを定義したプロパティーを持つオブジェクト。

    • response_include_resource_name

      リソース名をRPTのパーミッションに含めるかどうかをサーバーに示すブール値。falseの場合、リソース識別子のみが含まれます。

    • response_permissions_limit

      RPTが持つことができるパーミッションの量の限界を定義する整数N。 rpt パラメーターと一緒に使用すると、最後に要求されたN個のパーミッションだけがRPTに保持されます。

  • submit_request

    サーバーがリソースとパーミッション・チケットによって参照されるスコープへのパーミッション・リクエストを作成する必要があるかどうかを示すブール値。このパラメーターは、UMA認証プロセスの一部として ticket パラメーターとともに使用されるときにのみ有効になります。

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を有効にすること強くお勧めします。