1. 概要

Keycloakは、OpenID Connect(OAuth 2.0 への拡張機能)とSAML 2.0の両方をサポートしています。クライアントとサービスをセキュリティー保護する際に最初に決定すべきことは、どちらを使用するのかということです。必要に応じて、一部をOpenID Connectで、それ以外をSAMLでセキュリティー保護することも選択できます。

クライアントとサービスをセキュリティー保護するためには、選択したプロトコルに対応するアダプターやライブラリーも必要になります。Keycloakには選択したプラットフォームに対応する独自のアダプターが付属していますが、一般的なOpenID Connectのリソース・プロバイダーやSAMLのサービス・プロバイダーのライブラリーを使用することもできます。

1.1. クライアント・アダプターとは?

Keycloakのクライアント・アダプターは、Keycloakとともに使用してアプリケーションとサービスを非常に簡単にセキュリティー保護できるライブラリーです。基盤となるプラットフォームやフレームワークとのタイトな統合を提供するので、ライブラリーではなく、アダプターと呼んでいます。このような考え方により、アダプターは使いやすく、一般的にライブラリーが必要とするよりも定型コードが少なくて済みます。

1.2. サポートされているプラットフォーム

1.2.1. OpenID Connect

JavaScript(クライアントサイド)
Node.js(サーバーサイド)

1.2.2. C#

1.2.3. Python

1.2.4. Android

1.2.5. iOS

Apache HTTP Server

1.2.6. SAML

Apache HTTP Server

1.3. サポートされているプロトコル

1.3.1. OpenID Connect

OpenID Connect(OIDC)はOAuth 2.0を拡張した認証プロトコルです。OAuth 2.0が認可プロトコルのみを構築するためのフレームワークで、不完全であるのに対し、OIDCは完成された認証および認可のプロトコルです。OIDCはまた、Json Web Token(JWT)の標準セットを多用します。これらの標準は、コンパクトでwebフレンドリーな方法で、アイデンティティー・トークンのJSON形式とデジタル署名、データ暗号化の方法を定義します。

OIDCを使用するユースケースは、実際には2つの種類があります。1つ目は、Keycloakサーバーにユーザーの認証を要求するアプリケーションのユースケースです。ログインが成功すると、アプリケーションは identity tokenaccess token を受け取ります。 Identity token には、ユーザー名、電子メール、その他のプロファイル情報など、ユーザーに関する情報が含まれています。 Access token はレルムによってデジタル署名されており、アプリケーションがユーザーのアクセス可能なリソースを決定するために使用できるアクセス情報(ユーザー・ロール・マッピングのような)が含まれています。

2つ目のタイプは、リモートサービスへのアクセス権を取得したいクライアントのユースケースです。この場合、クライアントは、ユーザーの代理として他のリモートサービスの呼び出しに使用できる アクセストークン の取得をKeycloakに要求します。Keycloakは、ユーザーを認証し、クライアントのアクセスを許可する同意を要求します。そして、クライアントは アクセストークン を受け取ります。この アクセストークン はレルムによってデジタル署名されます。クライアントはこの アクセストークン を使用して、リモートサービスのREST呼び出しを行うことができます。REST サービスは アクセストークン を抽出し、トークンの署名を検証し、トークン内のアクセス情報に基づいて、リクエストを処理するかどうかを決定します。

1.3.2. SAML 2.0

SAML 2.0は、OIDCに似ていますが、それよりも古く成熟した仕様です。SOAPと過多なWS-*の仕様をそのルーツを持っているため、OIDCよりも少し冗長になる傾向があります。SAML 2.0は、主に認証サーバーとアプリケーション間のXMLドキュメントの交換によって動作する認証プロトコルです。XML署名と暗号化を使用して、リクエストとレスポンスを検証します。

Keycloakでは、SAMLはブラウザー・アプリケーションとREST呼び出しの2種類のユースケースを提供しています 。

SAMLを使用するユースケースは、実際には2つの種類があります。1つ目は、Keycloakサーバーにユーザーの認証を要求するアプリケーションのユースケースです。ログインが成功すると、アプリケーションは ユーザーに関する様々な属性を指定するSAMLアサーションと呼ばれるものが含まれるXMLドキュメントを受け取ります。このXMLドキュメントはレルムによってデジタル署名されており、アプリケーションがユーザーのアクセス可能なリソースを決定するために使用できるアクセス情報(ユーザー・ロール・マッピングなど)が含まれています。

2つ目のタイプは、リモートサービスへのアクセス権を取得したいクライアントのユースケースです。この場合、クライアントは、ユーザーの代理として他のリモートサービスの呼び出しに使用できるSAMLアサーションの取得をKeycloakに要求します。

1.3.3. OpenID Connect vs SAML

OpenID ConnectとSAMLの選択は、古いより成熟したプロトコル(SAML)の代わりに新しいプロトコル(OIDC)を使用するだけの問題ではありません。

ほとんどの場合において、KeycloakではOIDCを使用することをお勧めします。

SAMLは、OIDCよりも少し冗長になる傾向があります。

交換するデータの詳細度を度外視して仕様を比較した場合、OIDCはもともとWebで動作するように設計されていますが、SAMLはWeb上で動作するように改造されていることが分かります。たとえば、OIDCはSAMLよりもクライアントサイドに実装することが簡単なため、HTML5/JavaScriptアプリケーションにも適しています。トークンはJSON形式なので、JavaScriptにより簡単に扱うことができます。また、Webアプリケーションに対してセキュリティーの実装を容易にする、いくつかの素晴らしい機能があります。たとえば、ユーザーがログインしているかどうかを容易に判断するために使用するiframeトリックの仕様をチェックしてください。

SAMLにも用途はあります。OIDCの仕様の進化を見ると、SAMLが長年に渡って実装してきた多数の機能がOIDCにも実装されていることが分かります。SAMLがOIDCより成熟しているという認識と、SAMLによりセキュリティー保護されている既存のアプリケーションが存在するという理由により、OIDCよりもSAMLが選ばれることは多々あります。

2. OpenID Connect

このセクションでは、Keycloakアダプターまたは汎用OpenID Connectリソース・プロバイダーのライブラリーを使用して、アプリケーションとサービスをOpenID Connectでセキュリティー保護する方法について説明します。

2.1. Javaアダプター

Keycloakには、Javaアプリケーション用のさまざまなアダプターが付属しています。正しいアダプターの選択は、対象のプラットフォームによって異なります。

全てのJavaアダプターは、Javaアダプターの設定の章で説明されている共通の設定オプションのセットを共有しています。

2.1.1. Javaアダプターの設定

Keycloakでサポートされている各Javaアダプターは、単純なJSONファイルで設定できます。これは、次のようになります。

{
  "realm" : "demo",
  "resource" : "customer-portal",
  "realm-public-key" : "MIGfMA0GCSqGSIb3D...31LwIDAQAB",
  "auth-server-url" : "https://localhost:8443/auth",
  "ssl-required" : "external",
  "use-resource-role-mappings" : false,
  "enable-cors" : true,
  "cors-max-age" : 1000,
  "cors-allowed-methods" : "POST, PUT, DELETE, GET",
  "cors-exposed-headers" : "WWW-Authenticate, My-custom-exposed-Header",
  "bearer-only" : false,
  "enable-basic-auth" : false,
  "expose-token" : true,
   "credentials" : {
      "secret" : "234234-234234-234234"
   },

   "connection-pool-size" : 20,
   "disable-trust-manager": false,
   "allow-any-hostname" : false,
   "truststore" : "path/to/truststore.jks",
   "truststore-password" : "geheim",
   "client-keystore" : "path/to/client-keystore.jks",
   "client-keystore-password" : "geheim",
   "client-key-password" : "geheim",
   "token-minimum-time-to-live" : 10,
   "min-time-between-jwks-requests" : 10,
   "public-key-cache-ttl": 86400,
   "redirect-rewrite-rules" : {
   "^/wsmaster/api/(.*)$" : "/api/$1"
   }
}

${…​} エンクロージャーを使用して、システム・プロパティーの置換を行うことができます。たとえば、 ${jboss.server.config.dir}/path/to/Keycloak に置換できます。環境変数の置換では、 env プレフィックスもサポートされています。たとえば、 ${env.MY_ENVIRONMENT_VARIABLE} です。

初期設定ファイルは、管理コンソールから取得できます。これを行うには、管理コンソールを開き、メニューから Clients を選択し、対応するクライアントをクリックします。クライアントのページが開かれたら、 Installation タブをクリックし、 Keycloak OIDC JSON を選択します。

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

realm

レルムの名前。 これは REQUIRED です。

resource

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

realm-public-key

レルム公開鍵のPEM形式です。これは管理コンソールから取得できます。これは OPTIONAL であり、設定することはお勧めしません。これが設定されていない場合、アダプターは必要に応じて(Keycloakの鍵をローテーションさせる場合など)、Keycloakから常に再ダウンロードします。しかし、realm-public-keyが設定されている場合、アダプターはKeycloakから新しい鍵をダウンロードすることは無いので、Keycloakの鍵をローテーションするとアダプターが正常に動作しなくなります。

auth-server-url

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

ssl-required

Keycloakサーバーとの間のすべての通信がHTTPS経由であることを保証します。プロダクション環境では、これを all に設定する必要があります。これは OPTIONAL です。デフォルト値は external です。つまり、外部リクエストに対してデフォルトでHTTPSが必要です。有効な値は allexternalnone です。

confidential-port

SSL/TLS.を介した安全な接続のために、Keycloakサーバーが使用する機密ポートです。これは OPTIONAL です。デフォルト値は 8443 です。

use-resource-role-mappings

trueに設定すると、アダプターは、ユーザーのアプリケーション・レベルのロール・マッピングのトークンを調べます。falseの場合、ユーザー・ロール・マッピングのレルム・レベルを確認します。これは OPTIONAL です。デフォルト値は false です。

public-client

trueに設定すると、アダプターはクライアントのクレデンシャルをKeycloakに送信しません。これは OPTIONAL です。デフォルト値は false です。

enable-cors

これにより、CORSサポートが有効になります。CORSプリフライト・リクエストを処理します。また、アクセス・トークンを調べて、有効なオリジンを特定します。これは OPTIONAL です。デフォルト値は false です。

cors-max-age

CORSが有効な場合、これは Access-Control-Max-Age ヘッダーの値を設定します。これは OPTIONAL です。設定されていない場合、このヘッダーはCORSレスポンスで返されません。

cors-allowed-methods

CORSが有効な場合、これは Access-Control-Allow-Methods ヘッダーの値を設定します。 これはカンマ区切りの文字列でなければなりません。これは OPTIONAL です。設定されていない場合、このヘッダーはCORSレスポンスで返されません。

cors-allowed-headers

CORSが有効な場合、これは Access-Control-Allow-Headers ヘッダーの値を設定します。 これはカンマ区切りの文字列でなければなりません。これは OPTIONAL です。設定されていない場合、このヘッダーはCORSレスポンスで返されません。

cors-exposed-headers

CORSが有効な場合、これは Access-Control-Expose-Headers ヘッダーの値を設定します。 これはカンマ区切りの文字列でなければなりません。これは OPTIONAL です。設定されていない場合、このヘッダーはCORSレスポンスで返されません。

bearer-only

これは、サービスに対して true に設定する必要があります。有効にすると、アダプターはユーザーを認証しようとせず、ベアラー・トークンのみを検証します。これは OPTIONAL です。デフォルト値は false です。

autodetect-bearer-only

アプリケーションがWebアプリケーションとWebサービス(SOAPやRESTなど)の両方を提供する場合は、これを true に設定する必要があります。 Webアプリケーションの未認証のユーザーをKeycloakのログインページにリダイレクトできますが、ログインページへのリダイレクトを理解できない未認証のSOAPクライアントまたはRESTクライアントにはHTTPの 401 ステータスコードを送信します。Keycloakは、 X-Requested-WithSOAPActionAccept のような典型的なヘッダーに基づいて、SOAPクライアントまたはRESTクライアントを自動検出します。デフォルト値は false です。

enable-basic-auth

これは、BASIC認証もサポートするようにアダプターに指示します。このオプションを有効にすると、 secret も指定する必要があります。これは OPTIONAL です。 デフォルト値は false です。

expose-token

true の場合、(JavaScriptのHTTP呼び出しを介して)認証されたブラウザー・クライアントが、 root/k_query_bearer_token のURLを介して署名付きのアクセストークンを取得できます。これは OPTIONAL です。デフォルト値は false です。

credentials

アプリケーションのクレデンシャルを指定します。これは、キーがクレデンシャル・タイプで、値がクレデンシャル・タイプの値であるオブジェクト表記法です。 現在、パスワードとJWTがサポートされています。これは、 Confidential のアクセス・タイプのクライアントの場合にのみ REQUIRED です。

connection-pool-size

アダプターは、アクセス・コードをアクセス・トークンに変換するために、Keycloakサーバーに別のHTTP呼び出しを行います。この設定オプションは、Keycloakサーバーにプールすべき接続数を定義します。これは OPTIONAL です。デフォルトは 20 です。

disable-trust-manager

KeycloakサーバーがHTTPSを必要とし、この設定オプションを true に設定する場合は、トラストストアを指定する必要はありません。この設定は、SSL証明書の検証を無効とするため、開発時にのみ使用すべきで、プロダクション環境では 決して使用してはいけません 。これは OPTIONAL です。デフォルトは false です。

allow-any-hostname

KeycloakサーバーがHTTPSを必要とし、この設定オプションを true に設定する場合、トラストストア経由でKeycloakサーバーの証明書は検証されますが、ホスト名の検証は行われません。SSL証明書の検証が無効となるため、この設定は開発時にのみ使用すべきで、プロダクション環境では 決して使用してはいけません 。これは OPTIONAL です。デフォルトは false です。

proxy-url

HTTPプロキシーを使用する場合はそのURLを設定します。

truststore

トラストストア・ファイルへのファイルパスです。パスに classpath: を付けると、トラストストアはデプロイメントのクラスパスから取得されます。これはKeycloakサーバーへのHTTPS通信に使用されます。HTTPSリクエストを行うクライアントは、通信を行うサーバーのホストを検証する必要があります。これがトラストストアの役割です。キーストアには、1つ以上の信頼されたホストの証明書または認証局が含まれています。このトラストストアは、KeycloakサーバーのSSLキーストアのパブリック証明書を抽出することで作成できます。これは、 ssl-requirednonedisable-trust-managertrue でない限り、 REQUIRED です。

truststore-password

Password for the truststore keystore. This is REQUIRED if truststore is set and the truststore requires a password.

client-keystore

キーストア・ファイルへのファイルパスです。このキーストアには、アダプターがKeycloakサーバーにHTTPSリクエストを行う際の、双方向SSLのためのクライアント証明書を含めます。これは OPTIONAL です。

client-keystore-password

クライアント・キーストア用のパスワードです。 client-keystore が設定されている場合、これは REQUIRED です。

client-key-password

Password for the client’s key. This is REQUIRED if client-keystore is set.

always-refresh-token

true の場合、アダプターはリクエストごとにトークンを更新します。

register-node-at-startup

true の場合、アダプターはKeycloakに登録リクエストを送信します。これはデフォルトで false であり、アプリケーションがクラスター化されている場合にのみ有効です。詳細はアプリケーション・クラスタリングを参照してください。

register-node-period

Keycloakへアダプターを再登録する期間です。アプリケーションがクラスター化されている場合に便利です。詳細はアプリケーション・クラスタリングを参照してください。

token-store

設定可能な値は sessioncookie です。デフォルトは session です。つまり、アダプターがアカウント情報をHTTPセッションに保管します。一方、 cookie は情報をクッキーに格納することを意味します。詳細はアプリケーション・クラスタリングを参照してください。

principal-attribute

ユーザー・プリンシパル名とするOpenID ConnectのIDトークン属性を設定します。トークン属性がnullの場合、デフォルトは sub になります。有効な値は subpreferred_usernameemailnamenicknamegiven_namefamily_name です。

turn-off-change-session-id-on-login

セッションIDは、セキュリティー攻撃口とならないように、一部のプラットフォームで正常にログインするとデフォルトで変更されます。これを無効にするには true に変更します。これは OPTIONAL です。デフォルト値は false です。

token-minimum-time-to-live

アクセス・トークンの有効期限が切れる前に、Keycloakサーバーでアクティブなアクセス・トークンを先にリフレッシュする時間です(秒単位)。これは、アクセス・トークンが評価される前に期限切れになる可能性がある別のRESTクライアントに送信されるときに特に便利です。この値は、レルムのアクセス・トークンの寿命を超えてはなりません。これは OPTIONAL です。 デフォルト値は 0 秒なので、アダプターは期限切れになったときだけ、アクセス・トークンを更新します。

min-time-between-jwks-requests

新しい公開鍵を取得するための、Keycloakへの2つのリクエスト間の最小間隔を指定する時間です(秒単位)。デフォルトでは10秒です。アダプターは、未知の kid を含むトークンを認識すると、常に新しい公開鍵をダウンロードしようとします。ただし、(デフォルトでは)10秒に1回以上試行しません。これは、攻撃者が不正な kid で大量のトークンを送りつけて、アダプターからKeycloakに大量のリクエストを送信させるというDoSを防ぐために使用されます。

public-key-cache-ttl

新しい公開鍵を取得するための、Keycloakへの2つのリクエスト間の最大間隔を指定する時間です(秒単位)。デフォルトでは86400秒(1日)です。アダプターは、未知の kid を含むトークンを認識すると、常に新しい公開鍵をダウンロードしようとします。既知の kid のトークンを認識すれば、以前にダウンロードした公開鍵だけを使用します。しかし、この設定された間隔(デフォルトでは1日)に少なくとも1回は、トークンの kid が既知でも常に新しい公開鍵がダウンロードされます。

ignore-oauth-query-parameter

デフォルトは false です。 true に設定されていると、ベアラー・トークン処理のための access_token クエリー・パラメーターの処理が無効になります。ユーザーは、 access_token を渡すだけで認証することはできません。

redirect-rewrite-rules

必要に応じて、リダイレクトURIリライトのルールを指定します。キーがリダイレクトURIに一致する正規表現であり、値が置換文字列であるオブジェクト表記法で表します。置換文字列の後方参照に $ 文字を使用できます。

2.1.2. JBoss EAP/WildFlyアダプター

JBoss EAP、WildFly、またはJBoss ASにデプロイされたWARアプリケーションをセキュリティー保護するには、Keycloakアダプター・サブシステムをインストールして設定する必要があります。さらに、WARをセキュリティー保護する2つのオプションがあります。

WARにアダプター設定ファイルを用意し、web.xml内のauth-methodをKEYCLOAKに変更することができます。

あるいは、WARをまったく変更せずに、 standalone.xml などの設定ファイルのKeycloakアダプター・サブシステム設定で保護することもできます。このセクションで、両方の方法について説明します。

アダプターのインストール

アダプターは、使用しているサーバーのバージョンに応じて別個のアーカイブとして利用できます。

アダプターをインストールする際に、WildFlyが起動している必要があります。どちらか一方が起動している場合は、インストールする前に停止し、インストールが完了した後で再起動する必要があります。

WildFly 9、10、11へのインストールは次のとおりです。

$ cd $WILDFLY_HOME
$ unzip keycloak-wildfly-adapter-dist-4.0.0.Final.zip

WildFly 8へのインストールは次のとおりです。

$ cd $WILDFLY_HOME
$ unzip keycloak-wf8-adapter-dist-4.0.0.Final.zip

JBoss EAP 7へのインストールは次のとおりです。

$ cd $EAP_HOME
$ unzip keycloak-eap7-adapter-dist-4.0.0.Final.zip

JBoss EAP 6へのインストールは次のとおりです。

$ cd $EAP_HOME
$ unzip keycloak-eap6-adapter-dist-4.0.0.Final.zip

JBoss AS 7.1へのインストールは次のとおりです。

$ cd $JBOSS_HOME
$ unzip keycloak-as7-adapter-dist-4.0.0.Final.zip

このZIPアーカイブには、Keycloakアダプター固有のJBossモジュールが含まれています。また、アダプター・サブシステムを設定するためのJBoss CLIスクリプトも含まれています。

サーバーが起動していない場合に、アダプター・サブシステムを設定するには、次のようにします。

あるいは、別の設定を使用してアダプターをインストールするため、コマンドラインからアダプターをインストールする際に server.config プロパティーを指定することもできます。たとえば、 -Dserver.config=standalone-ha.xml とします。
WildFly 11
$ cd bin
$ ./jboss-cli.sh --file=adapter-elytron-install-offline.cli
WildFly 10以上
$ cd bin
$ ./jboss-cli.sh --file=adapter-install-offline.cli
オフライン・スクリプトはJBoss EAP 6.4では使用できません

あるいは、サーバーが起動している場合は、次のように実行します。

WildFly 11
$ cd bin
$ ./jboss-cli.sh --file=adapter-elytron-install-offline.cli
WildFly 10以上
$ cd bin
$ ./jboss-cli.sh --file=adapter-install-offline.cli
JBoss SSO

WildFly has built-in support for single sign-on for web applications deployed to the same WildFly instance. This should not be enabled when using Keycloak.

WARごとに必要な設定

このセクションでは、直接WARパッケージ内に設定を追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。

まず、WARの WEB-INF ディレクトリーに keycloak.json アダプター設定ファイルを作成しておく必要があります。

この設定ファイルの形式は、Javaアダプターの設定のセクションで説明しています。

次に、 web.xml 内の auth-methodKEYCLOAK に設定する必要があります。また、標準のサーブレット・セキュリティーを使用して、URLのロールベース制約を指定する必要があります。

以下は例です。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

    <module-name>application</module-name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Admins</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customers</web-resource-name>
            <url-pattern>/customers/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <login-config>
        <auth-method>KEYCLOAK</auth-method>
        <realm-name>this is ignored currently</realm-name>
    </login-config>

    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>
アダプター・サブシステムによるWARの保護

KeycloakでWARを修正する必要はありません。代わりに、Keycloakアダプター・サブシステムを介して外部から保護することができます。 auth-methodKEYCLOAK を指定する必要はありませんが、 ` web.xml` に security-constraints を定義する必要はあります。しかし、 WEB-INF/keycloak.json ファイルを作成する必要はありません。このメタデータは代わりに、Keycloakサブシステム定義のサーバー設定(つまり、 standalone.xml )内で定義されます。

<extensions>
  <extension module="org.keycloak.keycloak-adapter-subsystem"/>
</extensions>

<profile>
  <subsystem xmlns="urn:jboss:domain:keycloak:1.1">
     <secure-deployment name="WAR MODULE NAME.war">
        <realm>demo</realm>
        <auth-server-url>http://localhost:8081/auth</auth-server-url>
        <ssl-required>external</ssl-required>
        <resource>customer-portal</resource>
        <credential name="secret">password</credential>
     </secure-deployment>
  </subsystem>
</profile>

secure-deploymentname 属性は保護したいWARを識別します。 web.xml 内の module-name.war を付加した値となります。残りの設定は、Java アダプターの設定で定義されている keycloak.json 設定オプションと一対一で対応しています。

例外は credential 要素です。

より簡単に行うには、Keycloak管理コンソールにアクセスし、このWARが並んでいるアプリケーションのClient/Installationタブに移動します。そこで、カット・アンド・ペーストできるサンプルXMLファイルが提供されてます。

同じレルムで複数のデプロイメントをセキュリティー保護している場合は、別の要素でレルム設定を共有できます。以下に例を示します。

<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
    <realm name="demo">
        <auth-server-url>http://localhost:8080/auth</auth-server-url>
        <ssl-required>external</ssl-required>
    </realm>
    <secure-deployment name="customer-portal.war">
        <realm>demo</realm>
        <resource>customer-portal</resource>
        <credential name="secret">password</credential>
    </secure-deployment>
    <secure-deployment name="product-portal.war">
        <realm>demo</realm>
        <resource>product-portal</resource>
        <credential name="secret">password</credential>
    </secure-deployment>
    <secure-deployment name="database.war">
        <realm>demo</realm>
        <resource>database-service</resource>
        <bearer-only>true</bearer-only>
    </secure-deployment>
</subsystem>
セキュリティー・ドメイン

セキュリティー・コンテキストをEJB層に伝播するには、"keycloak"セキュリティー・ドメインを使用するようにセキュリティー・コンテキストを設定する必要があります。これは @SecurityDomain アノテーションで実現できます。

import org.jboss.ejb3.annotation.SecurityDomain;
...

@Stateless
@SecurityDomain("keycloak")
public class CustomerService {

    @RolesAllowed("user")
    public List<String> getCustomers() {
        return db.getCustomers();
    }
}

2.1.3. RPMからJBoss EAPアダプターをインストールします。

次のように、RPMからEAP 7アダプターをインストールします。

Red Hat Enterprise Linux 7では、チャンネルという用語はリポジトリーという用語に置き換えられました。これらの説明では、リポジトリーという用語のみが使用されています。

RPMからEAP 7アダプターをインストールする前に、JBoss EAP 7.0リポジトリーにサブスクライブする必要があります。

前提条件
  1. Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。

  2. すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。

Using Red Hat Subscription Manager, subscribe to the JBoss EAP 7.0 repository using the following command. Replace <RHEL_VERSION> with either 6 or 7 depending on your Red Hat Enterprise Linux version.

$ sudo subscription-manager repos --enable=jb-eap-7-for-rhel-<RHEL_VERSION>-server-rpms

次のコマンドを使用して、OIDC用のEAP 7アダプターをインストールします。

$ sudo yum install eap7-keycloak-adapter-sso7_2
RPMインストールのためのデフォルトのEAP_HOMEパスは、/opt/rh/eap7/root/usr/share/wildflyです。

適切なモジュール・インストール・スクリプトを実行します。

OIDCモジュールの場合は、次のコマンドを実行します。

$ {EAP_HOME}/bin/jboss-cli.sh -c --file=${EAP_HOME}/bin/adapter-install.cli

インストールは完了です。

次のように、RPMからEAP 6アダプターをインストールします。

Red Hat Enterprise Linux 7では、チャンネルという用語はリポジトリーという用語に置き換えられました。これらの説明では、リポジトリーという用語のみが使用されています。

RPMからEAP 6アダプターをインストールする前に、JBoss EAP 6.0リポジトリーにサブスクライブする必要があります。

前提条件
  1. Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。

  2. すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。

Red Hat Subscription Managerを使用して、次のコマンドを使用してJBoss EAP 6.0リポジトリーにサブスクライブします。Red Hat Enterprise Linuxのバージョンに応じて、<RHEL_VERSION>を6または7のいずれかに置き換えてください。

$ sudo subscription-manager repos --enable=jb-eap-6-for-rhel-<RHEL_VERSION>-server-rpms

次のコマンドを使用して、OIDC用のEAP 6アダプターをインストールします。

$ sudo yum install keycloak-adapter-sso7_2-eap6
RPMインストールのためのデフォルトのEAP_HOMEパスは、/opt/rh/eap6/root/usr/share/wildflyです。

適切なモジュール・インストール・スクリプトを実行します。

OIDCモジュールの場合は、次のコマンドを実行します。

$ {EAP_HOME}/bin/jboss-cli.sh -c --file=${EAP_HOME}/bin/adapter-install.cli

インストールは完了です。

2.1.4. JBoss Fuse 6アダプター

Keycloakは JBoss Fuse 6 内で実行されているWebアプリケーションのセキュリティー保護をサポートしています。

JBoss Fuse 6.3.0 Rollup 5は Jetty 9.2 server にバンドルされており、Jettyはさまざまな種類のWebアプリケーションの実行に使用されているため、JBoss Fuse 6はJetty 9アダプターを活用しています。

サポートされているFuse 6のバージョンはJBoss Fuse 6.3.0 Rollup 5のみです。以前のバージョンのFuse 6を使用している場合、一部の機能が正しく動作しない可能性があります。特に、 Hawtio との統合は、Fuse 6の以前のバージョンでは機能しません。

Fuseに対して、以下の項目のセキュリティーがサポートされています。

  • Pax Web War Extenderを使用して、FuseにデプロイされたクラシックWARアプリケーション

  • Pax Web Whiteboard Extenderを使用して、FuseにOSGIサービスとしてデプロイされたサーブレット

  • Camel Jetty コンポーネントで動作する Apache Camel Jettyエンドポイント

  • 独自の分離された Jettyエンジン で動作する Apache CXF エンドポイント

  • CXFサーブレットによって提供されるデフォルト・エンジンで実行されている Apache CXF エンドポイント

  • SSHおよびJMXの管理者アクセス

  • Hawtio administration console

Fuse 6内でWebアプリケーションを保護する

最初にKeycloak Karafの機能をインストールする必要があります。次に、セキュリティー保護するアプリケーションの種類に応じた手順を実行する必要があります。参照されているすべてのWebアプリケーションで、Keycloak Jettyオーセンティケーターを、基盤となるJettyサーバーに注入する必要があります。これを達成するための手順は、アプリケーションの種類によって異なります。詳細は以下のとおりです。

始めるのに最適なのは、 fuse ディレクトリー内のKeycloakのサンプルの一部としてバンドルされているFuseのデモを見ることです。ほとんどの手順はテストとデモから理解できるはずです。

Keycloakフィーチャーのインストール

最初に keycloak フィーチャーをJBoss Fuse環境にインストールする必要があります。 keycloak フィーチャーには、Fuseアダプターとサード・パーティーのすべての依存関係が含まれます。Mavenリポジトリーまたはアーカイブからインストールすることができます。

Mavenリポジトリーからのインストール

前提条件として、オンラインでMavenリポジトリーにアクセスできる必要があります。

コミュニティー版の場合、すべてのアーティファクトとサード・パーティーの依存関係がMavenのセントラル・リポジトリーで利用できるため、オンラインにするだけで十分です。

Mavenリポジトリーを使用して、Keycloakフィーチャーをインストールするには、以下の手順を実行します。

  1. JBoss Fuse 6.3.0 Rollup 5を開始します。Karafターミナルで以下のとおりにタイプします。

    features:addurl mvn:org.keycloak/keycloak-osgi-features/4.0.0.Final/xml/features
    features:install keycloak
  2. 以下のようにJetty 9フィーチャーをインストールする必要があるかもしれません。

    features:install keycloak-jetty9-adapter
    JBoss Fuse 6.2以降を使用している場合は、 keycloak-jetty8-adapter を使用してください。ただし、JBoss Fuse 6.3.0 Rollup 5にアップグレードすることをお勧めします。
  3. 以下のようにフィーチャーがインストールされていることを確認します。

features:list | grep keycloak
ZIPバンドルからのインストール

これは、オフラインになっている場合や、Mavenを使用してJARファイルやその他のアーティファクトを取得したくない場合に便利です。

ZIPアーカイブからFuseアダプターをインストールするには、次の手順を実行します。

  1. Keycloak FuseアダプターのZIPアーカイブをダウンロードしてください。

  2. JBoss Fuseのルート・ディレクトリーに解凍します。依存関係にあるファイルは system ディレクトリーの下にインストールされます。既存のすべてのjarファイルが上書きされます。

    JBoss Fuse 6.3.0 Rollup 5には、これを使用します。

    cd /path-to-fuse/jboss-fuse-6.3.0.redhat-254
    unzip -q /path-to-adapter-zip/keycloak-fuse-adapter-4.0.0.Final.zip
  3. Fuseを起動し、Fuse/Karafターミナルで次のコマンドを実行します。

    features:addurl mvn:org.keycloak/keycloak-osgi-features/4.0.0.Final/xml/features
    features:install keycloak
  4. 対応するJettyアダプターをインストールします。アーティファクトはJBoss Fuseの system ディレクトリーから直接利用できるので、Mavenリポジトリーを使う必要はありません。

クラシックWARアプリケーションのセキュリティー保護

WARアプリケーションをセキュリティー保護するために必要な手順は次のとおりです。

  1. /WEB-INF/web.xml ファイルで、次のように必要なものを宣言します。

    • <security-constraint>要素のセキュリティー制約

    • <login-config>要素のログイン設定

    • <security-role>要素のセキュリティー・ロール。

      例:

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
               version="3.0">
      
          <module-name>customer-portal</module-name>
      
          <welcome-file-list>
              <welcome-file>index.html</welcome-file>
          </welcome-file-list>
      
          <security-constraint>
              <web-resource-collection>
                  <web-resource-name>Customers</web-resource-name>
                  <url-pattern>/customers/*</url-pattern>
              </web-resource-collection>
              <auth-constraint>
                  <role-name>user</role-name>
              </auth-constraint>
          </security-constraint>
      
          <login-config>
              <auth-method>BASIC</auth-method>
              <realm-name>does-not-matter</realm-name>
          </login-config>
      
          <security-role>
              <role-name>admin</role-name>
          </security-role>
          <security-role>
              <role-name>user</role-name>
          </security-role>
      </web-app>
  2. オーセンティケーターを設定した /WEB_INF/jjetty-web.xml ファイルを追加してください。

    例:

    <?xml version="1.0"?>
    <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
     "http://www.eclipse.org/jetty/configure_9_0.dtd">
    <Configure class="org.eclipse.jetty.webapp.WebAppContext">
        <Get name="securityHandler">
            <Set name="authenticator">
                <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
                </New>
            </Set>
        </Get>
    </Configure>
  3. WARの /WEB-INF/ ディレクトリー内に、新しい keycloak.json ファイルを作成します。この設定ファイルの形式は、Javaアダプターの設定のセクションで説明しています。外部アダプターの設定で説明されているように、外部でこのファイルを使用することもできます。

  4. WARアプリケーションが org.keycloak.adapters.jettyMETA-INF/MANIFEST.MF ファイルの Import-Package ヘッダーの下にあるパッケージをインポートしていることを確認してください。プロジェクトで maven-bundle-plugin を使うと、マニフェストにOSGIヘッダーが正しく生成されます。パッケージの "*" による解決は org.keycloak.adapters.jetty パッケージをインポートしないことに注意してください。アプリケーションやBlueprint、Spring記述子では使用されず、 jetty-web.xml ファイルで使用されるためです。

    インポートするパッケージのリストは次のようになります。

    org.keycloak.adapters.jetty;version="4.0.0.Final",
    org.keycloak.adapters;version="4.0.0.Final",
    org.keycloak.constants;version="4.0.0.Final",
    org.keycloak.util;version="4.0.0.Final",
    org.keycloak.*;version="4.0.0.Final",
    *;resolution:=optional
外部アダプターの設定

keycloak.json アダプターの設定ファイルをWARアプリケーションの中にバンドルするのではなく、外部で使用可能にし、命名規則に基づいてロードする場合は、この設定方法を使用してください。

この機能を有効にするには、次のセクションを /WEB_INF/web.xml ファイルに追加してください。

<context-param>
    <param-name>keycloak.config.resolver</param-name>
    <param-value>org.keycloak.adapters.osgi.PathBasedKeycloakConfigResolver</param-value>
</context-param>

そのコンポーネントは、 keycloak.config または karaf.etc のjavaプロパティーを使って基本フォルダーを検索し、設定を探します。そして、見つけたフォルダーの中で <your_web_context>-keycloak.json というファイルを探します。

たとえば、Webアプリケーションにコンテキスト my-portal がある場合、アダプターの設定は $FUSE_HOME/etc/my-portal-keycloak.json ファイルからロードされます。

OSGIサービスとしてデプロイされたサーブレットのセキュリティー保護

クラシックなWARアプリケーションとしてデプロイされていないOSGIバンドルされたプロジェクト内にサーブレット・クラスがある場合、この方式を使用できます。 FuseはPax Web Whiteboard Extenderを使用して、サーブレットをWebアプリケーションとしてデプロイします。

Keycloakでサーブレットをセキュリティー保護するには、次の手順を実行します。

  1. KeycloakはPaxWebIntegrationServiceを提供します。これにより、jetty-web.xmlを注入し、アプリケーションのセキュリティー制約を設定できます。アプリケーション内の OSGI-INF/blueprint/blueprint.xml ファイルでそのようなサービスを宣言する必要があります。サーブレットはそれに依存する必要があることに注意してください。設定例は次のとおりです。

    <?xml version="1.0" encoding="UTF-8"?>
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0
               http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
    
        <!-- Using jetty bean just for the compatibility with other fuse services -->
        <bean id="servletConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
            <property name="constraint">
                <bean class="org.eclipse.jetty.util.security.Constraint">
                    <property name="name" value="cst1"/>
                    <property name="roles">
                        <list>
                            <value>user</value>
                        </list>
                    </property>
                    <property name="authenticate" value="true"/>
                    <property name="dataConstraint" value="0"/>
                </bean>
            </property>
            <property name="pathSpec" value="/product-portal/*"/>
        </bean>
    
        <bean id="keycloakPaxWebIntegration" class="org.keycloak.adapters.osgi.PaxWebIntegrationService"
              init-method="start" destroy-method="stop">
            <property name="jettyWebXmlLocation" value="/WEB-INF/jetty-web.xml" />
            <property name="bundleContext" ref="blueprintBundleContext" />
            <property name="constraintMappings">
                <list>
                    <ref component-id="servletConstraintMapping" />
                </list>
            </property>
        </bean>
    
        <bean id="productServlet" class="org.keycloak.example.ProductPortalServlet" depends-on="keycloakPaxWebIntegration">
        </bean>
    
        <service ref="productServlet" interface="javax.servlet.Servlet">
            <service-properties>
                <entry key="alias" value="/product-portal" />
                <entry key="servlet-name" value="ProductServlet" />
                <entry key="keycloak.config.file" value="/keycloak.json" />
            </service-properties>
        </service>
    
    </blueprint>
    • プロジェクト内に WEB-INF ディレクトリー(プロジェクトがWebアプリケーションでない場合でも)を用意し、クラシックWARアプリケーションのセクションのように /WEB-INF/jetty-web.xml/WEB-INF/keycloak.json ファイルを作成する必要があります。security-constraintsがblueprint設定ファイルで宣言されているので、 web.xml ファイルは必要ありません。

  2. META-INF/MANIFEST.MFImport-Package は、少なくとも以下のインポートを含んでいなければなりません。

    org.keycloak.adapters.jetty;version="4.0.0.Final",
    org.keycloak.adapters;version="4.0.0.Final",
    org.keycloak.constants;version="4.0.0.Final",
    org.keycloak.util;version="4.0.0.Final",
    org.keycloak.*;version="4.0.0.Final",
    *;resolution:=optional
Apache Camelアプリケーションのセキュリティー保護

KeycloakJettyAuthenticator とsecurityHandlerを追加し、適切なセキュリティー制約を注入することで、 camel-jettyコンポーネントで実装されたApache Camelエンドポイントをセキュリティー保護できます。 OSGI-INF/blueprint/blueprint.xml ファイルを、以下のような設定でCamelアプリケーションに追加できます。ロール、セキュリティー制約のマッピング、およびKeycloakアダプターの設定は、使用する環境と必要性により若干異なる場合があります。

例:

<?xml version="1.0" encoding="UTF-8"?>

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:camel="http://camel.apache.org/schema/blueprint"
           xsi:schemaLocation="
       http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
       http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">

    <bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
        <property name="realm" value="demo"/>
        <property name="resource" value="admin-camel-endpoint"/>
        <property name="bearerOnly" value="true"/>
        <property name="authServerUrl" value="http://localhost:8080/auth" />
        <property name="sslRequired" value="EXTERNAL"/>
    </bean>

    <bean id="keycloakAuthenticator" class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
        <property name="adapterConfig" ref="kcAdapterConfig"/>
    </bean>

    <bean id="constraint" class="org.eclipse.jetty.util.security.Constraint">
        <property name="name" value="Customers"/>
        <property name="roles">
            <list>
                <value>admin</value>
            </list>
        </property>
        <property name="authenticate" value="true"/>
        <property name="dataConstraint" value="0"/>
    </bean>

    <bean id="constraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
        <property name="constraint" ref="constraint"/>
        <property name="pathSpec" value="/*"/>
    </bean>

    <bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler">
        <property name="authenticator" ref="keycloakAuthenticator" />
        <property name="constraintMappings">
            <list>
                <ref component-id="constraintMapping" />
            </list>
        </property>
        <property name="authMethod" value="BASIC"/>
        <property name="realmName" value="does-not-matter"/>
    </bean>

    <bean id="sessionHandler" class="org.keycloak.adapters.jetty.spi.WrappingSessionHandler">
        <property name="handler" ref="securityHandler" />
    </bean>

    <bean id="helloProcessor" class="org.keycloak.example.CamelHelloProcessor" />

    <camelContext id="blueprintContext"
                  trace="false"
                  xmlns="http://camel.apache.org/schema/blueprint">
        <route id="httpBridge">
            <from uri="jetty:http://0.0.0.0:8383/admin-camel-endpoint?handlers=sessionHandler&amp;matchOnUriPrefix=true" />
            <process ref="helloProcessor" />
            <log message="The message from camel endpoint contains ${body}"/>
        </route>
    </camelContext>

</blueprint>
  • META-INF/MANIFEST.MFImport-Package には、以下のインポートが含まれている必要があります。

javax.servlet;version="[3,4)",
javax.servlet.http;version="[3,4)",
org.apache.camel.*,
org.apache.camel;version="[2.13,3)",
org.eclipse.jetty.security;version="[8,10)",
org.eclipse.jetty.server.nio;version="[8,10)",
org.eclipse.jetty.util.security;version="[8,10)",
org.keycloak.*;version="4.0.0.Final",
org.osgi.service.blueprint,
org.osgi.service.blueprint.container,
org.osgi.service.event,
Camel RestDSL

Camel RestDSLは、流暢な方法でRESTエンドポイントを定義するために使用されるCamelの機能です。しかし、依然として特定の実装クラスを使用し、Keycloakとの統合方法に関する指示を提供する必要があります。

統合機構を設定する方法は、RestDSLで定義されたルートを設定するCamelコンポーネントによって異なります。

次の例は、Jettyコンポーネントを使用して統合を設定する方法を示しています(以前のBlueprintの例で定義されているBeanの一部を参照)。

<bean id="securityHandlerRest" class="org.eclipse.jetty.security.ConstraintSecurityHandler">
    <property name="authenticator" ref="keycloakAuthenticator" />
    <property name="constraintMappings">
        <list>
            <ref component-id="constraintMapping" />
        </list>
    </property>
    <property name="authMethod" value="BASIC"/>
    <property name="realmName" value="does-not-matter"/>
</bean>

<bean id="sessionHandlerRest" class="org.keycloak.adapters.jetty.spi.WrappingSessionHandler">
    <property name="handler" ref="securityHandlerRest" />
</bean>


<camelContext id="blueprintContext"
              trace="false"
              xmlns="http://camel.apache.org/schema/blueprint">

    <restConfiguration component="jetty" contextPath="/restdsl"
                       port="8484">
        <!--the link with Keycloak security handlers happens here-->
        <endpointProperty key="handlers" value="sessionHandlerRest"></endpointProperty>
        <endpointProperty key="matchOnUriPrefix" value="true"></endpointProperty>
    </restConfiguration>

    <rest path="/hello" >
        <description>Hello rest service</description>
        <get uri="/{id}" outType="java.lang.String">
            <description>Just an helllo</description>
            <to uri="direct:justDirect" />
        </get>

    </rest>

    <route id="justDirect">
        <from uri="direct:justDirect"/>
        <process ref="helloProcessor" />
        <log message="RestDSL correctly invoked ${body}"/>
        <setBody>
            <constant>(__This second sentence is returned from a Camel RestDSL endpoint__)</constant>
        </setBody>
    </route>

</camelContext>
独立したJettyエンジンでのApache CXFエンドポイントのセキュリティー保護

別のJettyエンジンでKeycloakによって保護されたCXFエンドポイントを実行するには、以下の手順に沿って行います。

  1. アプリケーションに META-INF/spring/beans.xml を追加し、 KeycloakJettyAuthenticator を注入したJettyの SecurityHandlerhttpj:engine-factory を宣言してください。CFXのJAX-WSアプリケーションの設定は、次のようになります。

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jaxws="http://cxf.apache.org/jaxws"
           xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
            http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd
            http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd">
    
        <import resource="classpath:META-INF/cxf/cxf.xml" />
    
        <bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
            <property name="realm" value="demo"/>
            <property name="resource" value="custom-cxf-endpoint"/>
            <property name="bearerOnly" value="true"/>
            <property name="authServerUrl" value="http://localhost:8080/auth" />
            <property name="sslRequired" value="EXTERNAL"/>
        </bean>
    
        <bean id="keycloakAuthenticator" class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
            <property name="adapterConfig">
                <ref local="kcAdapterConfig" />
            </property>
        </bean>
    
        <bean id="constraint" class="org.eclipse.jetty.util.security.Constraint">
            <property name="name" value="Customers"/>
            <property name="roles">
                <list>
                    <value>user</value>
                </list>
            </property>
            <property name="authenticate" value="true"/>
            <property name="dataConstraint" value="0"/>
        </bean>
    
        <bean id="constraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
            <property name="constraint" ref="constraint"/>
            <property name="pathSpec" value="/*"/>
        </bean>
    
        <bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler">
            <property name="authenticator" ref="keycloakAuthenticator" />
            <property name="constraintMappings">
                <list>
                    <ref local="constraintMapping" />
                </list>
            </property>
            <property name="authMethod" value="BASIC"/>
            <property name="realmName" value="does-not-matter"/>
        </bean>
    
        <httpj:engine-factory bus="cxf" id="kc-cxf-endpoint">
            <httpj:engine port="8282">
                <httpj:handlers>
                    <ref local="securityHandler" />
                </httpj:handlers>
                <httpj:sessionSupport>true</httpj:sessionSupport>
            </httpj:engine>
        </httpj:engine-factory>
    
        <jaxws:endpoint
                        implementor="org.keycloak.example.ws.ProductImpl"
                        address="http://localhost:8282/ProductServiceCF" depends-on="kc-cxf-endpoint" />
    
    </beans>

    CXFのJAX-RSアプリケーションの場合、engine-factortyに依存するエンドポイントの設定にのみ違いがあります。

    <jaxrs:server serviceClass="org.keycloak.example.rs.CustomerService" address="http://localhost:8282/rest"
        depends-on="kc-cxf-endpoint">
        <jaxrs:providers>
            <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />
        </jaxrs:providers>
    </jaxrs:server>
  2. META-INF/MANIFEST.MFImport-Package は以下のインポートを含まなければなりません。

META-INF.cxf;version="[2.7,3.2)",
META-INF.cxf.osgi;version="[2.7,3.2)";resolution:=optional,
org.apache.cxf.bus;version="[2.7,3.2)",
org.apache.cxf.bus.spring;version="[2.7,3.2)",
org.apache.cxf.bus.resource;version="[2.7,3.2)",
org.apache.cxf.transport.http;version="[2.7,3.2)",
org.apache.cxf.*;version="[2.7,3.2)",
org.springframework.beans.factory.config,
org.eclipse.jetty.security;version="[8,10)",
org.eclipse.jetty.util.security;version="[8,10)",
org.keycloak.*;version="4.0.0.Final"
デフォルトのJettyエンジンでのApache CXFエンドポイントの保護

いくつかのサービスは、起動時にデプロイされたサーブレットを自動的に提供します。そのようなサービスの1つは、http://localhost:8181/cxf コンテキストで実行されているCXFサーブレットです。そのようなエンドポイントを保護することは複雑になる可能性があります。Keycloakが現在使用しているアプローチの1つは ServletReregistrationService で、これは組み込みのサーブレットを起動時にアンデプロイし、Keycloakによってセキュリティー保護されたコンテキストに再デプロイできるようにします。

アプリケーション内の設定ファイル OSGI-INF/blueprint/blueprint.xml は、以下のようになります。JAX-RSの customerservice エンドポイント(アプリケーション固有のエンドポイント)を追加しますが、もっと重要なのは、 /cxf コンテキスト全体をセキュリティー保護することです。

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
           xsi:schemaLocation="
                http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
                http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd">

    <!-- JAXRS Application -->

    <bean id="customerBean" class="org.keycloak.example.rs.CxfCustomerService" />

    <jaxrs:server id="cxfJaxrsServer" address="/customerservice">
        <jaxrs:providers>
            <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />
        </jaxrs:providers>
        <jaxrs:serviceBeans>
            <ref component-id="customerBean" />
        </jaxrs:serviceBeans>
    </jaxrs:server>


    <!-- Securing of whole /cxf context by unregister default cxf servlet from paxweb and re-register with applied security constraints -->

    <bean id="cxfConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
        <property name="constraint">
            <bean class="org.eclipse.jetty.util.security.Constraint">
                <property name="name" value="cst1"/>
                <property name="roles">
                    <list>
                        <value>user</value>
                    </list>
                </property>
                <property name="authenticate" value="true"/>
                <property name="dataConstraint" value="0"/>
            </bean>
        </property>
        <property name="pathSpec" value="/cxf/*"/>
    </bean>

    <bean id="cxfKeycloakPaxWebIntegration" class="org.keycloak.adapters.osgi.PaxWebIntegrationService"
          init-method="start" destroy-method="stop">
        <property name="bundleContext" ref="blueprintBundleContext" />
        <property name="jettyWebXmlLocation" value="/WEB-INF/jetty-web.xml" />
        <property name="constraintMappings">
            <list>
                <ref component-id="cxfConstraintMapping" />
            </list>
        </property>
    </bean>

    <bean id="defaultCxfReregistration" class="org.keycloak.adapters.osgi.ServletReregistrationService" depends-on="cxfKeycloakPaxWebIntegration"
          init-method="start" destroy-method="stop">
        <property name="bundleContext" ref="blueprintBundleContext" />
        <property name="managedServiceReference">
            <reference interface="org.osgi.service.cm.ManagedService" filter="(service.pid=org.apache.cxf.osgi)" timeout="5000"  />
        </property>
    </bean>

</blueprint>

その結果、デフォルトのCXF HTTPの宛先で実行されている他のすべてのCXFサービスも保護されます。同様に、アプリケーションがアンデプロイされると、 /cxf コンテキスト全体がセキュリティー保護されなくなります。このため、独立したJettyエンジンでのApache CXFエンドポイントの保護で説明されているように、独自のJettyエンジンをアプリケーションに使用すると、個々のアプリケーションのセキュリティーをより詳細に制御できます。

  • WEB-INF ディレクトリーはプロジェクト内にある必要があります(プロジェクトがWebアプリケーションでない場合でも)。 また、クラシックWARアプリケーションと同様に、 /WEB-INF/jetty-web.xml および /WEB-INF/keycloak.json ファイルを編集する必要があります。セキュリティー制約がblueprint設定ファイルで宣言されているので、 web.xml ファイルは必要ないことに注意してください。

  • META-INF/MANIFEST.MFImport-Package は以下のインポートを含まなければなりません。

META-INF.cxf;version="[2.7,3.2)",
META-INF.cxf.osgi;version="[2.7,3.2)";resolution:=optional,
org.apache.cxf.transport.http;version="[2.7,3.2)",
org.apache.cxf.*;version="[2.7,3.2)",
com.fasterxml.jackson.jaxrs.json;version="[2.5,3)",
org.eclipse.jetty.security;version="[8,10)",
org.eclipse.jetty.util.security;version="[8,10)",
org.keycloak.*;version="4.0.0.Final",
org.keycloak.adapters.jetty;version="4.0.0.Final",
*;resolution:=optional
Fuse管理サービスのセキュリティー保護
FuseターミナルへのSSH認証の使用

Keycloakは、主にWebアプリケーションの認証のユースケースを扱います。ただし、他のWebサービスやアプリケーションがKeycloakで保護されている場合は、KeycloakのクレデンシャルでSSHなどのWeb以外の管理サービスを保護するのが最善の方法です。これは、Keycloakへのリモート接続を許可し、リソース・オーナー・パスワード・クレデンシャルに基づいてクレデンシャルを検証するJAASログイン・モジュールを使用して実行できます。

SSH認証を有効にするには、次の手順を実行します。

  1. Keycloakでは、SSH認証に使用されるクライアント(たとえば、 ssh-jmx-admin-client )を作成します。このクライアントでは、 Direct Access Grants EnabledOn に選択されている必要があります。

  2. $FUSE_HOME/etc/org.apache.karaf.shell.cfg ファイルで、次のとおりにこのプロパティーを更新または指定します。

    sshRealm=keycloak
  3. Add the $FUSE_HOME/etc/keycloak-direct-access.json file with content similar to the following (based on your environment and Keycloak client settings):

    {
        "realm": "demo",
        "resource": "ssh-jmx-admin-client",
        "ssl-required" : "external",
        "auth-server-url" : "http://localhost:8080/auth",
        "credentials": {
            "secret": "password"
        }
    }

    このファイルでは、JAASの DirectAccessGrantsLoginModule がSSH認証のために keycloak JAASレルムから使用するクライアント・アプリケーションの設定を指定します。

  4. Fuseを起動し、 keycloak JAASレルムをインストールしてください。最も簡単な方法は、JAASレルムがあらかじめ定義された keycloak-jaas フィーチャーをインストールすることです。より高いランクの独自 keycloak JAASレルムを使用して、フィーチャーに定義済みのレルムをオーバーライドすることができます。詳細については、 JBoss Fuse documentationを参照してください。

    Fuseターミナルで次のコマンドを使用します。

    features:addurl mvn:org.keycloak/keycloak-osgi-features/4.0.0.Final/xml/features
    features:install keycloak-jaas
  5. SSHで admin ユーザーとしてログインするには、ターミナルで次のように入力します。

    ssh -o PubkeyAuthentication=no -p 8101 admin@localhost
  6. パスワードは password でログインしてください。

最近のオペレーティング・システムでは、SSHコマンドの-oオプションを -o HostKeyAlgorithms=+ssh-dss として使用する必要があるかもしれません。これは、最近のSSHクライアントではデフォルトで ssh-dss アルゴリズムを使用できないためです。しかし、現在JBoss Fuse 6.3.0 Rollup 5ではデフォルトで使用されています。

Note that the user needs to have realm role admin to perform all operations or another role to perform a subset of operations (for example, the viewer role that restricts the user to run only read-only Karaf commands). The available roles are configured in $FUSE_HOME/etc/org.apache.karaf.shell.cfg or $FUSE_HOME/etc/system.properties.

JMX認証の使用

jconsoleまたは別の外部ツールを使用してRMI経由でJMXにリモート接続する場合は、JMX認証が必要になることがあります。それ以外の場合は、デフォルトでhaolt.ioにjolokiaエージェントがインストールされているので、hawt.io/jolokiaを使用する方がよいでしょう。詳細については、Hawtio Admin Consoleを参照してください。

JMX認証を使用するには、次の手順を実行します。

  1. $FUSE_HOME/etc/org.apache.karaf.management.cfg ファイルで、 jmxRealm プロパティーを次のように変更します。

    jmxRealm=keycloak
  2. 上記のSSHのセクションで説明したように、 keycloak-jaas フィーチャーをインストールし、 $FUSE_HOME/etc/keycloak-direct-access.json ファイルを設定してください。

  3. jconsoleでは、次のようなURLを使用できます。

service:jmx:rmi://localhost:44444/jndi/rmi://localhost:1099/karaf-root

クレデンシャルはadmin/password(利用環境の管理者権限を持つユーザー次第)です。

Hawtio管理コンソールのセキュリティー保護

Keycloakを使用して、Hawtio管理コンソールをセキュリティー保護するには、以下の手順を実行します。

  1. これらのプロパティーを $FUSE_HOME/etc/system.properties ファイルに追加します。

    hawtio.keycloakEnabled=true
    hawtio.realm=keycloak
    hawtio.keycloakClientConfig=file://${karaf.base}/etc/keycloak-hawtio-client.json
    hawtio.rolePrincipalClasses=org.keycloak.adapters.jaas.RolePrincipal,org.apache.karaf.jaas.boot.principal.RolePrincipal
  2. Create a client in the Keycloak administration console in your realm. For example, in the Keycloak demo realm, create a client hawtio-client, specify public as the Access Type, and specify a redirect URI pointing to Hawtio: http://localhost:8181/hawtio/*. You must also have a corresponding Web Origin configured (in this case, http://localhost:8181).

  3. $FUSE_HOME/etc ディレクトリーに keycloak-hawtio-client.json ファイルを作成します。このファイルは、以下の例のような内容で作成します。Keycloak環境に応じて、 realmresourceauth-server-url の各プロパティーを変更してください。 resource プロパティーは前のステップで作成されたクライアントを指し示さなければなりません。このファイルは、クライアント(Hawtio JavaScriptアプリケーション)側で使用されます。

    {
      "realm" : "demo",
      "resource" : "hawtio-client",
      "auth-server-url" : "http://localhost:8080/auth",
      "ssl-required" : "external",
      "public-client" : true
    }
  4. $FUSE_HOME/etc ディレクトリーに keycloak-hawtio.json ファイルを作成します。このファイルは、以下の例のような内容です。Keycloakの環境に応じて realmauth-server-url プロパティーを変更してください。このファイルは、サーバー(JAASログイン・モジュール)側のアダプターによって使用されます。

    {
      "realm" : "demo",
      "resource" : "jaas",
      "bearer-only" : true,
      "auth-server-url" : "http://localhost:8080/auth",
      "ssl-required" : "external",
      "use-resource-role-mappings": false,
      "principal-attribute": "preferred_username"
    }
  5. Keycloakフィーチャーをまだインストールしていない場合は、JBoss Fuse 6.3.0 Rollup 5を起動し、インストールしてください。Karafターミナルのコマンドはこの例に似ています。

    features:addurl mvn:org.keycloak/keycloak-osgi-features/4.0.0.Final/xml/features
    features:install keycloak
  6. http://localhost:8181/hawtio に移動し、Keycloakのレルムからユーザーとしてログインします。

    Note that the user needs to have the proper realm role to successfully authenticate to Hawtio. The available roles are configured in the $FUSE_HOME/etc/system.properties file in hawtio.roles.

JBoss EAP 6.4上のHawtioのセキュリティー保護

JBoss EAP 6.4サーバーでHawtioを実行するには、以下の手順を実行します。

  1. 前のセクション(Hawtio管理コンソールをセキュリティー保護する)で説明したように、Keycloakを設定します。次のように仮定します。

    • Keycloakのレルムのデモとクライアント hawtio-client を持っている

    • Keycloakが localhost:8080 で動作している

    • 展開されたHawtioがあるJBoss EAP 6.4サーバーは localhost:8181 で動作します。このサーバーのディレクトリーは、次のステップでは、 $EAP_HOME と呼ばれます。

  2. hawtio-wildfly-1.4.0.redhat-630254.war アーカイブを $EAP_HOME/standalone/configuration ディレクトリーにコピーします。Hawtioの導入の詳細については、 Fuse Hawtio documentationを参照してください。

  3. 上記内容の keycloak-hawtio.json ファイルと keycloak-hawtio-client.json ファイルを $EAP_HOME/standalone/configuration ディレクトリーにコピーします。

  4. JBossアダプターのドキュメントの説明に従って、Keycloakアダプター・サブシステムをJBoss EAP 6.4サーバーにインストールします。

  5. $EAP_HOME/standalone/configuration/standalone.xml ファイルで、次の例のようにシステムのプロパティーを設定します。

    <extensions>
    ...
    </extensions>
    
    <system-properties>
        <property name="hawtio.authenticationEnabled" value="true" />
        <property name="hawtio.realm" value="hawtio" />
        <property name="hawtio.roles" value="admin,viewer" />
        <property name="hawtio.rolePrincipalClasses" value="org.keycloak.adapters.jaas.RolePrincipal" />
        <property name="hawtio.keycloakEnabled" value="true" />
        <property name="hawtio.keycloakClientConfig" value="${jboss.server.config.dir}/keycloak-hawtio-client.json" />
        <property name="hawtio.keycloakServerConfig" value="${jboss.server.config.dir}/keycloak-hawtio.json" />
    </system-properties>
  6. Hawtioレルムを同じファイルの security-domains セクションに追加します。

    <security-domain name="hawtio" cache-type="default">
        <authentication>
            <login-module code="org.keycloak.adapters.jaas.BearerTokenLoginModule" flag="required">
                <module-option name="keycloak-config-file" value="${hawtio.keycloakServerConfig}"/>
            </login-module>
        </authentication>
    </security-domain>
  7. hawtiosecure-deployment セクションをアダプター・サブシステムに追加してください。これにより、Hawtio WARがJAASログイン・モジュール・クラスを見つけることができます。

    <subsystem xmlns="urn:jboss:domain:keycloak:1.1">
        <secure-deployment name="hawtio-wildfly-1.4.0.redhat-630254.war" />
    </subsystem>
  8. HawtioとJBoss EAP 6.4サーバーを再起動します。

    cd $EAP_HOME/bin
    ./standalone.sh -Djboss.socket.binding.port-offset=101
  9. Hawtio(http://localhost:8181/hawtio)へアクセスしてください。 Keycloakによってセキュリティー保護されています。

2.1.5. JBoss Fuse 7 Adapter

Keycloak supports securing your web applications running inside JBoss Fuse 7.

JBoss Fuse 7 leverages Undertow adapter which is essentially the same as EAP 7 / WildFly 10 Adapter as JBoss Fuse 7.0.1 is bundled with Undertow HTTP engine under the covers and Undertow is used for running various kinds of web applications.

The only supported versions of Fuse 7 is JBoss Fuse 7.0.1. If you use earlier versions of Fuse 7, it is possible that some functions will not work correctly. In particular, integration will not work at all for earlier versions of Fuse 7 than 7.0.1.

Fuseに対して、以下の項目のセキュリティーがサポートされています。

  • Pax Web War Extenderを使用して、FuseにデプロイされたクラシックWARアプリケーション

  • Servlets deployed on Fuse as OSGI services with Pax Web Whiteboard Extender and additionally servlets registered through org.osgi.service.http.HttpService#registerServlet() which is standard OSGi Enterprise HTTP Service

  • Apache Camel Undertow endpoints running with the Camel Undertow component

  • Apache CXF endpoints running on their own separate Undertow engine

  • CXFサーブレットによって提供されるデフォルト・エンジンで実行されている Apache CXF エンドポイント

  • SSHおよびJMXの管理者アクセス

  • Hawtio administration console

Securing Your Web Applications Inside Fuse 7

You must first install the Keycloak Karaf feature. Next you will need to perform the steps according to the type of application you want to secure. All referenced web applications require injecting the Keycloak Undertow authentication mechanism into the underlying web server. The steps to achieve this depend on the application type. The details are described below.

始めるのに最適なのは、 fuse ディレクトリー内のKeycloakのサンプルの一部としてバンドルされているFuseのデモを見ることです。ほとんどの手順はテストとデモから理解できるはずです。

Keycloakフィーチャーのインストール

You must first install the keycloak-pax-http-undertow and keycloak-jaas features in the JBoss Fuse environment. The keycloak feature includes the Fuse adapter and all third-party dependencies. The keycloak-jaas contains JAAS module used in realm for SSH and JMX authentication. You can install it either from the Maven repository or from an archive.

Mavenリポジトリーからのインストール

前提条件として、オンラインでMavenリポジトリーにアクセスできる必要があります。

コミュニティー版の場合、すべてのアーティファクトとサード・パーティーの依存関係がMavenのセントラル・リポジトリーで利用できるため、オンラインにするだけで十分です。

Mavenリポジトリーを使用して、Keycloakフィーチャーをインストールするには、以下の手順を実行します。

  1. Start JBoss Fuse 7.0.1; then in the Karaf terminal type:

    feature:repo-add mvn:org.keycloak/keycloak-osgi-features/4.0.0.Final/xml/features
    feature:install keycloak-pax-http-undertow keycloak-jaas
  2. You might also need to install the Undertow feature:

    feature:install pax-http-undertow
  3. 以下のようにフィーチャーがインストールされていることを確認します。

feature:list | grep keycloak
ZIPバンドルからのインストール

これは、オフラインになっている場合や、Mavenを使用してJARファイルやその他のアーティファクトを取得したくない場合に便利です。

ZIPアーカイブからFuseアダプターをインストールするには、次の手順を実行します。

  1. Keycloak FuseアダプターのZIPアーカイブをダウンロードしてください。

  2. JBoss Fuseのルート・ディレクトリーに解凍します。依存関係にあるファイルは system ディレクトリーの下にインストールされます。既存のすべてのjarファイルが上書きされます。

    Use this for JBoss Fuse 7.0.1:

    cd /path-to-fuse/jboss-fuse-7.0.z
    unzip -q /path-to-adapter-zip/keycloak-fuse-adapter-4.0.0.Final.zip
  3. Fuseを起動し、Fuse/Karafターミナルで次のコマンドを実行します。

    feature:repo-add mvn:org.keycloak/keycloak-osgi-features/4.0.0.Final/xml/features
    feature:install keycloak-pax-http-undertow keycloak-jaas
  4. Install the corresponding Undertow adapter. Since the artifacts are available directly in the JBoss Fuse system directory, you do not need to use the Maven repository.

クラシックWARアプリケーションのセキュリティー保護

WARアプリケーションをセキュリティー保護するために必要な手順は次のとおりです。

  1. /WEB-INF/web.xml ファイルで、次のように必要なものを宣言します。

    • <security-constraint>要素のセキュリティー制約

    • <login-config> 要素内のログイン設定。 <auth-method>KEYCLOAK であることを確認してください。

    • <security-role> 要素のセキュリティー・ロール。

      例:

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
               version="3.0">
      
          <module-name>customer-portal</module-name>
      
          <welcome-file-list>
              <welcome-file>index.html</welcome-file>
          </welcome-file-list>
      
          <security-constraint>
              <web-resource-collection>
                  <web-resource-name>Customers</web-resource-name>
                  <url-pattern>/customers/*</url-pattern>
              </web-resource-collection>
              <auth-constraint>
                  <role-name>user</role-name>
              </auth-constraint>
          </security-constraint>
      
          <login-config>
              <auth-method>KEYCLOAK</auth-method>
              <realm-name>does-not-matter</realm-name>
          </login-config>
      
          <security-role>
              <role-name>admin</role-name>
          </security-role>
          <security-role>
              <role-name>user</role-name>
          </security-role>
      </web-app>
  2. WARの /WEB-INF/ ディレクトリー内に、新しい keycloak.json ファイルを作成します。この設定ファイルの形式は、Javaアダプターの設定のセクションで説明しています。外部アダプターの設定で説明されているように、外部でこのファイルを使用することもできます。

    例:

    {
        "realm": "demo",
        "resource": "customer-portal",
        "auth-server-url": "http://localhost:8080/auth",
        "ssl-required" : "external",
        "credentials": {
            "secret": "password"
        }
    }
  3. Fuse 6アダプターとは異なり、MANIFEST.MFには特別なOSGiのインポートは必要ありません。

外部アダプターの設定

keycloak.json アダプターの設定ファイルをWARアプリケーションの中にバンドルするのではなく、外部で使用可能にし、命名規則に基づいてロードする場合は、この設定方法を使用してください。

この機能を有効にするには、次のセクションを /WEB_INF/web.xml ファイルに追加してください。

<context-param>
    <param-name>keycloak.config.resolver</param-name>
    <param-value>org.keycloak.adapters.osgi.PathBasedKeycloakConfigResolver</param-value>
</context-param>

そのコンポーネントは、 keycloak.config または karaf.etc のjavaプロパティーを使って基本フォルダーを検索し、設定を探します。そして、見つけたフォルダーの中で <your_web_context>-keycloak.json というファイルを探します。

たとえば、Webアプリケーションにコンテキスト my-portal がある場合、アダプターの設定は $FUSE_HOME/etc/my-portal-keycloak.json ファイルからロードされます。

OSGIサービスとしてデプロイされたサーブレットのセキュリティー保護

クラシックなWARアプリケーションとしてデプロイされていないOSGIバンドルされたプロジェクト内にサーブレット・クラスがある場合、この方式を使用できます。 FuseはPax Web Whiteboard Extenderを使用して、サーブレットをWebアプリケーションとしてデプロイします。

Keycloakでサーブレットをセキュリティー保護するには、次の手順を実行します。

  1. Keycloak provides org.keycloak.adapters.osgi.undertow.PaxWebIntegrationService, which allows configuring authentication method and security constraints for your application. You need to declare such services in the OSGI-INF/blueprint/blueprint.xml file inside your application. Note that your servlet needs to depend on it. An example configuration:

    <?xml version="1.0" encoding="UTF-8"?>
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
    
        <bean id="servletConstraintMapping" class="org.keycloak.adapters.osgi.PaxWebSecurityConstraintMapping">
            <property name="roles">
                <list>
                    <value>user</value>
                </list>
            </property>
            <property name="authentication" value="true"/>
            <property name="url" value="/product-portal/*"/>
        </bean>
    
        <!-- This handles the integration and setting the login-config and security-constraints parameters -->
        <bean id="keycloakPaxWebIntegration" class="org.keycloak.adapters.osgi.undertow.PaxWebIntegrationService"
              init-method="start" destroy-method="stop">
            <property name="bundleContext" ref="blueprintBundleContext" />
            <property name="constraintMappings">
                <list>
                    <ref component-id="servletConstraintMapping" />
                </list>
            </property>
        </bean>
    
        <bean id="productServlet" class="org.keycloak.example.ProductPortalServlet" depends-on="keycloakPaxWebIntegration" />
    
        <service ref="productServlet" interface="javax.servlet.Servlet">
            <service-properties>
                <entry key="alias" value="/product-portal" />
                <entry key="servlet-name" value="ProductServlet" />
                <entry key="keycloak.config.file" value="/keycloak.json" />
            </service-properties>
        </service>
    </blueprint>
    • You might need to have the WEB-INF directory inside your project (even if your project is not a web application) and create the /WEB-INF/keycloak.json file as described in the Classic WAR application section. Note you don’t need the web.xml file as the security-constraints are declared in the blueprint configuration file.

  2. Fuse 6アダプターとは異なり、MANIFEST.MFには特別なOSGiのインポートは必要ありません。

Apache Camelアプリケーションのセキュリティー保護

You can secure Apache Camel endpoints implemented with the camel-undertow component by injecting the proper security constraints via blueprint and updating the used component to undertow-keycloak. You have to add the OSGI-INF/blueprint/blueprint.xml file to your Camel application with a similar configuration as below. The roles and security constraint mappings, and adapter configuration might differ slightly depending on your environment and needs.

Compared to the standard undertow component, undertow-keycloak component adds two new properties:

  • configResolver is a bean that supplies Keycloak configuration file to:

  • org.keycloak.adapters.osgi.BundleBasedKeycloakConfigResolver: the Keycloak adapter configuration will be looked up inside the bundle and should be stored in WEB-INF/keycloak.json file.

  • org.keycloak.adapters.osgi.PathBasedKeycloakConfigResolver: the Keycloak adapter configuration will be looked up as described in External adapter configuration.

  • allowedRoles is a comma-separated list of roles. User accessing the service has to have at least one role to be permitted the access.

例:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:camel="http://camel.apache.org/schema/blueprint"
           xsi:schemaLocation="
       http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
       http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint-2.17.1.xsd">

    <bean id="keycloakConfigResolver" class="org.keycloak.adapters.osgi.BundleBasedKeycloakConfigResolver" >
        <property name="bundleContext" ref="blueprintBundleContext" />
    </bean>

    <bean id="helloProcessor" class="org.keycloak.example.CamelHelloProcessor" />

    <camelContext id="blueprintContext"
                  trace="false"
                  xmlns="http://camel.apache.org/schema/blueprint">

        <route id="httpBridge">
            <from uri="undertow-keycloak:http://0.0.0.0:8383/admin-camel-endpoint?matchOnUriPrefix=true&amp;configResolver=#keycloakConfigResolver&amp;allowedRoles=admin" />
            <process ref="helloProcessor" />
            <log message="The message from camel endpoint contains ${body}"/>
        </route>

    </camelContext>

</blueprint>
  • META-INF/MANIFEST.MFImport-Package には、以下のインポートが含まれている必要があります。

javax.servlet;version="[3,4)",
javax.servlet.http;version="[3,4)",
javax.net.ssl,
org.apache.camel.*,
org.apache.camel;version="[2.13,3)",
io.undertow.*,
org.keycloak.*;version="4.0.0.Final",
org.osgi.service.blueprint,
org.osgi.service.blueprint.container
Camel RestDSL

Camel RestDSLは、流暢な方法でRESTエンドポイントを定義するために使用されるCamelの機能です。しかし、依然として特定の実装クラスを使用し、Keycloakとの統合方法に関する指示を提供する必要があります。

統合機構を設定する方法は、RestDSLで定義されたルートを設定するCamelコンポーネントによって異なります。

The following example shows how to configure integration using the undertow-keycloak component, with references to some of the beans defined in previous Blueprint example.

<camelContext id="blueprintContext"
              trace="false"
              xmlns="http://camel.apache.org/schema/blueprint">

    <!--the link with Keycloak security handlers happens by using undertow-keycloak component -->
    <restConfiguration apiComponent="undertow-keycloak" contextPath="/restdsl" port="8484">
        <endpointProperty key="configResolver" value="#keycloakConfigResolver" />
        <endpointProperty key="allowedRoles" value="admin,superadmin" />
    </restConfiguration>

    <rest path="/hello" >
        <description>Hello rest service</description>
        <get uri="/{id}" outType="java.lang.String">
            <description>Just a hello</description>
            <to uri="direct:justDirect" />
        </get>

    </rest>

    <route id="justDirect">
        <from uri="direct:justDirect"/>
        <process ref="helloProcessor" />
        <log message="RestDSL correctly invoked ${body}"/>
        <setBody>
            <constant>(__This second sentence is returned from a Camel RestDSL endpoint__)</constant>
        </setBody>
    </route>

</camelContext>
Securing an Apache CXF Endpoint on a Separate Undertow Engine

To run your CXF endpoints secured by Keycloak on a separate Undertow engine, complete the following steps:

  1. Add OSGI-INF/blueprint/blueprint.xml to your application, and in it, add the proper configuration resolver bean similarly to Camel configuration. In the httpu:engine-factory declare org.keycloak.adapters.osgi.undertow.CxfKeycloakAuthHandler handler using that camel configuration. The configuration for a CFX JAX-WS application might resemble this one:

    <?xml version="1.0" encoding="UTF-8"?>
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:jaxws="http://cxf.apache.org/blueprint/jaxws"
               xmlns:cxf="http://cxf.apache.org/blueprint/core"
               xmlns:httpu="http://cxf.apache.org/transports/http-undertow/configuration".
               xsi:schemaLocation="
          http://cxf.apache.org/transports/http-undertow/configuration http://cxf.apache.org/schemas/configuration/http-undertow.xsd
          http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
          http://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsd">
    
        <bean id="keycloakConfigResolver" class="org.keycloak.adapters.osgi.BundleBasedKeycloakConfigResolver" >
            <property name="bundleContext" ref="blueprintBundleContext" />
        </bean>
    
        <httpu:engine-factory bus="cxf" id="kc-cxf-endpoint">
            <httpu:engine port="8282">
                <httpu:handlers>
                    <bean class="org.keycloak.adapters.osgi.undertow.CxfKeycloakAuthHandler">
                        <property name="configResolver" ref="keycloakConfigResolver" />
                    </bean>
                </httpu:handlers>
            </httpu:engine>
        </httpu:engine-factory>
    
        <jaxws:endpoint implementor="org.keycloak.example.ws.ProductImpl"
                        address="http://localhost:8282/ProductServiceCF" depends-on="kc-cxf-endpoint"/>
    
    </blueprint>

    CXFのJAX-RSアプリケーションの場合、engine-factortyに依存するエンドポイントの設定にのみ違いがあります。

    <jaxrs:server serviceClass="org.keycloak.example.rs.CustomerService" address="http://localhost:8282/rest"
        depends-on="kc-cxf-endpoint">
        <jaxrs:providers>
            <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />
        </jaxrs:providers>
    </jaxrs:server>
  2. META-INF/MANIFEST.MFImport-Package は以下のインポートを含まなければなりません。

META-INF.cxf;version="[2.7,3.3)",
META-INF.cxf.osgi;version="[2.7,3.3)";resolution:=optional,
org.apache.cxf.bus;version="[2.7,3.3)",
org.apache.cxf.bus.spring;version="[2.7,3.3)",
org.apache.cxf.bus.resource;version="[2.7,3.3)",
org.apache.cxf.transport.http;version="[2.7,3.3)",
org.apache.cxf.*;version="[2.7,3.3)",
org.springframework.beans.factory.config,
org.keycloak.*;version="4.0.0.Final"
デフォルトのJettyエンジンでのApache CXFエンドポイントの保護

Some services automatically come with deployed servlets on startup. One such service is the CXF servlet running in the http://localhost:8181/cxf context. Securing such endpoints can be complicated. One approach, which Keycloak is currently using, is ServletReregistrationService which undeploys a built-in servlet at startup, enabling you to redeploy it on a context secured by Keycloak.

アプリケーション内の設定ファイル OSGI-INF/blueprint/blueprint.xml は、以下のようになります。JAX-RSの customerservice エンドポイント(アプリケーション固有のエンドポイント)を追加しますが、もっと重要なのは、 /cxf コンテキスト全体をセキュリティー保護することです。

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
           xsi:schemaLocation="
                http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
                http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd">

    <!-- JAXRS Application -->

    <bean id="customerBean" class="org.keycloak.example.rs.CxfCustomerService" />

    <jaxrs:server id="cxfJaxrsServer" address="/customerservice">
        <jaxrs:providers>
            <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />
        </jaxrs:providers>
        <jaxrs:serviceBeans>
            <ref component-id="customerBean" />
        </jaxrs:serviceBeans>
    </jaxrs:server>


    <!-- Securing of whole /cxf context by unregister default cxf servlet from paxweb and re-register with applied security constraints -->
    <bean id="cxfConstraintMapping" class="org.keycloak.adapters.osgi.PaxWebSecurityConstraintMapping">
        <!-- user accessing the servise has to have at least one of the following roles -->
        <property name="roles">
            <list>
                <value>user</value>
            </list>
        </property>
        <property name="url" value="/cxf/*" />
        <property name="authentication" value="true"/>
    </bean>

    <bean id="cxfKeycloakPaxWebIntegration" class="org.keycloak.adapters.osgi.undertow.PaxWebIntegrationService"
          init-method="start" destroy-method="stop">
        <property name="bundleContext" ref="blueprintBundleContext" />
        <property name="constraintMappings">
            <list>
                <ref component-id="cxfConstraintMapping" />
            </list>
        </property>
    </bean>

    <bean id="defaultCxfReregistration" class="org.keycloak.adapters.osgi.ServletReregistrationService" depends-on="cxfKeycloakPaxWebIntegration"
          init-method="start" destroy-method="stop">
        <property name="bundleContext" ref="blueprintBundleContext" />
        <property name="managedServiceReference">
            <reference interface="org.osgi.service.cm.ManagedService" filter="(service.pid=org.apache.cxf.osgi)" timeout="5000"  />
        </property>
    </bean>

</blueprint>

As a result, all other CXF services running on the default CXF HTTP destination are also secured. Similarly, when the application is undeployed, the entire /cxf context becomes unsecured as well. For this reason, use your own undertow engine for your applications as described in Secure CXF Application on separate Undertow Engine since that gives you more control over security for each individual application.

  • The WEB-INF directory might need to be inside your project (even if your project is not a web application). You might also need to edit the /WEB-INF/keycloak.json file similarly to Classic WAR application. Note that you do not need the web.xml file as the security constraints are declared in the blueprint configuration file.

  • META-INF/MANIFEST.MFImport-Package は、少なくとも以下のインポートを含んでいなければなりません。

javax.ws.rs;version="[2,3)",
META-INF.cxf;version="[2.7,3.3)",
META-INF.cxf.osgi;version="[2.7,3.3)";resolution:=optional,
org.apache.cxf.transport.http;version="[2.7,3.3)",
org.apache.cxf.*;version="[2.7,3.3)",
com.fasterxml.jackson.jaxrs.json;version="${jackson.version}",
org.keycloak.*;version="${project.version}",
Fuse管理サービスのセキュリティー保護
FuseターミナルへのSSH認証の使用

Keycloakは、主にWebアプリケーションの認証のユースケースを扱います。ただし、他のWebサービスやアプリケーションがKeycloakで保護されている場合は、KeycloakのクレデンシャルでSSHなどのWeb以外の管理サービスを保護するのが最善の方法です。これは、Keycloakへのリモート接続を許可し、リソース・オーナー・パスワード・クレデンシャルに基づいてクレデンシャルを検証するJAASログイン・モジュールを使用して実行できます。

SSH認証を有効にするには、次の手順を実行します。

  1. Keycloakでは、SSH認証に使用されるクライアント(たとえば、 ssh-jmx-admin-client )を作成します。このクライアントでは、 Direct Access Grants EnabledOn に選択されている必要があります。

  2. $FUSE_HOME/etc/org.apache.karaf.shell.cfg ファイルで、次のとおりにこのプロパティーを更新または指定します。

    sshRealm=keycloak
  3. Add the $FUSE_HOME/etc/keycloak-direct-access.json file with content similar to the following (based on your environment and Keycloak client settings):

    {
        "realm": "demo",
        "resource": "ssh-jmx-admin-client",
        "ssl-required" : "external",
        "auth-server-url" : "http://localhost:8080/auth",
        "credentials": {
            "secret": "password"
        }
    }

    このファイルでは、JAASの DirectAccessGrantsLoginModule がSSH認証のために keycloak JAASレルムから使用するクライアント・アプリケーションの設定を指定します。

  4. Fuseを起動し、 keycloak のJAASレルムをインストールしてください。最も簡単な方法は、JAASレルムがあらかじめ定義された keycloak-jaas 機能をインストールすることです。独自の keycloak JAASレルムを使用して、より高いランクでその機能の定義済みレルムを上書きすることができます。詳細については、 JBoss Fuse documentation を参照してください。

    Fuseターミナルで次のコマンドを使用します。

    features:addurl mvn:org.keycloak/keycloak-osgi-features/4.0.0.Final/xml/features
    features:install keycloak-jaas
  5. SSHで admin ユーザーとしてログインするには、ターミナルで次のように入力します。

    ssh -o PubkeyAuthentication=no -p 8101 admin@localhost
  6. パスワードは password でログインしてください。

最近のオペレーティング・システムでは、SSHコマンドの-oオプション -o HostKeyAlgorithms=+ssh-dss を使用する必要があります。これは、最近のSSHクライアントではデフォルトで ssh-dss アルゴリズムの使用は許可されていないためです。しかし、JBoss Fuse 7.0.1では現在デフォルトで使用されています。

Note that the user needs to have realm role admin to perform all operations or another role to perform a subset of operations (for example, the viewer role that restricts the user to run only read-only Karaf commands). The available roles are configured in $FUSE_HOME/etc/org.apache.karaf.shell.cfg or $FUSE_HOME/etc/system.properties.

JMX認証の使用

jconsoleまたは別の外部ツールを使用してRMI経由でJMXにリモート接続する場合は、JMX認証が必要になることがあります。そうでなければ、jolokiaエージェントがデフォルトでhawt.ioにインストールされているので、hawt.io/jolokiaを使用する方が良いかもしれません。詳細については、Hawtio Admin Consoleを参照してください。

JMX認証を使用するには、次の手順を実行します。

  1. $FUSE_HOME/etc/org.apache.karaf.management.cfg ファイルで、 jmxRealm プロパティーを次のように変更します。

    jmxRealm=keycloak
  2. 上記のSSHのセクションで説明したように、 keycloak-jaas フィーチャーをインストールし、 $FUSE_HOME/etc/keycloak-direct-access.json ファイルを設定してください。

  3. jconsoleでは、次のようなURLを使用できます。

service:jmx:rmi://localhost:44444/jndi/rmi://localhost:1099/karaf-root

クレデンシャルはadmin/password(利用環境の管理者権限を持つユーザー次第)です。

Hawtio管理コンソールのセキュリティー保護

Keycloakを使用して、Hawtio管理コンソールをセキュリティー保護するには、以下の手順を実行します。

  1. Create a client in the Keycloak administration console in your realm. For example, in the Keycloak demo realm, create a client hawtio-client, specify public as the Access Type, and specify a redirect URI pointing to Hawtio: http://localhost:8181/hawtio/*. You must also have a corresponding Web Origin configured (in this case, http://localhost:8181).

  2. $FUSE_HOME/etc ディレクトリーに keycloak-hawtio-client.json ファイルを作成します。このファイルは、以下の例のような内容で作成します。Keycloak環境に応じて、 realmresourceauth-server-url の各プロパティーを変更してください。 resource プロパティーは前のステップで作成されたクライアントを指し示さなければなりません。このファイルは、クライアント(Hawtio JavaScriptアプリケーション)側で使用されます。

    {
      "realm" : "demo",
      "clientId" : "hawtio-client",
      "url" : "http://localhost:8080/auth",
      "ssl-required" : "external",
      "public-client" : true
    }
  3. $FUSE_HOME/etc ディレクトリーに keycloak-direct-access.json ファイルを作成します。このファイルは、以下の例のような内容です。Keycloakの環境に応じて realmurl プロパティーを変更してください。このファイルは、JavaScriptクライアントによって使用されます。

    {
      "realm" : "demo",
      "resource" : "ssh-jmx-admin-client",
      "auth-server-url" : "http://localhost:8080/auth",
      "ssl-required" : "external",
      "credentials": {
        "secret": "password"
      }
    }
  4. $FUSE_HOME/etc ディレクトリーに keycloak-bearer.json ファイルを作成します。このファイルは、以下の例のような内容です。Keycloakの環境に応じて realmauth-server-url プロパティーを変更してください。このファイルは、サーバー(JAASログイン・モジュール)側のアダプターによって使用されます。

    {
      "realm" : "demo",
      "resource" : "jaas",
      "bearer-only" : true,
      "auth-server-url" : "http://localhost:8080/auth",
      "ssl-required" : "external",
      "use-resource-role-mappings": false,
      "principal-attribute": "preferred_username"
    }
  5. JBoss Fuse 7.0.1を開始し、Keycloak featureをインストールします。次に以下をKarafターミナルに入力してください。

    system:property hawtio.keycloakEnabled true
    system:property hawtio.realm keycloak
    system:property hawtio.keycloakClientConfig file://\${karaf.base}/etc/keycloak-hawtio-client.json
    system:property hawtio.rolePrincipalClasses org.keycloak.adapters.jaas.RolePrincipal,org.apache.karaf.jaas.boot.principal.RolePrincipal
    restart io.hawt.hawtio-war
  6. http://localhost:8181/hawtio に移動し、Keycloakのレルムからユーザーとしてログインします。

    Note that the user needs to have the proper realm role to successfully authenticate to Hawtio. The available roles are configured in the $FUSE_HOME/etc/system.properties file in hawtio.roles.

2.1.6. Spring Bootアダプター

Spring Bootアプリケーションをセキュリティー保護するには、Keycloak Spring BootアダプターJARをアプリケーションに追加する必要があります。通常のSpring Bootの設定( application.properties )でいくつかの設定を追加する必要があります。これらの手順について説明します。

アダプターのインストール

Keycloak Spring Bootアダプターは、Spring Bootの自動設定を利用するので、Keycloak Spring Boot Starterをプロジェクトに追加するだけです。Keycloak Spring Boot Starterも Spring Start Pageから直接入手できます。Mavenを使用していて手動で追加するためには、依存関係に以下を追加します。

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>

アダプターのBOM依存関係も追加して下さい。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.keycloak.bom</groupId>
      <artifactId>keycloak-adapter-bom</artifactId>
      <version>4.0.0.Final</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

現在、次の組み込みコンテナーがサポートされており、Starterを使用する場合は特別な依存関係は必要ありません。

  • Tomcat

  • Undertow

  • Jetty

必要なSpring Bootアダプターの設定

このセクションでは、Keycloakを使用するようにSpring Bootアプリケーションを設定する方法について説明します。

keycloak.json ファイルの代わりに、通常のSpring Bootの設定を使って、Spring Boot Keycloakアダプターに対するレルムを設定します。例を以下に示します。

keycloak.realm = demorealm
keycloak.auth-server-url = http://127.0.0.1:8080/auth
keycloak.ssl-required = external
keycloak.resource = demoapp
keycloak.credentials.secret = 11111111-1111-1111-1111-111111111111
keycloak.use-resource-role-mappings = true

keycloak.enabled = false を設定することで、Keycloak Spring Bootアダプターを無効にすることができます(テストなどで)。

Policy Enforcerを設定するには、keycloak.jsonとは異なり、 policy-enforcer の代わりに policy-enforcer-config を使用する必要があります。

また、通常は web.xml に記述するJava EEのセキュリティー設定を指定する必要があります。 Spring Bootアダプターは login-methodKEYCLOAK に設定し、起動時に security-constraints を設定します。 次に設定例を示します。

keycloak.securityConstraints[0].authRoles[0] = admin
keycloak.securityConstraints[0].authRoles[1] = user
keycloak.securityConstraints[0].securityCollections[0].name = insecure stuff
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /insecure

keycloak.securityConstraints[1].authRoles[0] = admin
keycloak.securityConstraints[1].securityCollections[0].name = admin stuff
keycloak.securityConstraints[1].securityCollections[0].patterns[0] = /admin
SpringアプリケーションをWARとしてデプロイする予定の場合は、Spring Bootアダプターを使用せず、使用しているアプリケーション・サーバーまたはサーブレット・コンテナーの専用アダプターを使用してください。Spring Bootには web.xml ファイルも含まれていなければなりません。

2.1.7. Tomcat 6、7、8アダプター

Tomcat 6、7、8にデプロイされたWARアプリケーションをセキュリティー保護するには、Keycloak Tomcat 6、7、8 アダプターをTomcatにインストールする必要があります。その後、TomcatにデプロイするWARにもいくつかの設定を行う必要があります。これらの手順について説明します。

アダプターのインストール

アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。

アダプターの配布物をTomcatの lib/ ディレクトリーに解凍する必要があります。WEB-INF/libディレクトリー内にアダプターのjarを含めても動作しません!KeycloakアダプターはValveとして実装され、ValveのコードはTomcatのメインのlib/ディレクトリーに存在する必要があります。

$ cd $TOMCAT_HOME/lib
$ unzip keycloak-tomcat6-adapter-dist.zip
    or
$ unzip keycloak-tomcat7-adapter-dist.zip
    or
$ unzip keycloak-tomcat8-adapter-dist.zip
WARごとに必要な設定

このセクションでは、直接WARパッケージ内にconfigファイルを追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。

まず、WARパッケージに META-INF/context.xml ファイルを作成します。 これはTomcat固有の設定ファイルであり、Keycloak固有のValveを定義する必要があります。

<Context path="/your-context-path">
    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
</Context>

次に、WARの WEB-INF ディレクトリーに keycloak.json アダプター設定ファイルを作成しておく必要があります。

この設定ファイルの形式はJavaアダプターの設定で説明しています。

最後に、URLに対してロールベース制約を指定するために、 login-config と標準のサーブレット・セキュリティーの両方を指定する必要があります。例を次に示します。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

        <module-name>customer-portal</module-name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customers</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>this is ignored currently</realm-name>
    </login-config>

    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>

2.1.8. Jetty 9.xアダプター

Keycloakには、Jetty 9.1.x、Jetty 9.2.x、Jetty 9.3.x用の個別のアダプターがあります。これらをJettyにインストールする必要があります。Jettyにデプロイする各WARには、さらにいくつかの設定を行う必要があります。これらの手順について説明します。

アダプターのインストール

アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。

Jetty 9.x用の配布物をJetty 9.xのbaseディレクトリーに解凍する必要があります。WEB-INF/libディレクトリー内にアダプターのjarを含めても動作しません!以下の例では、Jettyベースの名前は your-base です。

$ cd your-base
$ unzip keycloak-jetty93-adapter-dist-2.5.0.Final.zip

次に、Jettyベースの keycloak モジュールを有効にする必要があります。

$ java -jar $JETTY_HOME/start.jar --add-to-startd=keycloak
WARごとに必要な設定

このセクションでは、直接WARパッケージ内にconfigファイルを追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。

まず、WARパッケージに WEB-INF/jetty-web.xml ファイルを作成します。これはJetty固有の設定ファイルで、その中にKeycloak固有のAuthenticatorを定義する必要があります。

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
    <Get name="securityHandler">
        <Set name="authenticator">
            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
            </New>
        </Set>
    </Get>
</Configure>

次に、WARの WEB-INF ディレクトリーに keycloak.json アダプター設定ファイルを作成しておく必要があります。

この設定ファイルの形式は、Javaアダプターの設定のセクションで説明しています。

Jetty 9.1.xアダプターは、 keycloak.json ファイルを見つけることができません。下記のように jetty-web.xml ファイル内にすべてのアダプター設定を定義する必要があります。

keycloak.jsonを使用する代わりに、 jetty-web.xml' 内にすべてを定義することができます。 json設定が `org.keycloak.representations.adapters.config.AdapterConfig クラスとどのようにマッチするかを把握する必要があります。

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <Get name="securityHandler">
    <Set name="authenticator">
        <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
            <Set name="adapterConfig">
                <New class="org.keycloak.representations.adapters.config.AdapterConfig">
                    <Set name="realm">tomcat</Set>
                    <Set name="resource">customer-portal</Set>
                    <Set name="authServerUrl">http://localhost:8081/auth</Set>
                    <Set name="sslRequired">external</Set>
                    <Set name="credentials">
                        <Map>
                            <Entry>
                                <Item>secret</Item>
                                <Item>password</Item>
                            </Entry>
                        </Map>
                    </Set>
                </New>
            </Set>
        </New>
    </Set>
  </Get>
</Configure>

KeycloakでWARをセキュリティー保護するために、WARをオープンする必要はありません。代わりに、yourwar.xmlという名前でwebappsディレクトリーにjetty-web.xmlファイルを作成します。Jettyはそれをピックアップします。このモードでは、keycloak.jsonの設定をxmlファイル内で直接宣言する必要があります。

最後に、URLに対してロールベース制約を指定するために、 login-config と標準のサーブレット・セキュリティーの両方を指定する必要があります。例を次に示します。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

        <module-name>customer-portal</module-name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customers</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>this is ignored currently</realm-name>
    </login-config>

    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>

2.1.9. Jetty 8.1.xアダプター

Keycloakには、Jettyのインストール先にインストールする必要のあるJetty 8.1.x用の別のアダプターがあります。Jettyにデプロイする各WARには、さらにいくつかの設定を行う必要があります。これらの手順について説明します。

アダプターのインストール

アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。

You must unzip the Jetty 8.1.x distro into Jetty 8.1.x’s root directory. Including adapter’s jars within your WEB-INF/lib directory will not work!

$ cd $JETTY_HOME
$ unzip keycloak-jetty81-adapter-dist.zip

次に、keycloakオプションを有効にする必要があります。start.iniを編集し、オプションにkeycloakを追加します。

#===========================================================
# Start classpath OPTIONS.
# These control what classes are on the classpath
# for a full listing do
#   java -jar start.jar --list-options
#-----------------------------------------------------------
OPTIONS=Server,jsp,jmx,resources,websocket,ext,plus,annotations,keycloak
WARごとに必要な設定

WARに対してKeycloakを有効にする方法は、Jetty 9.xアダプターと同じです。8.1.xアダプターは、keycloak.jsonとjboss-web.xmlの両方の高度な設定をサポートしています。WARごとに必要な設定を参照してください。

2.1.10. Spring Securityアダプター

Spring SecurityとKeycloakでアプリケーションを保護するには、このアダプターをプロジェクトのdependencyに追加します。Spring Securityの設定ファイルにいくつか追加のBeanを用意し、パイプラインにKeycloakセキュリティー・フィルターを追加する必要があります。

他のKeycloakアダプターとは異なり、web.xmlにセキュリティーを設定しないでください。ただし、 keycloak.json は依然として必要です。

アダプターのインストール

MavenのPOMまたはGradleのbuildに、依存するKeycloak Spring Securityアダプターを追加してください。

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-security-adapter</artifactId>
    <version>4.0.0.Final</version>
</dependency>
Spring Securityの設定

Keycloak Spring Securityアダプターは、Spring Securityの柔軟なセキュリティー設定構文を利用します。

Java設定

Keycloakは、https://docs.spring.io/spring-security/site/docs/4.0.x/apidocs/org/springframework/security/config/annotation/web/WebSecurityConfigurer.html[WebSecurityConfigurer]を作成するための便利な基本クラスとして、 KeycloakWebSecurityConfigurerAdapter を提供します。この実装では、メソッドのオーバーライドによるカスタマイズが可能です。その使用は必須ではありませんが、セキュリティー・コンテキストの設定が大幅に簡素化されます。

@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
    /**
     * Registers the KeycloakAuthenticationProvider with the authentication manager.
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    /**
     * Defines the session authentication strategy.
     */
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        super.configure(http);
        http
                .authorizeRequests()
                .antMatchers("/customers*").hasRole("USER")
                .antMatchers("/admin*").hasRole("ADMIN")
                .anyRequest().permitAll();
    }
}

パブリックまたはコンフィデンシャルなアプリケーションの場合は RegisterSessionAuthenticationStrategy の、bearer-onlyアプリケーションの場合は NullAuthenticatedSessionStrategy のタイプのセッション認証ストラテジーBeanを提供する必要があります。

Keycloak経由でログインした後にセッション識別子を変更するため、Spring Securityの SessionFixationProtectionStrategy は現在サポートされていません。セッション識別子が変更された場合、Keycloakは新しいセッション識別子を認識しないため、ユニバーサル・ログアウトは機能しません。

@KeycloakConfiguration アノテーションは、Spring SecurityでKeycloakを統合するために必要なすべてのアノテーションを定義するメタ・データ・アノテーションです。複雑なSpring Securityの設定をする場合は、 @KeycloakConfiguration アノテーションを参照して、独自のカスタム・メタ・アノテーションを作成してください。もしくは、Keycloakアダプター用の特定のSpringアノテーションを使用してください。
XML設定

Spring SecurityのXML名前空間は設定を簡素化しますが、設定のカスタマイズは少し冗長になる可能性があります。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security.xsd">

    <context:component-scan base-package="org.keycloak.adapters.springsecurity" />

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="keycloakAuthenticationProvider" />
    </security:authentication-manager>

    <bean id="adapterDeploymentContext" class="org.keycloak.adapters.springsecurity.AdapterDeploymentContextFactoryBean">
        <constructor-arg value="/WEB-INF/keycloak.json" />
    </bean>

    <bean id="keycloakAuthenticationEntryPoint" class="org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint" />
    <bean id="keycloakAuthenticationProvider" class="org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider" />
    <bean id="keycloakPreAuthActionsFilter" class="org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter" />
    <bean id="keycloakAuthenticationProcessingFilter" class="org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter">
        <constructor-arg name="authenticationManager" ref="authenticationManager" />
    </bean>

    <bean id="keycloakLogoutHandler" class="org.keycloak.adapters.springsecurity.authentication.KeycloakLogoutHandler">
        <constructor-arg ref="adapterDeploymentContext" />
    </bean>

    <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <constructor-arg name="logoutSuccessUrl" value="/" />
        <constructor-arg name="handlers">
            <list>
                <ref bean="keycloakLogoutHandler" />
                <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
            </list>
        </constructor-arg>
        <property name="logoutRequestMatcher">
            <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
                <constructor-arg name="pattern" value="/sso/logout**" />
                <constructor-arg name="httpMethod" value="GET" />
            </bean>
        </property>
    </bean>

    <security:http auto-config="false" entry-point-ref="keycloakAuthenticationEntryPoint">
        <security:custom-filter ref="keycloakPreAuthActionsFilter" before="LOGOUT_FILTER" />
        <security:custom-filter ref="keycloakAuthenticationProcessingFilter" before="FORM_LOGIN_FILTER" />
        <security:intercept-url pattern="/customers**" access="ROLE_USER" />
        <security:intercept-url pattern="/admin**" access="ROLE_ADMIN" />
        <security:custom-filter ref="logoutFilter" position="LOGOUT_FILTER" />
    </security:http>

</beans>
マルチテナンシー

Keycloak Spring Securityアダプターはマルチテナンシーをサポートしています。 AdapterDeploymentContextFactoryBeankeycloak.json へのパスを注入する代わりに、KeycloakConfigResolver インターフェイスの実装を注入することができます。 KeycloakConfigResolver の実装方法の詳細はマルチテナンシーにあります。

セキュリティー・ロールの命名

Spring Securityで、ロールベースの認証を使用する場合、ロール名は ROLE_ で始まる必要があります。たとえば、管理者のロールは単に ADMIN ではなく、 ROLE_ADMIN または同様のものとして、Keycloakで宣言されなければなりません。

org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider クラスはオプションで org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper をサポートしており、Spring Securityによって認識されるロールにKeycloakから来るロールをマップするために使用することができます。 たとえば、 org.springframework.security.core.authority.mapping.SimpleAuthorityMapper を使用して、接頭辞 ROLE_ を挿入し、ロール名を大文字に変換します。 クラスはSpring Security Coreモジュールの一部です。

クライアント・トゥ・クライアント・サポート

クライアント間の通信を簡素化するために、Keycloakはベアラー・トークン認証を処理するSpringの RestTemplate の拡張を提供します。この機能を有効にするには、セキュリティー設定で KeycloakRestTemplate を追加する必要があります。正しく機能するには、プロトタイプとしてスコープを設定する必要があることに注意してください。

Javaによる設定:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    ...

    @Autowired
    public KeycloakClientRequestFactory keycloakClientRequestFactory;

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public KeycloakRestTemplate keycloakRestTemplate() {
        return new KeycloakRestTemplate(keycloakClientRequestFactory);
    }

    ...
}

XMLによる設定:

<bean id="keycloakRestTemplate" class="org.keycloak.adapters.springsecurity.client.KeycloakRestTemplate" scope="prototype">
    <constructor-arg name="factory" ref="keycloakClientRequestFactory" />
</bean>

アプリケーション・コードは、別のクライアントを呼び出す必要があるときはいつでも、 KeycloakRestTemplate を使うことができます。 次に例を示します。

@Service
public class RemoteProductService implements ProductService {

    @Autowired
    private KeycloakRestTemplate template;

    private String endpoint;

    @Override
    public List<String> getProducts() {
        ResponseEntity<String[]> response = template.getForEntity(endpoint, String[].class);
        return Arrays.asList(response.getBody());
    }
}
Spring Boot統合

Spring BootアダプターとSpring Securityアダプターを組み合わせることができます。

Spring Securityアダプターを使用するために、Keycloak Spring Boot Starterを使用している場合は、Spring Security Starterを追加するだけです。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Boot設定の使用

デフォルトでは、Spring Securityアダプターは keycloak.json 設定ファイルを探します。このBeanを追加することで、Spring Bootアダプターが提供する設定を確認できます。

@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
    return new KeycloakSpringBootConfigResolver();
}
Filter Beanの二重登録を避ける

Spring Bootは、フィルターBeanをWebアプリケーション・コンテキストに登録しようとします。そのため、Spring Boot環境でKeycloak Spring Securityアダプターを実行する場合は、Keycloakフィルターが2回登録されないように、セキュリティー設定に FilterRegistrationBean を追加する必要があります。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
    ...

    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean(
            KeycloakAuthenticatedActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakSecurityContextRequestFilterBean(
        KeycloakSecurityContextRequestFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    ...
}

2.1.11. Javaサーブレット・フィルター・アダプター

KeycloakアダプターがないプラットフォームにJavaサーブレット・アプリケーションをデプロイする場合は、サーブレット・フィルター・アダプターを使用することを選択します。このアダプターは、他のアダプターとは多少動作が異なります。web.xmlにはセキュリティー制約を定義しません。代わりにKeycloakサーブレット・フィルター・アダプターを使用してフィルター・マッピングを定義して、URLパターンでセキュリティー保護します。

バックチャネル・ログアウトは、標準のアダプターとは少し異なります。HTTPセッションを無効にする代わりに、セッションIDをログアウトしたものとしてマークします。セッションIDに基づいてHTTPセッションを無効にする標準的な方法はありません。
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

        <module-name>application</module-name>

    <filter>
        <filter-name>Keycloak Filter</filter-name>
        <filter-class>org.keycloak.adapters.servlet.KeycloakOIDCFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Keycloak Filter</filter-name>
        <url-pattern>/keycloak/*</url-pattern>
        <url-pattern>/protected/*</url-pattern>
    </filter-mapping>
</web-app>

上記のスニペットには2つのURLパターンがあります。 ?/protected/* は保護したいファイルで、/keycloak/* のurl-patternはKeycloakサーバーからのコールバックを処理します。

設定された url-patterns の下にあるいくつかのパスを除外する必要がある場合は、keycloakフィルターが直ちにフィルター・チェーンに委譲すべきパス・パターンを記述する正規表現を設定するために、フィルターのinit-param keycloak.config.skipPattern を使用できます。デフォルトでは、skipPatternは設定されていません。

パターンは コンテキスト・パス なしで requestURI と照合されます。コンテキスト・パス /myapp が与えられると、 /myapp/index.html のリクエストは、スキップ・パターンと /index.html で照合されます。

<init-param>
    <param-name>keycloak.config.skipPattern</param-name>
    <param-value>^/(path1|path2|path3).*</param-value>
</init-param>

Keycloak管理コンソールでクライアントのURLを設定する必要があります。Admin URLは、フィルターのurl-patternで保護されたセクションを指します。

Admin URLは、バックチャネル・ログアウトなどの操作を行うために、管Admin URLへのコールバックを行います。したがって、この例のAdmin URLは http[s]://hostname/{context-root}/keycloak でなければなりません。

Keycloakフィルターは、コンテキスト・パラメーターの代わりにフィルター初期化パラメーターとして定義する必要がある以外は、他のアダプターと同じ設定パラメーターを持ちます。

このフィルタを使用するには、WARのpomに次のmavenアーティファクトを含めます。

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-servlet-filter-adapter</artifactId>
    <version>4.0.0.Final</version>
</dependency>

2.1.12. JAASプラグイン

ほとんどのアプリケーションでJAASを使用する必要はありません。特にHTTPベースのアプリケーションの場合は、JAASを使用する必要はありません。 しかし、一部のアプリケーションやシステムは、依然として純粋なレガシーJAASソリューションに依存している場合があります。Keycloakは、このような状況に役立つ2つのログイン・モジュールを提供します。

提供されるログイン・モジュールは次のとおりです。

org.keycloak.adapters.jaas.DirectAccessGrantsLoginModule

このログイン・モジュールは、Keycloakのユーザー名/パスワードで認証することができます。リソース・オーナー・パスワード・クレデンシャルのフローを使用して、提供されたユーザー名/パスワードが有効かどうかを検証します。JAASに依存する必要があり、Keycloakを使用したい非Webベースのシステムにとっては有益ですが、Web以外の性質のため、標準のブラウザー・ベースのフローを使用することはできません。このようなアプリケーションとして挙げられるのは、メッセージングやSSHです。

org.keycloak.adapters.jaas.BearerTokenLoginModule

このログイン・モジュールでは、パスワードとして CallbackHandler を介して渡されたKeycloakのアクセストークンで認証できます。たとえば、標準ベースの認証フローからKeycloakのアクセストークンを取得し、WebアプリケーションがJAASに依存する外部の非Webベースのシステムと対話する必要がある場合などに便利です。たとえば、メッセージング・システムです。

どちらのモジュールも次の設定プロパティーを使用します。

keycloak-config-file

keycloak.json 設定ファイルの場所。設定ファイルは、ファイルシステム上またはクラスパス上に置くことができます。クラスパス上にある場合は、その場所の前に classpath: を付ける必要があります(たとえば classpath:/path/keycloak.json )。これは 必須 です。

role-principal-class

JAAS Subjectに添付されているロール・プリンシパルの代替クラスを設定します。デフォルト値は org.keycloak.adapters.jaas.RolePrincipal です。注意:クラスには、単一の String 引数を持つコンストラクタが必要です。

2.1.13. CLI / デスクトップ・アプリケーション

Keycloakは、システム・ブラウザーを介して認証ステップを実行することによって、 KeycloakInstalled アダプターを介したデスクトップ(たとえば、Swing、JavaFX)またはCLIアプリケーションのセキュリティー保護をサポートします。

KeycloakInstalled アダプターは、 desktopmanual のバリアントをサポートしています。デスクトップ・バリアントは、システム・クレデンシャルを収集するためにシステム・ブラウザーを使用します。手動バリアントは、ユーザー・クレデンシャルを STDIN から読み込みます。

Tip:Googleは OAuth2InstalledApp で、このアプローチに関する情報を提供しています。

どのように動くか

desktop バリアントを使用してユーザーを認証するために、 KeycloakInstalled アダプターはデスクトップ・ブラウザーのウィンドウを開きます。ここで KeycloakInstalled オブジェクトに対して loginDesktop() メソッドが呼び出されると、ユーザーは通常のKeycloakログインページを使用してログインします。

ログイン・ページのURLは、アダプターによって起動される localhost の空きエフェメラル・ポートをリッスンするローカル ServerSocket を指すリダイレクト・パラメーターでオープンされます。

ログイン成功後、 KeycloakInstalled は受信したHTTPリクエストから認可コードを受け取り、認可コード・フローを実行します。トークンからコードへの交換が完了すると、 ServerSocket はシャットダウンされます。

ユーザーがすでにKeycloakのアクティブなセッションを持っている場合、ログイン・フォームは表示されませんが、コードからトークンへの交換は継続され、スムーズなWebベースのSSO体験が可能になります。

クライアントは、最終的にバックエンド・サービスを呼び出すために使用できるトークン(access_token、refresh_token、id_token)を受け取ります。

KeycloakInstalled アダプターは失効したトークンの更新をサポートします。

アダプターのインストール
<dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-installed-adapter</artifactId>
        <version>4.0.0.Final</version>
</dependency>
クライアントの設定

アプリケーションは、 Standard Flow Enabledpublic なOpenID Connectクライアントであり、許可される Valid Redirect URI としてhttp://localhost:*が設定される必要があります。

使い方

KeycloakInstalled アダプターはクラスパス上の META-INF/keycloak.json から設定を読み込みます。カスタム設定は、 KeycloakInstalled コンストラクタを介して、 InputStream または KeycloakDeployment で提供することができます。

以下の例では、 desktop-app のクライアント設定は keycloak.json を使います。

{
  "realm": "desktop-app-auth",
  "auth-server-url": "http://localhost:8081/auth",
  "ssl-required": "external",
  "resource": "desktop-app",
  "public-client": true,
  "use-resource-role-mappings": true
}

次のスケッチは、 KeycloakInstalled アダプターとの動作を示しています。

// reads the configuration from classpath: META-INF/keycloak.json
KeycloakInstalled keycloak = new KeycloakInstalled();

// opens desktop browser
keycloak.loginDesktop();

AccessToken token = keycloak.getToken();
// use token to send backend request

// ensure token is valid for at least 30 seconds
long minValidity = 30L;
String tokenString = keycloak.getTokenString(minValidity, TimeUnit.SECONDS);


 // when you want to logout the user.
keycloak.logout();
KeycloakInstalled クラスは loginResponseWriter 属性と logoutResponseWriter 属性を介したログイン/ログアウト・リクエストによって、返されたHTTPレスポンスのカスタマイズをサポートしています。

以下に、上記の設定例を示します。

import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.keycloak.adapters.installed.KeycloakInstalled;
import org.keycloak.representations.AccessToken;

public class DesktopApp {

        public static void main(String[] args) throws Exception {

                KeycloakInstalled keycloak = new KeycloakInstalled();
                keycloak.setLocale(Locale.ENGLISH);
                keycloak.loginDesktop();

                AccessToken token = keycloak.getToken();
                Executors.newSingleThreadExecutor().submit(() -> {

                        System.out.println("Logged in...");
                        System.out.println("Token: " + token.getSubject());
                        System.out.println("Username: " + token.getPreferredUsername());
                        try {
                                System.out.println("AccessToken: " + keycloak.getTokenString());
                        } catch (Exception ex) {
                                ex.printStackTrace();
                        }

                        int timeoutSeconds = 20;
                        System.out.printf("Logging out in...%d Seconds%n", timeoutSeconds);
                        try {
                                TimeUnit.SECONDS.sleep(timeoutSeconds);
                        } catch (Exception e) {
                                e.printStackTrace();
                        }

                        try {
                                keycloak.logout();
                        } catch (Exception e) {
                                e.printStackTrace();
                        }

                        System.out.println("Exiting...");
                        System.exit(0);
                });
        }
}

2.1.14. セキュリティー・コンテキスト

KeycloakSecurityContext インターフェイスはトークンに直接アクセスする必要がある場合に利用できます。これは、トークンから追加の詳細情報(ユーザー・プロファイル情報など)を取得する場合や、Keycloakによって保護されているRESTfulサービスを呼び出す場合に便利です。

サーブレット環境では、セキュアな呼び出しで HttpServletRequest の属性として以下のようにセキュリティー・コンテキストを利用できます。

httpServletRequest
    .getAttribute(KeycloakSecurityContext.class.getName());

または、セキュアでないリクエストでは以下のように HttpSession からセキュリティー・コンテキストを利用できます。

httpServletRequest.getSession()
    .getAttribute(KeycloakSecurityContext.class.getName());

2.1.15. エラー処理

Keycloakには、サーブレットベースのクライアント・アダプター用のエラー処理機能があります。認証でエラーが発生すると、Keycloakは HttpServletResponse.sendError() を呼び出します。 web.xml ファイル内にerror-pageを設定してエラーを処理することができます。Keycloakは400、401、403、500のエラーをスローできます。

<error-page>
    <error-code>403</error-code>
    <location>/ErrorHandler</location>
</error-page>

Keycloakはまた、取得可能な HttpServletRequest 属性を設定します。属性名は、 org.keycloak.adapters.spi.AuthenticationError です。これは org.keycloak.adapters.OIDCAuthenticationError にキャストする必要があります。

例:

import org.keycloak.adapters.OIDCAuthenticationError;
import org.keycloak.adapters.OIDCAuthenticationError.Reason;
...

OIDCAuthenticationError error = (OIDCAuthenticationError) httpServletRequest
    .getAttribute('org.keycloak.adapters.spi.AuthenticationError');

Reason reason = error.getReason();
System.out.println(reason.name());

2.1.16. ログアウト

Webアプリケーションからログアウトする方法は複数あります。Java EEサーブレット・コンテナーの場合、HttpServletRequest.logout()を呼び出すことができます。他のブラウザー・アプリケーションでブラウザーのSSOセッションがある場合は、 http://auth-server/auth/realms/{realm-name}/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri にリダイレクトすることでログアウトできます。

2.1.17. パラメーター・フォワーディング

Keycloakの初期認可エンドポイント・リクエストは、さまざまなパラメーターをサポートしています。ほとんどのパラメータは OIDC仕様 に記述されています。一部のパラメーターは、アダプターの設定に基づいて、アダプターにより自動的に追加されます。ただし、呼び出しごとに追加できるパラメーターもいくつかあります。保護されたアプリケーションURIにアクセスすると、特定のパラメーターはKeycloak認可エンドポイントにフォワードされます。

たとえば、オフライントークンを要求する場合、以下のように scope パラメーターを使用して保護されたアプリケーションのURIにアクセスできます。

http://myappserver/mysecuredapp?scope=offline_access

パラメーター scope=offline_access が自動的にKeycloak認可エンドポイントにフォワードされます。

サポートされるパラメーターは次のとおりです。

  • scope - Use a space-delimited list of scopes. A space-delimited list typically references Client scopes defined on particular client. Note that the scope openid will be always be added to the list of scopes by the adapter. For example, if you enter the scope options address phone, then the request to Keycloak will contain the scope parameter scope=openid address phone.

  • prompt - Keycloak supports these settings: login - SSO will be ignored and the Keycloak login page will be always shown, even if the user is already authenticated none - The login page will never be shown; instead the user will be redirected to the application, with an error if the user is not yet authenticated. This setting allows you to create a filter/interceptor on the application side and show a custom error page to the user. See more details in the specification.

  • max_age - Used only if a user is already authenticated. Specifies maximum permitted time for the authentication to persist, measured from when the user authenticated. If user is authenticated longer than maxAge, the SSO is ignored and he must re-authenticate.

  • login_hint - Used to pre-fill the username/email field on the login form.

  • kc_idp_hint - Used to tell Keycloak to skip showing login page and automatically redirect to specified identity provider instead. More info in the Identity Provider documentation.

ほとんどのパラメーターは OIDC仕様 に記載されています。唯一の例外はパラメーター kc_idp_hint です。これはKeycloak固有で、自動的に使用するアイデンティティー・プロバイダーの名前を含んでいます。詳細はServer Administration Guideアイデンティティー・ブローカリング のセクションを参照してください。

If you open the URL using the attached parameters, the adapter will not redirect you to Keycloak if you are already authenticated in the application. For example, opening http://myappserver/mysecuredapp?prompt=login will not automatically redirect you to the Keycloak login page if you are already authenticated to the application mysecredapp . This behavior may be changed in the future.

2.1.18. クライアント認証

When a confidential OIDC client needs to send a backchannel request (for example, to exchange code for the token, or to refresh the token) it needs to authenticate against the Keycloak server. By default, there are three ways to authenticate the client: client ID and client secret, client authentication with signed JWT, or client authentication with signed JWT using client secret.

クライアントIDとクライアント・シークレット

これは、OAuth2の仕様で説明されている伝統的な方法です。クライアントにはシークレットがあり、アダプター(アプリケーション)とKeycloakサーバーの両方に知られている必要があります。Keycloak管理コンソールで特定のクライアントのシークレットを生成し、このシークレットをアプリケーション側の keycloak.json ファイルに以下のように貼り付けます。

"credentials": {
    "secret": "19666a4f-32dd-4049-b082-684c74115f28"
}
署名付きJWTによるクライアント認証

これは RFC7523 の仕様に基づいています。以下の方法で動作します。

  • クライアントには秘密鍵と証明書が必要です。Keycloakの場合、これは伝統的な keystore ファイルから利用できます。これはクライアント・アプリケーションのクラスパスかファイルシステムのどこかで利用できます。

  • クライアント・アプリケーションが開始されると、 http://myhost.com/myapp/k_jwks のようなURLを使った JWKS 形式の公開鍵のダウンロードが許可されます。 http://myhost.com/myapp はクライアント・アプリケーションのベースURLであることを前提としています。このURLはKeycloakにより使用されます(下記参照)。

  • 認証中に、クライアントはJWTトークンを生成し、その秘密鍵で署名し、 client_assertion パラメーターとともに特定のバックチャネル・リクエスト(たとえば、コードからトークンへの交換リクエスト)をKeycloakに送信します。

  • Keycloakは、JWTの署名を検証できるように、クライアントの公開鍵または証明書を持っていなければなりません。Keycloakでは、クライアントのクライアント・クレデンシャルを設定する必要があります。まず、管理コンソールの Credentials タブでクライアントを認証する方法として、 Signed JWT を選択する必要があります。そして、次のどちらかを選択することができます。 Keycloakがクライアントの公開鍵をダウンロードできるJWKS URLを設定します。これは http://myhost.com/myapp/k_jwks のようなURLです(詳細は上記を参照)。クライアントはいつでもキーをローテーションさせることができるので、このオプションは最も柔軟です。Keycloakは、設定を変更することなく、必要なときに常に新しいキーをダウンロードします。より正確には、Keycloakは、未知の kid (Key ID)で署名されたトークンを見ると、新しい鍵をダウンロードします。 クライアントの公開鍵または証明書を、PEM形式、JWK形式、またはキーストアからアップロードします。このオプションを使用すると、公開鍵はハードコードされるので、クライアントが新しい鍵ペアを生成するときに変更する必要があります。独自のキーストアがない場合は、Keycloak管理コンソールから独自のキーストアを生成することもできます。Keycloak管理コンソールの設定方法の詳細については、 Server Administration Guide を参照してください。

アダプター側でセットアップするには、 keycloak.json ファイルに次のようなものが必要です。

"credentials": {
  "jwt": {
    "client-keystore-file": "classpath:keystore-client.jks",
    "client-keystore-type": "JKS",
    "client-keystore-password": "storepass",
    "client-key-password": "keypass",
    "client-key-alias": "clientkey",
    "token-expiration": 10
  }
}

この設定では、キーストア・ファイル keystore-client.jks がWARのクラスパス上で利用可能でなければなりません。 classpath: というプレフィックスを使用しない場合は、クライアント・アプリケーションが実行されているファイルシステム上のファイルを指すことができます。

インスピレーションのために、 product-portal アプリケーションのデモのサンプル配布物を見てみることができます。

Client Authentication with Signed JWT using Client Secret

This is the same as Client Authentication with Signed JWT except for using the client secret instead of the private key and certificate.

The client has a secret, which needs to be known to both the adapter (application) and the Keycloak server. You need to choose Signed JWT with Client Secret as the method of authenticating your client in the tab Credentials in administration console, and then paste this secret into the keycloak.json file on the application side:

"credentials": {
  "secret-jwt": {
    "secret": "19666a4f-32dd-4049-b082-684c74115f28"
  }
}
独自のクライアント認証方式の追加

独自のクライアント認証方式を追加することもできます。クライアントサイドとサーバーサイドの両方のプロバイダーを実装する必要があります。詳細はServer Developer GuideAuthentication SPI のセクションを参照してください。

2.1.19. マルチテナンシー

マルチテナンシーとは、単一のターゲット・アプリケーション(WAR)が複数のKeycloakのレルムで保護されることを意味します。レルムは、同じKeycloakインスタンスまたは異なるインスタンスに配置できます。

実際には、これはアプリケーションが複数の keycloak.json アダプター設定ファイルを持つ必要があることを意味します。

さまざまなコンテキストパスに異なるアダプター設定ファイルをデプロイして、WARの複数のインスタンスを作成することができます。しかし、これは不便かもしれませんし、コンテキストパス以外のものに基づいてレルムを選択するようにできます。

Keycloakはカスタムの設定リゾルバーを持つことができるので、各リクエストにどのアダプター設定が使われるかを選ぶことができます。

まずこれを達成するためには、 org.keycloak.adapters.KeycloakConfigResolver の実装を作成する必要があります。たとえば、以下のようになります。

package example;

import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;

public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {

    @Override
    public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
        if (path.startsWith("alternative")) {
            KeycloakDeployment deployment = cache.get(realm);
            if (null == deployment) {
                InputStream is = getClass().getResourceAsStream("/tenant1-keycloak.json");
                return KeycloakDeploymentBuilder.build(is);
            }
        } else {
            InputStream is = getClass().getResourceAsStream("/default-keycloak.json");
            return KeycloakDeploymentBuilder.build(is);
        }
    }

}

また、以下のように web.xmlkeycloak.config.resolver のcontext-paramでどの KeycloakConfigResolver 実装を使うかを設定する必要もあります。

<web-app>
    ...
    <context-param>
        <param-name>keycloak.config.resolver</param-name>
        <param-value>example.PathBasedKeycloakConfigResolver</param-value>
    </context-param>
</web-app>

2.1.20. アプリケーション・クラスタリング

この章では、JBoss EAP、WildFly、またはJBoss ASにデプロイされてクラスター化されたアプリケーションのサポートについて解説します。

アプリケーションが次のような場合には、いくつかのオプションがあります。

  • ステートレスまたはステートフル

  • 分散可能(HTTPセッション・レプリケーション)または分散不可能

  • ロードバランサーによって提供されるスティッキー・セッションに依存する

  • Keycloakと同じドメインでホストされている

クラスタリングを扱うことは、通常のアプリケーションほど簡単ではありません。ブラウザーとサーバーサイド・アプリケーションの両方がKeycloakにリクエストを送信することになるため、ロードバランサーでスティッキー・セッションを有効にするほど簡単ではありません。

ステートレス・トークン・ストア

デフォルトでは、Keycloakによって保護されたWebアプリケーションは、HTTPセッションを使用してセキュリティー・コンテキストを保存します。つまり、スティッキー・セッションを有効にするか、HTTPセッションをレプリケーションする必要があります。

HTTPセッションにセキュリティー・コンテキストを保存する代わりに、これをCookieに保存するようにアダプターを設定することもできます。これは、アプリケーションをステートレスにする場合や、セキュリティー・コンテキストをHTTPセッションに保存したくない場合に便利です。

セキュリティー・コンテキストを保存するためにCookieストアを使用するには、アプリケーションの WEB-INF/keycloak.json を編集して次の行を追加します。

"token-store": "cookie"
token-store のデフォルト値は session です。これにより、セキュリティー・コンテキストがHTTPセッションに保存されます。

Cookieストアを使用する際の制限の1つは、すべてのHTTPリクエストに対して、セキュリティー・コンテキスト全体がCookieに渡されることです。これはパフォーマンスに影響する可能性があります。

もう一つの小さな制限は、シングルサイン・アウトのサポートが限られていることです。アダプターが KEYCLOAK_ADAPTER_STATE クッキーを削除するので、アプリケーション自体からサーブレット・ログアウト( HttpServletRequest.logout )を開始すると、問題なく動作します。 ただし、別のアプリケーションからの初期化されたバックチャネル・ログアウトは、KeycloakによってCookieストアを使用するアプリケーションに伝播されません。したがって、アクセストークンのタイムアウトに短い値(たとえば1分)を使用することをお勧めします。

相対URIの最適化

Keycloakとアプリケーションが同じドメイン(リバース・プロキシーまたはロードバランサーを介して)でホストされているデプロイメントのシナリオでは、クライアント設定で相対URIオプションを使用すると便利です。

相対URIの場合、URIはKeycloakにアクセスするために使用されるURLに関連して解決されます。

たとえば、アプリケーションへのURLが https://acme.org/myapp で、KeycloakへのURLが https://acme.org/auth である場合、 https://acme.org/myapp の代わりにリダイレクトURIの /myapp を使うことができます。

管理者URLの設定

特定のクライアント用の管理者URLは、Keycloak管理コンソールで設定できます。これは、Keycloakサーバーによって、ユーザーのログアウトや取消しポリシーのプッシュなどのさまざまなタスクのバックエンド・リクエストをアプリケーションに送信するために使用されます。

たとえば、バックチャネル・ログアウトの仕組みは次のとおりです。

  1. ユーザーが1つのアプリケーションからログアウト・リクエストを送信します

  2. アプリケーションはKeycloakにログアウト・リクエストを送信します

  3. Keycloakサーバーはユーザー・セッションを無効にします

  4. Keycloakサーバーは、セッションに関連付けられた管理者URLでバックチャネル・リクエストをアプリケーションに送信します

  5. アプリケーションがログアウト・リクエストを受信すると、対応するHTTPセッションが無効になります

管理者URLに ${application.session.host} が含まれていると、HTTPセッションに関連付けられたノードのURLに置き換えられます。

アプリケーション・ノードの登録

前のセクションでは、Keycloakが特定のHTTPセッションに関連付けられたノードにログアウト・リクエストを送信する方法について説明しました。しかし、管理者が管理タスクを登録されている全てのクラスターノードに伝播させたい場合があります。たとえば、新しいnot beforeポリシーをアプリケーションにプッシュする、またはアプリケーションからすべてのユーザーをログアウトする場合などです。

この場合、Keycloakはすべてのアプリケーション・クラスター・ノードを認識する必要があります。これにより、全てのノードにイベントを送信できます。これを達成するために、オート・ディスカバリーのメカニズムをサポートしています。

  1. 新しいアプリケーション・ノードがクラスターに参加すると、Keycloakサーバーに登録リクエストを送信します。

  2. 定期的に設定された間隔で、設定がKeycloakに送信されます

  3. Keycloakサーバーが指定されたタイムアウト時間内に再登録リクエストを受信しなかった場合、Keycloakサーバーは自動的に特定のノードの登録を解除します

  4. また、登録解除リクエストを送信するときに、ノードはKeycloakで登録抹消されます。これは、通常、ノードのシャットダウンまたはアプリケーションのアンデプロイメント中です。アンデプロイメント・リスナーが呼び出されない場合、強制シャットダウンで正しく動作しないことがあります。その結果、自動登録解除が必要になります

スタートアップ登録の送信と定期的な再登録は、クラスター化された一部のアプリケーションでのみ必要なので、デフォルトでは無効になっています。

この機能を有効にするには、アプリケーションの WEB-INF/keycloak.json ファイルを編集し、次の行を追加します。

"register-node-at-startup": true,
"register-node-period": 600,

これは、アダプターが起動時に登録リクエストを送信し、10分ごとに再登録することを意味します。

Keycloak管理コンソールでは、最大ノード再登録タイムアウトを指定できます(アダプター設定から register-node-period より大きい値にする必要があります)。管理コンソールから、クラスター・ノードを手動で追加したり、削除することもできます。自動登録機能を使用したくない場合や、自動登録解除機能を使用しない場合、失効したアプリケーション・ノードを削除する場合に便利です 。

各リクエストのトークンのリフレッシュ

デフォルトでは、アプリケーション・アダプターは期限切れになったときにのみ、アクセストークンを更新します。ただし、リクエストごとにトークンをリフレッシュするようにアダプターを設定することもできます。これは、アプリケーションがKeycloakサーバーにさらに多くのリクエストを送信するため、パフォーマンスに影響を与える可能性があります。

この機能を有効にするには、アプリケーションの WEB-INF/keycloak.json ファイルを編集し、次の行を追加します。

"always-refresh-token": true
これはパフォーマンスに重大な影響を与える可能性があります。ログアウトとnot beforeポリシーを伝播するために、バックチャネル・メッセージに頼ることができない場合にのみ、この機能を有効にしてください。考慮すべきことは、デフォルトではアクセストークンの有効期限が短いので、ログアウトが伝播されなくてもログアウトから数分以内にトークンが期限切れになることです。

2.2. JavaScript Adapter

Keycloakには、HTML5/JavaScriptアプリケーションをセキュリティー保護するために使用可能なクライアント・サイドのJavaScriptライブラリーが付属しています。JavaScriptアダプターには、Cordovaアプリケーションのサポートが組み込まれています。

ライブラリーはKeycloakサーバーの /auth/js/keycloak.js から直接取得することができ、ZIPアーカイブとしても配布されています。

Keycloakサーバーをアップグレードする際に自動的にJavaScriptアダプターが更新されるため、ベスト・プラクティスはKeycloakサーバーからJavaScriptアダプターを直接ロードすることです。そうではなくアダプターをWebアプリケーションにコピーする場合は、サーバーをアップグレードした後に、アダプターもアップグレードするようにしてください。

クライアント・サイドのアプリケーションを使用する際に注意すべき重要な点の1つは、クライアント・サイドのアプリケーションにクライアント・クレデンシャルを安全に保存する方法がないため、クライアントをパブリック・クライアントにする必要があることです。これにより、クライアント用に設定したリダイレクトURIが正しいか、できるだけ具体的であるかを確認することが非常に重要になります。

JavaScriptアダプターを使用するには、まずKeycloak管理コンソールでアプリケーション用のクライアントを作成する必要があります。 Access Typepublic が選択されていることを確認してください。

また、有効なリダイレクトURIと有効なWebオリジンを設定する必要があります。できるだけ具体的にする理由は、そうしなければセキュリティー上の脆弱性が生じる可能性があるためです。

クライアントが作成されたら Installation タブをクリックし、 Format OptionKeycloak OIDC JSON を選択して、 Download をクリックします。ダウンロードした keycloak.json ファイルは、HTMLページと同じ場所にあるWebサーバー上にホストされるべきです。

または、設定ファイルではなく、アダプターを手動で設定することもできます。

次の例は、JavaScriptアダプターを初期化する方法を示しています。

<head>
    <script src="keycloak.js"></script>
    <script>
        var keycloak = Keycloak();
        keycloak.init().then(function(authenticated) {
            alert(authenticated ? 'authenticated' : 'not authenticated');
        }).catch(function() {
            alert('failed to initialize');
        });
    </script>
</head>

keycloak.json ファイルが別の場所にある場合、以下のように指定することができます。

var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json');

または、以下のように必要な設定でJavaScriptオブジェクトを渡すこともできます。

var keycloak = Keycloak({
    url: 'http://keycloak-server/auth',
    realm: 'myrealm',
    clientId: 'myapp'
});

デフォルトでは login 関数を呼び出す必要があります。ただし、アダプターを自動的に認証させるための2つのオプションがあります。 init 関数に login-required または check-sso を渡すことができます。 login-required は、ユーザーがKeycloakにログインしていない場合にクライアントを認証し、そうでない場合にログインページを表示します。 check-sso は、ユーザーがすでにログインしている場合にのみクライアントを認証します。ユーザーがログインしていない場合、ブラウザーはアプリケーションにリダイレクトされ、未認証のままになります。

login-required を有効にするには、以下のように onLoadlogin-required を設定し、 init メソッドに渡します。

keycloak.init({ onLoad: 'login-required' })

ユーザーが認証された後、アプリケーションは Authorization ヘッダーにベアラー・トークンを含めることによって、Keycloakによって保護されたRESTfulサービスへのリクエストを行うことができます。以下に例を示します。

var loadData = function () {
    document.getElementById('username').innerText = keycloak.subject;

    var url = 'http://localhost:8080/restful-service';

    var req = new XMLHttpRequest();
    req.open('GET', url, true);
    req.setRequestHeader('Accept', 'application/json');
    req.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);

    req.onreadystatechange = function () {
        if (req.readyState == 4) {
            if (req.status == 200) {
                alert('Success');
            } else if (req.status == 403) {
                alert('Forbidden');
            }
        }
    }

    req.send();
};

注意すべきことは、デフォルトではアクセス・トークンの有効期限が短いため、リクエストを送信する前にアクセス・トークンを更新する必要があることです。これは updateToken メソッドで行うことができます。 updateToken メソッドは、トークンが正常にリフレッシュされた場合にのみ、サービスの呼び出しを容易にするプロミス・オブジェクトを返し、そうでない場合は、たとえば、ユーザーにエラーを表示します。 以下に例を示します。

keycloak.updateToken(30).then(function() {
    loadData();
}).catch(function() {
    alert('Failed to refresh token');
});

2.2.1. セッション・ステータスiframe

デフォルトでは、JavaScriptアダプターは、シングル・サイン・アウトが発生したかどうかを検出するために使用される非表示のiframeを作成します。これはネットワーク・トラフィックを必要とせず、代わりに特殊なステータス・クッキーを調べることによってステータスを取得します。この機能は、 init メソッドに渡されるオプションに checkLoginIframe: false を設定することで無効にできます。

You should not rely on looking at this cookie directly. Its format can change and it’s also associated with the URL of the Keycloak server, not your application.

2.2.2. インプリシット・フローとハイブリッド・フロー

デフォルトで、JavaScriptアダプターは 認可コード フローを使用します。

このフローにより、Keycloakサーバーは認証トークンではなく、認可コードをアプリケーションに返します。ブラウザーがアプリケーションにリダイレクトされた後、JavaScriptアダプターは code をアクセス・トークンとリフレッシュ・トークンに交換します。

Keycloakは、Keycloakでの認証が成功した直後にアクセス・トークンが送信される インプリシット フローもサポートしています。これは、トークンに対してコードを交換する追加のリクエストが無いので、標準フローよりもパフォーマンスに優れる可能性がありますが、アクセス・トークンの有効期限が切れたときに影響があります。

ただし、URLフラグメントにアクセス・トークンを送信することはセキュリティー上の脆弱性となります。たとえば、Webサーバーのログやブラウザーの履歴からトークンが漏洩する可能性があります。

インプリシット・フローを有効にするには、Keycloak管理コンソールでクライアントの Implicit Flow Enabled フラグを有効にする必要があります。 init メソッドに implicit という値を持つ flow パラメータを渡す必要もあります:

keycloak.init({ flow: 'implicit' })

注意すべき点の1つは、アクセス・トークンのみが提供され、リフレッシュ・トークンがないことです。つまり、アクセス・トークンが期限切れになると、アプリケーションはKeycloakへのリダイレクトを再度実行して、新しいアクセス・トークンを取得する必要があります。

Keycloakは ハイブリッド ・フローもサポートしています。

これは、管理コンソールでクライアントの Standard Flow EnabledImplicit Flow Enabled フラグを有効にすることを要求します。Keycloakサーバーはコードとトークンの両方をアプリケーションに送信します。アクセス・トークンとリフレッシュ・トークンの交換ができる間、アクセス・トークンは即時使用できます。インプリシット・フローと同様に、アクセス・トークンがすぐに利用できるため、ハイブリッド・フローはパフォーマンスに優れています。しかし、トークンは引き続きURLに送信され、前述のセキュリティーの脆弱性が当てはまる可能性があります。

ハイブリッド・フローの1つの利点は、アプリケーションでリフレッシュ・トークンが利用可能になることです。

ハイブリッド・フローの場合、以下のようにパラメーター flow を値 hybridinit メソッドに渡す必要があります。

keycloak.init({ flow: 'hybrid' })

2.2.3. 以前のブラウザー

JavaScriptアダプターは、Base64(window.btoaとwindow.atob)とHTML5 History APIに依存しています。これらが利用できないブラウザー(IE9など)をサポートする必要がある場合は、Polyfillを追加する必要があります。

Polyfillライブラリーの例:

If available, the JavaScript adapter will use native Promise instances as return values from functions documented as returning promises. To retain backwards compatibility, the success() and error() functions from previous versions of the adapter are retained. These remain available whether or not native Promises are provided by the browser. Promise API polyfills are available for browsers without support:

2.2.4. JavaScriptアダプター・リファレンス

コンストラクター
new Keycloak();
new Keycloak('http://localhost/keycloak.json');
new Keycloak({ url: 'http://localhost/auth', realm: 'myrealm', clientId: 'myApp' });
プロパティー
authenticated

ユーザーが認証されている場合は true 、それ以外の場合は false です。

token

サービスへのリクエストの Authorization ヘッダーで送信できるBase64でエンコードされたトークンです。

tokenParsed

JavaScriptオブジェクトとして解析されたトークン。

subject

ユーザーID。

idToken

Base64でエンコードされたIDトークン。

idTokenParsed

JavaScriptオブジェクトとして解析されたIDトークン。

realmAccess

トークンに関連付けられているレルムのロール。

resourceAccess

トークンに関連付けられているリソースのロール。

refreshToken

新しいトークンの取得に使用できるBase64でエンコードされたリフレッシュ・トークン。

refreshTokenParsed

JavaScriptオブジェクトとして解析されたリフレッシュ・トークン。

timeSkew

ブラウザーとKeycloakサーバーの推定される時間差(秒単位)。この値は単なる見積もりですが、トークンが期限切れになっているかどうかを判断するには十分正確です。

responseMode

initに渡されるレスポンス・モード(デフォルト値はfragment)。

flow

initに渡されるフロー。

adapter

Allows you to override the way that redirects and other browser-related functions will be handled by the library. Available options:

  • "default" - the library uses the browser api for redirects (this is the default)

  • "cordova" - the library will try to use the InAppBrowser cordova plugin to load keycloak login/registration pages (this is used automatically when the library is working in a cordova ecosystem)

  • custom - allows you to implement a custom adapter (only for advanced use cases)

responseType

Keycloakにログイン・リクエストとともに送信されたレスポンスタイプ。これは、初期化中に使用されたフロー値に基づいて決定されますが、この値を設定することで上書きできます。

メソッド
init(options)

アダプターを初期化するために呼び出されます。

optionsはオブジェクトで、以下のプロパティーがあります。

  • onLoad - ロード時に実行するアクションを指定します。サポートされている値は’login-required’または’check-sso’です。

  • token - トークンの初期値を設定します。

  • refreshToken - リフレッシュ・トークンの初期値を設定します。

  • idToken - IDトークンの初期値を設定します(tokenまたはrefreshTokenとともにする場合のみ)。

  • timeSkew - ローカルの時間とKeycloakサーバーとの間のスキューの初期値を秒単位で設定します(tokenまたはrefreshTokenとともにする場合のみ)。

  • checkLoginIframe - ログイン状態の監視を有効/無効に設定します(デフォルトはtrue)。

  • checkLoginIframeInterval - ログイン状態を確認する間隔を設定します(デフォルトは5秒)。

  • responseMode - ログイン・リクエストの時にKeycloakサーバーに送信するOpenID Connectレスポンス・モードを設定します。有効な値は、queryまたはfragmentです。デフォルト値はfragmentです。つまり、認証が成功した後、KeycloakはURLフラグメントに追加されたOpenID Connectパラメーターとともに、JavaScriptアプリケーションにリダイレクトされます。これは一般的にクエリーよりも安全で推奨されます。

  • flow - OpenID Connectのフローを設定します。有効な値は、standard、implicit、hybridのいずれかです。

成功またはエラー発生時に呼び出される関数を設定するPromiseを返します。

login(options)

ログイン・フォームにリダイレクトします(optionsは、redirectUriおよび/またはpromptフィールドを持つ任意のオブジェクトです)。

optionsはオブジェクトで、以下のプロパティーがあります。

  • redirectUri - ログイン後にリダイレクトするURIを指定します。

  • prompt - ユーザーがKeycloakにログインしていない場合、デフォルトでログイン画面が表示されます。ユーザーがすでにログインしている場合にのみアプリケーションを認証し、ログインしていない場合にログイン・ページを表示しないようにするには、このオプションを none に設定します。 常に再認証が必要でSSOを無視するには、このオプションを login に設定します。

  • maxAge - ユーザーがすでに認証されている場合にのみ使用されます。ユーザーの認証が行われてからの最大時間を指定します。ユーザーがすでに maxAge よりも長い時間認証済みの場合、SSOは無視され、再度認証する必要があります。

  • loginHint - ログイン・フォームのユーザー名/電子メール・フィールドを事前入力するために使用されます。

  • scope - Used to forward the scope parameter to the Keycloak login endpoint. Use a space-delimited list of scopes. Those typically reference Client scopes defined on particular client. Note that the scope openid will be always be added to the list of scopes by the adapter. For example, if you enter the scope options address phone, then the request to Keycloak will contain the scope parameter scope=openid address phone.

  • idpHint - Used to tell Keycloak to skip showing the login page and automatically redirect to the specified identity provider instead. More info in the Identity Provider documentation.

  • action - 値が 'register' の場合、ユーザーは登録ページにリダイレクトされ、そうでない場合はログイン・ページにリダイレクトされます。

  • locale - Sets the 'ui_locales' query param in compliance with section 3.1.2.1 of the OIDC 1.0 specification.

  • kcLocale - Specifies the desired Keycloak locale for the UI. This differs from the locale param in that it tells the Keycloak server to set a cookie and update the user’s profile to a new preferred locale.

  • cordovaOptions - Specifies the arguments that are passed to the Cordova in-app-browser (if applicable). Options hidden and location are not affected by these arguments. All available options are defined at https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/. Example of use: { zoom: "no", hardwareback: "yes" };

createLoginUrl(options)

ログイン・フォームへのURLを返します(optionsは、redirectUriおよび/またはpromptフィールドを持つ任意のオブジェクトです)。

optionsはオブジェクトで、 login 関数と同様のオプションをサポートします。

logout(options)

ログアウトにリダイレクトします。

optionsはオブジェクトで、以下のプロパティーがあります。

  • redirectUri - ログアウト後にリダイレクトするURIを指定します。

createLogoutUrl(options)

ユーザーをログアウトするURLを返します。

optionsはオブジェクトで、以下のプロパティーがあります。

  • redirectUri - ログアウト後にリダイレクトするURIを指定します。

register(options)

登録フォームにリダイレクトします。オプション action = 'register' でのloginメソッドのショートカットです。

optionsはloginメソッドと同じですが、 'action' は 'register' に設定されています。

createRegisterUrl(options)

登録ページのURLを返します。オプション action = 'register' でのcreateLoginUrlメソッドのショートカットです。

optionsは createLoginUrlメソッドと同じですが、 'action' は 'register' に設定されています。

accountManagement()

アカウント管理コンソールにリダイレクトします。

createAccountUrl()

アカウント管理コンソールのURLを返します。

hasRealmRole(role)

トークンに指定されたレルム・ロールがある場合は、trueを返します。

hasResourceRole(role, resource)

トークンに指定されたresourceのロールがある場合は、trueを返します(resourceはオプションであり、指定されていない場合はclientIdが使用されます)。

loadUserProfile()

ユーザーのプロファイルを読み込みます。

プロファイルが正常にロードされた場合、またはプロファイルをロードできなかった場合に、呼び出される関数を設定するPromiseを返します。

例:

keycloak.loadUserProfile().then(function(profile) {
        alert(JSON.stringify(test, null, "  "));
    }).catch(function() {
        alert('Failed to load user profile');
    });
isTokenExpired(minValidity)

トークンが期限切れになる前にminValidity秒を下回っている場合はtrueを返します(指定されていない場合はminValidityはオプションです。0が使用されます)。

updateToken(minValidity)

トークンがminValidity秒以内に期限切れになると(minValidityは省略可能です。指定されていない場合は5が使用されます)、トークンがリフレッシュされます。セッション・ステータスiframeが有効な場合、セッション・ステータスもチェックされます。

トークンが有効な場合、またはトークンがもはや有効でない場合に呼び出される関数を設定するPromiseを返します。以下に例を示します。

keycloak.updateToken(5).then(function(refreshed) {
        if (refreshed) {
            alert('Token was successfully refreshed');
        } else {
            alert('Token is still valid');
        }
    }).catch(function() {
        alert('Failed to refresh the token, or the session has expired');
    });
clearToken()

認証状態(トークンを含む)をクリアします。これは、トークンの更新が失敗した場合など、セッションが終了したことをアプリケーションが検出した場合に役立ちます。

これを呼び出すと、onAuthLogoutコールバック・リスナーが呼び出されます。

コールバック・イベント

アダプターは、特定のイベントのコールバック・リスナーの設定をサポートします。

例:

keycloak.onAuthSuccess = function() { alert('authenticated'); }

使用できるイベントは次のとおりです。

  • onReady(authenticated) - アダプターが初期化されたときに呼び出されます。

  • onAuthSuccess - ユーザーが正常に認証されたときに呼び出されます。

  • onAuthError - 認証時にエラーが発生した場合に呼び出されます。

  • onAuthRefreshSuccess - トークンがリフレッシュされたときに呼び出されます。

  • onAuthRefreshError - トークンをリフレッシュする際にエラーが発生した場合に呼び出されます。

  • onAuthLogout - ユーザーがログアウトしたときに呼び出されます(セッション・ステータスiframeが有効な場合、またはCordovaモードの場合にのみ、呼び出されます)。

  • onTokenExpired - アクセス・トークンが期限切れになったときに呼び出されます。リフレッシュ・トークンが利用可能な場合、トークンはupdateTokenでリフレッシュすることができます。リフレッシュ・トークンが利用できない場合(つまり、インプリシット・フローの場合)、ログイン画面にリダイレクトして新しいアクセス・トークンを取得できます。

2.3. Node.jsアダプター

Keycloakは、サーバーサイドのJavaScriptアプリケーションを保護するために、 Connect の上に構築されたNode.jsアダプターを提供します。目標は、 Express.js などのフレームワークと統合するのに十分な柔軟性を得ることです。

ライブラリーは Keycloak organization から直接ダウンロードすることができ、ソースは GitHub で利用可能です。

Node.jsアダプターを使用するには、まず、Keycloak管理コンソールでアプリケーションのクライアントを作成する必要があります。アダプターは、public、confidential、bearer-onlyのアクセス・タイプをサポートします。どれを選択するかは、ユースケースのシナリオに依存します。

クライアントが作成されたら、 Installation タブをクリックし、 Format OptionKeycloak OIDC JSON を選択し、 Download をクリックします。ダウンロードした keycloak.json ファイルはプロジェクトのルート・フォルダーに配置します。

2.3.1. インストール

すでに Node.js がインストールされていると仮定して、アプリケーション用のフォルダーを作成します。

mkdir myapp && cd myapp

npm init コマンドを使ってアプリケーション用の package.json を作成してください。依存関係リストにKeycloak接続アダプターを追加します。

    "dependencies": {
        "keycloak-connect": "4.0.0-final"
    }

2.3.2. 使い方

Keycloakクラスのインスタンスの作成

Keycloak クラスは、アプリケーションの設定と統合のための中心的なポイントを提供します。最も簡単な作成では引数はありません。

    var session = require('express-session');
    var Keycloak = require('keycloak-connect');

    var memoryStore = new session.MemoryStore();
    var keycloak = new Keycloak({ store: memoryStore });

デフォルトでは、keycloak固有の設定(公開鍵、レルム名、さまざまなURL)を初期化するために、アプリケーションのメイン実行可能ファイルの横に keycloak.json という名前のファイルがあります。 keycloak.json ファイルは、Keycloak管理者コンソールから取得できます。

このメソッドでインスタンス化すると、合理的なデフォルトが使用されます。代替として、 keycloak.json ファイルではなく、次のように設定オブジェクトを提供することも可能です。

    let kcConfig = {
        clientId: 'myclient',
        bearerOnly: true,
        serverUrl: 'http://localhost:8080/auth',
        realm: 'myrealm',
        realmPublicKey: 'MIIBIjANB...'
    };

    let keycloak = new Keycloak({ store: memoryStore }, kcConfig);
Webセッションストアの設定

認証のために、Webセッションを使用してサーバーサイドの状態を管理する場合は、少なくとも store パラメータで Keycloak(…​) を初期化し、実際のセッションストアで express-session 使用する必要があります。

    var session = require('express-session');
    var memoryStore = new session.MemoryStore();

    var keycloak = new Keycloak({ store: memoryStore });
カスタムスコープ値を渡す

デフォルトでは、スコープ値 openid はクエリー・パラメーターとしてKeycloakのログインURLに渡されますが、次のようにカスタム値を新たに追加することもできます。

    var keycloak = new Keycloak({ scope: 'offline_access' });

2.3.3. Middlewareのインストール

インスタンス化が完了したら、Middlewareをconnectに対応したアプリケーションにインストールします。

    var app = express();

    app.use( keycloak.middleware() );

2.3.4. リソースの保護

単純な認証

リソースにアクセスする前にユーザーの認証を強制するには、引数のないバージョンの keycloak.protect() を使うだけです。

    app.get( '/complain', keycloak.protect(), complaintHandler );
ロールベースの認可

現在のアプリケーションのアプリケーション・ロールでリソースを保護するには次のようにします。

    app.get( '/special', keycloak.protect('special'), specialHandler );

別の アプリケーションのアプリケーション・ロールでリソースを保護するには次のようにします。

    app.get( '/extra-special', keycloak.protect('other-app:special', extraSpecialHandler );

レルムロールを使用してリソースを保護するには次のようにします。

    app.get( '/admin', keycloak.protect( 'realm:admin' ), adminHandler );
高度な認可

URLの一部に基づいてリソースを保護するには次のようにします(各セクションにロールが存在すると仮定します)。

    function protectBySection(token, request) {
      return token.hasRole( request.params.section );
    }

    app.get( '/:section/:page', keycloak.protect( protectBySection ), sectionHandler );

2.3.5. 追加のURL

明示的なユーザー・トリガー・ログアウト

デフォルトでは、Middlewareは /logout の呼び出しをキャッチし、ユーザーにKeycloak中心のログアウト・ワークフローを経由させます。これは、 logout 設定パラメーターを middleware() の呼び出しに指定することで変更できます。

    app.use( keycloak.middleware( { logout: '/logoff' } ));

Keycloak Adminコールバック

また、MiddlewareはKeycloakコンソールからのコールバックをサポートしており、単一セッションまたはすべてのセッションをログアウトします。デフォルトでは、これらのタイプのAdminコールバックは / のルートURLを基準に発生しますが、 admin パラメーターを middleware() の呼び出しに与えることで変更できます。

    app.use( keycloak.middleware( { admin: '/callbacks' } );

2.4. 他のOpenID Connectライブラリー

Keycloakは、使いやすくて、Keycloakと統合しやすい付属のアダプターにより、セキュリティー保護できます。ただし、使用するプログラミング言語、フレームワーク、プラットフォームでアダプターが使用できない場合は、代わりに一般的なOpenID Connect Resource Provider(RP)ライブラリを使用することができます。この章では、Keycloak固有のことについて詳細に説明しますが、特定のプロトコルの詳細については言及しません。詳細については、 OpenID Connect specificationsOAuth2 specification を参照してください。

2.4.1. エンドポイント

理解すべき最も重要なエンドポイントは、 well-known 設定エンドポイントです。これは、KeycloakのOpenID Connectの実装に関連するエンドポイントとその他の設定オプションを一覧化します。エンドポイントは次のとおりです。

/realms/{realm-name}/.well-known/openid-configuration

完全なURLを取得するには、KeycloakのベースURLを追加し、 {realm-name} をレルム名で置換します。以下に例を示します。

http://localhost:8080/auth/realms/master/.well-known/openid-configuration

一部のRPライブラリーは、このエンドポイントから必要なすべてのエンドポイントを取得しますが、他はエンドポイントを個別に記載する必要があります。

認可エンドポイント
/realms/{realm-name}/protocol/openid-connect/auth

認可エンドポイントは、エンドユーザーの認証を実行します。これは、ユーザー・エージェントをこのエンドポイントにリダイレクトすることによって行われます。

詳細については、OpenID Connectの仕様の Authorization Endpoint を参照してください。

トークン・エンドポイント
/realms/{realm-name}/protocol/openid-connect/token

トークン・エンドポイントは、トークンを取得するために使用されます。トークンは、認可コードを交換するか、使用されているフロー次第ではクレデンシャルを直接指定することによって取得できます。トークン・エンドポイントは、有効期限が切れたときに新しいアクセス・トークンを取得するためにも使用されます。

詳細については、OpenID Connectの仕様の Token Endpoint を参照してください。

Userinfoエンドポイント
/realms/{realm-name}/protocol/openid-connect/userinfo

UserInfoエンドポイントは、認証されたユーザーに関する標準クレームを返します。また、ベアラー・トークンによって保護されています。

詳細については、OpenID Connectの仕様の Userinfo Endpointを参照してください。

ログアウト・エンドポイント
/realms/{realm-name}/protocol/openid-connect/logout

ログアウト・エンドポイントは、認証されたユーザーをログアウトします。

ユーザー・エージェントはこのエンドポイントにリダイレクトされた場合、アクティブ・ユーザー・セッションはログアウトされます。その後、ユーザー・エージェントはアプリケーションにリダイレクトされます。

エンドポイントは、アプリケーションによって直接呼び出すこともできます。このエンドポイントを直接呼び出すには、リフレッシュ・トークンと、クライアント認証に必要なクレデンシャルを含める必要があります。

証明書エンドポイント
/realms/{realm-name}/protocol/openid-connect/certs

証明書エンドポイントは、JSON Web Key(JWK)としてエンコードされ、レルムで有効化されている公開鍵を返します。レルム設定次第で、トークンを検証するために1つ以上のキーを有効にすることができます。詳細については、Server Administration GuideJSON Web Key specification のリンクを参照してください。

イントロスペクション・エンドポイント
/realms/{realm-name}/protocol/openid-connect/token/introspect

The introspection endpoint is used to retrieve the active state of a token. In other words, you can use it to validate an access or refresh token. It can only be invoked by confidential clients.

For more details on how to invoke on this endpoint, see OAuth 2.0 Token Introspection specification.

動的クライアント登録エンドポイント
/realms/{realm-name}/clients-registrations/openid-connect

動的クライアント登録エンドポイントを使用して、クライアントを動的に登録します。

詳細については、クライアントの登録の章OpenID Connect Dynamic Client Registration specification を参照してください。

2.4.2. Validating Access Tokens

If you need to manually validate access tokens issued by Keycloak you can invoke the Introspection Endpoint. The downside to this approach is that you have to make a network invocation to the Keycloak server. This can be slow and possibily overload the server if you have too many validation requests going on at the same time. Keycloak issued access tokens are JSON Web Tokens (JWT) digitally signed and encoded using JSON Web Signature (JWS). Because they are encoded in this way, this allows you to locally validate access tokens using the public key of the issuing realm. You can either hard code the realm’s public key in your validation code, or lookup and cache the public key using the certificate endpoint with the Key ID (KID) embedded within the JWS. Depending what language you code in, there are a multitude of third party libraries out there that can help you with JWS validation.

2.4.3. フロー

認可コード

認可コード・フローは、ユーザー・エージェントをKeycloakにリダイレクトします。ユーザーがKeycloakで正常に認証されると、認可コードが作成され、ユーザー・エージェントはアプリケーションにリダイレクトされます。次に、アプリケーションは、クレデンシャルとともに認可コードを使用して、Keycloakからアクセス・トークン、リフレッシュ・トークン、IDトークンを取得します。

このフローはWebアプリケーションを対象としていますが、ユーザー・エージェントを組み込むことができるモバイルアプリケーションなどのネイティブアプリケーションにも推奨されます。

詳細については、OpenID Connectの仕様の Authorization Code Flow を参照してください。

インプリシット

The Implicit flow redirects works similarly to the Authorization Code flow, but instead of returning an Authorization Code the Access Token and ID Token is returned. This reduces the need for the extra invocation to exchange the Authorization Code for an Access Token. However, it does not include a Refresh Token. This results in the need to either permit Access Tokens with a long expiration, which is problematic as it’s very hard to invalidate these. Or requires a new redirect to obtain new Access Token once the initial Access Token has expired. The Implicit flow is useful if the application only wants to authenticate the user and deals with logout itself.

アクセス・トークンと認可コードが返されるハイブリッド・フローもあります。

インプリシット・フローとハイブリッド・フローの両方で、Webサーバーのログとブラウザーの履歴を通じてアクセス・トークンが漏洩する可能性があるため、潜在的なセキュリティー上のリスクがあることに注意してください。これは、アクセス・トークンの有効期限を短くすることで多少緩和されます。

詳細については、OpenID Connectの仕様の Implicit Flow を参照してください。

リソース・オーナー・パスワード・クレデンシャル

リソース・オーナー・パスワード・クレデンシャル(Keycloakではダイレクト・グラントと呼ばれます)は、ユーザー・クレデンシャルとトークンの交換を可能にします。絶対に必要としない限り、このフローを使用することはお勧めしません。これが有用な場合の例は、レガシー・アプリケーションとコマンドライン・インターフェイスです。

このフローの使用には次のような制限があります。

  • ユーザーのクレデンシャルがアプリケーションに公開されます

  • アプリケーションはログイン・ページが必要です

  • アプリケーションは認証方式を意識する必要があります

  • 認証フローを変更するには、アプリケーションを変更する必要があります

  • アイデンティティー・ブローカリングまたはソーシャル・ログインはサポートされません

  • フローはサポートされていません(ユーザーの自己登録、必須アクションなど)

リソース・オーナー・パスワード・クレデンシャルの使用が許可されるためには、クライアントは Direct Access Grants Enabled オプションを有効にする必要があります。

このフローはOpenID Connectには含まれていませんが、OAuth 2.0の仕様の一部です。

詳細については、OAuth 2.0仕様の Resource Owner Password Credentials Grant のセクションを参照してください。

CURLを使用した例

次の例は、ユーザー名 user とパスワード password を使用して、 master レルムにあるユーザーのアクセス・トークンを取得する方法を示しています。この例では、コンフィデンシャル・クライアント myclient を使用しています。

curl \
  -d "client_id=myclient" \
  -d "client_secret=40cc097b-2a57-4c17-b36a-8fdf3fc2d578" \
  -d "username=user" \
  -d "password=password" \
  -d "grant_type=password" \
  "http://localhost:8080/auth/realms/master/protocol/openid-connect/token"
クライアント・クレデンシャル

クライアント・クレデンシャルは、クライアント(アプリケーションおよびサービス)がユーザーの代わりにではなく、自分のためにアクセス権を取得したい場合に使用されます。これは、たとえば、特定のユーザーのためにではなく一般的にシステムに変更を適用するバックグラウンド・サービスに役立ちます。

Keycloakは、クライアントがシークレットまたは公開鍵/秘密鍵のいずれかで認証することをサポートします。

このフローはOpenID Connectには含まれていませんが、OAuth 2.0の仕様の一部です。

詳細については、OAuth 2.0仕様の Client Credentials Grant のセクションを参照してください。

2.4.4. リダイレクトURI

リダイレクト・ベースのフローを使用する場合は、クライアントで有効なリダイレクトURLを使用することが重要です。リダイレクトURLはできるだけ具体的にする必要があります。これは、特にクライアント・サイド(パブリック・クライアント)のアプリケーションに適用されます。そうしないと次のことが起こる可能性があります。

  • オープン・リダイレクト - これにより、攻撃者はあなたのドメインでできている偽のリンクを作成することができます

  • 不正侵入 - ユーザーがKeycloakですでに認証済みの場合、攻撃者はリダイレクトURLが正しく設定されていない公開クライアントを使用し、ユーザーを知らないうちにリダイレクトさせることで、アクセス権を得ます

Webアプリケーション用のプロダクション環境では、常にすべてのリダイレクトURIに https を使用します。httpへのリダイレクトは許可しないでください。

また、次のような特別なリダイレクトURIがいくつかあります。

http://localhost

このリダイレクトURIはネイティブ・アプリケーションに役立ちます。ネイティブ・アプリケーションが認可コードを取得するために、ランダムなポート上にWebサーバーを作成することを許可します。このリダイレクトURIは任意のポートを許可します。

urn:ietf:wg:oauth:2.0:oob

クライアントでWebサーバーを起動できない(またはブラウザーが利用できない)場合は、特殊な urn:ietf:wg:oauth:2.0:oob リダイレクトURIを使用することができます。このリダイレクトURIが使用されると、Keycloakは認可コードをページのタイトルとボックスに含めたページを表示します。アプリケーションがブラウザーのタイトルが変更されたことを検出するか、ユーザーが手動でコードをアプリケーションにコピー/ペーストすることができます。このリダイレクトURIを使用すると、ユーザーが別のデバイスを使用してアプリケーションに貼り付けるコードを取得することもできます。

2.4.5. mod_auth_openidc Apache HTTPDモジュール

mod_auth_openidcは、OpenID Connect用のApache HTTPプラグインです。現在利用している言語/環境でApache HTTPDをプロキシとして使用できる場合は、 mod_auth_openidc を使用してOpenID ConnectでWebアプリケーションを保護することができます。このモジュールの設定は、このドキュメントの範囲を超えています。設定の詳細については、 mod_auth_openidc のGitHubリポジトリーを参照ください。

mod_auth_openidc を設定するには、以下が必要です。

  • client_id。

  • client_secret。

  • アプリケーションへのredirect_uri。

  • Keycloak openid-configuration URL

  • mod_auth_openidc 固有のApache HTTPDモジュールの設定。

設定例は次のようになります。

LoadModule auth_openidc_module modules/mod_auth_openidc.so

ServerName ${HOSTIP}

<VirtualHost *:80>

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    #this is required by mod_auth_openidc
    OIDCCryptoPassphrase a-random-secret-used-by-apache-oidc-and-balancer

    OIDCProviderMetadataURL ${KC_ADDR}/auth/realms/${KC_REALM}/.well-known/openid-configuration

    OIDCClientID ${CLIENT_ID}
    OIDCClientSecret ${CLIENT_SECRET}
    OIDCRedirectURI http://${HOSTIP}/${CLIENT_APP_NAME}/redirect_uri

    # maps the prefered_username claim to the REMOTE_USER environment variable
    OIDCRemoteUserClaim preferred_username

    <Location /${CLIENT_APP_NAME}/>
        AuthType openid-connect
        Require valid-user
    </Location>
</VirtualHost>

mod_auth_openidcの設定方法の詳細については、 mod_auth_openidcプロジェクトページを参照してください。

3. SAML

このセクションでは、Keycloakクライアント・アダプターまたは汎用SAMLプロバイダー・ライブラリーのいずれかを使用して、アプリケーションとサービスをSAMLでセキュリティー保護する方法について説明します。

3.1. Javaアダプター

Keycloakには、Javaアプリケーション用のさまざまなアダプターが付属しています。正しいアダプターの選択は、対象のプラットフォームによって異なります。

3.1.1. 共通アダプター設定

KeycloakでサポートされているSAMLクライアント・アダプターは、いずれも簡単なXMLテキストファイルで設定できます。これは以下のようなものです。

<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
                       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                       xsi:schemaLocation="urn:keycloak:saml:adapter https://www.keycloak.org/schema/keycloak_saml_adapter_1_9.xsd">
    <SP entityID="http://localhost:8081/sales-post-sig/"
        sslPolicy="EXTERNAL"
        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
        logoutPage="/logout.jsp"
        forceAuthentication="false"
        isPassive="false"
        turnOffChangeSessionIdOnLogin="false"
        autodetectBearerOnly="false">
        <Keys>
            <Key signing="true" >
                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
                </KeyStore>
            </Key>
        </Keys>
        <PrincipalNameMapping policy="FROM_NAME_ID"/>
        <RoleIdentifiers>
            <Attribute name="Role"/>
        </RoleIdentifiers>
        <IDP entityID="idp"
             signaturesRequired="true">
        <SingleSignOnService requestBinding="POST"
                             bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
                    />

            <SingleLogoutService
                    requestBinding="POST"
                    responseBinding="POST"
                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
                    />
            <Keys>
                <Key signing="true">
                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                        <Certificate alias="demo"/>
                    </KeyStore>
                </Key>
            </Keys>
        </IDP>
     </SP>
</keycloak-saml-adapter>

これらの設定の中には、アダプター固有のものもあれば、すべてのアダプターに共通のものもあります。Javaアダプターの場合は、システム・プロパティーの置換に ${…​} エンクロージャーを使用できます。 たとえば、 ${jboss.server.config.dir} です。

SP要素

ここでは、SP要素の属性の説明をします。

<SP entityID="sp"
    sslPolicy="ssl"
    nameIDPolicyFormat="format"
    forceAuthentication="true"
    isPassive="false"
    autodetectBearerOnly="false">
...
</SP>
entityID

このクライアントの識別子です。IdPは、IdPと通信しているクライアントを特定するため、この値を必要とします。この設定は、REQUIRED です。

sslPolicy

これは、アダプターが実施するSSLポリシーです。有効な値は ALLEXTERNALNONE です。 ALL の場合、すべてのリクエストはHTTPSを経由しなければなりません。 EXTERNAL の場合、非プライベートIPアドレスだけがHTTPSを経由しなければなりません。 NONE の場合、HTTPS経由であることは要求されません。この設定は OPTIONAL です。デフォルト値は EXTERNAL です。

nameIDPolicyFormat

SAMLクライアントは、特定のNameID Subject形式を要求できます。特定の書式が必要な場合は、この値を入力します。これは標準のSAML形式の識別子である urn:oasis:names:tc:SAML:2.0:nameid-format:transient でなければなりません。この設定は OPTIONAL です。デフォルトでは、特別な形式は要求されません。

forceAuthentication

SAMLクライアントは、すでにIdPにログインしていても、ユーザーが再認証されるように要求できます。有効にするには、これを true に設定します。この設定は OPTIONAL です。デフォルト値は false です。

isPassive

SAMLクライアントは、IdPにログインしていなくても、ユーザーに認証を要求しないようにすることができます。その場合は、 true に設定してください。 forceAuthentication と反対の設定なため一緒に使用しないでください。この設定は OPTIONAL です。デフォルト値は false です。

turnOffChangeSessionIdOnLogin

セッションIDは、セキュリティー攻撃口とならないように、一部のプラットフォームで正常にログインするとデフォルトで変更されます。これを無効にするには、 true に変更してください。これは無効にしないことをお勧めします。デフォルト値は false です。

autodetectBearerOnly

アプリケーションがWebアプリケーションとWebサービス(SOAPやRESTなど)の両方を提供する場合は、これを true に設定する必要があります。 Webアプリケーションの未認証のユーザーをKeycloakのログインページにリダイレクトできますが、ログインページへのリダイレクトを理解できない未認証のSOAPクライアントまたはRESTクライアントにはHTTPの 401 ステータスコードを送信します。Keycloakは、 X-Requested-WithSOAPActionAccept のような典型的なヘッダーに基づいて、SOAPクライアントまたはRESTクライアントを自動検出します。デフォルト値は false です。

logoutPage

This sets the page to display after logout. If the page is a full URL, such as http://web.example.com/logout.html, the user is redirected after logout to that page using the HTTP 302 status code. If a link without scheme part is specified, such as /logout.jsp, the page is displayed after logout, regardless of whether it lies in a protected area according to security-constraint declarations in web.xml, and the page is resolved relative to the deployment context root.

サービス・プロバイダーの鍵とキー要素

IdPがクライアント・アプリケーション(またはSP)に対してすべてのリクエストに署名することを要求する場合や、IdPがアサーションを暗号化する場合は、それを行うために使用する鍵を定義する必要があります。クライアント署名ドキュメントの場合、署名に使用される秘密鍵と公開鍵、または証明書の両方を定義する必要があります。暗号化の場合、復号化に使用される秘密鍵を定義するだけで済みます。

鍵を記述する方法は2つあります。Javaキーストア内に格納するか、PEM 形式で keycloak-saml.xml 内に直接コピー/ペーストできます。

        <Keys>
            <Key signing="true" >
               ...
            </Key>
        </Keys>

Key 要素には、2つの省略可能な属性 signingencryption があります。 これらをtrueに設定すると、アダプターはどの鍵を使用するか決定します。 両方の属性がtrueに設定される場合は、ドキュメントの署名と暗号化されたアサーションの復号化の両方に鍵が使用されます。これらの属性の少なくとも1つはtrueに設定する必要があります。

KeyStore要素

Key 要素内でJavaのキーストアから鍵と証明書を読み込むことができます。これは KeyStore 要素内で宣言されています。

        <Keys>
            <Key signing="true" >
                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                    <PrivateKey alias="myPrivate" password="test123"/>
                    <Certificate alias="myCertAlias"/>
                </KeyStore>
            </Key>
        </Keys>

KeyStore 要素に定義されているXML設定属性を示します。

file

キーストアのファイルパスです。このオプションは OPTIONAL です。file属性またはresource属性を設定する必要があります。

resource

キーストアへのWARリソース・パスです。これは、ServletContext.getResourceAsStream()へのメソッド呼び出しで使用されるパスです。このオプションは OPTIONAL です。file属性またはresource属性を設定する必要があります。

password

キーストアのパスワードです。このオプションは REQUIRED です。

SPがドキュメントの署名に使用する鍵を定義している場合、Javaのキーストア内の秘密鍵と証明書への参照も指定する必要があります。上記の例の PrivateKey 要素と Certificate 要素はキーストア内の鍵または証明書を指す alias を定義します。キーストアには、秘密鍵にアクセスするための追加のパスワードが必要です。 PrivateKey 要素では、このパスワードを password 属性の中で定義する必要があります。

Key PEMS

Key 要素の中では、 PrivateKeyPemPublicKeyPem 、 ` CertificatePem` というサブ要素を使って、鍵と証明書を直接宣言します。これらの要素に含まれる値は、PEM鍵形式に準拠している必要があります。 openssl などのコマンドライン・ツールを使用して鍵を生成する場合は、通常このオプションを使用します。

<Keys>
   <Key signing="true">
      <PrivateKeyPem>
         2341251234AB31234==231BB998311222423522334
      </PrivateKeyPem>
      <CertificatePem>
         211111341251234AB31234==231BB998311222423522334
      </CertificatePem>
   </Key>
</Keys>
SP PrincipalNameMapping要素

この要素はオプションです。 HttpServletRequest.getUserPrincipal() などのメソッドから取得したJavaの Principal オブジェクトを作成するときに、 Principal.getName() メソッドが返す名前を定義することができます。

<SP ...>
  <PrincipalNameMapping policy="FROM_NAME_ID"/>
</SP>

<SP ...>
  <PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="email" />
</SP>

policy 属性は、この値を設定するためのポリシーを定義します。 この属性に指定できる値は次のとおりです。

FROM_NAME_ID

このポリシーはSAMLサブジェクトの値が何であれ使用します。これはデフォルト設定です。

FROM_ATTRIBUTE

これにより、サーバーから受け取ったSAMLアサーションで宣言された属性の1つから、値が取得されます。 attribute XML属性内で使用するSAMLアサーション属性の名前を指定する必要があります。

RoleIdentifiers要素

RoleIdentifiers 要素は、ユーザーから受信したアサーション内のどのSAML属性が、Java EEのセキュリティー・コンテキスト内のロール識別子として使用されるか定義します。

<RoleIdentifiers>
     <Attribute name="Role"/>
     <Attribute name="member"/>
     <Attribute name="memberOf"/>
</RoleIdentifiers>

デフォルトでは、 Role 属性の値はJava EEのロールに変換されます。いくつかのIdPは、 member または memberOf 属性アサーションを使用してロールを送信します。どのSAML属性をロールに変換すべきかを指定するために、1つ以上の Attribute 要素を定義できます。

IDP要素

IDP要素内には、SPと通信しているアイデンティティー・プロバイダー(認証サーバー)の設定を記述します。

<IDP entityID="idp"
     signaturesRequired="true"
     signatureAlgorithm="RSA_SHA1"
     signatureCanonicalizationMethod="http://www.w3.org/2001/10/xml-exc-c14n#">
...
</IDP>

IDP 要素宣言内で指定できる属性設定オプションを示します。

entityID

IDPの発行者IDです。この設定は REQUIRED です。

signaturesRequired

true に設定すると、クライアント・アダプターはIDPに送信する全ての文書に署名します。 また、クライアントは、送信されたすべてのドキュメントにIDPが署名していることを期待します。このスイッチは、すべてのリクエストとレスポンスの種類に対してデフォルト値を設定しますが、それ以上に細かい制御ができることが後で分かります。この設定は OPTIONAL で、 false がデフォルトとなります。

signatureAlgorithm

IDPが署名済みドキュメントに使用することを想定している署名アルゴリズムです。許可値は、 RSA_SHA1RSA_SHA256RSA_SHA512DSA_SHA1 です。 この設定は OPTIONAL で、デフォルトは RSA_SHA256 です。

signatureCanonicalizationMethod

IDPが署名済みのドキュメントに使用することを想定している署名の正規化方法です。この設定は OPTIONAL です。デフォルトは http://www.w3.org/2001/10/xml-exc-c14n# で、ほとんどのIDPに対して変更が不要です。

IDP SingleSignOnServiceサブ要素

SingleSignOnService サブ要素は、IDPのログインSAMLエンドポイントを定義します。クライアント・アダプターは、ログインしたいときに、この要素内の設定によって書式設定されたIDPにリクエストを送信します。

<SingleSignOnService signRequest="true"
                     validateResponseSignature="true"
                     requestBinding="post"
                     bindingUrl="url"/>

この要素に定義できる設定属性は次のとおりです。

signRequest

クライアントが認証リクエストに署名する必要があるかどうかの設定です。この設定は OPTIONAL です。デフォルトはIDPの signaturesRequired 要素の値です。

validateResponseSignature

クライアントが、認証リクエストからのアサーション・レスポンスのドキュメントが署名されていることを期待するかどうかの設定です。この設定は OPTIONAL です。デフォルトはIDPの signaturesRequired 要素の値です。

requestBinding

IDPとの通信に使用するSAMLバインディング・タイプです。この設定は OPTIONAL です。デフォルト値は POST ですが、 REDIRECT に設定することもできます。

responseBinding

SAMLでは、クライアントが認証レスポンスに使用したいバインディング・タイプを要求することができます。この値には、 POST または REDIRECT を設定できます。この設定は OPTIONAL です。デフォルトでは、クライアントはレスポンスに対して特定のバインディング・タイプを要求しません。

assertionConsumerServiceUrl

IDPログイン・サービスがレスポンスを送信するアサーション・コンシューマー・サービス(ACS)のURLの設定です。この設定は OPTIONAL です。デフォルトでは未設定で、IdPの設定に依存します。設定されている場合、 http://sp.domain.com/my/endpoint/for/saml のように、 /saml で終わる必要があります。このプロパティーの値は、SAMLの AuthnRequest メッセージの AssertionConsumerServiceURL 属性で送信されます。このプロパティーは、通常 responseBinding 属性を伴います。

bindingUrl

これは、クライアントがリクエストを送信するIDPログイン・サービスのURLです。この設定は REQUIRED です。

IDP SingleLogoutServiceサブ要素

`SingleLogoutService`サブ要素は、IDPのログアウトSAMLエンドポイントを定義します。クライアント・アダプターは、ログアウトしたいときに、この要素内の設定によって書式設定されたIDPにリクエストを送信します。

<SingleLogoutService validateRequestSignature="true"
                     validateResponseSignature="true"
                     signRequest="true"
                     signResponse="true"
                     requestBinding="redirect"
                     responseBinding="post"
                     postBindingUrl="posturl"
                     redirectBindingUrl="redirecturl">
signRequest

IDPへのログアウト・リクエストにクライアントが署名する必要があるかどうかの設定です。この設定は OPTIONAL です。デフォルトはIDPの signaturesRequired 要素の値です。

signResponse

IDPへのログアウト・レスポンスにクライアントが署名する必要があるかどうかの設定です。この設定は OPTIONAL です。デフォルトはIDPの signaturesRequired 要素の値です。

validateRequestSignature

IDPからのログアウト・リクエストのドキュメントが署名されていることをクライアントが期待するかどうかの設定です。この設定は OPTIONAL です。デフォルトはIDPの signaturesRequired 要素の値です。

validateResponseSignature

IDPからのログアウト・レスポンスのドキュメントが署名されていることをクライアントが期待するかどうかの設定です。この設定は OPTIONAL です。デフォルトはIDPの signaturesRequired 要素の値です。

requestBinding

IDPとのSAMLリクエストでの通信に使用するSAMLバインディング・タイプです。この設定は OPTIONAL です。デフォルト値は POST ですが、 REDIRECT に設定することもできます。

responseBinding

IDPとのSAMLレスポンスでの通信に使用するSAMLバインディング・タイプです。この値は POST または REDIRECT にできます。この設定は OPTIONAL です。デフォルト値は POST ですが、 REDIRECT に設定することもできます。

postBindingUrl

POST バインディングを使用する際のIDPのログアウト・サービス用のURLです。 POST バインディングを使用する場合、この設定は REQUIRED です。

redirectBindingUrl

REDIRECTバインディングを使用する際のIDPのログアウト・サービス用のURLです。REDIRECTバインディングを使用する場合、この設定は REQUIRED です。

IDP Keysサブ要素

IDPのKeysサブ要素は、IDPによって署名されたドキュメントの検証に使用する証明書や公開鍵を定義するために使用されます。Keysサブ要素は、SPの鍵とKeys要素と同じ方法で定義されます。しかし、証明書または公開鍵の参照を1つだけ定義する必要があります。IDPとSPがKeycloakサーバーとアダプターによって実現された場合、それぞれで、署名の検証のために鍵を指定する必要はないことに注意してください(以下を参照してください)。

SPとIDPの両方がKeycloakで提供された場合、公開された証明書から自動的にIDP署名検証用の公開鍵を取得するようにSPを設定できます。これは、Keysサブ要素内の署名検証鍵のすべての宣言を削除することによって行われます。Keysサブ要素が空であれば、完全に省略できます。鍵は、SAML記述子からSPによって自動的に取得されます。その場所は、IDP SingleSignOnServiceサブ要素で指定したSAMLエンドポイントURLが基になります。SAML記述子の取得に使用されるHTTPクライアントの設定は、通常追加の設定は必要がありませんが、IDP HttpClientサブ要素内に設定できます。

署名検証用の鍵を複数指定することもできます。 signing 属性を true に設定し、Keysサブ要素内に複数のKey要素を宣言することによって行います。これは、たとえばIDPの署名鍵をローテーションするような状況で役に立ちます。通常、新しいSAMLプロトコルのメッセージとアサーションが新しい鍵で署名されても、以前の鍵で署名されたものを受け入れられる移行期間があります。

署名検証用の鍵を自動的に取得することと、追加の静的な署名検証の鍵を定義することの、両方をKeycloakに設定することはできません。

       <IDP entityID="idp">
            ...
            <Keys>
                <Key signing="true">
                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
                        <Certificate alias="demo"/>
                    </KeyStore>
                </Key>
            </Keys>
        </IDP>
IDP HttpClient サブ要素

オプションである HttpClient サブ要素は、HTTPクライアントのプロパティーを定義します。enabledの場合、IDPのSAML記述子による、IDP署名検証用の公開鍵を含む証明書の自動取得に使用されるます。

<HttpClient connectionPoolSize="10"
            disableTrustManager="false"
            allowAnyHostname="false"
            clientKeystore="classpath:keystore.jks"
            clientKeystorePassword="pwd"
            truststore="classpath:truststore.jks"
            truststorePassword="pwd"
            proxyUrl="http://proxy/" />
connectionPoolSize

アダプターは、アクセス・コードをアクセス・トークンに変換するために、Keycloakサーバーに別のHTTP呼び出しを行います。この設定オプションは、Keycloakサーバーにプールすべき接続数を定義します。 これは OPTIONAL です。デフォルトは 10 です。

disableTrustManager

KeycloakサーバーがHTTPSを必要とし、この設定オプションを true に設定する場合は、トラストストアを指定する必要はありません。この設定は、SSL証明書の検証を無効とするため、開発時にのみ使用すべきで、プロダクション環境では 決して使用してはいけません 。これは OPTIONAL です。デフォルトは false です。

allowAnyHostname

KeycloakサーバーがHTTPSを必要とし、この設定オプションを true に設定する場合、トラストストア経由でKeycloakサーバーの証明書は検証されますが、ホスト名の検証は行われません。 SSL証明書の検証が一部無効となるため、この設定は開発時にのみ使用すべきで、プロダクション環境では 決して使用してはいけません 。これは OPTIONAL です。デフォルトは false です。

truststore

キーストア・ファイルへのファイルパスです。パスに classpath: を付けると、トラストストアはデプロイメントのクラスパスから取得されます。これはKeycloakサーバーへのHTTPS通信に使用されます。HTTPSリクエストを行うクライアントは、通信を行うサーバーのホストを検証する必要があります。これがトラストストアの役割です。キーストアには、1つ以上の信頼されたホストの証明書または認証局が含まれています。このトラストストアは、KeycloakサーバーのSSLキーストアのパブリック証明書を抽出することで作成できます。これは、 disableTrustManagertrue でない限り、 REQUIRED です。

truststorePassword

Password for the truststore keystore. This is REQUIRED if truststore is set and the truststore requires a password.

clientKeystore

キーストア・ファイルへのファイルパスです。このキーストアには、アダプターがKeycloakサーバーにHTTPSリクエストを行う際の、双方向SSLのためのクライアント証明書を含めます。これは OPTIONAL です。

clientKeystorePassword

クライアントのキーとクライアントのキーストアのパスワードです。 clientKeystore が設定されている場合は、 REQUIRED です。

proxyUrl

HTTP接続に使用するHTTPプロキシのURLです。これは OPTIONAL です。

3.1.2. JBoss EAP/WildFlyアダプター

JBoss EAPまたはWildFlyにデプロイされたWARアプリケーションを保護するには、Keycloak SAMLアダプター・サブシステムをインストールして設定する必要があります。

keycloak設定ファイルである /WEB-INF/keycloak-saml.xml をWARに提供し、 web.xml 内の auth-methodKEYCLOAK-SAML に変更します。両方の方法についてこのセクションで説明します。

アダプターのインストール

各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。

WildFly 9、10、11、またはJBoss EAP 7へのインストールは次のとおりです。

$ cd $WILDFLY_HOME
$ unzip keycloak-saml-wildfly-adapter-dist.zip

JBoss EAP 6.xへのインストールは次のとおりです。

$ cd $JBOSS_HOME
$ unzip keycloak-saml-eap6-adapter-dist.zip

これらのzipファイルは、WildFlyまたはJBoss EAP用の配布物内のWildFly/JBoss EAP SAMLアダプターに固有の新しいJBossモジュールを作成します。

モジュールを追加したら、アプリケーション・サーバーのサーバー設定 domain.xml または standalone.xml 内にあるKeycloak SAMLサブシステムを有効にする必要があります。

サーバー設定の変更に役立つCLIスクリプトがあります。サーバーを起動し、サーバーの bin ディレクトリーからスクリプトを実行します。

WildFly 11
$ cd bin
$ ./jboss-cli.sh --file=adapter-elytron-install-offline.cli
WildFly 10以上
$ cd $JBOSS_HOME/bin
$ jboss-cli.sh -c --file=adapter-install-saml.cli

スクリプトは、以下に説明するように、extension、subsystem、オプションでsecurity-domainを追加します。

<server xmlns="urn:jboss:domain:1.4">

    <extensions>
        <extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
          ...
    </extensions>

    <profile>
        <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1"/>
         ...
    </profile>

セキュリティー保護されたWeb層で作成されたセキュリティー・コンテキストを呼び出すEJB(他のEEコンポーネント)に伝播する必要がある場合は、 keycloak セキュリティー・ドメインをEJBなどのコンポーネントとともに使用する必要があります。それ以外の場合、この設定はオプションです。

<server xmlns="urn:jboss:domain:1.4">
 <subsystem xmlns="urn:jboss:domain:security:1.2">
    <security-domains>
...
      <security-domain name="keycloak">
         <authentication>
           <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule"
                         flag="required"/>
          </authentication>
      </security-domain>
    </security-domains>

たとえば、 WEB-INF/classes ディレクトリー内のEJBであるJAX-RSサービスを使用している場合は、次のように @SecurityDomain アノテーションを付けます。

import org.jboss.ejb3.annotation.SecurityDomain;
import org.jboss.resteasy.annotations.cache.NoCache;

import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.ArrayList;
import java.util.List;

@Path("customers")
@Stateless
@SecurityDomain("keycloak")
public class CustomerService {

    @EJB
    CustomerDB db;

    @GET
    @Produces("application/json")
    @NoCache
    @RolesAllowed("db_user")
    public List<String> getCustomers() {
        return db.getCustomers();
    }
}

keycloak セキュリティー・コンテキストをEJB層に伝播するときに、 @SecurityDomain アノテーションを指定する必要がないように、今後の統合を改善したいと考えています。

JBoss SSO

WildFly has built-in support for single sign-on for web applications deployed to the same WildFly instance. This should not be enabled when using Keycloak.

3.1.3. RPMからJBoss EAPアダプターをインストールします。

次のように、RPMからEAP 7アダプターをインストールします。

Red Hat Enterprise Linux 7では、チャンネルという用語はリポジトリーという用語に置き換えられました。これらの説明では、リポジトリーという用語のみが使用されています。

RPMからEAP 7アダプターをインストールする前に、JBoss EAP 7.0リポジトリーにサブスクライブする必要があります。

前提条件
  1. Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。

  2. すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。

Using Red Hat Subscription Manager, subscribe to the JBoss EAP 7.0 repository using the following command. Replace <RHEL_VERSION> with either 6 or 7 depending on your Red Hat Enterprise Linux version.

$ sudo subscription-manager repos --enable=jb-eap-7-for-rhel-<RHEL_VERSION>-server-rpms

次のコマンドを使用して、SAML用のEAP 7アダプターをインストールします。

$ sudo yum install eap7-keycloak-saml-adapter-sso7_2
RPMインストールのためのデフォルトのEAP_HOMEパスは、/opt/rh/eap7/root/usr/share/wildflyです。

適切なモジュール・インストール・スクリプトを実行します。

SAMLモジュールの場合は、次のコマンドを実行します。

$ {EAP_HOME}/bin/jboss-cli.sh -c --file=${EAP_HOME}/bin/adapter-install-saml.cli

インストールは完了です。

次のように、RPMからEAP 6アダプターをインストールします。

Red Hat Enterprise Linux 7では、チャンネルという用語はリポジトリーという用語に置き換えられました。これらの説明では、リポジトリーという用語のみが使用されています。

RPMからEAP 6アダプターをインストールする前に、JBoss EAP 6.0リポジトリーにサブスクライブする必要があります。

前提条件
  1. Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。

  2. すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。

Red Hat Subscription Managerを使用して、次のコマンドを使用してJBoss EAP 6.0リポジトリーにサブスクライブします。Red Hat Enterprise Linuxのバージョンに応じて、<RHEL_VERSION>を6または7のいずれかに置き換えてください。

$ sudo subscription-manager repos --enable=jb-eap-6-for-rhel-<RHEL_VERSION>-server-rpms

次のコマンドを使用して、SAML用のEAP 6アダプターをインストールします。

$ sudo yum install keycloak-saml-adapter-sso7_2-eap6
RPMインストールのためのデフォルトのEAP_HOMEパスは、/opt/rh/eap6/root/usr/share/wildflyです。

適切なモジュール・インストール・スクリプトを実行します。

SAMLモジュールの場合は、次のコマンドを実行します。

$ {EAP_HOME}/bin/jboss-cli.sh -c --file=${EAP_HOME}/bin/adapter-install-saml.cli

インストールは完了です。

WARごとの設定

このセクションでは、直接WARパッケージ内にconfigファイルを追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。

まず、WARの WEB-INF ディレクトリーに keycloak-saml.xml アダプター設定ファイルを作成します。この設定ファイルの形式は、共通アダプター設定セクションで説明しています。

次に、 web.xmlKEYCLOAK-SAMLauth-method を設定する必要があります。また、標準サーブレット・セキュリティーを使用して、URLに対してロールベース制約を指定する必要があります。 web.xml ファイルの例を次に示します。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

        <module-name>customer-portal</module-name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Admins</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customers</web-resource-name>
            <url-pattern>/customers/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <login-config>
        <auth-method>KEYCLOAK-SAML</auth-method>
        <realm-name>this is ignored currently</realm-name>
    </login-config>

    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>

auth-method の設定を除いて、すべての標準のサーブレット設定です。

Keycloak SAMLサブシステムを介してWARをセキュリティー保護する

Keycloakでセキュリティー保護するためにWARを開く必要はありません。代わりに、Keycloak SAMLアダプター・サブシステムを使用して、外部からセキュリティー保護することもできます。KEYCLOAK-SAMLを auth-method として指定する必要はありませんが、 web.xmlsecurity-constraints を定義する必要があります。しかし、 WEB-INF/keycloak-saml.xml ファイルを作成する必要はありません。このメタデータは、代わりにサーバーの domain.xml または standalone.xml のサブシステム設定セクションのXML内で定義されます。

<extensions>
  <extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
</extensions>

<profile>
  <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
    <secure-deployment name="WAR MODULE NAME.war">
      <SP entityID="APPLICATION URL">
        ...
      </SP>
    </secure-deployment>
  </subsystem>
</profile>

secure-deploymentname 属性は保護したいWARを識別します。 web.xml 内の module-name.war を付加した値となります。残りの設定は、共通アダプター設定で定義された keycloak-saml.xml 設定と同じXML構文を使用します。

設定例を次に示します。

<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
  <secure-deployment name="saml-post-encryption.war">
    <SP entityID="http://localhost:8080/sales-post-enc/"
        sslPolicy="EXTERNAL"
        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
        logoutPage="/logout.jsp"
        forceAuthentication="false">
      <Keys>
        <Key signing="true" encryption="true">
          <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
            <PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
            <Certificate alias="http://localhost:8080/sales-post-enc/"/>
          </KeyStore>
        </Key>
      </Keys>
      <PrincipalNameMapping policy="FROM_NAME_ID"/>
      <RoleIdentifiers>
        <Attribute name="Role"/>
      </RoleIdentifiers>
      <IDP entityID="idp">
        <SingleSignOnService signRequest="true"
            validateResponseSignature="true"
            requestBinding="POST"
            bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>

        <SingleLogoutService
            validateRequestSignature="true"
            validateResponseSignature="true"
            signRequest="true"
            signResponse="true"
            requestBinding="POST"
            responseBinding="POST"
            postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
            redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
        <Keys>
          <Key signing="true" >
            <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
              <Certificate alias="saml-demo"/>
            </KeyStore>
          </Key>
        </Keys>
      </IDP>
    </SP>
   </secure-deployment>
</subsystem>

3.1.4. Tomcat SAMLアダプター

Tomcat 6、7、8にデプロイされたWARアプリケーションを保護するには、Keycloak Tomcat 6、7、8 SAMLアダプターをTomcatにインストールする必要があります。その後、TomcatにデプロイするWARにもいくつかの設定を行う必要があります。これらの手順について説明します。

アダプターのインストール

アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。

アダプターの配布物をTomcatの lib/ ディレクトリーに解凍する必要があります。WEB-INF/libディレクトリー内にアダプターのjarを含めても動作しません!Keycloak SAMLアダプターはValveとして実装され、ValveのコードはTomcatのメインのlib/ディレクトリーに存在する必要があります。

$ cd $TOMCAT_HOME/lib
$ unzip keycloak-saml-tomcat6-adapter-dist.zip
    or
$ unzip keycloak-saml-tomcat7-adapter-dist.zip
    or
$ unzip keycloak-saml-tomcat8-adapter-dist.zip
WARごとの設定

このセクションでは、直接WARパッケージ内にconfigファイルを追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。

まず、WARパッケージに META-INF/context.xml ファイルを作成します。 これはTomcat固有の設定ファイルであり、Keycloak固有のValveを定義する必要があります。

<Context path="/your-context-path">
    <Valve className="org.keycloak.adapters.saml.tomcat.SamlAuthenticatorValve"/>
</Context>

次に、WARの WEB-INF ディレクトリーに keycloak-saml.xml アダプター設定ファイルを作成する必要があります。この設定ファイルの形式は、共通アダプター設定のセクションで説明しています。

最後に、URLに対してロールベース制約を指定するために、 login-config と標準のサーブレット・セキュリティーの両方を指定する必要があります。例を次に示します。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

        <module-name>customer-portal</module-name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customers</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>this is ignored currently</realm-name>
    </login-config>

    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>

3.1.5. Jetty SAMLアダプター

JettyにデプロイされたWARアプリケーションを保護するには、Keycloak Jetty 9.xまたは8.x SAMLアダプターをJettyにインストールする必要があります。その後、JettyにデプロイするWARにもいくつかの設定を行う必要があります。これらの手順について説明します。

Jetty 9アダプターのインストール

KeycloakにはJetty 9.x用のSAMLアダプターがあります。Jettyにデプロイする各WARには、さらにいくつかの設定を行う必要があります。これらの手順について説明します。

アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。

Jetty 9.x用の配布物をJetty 9.xのルートディレクトリーに解凍する必要があります。WEB-INF/libディレクトリー内にアダプターのjarを含めても動作しません!

$ cd $JETTY_HOME
$ unzip keycloak-saml-jetty92-adapter-dist.zip

次に、jetty.base用のkeycloakモジュールを有効にする必要があります。

$ cd your-base
$ java -jar $JETTY_HOME/start.jar --add-to-startd=keycloak
WARごとのJetty 9の設定

このセクションでは、直接WARパッケージ内にconfigファイルを追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。

まず、WARパッケージに WEB-INF/jetty-web.xml ファイルを作成します。これはJetty固有の設定ファイルで、その中にKeycloak固有のAuthenticatorを定義する必要があります。

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
    <Get name="securityHandler">
        <Set name="authenticator">
            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
            </New>
        </Set>
    </Get>
</Configure>

次に、WARの WEB-INF ディレクトリーに keycloak-saml.xml アダプター設定ファイルを作成する必要があります。この設定ファイルの形式は、共通アダプター設定のセクションで説明しています。

最後に、URLに対してロールベース制約を指定するために、 login-config と標準のサーブレット・セキュリティーの両方を指定する必要があります。例を次に示します。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

        <module-name>customer-portal</module-name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customers</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>this is ignored currently</realm-name>
    </login-config>

    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>
Jetty 8 アダプターのインストール

Keycloakには、Jettyのインストール先にインストールする必要のあるJetty 8.1.x用のSAMLアダプターがあります。Jettyにデプロイする各WARには、さらにいくつかの設定を行う必要があります。これらの手順について説明します。

アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。

You must unzip the Jetty 8.1.x distro into Jetty 8.1.x’s root directory. Including adapter’s jars within your WEB-INF/lib directory will not work!

$ cd $JETTY_HOME
$ unzip keycloak-saml-jetty81-adapter-dist.zip

次に、keycloakオプションを有効にする必要があります。start.iniを編集し、オプションにkeycloakを追加します。

#===========================================================
# Start classpath OPTIONS.
# These control what classes are on the classpath
# for a full listing do
#   java -jar start.jar --list-options
#-----------------------------------------------------------
OPTIONS=Server,jsp,jmx,resources,websocket,ext,plus,annotations,keycloak
Jetty 8 WARごとの設定

WARに対してKeycloakを有効にする方法は、Jetty 9.xアダプターと同じです。Jetty 9 WARごとの設定を参照してください。

3.1.6. Javaサーブレット・フィルター・アダプター

サーブレット・プラットフォーム用のアダプターを持たないJavaサーブレット・アプリケーションでSAMLを使用する場合は、Keycloakにあるサーブレット・フィルター・アダプターを使用することができます。このアダプターは、他のアダプターとは少し異なります。共通アダプター設定セクションで定義されているように /WEB-INF/keycloak-saml.xml ファイルを指定する必要がありますが、 web.xml にセキュリティー制約を定義しません。代わりにKeycloakサーブレット・フィルター・アダプターを使用してフィルター・マッピングを定義して、URLパターンでセキュリティー保護します。

バックチャネル・ログアウトは、標準のアダプターとは少し異なります。 HTTPセッションを無効にするのではなく、セッションIDをログアウトしたものとしてマークします。 セッションIDに基づいてHTTPセッションを任意に無効にする方法はありません。
現時点では、SAMLフィルターを使用するクラスター化されたアプリケーションでは、バックチャネル・ログアウトは機能しません。
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">

        <module-name>customer-portal</module-name>

    <filter>
        <filter-name>Keycloak Filter</filter-name>
        <filter-class>org.keycloak.adapters.saml.servlet.SamlFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Keycloak Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Keycloakフィルターは、コンテキスト・パラメータの代わりにフィルター初期化パラメータとして定義する必要がある以外は、他のアダプターと同じ設定パラメータを使用できます。

さまざまな異なる安全なURLパターンと安全でないURLパターンが存在する場合は、複数のフィルター・マッピングを定義できます。

/saml をカバーするフィルター・マッピングが必要です。 このマッピングは、すべてのサーバー・コールバックを対象としています。

IdPとともにSPを登録するときは、Assert Consumer Service URLとSingle Logout Service URLとして http[s]://hostname/{context-root}/saml を登録する必要があります。

このフィルタを使用するには、WARのpomに次のmavenアーティファクトを含めます。

<dependency>
   <groupId>org.keycloak</groupId>
   <artifactId>keycloak-saml-servlet-filter-adapter</artifactId>
   <version>4.0.0.Final</version>
</dependency>

3.1.7. アイデンティティ・プロバイダーでの登録

サーブレット・ベース・アダプターごとに、アサート・コンシューマー・サービスURLとシングル・ログアウト・サービスURLに登録するエンドポイントは、 /saml が付加されるサーブレット・アプリケーションのベースURLでなければなりません。つまり、 https://example.com/contextPath/saml のようなURLになります。

3.1.8. ログアウト

Webアプリケーションからログアウトするには、複数の方法があります。Java EEサーブレット・コンテナーの場合は、 HttpServletRequest.logout() を呼び出すことができます。他のブラウザーアプリケーションでは、ブラウザーにセキュリティー制約のあるWebアプリケーションのURLを指定し、クエリー・パラメーターGLO、つまり、 http://myapp?GLO=true を渡すことができます。これにより、ブラウザーとのSSOセッションがある場合は、ログアウトされます。

クラスター環境でのログアウト

内部的には、SAMLアダプターは、SAMLセッション・インデックス、プリンシパル名(既知の場合)、およびHTTPセッションIDの間のマッピングを保存します。このマッピングは、分散アプリケーション用にJBossアプリケーション・サーバー・ファミリー(Wildfly 10/11、EAP 6/7)のクラスター全体で維持されます。前提条件として、HTTPセッションをクラスター全体に分散する必要があります(つまり、アプリケーションの web.xml<distributable/> タグが設定されています)。

この機能を有効にするには、 /WEB_INF/web.xml ファイルに次のセクションを追加してください。

EAP 7、WildFly 10/11の場合:

<context-param>
    <param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
    <param-value>org.keycloak.adapters.saml.wildfly.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>

EAP 6の場合:

<context-param>
    <param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
    <param-value>org.keycloak.adapters.saml.jbossweb.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>

デプロイメントのセッション・キャッシュの名前が deployment-cache である場合、SAMLマッピングに使用されるキャッシュは deployment-cache.ssoCache という名前になります。キャッシュの名前は、コンテキスト・パラメーター keycloak.sessionIdMapperUpdater.infinispan.cacheName によってオーバーライドできます。キャッシュを含むキャッシュ・コンテナーは、デプロイメント・セッション・キャッシュを含むキャッシュ・コンテナーと同じですが、コンテキスト・パラメーター keycloak.sessionIdMapperUpdater.infinispan.containerName によってオーバーライドできます。

デフォルトでは、SAMLマッピング・キャッシュの設定はセッション・キャッシュから取得されます。この設定は、他のキャッシュとまったく同じサーバーのキャッシュ設定セクションで手動でオーバーライドできます。

現在、信頼性の高いサービスを提供するために、SAMLセッション・キャッシュにレプリケート・キャッシュを使用することをお勧めします。分散キャッシュを使用すると、SAMLログアウト・リクエストがSAMLセッション・インデックスからHTTPセッション・マッピングへのアクセスがないノードに到達し、ログアウトに失敗する結果につながる可能性があります。

クロスDCシナリオでのログアウト

クロスDCシナリオは、WildFly 10以上、EAP 7以上にのみ適用されます。

複数のデータセンターにまたがるセッションを処理するには、特別な処理が必要です。以下のシナリオを想像してみてください。

  1. ログイン・リクエストは、データセンター1のクラスター内で処理されます。

  2. 管理者が特定のSAMLセッションのログアウト・リクエストを発行すると、そのリクエストはデータセンター2に送信されます。

データセンター2は、データセンター1(およびHTTPセッションを共有する他のすべてのデータセンター)に存在するすべてのセッションをログアウトする必要があります。

このケースをカバーするために、上記で記述されたSAMLセッション・キャッシュは、個々のクラスター内だけでなく、すべてのデータセンターにわたってレプリケーションする必要があります。例: スタンド・アロンInfinispan/JDGサーバー経由

  1. スタンドアローンのInfinispan/JDGサーバーにキャッシュを追加する必要があります。

  2. 前の項目のキャッシュは、それぞれのSAMLセッション・キャッシュ用にリモートストアとして追加する必要があります。

デプロイ中にリモートストアがSAMLセッション・キャッシュに存在すると、変更が監視され、ローカルSAMLセッション・キャッシュがそれに応じて更新されます。

3.1.9. アサーション属性の取得

SAMLログインが成功したら、アプリケーションのコードで、SAMLアサーションに渡された属性値を取得したい場合があるかもしれません。 HttpServletRequest.getUserPrincipal() は、 org.keycloak.adapters.saml.SamlPrincipal と呼ばれるKeycloak特有のクラスにキャスト可能な、 Principal オブジェクトを返します。このオブジェクトには、未加工のアサーションを参照したり、属性値を取得する便利な機能があります。

package org.keycloak.adapters.saml;

public class SamlPrincipal implements Serializable, Principal {
    /**
     * Get full saml assertion
     *
     * @return
     */
    public AssertionType getAssertion() {
       ...
    }

    /**
     * Get SAML subject sent in assertion
     *
     * @return
     */
    public String getSamlSubject() {
        ...
    }

    /**
     * Subject nameID format
     *
     * @return
     */
    public String getNameIDFormat() {
        ...
    }

    @Override
    public String getName() {
        ...
    }

    /**
     * Convenience function that gets Attribute value by attribute name
     *
     * @param name
     * @return
     */
    public List<String> getAttributes(String name) {
        ...

    }

    /**
     * Convenience function that gets Attribute value by attribute friendly name
     *
     * @param friendlyName
     * @return
     */
    public List<String> getFriendlyAttributes(String friendlyName) {
        ...
    }

    /**
     * Convenience function that gets first  value of an attribute by attribute name
     *
     * @param name
     * @return
     */
    public String getAttribute(String name) {
        ...
    }

    /**
     * Convenience function that gets first  value of an attribute by attribute name
     *
     *
     * @param friendlyName
     * @return
     */
    public String getFriendlyAttribute(String friendlyName) {
        ...
    }

    /**
     * Get set of all assertion attribute names
     *
     * @return
     */
    public Set<String> getAttributeNames() {
        ...
    }

    /**
     * Get set of all assertion friendly attribute names
     *
     * @return
     */
    public Set<String> getFriendlyNames() {
        ...
    }
}

3.1.10. エラー処理

Keycloakには、サーブレットベースのクライアント・アダプター用のエラー処理機能があります。認証でエラーが発生すると、クライアント・アダプターは HttpServletResponse.sendError() を呼び出します。 web.xml ファイル内にerror-pageを設定してエラーを処理することができます。クライアント・アダプターは、400、401、403、500のエラーをスローできます。

<error-page>
    <error-code>403</error-code>
    <location>/ErrorHandler</location>
</error-page>

クライアント・アダプターはまた、取得可能な HttpServletRequest 属性を設定します。属性名は、 org.keycloak.adapters.spi.AuthenticationError です。このオブジェクトを org.keycloak.adapters.saml.SamlAuthenticationError にキャストします。このクラスは、正確に何が起こったかを伝えることができます。この属性が設定されない場合、アダプターはエラーコードに対して何もしません。

public class SamlAuthenticationError implements AuthenticationError {
    public static enum Reason {
        EXTRACTION_FAILURE,
        INVALID_SIGNATURE,
        ERROR_STATUS
    }

    public Reason getReason() {
        return reason;
    }
    public StatusResponseType getStatus() {
        return status;
    }
}

3.1.11. トラブルシューティング

問題を解決する最善の方法は、SAMLクライアント・アダプターとKeycloakサーバーの両方でデバッギングを有効にすることです。ロギング・フレームワークを使用して、 org.keycloak.saml パッケージのログ・レベルを DEBUG に設定します。これを有効にすることで、サーバー間で送信されるSAMLのリクエスト/レスポンスのドキュメントを見ることができます。 ==== 以前のバージョンからの移行

1.9.0への移行
SAML SPクライアント・アダプターの変更

Keycloak SAML SPクライアント・アダプターでは、特定のエンドポイント( /saml )がIdPに登録されている必要があります。SamlFilterもまた、他のバインディングに加えて /saml にもバインドされている必要があります。SAML POSTバインディングがリクエスト入力ストリームを処理することになるため必要でした。これは、依存するクライアントにとって本当に悪いことです。

3.2. mod_auth_mellon Apache HTTPDモジュール

mod_auth_mellon モジュールは、SAML用のApache HTTPDプラグインです。使用している言語/環境がApache HTTPDをプロキシとして使用することをサポートしている場合、mod_auth_mellonを使用してWebアプリケーションをSAMLでセキュリティー保護できます。このモジュールの詳細については、 mod_auth_mellon のGitHubリポジトリーを参照してください。

mod_auth_mellonを設定するには、以下が必要です。

  • アイデンティティ・プロバイダー(IdP)のエンティティー記述子XMLファイル。Keycloakまたは別のSAML IdPへの接続情報を記述します。

  • SPエンティティー記述子XMLファイル。セキュアにするアプリケーションのSAML接続と設定を記述します。

  • 秘密鍵PEMファイル。アプリケーションが文書に署名するために使用する秘密鍵を定義するPEM形式のテキストファイルです。

  • 証明書のPEMファイル。アプリケーションの証明書を定義するテキストファイルです。

  • mod_auth_mellon特有のApache HTTPDモジュールの設定。

Keycloakアプリケーション・サーバーのレルム内にクライアント・アプリケーションを定義して登録している場合、KeycloakはApache HTTPDモジュールの設定を除くすべての必要なファイルを生成できます。

Apache HTTPDモジュールの設定を生成するには、以下のステップを実行します。

  1. SAMLクライアントのインストール・ページに移動し、Mod Auth Mellonファイル・オプションを選択します。

    mod_auth_mellon設定のダウンロード

    mod auth mellon config download

  2. 必要なXML記述子とPEMファイルを含むzipファイルをダウンロードするには、 Download をクリックします。

3.2.1. mod_auth_mellonのKeycloakとの設定

関連するホストは2つあります。

  • Keycloakが実行されているホスト。KeycloakがSAMLアイデンティティー・プロバイダー(IdP)であるため、$idp_hostと呼ばれます。

  • Webアプリケーションが実行されているホスト。$sp_hostと呼ばれます。SAMLでは、IdPを使用するアプリケーションをサービス・プロバイダー(SP)と呼びます。

次のすべての手順は、root特権で$sp_hostに対して実行される必要があります。

パッケージのインストール

必要なパッケージをインストールするには、次のものが必要です。

  • Apache Webサーバー(httpd)

  • Apache用のMellon SAML SPアドオン・モジュール

  • X509証明書を作成するためのツール

必要なパッケージをインストールするには、次のコマンドを実行します。

yum install httpd mod_auth_mellon mod_ssl openssl
Apache SAMLの設定ディレクトリーの作成

ApacheのSAML使用に関する設定ファイルは、1か所に保存することをお勧めします。

Apache設定ルート(/etc/httpd)の下に、saml2という名前の新しいディレクトリーを作成します。

mkdir /etc/httpd/saml2
Mellonサービス・プロバイダーの設定

Apacheアドオン・モジュールの設定ファイルは/etc/httpd/conf.dディレクトリーにあり、拡張子は.confです。/etc/httpd/conf.d/mellon.confファイルを作成し、Mellonの設定ディレクティブをその中に置く必要があります。

Mellonの設定ディレクティブは、大まかに2つのクラスの情報に分類できます。

  • SAML認証で保護するURL

  • 保護されたURLが参照されるときに使用されるSAMLパラメーター。

Apacheの設定ディレクティブは通常、URL空間の階層ツリー構造に従います。これらは、ロケーションとして知られています。Mellonが保護するURLのロケーションを1つ以上指定する必要があります。各場所に適用される設定パラメーターの追加方法には柔軟性があります。ロケーション・ブロックに必要なすべてのパラメーターを追加するか、特定の保護されたロケーションが継承するURLロケーション階層の上位の共通の場所(またはその両方の組み合わせ)にMellonパラメーターを追加できます。どのロケーションがSAMLアクションをトリガーするかにかかわらず、同じ方法でSPが動作するのが一般的であるため、ここで使用されている設定例では、Mellon設定ディレクティブを階層のルートに置き、Mellonによって保護される特定のロケーションを最小限のディレクティブで定義できます。この戦略は、保護された各ロケーションで同じパラメーターを複製することを回避します。

この例では、保護された場所は https://$sp_host/protected 1つだけです。

Mellonサービス・プロバイダーを設定するには、次の手順を実行します。

  1. /etc/httpd/conf.d/mellon.confファイルを次の内容で作成します。

 <Location / >
    MellonEnable info
    MellonEndpointPath /mellon/
    MellonSPMetadataFile /etc/httpd/saml2/mellon_metadata.xml
    MellonSPPrivateKeyFile /etc/httpd/saml2/mellon.key
    MellonSPCertFile /etc/httpd/saml2/mellon.crt
    MellonIdPMetadataFile /etc/httpd/saml2/idp_metadata.xml
 </Location>
 <Location /private >
    AuthType Mellon
    MellonEnable auth
    Require valid-user
 </Location>
上記のコードで参照されているファイルの一部は、後の手順で作成されます。
サービス・プロバイダーのメタデータの作成

SAMLではIdPとSPがXML形式のSAMLメタデータを交換します。メタデータのスキーマは標準であるため、参加するSAMLエンティティーが互いのメタデータを消費できることが保証されます。必要なものは次のとおりです。

  • SPが利用するIdPのメタデータ

  • IdPに提供されたSPを記述するメタデータ

SAMLメタデータのコンポーネントの1つはX509証明書です。この証明書は、2つの目的で使用されます。

  • 受信側が予想される相手から発信されたメッセージを証明できるように、SAMLメッセージに署名します。

  • トランスポート中にメッセージを暗号化します(ほとんどの場合、SAMLメッセージはTLSで保護されたトランスポートで発生するため、使用されません)

すでに認証局(CA)がある場合、または自己署名証明書を生成できる場合は、独自の証明書を使用できます。この例では、簡単のため、自己署名証明書が使用されています。

MellonのSPメタデータは、mod_auth_mellonのインストールされたバージョンの機能を反映する必要があるため、有効なSPメタデータXMLでなければならず、X509証明書(X509証明書の生成に慣れていない限り、その作成は難解になることがあります)を含む必要があります。SPメタデータを生成する最も便利な方法は、mod_auth_mellonパッケージに含まれているツール( mellon_create_metadata.sh )を使用することです。生成されたメタデータは、テキストファイルであるため、後で編集することができます。このツールは、X509の鍵と証明書も作成します。

SAMLのIdPとSPは、EntityIDという固有の名前を使用して自分自身を識別します。Mellonのメタデータ作成ツールを使用するには、次のものが必要です。

  • EntityID。通常SPのURLであり、しばしばSPメタデータを取得できるSPのURLです。

  • SPのSAMLメッセージが消費されるURL(MellonがMellonEndPointPathを呼び出すURL)。

SPメタデータを作成するには、次の手順を実行します。

  1. ヘルパーのシェル変数をいくつか作成します。

    fqdn=`hostname`
    mellon_endpoint_url="https://${fqdn}/mellon"
    mellon_entity_id="${mellon_endpoint_url}/metadata"
    file_prefix="$(echo "$mellon_entity_id" | sed 's/[^A-Za-z.]/_/g' | sed 's/__*/_/g')"
  2. 次のコマンドを実行して、Mellonメタデータ作成ツールを呼び出します。

    /usr/libexec/mod_auth_mellon/mellon_create_metadata.sh $mellon_entity_id $mellon_endpoint_url
  3. 生成されたファイルを目的の場所に移動します(上記の/etc/httpd/conf.d/mellon.confファイルを参照)。

    mv ${file_prefix}.cert /etc/httpd/saml2/mellon.crt
    mv ${file_prefix}.key /etc/httpd/saml2/mellon.key
    mv ${file_prefix}.xml /etc/httpd/saml2/mellon_metadata.xml
Keycloakアイデンティティー・プロバイダーにMellonサービス・プロバイダーを追加する

仮定: project_name}のIdPはすでに$idp_hostにインストールされています。

Keycloakは複数のテナントをサポートしており、すべてのユーザー、クライアントなどがレルムと呼ばれる領域にグループ化されます。各レルムは他のレルムとは独立しています。Keycloakに既存のレルムを使用できますが、この例では、test_realmという新しいレルムを作成し、そのレルムを使用する方法を示しています。

これらの操作はすべて、Keycloak管理Webコンソールを使用して実行されます。$idp_hostの管理者ユーザー名とパスワードが必要です。

次の手順を完了してください。

  1. 管理コンソールを開き、管理者のユーザー名とパスワードを入力してログオンします。

    管理コンソールにログインすると、既存のレルムが存在します。Keycloakを最初に設定すると、デフォルトでルート・レルムのmasterが作成されます。以前に作成されたレルムは、管理コンソールの左上隅にドロップダウン・リストに表示されます。

  2. レルムのドロップダウン・リストから Add realm を選択します。

  3. 名前フィールドに test_realm と入力し、 Create をクリックします。

Mellonサービス・プロバイダーをレルムのクライアントとして追加する

Keycloakでは、SAML SPはクライアントと呼ばれます。SPを追加するには、レルムのクライアントのセクションに移動します。

  1. 左側のClientsメニュー項目をクリックし、右上の Create をクリックして新しいクライアントを作成します。

Mellon SPクライアントの追加

Mellon SPクライアントを追加するには、次の手順を実行します。

  1. クライアント・プロトコルをSAMLに設定します。Client Protocolドロップダウン・リストから、 saml を選択します。

  2. 上記で作成したMellon SPメタデータ・ファイル(/etc/httpd/saml2/mellon_metadata.xml)を提供します。ブラウザーが実行されている場所によっては、$sp_hostからブラウザーが実行されているマシンにSPメタデータをコピーして、ブラウザーがそのファイルを見つけなければならない場合があります。

  3. Save をクリックします。

Mellon SPクライアントの編集

いくつかのクライアント設定パラメータがあります。

  • "Force POST Binding"がオンになっていることを確認します。

  • 有効なリダイレクトURIリストにpaosResponseを追加します。

    1. "Valid Redirect URIs"内のpostResponse URLをコピーし、 "+"のすぐ下の空の追加テキスト・フィールドに貼り付けます。

    2. "postResponse"を"paosResponse"に変更します(SAML ECPにはpaosResponse URLが必要です)。

    3. 下部の Save をクリックしてください。

多くのSAML SPは、グループ内のユーザーのメンバーシップに基づいて認可を決定します。KeycloakのIdPはユーザー・グループ情報を管理できますが、IdPがSAML属性としてそれを提供するように設定されていない限り、ユーザーのグループは提供されません。

ユーザーのグループをSAML属性として提供するようにIdPを設定するには、次の手順を実行します。

  1. クライアントのMapperタブをクリックします。

  2. Mapperページの右上にある Create をクリックします。

  3. Mapper Typeのドロップダウン・リストから Group list を選択します。

  4. "group list"に名前を設定します。

  5. "groups"にSAML属性名を設定します。

  6. Save をクリックします。

残りの手順は$sp_hostで実行されます。

アイデンティティー・プロバイダー・メタデータの取得

IdPでレルムを作成したので、それに関連付けられたIdPメタデータを取得して、Mellon SPがそれを認識できるようにする必要があります。前に作成した/etc/httpd/conf.d/mellon.confファイルでは、MellonIdPMetadataFileは/etc/httpd/saml2/idp_metadata.xmlとして指定されていますが、そのファイルは$sp_host上に存在しませんでした。そのファイルを取得するには、IdPからファイルを検索します。

  1. $idp_hostを正しい値に置き換えて、IdPからファイルを取得します。

    curl -k -o /etc/httpd/saml2/idp_metadata.xml \
    https://$idp_host/auth/realms/test_realm/protocol/saml/descriptor

    これでMellonの設定は完了となります。

  2. Apache設定ファイルの構文チェックを実行するには、次のようにします。

    apachectl configtest
    Configtestは apachectl の -t 引数に相当します。設定テストでエラーが示された場合は、先に進む前に修正してください。
  3. Apacheサーバーを再起動します。

    systemctl restart httpd.service

$ idp_host のIdPに対して認証することで、$sp_host/protected(とその配下すべて)のURLを保護するように、test_realmのSAML IdPとしてKeycloakを、SAML SPとしてmod_auth_mellonを設定しました。

4. Dockerレジストリーの設定

Docker認証はデフォルトで無効です。有効にするには、Profilesを参照してください。

このセクションでは、Keycloakを認証サーバーとして使用するようにDockerレジストリーを設定する方法について説明します。

Dockerレジストリーを設定および設定する方法の詳細については、Docker Registry Configuration Guideを参照してください。

4.1. Dockerレジストリーの設定ファイルのインストール

より高度なDockerレジストリー設定を持つユーザーの場合は、通常、独自のレジストリー設定ファイルを提供することをお勧めします。Keycloak Dockerプロバイダーは、 Registry Config File Format Optionを使用してこのメカニズムをサポートしています。このオプションを選択すると、次のような出力が生成されます。

auth:
  token:
    realm: http://localhost:8080/auth/auth/realms/master/protocol/docker-v2/auth
    service: docker-test
    issuer: http://localhost:8080/auth/auth/realms/master

この出力は、既存のレジストリー設定ファイルにコピーできます。ファイルの設定方法の詳細については、レジストリー設定ファイルの仕様を参照してください。または、基本的な例から始めてください。

rootcertbundle フィールドにKeycloakのレルムの公開証明書の場所を設定するのを忘れないでください。auth設定は、この引数なしでは動作しません。

4.2. Dockerレジストリー環境変数のオーバーライド・インストール

開発やPOC用のDockerレジストリーに単純な環境変数のオーバーライドを使用することが適切な場合がよくあります。このアプローチは、通常プロダクション環境での使用では推奨されていませんが、レジストリーを立ち上げるための安上がりな方法が必要な場合に役立ちます。クライアント・インストール・タブから Variable Override Format Optionを使用するだけで、出力は次のようになります。

REGISTRY_AUTH_TOKEN_REALM: http://localhost:8080/auth/auth/realms/master/protocol/docker-v2/auth
REGISTRY_AUTH_TOKEN_SERVICE: docker-test
REGISTRY_AUTH_TOKEN_ISSUER: http://localhost:8080/auth/auth/realms/master
REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE オーバーライドをKeycloakレルムの公開証明書の場所で設定するのを忘れないでください。auth設定は、この引数なしでは動作しません。

4.3. Docker Compose YAMLファイル

このインストール方法は、Keycloakサーバーで認証するDockerレジストリーを構築する簡易的な方法です。これは開発目的のみを対象としており、プロダクション環境やそれと同等の環境には使用しないでください。

zipファイルのインストール・メカニズムは、KeycloakサーバーがDockerレジストリーとどのようにやりとりができるかを理解したい開発者のために、クイックスタートを提供します。 下記のとおりに設定します。

  1. 目的のレルムから、クライアント設定を作成します。この時点で、Dockerレジストリーはありません。クイックスタートがその部分を担当します。

  2. インストール・タブから"Docker Compose YAML"オプションを選択し、.zipファイルをダウンロードします。

  3. アーカイブを目的の場所に解凍し、ディレクトリーを開きます。

  4. Dockerレジストリーを docker-compose up で起動します。

情報:HTTP BASIC認証のフローはフォームを提示しないので、Dockerレジストリー・クライアントを’master’以外のレルムに設定することをお勧めします。

上記の設定が完了し、KeycloakサーバーとDockerレジストリーが実行されたら、Docker認証が成功するはずです。

[user ~]# docker login localhost:5000 -u $username
Password: *******
Login Succeeded

5. クライアントの登録

Keycloakをアプリケーションまたはサービスで使用するには、Keycloakにクライアントを登録する必要があります。管理者は管理コンソール(または管理RESTエンドポイント)にて登録できますが、クライアント自身でもKeycloakクライアント登録サービスにおいて登録することはできます。

クライアント登録サービスには、Keycloak Client Representations、OpenID Connect Client Meta DataおよびSAML Entity Descriptorsのビルトインサポートが用意されています。クライアント登録サービスのエンドポイントは /realms/<realm>/clients-registrations/<provider> です。

サポートされている組み込みの providers は以下のとおりです。

  • default - Keycloak Client Representation(JSON)

  • install - Keycloakアダプター設定 (JSON)

  • openid-connect - OpenID Connectクライアント・メタデータ・ディスクリプション(JSON)

  • saml2-entity-descriptor - SAMLエンティティー記述子(XML)

以下のセクションでは、異なるプロバイダーを使用する方法を説明します。

5.1. 認証

クライアント登録サービスを呼び出すには、通常トークンが必要です。トークンは、ベアラートークン、初期アクセストークン、登録アクセストークンのいずれかです。いずれのトークンも含まず、同様に新規クライアントを登録する方法がありますが、クライアント登録ポリシー(下記参照)を設定する必要があります。

5.1.1. ベアラートークン

ベアラートークンは、ユーザーやサービス・アカウントに代わって発行されます。エンドポイントを呼び出すには、次の権限が必要です(詳細についてはServer Administration Guideを参照してください)。

  • create-client または manage-client - クライアントの作成権限

  • view-client または manage-client - クライアントの参照権限

  • manage-client - クライアントの更新または削除権限

クライアントを作成するためにベアラートークンを使用する場合、 create-client ロールのみを持つサービス・アカウントのトークンを使用することをお勧めします(詳細については、Server Administration Guideを参照してください)。

5.1.2. 初期アクセストークン

新しいクライアントを登録するための推奨される方法は、初期アクセストークンを使用することです。初期アクセストークンは、クライアントを作成する場合にのみ使用でき、有効期限が設定できるだけでなく、クライアントを作成可能な回数の上限も設定できます。

初期アクセストークンは、管理コンソールで作成できます。新たに初期アクセストークンを作成するには、まず管理コンソールでレルムを選択し、左側のメニューの Realm Settings 、続いてページに表示されるタブの Client Registration をクリックします。そして、最後に Initial Access Tokens のサブタブをクリックします。

これにより既存の初期アクセストークンを参照できるようになります。アクセスできる場合は、不要になったトークンを削除できます。トークン作成時のみその値を取得できます。 Create をクリックして新しいトークンを作成します。必要に応じてトークンの有効期間や、トークンを使用して作成することができるクライアント数を追加できます。 Save をクリックすると、トークンの値が表示されます。

後でトークンを取得することはできないので、このトークンをコピー/ペーストすることが重要です。コピー/ペーストすることを忘れた場合は、そのトークンを削除し、別のトークンを作成してください。

リクエストにAuthorizationヘッダーを追加することにより、トークンの値はクライアント登録サービスを呼び出す際の標準ベアラートークンとして使用されます。以下に例を示します。

Authorization: bearer eyJhbGciOiJSUz...

5.1.3. 登録アクセストークン

クライアント登録サービスを介してクライアントを作成する際には、レスポンスには登録アクセストークンが含まれます。登録アクセストークンは、クライアント設定を取得するだけでなく、クライアントの更新や削除のためのアクセス権を提供します。登録アクセストークンは、ベアラートークンや初期アクセストークンと同じ方法でリクエストに含まれます。登録アクセストークンの使用は一度だけ有効であり、新しいトークンがレスポンスに含まれます。

クライアント登録サービス以外でクライアントが作成された場合、それに関連付けられた登録アクセストークンはありません。管理コンソールを介して、登録アクセストークンを作成できます。これは、特定のクライアントのトークンを紛失した場合に役立ちます。新しいトークンを作成するには、管理コンソールでクライアントを検索し、 Credentials をクリックします。そして、 Generate registration access token をクリックします。

5.2. Keycloak Representations

default クライアント登録プロバイダーは、クライアントを作成、取得、更新、削除するために使用できます。管理コンソールでの設定と同等なクライアント設定のサポートを提供する、Keycloak Client Representation形式を使用します。また、プロトコル・マッパーの設定例が含まれています。

クライアントを作成するには、Client Representation(JSON)を作成し、次にHTTP POSTリクエストを /realms/<realm>/clients-registrations/default に送信します。

登録アクセストークンを含むClient Representationが返されます。設定を取得したり、クライアントを後で更新、削除したい場合は、登録アクセストークンをどこかに保存する必要があります。

Client Representationを取得するには、HTTP GETリクエストを /realms/<realm>/clients-registrations/default/<client id> に送信します。

新しい登録アクセストークンも返します。

Client Representationを更新するには、更新したClient Representationを次のURLにHTTP PUTします: /realms/<realm>/clients-registrations/default/<client id>

新しい登録アクセストークンも返します。

Client Representationを削除するには、HTTP DELETEリクエストを /realms/<realm>/clients-registrations/default/<client id> に送信します。

5.3. Keycloakアダプター設定

installation クライアント登録プロバイダーは、クライアントのアダプター設定を取得するために使用できます。トークン認証に加えて、HTTP BASIC認証を使用してクライアント・クレデンシャルで認証することもできます。 これを行うには、リクエストに次のヘッダーを含めます。

Authorization: basic BASE64(client-id + ':' + client-secret)

アダプター設定を取得するには、HTTP GETリクエストを /realms/<realm>/clients-registrations/install/<client id> に送信します。

パブリック・クライアントは認証が要求されません。これは、JavaScriptアダプターは、上記URLを使用して、直接Keycloakからクライアント設定を読み込めることを意味します。

5.4. OpenID Connect動的クライアント登録

これらの仕様を使用した、Keycloakにクライアントを登録するエンドポイントは、 /realms/<realm>/clients-registrations/openid-connect[/<client id>] です。

このエンドポイントは、そのレルムのOpenID Connect Discoveryエンドポイント( /realms/<realm>/.well-known/openid-configuration )でも見つかります。

5.5. SAMLエンティティー記述子

SAMLエンティティー記述子エンドポイントは、クライアントを作成するために、SAML v2エンティティー記述子を使用することだけをサポートします。クライアントの取得、更新、削除はサポートしていません。これらの操作に対しては、Keycloak represendationのエンドポイントを使用してください。クライアントを作成すると、作成されたクライアントの詳細とともに、Keycloak Client Representationが返されます(登録アクセストークンを含みます)。

クライアントを作成するには、SAMLエンティティー記述子を使用して /realms/<realm>/clients-registrations/saml2-entity-descriptor にHTTP POSTリクエストを送信します。

5.6. CURLを使用した例

CURLを使用して、クライアントID myclient でクライアントを作成する例を次に示します。適切な初期アクセストークンまたはベアラートークンで eyJhbGciOiJSUz…​ を置き換える必要があります。

curl -X POST \
    -d '{ "clientId": "myclient" }' \
    -H "Content-Type:application/json" \
    -H "Authorization: bearer eyJhbGciOiJSUz..." \
    http://localhost:8080/auth/realms/master/clients-registrations/default

5.7. Javaクライアント登録APIを使用した例

クライアント登録Java APIは、Javaを使用してクライアント登録サービスを使いやすくします。使用するには、Mavenに org.keycloak:keycloak-client-registration-api:>VERSION< の依存関係を含めてください。

クライアント登録の使用方法の完全な説明は、JavaDocsを参照してください。以下は、クライアントを作成する例です。 eyJhbGciOiJSUz…​ を適切な初期アクセストークンまたはベアラートークンに置き換える必要があります。

String token = "eyJhbGciOiJSUz...";

ClientRepresentation client = new ClientRepresentation();
client.setClientId(CLIENT_ID);

ClientRegistration reg = ClientRegistration.create()
    .url("http://localhost:8080/auth", "myrealm")
    .build();

reg.auth(Auth.token(token));

client = reg.create(client);

String registrationAccessToken = client.getRegistrationAccessToken();

5.8. クライアント登録ポリシー

Keycloakは現在、クライアント登録サービスを介して新しいクライアントを登録できる2つの方法をサポートしています。

  • 認証済みリクエスト - 新しいクライアントを登録するためのリクエストは、前述の 初期アクセストークン または ベアラートークン のいずれかを含める必要があります。

  • 匿名リクエスト - 新しいクライアントを登録するためのリクエストは、すべての任意のトークンを含める必要はありません。

匿名クライアント登録リクエストは、非常に面白く、強力な機能ですが、誰でも制限なく新しいクライアントを登録できることを通常は望みません。したがって、そのような条件下で、新しいクライアントを登録できるユーザーを制限する方法を提供する、 Client Registration Policy SPI があります。

Keycloak管理コンソールで、 Client Registration タブ、 Client Registration Policies サブタブをクリックします。ここでは、匿名リクエストに対してデフォルトでどのようなポリシーが設定されるか、認証リクエストに対してどのようなポリシーを設定されるかが表示されます。

匿名リクエスト(トークンの無いリクエスト)は、新しいクライアントを作成(登録)することだけが許可されています。したがって、匿名リクエストを使用して新しいクライアントを登録すると、レスポンスにはそのクライアントの読み取り、更新、削除リクエストに使用する登録アクセストークンが含まれます。ただし、匿名登録レスポンスから取得した登録アクセストークンを使用すると、匿名ポリシーの対象にもなります!これは、たとえば、 Trusted Hosts ポリシーがあるならば、クライアント更新リクエストも信頼されたホストから来る必要があることを意味します。また、たとえば、クライアントの更新時に Consent Required ポリシーが存在する場合に、 Consent Required を無効にするなどはできません。

現在、以下のポリシーの実装があります。

  • Trusted Hosts Policy - 信頼されたホストと信頼されているドメインの一覧を設定できます。それらのホストやドメインだけからクライアント登録サービスへのリクエストを送信できます。信頼されていないIPから送信されたリクエストは拒否されます。また、新たに登録されたクライアントのURLは、信頼されたホストやドメインだけを使わなければなりません。たとえば、信頼できないホストを指すクライアントの Redirect URI を設定することは許可されません。デフォルトでは、ホワイトリストに登録されているホストが無いため、匿名クライアント登録は事実上無効になっています。

  • Consent Required Policy - 新たに登録されたクライアントは、 Consent Allowed スイッチが有効になります。したがって、認証成功後、アクセス権(クライアント・スコープ)を承認する必要がある場合、常に同意画面が表示されます。つまり、ユーザーが承認しない限り、クライアントはユーザーの個人情報やアクセス権にアクセスすることができません。

  • Protocol Mappers Policy - プロトコル・マッパー実装のホワイトリストを設定できます。ホワイトリストに無いプロトコル・マッパーが含まれている場合は、新たなクライアントを登録または更新できません。このポリシーは認証済みのリクエストにも使用されるため、認証済みのリクエストに対しても、どのプロトコル・マッパーを使用できるかの制限があることに注意してください。

  • Client Scope Policy - 新たに登録または更新したクライアントで使うことができる Client Scopes のホワイトリスト化を許可します。デフォルトでは、ホワイトリスト化されたスコープはありません。 Realm Default Client Scopes として定義されているクライアント・スコープのみがデフォルトでホワイトリストに登録されています。

  • Full Scope Policy - 新たに登録されたクライアントは Full Scope Allowed スイッチが無効に切り替わります。これは、スコープが設定されたレルム・ロールや他のクライアントのクライアント・ロールが無いことを意味します。

  • Max Clients Policy - レルム内の現在のクライアント数が指定された制限以上の場合、登録を拒否します。匿名登録のデフォルトは200です。

  • Client Disabled Policy - 新たに登録されたクライアントは無効になります。これは、管理者が新しく登録された全てのクライアントを手動で承認し、有効にする必要があることを意味します。このポリシーは、匿名登録でもデフォルトでは使用されません。

6. クライアント登録CLI

クライアント登録CLIは、アプリケーション開発者がKeycloakと統合する際にセルフ・サービスで新しいクライアントを設定するためのコマンドライン・インターフェイス(CLI)ツールです。 これは、Keycloakクライアント登録RESTエンドポイントと対話するように特別に設計されています。

Keycloakを使用できるように、任意のアプリケーションのクライアント設定を作成または取得する必要があります。通常は、一意のホスト名でホストされる新しいアプリケーションごとに、新しいクライアントを設定します。アプリケーションがKeycloakと対話する際に、アプリケーションはクライアントIDで自身を識別し、Keycloakはログイン・ページ、シングル・サインオン(SSO)セッション管理、およびその他のサービスを提供できます。

アプリケーション・クライアントは、クライアント登録CLIを使用してコマンド・ラインから設定でき、シェルスクリプトで使用できます。

特定のユーザーが クライアント登録CLI を使用できるようにするため、通常、Keycloak管理者は管理コンソールを使って新しいユーザーを適切なロールで設定するか、クライアント登録REST APIの権限を与えるように新しいクライアントとクライアント・シークレットを設定します 。

6.1. クライアント登録CLIで使用するための新しい正規ユーザーの設定

  1. 管理コンソール(たとえば、 http://localhost:8080/auth/admin)に admin としてログインします。

  2. 管理するレルムを選択します。

  3. 既存のユーザーを使用する場合は、編集するユーザーを選択します。それ以外の場合は、新しいユーザーを作成します。

  4. Role Mappings > Client Roles > realm-management を選択します。masterレルムにいる場合は、NAME-realm を選択します。ここで、 NAME はターゲット・レルムの名前です。masterレルム内のユーザーに他のレルムへのアクセス権を与えることができます。

  5. Available Roles > manage-client を選択して、クライアント管理権限のフルセットを付与します。別の選択肢として、読み取り専用に view-clients を、または新しいクライアント作成用に create-client を選択します。

    これらの権限は、ユーザーに初期アクセストークンまたは登録アクセストークンを使用せずに操作を実行できるようにします。

It is possible to not assign any realm-management roles to a user. In that case, a user can still log in with the Client Registration CLI but cannot use it without an Initial Access Token. Trying to perform any operations without a token results in a 403 Forbidden error.

管理者は、管理コンソールの Realm Settings > Client Registration > Initial Access Token メニューから初期アクセストークンを発行できます。

6.2. クライアント登録CLIで使用するためのクライアントの設定

デフォルトでは、サーバーはクライアント登録CLIを admin-cli クライアントとして認識します。これは新規レルムごとに自動的に設定されます。ユーザー名でログインする場合、追加のクライアント設定は必要ありません。

  1. Create a new client (for example, reg-cli) if you want to use a separate client configuration for the Client Registration CLI.

  2. Toggle the Standard Flow Enabled setting it to Off.

  3. クライアント Access TypeConfidential に設定し、 Credentials > ClientId and Secret を選択することで、セキュリティーを強化してください。

Credentials タブの下で、 Client Id and Secret または Signed JWT のいずれかを設定できます。

  1. クライアントに関連付けられたサービス・アカウントを使用したい場合は、 管理コンソールClients セクションで編集するクライアントを選択することで、サービス・アカウントを有効にします。

    1. Under Settings, change the Access Type to Confidential, toggle the Service Accounts Enabled setting to On, and click Save.

    2. Click Service Account Roles and select desired roles to configure the access for the service account. For the details on what roles to select, see クライアント登録CLIで使用するための新しい正規ユーザーの設定.

  2. Toggle the Direct Access Grants Enabled setting it to On if you want to use a regular user account instead of a service account.

  3. If the client is configured as Confidential, provide the configured secret when running kcreg config credentials by using the --secret option.

  4. kcreg config credentials を実行する際に使用する clientId を指定します(たとえば、 --client reg-cli )。

  5. サービス・アカウントを有効にすると、 kcreg config credentials を実行するときにユーザーを指定せずに、クライアント・シークレットまたはキーストア情報のみを提供することができます。

6.3. クライアント登録CLIのインストール

The Client Registration CLI is packaged inside the Keycloak Server distribution. You can find execution scripts inside the bin directory. The Linux script is called kcreg.sh, and the Windows script is called kcreg.bat.

Add the Keycloak server directory to your PATH when setting up the client for use from any location on the file system.

以下に例を示します。

  • Linuxの場合:

$ export PATH=$PATH:$KEYCLOAK_HOME/bin
$ kcreg.sh
  • Windowsの場合:

c:\> set PATH=%PATH%;%KEYCLOAK_HOME%\bin
c:\> kcreg

KEYCLOAK_HOME refers to a directory where the Keycloak Server distribution was unpacked.

6.4. クライアント登録CLIの使用

  1. クレデンシャルでログインして、認証されたセッションを開始します。

  2. Client Registration REST エンドポイントでコマンドを実行します。

    以下に例を示します。

    • Linuxの場合:

      $ kcreg.sh config credentials --server http://localhost:8080/auth --realm demo --user user --client reg-cli
      $ kcreg.sh create -s clientId=my_client -s 'redirectUris=["http://localhost:8980/myapp/*"]'
      $ kcreg.sh get my_client
    • Windowsの場合:

      c:\> kcreg config credentials --server http://localhost:8080/auth --realm demo --user user --client reg-cli
      c:\> kcreg create -s clientId=my_client -s "redirectUris=[\"http://localhost:8980/myapp/*\"]"
      c:\> kcreg get my_client

      In a production environment, Keycloak has to be accessed with https: to avoid exposing tokens to network sniffers.

  3. サーバーの証明書が、Javaのデフォルトの証明書トラストストアに含まれている信頼できる証明機関(CA)のいずれかによって発行されていない場合は、 truststore.jks ファイルを準備し、クライアント登録CLIに使用するよう指示します。

    以下に例を示します。

    • Linuxの場合:

      $ kcreg.sh config truststore --trustpass $PASSWORD ~/.keycloak/truststore.jks
    • Windowsの場合:

      c:\> kcreg config truststore --trustpass %PASSWORD% %HOMEPATH%\.keycloak\truststore.jks

6.4.1. ログイン

  1. クライアント登録CLIを使用してログインする際は、サーバーのエンドポイントURLとレルムを指定します。

  2. ユーザー名またはクライアントIDを指定すると、特別なサービス・アカウントが使用されます。ユーザー名を使用する場合は、指定されたユーザーのパスワードを使用する必要があります。クライアントIDを使用する場合は、パスワードの代わりにクライアント・シークレットまたは Signed JWT を使用します。

ログイン方法にかかわらず、ログインするアカウントには、クライアント登録操作を実行するための適切な権限が必要です。master以外のレルムのアカウントは、同じレルム内のクライアントを管理する権限しか持てません。異なるレルムを管理する必要がある場合は、複数のユーザーを異なるレルムで設定するか、 master レルムで1人のユーザーを作成して、異なるレルムのクライアントを管理するロールを追加します。

クライアント登録CLIでユーザーを設定することはできません。管理コンソールのWebインターフェイスまたは管理クライアントCLIを使用して、ユーザーを設定します。詳細については、Server Administration Guideを参照してください。

kcreg が正常にログインすると、認可トークンを受信してプライベート設定ファイルに保存し、その後の呼び出しでトークンを使用できるようにします。設定ファイルの詳細については、代替設定の使用を参照してください。

クライアント登録CLIの使用方法の詳細については、組み込みのヘルプを参照してください。

以下に例を示します。

  • Linuxの場合:

$ kcreg.sh help
  • Windowsの場合:

c:\> kcreg help

認証されたセッションの開始についての詳細は、 kcreg config credentials --help を参照してください。

6.4.2. 代替設定の使用

デフォルトでは、クライアント登録CLIは、ユーザーのホーム・ディレクトリー配下のデフォルトの場所に設定ファイル( ./.keycloak/kcreg.config )を自動的に保存します。 --config オプションを使うと別のファイルや場所を指すことができ、複数の認証済みセッションを並行して処理できます。1つのスレッドから1つの設定ファイルに結び付けられた操作を実行するのが最も安全な方法です。

システム上の他のユーザーが設定ファイルを参照できないようにしてください。設定ファイルには、非公開にしておくべきアクセストークンとシークレットが含まれています。

You might want to avoid storing secrets inside a configuration file by using the --no-config option with all of your commands, even though it is less convenient and requires more token requests to do so. Specify all authentication information with each kcreg invocation.

6.4.3. 初期アクセストークンと登録アクセストークン

Developers who do not have an account configured at the Keycloak server they want to use can use the Client Registration CLI. This is possible only when the realm administrator issues a developer an Initial Access Token. It is up to the realm administrator to decide how and when to issue and distribute these tokens. The realm administrator can limit the maximum age of the Initial Access Token and the total number of clients that can be created with it.

開発者が初期アクセストークンを取得すると、開発者はこれを使用して、 kcreg config credentials で認証せずに新しいクライアントを作成できます。初期アクセストークンは、設定ファイルに保存するか、 kcreg create コマンドの一部として指定することができます。

以下に例を示します。

  • Linuxの場合:

$ kcreg.sh config initial-token $TOKEN
$ kcreg.sh create -s clientId=myclient

または

$ kcreg.sh create -s clientId=myclient -t $TOKEN
  • Windowsの場合:

c:\> kcreg config initial-token %TOKEN%
c:\> kcreg create -s clientId=myclient

または

c:\> kcreg create -s clientId=myclient -t %TOKEN%

初期アクセストークンを使用する場合、サーバー・レスポンスには新しく発行された登録アクセストークンが含まれます。そのクライアントの後続の操作は、そのクライアントに対してのみ有効なトークンで認証することによって実行される必要があります。

クライアント登録CLIはプライベートな設定ファイルを自動的に使用して、このトークンを関連付けられたクライアントと共に保存して使用します。すべてのクライアント操作で同じ設定ファイルが使用されている限り、開発者はこのように作成されたクライアントの読み取り、更新、または削除をするために、認証する必要はありません。

初期アクセストークンおよび登録アクセストークンの詳細については、クライアント登録を参照してください。

クライアント登録CLIでトークンを設定する方法の詳細については、 kcreg config initial-token --helpkcreg config registration-token --help コマンドを実行してください。

6.4.4. クライアント設定の作成

クレデンシャルで認証したり、初期アクセストークンを設定した後の最初のタスクは、通常、新しいクライアントを作成することです。準備されたJSONファイルをテンプレートとして使用し、いくつかの属性を設定または上書きすることがよくあります。

次の例は、JSONファイルを読み込み、それに含まれるクライアントIDを上書きし、他の属性を設定し、作成が成功した後に標準出力に設定を出力する方法を示しています。

  • Linuxの場合:

$ kcreg.sh create -f client-template.json -s clientId=myclient -s baseUrl=/myclient -s 'redirectUris=["/myclient/*"]' -o
  • Windowsの場合:

C:\> kcreg create -f client-template.json -s clientId=myclient -s baseUrl=/myclient -s "redirectUris=[\"/myclient/*\"]" -o

kcreg create コマンドの詳細については、 kcreg create --help を実行してください。

kcreg attrs を使って、利用可能な属性の一覧を取得できます。多くの設定属性の妥当性や一貫性はチェックされません。適切な値を指定する必要があります。また、テンプレートには id フィールドを持たせず、 kcreg create の引数として指定しないことを忘れないでください。

6.4.5. クライアント設定の取得

すでに存在するクライアントについては、 kcreg get コマンドを使用することで取得できます。

以下に例を示します。

  • Linuxの場合:

$ kcreg.sh get myclient
  • Windowsの場合:

C:\> kcreg get myclient

また、Webアプリケーションとパッケージ化できるアダプター設定ファイルとして、クライアント設定を取得することもできます。

以下に例を示します。

  • Linuxの場合:

$ kcreg.sh get myclient -e install > keycloak.json
  • Windowsの場合:

C:\> kcreg get myclient -e install > keycloak.json

kcreg get コマンドの詳細については、 kcreg get --help コマンドを実行してください。

6.4.6. クライアント設定の更新

クライアント設定の更新には2つの方法があります。

1つ目の方法は、現在の設定を取得してファイルに保存し、編集してから、新しい状態をサーバーにPOSTで送信する方法です。

以下に例を示します。

  • Linuxの場合:

$ kcreg.sh get myclient > myclient.json
$ vi myclient.json
$ kcreg.sh update myclient -f myclient.json
  • Windowsの場合:

C:\> kcreg get myclient > myclient.json
C:\> notepad myclient.json
C:\> kcreg update myclient -f myclient.json

2つ目の方法は、現在のクライアントをフェッチし、そのクライアント上のフィールドを設定または削除し、一度にPOSTで送信する方法です。

以下に例を示します。

  • Linuxの場合:

$ kcreg.sh update myclient -s enabled=false -d redirectUris
  • Windowsの場合:

C:\> kcreg update myclient -s enabled=false -d redirectUris

適用される変更のみを含むファイルを使用することもできるので、引数に多くの値を指定する必要はありません。この場合、 --merge をクライアント登録CLIに指定すると、JSONファイルは完全な新しい設定として扱われるのではなく、既存の設定に適用される属性のセットとして扱われます。

以下に例を示します。

  • Linuxの場合:

$ kcreg.sh update myclient --merge -d redirectUris -f mychanges.json
  • Windowsの場合:

C:\> kcreg update myclient --merge -d redirectUris -f mychanges.json

kcreg update コマンドの詳細については、 kcreg update --help コマンドを実行してください。

6.4.7. クライアント設定の削除

クライアントを削除するには、以下の例を使用します。

  • Linuxの場合:

$ kcreg.sh delete myclient
  • Windowsの場合:

C:\> kcreg delete myclient

kcreg delete コマンドの詳細については、 kcreg delete --help コマンドを実行してください。

6.4.8. 無効な登録アクセストークンのリフレッシュ

--no-config モードを使用して作成、読み込み、更新、削除(CRUD)操作を実行すると、クライアント登録CLIは登録アクセストークンを処理できなくなります。その場合、クライアントのために最も最近発行された登録アクセストークンの追跡を失う可能性があり、 manage-clients 権限を持つアカウントで認証なしでは、そのクライアントでそれ以上のCRUD操作を実行することは不可能になります。

権限を持っている場合は、クライアント用に新しい登録アクセストークンを発行し、標準出力に出力するか、選択した設定ファイルに保存することができます。それ以外の場合は、レルム管理者にクライアントの新しい登録アクセストークンを発行して、それを送信するよう依頼する必要があります。その際は、 --token オプションを使ってCRUDコマンドに渡すことができます。また、 kcreg config registration-token コマンドを使って新しいトークンを設定ファイルに保存し、クライアント登録CLIが自動的にそれを処理するようにすることもできます。

kcreg update-token コマンドの詳細については、 kcreg update-token --help コマンドを実行してください。

6.5. トラブルシューティング

  • Q:ログインすると、次のエラーが表示されます:*Parameter client_assertion_type is missing [invalid_client]

    A:このエラーメッセージは、クライアントが Signed JWT のトークン・クレデンシャルで設定されていることを意味します。つまり、ログイン時に --keystore パラメータを使用する必要があります。

7. トークンの交換

Keycloakにおいて、トークンの交換とはクレデンシャルまたはトークンのセットを使用して、全く異なるトークンを取得するプロセスです。クライアントは信頼性の低いアプリケーションを呼び出すかもしれず、現在のトークンをダウングレードしたい場合があります。クライアントは、リンクされたソーシャル・プロバイダー・アカウントのために保存されたトークンを、Keycloakトークンに交換したいことがあります。他のKeycloakのレルムや外部IDPによって作成された外部トークンを信頼することができます。クライアントはあるユーザーに成り代わる必要があるかもしれません。トークンの交換に関するKeycloakの現在の機能の概要を簡単に説明します。

  • クライアントは、特定のクライアントに対して作成された既存のKeycloakトークンを、別のクライアントをターゲットとする新しいトークンと交換することができます

  • クライアントは既存のKeycloakトークンを外部トークン(つまりリンクされたFacebookアカウント)と交換できます

  • クライアントは、外部トークンをKeycloakトークンに交換できます。

  • クライアントはユーザーに成り代わることができます。

Keycloakのトークンの交換は、OAuth Token Exchangeの仕様の非常にルーズな実装です。Keycloakでは、それを少し拡張し、一部を無視し、仕様の他の部分をルーズに解釈しました。これは、あるレルムのOpenID Connectトークン・エンドポイントでの単純なグラント・タイプの呼び出しです。

/realms/{realm}/protocol/openid-connect/token

フォーム・パラメーター( application/x-www-form-urlencoded )を入力として受け取り、出力は交換をリクエストしたトークンのタイプに依存します。トークンの交換はクライアント・エンドポイントであるため、リクエストは呼び出し元のクライアントに認証情報を提供する必要があります。パブリック・クライアントは、クライアント識別子をフォーム・パラメーターとして指定します。コンフィデンシャルクライアントは、フォーム・パラメーターを使用してクライアントIDとシークレット、BASIC認証を渡すこともできますが、管理者はレルム内でクライアント認証フローを設定することもできます。 フォーム・パラメーターのリストは次のとおりです

client_id

REQUIRED MAYBE 。このパラメーターは、認証にフォーム・パラメーターを使用するクライアントに必要です。BASIC認証、クライアントJWTトークン、またはクライアント証明書認証を使用している場合は、このパラメーターを指定しないでください。

client_secret

REQUIRED MAYBE 。 このパラメーターは、認証にフォーム・パラメーターを使用し、クレデンシャルとしてクライアント・シークレットを使用するクライアントに必要です。レルム内のクライアント呼び出しが別の方法で認証されている場合は、このパラメータを指定しないでください。

grant_type

REQUIRED 。パラメータの値は urn:ietf:params:oauth:grant-type:token-exchange でなければなりません。

subject_token

OPTIONAL 。リクエストを送信したユーザーの代りのパーティのアイデンティティーを表すセキュリティー・トークンです。既存のトークンを新しいトークンと交換する場合に必要です。

subject_issuer

OPTIONALsubject_token の発行者を識別します。トークンが現在のレルムによるものの場合、または発行者が subject_token_type から決定できる場合は、空白のままにすることができます。それ以外の場合は、指定する必要があります。有効な値は、レルムに設定された Identity Provider のエイリアスです。または、特定の Identity Provider によって設定された発行者クレーム識別子です。

subject_token_type

OPTIONAL 。このパラメータは subject_token パラメータで渡されるトークンのタイプです。 subject_token がレルムのものでアクセス・トークンである場合、これはデフォルトで urn:ietf:params:oauth:token-type:access_token になります。それが外部トークンである場合、このパラメータは subject_issuer の要件に応じて、指定する必要がある場合とない場合があります。

requested_token_type

OPTIONAL 。このパラメータは、クライアントが交換したいトークンのタイプを表します。現在、トークン・タイプとしてOAuthとOpenID Connectのみがサポートされています。デフォルト値は、これが urn:ietf:params:oauth:token-type:refresh_token であるかどうかによって決まります。この場合、レスポンス内でアクセス・トークンとリフレッシュ・トークンの両方が返されます。その他の適切な値は urn:ietf:params:oauth:token-type:access_tokenurn:ietf:params:oauth:token-type:id_token です。

audience

OPTIONAL 。このパラメータには、新しいトークンを作成する対象となるクライアントを指定します。

requested_issuer

OPTIONAL 。このパラメーターは、クライアントが外部プロバイダーによって作成されたトークンを必要とすることを指定します。これは、レルム内で設定された Identity Provider のエイリアスでなければなりません。

requested_subject

OPTIONAL 。クライアントが別のユーザーに成り代わる場合は、ユーザー名またはユーザーIDを指定します。

scope

NOT IMPLEMENTED 。このパラメーターは、クライアントが要求しているOAuthおよびOpenID Connectのスコープのセットを表します。現時点では実装されていませんが、Keycloakがスコープの一般的なサポートを強化した後に利用可能になります。

現在のところ、OpenID ConnectとOAuthの交換のみサポートしています。SAMLベースのクライアントおよびアイデンティティー・プロバイダーのサポートは、将来、ユーザーの要求に応じて追加される可能性があります。

トークン交換の呼び出しの成功レスポンスは、クライアントがリクエストする requested-token-typerequested_issuer に依存したコンテンツ・タイプとともにHTTP 200レスポンス・コードを返します。OAuthでリクエストされたトークン・タイプの場合は、OAuth Token Exchangeの仕様に記載されているJSONドキュメントを返します。

{
   "access_token" : ".....",
   "refresh_token" : ".....",
   "expires_in" : "...."
 }

リフレッシュ・トークンを要求するクライアントは、レスポンス内のアクセス・トークンとリフレッシュ・トークンの両方を取得し直します。アクセス・トークン・タイプのみを要求するクライアントは、レスポンス内のアクセス・トークンを取得します。 requested_issuer パラメータを介して外部発行者を要求するクライアントに対して、有効期限情報が含まれる場合と含まれない場合があります。

エラー・レスポンスは一般的に400 HTTPレスポンス・コード・カテゴリーに該当しますが、エラーの重大度に応じて他のエラー・ステータスコードが返されることがあります。エラー・レスポンスには、 requested_issuer に応じた内容が含まれます。OAuthベースのトークン交換では、次のようにJSON文書が返ることがあります。

{
   "error" : "...."
   "error_description" : "...."
}

トークン交換のタイプによっては追加のエラー・クレームが返されることがあります。たとえば、ユーザーがアイデンティティー・プロバイダーへのリンクを持っていない場合、OAuthアイデンティティー・プロバイダーは追加の account-link-url クレームを含めることがあります。このリンクは、クライアントが開始したリンク・リクエストに使用できます。

トークン交換のセットアップには細かい粒度の管理権限が必要です(詳細はServer Administration Guideのリンクを参照してください)。クライアントに交換の権限を付与する必要があります。これについては、この章の後半で説明します。

この章では、セットアップの要件について説明し、さまざまな交換のシナリオの例を示します。簡単にするために、現在のレルムで作成されたトークンを 内部 トークン、外部レルムまたはアイデンティティー・プロバイダーが作成したトークンを 外部 トークンとして呼ぶことにします。

7.1. 内部トークンから内部トークンへの交換

内部トークンから内部トークンへの交換で、特定のクライアントに発行された既存のトークンを、別のターゲット・クライアント用に作成された新しいトークンと交換する必要があります。なぜこれをしたいのでしょうか?これは一般に、クライアントはトークンを持っているが、別のアクセス・トークンのクレームと権限を必要とする他のアプリケーションに対して、追加のリクエストを行う必要がある場合に発生します。このタイプの交換が必要なその他の理由は、信頼性の低いアプリケーションでアプリケーションを呼び出す必要があり、現在のアクセス・トークンを伝播したくない場合に"権限のダウングレード"を実行する必要がある場合です。

7.1.1. 交換のための権限を付与

別のクライアントとトークンを交換したいクライアントは、管理コンソールで認可される必要があります。交換の権限を与えたいターゲット・クライアントに token-exchange のきめ細かい権限を定義する必要があります。

ターゲット・クライアントの権限

exchange target client permission unset

Permissions Enabled スイッチをtrueに切り替えます。

ターゲット・クライアントの権限

exchange target client permission set

このページに token-exchange のリンクがあります。クリックすると、権限の定義が開始され、このページに移動します。

ターゲット・クライアントの交換権限のセットアップ

exchange target client permission setup

この権限に対するポリシーを定義する必要があります。 Authorization のリンクをクリックし、 Policies タブに行き、 Client ポリシーを作成してください。

クライアント・ポリシーの作成

exchange target client policy

ここでは、開始するクライアント、つまりトークン交換を要求している認証済みクライアントを入力します。このポリシーを作成したら、ターゲット・クライアントの token-exchange の権限に戻り、今定義したクライアント・ポリシーを追加します。

クライアント・ポリシーの適用

exchange target client exchange apply policy

これでクライアントは交換を実行する権限を持ちます。これを正しく行わないで交換しようとすると、403 Forbiddenのレスポンスが表示されます。

7.1.2. リクエストの実行

クライアントがターゲットとする別のクライアントのトークンを既存のトークンと交換しているときは、 audience パラメーターを使用する必要があります。このパラメーターは、管理コンソールで設定したターゲット・クライアントのクライアント識別子である必要があります。

curl -X POST \
    -d "client_id=starting-client" \
    -d "client_secret=geheim" \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
    -d "subject_token=...." \
    --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:refresh_token" \
    -d "audience=target-client" \
    http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token

subject_token パラメーターは、ターゲット・レルムのアクセス・トークンでなければなりません。 requested_token_type パラメーターがリフレッシュ・トークン・タイプの場合、レスポンスにはアクセス・トークン、リフレッシュ・トークン、および有効期限の全てが含まれます。この呼び出しから返されるJSONレスポンスの例を、次に示します。

{
   "access_token" : "....",
   "refresh_token" : "....",
   "expires_in" : 3600
}

7.2. 内部トークンから外部のトークンへの交換

レルムのトークンを、外部アイデンティティー・プロバイダーによって作成された外部トークンに交換することができます。この外部アイデンティティー・プロバイダーは、管理コンソールの Identity Provider セクション内で設定する必要があります。現在のところ、OAuth/OpenID Connectベースの外部アイデンティティー・プロバイダーのみがサポートされています。これには、すべてのソーシャル・プロバイダーが含まれます。Keycloakは、外部プロバイダーへのバックチャネル交換を実行しません。したがって、アカウントがリンクされていない場合、外部トークンを取得することはできません。外部トークンを取得するには、次のいずれかの条件を満たす必要があります。

  • ユーザーは、外部アイデンティティー・プロバイダーに少なくとも1回はログインしている必要があります。

  • ユーザーは、外部アイデンティティー・プロバイダーにユーザー・アカウント・サービスを介してリンクしている必要があります。

  • ユーザー・アカウントは、Client Initiated Account Linking APIを使用して外部アイデンティティー・プロバイダーを介してリンクされています。

最後に、外部アイデンティティー・プロバイダーがトークンを保存するように設定されている必要があります。または、上記のアクションの1つが、交換する内部トークンと同じユーザー・セッションで実行されている必要があります。

アカウントがリンクされていない場合、交換レスポンスにはリンクの確立に使用できるリンクが含まれます。これについては、リクエストの実行のセクションで詳しく説明します。

7.2.1. 交換のための権限を付与

呼び出し側のクライアントに外部アイデンティティー・プロバイダーとトークンを交換する権限を与えるまで、内部トークンから外部トークンへの交換リクエストは、403 Forbiddenレスポンスで拒否されます。クライアントに権限を与えるには、アイデンティティー・プロバイダーの設定ページの Permissions タブに移動する必要があります。

アイデンティティー・プロバイダーの権限

exchange idp permission unset

Permissions Enabled スイッチをtrueに切り替えます。

アイデンティティー・プロバイダーの権限

exchange idp permission set

このページに token-exchange のリンクがあります。クリックすると、権限の定義が開始され、このページに移動します。

アイデンティティー・プロバイダーの交換権限のセットアップ

exchange idp permission setup

この権限に対するポリシーを定義する必要があります。 Authorization のリンクをクリックし、 Policies タブに行き、 Client ポリシーを作成してください。

クライアント・ポリシーの作成

exchange idp client policy

ここでは、開始するクライアント、つまりトークン交換を要求している認証済みクライアントを入力します。このポリシーを作成したら、アイデンティティー・プロバイダーの token-exchange の権限に戻り、今定義したクライアント・ポリシーを追加します。

クライアント・ポリシーの適用

exchange idp apply policy

これでクライアントは交換を実行する権限を持ちます。これを正しく行わないで交換しようとすると、403 Forbiddenのレスポンスが表示されます。

7.2.2. リクエストの実行

クライアントが既存の内部トークンを外部トークンと交換する場合は、 requested_issuer パラメーターを指定する必要があります。パラメーターは、設定済みのアイデンティティー・プロバイダーのエイリアスでなければなりません。

curl -X POST \
    -d "client_id=starting-client" \
    -d "client_secret=geheim" \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
    -d "subject_token=...." \
    --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
    -d "requested_issuer=google" \
    http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token

subject_token パラメーターは、ターゲット・レルムのアクセス・トークンでなければなりません。 requested_token_type パラメーターは、 urn:ietf:params:oauth:token-type:access_token またはブランクのままでなければなりません。現時点では、それ以外の要求されたトークン・タイプはサポートされていません。この呼び出しから返される成功のJSONレスポンスの例を次に示します。

{
   "access_token" : "....",
   "expires_in" : 3600
   "account-link-url" : "https://...."
}

外部アイデンティティー・プロバイダーが何らかの理由でリンクされていない場合は、このJSONドキュメントでHTTP 400レスポンス・コードが返ります。

{
   "error" : "....",
   "error_description" : "..."
   "account-link-url" : "https://...."
}

error クレームは、 token_expirednot_linked のどちらかになります。 account-link-url クレームは、クライアントがClient Initiated Account Linkingを実行できるように提供されています。ほとんど(すべて?)のプロバイダーは、ブラウザーOAuthプロトコルを介してリンクする必要があります。 account-link-url では、 redirect_uri クエリー・パラメータを追加するだけで、ブラウザーを転送してリンクを実行することができます。

7.3. 外部トークンから内部トークンへの交換

外部アイデンティティー・プロバイダーが発行した外部トークンを信頼して、内部トークンに交換することができます。これは、レルム間のブリッジや、ソーシャル・プロバイダーのトークンの信頼に使用できます。これは、アイデンティティー・プロバイダーのブラウザーのログインと同様に動作します。新しいユーザーが存在しない場合、そのユーザーはレルムにインポートされます。

外部トークン交換の現在の制限は、外部トークンが既存のユーザーにマップされている場合、既存のユーザーに外部アイデンティティー・プロバイダーへのアカウント・リンクがない限り、交換は許可されないということです。

交換が完了すると、レルム内にユーザー・セッションが作成され、 requested_token_type パラメーター値に応じて、アクセス・トークンまたはリフレッシュ・トークンを受け取れます。この新しいユーザー・セッションは、タイムアウトするまで、またはこの新しいアクセス・トークンを渡すレルムのログアウト・エンドポイントを呼び出すまで、アクティブなままであることに注意してください。

これらのタイプの変更には、管理コンソールで設定されたアイデンティティー・プロバイダーが必要でした。

現時点では、SAMLアイデンティティー・プロバイダーはサポートされていません。Twitterのトークンも交換できません。

7.3.1. 交換のための権限を付与

外部トークンの交換が可能になる前に、発信側のクライアントが交換を行うための権限を与える必要があります。この権限は、内部トークンから外部トークンへの交換権限の付与と同じ方法で付与されます。

値が呼び出し側以外の別のクライアントを指し示す audience パラメーターも指定した場合、呼び出し側クライアントに audience パラメーターで特定のターゲット・クライアントに交換する権限を与える必要があります。これを行う方法については、このセクションの前半で説明しています。

7.3.2. リクエストの実行

subject_token_type は、 urn:ietf:params:oauth:token-type:access_token または urn:ietf:params:oauth:token-type:jwt のいずれかでなければなりません。タイプが urn:ietf:params:oauth:token-type:access_token の場合、 subject_issuer パラメーターを指定しなければなりません。また、設定されたアイデンティティー・プロバイダーのエイリアスでなければなりません。タイプが urn:ietf:params:oauth:token-type:jwt の場合、プロバイダーは、プロバイダーのエイリアスであるJWT内の issuer クレームまたは、プロバイダー設定内の登録された発行者と一致します。

トークンがアクセス・トークンである場合、プロバイダーのUserInfoサービスが呼び出されてトークンを検証します。呼び出しが成功することは、アクセス・トークンが有効であることを意味します。サブジェクト・トークンがJWTであり、プロバイダーが署名検証を有効にしている場合は、それが試行され、そうでない場合は、デフォルトでトークンを検証するためにUserInfoサービスが呼び出されます。

デフォルトでは、発行された内部トークンは、呼び出し元クライアント用に定義されたプロトコル・マッパーを使用してトークンの内容を判断するため、呼び出し元クライアントを使用します。あるいは、 audience パラメーターを使って別のターゲット・クライアントを指定することもできます。

curl -X POST \
    -d "client_id=starting-client" \
    -d "client_secret=geheim" \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
    -d "subject_token=...." \
    -d "subject_issuer=myOidcProvider" \
    --data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
    -d "audience=target-client" \
    http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token

requested_token_type パラメーターがリフレッシュ・トークン・タイプの場合、レスポンスにはアクセス・トークン、リフレッシュ・トークン、および有効期限の両方が含まれます。この呼び出しで返されるJSONレスポンスの例を次に示します。

{
   "access_token" : "....",
   "refresh_token" : "....",
   "expires_in" : 3600
}

7.4. Impersonation

内部トークン交換と外部トークン交換の場合、クライアントはユーザーの代わりに別のユーザーに成り代わるように要求できます。たとえば、サポート・エンジニアが問題をデバッグできるように、ユーザーに成り変わる必要がある管理アプリケーションがあるとします。

7.4.1. 交換のための権限を付与

サブジェクト・トークンが表すユーザーには、他のユーザーに成り代わる権限が必要です。この権限を有効にする方法については、Server Administration Guideを参照してください。ロールを通じて、またはきめ細かい管理権限を使って行うことができます。

7.4.2. リクエストの実行

request_subject パラメーターを追加で指定しない限り、他の章で説明したようにリクエストを行います。このパラメーターの値は、ユーザー名またはユーザーIDでなければなりません。

curl -X POST \
    -d "client_id=starting-client" \
    -d "client_secret=geheim" \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
    -d "subject_token=...." \
    --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
    -d "audience=target-client" \
    -d "requested_subject=wburke" \
    http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token

7.5. ダイレクト・ネイキッドな成り代わり

subject_token を指定せずに、内部トークンの交換要求を行うことができます。これは、ダイレクト・ネイキッドな成り代わりと呼ばれます。クライアントがそのレルム内の任意のユーザーに成り代わる可能性があるため、クライアントに多くの信頼を置くからです。交換するサブジェクト・トークンを取得することが不可能なアプリケーションをブリッジするためにこれが必要となるかもしれません。たとえば、LDAPに直接ログインするレガシー・アプリケーションを統合したいかもしれません。その場合、従来のアプリケーションはユーザー自身を認証できますが、トークンを取得することができません。

クライアントにダイレクト・ネイキッドな成り代わりを有効にすることは非常に危険です。クライアントのクレデンシャルが盗まれた場合、そのクライアントはシステム内のすべてのユーザーに成り代わる可能性があります。

7.5.1. 交換のための権限を付与

audience パラメーターが提供されている場合、呼び出し側クライアントはクライアントとの交換権限を持っていなければなりません。これを設定する方法については、この章の前半で説明します。

さらに、呼び出し元のクライアントにユーザーに成り代わる権限が与えられている必要があります。管理コンソールで、 Users 画面を表示し、 Permissions タブをクリックしてください。

ユーザーの権限

exchange users permission unset

Permissions Enabled スイッチをtrueに切り替えます。

アイデンティティー・プロバイダーの権限

exchange users permission set

ページに impersonation リンクがあります。クリックすると、権限の定義が開始され、このページに移動します。

ユーザー成り代わり権限のセットアップ

exchange users permission setup

この権限に対するポリシーを定義する必要があります。 Authorization のリンクをクリックし、 Policies タブに行き、 Client ポリシーを作成してください。

クライアント・ポリシーの作成

exchange users client policy

ここでは、開始するクライアント、つまりトークン交換を要求している認証済みクライアントを入力します。このポリシーを作成したら、ユーザーの impersonation 権限に戻り、今定義したクライアント・ポリシーを追加します。

クライアント・ポリシーの適用

exchange users apply policy

クライアントにユーザーに成り代わる権限が付与されました。これを正しく行わないと、これを交換のタイプにしようとする際に、403 Forbiddenのレスポンスが表示されます。

パブリック・クライアントはダイレクト・ネイキッドな成り代わりを行うことができません。

7.5.2. リクエストの実行

リクエストを行うには、 requested_subject パラメーターを指定してください。これは、有効なユーザーのユーザー名またはユーザーIDでなければなりません。また、必要に応じて audience パラメーターを指定することもできます。

curl -X POST \
    -d "client_id=starting-client" \
    -d "client_secret=geheim" \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
    -d "requested_subject=wburke" \
    http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token

7.6. サービス・アカウントの権限モデルの拡張

クライアントに交換の権限を付与する際に、クライアントごとに権限を手動で有効にする必要はありません。クライアントに関連付けられているサービス・アカウントがある場合は、ロールを使用して権限をグループ化し、クライアントのサービス・アカウントにロールを割り当てて、交換の権限を割り当てることができます。たとえば、 naked-exchange ロールを定義し、そのロールを持つサービス・アカウントでネイキッドな交換を行うことができます。

7.7. 交換の脆弱性

トークン交換の許可を行う上で、意識して気をつけなければならないさまざまなことがあります。

1つはパブリック・クライアントです。パブリック・クライアントは、交換を実行するためにクライアント・クレデンシャルを持たない、または必要としません。有効なトークンを持っていれば、パブリック・クライアントに偽装することができ、パブリック・クライアントに実行が許可されている交換を実行できます。レルムで管理されている信頼できないクライアントがある場合、パブリック・クライアントは許可モデルで脆弱性を公開する可能性があります。このため、ダイレクト・ネイキッド交換ではパブリック・クライアントは許可されず、呼び出し元のクライアントがパブリックの場合は、エラーで中止されます。

FacebookやGoogleなどが提供するソーシャル・トークンをレルム・トークンと交換することが可能です。これらのソーシャル・ウェブサイト上で偽のアカウントを作成するのが難しくないため、交換するトークンで何ができるのかを注意して自警してください。デフォルトのロール、グループ、およびアイデンティティー・プロバイダーのマッパーを使用して、外部ソーシャル・ユーザーに割り当てられる属性とロールを制御します。

ダイレクト・ネイキッド交換は非常に危険です。呼び出し元のクライアントに対して、クライアントのクレデンシャルが漏洩しないということを非常に信頼しています。これらのクレデンシャルが漏洩した場合、攻撃者はシステム内の誰かに偽装する可能性があります。これは、既存のトークンを持つコンフィデンシャル・クライアントとはまったく対照的です。2要素の認証(アクセス・トークンとクライアントのクレデンシャル)がありますが、1ユーザーしか扱っていません。したがって、ダイレクト・ネイキッド交換は控えめに使用してください。