概要

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

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

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

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

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

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

    • JavaScriptを使用

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

  • サービス・プロバイダー・インタフェース(SPI)によるカスタムACM(Access Control Mechanism)のサポート

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

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

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

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

  • セキュリティー要件の変更を反映するためには、アプリケーションのコードの大幅な変更が必要となる可能性があります。

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

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

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

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

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

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

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

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

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

アーキテクチャー

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

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

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

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

  • ポリシー決定点(PDP)

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

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

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

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

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

認可プロセス

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

  • リソースの管理

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

  • ポリシーの実施

リソースの管理

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

リソース管理の概要

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

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

リソースサーバーの概要

リソースには、Webページ、RESTFulリソース、ファイルシステム内のファイル、EJBなどがあります。それらは(JavaのClassのように)リソースのグループを表すことも、単一の具体的なリソースを表すこともできます。

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

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

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

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

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

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

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

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

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

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

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

ポリシー実施

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

PEPの概要

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

Authorization Services

認可サービスは以下の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を参照してください。

用語

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

リソースサーバー

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

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

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

リソース

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

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

スコープ

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

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

Permission

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

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

  • X CAN DO Y ON RESOURCE Z

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

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

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

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

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

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

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

  • 実行時に変更を加えます。アプリケーションは、保護されているリソースとスコープについてのみに考慮し、それらがどのように保護されるかについては考慮しません。

Policy

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

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

ポリシー・プロバイダー

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

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

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

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

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

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

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

Getting Started

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

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

Linux/Unix
$ .../bin/kc.sh start-dev --http-port 8180
Windows
> ...\bin\kc.bat start-dev --http-port 8180

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

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

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

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

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

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

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

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

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

レルムとユーザーの作成

このチュートリアルの最初のステップは、レルムとそのレルム内にユーザーを作成することです。次に、レルム内で、単一のクライアント・アプリケーションを作成します。このアプリケーションは、認可サービスを有効にする必要があるリソースサーバーになります。

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

  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. Set Password をクリックして、ユーザーのパスワードを設定します。

認可サービスの有効化

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

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

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

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

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

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

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

    クライアントの詳細

    クライアントの詳細

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

    認可の設定

    認可の設定

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

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

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

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

デプロイするアプリケーションのプロジェクトとコードは、Keycloak Quickstarts Repositoryから入手できます。続行するには、マシンに以下をインストールし、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

アダプターの設定を取得

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

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 メッセージを返すのではなく)。

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

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

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

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

アプリケーションが正常にデプロイされた場合は、 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 に変更します。これにより、デフォルトではすべてのアクセス要求が拒否されますが、そのポリシーの結果が否定されるため、アプリケーションへのアクセスが再度有効になります。再度、この変更をテストする前に、必ずログアウトして再ログインしてください。

次のステップ

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

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

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

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

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

認可のクイックスタート

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

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

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

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

app-authz-jee-servlet

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

app-authz-jee-vanilla

Jakarta 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を有効にし、ユーザーにリソースのパーミッションを管理させる方法を示します。

リソースサーバーの管理

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

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

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

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

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

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

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

    Clients

    クライアント

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

    クライアントの作成

    クライアントの作成

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

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

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

    クライアントの設定

    クライアントの設定

認可サービスの有効化

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

認可サービスの有効化

認可サービスの有効化

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

リソースサーバーの設定

リソースサーバーの設定

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

  • Settings

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

  • Resource

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

  • Authorization Scopes

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

  • Policies

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

  • Permissions

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

  • Evaluate

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

  • Export Settings

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

リソースサーバーの設定

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

  • Policy Enforcement Mode

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

    • Enforcing

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

    • Permissive

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

    • Disabled

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

  • Decision Strategy

    この設定により、評価されたすべてのパーミッションの結果に基づいて、ポリシー評価エンジンがリソースまたはスコープを許可するかどうか決定する方法が変更されます。 Affirmative とは、リソースとそのスコープへのアクセスを許可するために、少なくとも1つのパーミッションが肯定的な決定に評価される必要があることを意味します。 Unanimous とは、最終決定も肯定的であるために、すべてのパーミッションが肯定的決定に評価されなければならないことを意味します。たとえば、同じリソースまたはスコープの2つのパーミッションが競合している場合(一方がアクセスを許可し、もう一方がアクセスを拒否している場合)、選択された戦略が Affirmative であれば、リソースまたはスコープへのパーミッションが許可されます。そうでなければ、パーミッションからの単一の拒否は、リソースまたはスコープへのアクセスも拒否します。

  • Remote Resource Management

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

デフォルト設定

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

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

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

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

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

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

デフォルト・リソース

デフォルト・リソース

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

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

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

デフォルト・ポリシー

デフォルト・ポリシー

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

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

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

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

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

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

デフォルト設定の変更

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

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

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

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

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

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

  • ポリシー

  • パーミッション

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

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

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

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

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

    エクスポートの設定

    エクスポートの設定

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

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

設定ファイルをインポートするには、以下の手順を実行します。

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

    インポート設定

    Import Settings

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

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

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

リソースの表示

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

リソース

Resources

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

  • Type

  • URI

  • オーナー

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

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

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

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

リソースの作成

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

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

リソースの追加

リソースの追加

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

  • Name

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

  • Type

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

  • URIS

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

  • Scopes

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

リソース属性

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

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

タイプ付きのリソース

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

リソース・オーナー

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

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

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

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

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

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

ポリシーの管理

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

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

ポリシー

Policies

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

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

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

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

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

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

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

設定

  • Name

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

  • 説明

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

  • Users

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

  • Logic

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

ロールベース・ポリシー

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

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

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

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

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

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

設定

  • Name

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

  • 説明

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

  • Realm Roles

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

  • Client Roles

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

  • Logic

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

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

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

必須ロールの例

Example of Required Role

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

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

JavaScriptベースポリシー

以下の例のように、ポリシーの実装で属性ベースのアクセス・コントロール(ABAC)を使用している場合は、ユーザーが保護された属性を編集できず、対応する属性が読み取り専用であることを確認してください。詳細については 脅威モデルの緩和の章 を参照してください。

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

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

デフォルトでは、JavaScriptポリシーはサーバーにアップロードできません。JavaScript Providersで説明されているように、JSポリシーをサーバーに直接デプロイすることをお勧めします。それでもKeycloak管理コンソールを使用してJSポリシーを管理したい場合は、 Upload Scripts 機能を有効にする必要があります。
JavaScriptポリシーの追加

JavaScriptポリシーの追加

設定

  • Name

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

  • 説明

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

  • Code

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

  • Logic

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

デプロイされたJARファイルから取得したJSポリシーの作成

Keycloakを使用すると、JARファイルをデプロイして、サーバーにスクリプトをデプロイできます。詳細については、JavaScript Providersを参照してください。

スクリプトをデプロイしたら、利用可能なポリシー・プロバイダーのリストからデプロイしたスクリプトを選択できるようになります。

サンプル

評価コンテキストから取得した属性のチェック

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

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

if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
    $evaluation.grant();
}
現在のアイデンティティーから取得した属性のチェック

現在のアイデンティティーに関連した属性で条件を定義するために、属性ベース・アクセス・コントロール(ABAC)を使用するJavaScriptベースポリシーの簡単な例です。

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

これらの属性は、認可リクエストで使用されるトークンで定義されているクレームからマップされます。

現在のアイデンティティーに付与されているロールのチェック

ロール・ベース・アクセス・コントロール(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();
}
ユーザーに付与されているロールのチェック

ユーザーに付与されているレルムロールをチェックするには、次のようにします。

var realm = $evaluation.getRealm();

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

または、ユーザーに付与されたクライアントロールの場合は、以下のようになります。

var realm = $evaluation.getRealm();

if (realm.isUserInClientRole('marta', 'my-client', 'some-client-role')) {
    $evaluation.grant();
}
グループに付与されたロールのチェック

グループに付与されているレルムロールをチェックするには、次のようにします。

var realm = $evaluation.getRealm();

if (realm.isGroupInRole('/Group A/Group D', 'role-a')) {
    $evaluation.grant();
}
任意のクレームをリソースサーバーにプッシュする

パーミッションの強制方法に関する追加情報を提供するために、任意のクレームをリソースサーバーにプッシュするには、次のようにします。

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');
}
グループ・メンバーシップのチェック
var realm = $evaluation.getRealm();

if (realm.isUserInGroup('marta', '/Group A/Group B')) {
    $evaluation.grant();
}
異なるアクセス制御メカニズムを混在させる

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

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

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

タイムベース・ポリシー

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

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

タイムポリシーの追加

タイムポリシーの追加

設定

  • Name

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

  • 説明

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

  • Not Before

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

  • Not On or After

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

  • Day of Month

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

  • Month

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

  • Year

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

  • Hour

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

  • Minute

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

  • Logic

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

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

集約されたポリシー

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

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

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

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

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

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

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

設定

  • Name

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

  • 説明

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

  • Apply Policy

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

  • Decision Strategy

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

  • Logic

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

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

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

  • Unanimous

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

  • Affirmative

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

  • Consensus

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

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

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

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

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

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

設定

  • Name

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

  • 説明

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

  • Clients

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

  • Logic

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

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

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

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

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

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

設定

  • Name

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

  • 説明

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

  • Groups Claim

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

  • Groups

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

  • Logic

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

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

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

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

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

Extending Access to Child Groups

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

クライアント・スコープ・ベース・ポリシー

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

デフォルトでは、このポリシーに追加されたクライアント・スコープは必要に応じて指定されておらず、アクセスを要求しているクライアントにこれらのクライアントスコープのいずれかが許可されている場合、ポリシーはアクセスを許可します。ただし、特定のクライアントスコープを適用する場合は、特定のクライアントスコープをrequiredとして指定できます。

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

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

Add Client Scope-Based Policy

設定

  • Name

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

  • 説明

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

  • Client Scopes

    このポリシーによって、どのクライアント・スコープが許可されるかを指定します。

  • Logic

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

必須としてクライアント・スコープを定義する

クライアント・スコープ・ベースのポリシーを作成するときに、特定のクライアント・スコープを Required として指定できます。これを行うと、アクセスを要求しているクライアントに 全て必須 クライアント・スコープが付与されている場合にのみ、ポリシーはアクセスを許可します。

必須クライアント・スコープの例

Example of Required Client Scope

クライアント・スコープを必須と指定するには、そのクライアント・スコープの Required チェックボックスをチェックします。

必須のクライアント・スコープは、ポリシーで複数のクライアント・スコープが定義されているが、それらのサブセットのみが必須である場合に役立ちます。

正規表現ベースのポリシー

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

新しい正規表現ベースのポリシーを作成するには、ポリシー一覧の右上にある項目リストで Regex を選択します。

正規表現ベースのポリシーの追加

Add Regex-Based Policy

設定

  • Name

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

  • 説明

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

  • Target Claim

    トークン内の対象クレームの名称を指定します。

  • Regex Pattern

    正規表現パターンを指定します。

  • Logic

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

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

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

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

Policy Evaluation API

JavaScriptを使用してルールベースのポリシーを作成する場合、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 を参照してください。

評価コンテキスト

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

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. 実行属性およびランタイム属性
名前 説明 Type

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

パーミッションの管理

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

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

パーミッション

権限

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

  • Resources

  • Scopes

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

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

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

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

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

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

設定

  • Name

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

  • 説明

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

  • Apply To Resource Type

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

    • Resource Type

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

  • Resources

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

  • Apply Policy

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

  • Decision Strategy

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

設定

  • Name

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

  • 説明

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

  • Resource

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

  • Scopes

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

  • Apply Policy

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

  • Decision Strategy

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

ポリシー決定戦略

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

  • Unanimous

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

  • Affirmative

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

  • Consensus

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

ポリシーの評価とテスト

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

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

ポリシー評価ツール

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

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

コンテキスト情報の提供

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

パーミッションの提供

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

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

Authorization Services

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

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

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

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

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

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

curl -X GET \
  http://${host}:${port}/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}:${port}/realms/${realm}/protocol/openid-connect/token",
    "token_introspection_endpoint": "http://${host}:${port}/realms/${realm}/protocol/openid-connect/token/introspect",
    "resource_registration_endpoint": "http://${host}:${port}/realms/${realm}/authz/protection/resource_set",
    "permission_endpoint": "http://${host}:${port}/realms/${realm}/authz/protection/permission",
    "policy_endpoint": "http://${host}:${port}/realms/${realm}/authz/protection/uma-policy"
}

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

  • token_endpoint

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

  • token_introspection_endpoint

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

  • resource_registration_endpoint

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

  • permission_endpoint

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

パーミッションの取得

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

    このパラメーターは optional です。 claim_token パラメーターで指定されたトークンの形式を示す文字列です。Keycloakは urn:ietf:params:oauth:token-type:jwthttps://openid.net/specs/openid-connect-core-1_0.html#IDToken の2つのトークン形式をサポートしています。 urn:ietf:params:oauth:token-type:jwt 形式は、 claim_token パラメーターがアクセストークンを参照することを示します。 https://openid.net/specs/openid-connect-core-1_0.html#IDToken は、 claim_token パラメーターがOpenID ConnectのIDトークンを参照することを示します。

  • 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

    このパラメーターは optional です。サーバーが認可リクエストにどのように応答するかを示す文字列値。このパラメーターは、標準的なOAuth2レスポンスではなく、サーバーによって付与された全体的な決定またはパーミッションに主に関心がある場合に特に便利です。可能な値は次のとおりです。

    • decision

      サーバーからの応答は、次の形式でJSONを返すことによって、全体の決定のみを表すことを示します。

      {
          'result': true
      }

      認可リクエストがどのパーミッションにもマッピングされない場合、代わりに 403 HTTPステータスコードが返されます。

    • permissions

      サーバーからの応答は、次の形式でJSONを返すことによって、サーバーにより付与されたパーミッションが含まれていることを示します。

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

      認可リクエストがどのパーミッションにもマッピングされない場合、代わりに 403 HTTPステータスコードが返されます。

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

curl -X POST \
  http://${host}:${port}/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}/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}/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"
}

クライアントの認証方式

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

  • Bearer Token

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

    例:アクセストークンを使用してトークン・エンドポイントで認証する認可リクエスト
    curl -X POST \
      http://${host}:${port}/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がアクセス権を持つリソース及びスコープに応じてパーミッションが与えられます。

  • Client Credentials

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

    例:クライアントIDとクライアント・シークレットを使用して、トークン・エンドポイントで認証する認可リクエスト
    curl -X POST \
      http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
      -H "Authorization: Basic cGhvdGg6L7Jl13RmfWgtkk==pOnNlY3JldA==" \
      --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"

クレームのプッシュ

サーバーからパーミッションを取得する際に、パーミッションの評価においてクレームをポリシーで利用できるようにするために、任意のクレームをプッシュできます。

パーミッション・チケットを使用 せずに サーバーからパーミッションを取得している場合(UMAフロー)、次のようにトークン・エンドポイントに認可リクエストを送信できます。

curl -X POST \
  http://${host}:${port}/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}"

claim_token パラメーターは、以下の例のような形式のBASE64でエンコードされたJSONを期待します。

{
    "organization" : ["acme"]
}

この形式では、1つ以上のクレームを想定しており、各クレームの値は文字列型の配列である必要があります。

UMAを使用したクレームのプッシュ

UMAとパーミッション・チケットを使用してクレームをプッシュする方法の詳細については、Permission APIを参照してください。

User-Managed Access

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

  • Privacy

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

  • Party-to-Party Authorization

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

  • Resource Sharing

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

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

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

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

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

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

認可プロセス

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

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

クライアントは、RPTを送信せずに保護されたリソースを要求します
curl -X GET \
  http://${host}:${port}/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}:${port}/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"

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

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

クライアントは、RPTを取得するためにトークン・エンドポイントに認可リクエストを送信します
curl -X POST \
  http://${host}:${port}/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"
}

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

認可プロセスの一環として、クライアントは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}/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 ボタンとして考えることができます。このボタンは、ユーザーが他のユーザーにリソースへのアクセスを求めることを可能にします。

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

ユーザーは、Keycloakユーザー・アカウント・サービスを使用して、リソースへのアクセスを管理できます。この機能を有効にするには、まず、レルムのUser-Managed Accessを有効にする必要があります。これを行うには、Keycloak管理コンソールでレルム設定ページを開き、User-Managed Accessスイッチを有効にします。

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 this resource の管理

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

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

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

Protection API

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

  • リソースの管理

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

  • パーミッションの管理

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

  • Policy API

    KeycloakはUMA Protection APIを利用して、リソースサーバーがユーザーのパーミッションを管理できるようにします。KeycloakはリソースAPIとパーミッションAPIに加えて、ユーザーの代わりにリソースサーバーによって、リソースにパーミッションを設定できるPolicy APIを提供します。

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

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

Protection 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/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 が必要です。サポートされている認証方法の使用を選択することができます。

リソースの管理

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

http://${host}:${port}/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 を参照してください。

リソースの作成

リソースを作成するには、次のようにHTTP POSTリクエストを送信する必要があります。

curl -v -X POST \
  http://${host}:${port}/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"
      ]
  }'

デフォルトでは、リソースオーナーがリソースサーバーです。特定のユーザーなど、別のオーナーを定義する場合は、次のようにリクエストを送信できます。

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

ここで、プロパティー owner はユーザーのユーザー名または識別子で設定できます。

ユーザー管理のリソースの作成

デフォルトでは、Protection API経由で作成されたリソースを、リソースオーナーがユーザー・アカウント・サービスを介して管理することはできません。

リソースを作成し、リソースオーナーがこれらのリソースを管理できるようにするには、次のように ownerManagedAccess プロパティーを設定する必要があります。

curl -v -X POST \
  http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Alice Resource",
     "owner": "alice",
     "ownerManagedAccess": true
  }'
リソースの更新

既存のリソースを更新するには、次のようにHTTP PUTリクエストを送信します。

curl -v -X PUT \
  http://${host}:${port}/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"
     ]
  }'
リソースの削除

既存のリソースを削除するには、次のようにHTTP DELETEリクエストを送信します。

curl -v -X DELETE \
  http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
  -H 'Authorization: Bearer '$pat
リソースの照会

id でリソースを照会するには、次のようにHTTP GETリクエストを送信します。

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

name を指定してリソースを照会するには、次のようにHTTP GETリクエストを送信します。

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

デフォルトでは、 name フィルターは指定されたパターンのすべてのリソースと一致します。完全に一致するリソースのみを返すようにクエリーを制限するには、次を使用します。

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

uri を指定してリソースを照会するには、次のようにHTTP GETリクエストを送信します。

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

owner を指定してリソースを照会するには、次のようにHTTP GETリクエストを送信します。

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

type を指定してリソースを照会するには、次のようにHTTP GETリクエストを送信します。

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

scope を指定してリソースを照会するには、次のようにHTTP GETリクエストを送信します。

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

サーバーにパーミッションを問い合わせる際に、結果を制限するためにパラメーター firstmax を使用します。

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

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

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

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

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

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

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

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

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

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

クライアントから見ると、パーミッション・チケットには重要な側面もあります。

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

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

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

パーミッション・チケットを作成する

パーミッション・チケットを作成するには、次のようにHTTP POSTリクエストを送信します。

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

チケットを作成するときは、任意のクレームをプッシュして、これらのクレームをチケットに関連付けることもできます。

curl -X POST \
  http://${host}:${port}/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"]
    }
  }
]'

ここで、パーミッション・チケットに関連付けられているリソースおよびスコープのパーミッションを評価する際に、これらのクレームをポリシーで利用できます。

その他のUMA非準拠エンドポイント
パーミッション・チケットを作成する

ID {resource_id} の特定のリソースに対するパーミッションをID {user_id} のユーザーに付与するには、リソースの所有者として次のようにHTTP POSTリクエストを送信します。

curl -X POST \
     http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket \
     -H 'Authorization: Bearer '$access_token \
     -H 'Content-Type: application/json' \
     -d '{
       "resource": "{resource_id}",
       "requester": "{user_id}",
       "granted": true,
       "scopeName": "view"
     }'
パーミッション・チケットを取得する
curl http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket \
     -H 'Authorization: Bearer '$access_token

次のクエリー・パラメーターはどれでも使用できます。

  • scopeId

  • resourceId

  • owner

  • requester

  • granted

  • returnNames

  • first

  • max

パーミッション・チケットを更新する
curl -X PUT \
     http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket \
     -H 'Authorization: Bearer '$access_token \
     -H 'Content-Type: application/json' \
     -d '{
       "id": "{ticket_id}"
       "resource": "{resource_id}",
       "requester": "{user_id}",
       "granted": false,
       "scopeName": "view"
     }'
パーミッション・チケットを削除する
curl -X DELETE http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket/{ticket_id} \
     -H 'Authorization: Bearer '$access_token

Policy APIを使用したリソース・パーミッションの管理

KeycloakはUMA Protection APIを利用して、リソースサーバーがユーザーのパーミッションを管理できるようにします。KeycloakはリソースAPIとパーミッションAPIに加えて、ユーザーの代わりにリソースサーバーによって、リソースにパーミッションを設定できるPolicy APIを提供します。

Policy APIは次の場所にあります。

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

このAPIは、ユーザーからリソースサーバーへの承諾を表すベアラトークンによって保護されています。ベアラトークンは、以下を使用することで、トークン・エンドポイントから取得された通常のアクセストークンとすることができます。

  • リソース・オーナー・パスワード・クレデンシャル・グラント・タイプ

  • Audienceがリソースサーバーであるトークンのために、あるクライアント(パブリック・クライアント)に与えられたアクセストークンを交換するためのToken Exchange

パーミッションとリソースの関連付け

パーミッションを特定のリソースに関連付けるには、次のようにHTTP POSTリクエストを送信する必要があります。

curl -X POST \
  http://localhost:8180/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"]
}'

上記の例では、 people-manager ロールを持つユーザに対して read スコープを付与するように、 resource_id で表されるリソースに新しいパーミッションを作成して関連付けています。

次のようにグループを使用するなど、他のアクセス・コントロールの機構を使用してポリシーを作成することもできます。

curl -X POST \
  http://localhost:8180/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"]
}'

または、次のように特定のクライアントを使用できます。

curl -X POST \
  http://localhost:8180/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"]
}'

あるいは、次のようにJavaScriptを使用してカスタムポリシーを使用することもできます。

Upload Scriptsは 非推奨 であり、将来のリリースで削除されます。この機能はデフォルトで無効になっています。

有効にするには、 -Dkeycloak.profile.feature.upload_scripts=enabled でサーバーを起動します。詳細はProfilesを参照してください。

curl -X POST \
  http://localhost:8180/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()}"
}'

これらのアクセス・コントロール機構を任意に組み合わせて設定することもできます。

既存のパーミッションを更新するには、次のようにHTTP PUTリクエストを送信します。

curl -X PUT \
  http://localhost:8180/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"
    ]
}'
パーミッションの削除

リソースに関連付けられているパーミッションを削除するには、次のようにHTTP DELETEリクエストを送信します。

curl -X DELETE \
  http://localhost:8180/realms/photoz/authz/protection/uma-policy/{permission_id} \
  -H 'Authorization: Bearer '$access_token
パーミッションの問い合わせ

リソースに関連付けられているパーミッションを参照するには、次のようにHTTP GETリクエストを送信します。

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

名前でパーミッションを参照するには、次のようにHTTP GETリクエストを送信します。

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

特定のスコープに関連付けられているパーミッションを参照するには、次のようにHTTP GETリクエストを送信します。

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

すべてのパーミッションを参照するには、次のようにHTTP GETリクエストを送信します。

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

サーバーにパーミッションを問い合わせる際に、結果を制限するためにパラメーター firstmax を使用します。

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

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

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

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

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

トークン・イントロスペクションが役立つ2つの主なユースケースがあります。

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

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

RPTに関する情報の取得

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

http://${host}:${port}/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/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
}

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

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

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

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

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

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

認可クライアントJava API

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

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

Maven依存関係

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

設定

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

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

    レルムの名前。

  • auth-server-url (required)

    The base URL of the Keycloak server. All other Keycloak pages and REST service endpoints are derived from this. It is usually in the form https://host:port.

  • resource (required)

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

  • credentials (required)

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

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

認可クライアントの作成

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

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

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

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

// create a new instance based on the configuration defined in keycloak.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.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

Protection APIを使用したリソースの作成

// create a new instance based on the configuration defined in keycloak.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);

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

// create a new instance based on the configuration defined in keycloak.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);
}

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

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

PEPの概要

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

パーミッションは、使用しているプロトコルによって異なります。UMAを使用する場合、ポリシー・エンフォーサーは、リクエストを処理できるかどうかを決定するために、RPTをベアラートークンとして常に想定しています。つまり、クライアントは、リソースサーバーにリクエストを送信する前に、まずKeycloakからRPTを取得する必要があります。

ただし、UMAを使用していない場合は、通常のアクセストークンをリソースサーバーに送信することもできます。この場合、ポリシー・エンフォーサーはサーバーから直接パーミッションを取得しようとします。

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

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

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

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

設定

アプリケーションのポリシー適用を有効にするには、 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

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

    • user-managed-access

      アダプターがUMAプロトコルを使用することを指定します。指定されている場合、アダプターはサーバーにパーミッション・チケットを問い合わせ、UMA仕様に従ってクライアントに戻します。指定されていない場合、ポリシー・エンフォーサーは、通常のアクセストークンまたはRPTに基づいて、パーミッションを適用できます。この場合、トークンにパーミッションがないときは、リソースへのアクセスを拒否する前に、ポリシー・エンフォーサーはサーバーから直接パーミッションを取得しようとします。

    • enforcement-mode

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

      • ENFORCING

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

      • PERMISSIVE

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

      • DISABLED

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

    • on-deny-redirect-to

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

    • path-cache

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

      • lifespan

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

      • max-entries

        キャッシュに保持する必要があるエントリーの制限を定義します。指定されていない場合、デフォルト値は 1000 です。

    • paths

      保護するパスを指定します。この設定はオプションです。定義されていない場合、ポリシー・エンフォーサーはKeycloakでアプリケーションに定義したリソースをフェッチすることによってすべてのパスを検出します。これらのリソースは、アプリケーションのパスを表す URIS で定義されます。

      • name

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

      • path

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

        • ワイルドカード: /*

        • サフィックス: /*.html

        • サブパス: /path/*

        • パスパラメーター:/resource/{id}

        • 完全一致:/resource

        • パターン:/{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つ以上のクレームのセットを定義します。詳細については、Claim Information Pointを参照してください。

    • lazy-load-paths

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

    • http-method-as-scope

      スコープをHTTPメソッドにマッピングする方法を指定します。 true に設定されている場合、ポリシー・エンフォーサーは現在のリクエストからのHTTPメソッドを使用して、アクセスを許可する必要があるかどうかをチェックします。有効になっている場合は、Keycloakのリソースが保護している各HTTPメソッドを表すスコープに関連付けられていることを確認してください。

    • claim-information-point

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

クレーム情報ポイント

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

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

  • 外部HTTPサービス

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

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

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

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']} "
          }
        }
      }
    ]
  }

外部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']}"
            }
          }
        }
      }
    ]
  }

静的なクレーム

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"],
          }
        }
      }
    ]
  }

クレーム情報プロバイダー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 MyClaimInformationPointProvider(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;
    }
}

認可コンテキストの取得

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

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

    HttpServletRequest request = ... // obtain 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 に関連するパーミッションとポリシーが変更されます。

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

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

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

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

JavaScriptの統合

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

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

<script src="http://.../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認可サービスの両方との対話を容易にし、クライアントがリソースサーバー上の保護されたリソースにアクセスするベアラー・トークンとして使用できる権限を持つトークンを取得できます。

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

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

HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${port}/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をリトライのためのベアラー・トークンとして含める必要があります。

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

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引数。サーバーが予期せず応答する場合にのみ呼び出されます。

認可リクエスト

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 パラメーターとともに使用されるときにのみ有効になります。

RPTの取得

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

var rpt = authorization.rpt;

TLS/HTTPSの設定

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

keycloak.json
{
  "truststore": "path_to_your_trust_store",
  "truststore-password": "trust_store_password"
}

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

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