1. 概要
Keycloakは、OpenID Connect(OAuth 2.0 への拡張)とSAML 2.0の両方をサポートしています。クライアントとサービスをセキュリティー保護する際に最初に決定すべきことは、どちらを使用するのかということです。必要に応じて、一部をOpenID Connectで、それ以外をSAMLでセキュリティー保護することも選択できます。
クライアントとサービスをセキュリティー保護するためには、選択したプロトコルに対応するアダプターやライブラリーも必要になります。Keycloakには選択したプラットフォームに対応する独自のアダプターが付属していますが、一般的なOpenID Connectのリライング・パーティーやSAMLのサービス・プロバイダーのライブラリーを使用することもできます。
1.1. クライアント・アダプターとは?
Keycloakのクライアント・アダプターは、Keycloakとともに使用してアプリケーションとサービスを非常に簡単にセキュリティー保護できるライブラリーです。基盤となるプラットフォームやフレームワークとのタイトな統合を提供するので、ライブラリーではなく、アダプターと呼んでいます。このような考え方により、アダプターは使いやすく、一般的にライブラリーが必要とするよりも定型コードが少なくて済みます。
1.2. サポートされているプラットフォーム
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サーバーにユーザーの認証を要求するアプリケーションのユースケースです。ログインが成功すると、アプリケーションは IDトークン と アクセストークン を受け取ります。 IDトークン には、ユーザーに関する情報(ユーザー名、電子メール、その他のプロファイル情報など)が含まれています。 アクセストークン はレルムによってデジタル署名されており、アプリケーションがユーザーのアクセス可能なリソースを決定するために使用できるアクセス情報(ユーザー・ロール・マッピングのような)が含まれています。
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,
"verify-token-audience" : 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が必要です。有効な値はall
、external
、none
です。 - 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-With
、SOAPAction
、Accept
のような典型的なヘッダーに基づいて、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サーバーにプールすべき接続数を定義します。これは 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-required
がnone
かdisable-trust-manager
がtrue
でない限り、 REQUIRED です。 - truststore-password
-
トラストストアのパスワードです。これは REQUIRED で、
truststore
を設定すると、トラストストアはパスワードを必要とします。 - client-keystore
-
キーストア・ファイルへのファイルパスです。このキーストアには、アダプターがKeycloakサーバーにHTTPSリクエストを行う際の、双方向SSLのためのクライアント証明書を含めます。これは OPTIONAL です。
- client-keystore-password
-
クライアント・キーストア用のパスワードです。
client-keystore
が設定されている場合、これは REQUIRED です。 - client-key-password
-
クライアントキー用のパスワードです。
client-keystore
が設定されている場合、これは REQUIRED です。 - always-refresh-token
-
true の場合、アダプターはすべてのリクエストでトークンをリフレッシュします。警告 - 有効にすると、アプリケーションへのすべてのリクエストに対してKeycloakへのリクエストが発生します。
- register-node-at-startup
-
true の場合、アダプターはKeycloakに登録リクエストを送信します。これはデフォルトで false であり、アプリケーションがクラスター化されている場合にのみ有効です。詳細はアプリケーション・クラスタリングを参照してください。
- register-node-period
-
Keycloakへアダプターを再登録する期間です。アプリケーションがクラスター化されている場合に便利です。詳細はアプリケーション・クラスタリングを参照してください。
- token-store
-
設定可能な値は session と cookie です。デフォルトは session です。つまり、アダプターがアカウント情報をHTTPセッションに保管します。一方、 cookie は情報をクッキーに格納することを意味します。詳細はアプリケーション・クラスタリングを参照してください。
- token-cookie-path
-
Cookieストアを使用する場合、このオプションにはアカウント情報を保存するために使用されるCookieのパスを設定します。相対パスの場合、アプリケーションはコンテキスト・ルートで実行されていると見なされ、そのコンテキスト・ルートに対して相対的に解釈されます。絶対パスの場合は、絶対パスを使用してCookieのパスを設定します。デフォルトではコンテキスト・ルートからの相対パスを使用します。
- principal-attribute
-
ユーザー・プリンシパル名とするOpenID ConnectのIDトークン属性を設定します。トークン属性がnullの場合、デフォルトは
sub
になります。有効な値はsub
、preferred_username
、email
、name
、nickname
、given_name
、family_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に一致する正規表現であり、値が置換文字列であるオブジェクト表記法で表します。置換文字列の後方参照に
$
文字を使用できます。 - verify-token-audience
-
true
に設定されている場合、ベアラートークンによる認証中に、アダプターはトークンにこのクライアント名(リソース)がAudienceとして含まれているかどうかを検証します。このオプションは、ベアラートークンによって認証されたリクエストを主に処理するサービスに特に便利です。これはデフォルトでfalse
に設定されていますが、セキュリティーを強化するため、これを有効にすることをお勧めします。オーディエンス・サポートの詳細については、 Audienceのサポート を参照してください。
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の新しいバージョンがリリースされると、現在のアダプターは非推奨になり、WildFlyの次のリリース後にサポートが削除されます。もう一つの選択肢は、JBoss EAPアダプターの場合はより長期間サポートされるので、アプリケーションをWildFlyからJBoss EAPに切り替えることです。 |
WildFly 9以上へのインストールは次のとおりです。
$ cd $WILDFLY_HOME
$ unzip keycloak-wildfly-adapter-dist-13.0.1.zip
JBoss EAP 7へのインストールは次のとおりです。
$ cd $EAP_HOME
$ unzip keycloak-eap7-adapter-dist-13.0.1.zip
JBoss EAP 6へのインストールは次のとおりです。
$ cd $EAP_HOME
$ unzip keycloak-eap6-adapter-dist-13.0.1.zip
JBoss AS 7.1へのインストールは次のとおりです。
$ cd $JBOSS_HOME
$ unzip keycloak-as7-adapter-dist-13.0.1.zip
このZIPアーカイブには、Keycloakアダプター固有のJBossモジュールが含まれています。また、アダプター・サブシステムを設定するためのJBoss CLIスクリプトも含まれています。
サーバーが起動していない場合に、アダプター・サブシステムを設定するには、次のようにします。
あるいは、別の設定を使用してアダプターをインストールするため、コマンドラインからアダプターをインストールする際に server.config プロパティーを指定することもできます。たとえば、 -Dserver.config=standalone-ha.xml とします。
|
$ ./bin/jboss-cli.sh --file=bin/adapter-elytron-install-offline.cli
$ ./bin/jboss-cli.sh --file=bin/adapter-install-offline.cli
WildFly 11以上でもレガシーな非Elytronアダプターが使用できます。つまり、それらのバージョンでも adapter-install-offline.cli を使用することができます。ただし、新しいElytronアダプターを使用することをお勧めします。
|
あるいは、サーバーが起動している場合は、次のように実行します。
$ ./bin/jboss-cli.sh -c --file=bin/adapter-elytron-install.cli
$ ./bin/jboss-cli.sh -c --file=bin/adapter-install.cli
JBoss SSO
WildFlyには、同じWildFlyインスタンスにデプロイされたWebアプリケーションのシングル・サインオンのサポートが組み込まれています。これは、Keycloakを使用しているときは有効にしないでください。
WARごとに必要な設定
このセクションでは、直接WARパッケージ内に設定を追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。
まず、WARの WEB-INF
ディレクトリーに keycloak.json
アダプター設定ファイルを作成しておく必要があります。
この設定ファイルの形式は、Javaアダプターの設定のセクションで説明しています。
次に、 web.xml
内の auth-method
を KEYCLOAK
に設定する必要があります。また、標準のサーブレット・セキュリティーを使用して、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-method
に KEYCLOAK
を指定する必要はありませんが、 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-deployment
の name
属性は保護したい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>
2.1.3. RPMからのJBoss EAPアダプターのインストール
次のように、RPMからEAP 7アダプターをインストールします。
Red Hat Enterprise Linux 7では、チャンネルという用語はリポジトリーという用語に置き換えられました。これらの説明では、リポジトリーという用語のみが使用されています。 |
RPMからWildFly 7アダプターをインストールする前に、WildFly 23リポジトリーをサブスクライブする必要があります。
-
Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。
-
すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。
Red Hat Enterprise Linux 6、7の場合:Red Hat Subscription Managerを使用して、次のコマンドでWildFly 23リポジトリーに登録します。Red Hat Enterprise Linuxバージョンに応じて、 <RHEL_VERSION> を6または7のいずれかに置き換えてください。
$ sudo subscription-manager repos --enable=jb-eap-7-for-rhel-<RHEL_VERSION>-server-rpms
Red Hat Enterprise Linux 8の場合:Red Hat Subscription Managerを使用して、次のコマンドでWildFly 23リポジトリーに登録します。
$ sudo subscription-manager repos --enable=jb-eap-23-for-rhel-8-x86_64-rpms --enable=rhel-8-for-x86_64-baseos-rpms --enable=rhel-8-for-x86_64-appstream-rpms
Red Hat Enterprise Linux 6、7で次のコマンドを使用して、OIDC用のWildFly 7アダプターをインストールします。
$ sudo yum install eap7-keycloak-adapter-sso7_4
または、次のいずれかをRed Hat Enterprise Linux 8に使用します。
$ sudo dnf install eap7-keycloak-adapter-sso7_4
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リポジトリーにサブスクライブする必要があります。
-
Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。
-
すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。
Red Hat Subscription Managerを使用して、次のコマンドを使用してJBoss EAP 6リポジトリーにサブスクライブします。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_4-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 12は Jetty 9.2 server にバンドルされており、Jettyはさまざまな種類のWebアプリケーションの実行に使用されているため、JBoss Fuse 6はJetty 9アダプターを活用しています。
サポートされているFuse 6のバージョンは最新リリースのみです。以前のバージョンの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の管理者アクセス
Fuse 6内でWebアプリケーションを保護する
最初にKeycloak Karafの機能をインストールする必要があります。次に、セキュリティー保護するアプリケーションの種類に応じた手順を実行する必要があります。参照されているすべてのWebアプリケーションで、Keycloak Jettyオーセンティケーターを、基盤となるJettyサーバーに注入する必要があります。これを達成するための手順は、アプリケーションの種類によって異なります。詳細は以下のとおりです。
始めるのに最適なのは、 fuse
ディレクトリー内のKeycloakのサンプルの一部としてバンドルされているFuseのデモを見ることです。ほとんどの手順はテストとデモから理解できるはずです。
Keycloakフィーチャーのインストール
最初に keycloak
フィーチャーをJBoss Fuse環境にインストールする必要があります。 keycloak
フィーチャーには、Fuseアダプターとサード・パーティーのすべての依存関係が含まれます。Mavenリポジトリーまたはアーカイブからインストールすることができます。
Mavenリポジトリーからのインストール
前提条件として、オンラインでMavenリポジトリーにアクセスできる必要があります。
コミュニティー版の場合、すべてのアーティファクトとサード・パーティーの依存関係がMavenのセントラル・リポジトリーで利用できるため、オンラインにするだけで十分です。
Mavenリポジトリーを使用して、Keycloakフィーチャーをインストールするには、以下の手順を実行します。
-
JBoss Fuse 6.3.0 Rollup 12を開始します。Karafターミナルで以下のとおりにタイプします。
features:addurl mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features features:install keycloak
-
以下のようにJetty 9フィーチャーをインストールする必要があるかもしれません。
features:install keycloak-jetty9-adapter
-
以下のようにフィーチャーがインストールされていることを確認します。
features:list | grep keycloak
ZIPバンドルからのインストール
これは、オフラインになっている場合や、Mavenを使用してJARファイルやその他のアーティファクトを取得したくない場合に便利です。
ZIPアーカイブからFuseアダプターをインストールするには、次の手順を実行します。
-
Keycloak FuseアダプターのZIPアーカイブをダウンロードしてください。
-
JBoss Fuseのルート・ディレクトリーに解凍します。依存関係にあるファイルは
system
ディレクトリーの下にインストールされます。既存のすべてのjarファイルが上書きされます。JBoss Fuse 6.3.0 Rollup 12には、これを使用します。
cd /path-to-fuse/jboss-fuse-6.3.0.redhat-254 unzip -q /path-to-adapter-zip/keycloak-fuse-adapter-13.0.1.zip
-
Fuseを起動し、Fuse/Karafターミナルで次のコマンドを実行します。
features:addurl mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features features:install keycloak
-
対応するJettyアダプターをインストールします。アーティファクトはJBoss Fuseの
system
ディレクトリーから直接利用できるので、Mavenリポジトリーを使う必要はありません。
クラシックWARアプリケーションのセキュリティー保護
WARアプリケーションをセキュリティー保護するために必要な手順は次のとおりです。
-
/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>
-
-
オーセンティケーターを設定した
/WEB_INF/jetty-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>
-
WARの
/WEB-INF/
ディレクトリー内に、新しいkeycloak.json
ファイルを作成します。この設定ファイルの形式は、Javaアダプターの設定のセクションで説明しています。外部アダプターの設定で説明されているように、外部でこのファイルを使用することもできます。 -
WARアプリケーションが
org.keycloak.adapters.jetty
とMETA-INF/MANIFEST.MF
ファイルのImport-Package
ヘッダーの下にあるパッケージをインポートしていることを確認してください。プロジェクトでmaven-bundle-plugin
を使うと、マニフェストにOSGIヘッダーが正しく生成されます。パッケージの "*" による解決はorg.keycloak.adapters.jetty
パッケージをインポートしないことに注意してください。アプリケーションやBlueprint、Spring記述子では使用されず、jetty-web.xml
ファイルで使用されるためです。インポートするパッケージのリストは次のようになります。
org.keycloak.adapters.jetty;version="13.0.1", org.keycloak.adapters;version="13.0.1", org.keycloak.constants;version="13.0.1", org.keycloak.util;version="13.0.1", org.keycloak.*;version="13.0.1", *;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でサーブレットをセキュリティー保護するには、次の手順を実行します。
-
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
ファイルは必要ありません。
-
-
META-INF/MANIFEST.MF
のImport-Package
は、少なくとも以下のインポートを含んでいなければなりません。org.keycloak.adapters.jetty;version="13.0.1", org.keycloak.adapters;version="13.0.1", org.keycloak.constants;version="13.0.1", org.keycloak.util;version="13.0.1", org.keycloak.*;version="13.0.1", *;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&matchOnUriPrefix=true" />
<process ref="helloProcessor" />
<log message="The message from camel endpoint contains ${body}"/>
</route>
</camelContext>
</blueprint>
-
META-INF/MANIFEST.MF
のImport-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="[9,10)",
org.eclipse.jetty.server.nio;version="[9,10)",
org.eclipse.jetty.util.security;version="[9,10)",
org.keycloak.*;version="13.0.1",
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エンドポイントを実行するには、以下の手順に沿って行います。
-
アプリケーションに
META-INF/spring/beans.xml
を追加し、KeycloakJettyAuthenticator
を注入したJettyのSecurityHandler
でhttpj: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>
-
META-INF/MANIFEST.MF
のImport-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="[9,10)",
org.eclipse.jetty.util.security;version="[9,10)",
org.keycloak.*;version="13.0.1"
デフォルトの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.MF
のImport-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="[9,10)",
org.eclipse.jetty.util.security;version="[9,10)",
org.keycloak.*;version="13.0.1",
org.keycloak.adapters.jetty;version="13.0.1",
*;resolution:=optional
Fuse管理サービスのセキュリティー保護
FuseターミナルへのSSH認証の使用
Keycloakは、主にWebアプリケーションの認証のユースケースを扱います。ただし、他のWebサービスやアプリケーションがKeycloakで保護されている場合は、KeycloakのクレデンシャルでSSHなどのWeb以外の管理サービスを保護するのが最善の方法です。これは、Keycloakへのリモート接続を許可し、リソース・オーナー・パスワード・クレデンシャルに基づいてクレデンシャルを検証するJAASログイン・モジュールを使用して実行できます。
SSH認証を有効にするには、次の手順を実行します。
-
Keycloakでは、SSH認証に使用されるクライアント(たとえば、
ssh-jmx-admin-client
)を作成します。このクライアントでは、Direct Access Grants Enabled
がOn
に選択されている必要があります。 -
$FUSE_HOME/etc/org.apache.karaf.shell.cfg
ファイルで、次のとおりにこのプロパティーを更新または指定します。sshRealm=keycloak
-
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レルムから使用するクライアント・アプリケーションの設定を指定します。 -
Fuseを起動し、
keycloak
JAASレルムをインストールしてください。最も簡単な方法は、JAASレルムがあらかじめ定義されたkeycloak-jaas
フィーチャーをインストールすることです。より高いランクの独自keycloak
JAASレルムを使用して、フィーチャーに定義済みのレルムをオーバーライドすることができます。詳細については、 JBoss Fuse documentationを参照してください。Fuseターミナルで次のコマンドを使用します。
features:addurl mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features features:install keycloak-jaas
-
SSHで
admin
ユーザーとしてログインするには、ターミナルで次のように入力します。ssh -o PubkeyAuthentication=no -p 8101 admin@localhost
-
パスワードは
password
でログインしてください。
最近のオペレーティング・システムでは、SSHコマンドの-oオプションを -o HostKeyAlgorithms=+ssh-dss として使用する必要があるかもしれません。これは、最近のSSHクライアントではデフォルトで ssh-dss アルゴリズムを使用できないためです。しかし、現在JBoss Fuse 6.3.0 Rollup 12ではデフォルトで使用されています。
|
ユーザーはすべての操作を実行するために、レルムロール admin
を持つ必要があることに注意してください。また、操作のサブセットを実行するためには別のロールが必要となります(たとえば、読み取り専用のKarafコマンドのみを実行するようにユーザーを制限する viewer ロール)。利用可能なロールは、 $FUSE_HOME/etc/org.apache.karaf.shell.cfg
または $FUSE_HOME/etc/system.properties
で設定されます。
JMX認証の使用
jconsoleまたは別の外部ツールを使用してRMI経由でJMXにリモート接続する場合は、JMX認証が必要になることがあります。それ以外の場合は、デフォルトでhaolt.ioにjolokiaエージェントがインストールされているので、hawt.io/jolokiaを使用する方がよいでしょう。詳細については、Hawtio Admin Consoleを参照してください。
JMX認証を使用するには、次の手順を実行します。
-
$FUSE_HOME/etc/org.apache.karaf.management.cfg
ファイルで、jmxRealm
プロパティーを次のように変更します。jmxRealm=keycloak
-
上記のSSHのセクションで説明したように、
keycloak-jaas
フィーチャーをインストールし、$FUSE_HOME/etc/keycloak-direct-access.json
ファイルを設定してください。 -
jconsoleでは、次のようなURLを使用できます。
service:jmx:rmi://localhost:44444/jndi/rmi://localhost:1099/karaf-root
クレデンシャルはadmin/password(利用環境の管理者権限を持つユーザー次第)です。
Hawtio管理コンソールのセキュリティー保護
Keycloakを使用して、Hawtio管理コンソールをセキュリティー保護するには、以下の手順を実行します。
-
これらのプロパティーを
$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
-
利用レルムのKeycloak管理コンソールにクライアントを作成します。たとえば、Keycloakの
demo
レルムでクライアントhawtio-client
を作成し、アクセス・タイプとしてpublic
を指定し、Hawtio: http://localhost:8181/hawtio/* を指すリダイレクトURIを指定します。また、対応するWeb Origin(この場合は、 http://localhost:8181)も設定する必要があります。 -
$FUSE_HOME/etc
ディレクトリーにkeycloak-hawtio-client.json
ファイルを作成します。このファイルは、以下の例のような内容で作成します。Keycloak環境に応じて、realm
、resource
、auth-server-url
の各プロパティーを変更してください。resource
プロパティーは前のステップで作成されたクライアントを指し示さなければなりません。このファイルは、クライアント(Hawtio JavaScriptアプリケーション)側で使用されます。{ "realm" : "demo", "resource" : "hawtio-client", "auth-server-url" : "http://localhost:8080/auth", "ssl-required" : "external", "public-client" : true }
-
$FUSE_HOME/etc
ディレクトリーにkeycloak-hawtio.json
ファイルを作成します。このファイルは、以下の例のような内容です。Keycloakの環境に応じてrealm
とauth-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" }
-
Keycloakフィーチャーをまだインストールしていない場合は、JBoss Fuse 6.3.0 Rollup 12を起動し、インストールしてください。Karafターミナルのコマンドはこの例に似ています。
features:addurl mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features features:install keycloak
-
http://localhost:8181/hawtio に移動し、Keycloakのレルムからユーザーとしてログインします。
Hawtioに対して正常に認証するには、ユーザーが適切なレルムロールを持っている必要があることに注意してください。利用可能なロールは、
hawtio.roles
の$FUSE_HOME/etc/system.properties
ファイルで設定されます。
JBoss EAP 6.4上のHawtioのセキュリティー保護
JBoss EAP 6.4サーバーでHawtioを実行するには、以下の手順を実行します。
-
前のセクション(Hawtio管理コンソールをセキュリティー保護する)で説明したように、Keycloakを設定します。次のように仮定します。
-
Keycloakのレルムのデモとクライアント
hawtio-client
を持っている -
Keycloakが
localhost:8080
で動作している -
展開されたHawtioがあるJBoss EAP 6.4サーバーは
localhost:8181
で動作します。このサーバーのディレクトリーは、次のステップでは、$EAP_HOME
と呼ばれます。
-
-
hawtio-wildfly-1.4.0.redhat-630396.war
アーカイブを$EAP_HOME/standalone/configuration
ディレクトリーにコピーします。Hawtioの導入の詳細については、 Fuse Hawtio documentationを参照してください。 -
上記内容の
keycloak-hawtio.json
ファイルとkeycloak-hawtio-client.json
ファイルを$EAP_HOME/standalone/configuration
ディレクトリーにコピーします。 -
JBossアダプターのドキュメントの説明に従って、Keycloakアダプター・サブシステムをJBoss EAP 6.4サーバーにインストールします。
-
$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>
-
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>
-
hawtio
のsecure-deployment
セクションをアダプター・サブシステムに追加してください。これにより、Hawtio WARがJAASログイン・モジュール・クラスを見つけることができます。<subsystem xmlns="urn:jboss:domain:keycloak:1.1"> <secure-deployment name="hawtio-wildfly-1.4.0.redhat-630396.war" /> </subsystem>
-
HawtioとJBoss EAP 6.4サーバーを再起動します。
cd $EAP_HOME/bin ./standalone.sh -Djboss.socket.binding.port-offset=101
-
Hawtio( http://localhost:8181/hawtio )へアクセスしてください。Keycloakによってセキュリティー保護されています。
2.1.5. JBoss Fuse 7アダプター
Keycloakは JBoss Fuse 7 内で実行されているWebアプリケーションのセキュリティー保護をサポートしています。
JBoss Fuse 7は、基本的に同等であるUndertowアダプターを利用しています。 EAP 7 / WildFlyアダプター JBoss Fuse 7.4.0は Undertow HTTP engine にバンドルされており、Undertowはさまざまな種類のWebアプリケーションの実行に使用されています。
サポートされているFuse 7のバージョンは最新リリースのみです。以前のバージョンのFuse 7を使用している場合、一部の機能が正しく動作しない可能性があります。特に、7.0.1より前のバージョンのFuse 7では、統合はまったく機能しません。 |
Fuseに対して、以下の項目のセキュリティーがサポートされています。
-
Pax Web War Extenderを使用して、FuseにデプロイされたクラシックWARアプリケーション
-
Pax Web Whiteboard Extenderを使用してFuseにOSGIサービスとしてデプロイされたサーブレットと、さらに標準のOSGi Enterprise HTTP Serviceであるorg.osgi.service.http.HttpService#registerServlet()によって登録されたサーブレット
-
Camel Undertow コンポーネントで動作する Apache Camel Undertowエンドポイント
-
独自の分離されたUndertowエンジンで動作する Apache CXF エンドポイント
-
CXFサーブレットによって提供されるデフォルト・エンジンで実行されている Apache CXF エンドポイント
-
SSHおよびJMXの管理者アクセス
Fuse 7内でWebアプリケーションを保護する
最初にKeycloak Karafのフィーチャーをインストールする必要があります。次に、セキュリティー保護するアプリケーションの種類に応じた手順を実行する必要があります。参照されているすべてのWebアプリケーションで、Keycloak Undertow認証メカニズムを、基盤となるWebサーバーに注入する必要があります。これを達成するための手順は、アプリケーションの種類によって異なります。詳細は以下のとおりです。
始めるのに最適なのは、 fuse
ディレクトリー内のKeycloakのサンプルの一部としてバンドルされているFuseのデモを見ることです。ほとんどの手順はテストとデモから理解できるはずです。
Keycloakフィーチャーのインストール
最初に keycloak-pax-http-undertow
と keycloak-jaas
のフィーチャーをJBoss Fuse環境にインストールする必要があります。 keycloak-pax-http-undertow
フィーチャーには、Fuseアダプターとサードパーティーのすべての依存関係が含まれます。 keycloak-jaas
には、SSHとJMX認証のためにレルムで使用されるJAASモジュールが含まれています。Mavenリポジトリーまたはアーカイブからインストールすることができます。
Mavenリポジトリーからのインストール
前提条件として、オンラインでMavenリポジトリーにアクセスできる必要があります。
コミュニティー版の場合、すべてのアーティファクトとサード・パーティーの依存関係がMavenのセントラル・リポジトリーで利用できるため、オンラインにするだけで十分です。
Mavenリポジトリーを使用して、Keycloakフィーチャーをインストールするには、以下の手順を実行します。
-
JBoss Fuse 7.4.0を開始します。Karafターミナルで以下のとおりにタイプします。
feature:repo-add mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features feature:install keycloak-pax-http-undertow keycloak-jaas
-
以下のようにUndertowフィーチャーをインストールする必要もあるかもしれません。
feature:install pax-http-undertow
-
以下のようにフィーチャーがインストールされていることを確認します。
feature:list | grep keycloak
ZIPバンドルからのインストール
これは、オフラインになっている場合や、Mavenを使用してJARファイルやその他のアーティファクトを取得したくない場合に便利です。
ZIPアーカイブからFuseアダプターをインストールするには、次の手順を実行します。
-
Keycloak FuseアダプターのZIPアーカイブをダウンロードしてください。
-
JBoss Fuseのルート・ディレクトリーに解凍します。依存関係にあるファイルは
system
ディレクトリーの下にインストールされます。既存のすべてのjarファイルが上書きされます。JBoss Fuse 7.4.0には、これを使用します。
cd /path-to-fuse/fuse-karaf-7.z unzip -q /path-to-adapter-zip/keycloak-fuse-adapter-13.0.1.zip
-
Fuseを起動し、Fuse/Karafターミナルで次のコマンドを実行します。
feature:repo-add mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features feature:install keycloak-pax-http-undertow keycloak-jaas
-
対応するUndertowアダプターをインストールします。アーティファクトはJBoss Fuseの
system
ディレクトリーから直接利用できるので、Mavenリポジトリーを使う必要はありません。
クラシックWARアプリケーションのセキュリティー保護
WARアプリケーションをセキュリティー保護するために必要な手順は次のとおりです。
-
/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>
-
-
WARの
/WEB-INF/
ディレクトリー内に、新しいkeycloak.json
ファイルを作成します。この設定ファイルの形式は、Javaアダプターの設定のセクションで説明しています。外部アダプターの設定で説明されているように、外部でこのファイルを使用することもできます。例:
{ "realm": "demo", "resource": "customer-portal", "auth-server-url": "http://localhost:8080/auth", "ssl-required" : "external", "credentials": { "secret": "password" } }
-
Fuse 6アダプターとは異なり、MANIFEST.MFには特別なOSGiのインポートは必要ありません。
設定リゾルバー
keycloak.json
アダプター設定ファイルはバンドル内か(デフォルトの動作)、ファイルシステム上のディレクトリーに保存することができます。設定ファイルの実際のソースを指定するには、 keycloak.config.resolver
配備パラメーターを目的の設定リゾルバークラスに設定します。たとえば、古典的なWARアプリケーションでは、 web.xml
ファイルに keycloak.config.resolver
コンテキスト・パラメーターを以下のように設定します。
<context-param>
<param-name>keycloak.config.resolver</param-name>
<param-value>org.keycloak.adapters.osgi.PathBasedKeycloakConfigResolver</param-value>
</context-param>
keycloak.config.resolver
には、次のリゾルバーがあります。
- org.keycloak.adapters.osgi.BundleBasedKeycloakConfigResolver
-
これがデフォルトのリゾルバーです。設定ファイルは、セキュリティー保護されているOSGiバンドル内にあります。デフォルトでは、
WEB-INF/keycloak.json
という名前のファイルをロードしますが、このファイル名はconfigLocation
プロパティーで設定できます。 - org.keycloak.adapters.osgi.PathBasedKeycloakConfigResolver
-
このリゾルバーは、
keycloak.config
システム・プロパティーで指定されたフォルダーの中で<your_web_context>-keycloak.json
というファイルを探します。keycloak.config
が設定されていなければ、代わりにkaraf.etc
システム・プロパティーが使われます。たとえば、Webアプリケーションがコンテキスト
my-portal
にデプロイされている場合、アダプターの設定は${keycloak.config}/my-portal-keycloak.json
ファイルか${karaf.etc}/my-portal-keycloak.json
のいずれかからロードされます。 - org.keycloak.adapters.osgi.HierarchicalPathBasedKeycloakConfigResolver
-
このリゾルバーは、上記の
PathBasedKeycloakConfigResolver
に似ています。与えられたURIパスに対して、設定の場所が手当たり次第にチェックされます。たとえば、URIが
/my/web-app/context
の場合、設定場所が存在するまで、次のものが存在するかどうかが検索されます。-
${karaf.etc}/my-web-app-context-keycloak.json
-
${karaf.etc}/my-web-app-keycloak.json
-
${karaf.etc}/my-keycloak.json
-
${karaf.etc}/keycloak.json
-
OSGIサービスとしてデプロイされたサーブレットのセキュリティー保護
クラシックなWARアプリケーションとしてデプロイされていないOSGIバンドルされたプロジェクト内にサーブレット・クラスがある場合、この方式を使用できます。FuseはPax Web Whiteboard Extenderを使用して、サーブレットをWebアプリケーションとしてデプロイします。
Keycloakでサーブレットをセキュリティー保護するには、次の手順を実行します。
-
Keycloakは
org.keycloak.adapters.osgi.undertow.PaxWebIntegrationService
を提供します。これにより、アプリケーションに認証方法とセキュリティー制約の設定を設定できます。アプリケーション内の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"> <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>
-
プロジェクト内に
WEB-INF
ディレクトリー(プロジェクトがWebアプリケーションでない場合でも)を用意し、クラシックWARアプリケーションのセクションのような/WEB-INF/keycloak.json
ファイルを作成する必要があります。security-constraintsがblueprint設定ファイルで宣言されているので、web.xml
ファイルは必要ありません。
-
-
Fuse 6アダプターとは異なり、MANIFEST.MFには特別なOSGiのインポートは必要ありません。
Apache Camelアプリケーションのセキュリティー保護
camel-undertowコンポーネントで実装されたApache Camelエンドポイントをセキュリティー保護するには、適切なセキュリティー制約をBlueprintを介して注入し、使用されるコンポーネントを undertow-keycloak
に更新します。以下のような設定で、 OSGI-INF/blueprint/blueprint.xml
ファイルをCamelアプリケーションに追加する必要があります。ロール、セキュリティー制約のマッピング、およびアダプターの設定は、使用する環境と必要性により若干異なる場合があります。
標準の undertow
コンポーネントと比較して、 undertow-keycloak
コンポーネントは次の2つの新しいプロパティーを追加します。
-
configResolver
は、Keycloakアダプター設定を提供するリゾルバービーンです。利用可能なリゾルバーは、設定リゾルバーセクションにリストされています。 -
allowedRoles
はカンマで区切られたロールのリストです。サービスにアクセスするユーザーは、アクセスを許可されるロールを少なくとも1つは持っていなければなりません。
例:
<?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&configResolver=#keycloakConfigResolver&allowedRoles=admin" />
<process ref="helloProcessor" />
<log message="The message from camel endpoint contains ${body}"/>
</route>
</camelContext>
</blueprint>
-
META-INF/MANIFEST.MF
のImport-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="13.0.1",
org.osgi.service.blueprint,
org.osgi.service.blueprint.container
Camel RestDSL
Camel RestDSLは、流暢な方法でRESTエンドポイントを定義するために使用されるCamelの機能です。しかし、依然として特定の実装クラスを使用し、Keycloakとの統合方法に関する指示を提供する必要があります。
統合機構を設定する方法は、RestDSLで定義されたルートを設定するCamelコンポーネントによって異なります。
次の例は、 undertow-keycloak
コンポーネントを使用して統合を設定する方法を示しています。前回のBlueprintの例で定義されたBeanのいくつかを参照しています。
<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>
分離されたUndertowエンジンでのApache CXFエンドポイントのセキュリティー保護
分離されたUndertowエンジンで、Keycloakによってセキュリティー保護されたCXFエンドポイントを実行するには、以下の手順を実行します。
-
アプリケーションに
OSGI-INF/blueprint/blueprint.xml
を追加し、その中にCamelの設定と同様の適切な設定リゾルバービーンを追加します。httpu:engine-factory
の中で、そのCamelの設定を使ってorg.keycloak.adapters.osgi.undertow.CxfKeycloakAuthHandler
ハンドラーを宣言します。CFX JAX-WSアプリケーションの設定は、次のようになります。<?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>
-
META-INF/MANIFEST.MF
のImport-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="13.0.1"
デフォルトのUndertowエンジンでのApache CXFエンドポイントの保護
いくつかのサービスは、起動時にデプロイされたサーブレットを自動的に提供します。そのようなサービスの1つは、 http://localhost:8181/cxf コンテキストで実行されているCXFサーブレットです。FuseのPax Webは、設定管理を介して既存のコンテキストを変更することをサポートしています。これは、Keycloakでエンドポイントを保護するために使用できます。
アプリケーション内の設定ファイル OSGI-INF/blueprint/blueprint.xml
は、以下のようになります。アプリケーションにJAX-RSの customerservice
エンドポイント(アプリケーション固有のエンドポイント)を追加することに注意してください。
<?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>
</blueprint>
さらに ${karaf.etc}/org.ops4j.pax.web.context-anyName.cfg file
を作成する必要があります。これは、 pax-web-runtime
バンドルによって追跡されるファクトリーPID設定として扱われます。このような設定には、標準の web.xml
のいくつかのプロパティーに対応する以下のプロパティーを含めることができます。
bundle.symbolicName = org.apache.cxf.cxf-rt-transports-http
context.id = default
context.param.keycloak.config.resolver = org.keycloak.adapters.osgi.HierarchicalPathBasedKeycloakConfigResolver
login.config.authMethod = KEYCLOAK
security.cxf.url = /cxf/customerservice/*
security.cxf.roles = admin, user
設定管理ファイルで利用可能なプロパティーの詳細については、Fuseのドキュメントを参照してください。上記のプロパティーの意味は次のとおりです。
bundle.symbolicName
とcontext.id
-
org.ops4j.pax.web.service.WebContainer
内のバンドルとその配備コンテキストの識別。 context.param.keycloak.config.resolver
-
古典的なWARの
web.xml
とまったく同じバンドルへのkeycloak.config.resolver
コンテキスト・パラメーターの値を提供します。使用可能なリゾルバーについては、設定リゾルバーのセクションで説明しています。 login.config.authMethod
-
認証方法。
KEYCLOAK
でなければなりません。 security.anyName.url
とsecurity.anyName.roles
-
web.xml
のsecurity-constraint/web-resource-collection/url-pattern
とsecurity-constraint/auth-constraint/role-name
に設定されているように、それぞれ、ロールはカンマとその周囲の空白で区切られます。anyName
識別子は任意ですが、同じセキュリティー制約の個々のプロパティーに一致する必要があります。一部のFuseのバージョンには、ロールを
", "
(カンマと単一のスペース)で区切らなければならないバグがあります。ロールを区切るためにこの表記法を正確に使用してください。
META-INF/MANIFEST.MF
の Import-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}"
Fuse管理サービスのセキュリティー保護
FuseターミナルへのSSH認証の使用
Keycloakは、主にWebアプリケーションの認証のユースケースを扱います。ただし、他のWebサービスやアプリケーションがKeycloakで保護されている場合は、KeycloakのクレデンシャルでSSHなどのWeb以外の管理サービスを保護するのが最善の方法です。これは、Keycloakへのリモート接続を許可し、リソース・オーナー・パスワード・クレデンシャルに基づいてクレデンシャルを検証するJAASログイン・モジュールを使用して実行できます。
SSH認証を有効にするには、次の手順を実行します。
-
Keycloakでは、SSH認証に使用されるクライアント(たとえば、
ssh-jmx-admin-client
)を作成します。このクライアントでは、Direct Access Grants Enabled
がOn
に選択されている必要があります。 -
$FUSE_HOME/etc/org.apache.karaf.shell.cfg
ファイルで、次のとおりにこのプロパティーを更新または指定します。sshRealm=keycloak
-
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レルムから使用するクライアント・アプリケーションの設定を指定します。 -
Fuseを起動し、
keycloak
のJAASレルムをインストールしてください。最も簡単な方法は、JAASレルムがあらかじめ定義されたkeycloak-jaas
機能をインストールすることです。独自のkeycloak
JAASレルムを使用して、より高いランクでその機能の定義済みレルムを上書きすることができます。詳細については、 JBoss Fuse documentation を参照してください。Fuseターミナルで次のコマンドを使用します。
features:addurl mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features features:install keycloak-jaas
-
SSHで
admin
ユーザーとしてログインするには、ターミナルで次のように入力します。ssh -o PubkeyAuthentication=no -p 8101 admin@localhost
-
パスワードは
password
でログインしてください。
最近のオペレーティング・システムでは、SSHコマンドの-oオプション -o HostKeyAlgorithms=+ssh-dss を使用する必要があります。これは、最近のSSHクライアントではデフォルトで ssh-dss アルゴリズムの使用は許可されていないためです。しかし、JBoss Fuse 7.4.0では現在デフォルトで使用されています。
|
ユーザーはすべての操作を実行するために、レルムロール admin
を持つ必要があることに注意してください。また、操作のサブセットを実行するためには別のロールが必要となります(たとえば、読み取り専用のKarafコマンドのみを実行するようにユーザーを制限する viewer ロール)。利用可能なロールは、 $FUSE_HOME/etc/org.apache.karaf.shell.cfg
または $FUSE_HOME/etc/system.properties
で設定されます。
JMX認証の使用
jconsoleまたは別の外部ツールを使用してRMI経由でJMXにリモート接続する場合は、JMX認証が必要になることがあります。そうでなければ、jolokiaエージェントがデフォルトでhawt.ioにインストールされているので、hawt.io/jolokiaを使用する方が良いかもしれません。詳細については、Hawtio Admin Consoleを参照してください。
JMX認証を使用するには、次の手順を実行します。
-
$FUSE_HOME/etc/org.apache.karaf.management.cfg
ファイルで、jmxRealm
プロパティーを次のように変更します。jmxRealm=keycloak
-
上記のSSHのセクションで説明したように、
keycloak-jaas
フィーチャーをインストールし、$FUSE_HOME/etc/keycloak-direct-access.json
ファイルを設定してください。 -
jconsoleでは、次のようなURLを使用できます。
service:jmx:rmi://localhost:44444/jndi/rmi://localhost:1099/karaf-root
クレデンシャルはadmin/password(利用環境の管理者権限を持つユーザー次第)です。
Hawtio管理コンソールのセキュリティー保護
Keycloakを使用して、Hawtio管理コンソールをセキュリティー保護するには、以下の手順を実行します。
-
利用レルムのKeycloak管理コンソールにクライアントを作成します。たとえば、Keycloakの
demo
レルムでクライアントhawtio-client
を作成し、アクセスタイプとしてpublic
を指定し、Hawtio: http://localhost:8181/hawtio/* を指すリダイレクトURIを指定します。対応するWeb Origin(この場合は、 http://localhost:8181)を設定します。hawtio-client
クライアント詳細の Scope タブにある account クライアントの view-profile クライアントロールを含むようにクライアント・スコープ・マッピングを設定します。 -
$FUSE_HOME/etc
ディレクトリーにkeycloak-hawtio-client.json
ファイルを作成します。このファイルは、以下の例のような内容で作成します。Keycloak環境に応じて、realm
、resource
、auth-server-url
の各プロパティーを変更してください。resource
プロパティーは前のステップで作成されたクライアントを指し示さなければなりません。このファイルは、クライアント(Hawtio JavaScriptアプリケーション)側で使用されます。{ "realm" : "demo", "clientId" : "hawtio-client", "url" : "http://localhost:8080/auth", "ssl-required" : "external", "public-client" : true }
-
$FUSE_HOME/etc
ディレクトリーにkeycloak-direct-access.json
ファイルを作成します。このファイルは、以下の例のような内容です。Keycloakの環境に応じてrealm
とurl
プロパティーを変更してください。このファイルは、JavaScriptクライアントによって使用されます。{ "realm" : "demo", "resource" : "ssh-jmx-admin-client", "auth-server-url" : "http://localhost:8080/auth", "ssl-required" : "external", "credentials": { "secret": "password" } }
-
$FUSE_HOME/etc
ディレクトリーにkeycloak-hawtio.json
ファイルを作成します。このファイルは、以下の例のような内容です。Keycloakの環境に応じてrealm
とauth-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" }
-
JBoss Fuse 7.4.0を開始し、Keycloak featureをインストールします。次に以下をKarafターミナルに入力してください。
system:property -p hawtio.keycloakEnabled true system:property -p hawtio.realm keycloak system:property -p hawtio.keycloakClientConfig file://\${karaf.base}/etc/keycloak-hawtio-client.json system:property -p hawtio.rolePrincipalClasses org.keycloak.adapters.jaas.RolePrincipal,org.apache.karaf.jaas.boot.principal.RolePrincipal restart io.hawt.hawtio-war
-
http://localhost:8181/hawtio に移動し、Keycloakのレルムからユーザーとしてログインします。
Hawtioに対して正常に認証するには、ユーザーが適切なレルムロールを持っている必要があることに注意してください。利用可能なロールは、
hawtio.roles
の$FUSE_HOME/etc/system.properties
ファイルで設定されます。
2.1.6. Spring Bootアダプター
Spring Bootアプリケーションをセキュリティー保護するには、Keycloak Spring BootアダプターJARをアプリケーションに追加する必要があります。通常のSpring Bootの設定( application.properties
)でいくつかの設定を追加する必要があります。これらの手順について説明します。
アダプターのインストール
Keycloak Spring Bootアダプターは、Spring Bootの自動設定を利用するので、Keycloak Spring Boot Starterをプロジェクトに追加するだけです。
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>13.0.1</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-method
を KEYCLOAK
に設定し、起動時に 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 7、8、9アダプター
Tomcat 7、8、9にデプロイされたWARアプリケーションを保護するには、Keycloak Tomcat 7アダプターまたはKeycloak TomcatアダプターをTomcatにインストールする必要があります。その後、TomcatにデプロイするWARにもいくつかの設定を行う必要があります。これらの手順について説明します。
アダプターのインストール
アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。
アダプターの配布物をTomcatの lib/
ディレクトリーに解凍する必要があります。WEB-INF/libディレクトリー内にアダプターのjarを含めても動作しません!KeycloakアダプターはValveとして実装され、ValveのコードはTomcatのメインのlib/ディレクトリーに存在する必要があります。
Tomcat 7へのインストールは次のとおりです。
$ cd $TOMCAT_HOME/lib
$ unzip keycloak-tomcat7-adapter-dist.zip
Tomcat 8、9へのインストールは次のとおりです。
$ cd $TOMCAT_HOME/lib
$ unzip keycloak-tomcat-adapter-dist.zip
WARごとに必要な設定
このセクションでは、直接WARパッケージ内に設定を追加し、ファイルを編集することで、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.2.x、Jetty 9.3.x、Jetty 9.4.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パッケージ内に設定を追加し、ファイルを編集することで、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.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. Spring Securityアダプター
Spring SecurityとKeycloakでアプリケーションを保護するには、このアダプターをプロジェクトのdependencyに追加します。Spring Securityの設定ファイルにいくつか追加のBeanを用意し、パイプラインにKeycloakセキュリティー・フィルターを追加する必要があります。
他のKeycloakアダプターとは異なり、web.xmlにセキュリティーを設定しないでください。ただし、 keycloak.json
は依然として必要です。シングル・サインアウトが適切に機能するためには、セッション・リスナーを定義する必要があります。
-
web.xml内(純粋なSpring Security環境用)
<listener> <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener>
-
Spring Beanとして(Spring Securityアダプターを使用するSpring Boot環境で)
@Bean public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() { return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher()); }
アダプターのインストール
MavenのPOMまたはGradleのbuildに、依存するKeycloak Spring Securityアダプターを追加してください。
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
<version>13.0.1</version>
</dependency>
Spring Securityの設定
Keycloak Spring Securityアダプターは、Spring Securityの柔軟なセキュリティー設定構文を利用します。
Java設定
Keycloakは、 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">
<constructor-arg ref="adapterDeploymentContext" />
</bean>
<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="keycloakSecurityContextRequestFilter"
class="org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter" />
<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:custom-filter ref="keycloakSecurityContextRequestFilter" after="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アダプターはマルチテナンシーをサポートしています。 AdapterDeploymentContextFactoryBean
に keycloak.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();
}
Beanの二重登録を避ける
Spring Bootは、フィルターBeanをWebアプリケーション・コンテキストに登録しようとします。そのため、Spring Boot環境でKeycloak Spring Securityアダプターを実行する場合は、Keycloakフィルターが2回登録されないように、セキュリティー設定に FilterRegistrationBean
を追加する必要があります。
また、Spring Boot 2.1はデフォルトで spring.main.allow-bean-definition-overriding
を無効にしています。これは、もし KeycloakWebSecurityConfigurerAdapter
を拡張した Configuration
クラスが @ComponentScan
によってすでに検出されているBeanを登録しようとすると、 BeanDefinitionOverrideException
が発生することを意味します。これについては以下の HttpSessionManager
のように、 @ConditionalOnMissingBean
アノテーションを使用して登録を上書きすることで避けることができます。
@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;
}
@Bean
@Override
@ConditionalOnMissingBean(HttpSessionManager.class)
protected HttpSessionManager httpSessionManager() {
return new HttpSessionManager();
}
...
}
2.1.10. 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フィルターは、コンテキスト・パラメーターの代わりにフィルター初期化パラメーターとして定義する必要がある以外は、他のアダプターと同じ設定パラメーターを持ちます。
To use this filter, include this maven artifact in your WAR poms:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-filter-adapter</artifactId>
<version>13.0.1</version>
</dependency>
OSGiでの使用
サーブレット・フィルター・アダプターは、OSGiバンドルとしてパッケージされているため、HTTP ServiceとHTTP Whiteboardを使用する汎用OSGi環境(R6以上)で使用できます。
インストール
アダプターとその依存関係はMavenのアーティファクトとして配布されるため、Maven Centralにアクセスするためにインターネット接続を使用するか、ローカルのMavenリポジトリーにアーティファクトをキャッシュする必要があります。
Apache Karafを使用している場合は、Keycloakフィーチャー・リポジトリーからフィーチャーをインストールするだけです。
karaf@root()> feature:repo-add mvn:org.keycloak/keycloak-osgi-features/13.0.1/xml/features
karaf@root()> feature:install keycloak-servlet-filter-adapter
その他のOSGiランタイムについては、ランタイム・ドキュメントでアダプター・バンドルとその依存関係をインストールする方法を参照してください。
OSGiプラットフォームがPax WebとApache Karafである場合は、代わりにJBoss Fuse 6アダプターまたはJBoss Fuse 7アダプターを使用することを検討してください。 |
設定
まず、アダプターをOSGi HTTP Serviceでサーブレット・フィルターとして登録する必要があります。これを行う最も一般的な方法は、プログラム的な方法(例えば、バンドル・アクティベーターを介して)と宣言的な方法(OSGiアノテーションを使用して)です。フィルターを動的に登録および登録解除するプロセスが簡素化されるため、後者を使用することをお勧めします。
package mypackage;
import javax.servlet.Filter;
import org.keycloak.adapters.servlet.KeycloakOIDCFilter;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
@Component(
immediate = true,
service = Filter.class,
property = {
KeycloakOIDCFilter.CONFIG_FILE_PARAM + "=" + "keycloak.json",
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN + "=" +"/*",
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT + "=" + "(osgi.http.whiteboard.context.name=mycontext)"
}
)
public class KeycloakFilter extends KeycloakOIDCFilter {
//
}
上記のスニペットは、OSGi宣言型サービスの仕様を使用して、 javax.servlet.Filter
クラスの下でOSGIサービスとしてフィルターを公開します。クラスがOSGiサービス・レジストリーにパブリッシュされると、OSGi HTTP Serviceの実装によってピックアップされ、指定されたサーブレット・コンテキストへのリクエストをフィルタリングするために使用されます。これにより、サーブレットのコンテキストパス+フィルターパスに一致するすべてのリクエストに対して、Keycloakアダプターがトリガーされます。
コンポーネントはOSGi Configuration Admin Serviceの制御下に置かれるため、そのプロパティーは動的に設定できます。これを行うには、OSGiランタイムの標準の設定場所に mypackage.KeycloakFilter.cfg
ファイルを作成するか、
keycloak.config.file = /path/to/keycloak.json
osgi.http.whiteboard.filter.pattern = /secure/*
または、ランタイムが可能な場合は、対話型コンソールを使用してください。
karaf@root()> config:edit mypackage.KeycloakFilter
karaf@root()> config:property-set keycloak.config.file '${karaf.etc}/keycloak.json'
karaf@root()> config:update
より多くの制御が必要な場合、たとえばマルチテナンシーを実装するカスタム KeycloakConfigResolver
を提供する場合は、次のようにフィルターをプログラムで登録することができます。
public class Activator implements BundleActivator {
private ServiceRegistration registration;
public void start(BundleContext context) throws Exception {
Hashtable props = new Hashtable();
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, "/secure/*");
props.put(KeycloakOIDCFilter.CONFIG_RESOLVER_PARAM, new MyConfigResolver());
this.registration = context.registerService(Filter.class.getName(), new KeycloakOIDCFilter(), props);
}
public void stop(BundleContext context) throws Exception {
this.registration.unregister();
}
}
プログラムによる登録の詳細については、 Apache Felix HTTP Service を参照してください。
2.1.11. 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
引数を持つコンストラクタが必要です。 scope
-
このオプションは
DirectAccessGrantsLoginModule
にのみ適用されます。指定された値は、リソース・オーナー・パスワード・クレデンシャル・グラント・リクエストのOAuth2scope
パラメーターとして使用されます。
2.1.12. CLI / デスクトップ・アプリケーション
Keycloakは、システム・ブラウザーを介して認証ステップを実行することによって、 KeycloakInstalled
アダプターを介したデスクトップ(たとえば、Swing、JavaFX)またはCLIアプリケーションのセキュリティー保護をサポートします。
KeycloakInstalled
アダプターは、 desktop
と manual
のバリアントをサポートしています。デスクトップ・バリアントは、システム・クレデンシャルを収集するためにシステム・ブラウザーを使用します。手動バリアントは、ユーザー・クレデンシャルを STDIN
から読み込みます。
どのように動くか
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>13.0.1</version>
</dependency>
クライアントの設定
アプリケーションは、 Standard Flow Enabled
で public
なOpenID Connectクライアントであり、許可される Valid Redirect URI
として http://localhost が設定される必要があります。
KeycloakInstalled アダプターは、 OIDC プロトコルでのコードからトークンへの交換中に追加の保護を提供する PKCE [RFC 7636] メカニズムをサポートします。PKCEは、アダプター設定の "enable-pkce": true の設定で有効にできます。コード・インジェクションおよびコードリプレイ攻撃を回避するために、PKCEを有効にすることを強くお勧めします。
|
使い方
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,
"enable-pkce": 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.13. セキュリティー・コンテキスト
KeycloakSecurityContext
インターフェイスはトークンに直接アクセスする必要がある場合に利用できます。これは、トークンから追加の詳細情報(ユーザー・プロファイル情報など)を取得する場合や、Keycloakによって保護されているRESTfulサービスを呼び出す場合に便利です。
サーブレット環境では、セキュアな呼び出しで HttpServletRequest
の属性として以下のようにセキュリティー・コンテキストを利用できます。
httpServletRequest
.getAttribute(KeycloakSecurityContext.class.getName());
または、セキュアでないリクエストでは以下のように HttpSession
からセキュリティー・コンテキストを利用できます。
httpServletRequest.getSession()
.getAttribute(KeycloakSecurityContext.class.getName());
2.1.14. エラー処理
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.15. ログアウト
Webアプリケーションからログアウトする方法は複数あります。Java EEサーブレット・コンテナーの場合、 HttpServletRequest.logout()
を呼び出すことができます。他のブラウザー・アプリケーションの場合、ブラウザーにSSOセッションがあれば、 http://auth-server/auth/realms/{realm-name}/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri
にリダイレクトすることでログアウトできます。
HttpServletRequest.logout()
を使用すると、アダプターはKeycloakサーバーに対して、バックチャネルでリフレッシュトークンを渡すPOSTリクエストを送信します。保護されていないページ(有効なトークンをチェックしていないページ)からメソッドが実行された場合、リフレッシュトークンは使用できない可能性があり、その場合はアダプターがPOSTリクエストの送信をスキップします。このため、現在のトークンが常に考慮され、必要に応じてKeycloakサーバーとの対話が実行されるように、保護されたページを使用して HttpServletRequest.logout()
を実行することを推奨します。
ログアウト・プロセスの一部として外部アイデンティティー・プロバイダーからログアウトしないようにするには、パラメーター initiating_idp
を指定します。値は当該のアイデンティティー・プロバイダーのアイデンティティー(エイリアス)です。これは、外部アイデンティティー・プロバイダーによって開始されたシングルログアウトの一部として、ログアウト・エンドポイントが呼び出された場合に便利です。
2.1.16. パラメーター・フォワーディング
Keycloakの初期認可エンドポイント・リクエストは、さまざまなパラメーターをサポートしています。ほとんどのパラメータは OIDC仕様 に記述されています。一部のパラメーターは、アダプターの設定に基づいて、アダプターにより自動的に追加されます。ただし、呼び出しごとに追加できるパラメーターもいくつかあります。保護されたアプリケーションURIにアクセスすると、特定のパラメーターはKeycloak認可エンドポイントにフォワードされます。
たとえば、オフライントークンを要求する場合、以下のように scope
パラメーターを使用して保護されたアプリケーションのURIにアクセスできます。
http://myappserver/mysecuredapp?scope=offline_access
パラメーター scope=offline_access
が自動的にKeycloak認可エンドポイントにフォワードされます。
サポートされるパラメーターは次のとおりです。
-
scope - スペース区切りのスコープリストを使用します。スペースで区切られたリストは通常、特定のクライアントで定義されたクライアントスコープを参照します。スコープ
openid
は、アダプターによって常にスコープのリストに追加されることに注意してください。たとえば、スコープ・オプションaddress phone
を入力すると、Keycloakへのリクエストにスコープ・パラメーターscope=openid address phone
が含まれます。 -
prompt - Keycloakは以下の設定をサポートしています:
login
- SSOは無視され、ユーザーがすでに認証されていてもKeycloakログインページが常に表示されますconsent
-Consent Required
のクライアントにのみ適用されます。これを使用すると、ユーザーが以前にこのクライアントに同意したとしても、常に同意ページが表示されます。 **none
- ログインページは表示されません。代わりにユーザーはアプリケーションにリダイレクトされ、ユーザーがまだ認証されていない場合はエラーが発生します。この設定により、アプリケーション側でフィルター/インターセプターを作成し、ユーザーにカスタム・エラーページを表示することができます。詳細については、仕様を参照してください。 -
max_age - ユーザーがすでに認証されている場合にのみ使用されます。ユーザーが認証されたときから測定された、認証が維持される最大許容時間を指定します。ユーザーが認証されてから
maxAge
が経過すると、SSOは無視され、再認証が必要になります。 -
login_hint - ログイン・フォームのユーザー名/電子メール・フィールドを事前入力するために使用されます。
-
kc_idp_hint - Keycloakにログインページの表示をスキップし、代わりに指定されたアイデンティティー・プロバイダーに自動的にリダイレクトするように指示するために使用されます。詳細は、アイデンティティー・プロバイダーのドキュメントを参照してください。
ほとんどのパラメーターは OIDC仕様 に記載されています。唯一の例外はパラメーター kc_idp_hint
です。これはKeycloak固有で、自動的に使用するアイデンティティー・プロバイダーの名前を含んでいます。詳細は Server Administration Guide の アイデンティティー・ブローカリング
のセクションを参照してください。
アプリケーションで既に認証されている場合、添付されたパラメーターを使用してURLを開いても、アダプターはKeycloakにリダイレクトしません。たとえば、アプリケーションmysecredappにすでに認証されている場合、 http://myappserver/mysecuredapp?prompt=login を開いても、自動的にKeycloakログインページにリダイレクトされません。この挙動は将来変更される可能性があります。 |
2.1.17. クライアント認証
コンフィデンシャルOIDCクライアントがバックチャネル・リクエストを送信する必要がある場合(たとえば、トークンのコードを交換したり、トークンをリフレッシュするような場合)、Keycloakサーバーに対して認証する必要があります。デフォルトでは、クライアントIDとクライアント・シークレット、署名付きJWTによるクライアント認証、またはクライアント・シークレットを使用した署名付きJWTによるクライアント認証の3つの方法でクライアントを認証します。
クライアント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
アプリケーションのデモのサンプル配布物を見てみることができます。
クライアント・シークレットを使用した署名付きJWTによるクライアント認証
これは、署名付きJWTによるクライアント認証と同じですが、秘密鍵と証明書の代わりにクライアント・シークレットを使用する点が異なります。
クライアントにはシークレットがあり、アダプター(アプリケーション)とKeycloakサーバーの両方に知られている必要があります。管理コンソールの Credentials
タブでクライアントを認証する方法として Signed JWT with Client Secret
を選択し、このシークレットをアプリケーション側の keycloak.json
ファイルに以下のように貼り付けます。
"credentials": {
"secret-jwt": {
"secret": "19666a4f-32dd-4049-b082-684c74115f28",
"algorithm": "HS512"
}
}
"algorithm"フィールドには、クライアント・シークレットを使用した署名付きJWTのアルゴリズムを指定します。HS256、HS384、HS512のいずれかの値である必要があります。詳細については、 JSON Web Algorithms(JWA) を参照してください。
この"algorithm"フィールドはオプションであり、"algorithm"フィールドが keycloak.json
ファイルに存在しない場合はHS256が自動的に適用されます。
独自のクライアント認証方式の追加
独自のクライアント認証方式を追加することもできます。クライアントサイドとサーバーサイドの両方のプロバイダーを実装する必要があります。詳細は Server Developer Guide の Authentication SPI
のセクションを参照してください。
2.1.18. マルチテナンシー
マルチテナンシーとは、単一のターゲット・アプリケーション(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.xml
の keycloak.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.19. アプリケーション・クラスタリング
この章では、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分)を使用することをお勧めします。
一部のロードバランサーは、スティッキー・セッションCookieの名前や内容の設定を許可しません(Amazon ALBなど)。これらのために、 shouldAttachRoute オプションを false に設定することが推奨されます。
|
相対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つのアプリケーションからログアウト・リクエストを送信します
-
アプリケーションはKeycloakにログアウト・リクエストを送信します
-
Keycloakサーバーはユーザー・セッションを無効にします
-
Keycloakサーバーは、セッションに関連付けられた管理URLでバックチャネル・リクエストをアプリケーションに送信します
-
アプリケーションがログアウト・リクエストを受信すると、対応するHTTPセッションが無効になります
管理URLに ${application.session.host}
が含まれていると、HTTPセッションに関連付けられたノードのURLに置き換えられます。
アプリケーション・ノードの登録
前のセクションでは、Keycloakが特定のHTTPセッションに関連付けられたノードにログアウト・リクエストを送信する方法について説明しました。しかし、管理者が管理タスクを登録されている全てのクラスターノードに伝播させたい場合があります。たとえば、新しいnot beforeポリシーをアプリケーションにプッシュする、またはアプリケーションからすべてのユーザーをログアウトする場合などです。
この場合、Keycloakはすべてのアプリケーション・クラスター・ノードを認識する必要があります。これにより、全てのノードにイベントを送信できます。これを達成するために、オート・ディスカバリーのメカニズムをサポートしています。
-
新しいアプリケーション・ノードがクラスターに参加すると、Keycloakサーバーに登録リクエストを送信します。
-
定期的に設定された間隔で、設定がKeycloakに送信されます
-
Keycloakサーバーが指定されたタイムアウト時間内に再登録リクエストを受信しなかった場合、Keycloakサーバーは自動的に特定のノードの登録を解除します
-
また、登録解除リクエストを送信するときに、ノードは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アダプター
Keycloakには、HTML5/JavaScriptアプリケーションをセキュリティー保護するために使用可能なクライアント・サイドのJavaScriptライブラリーが付属しています。JavaScriptアダプターには、Cordovaアプリケーションのサポートが組み込まれています。
ライブラリーはKeycloakサーバーの /auth/js/keycloak.js
から直接取得することができ、ZIPアーカイブとしても配布されています。
Keycloakサーバーをアップグレードする際に自動的にJavaScriptアダプターが更新されるため、ベスト・プラクティスはKeycloakサーバーからJavaScriptアダプターを直接ロードすることです。そうではなくアダプターをWebアプリケーションにコピーする場合は、サーバーをアップグレードした後に、アダプターもアップグレードするようにしてください。
クライアント・サイドのアプリケーションを使用する際に注意すべき重要な点の1つは、クライアント・サイドのアプリケーションにクライアント・クレデンシャルを安全に保存する方法がないため、クライアントをパブリック・クライアントにする必要があることです。これにより、クライアント用に設定したリダイレクトURIが正しいか、できるだけ具体的であるかを確認することが非常に重要になります。
JavaScriptアダプターを使用するには、まずKeycloak管理コンソールでアプリケーション用のクライアントを作成する必要があります。 Access Type
に public
が選択されていることを確認してください。
また、 Valid Redirect URIs
と Web Origins
を設定する必要があります。できるだけ具体的にする理由は、そうしなければセキュリティー上の脆弱性が生じる可能性があるためです。
クライアントが作成されたら Installation
タブをクリックし、 Format Option
の中から Keycloak OIDC JSON
を選択して、 Download
をクリックします。ダウンロードした keycloak.json
ファイルは、HTMLページと同じ場所にあるWebサーバー上にホストされるべきです。
または、設定ファイルではなく、アダプターを手動で設定することもできます。
次の例は、JavaScriptアダプターを初期化する方法を示しています。
<html>
<head>
<script src="keycloak.js"></script>
<script>
function initKeycloak() {
var keycloak = new Keycloak();
keycloak.init().then(function(authenticated) {
alert(authenticated ? 'authenticated' : 'not authenticated');
}).catch(function() {
alert('failed to initialize');
});
}
</script>
</head>
<body onload="initKeycloak()">
<!-- your page content goes here -->
</body>
</html>
keycloak.json
ファイルが別の場所にある場合、以下のように指定することができます。
var keycloak = new Keycloak('http://localhost:8080/myapp/keycloak.json');
または、以下のように必要な設定でJavaScriptオブジェクトを渡すこともできます。
var keycloak = new Keycloak({
url: 'http://keycloak-server/auth',
realm: 'myrealm',
clientId: 'myapp'
});
デフォルトでは login
関数を呼び出す必要があります。ただし、アダプターを自動的に認証させるための2つのオプションがあります。 init
関数に login-required
または check-sso
を渡すことができます。 login-required
は、ユーザーがKeycloakにログインしていない場合にクライアントを認証し、そうでない場合にログインページを表示します。 check-sso
は、ユーザーがすでにログインしている場合にのみクライアントを認証します。ユーザーがログインしていない場合、ブラウザーはアプリケーションにリダイレクトされ、未認証のままになります。
silent check-sso
オプションを設定できます。この機能を有効にすると、ブラウザーはKeycloakサーバーへの完全なリダイレクトを行わず、アプリケーションに戻ります。このアクションは非表示のiframeで実行されるため、アプリケーションのリソースはアプリの初期化時にブラウザーによって1回だけロードと解析がされ、Keycloakからアプリへのリダイレクト・バック後に再度行われはしません。これは、SPA(シングル・ページ・アプリケーション)の場合に特に便利です。
silent check-sso
を有効にするには、initメソッドで silentCheckSsoRedirectUri
属性を提供する必要があります。このURIは、アプリケーションの有効なエンドポイントである必要があります(もちろん、Keycloak管理コンソールでクライアントの有効なリダイレクトとして設定する必要があります)。
keycloak.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html'
})
サイレント・チェックSSOリダイレクトURIのページは、認証状態を正常にチェックし、Keycloakサーバーからトークンを取得した後、iframeにロードされます。受信したトークンをメイン・アプリケーションに送信する以外のタスクはなく、次のように見えるはずです。
<html>
<body>
<script>
parent.postMessage(location.href, location.origin)
</script>
</body>
</html>
指定されたlocationにあるこのページは、アプリケーション自体によって提供される必要があり、JavaScriptアダプターの一部ではないことに注意してください。
Silent check-sso 機能は、一部の最新ブラウザーで制限されています。トラッキング防止機能を備えた最新のブラウザーのセクションを参照してください。
|
login-required
を有効にするには、以下のように onLoad
に login-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
メソッドは、トークンが正常にリフレッシュされた場合にのみ、サービスの呼び出しを容易にするPromiseを返し、そうでない場合は、ユーザーにエラーを表示します。以下に例を示します。
keycloak.updateToken(30).then(function() {
loadData();
}).catch(function() {
alert('Failed to refresh token');
});
2.2.1. セッション・ステータスiframe
デフォルトでは、JavaScriptアダプターは、シングル・サイン・アウトが発生したかどうかを検出するために使用される非表示のiframeを作成します。これはネットワーク・トラフィックを必要とせず、代わりに特殊なステータス・クッキーを調べることによってステータスを取得します。この機能は、 init
メソッドに渡されるオプションに checkLoginIframe: false
を設定することで無効にできます。
このクッキーを直接参照することに頼るべきではありません。フォーマットは変更可能で、アプリケーションではなくKeycloakサーバーのURLに関連付けられています。
Session Status iframe機能は、一部の最新ブラウザーで制限されています。トラッキング防止機能を備えた最新のブラウザーのセクションを参照してください。 |
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 Enabled
と Implicit Flow Enabled
フラグを有効にすることを要求します。Keycloakサーバーはコードとトークンの両方をアプリケーションに送信します。アクセス・トークンとリフレッシュ・トークンの交換ができる間、アクセス・トークンは即時使用できます。インプリシット・フローと同様に、アクセス・トークンがすぐに利用できるため、ハイブリッド・フローはパフォーマンスに優れています。しかし、トークンは引き続きURLに送信され、前述のセキュリティーの脆弱性が当てはまる可能性があります。
ハイブリッド・フローの1つの利点は、アプリケーションでリフレッシュ・トークンが利用可能になることです。
ハイブリッド・フローの場合、以下のようにパラメーター flow
を値 hybrid
で init
メソッドに渡す必要があります。
keycloak.init({
flow: 'hybrid'
})
2.2.3. ハイブリッド・アプリとCordova
Keycloakは Apache Cordova で開発されたハイブリッド・モバイルアプリをサポートしています。JavaScriptアダプターには、 cordova
と cordova-native
の2つのモードがあります。
デフォルトはcordovaで、アダプタータイプが設定されておらず、window.cordovaが存在する場合、アダプターは自動的に選択します。ログインすると、 InApp Browser が開き、ユーザーはKeycloakとやり取りした後、アプリを http://localhost
にリダイレクトします。そのため、管理コンソールのクライアント設定のセクションで、このURLを有効なリダイレクトURIとしてホワイトリストに登録する必要があります。
このモードはセットアップが簡単ですが、いくつかの欠点もあります。
-
InApp-Browserは、アプリに組み込まれたブラウザーであり、携帯電話のデフォルト・ブラウザーではありません。したがって、設定が異なり、保存されたクレデンシャルは利用できません。
-
特に複雑なテーマをレンダリングする場合、InApp-Browserの方が処理速度が遅くなる可能性があります。
-
このモードを使用する前に、アプリがログインページをレンダリングするブラウザーを完全に制御しているため、ユーザーのクレデンシャルにアクセスする可能性があるなど、セキュリティーを考慮する必要があります。そのため、信頼できないアプリでは使用を許可しないでください。
このサンプル・アプリケーションを使用して、開始します: https://github.com/keycloak/keycloak/tree/master/examples/cordova
代替モード cordova-native
は異なるアプローチをとっています。システムのブラウザーを使用してログインページを開きます。ユーザーが認証されると、特別なURLを使用して、ブラウザーがアプリにリダイレクトされます。そこから、Keycloakアダプターは、URLからコードまたはトークンを読み取ってログインを完了できます。
ネイティブモードをアクティブにするには、次のようにアダプタータイプ cordova-native
を init
メソッドに渡します。
keycloak.init({
adapter: 'cordova-native'
})
このアダプターには、次の2つの追加プラグインが必要でした。
-
cordova-plugin-browsertab:アプリがシステムのブラウザーでウェブページを開くことができます
-
cordova-plugin-deeplinks:ブラウザーが特別なURLでアプリにリダイレクトできるようにします
アプリにリンクするための技術的詳細は、各プラットフォームで異なり、特別な設定が必要です。詳しい手順については、 ディープリンク・プラグインのドキュメント のAndroidおよびiOSのセクションを参照してください。
アプリを開くためのリンクには、カスタムスキーマ(つまり、 myapp://login
または android-app://com.example.myapp/https/example.com/login
)と ユニバーサル・リンク(iOS))/ ディープリンク(Android)をクリックします。前者は設定が容易で、より確実に動作する傾向がありますが、後者はセキュリティーが強化され、ドメインの所有者のみが登録できます。カスタムURLはiOSでは推奨されていません。最良の信頼性を得るために、ユニバーサル・リンクとそれにcustom-urlリンクを持つ代替サイトを組み合わせて使用することをお勧めします。
さらに、Keycloakアダプターとの互換性を向上させるには、以下の手順を実行することをお勧めします。
-
iOS上のユニバーサル・リンクは、
query-mode
に設定されたresponse-mode
でより確実に動作するようです。 -
Androidがリダイレクト時にアプリケーションの新しいインスタンスをオープンすることを防ぐには、次のスニペットを
config.xml
に追加します。
<preference name="AndroidLaunchMode" value="singleTask" />
ネイティブモードを使用する方法を示すサンプル・アプリケーションがあります: https://github.com/keycloak/keycloak/tree/master/examples/cordova-native
2.2.4. カスタム・アダプター
デフォルトでサポートされていない環境(Capacitorなど)でJavaScriptクライアントを実行する必要がある場合があります。このような未知の環境でJavasScriptクライアントを使用できるようにするために、カスタム・アダプターを渡すことができます。たとえば、サードパーティーのライブラリーがそのようなアダプターを提供して、JavaScriptクライアントを問題なく実行できるようにすることができます。
import Keycloak from 'keycloak-js';
import KeycloakCapacitorAdapter from 'keycloak-capacitor-adapter';
const keycloak = new Keycloak();
keycloak.init({
adapter: KeycloakCapacitorAdapter,
});
この特定のパッケージは存在しませんが、そのようなアダプターをクライアントに渡す方法の良い例を示しています。
独自のアダプターを作成することもできます。そのためには、 KeycloakAdapter
インターフェイスで説明されているメソッドを実装する必要があります。たとえば、次のTypeScriptコードにより、すべてのメソッドが適切に実装されます。
import Keycloak, { KeycloakAdapter } from 'keycloak-js';
// Implement the 'KeycloakAdapter' interface so that all required methods are guaranteed to be present.
const MyCustomAdapter: KeycloakAdapter = {
login(options) {
// Write your own implementation here.
}
// The other methods go here...
};
const keycloak = new Keycloak();
keycloak.init({
adapter: MyCustomAdapter,
});
もちろん、タイプ情報を省略してTypeScriptを使用せずにこれを行うこともできますが、インターフェイスを適切に実装することは、完全にあなた次第です。
2.2.5. 以前のブラウザー
JavaScriptアダプターは、Base64(window.btoaとwindow.atob)、HTML5 History API、およびオプションでPromise APIに依存しています。これらが利用できないブラウザー(IE9など)をサポートする必要がある場合は、Polyfillを追加する必要があります。
Polyfillライブラリーの例:
-
HTML5 History - https://github.com/devote/HTML5-History-API
2.2.6. トラッキング防止を備えた最新のブラウザー
一部のブラウザーの最新バージョンでは、さまざまなCookieポリシーが適用され、ChromeのSameSiteやサードパーティーのCookieを完全にブロックするなど、サードパーティによるユーザーのトラッキングを防止しています。これらのポリシーは今後さらに制限が厳しくなり、他のブラウザによって採用され、最終的にサードパーティーのコンテキストのCookieが完全にサポートされなくなり、ブラウザーによってブロックされることが予想されます。これにより影響を受けるアダプター機能は、将来廃止される可能性があります。
JavaScriptアダプターは、Session Status iframe、 silent check-sso
、および通常の(非サイレント) check-sso
のサードパーティーCookieに依存しています。これらの機能は、機能が制限されているか、Cookieに関するブラウザーの制限に基づいて完全に無効になっています。アダプターはこの設定を検出しようとし、それに応じて反応します。
"SameSite=Lax by Default" ポリシーのブラウザー
SSL / TLS接続がKeycloak側とアプリケーション側で設定されている場合、すべての機能がサポートされます。 SSL / TLSの構成 を参照してください。影響を受けるのは バージョン84以降のChromeです。
サードパーティーのCookieがブロックされているブラウザー
セッション・ステータスiframeはサポートされておらず、そのようなブラウザーの動作がJSアダプターによって検出された場合は自動的に無効になります。つまり、アダプターはシングル・サインアウトの検出にセッションCookieを使用できず、純粋にトークンに依存する必要があります。これは、ユーザーが別のウィンドウでログアウトすると、JavaScriptアダプターを使用するアプリケーションは、アクセストークンをリフレッシュしようとするまでログアウトされないことを意味します。そのため、アクセストークンのライフスパンを比較的短い時間に設定して、ログアウトが検出されるのが遅くなるのを防ぐことを推奨します。 セッションとトークンのタイムアウト を参照してください。
Silent check-sso
はサポートされておらず、デフォルトでは通常の(非サイレント) check-sso
にフォールバックします。この動作は、 init
メソッドに渡されるオプションで silentCheckSsoFallback: false
を設定することで変更できます。この場合、ブラウザーの制限的な動作が検出されると、 check-sso
は完全に無効になります。
通常の check-sso
も影響を受けます。Session Status iframeはサポートされていないため、ユーザーのログイン・ステータスを確認するためにアダプターを初期化するときに、Keycloakへの追加のリダイレクトを行う必要があります。これは、iframeを使用してユーザーがログインしているかどうかを通知する標準の動作とは異なり、リダイレクトはログアウトした場合にのみ実行されます。
影響を受けるブラウザーは、バージョン13.1以降のSafariです。
2.2.7. 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に渡されるフロー。
- アダプター
-
リダイレクトの方法やライブラリーにより処理されるその他のブラウザー関連の関数をオーバーライドすることができます。利用可能なオプションは以下のとおりです。
-
"default" - ライブラリーはリダイレクトにブラウザーのAPIを使用します(これはデフォルトです)
-
"cordova" - ライブラリーは、InAppBrowser cordovaプラグインを使用して、Keycloakのログイン/登録ページを読み込もうとします(これは、ライブラリーがcordovaエコシステムで動作しているときに自動的に使用されます)
-
"cordova-native" - ライブラリーはBrowserTabs cordovaプラグインを使用して、電話のシステム・ブラウザーを使用してログインページと登録ページを開こうとします。これには、アプリケーションにリダイレクトするための特別な設定が必要です(ハイブリッド・アプリとCordovaを参照してください)。
-
custom - カスタム・アダプターを実装することができます(高度なユースケースのみ)
-
- responseType
-
Keycloakにログイン・リクエストとともに送信されたレスポンスタイプ。これは、初期化中に使用されたフロー値に基づいて決定されますが、この値を設定することで上書きできます。
メソッド
init(options)
アダプターを初期化するために呼び出されます。
optionsはオブジェクトで、以下のプロパティーがあります。
-
useNonce - 暗号化ノンスを追加して、認証レスポンスがリクエストと一致することを確認します(デフォルトは
true
です)。 -
onLoad - ロード時に実行するアクションを指定します。サポートされている値は
login-required
またはcheck-sso
です。 -
silentCheckSsoRedirectUri - onLoadが’check-sso’に設定されている場合、サイレント認証チェックのリダイレクトURIを設定します。
-
silentCheckSsoFallback - silent
check-sso
がブラウザーでサポートされていない場合、通常のcheck-sso
へのフォールバックを有効にします(デフォルトはtrue
です)。 -
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アプリケーションにリダイレクトされます。これは一般的にquery
よりも安全で推奨されます。 -
flow - OpenID Connectのフローを設定します。有効な値は、
standard
、implicit
、hybrid
のいずれかです。 -
enableLogging - Keycloakからコンソールへのメッセージのロギングを有効にします(デフォルトは
false
)。 -
pkceMethod - Proof Key Code Exchange( PKCE )が使用するメソッド。この値を設定すると、PKCEメカニズムが有効になります。利用可能なオプションは、以下の通りです。
-
"S256" - SHA256ベースのPKCEメソッド
-
初期化が完了すると解決するPromiseを返します。
login(options)
ログイン・フォームにリダイレクトします(optionsは、redirectUriおよび/またはpromptフィールドを持つ任意のオブジェクトです)。
optionsはオブジェクトで、以下のプロパティーがあります。
-
redirectUri - ログイン後にリダイレクトするURIを指定します。
-
prompt - このパラメーターを使用すると、Keycloakサーバー側のログインフローを少しだけカスタマイズできます。たとえば、値が
login
の場合は、ログイン画面を表示するようにします。prompt
パラメーターの詳細とすべての値については、 パラメーター転送のセクション を参照してください。 -
maxAge - ユーザーがすでに認証されている場合にのみ使用されます。ユーザーの認証が行われてからの最大時間を指定します。ユーザーがすでに
maxAge
よりも長い時間認証済みの場合、SSOは無視され、再度認証する必要があります。 -
loginHint - ログイン・フォームのユーザー名/電子メール・フィールドを事前入力するために使用されます。
-
scope - Keycloakログイン・エンドポイントに、scopeパラメーターを転送するために使用します。スペース区切りのスコープのリストを使用します。それらは通常、特定のクライアントで定義されたClient scopesを参照します。スコープ
openid
は、アダプターによって常にスコープのリストに追加されることに注意してください。たとえば、スコープ・オプションaddress phone
を入力すると、Keycloakへのリクエストにスコープ・パラメーターscope=openid address phone
が含まれます。 -
idpHint - ログインページの表示をスキップし、代わりに指定されたアイデンティティー・プロバイダーに自動的にリダイレクトするように、Keycloakに指示するために使用されます。詳細は、Identity Provider documentationを参照してください。
-
action - 値が
register
の場合、ユーザーは登録ページにリダイレクトされ、そうでない場合はログイン・ページにリダイレクトされます。 -
locale - OIDC 1.0仕様のセクション3.1.2.1 に準拠した 'ui_locales' クエリー・パラメーターを設定します。
-
cordovaOptions - Cordovaのアプリケーション内ブラウザーに渡される引数を指定します(該当する場合)。オプション
hidden
とlocation
はこれらの引数の影響を受けません。利用可能なすべてのオプションは https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/ で定義されています。使用例:{ 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' に設定されています。
createAccountUrl(options)
アカウント管理コンソールのURLを返します。
optionsはオブジェクトで、以下のプロパティーがあります。
-
redirectUri - アプリケーションにリダイレクトで戻るときに、リダイレクトするURIを指定します。
hasResourceRole(role, resource)
トークンに指定されたresourceのロールがある場合は、trueを返します(resourceはオプションであり、指定されていない場合はclientIdが使用されます)。
loadUserProfile()
ユーザーのプロファイルを読み込みます。
プロファイルで解決されるPromiseを返します。
例:
keycloak.loadUserProfile()
.then(function(profile) {
alert(JSON.stringify(profile, 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');
});
コールバック・イベント
アダプターは、特定のイベントのコールバック・リスナーの設定をサポートします。
例:
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 Option
で Keycloak OIDC JSON
を選択し、 Download
をクリックします。ダウンロードした keycloak.json
ファイルはプロジェクトのルート・フォルダーに配置します。
2.3.1. インストール
すでに Node.js がインストールされていると仮定して、アプリケーション用のフォルダーを作成します。
mkdir myapp && cd myapp
npm init
コマンドを使ってアプリケーション用の package.json
を作成してください。依存関係リストにKeycloak接続アダプターを追加します。
"dependencies": {
"keycloak-connect": "13.0.1"
}
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);
アプリケーションは、次の方法を使用して、ユーザーを優先度の高いアイデンティティー・プロバイダーにリダイレクトすることもできます。
let keycloak = new Keycloak({ store: memoryStore, idpHint: myIdP }, 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. プロキシーの設定
SSL接続を終了するプロキシーの背後でアプリケーションが実行されている場合は、 express behind proxies ガイドに従ってExpressを設定する必要があります。不適切なプロキシー設定を使用すると、無効なリダイレクトURIが生成される可能性があります。
設定例:
var app = express();
app.set( 'trust proxy', true );
app.use( keycloak.middleware() );
2.3.5. 認証のチェック
リソースにアクセスする前にユーザーが認証されていることを確認するには、単に keycloak.checkSso()
を使います。ユーザーがすでにログインしている場合にのみ認証されます。ユーザーがログインしていない場合、ブラウザーは最初に要求されたURLにリダイレクトされ、ユーザーは未認証のままになります。
app.get( '/check-sso', keycloak.checkSso(), checkSsoHandler );
2.3.6. リソースの保護
- 単純な認証
-
リソースにアクセスする前にユーザーの認証を強制するには、引数のないバージョンの
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 );
- リソースベースの認可
-
リソースベースの認可では、Keycloakで定義されている一連のポリシーに基づいてリソースとその特定のメソッド/アクションを保護することができます。したがって、アプリケーションからの認可を外部化できます。これは、リソースを保護するために使用できる
keycloak.enforcer
メソッドを公開することによって達成されます。
app.get('/apis/me', keycloak.enforcer('user:profile'), userProfileHandler);
keycloak-enforcer
メソッドは、 response_mode
設定オプションの値に応じて2つのモードで動作します。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), userProfileHandler);
response_mode
が token
に設定されている場合、パーミッションはアプリケーションに送られたベアラートークンによって表されるサブジェクトに代わりにサーバーから取得されます。この場合、Keycloakによって付与されたパーミッションとともに新しいアクセストークンが発行されます。サーバーが想定したパーミッションを持つトークンで応答しなかった場合、リクエストは拒否されます。このモードを使用するときは、次のようにリクエストからトークンを取得できるはずです。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), function (req, res) {
var token = req.kauth.grant.access_token.content;
var permissions = token.authorization ? token.authorization.permissions : undefined;
// show user profile
});
アプリケーションがセッションを使用していて、サーバーからの以前の決定をキャッシュしたい場合や、自動的に更新トークンを処理したい場合は、このモードを選択してください。このモードは、クライアントおよびリソースサーバーとして機能するアプリケーションに特に役立ちます。
response_mode
が permissions
に設定されている場合(デフォルトモード)、サーバーは新しいアクセストークンを発行せずに、許可されたパーミッションのリストのみを返します。新しいトークンを発行しないことに加えて、このメソッドは以下のように request
を介してサーバーにより与えられたパーミッションを公開します。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'permissions'}), function (req, res) {
var permissions = req.permissions;
// show user profile
});
response_mode
が使われているかどうかにかかわらず、 keycloak.enforcer
メソッドは最初にアプリケーションに送られたベアラートークンの中のパーミッションをチェックしようとします。ベアラートークンがすでに想定されたパーミッションを持っている場合は、決定を得るためにサーバーと対話する必要はありません。これは、保護されたリソースにアクセスする前に、クライアントが期待されるパーミッションでサーバーからアクセストークンを取得できる場合に特に役立ちます。そのため、クライアントは増分認可などのKeycloak認可サービスによって提供される機能を使用できます。 keycloak.enforcer
はリソースへのアクセスを強制します。
デフォルトでは、ポリシー・エンフォーサーはアプリケーションに定義された client_id
を使って(例えば keycloak.json
を介して)、Keycloakの認可サービスをサポートするKeycloakのクライアントを参照します。この場合、クライアントは実際にはリソースサーバーであるため、パブリックにすることはできません。
アプリケーションがパブリック・クライアント(フロントエンド)とリソースサーバー(バックエンド)の両方として機能している場合は、次の設定を使用して、施行したいポリシーでKeycloak内の別のクライアントを参照できます。
keycloak.enforcer('user:profile', {resource_server_id: 'my-apiserver'})
フロントエンドとバックエンドを表すために、Keycloakで個別のクライアントを使用することをお勧めします。
保護しているアプリケーションがKeycloak認可サービスで有効になっていて、 keycloak.json
でクライアントのクレデンシャルを定義している場合は、決定を下すために、追加のクレームをサーバーにプッシュし、それらをポリシーで利用できるようにすることができます。そのために、プッシュしたいクレームを持つJSONを返す function
を期待する claim
設定オプションを定義できます。
app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], {
claims: function(request) {
return {
"http.uri": ["/protected/resource"],
"user.agent": // get user agent from request
}
}
}), function (req, res) {
// access granted
アプリケーションのリソースを保護するようにKeycloakを設定する方法の詳細については、 Authorization Services Guide をご覧ください。
- 高度な認可
-
URLの一部に基づいてリソースを保護するには次のようにします(各セクションにロールが存在すると仮定します)。
function protectBySection(token, request) {
return token.hasRole( request.params.section );
}
app.get( '/:section/:page', keycloak.protect( protectBySection ), sectionHandler );
高度なログイン設定:
デフォルトでは、クライアントがbearer-onlyでない限り、許可されていないすべてのリクエストはKeycloakのログインページにリダイレクトされます。ただし、コンフィデンシャル・クライアントまたはパブリック・クライアントは、閲覧可能なエンドポイントとAPIエンドポイントの両方をホストする場合があります。認証されていないAPIリクエストでのリダイレクトを防ぎ、代わりにHTTP 401を返すようにするために、redirectToLogin関数をオーバーライドできます。
たとえば、このオーバーライドは、URLに/api/が含まれているかどうかを確認し、ログイン・リダイレクトを無効にします。
Keycloak.prototype.redirectToLogin = function(req) {
var apiReqMatcher = /\/api\//i;
return !apiReqMatcher.test(req.originalUrl || req.url);
};
2.3.7. 追加のURL
- 明示的なユーザー・トリガー・ログアウト
-
デフォルトでは、Middlewareは
/logout
の呼び出しをキャッチし、ユーザーにKeycloak中心のログアウト・ワークフローを経由させます。これは、logout
設定パラメーターをmiddleware()
の呼び出しに指定することで変更できます。
app.use( keycloak.middleware( { logout: '/logoff' } ));
ユーザートリガーのログアウトが呼び出されると、次のようにクエリー・パラメーター redirect_url
を渡すことができます。
https://example.com/logoff?redirect_url=https%3A%2F%2Fexample.com%3A3000%2Flogged%2Fout
このパラメーターはOIDCログアウト・エンドポイントのリダイレクトURLとして使用され、ユーザーは https://example.com/logged/out
にリダイレクトされます。
Keycloak Adminコールバック
また、MiddlewareはKeycloakコンソールからのコールバックをサポートしており、単一セッションまたはすべてのセッションをログアウトします。デフォルトでは、これらのタイプのAdminコールバックは /
のルートURLを基準に発生しますが、 admin
パラメーターを middleware()
の呼び出しに与えることで変更できます。
app.use( keycloak.middleware( { admin: '/callbacks' } );
2.4. 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プロジェクトページを参照してください。
2.5. 他のOpenID Connectライブラリー
Keycloakは、使いやすくて、Keycloakと統合しやすい付属のアダプターにより、セキュリティー保護できます。ただし、使用するプログラミング言語、フレームワーク、プラットフォームでアダプターが使用できない場合は、代わりに一般的なOpenID ConnectのRelying Party(RP)ライブラリーを使用することができます。この章では、Keycloak固有のことについて詳細に説明しますが、特定のプロトコルの詳細については言及しません。詳細については、 OpenID Connectの仕様 と OAuth2の仕様 を参照してください。
2.5.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 Guideと JSON Web Keyの仕様 を参照してください。
イントロスペクション・エンドポイント
/realms/{realm-name}/protocol/openid-connect/token/introspect
イントロスペクション・エンドポイントは、トークンのアクティブ状態を取得するために使用されます。言い換えると、アクセストークンやリフレッシュトークンの検証に使用できます。これはコンフィデンシャル・クライアントによってのみ呼び出すことができます。
このエンドポイントで呼び出す方法の詳細については、 OAuth 2.0 Token Introspectionの仕様 を参照してください。
動的クライアント登録エンドポイント
/realms/{realm-name}/clients-registrations/openid-connect
動的クライアント登録エンドポイントを使用して、クライアントを動的に登録します。
詳細については、クライアントの登録の章と OpenID Connect Dynamic Client Registrationの仕様 を参照してください。
トークン無効化エンドポイント
/realms/{realm-name}/protocol/openid-connect/revoke
トークン無効化エンドポイントは、トークンを無効化するために使用されます。このエンドポイントでは、リフレッシュトークンとアクセストークンの両方がサポートされています。
このエンドポイントで呼び出す方法の詳細については、 OAuth 2.0 Token Revocationの仕様 を参照してください。
デバイス認可エンドポイント
/realms/{realm-name}/protocol/openid-connect/auth/device
デバイス認可エンドポイントは、デバイスコードとユーザーコードを取得するために使用されます。コンフィデンシャル・クライアントのみが呼び出すことができます。
このエンドポイントで呼び出す方法の詳細については、 OAuth 2.0 Device Authorization Grantの仕様 を参照してください。
バックチャネル認証エンドポイント
/realms/{realm-name}/protocol/openid-connect/ext/ciba/auth
バックチャネル認証エンドポイントは、クライアントによって行われた認証リクエストを識別するauth_req_idを取得するために使用されます。コンフィデンシャル・クライアントのみが呼び出すことができます。
このエンドポイントで呼び出す方法の詳細については、 OpenID Connect Client Initiated Backchannel Authentication Flow specification を参照してください。
また、このガイドのClient Initiated Backchannel Authentication GrantセクションなどのKeycloakキュメントの他の場所とServer Administration GuideのClient Initiated Backchannel Authentication Grantのセクションを参照してください。
2.5.2. アクセストークンの検証
Keycloakによって発行されたアクセストークンを手動で検証する必要がある場合は、イントロスペクション・エンドポイントを呼び出すことができます。このアプローチの欠点は、Keycloakサーバーへのネットワーク呼び出しが必要であることです。これは、同時に実行される検証リクエストが多すぎると、サーバーの速度を低下させ、過剰な負荷をかかる可能性があります。Keycloakが発行したアクセストークンは JSON Web Tokens(JWT) であり、 JSON Web Signature(JWS) によりデジタル署名されています。このようにエンコードされているため、発行したレルムの公開鍵を使用してアクセストークンをローカルで検証できます。レルムの公開鍵を検証コードにハードコードするか、証明書エンドポイントを使用してJWSに埋め込まれたKey ID(KID)を使用して公開鍵を検索してキャッシュすることができます。コーディングする言語に応じて、JWS検証の手助けをするサードパーティー・ライブラリーが多数あります。
2.5.3. フロー
認可コード
認可コード・フローは、ユーザー・エージェントをKeycloakにリダイレクトします。ユーザーがKeycloakで正常に認証されると、認可コードが作成され、ユーザー・エージェントはアプリケーションにリダイレクトされます。次に、アプリケーションは、クレデンシャルとともに認可コードを使用して、Keycloakからアクセス・トークン、リフレッシュ・トークン、IDトークンを取得します。
このフローはWebアプリケーションを対象としていますが、ユーザー・エージェントを組み込むことができるモバイルアプリケーションなどのネイティブアプリケーションにも推奨されます。
詳細については、OpenID Connectの仕様の Authorization Code Flow を参照してください。
インプリシット
インプリシット・フローのリダイレクトは、認可コードフローと同様に機能しますが、認可コードが返される代わりに、アクセストークンとIDトークンが返されます。これにより、アクセストークンのために認可コードを交換するための余分な呼び出しの必要性が減ります。ただし、リフレッシュトークンは含まれません。その結果、長い有効期限を持つアクセストークンを許可する必要があります。これらのトークンを無効にするのは難しいため、問題があります。または、初期アクセストークンが期限切れになった場合は、新しいアクセス・トークンを取得するためにリダイレクトが必要です。インプリシット・フローは、アプリケーションがユーザーの認証のみを行い、自身でログアウトを処理する場合に便利です。
アクセス・トークンと認可コードが返されるハイブリッド・フローもあります。
インプリシット・フローとハイブリッド・フローの両方で、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 のセクションを参照してください。
デバイス認可グラント
デバイス認可グラントは、入力機能が制限されているか、適切なブラウザーがない、インターネットに接続されたデバイスで実行されているクライアントによって使用されます。アプリケーションはKeycloakにデバイスコードとユーザーコードを要求します。Keycloakは、デバイスコードとユーザーコードを作成します。Keycloakは、デバイスコードとユーザーコードを含むレスポンスをアプリケーションに返します。次に、アプリケーションはユーザーにユーザーコードと検証URIを提供します。ユーザーは、別のブラウザーを使用して、認証を受けるための検証URIにアクセスします。アプリケーションは、Keycloakがユーザーの認可を完了するまで、繰り返しKeycloakをポーリングします。ユーザーの認可が完了すると、アプリケーションはデバイスコードを取得します。次に、アプリケーションはデバイスコードとそのクレデンシャルを使用して、Keycloakからアクセストークン、リフレッシュトークン、およびIDトークンを取得します。
詳細については、https://tools.ietf.org/html/rfc8628 [OAuth 2.0 Device Authorization Grantの仕様] を参照してください。
Client Initiated Backchannel Authentication Grant
クライアント起点バックチャネル認証グラントは、OAuth 2.0の認証コードグラントのように、ユーザーのブラウザーを介してリダイレクトせずに、OpenIDプロバイダーと直接通信することによって認証フローを開始したいクライアントによって使用されます。
クライアントは、クライアントによって行われた認証リクエストを識別するauth_req_idをKeycloakに要求します。Keycloakはauth_req_idを作成します。
このauth_req_idを受信した後、このクライアントはKeycloakを繰り返しポーリングして、ユーザーが認証されるまでauth_req_idと引き換えにKeycloakからアクセストークン、リフレッシュトークン、IDトークンを取得する必要があります。
詳細については、 OpenID Connect Client Initiated Backchannel Authentication Flow specification を参照してください。
また、このガイドのバックチャネル認証グラントのセクションなどのKeycloakキュメントの他の場所とServer Administration Guideのクライアント起点バックチャネル認証グラントのセクションを参照してください。
2.5.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を使用すると、ユーザーが別のデバイスを使用してアプリケーションに貼り付けるコードを取得することもできます。
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_10.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>
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
</RoleMappingsProvider>
<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"
keepDOMAssertion="true"
autodetectBearerOnly="false">
...
</SP>
- entityID
-
このクライアントの識別子です。IdPは、IdPと通信しているクライアントを特定するため、この値を必要とします。この設定は、REQUIRED です。
- sslPolicy
-
これは、アダプターが実施するSSLポリシーです。有効な値は
ALL
、EXTERNAL
、NONE
です。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-With
、SOAPAction
、Accept
のような典型的なヘッダーに基づいて、SOAPクライアントまたはRESTクライアントを自動検出します。デフォルト値は false です。 - logoutPage
-
これは、ログアウト後に表示するページを設定します。ページが
http://web.example.com/logout.html
のような完全なURLである場合、ログアウトすると、HTTP302
ステータスコードを使用してそのページにリダイレクトされます。/logout.jsp
のようなスキーム部分を持たないリンクが指定された場合、 web.xmlのsecurity-constraint
宣言に従って保護されたレルムにあるかどうかに関わらず、 ログアウト後にそのページが表示されます。このページは、デプロイメント・コンテキスト・ルートに関連して解決されます。 - keepDOMAssertion
-
アダプターにアサーションのDOM表現を、リクエストに関連付けられた
SamlPrincipal
内に元の形式で保存させるには、この属性を true に設定する必要があります。アサーション・ドキュメントは、プリンシパル内のメソッドgetAssertionDocument
を使用して取得できます。これは、署名されたアサーションを再生するときに特に便利です。返されるドキュメントは、Keycloakサーバーが受信したSAMLレスポンスを解析して生成されたドキュメントです。この設定は OPTIONAL で、デフォルト値は false です(ドキュメントはプリンシパル内に保存されません)。
サービス・プロバイダーのKeysとKey要素
IdPがクライアント・アプリケーション(またはSP)に対してすべてのリクエストに署名することを要求する場合や、IdPがアサーションを暗号化する場合は、それを行うために使用する鍵を定義する必要があります。クライアント署名ドキュメントの場合、署名に使用される秘密鍵と公開鍵、または証明書の両方を定義する必要があります。暗号化の場合、復号化に使用される秘密鍵を定義するだけで済みます。
鍵を記述する方法は2つあります。Javaキーストア内に格納するか、PEM 形式で keycloak-saml.xml
内に直接コピー/ペーストできます。
<Keys>
<Key signing="true" >
...
</Key>
</Keys>
Key
要素には、2つの省略可能な属性 signing
と encryption
があります。 これらを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
要素の中では、 PrivateKeyPem
、 PublicKeyPem
、 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
要素を定義できます。
RoleMappingsProvider要素
RoleMappingsProvider
は、SAMLアダプターによって使用される org.keycloak.adapters.saml.RoleMappingsProvider
SPIの実装のidと設定を指定できるオプションの要素です。
KeycloakをIDPとして使用する場合、組み込みのロールマッパーを使用して、ロールをSAMLアサーションに追加する前にマッピングできます。ただし、SAMLアダプターを使用することでSAMLリクエストをサードパーティーのIDPに送信できるため、この場合、SPの要求に応じて、アサーションから抽出されたロールを異なるロールセットにマッピングする必要があります。 RoleMappingsProvider
SPIは、必要なマッピングを実行するために使用できるプラグ可能なロールマッパーの設定を可能にします。
プロバイダーの設定は次のようになります。
...
<RoleIdentifiers>
...
</RoleIdentifiers>
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
</RoleMappingsProvider>
<IDP>
...
</IDP>
id
属性は、インストールされているプロバイダーのどれを使用するかを識別します。 Property
サブ要素を複数回使用して、プロバイダーの設定プロパティーを指定できます。
プロパティー・ベースのロールマッピング・プロバイダー
Keycloakには、 properties
ファイルを使用してロールマッピングを実行する RoleMappingsProvider
の実装が含まれます。このプロバイダーは、ID properties-based-role-mapper
によって識別され、 org.keycloak.adapters.saml.PropertiesBasedRoleMapper
クラスによって実装されます。
このプロバイダーは、使用される properties
ファイルの場所を指定するために使用できる2つの設定プロパティーに依存しています。まず、 properties.file.location
プロパティーが指定されているかどうかを確認し、設定された値を使用してファイルシステム内の properties
ファイルを見つけます。設定されたファイルが見つからない場合、プロバイダーは RuntimeException
をスローします。次のスニペットは、 properties.file.configuration
オプションを使用して、ファイルシステムの /opt /mappers/
ディレクトリーから roles.properties
ファイルをロードするプロバイダーの例を示しています。
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.file.location" value="/opt/mappers/roles.properties"/>
</RoleMappingsProvider>
properties.file.location
が設定されていない場合、プロバイダーは properties.resource.location
プロパティーをチェックし、設定された値を使用して WAR
リソースから properties
ファイルをロードします。この設定プロパティーが存在しない場合、プロバイダーはデフォルトで /WEB-INF/role-mappings.properties
からファイルをロードしようとします。リソースからファイルをロードできないと、プロバイダーは RuntimeException
をスローします。 次のスニペットは、 properties.resource.location
を使用してアプリケーションの /WEB-INF/conf/
ディレクトリーから roles.properties
ファイルをロードするプロバイダーの例を示しています。
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/conf/roles.properties"/>
</RoleMappingsProvider>
properties
ファイルには、キーとしてロールとプリンシパルの両方を、値としてカンマで区切られたゼロ以上のロールのリストを含めることができます。呼び出されると、実装はアサーションから抽出された一連のロールを反復処理し、各ロールについてマッピングが存在するかどうかを確認します。ロールが空のロールにマップされている場合は、破棄されます。1つ以上の異なるロールのセットにマップされる場合、これらのロールは結果セットに設定されます。ロールのマッピングが見つからない場合は、結果セットにそのまま含まれます。
ロールが処理されると、実装はアサーションから抽出されたプリンシパルにエントリーの properties
ファイルが含まれているかどうかを確認します。プリンシパルのマッピングが存在する場合、値としてリストされているロールが結果セットに追加されます。これにより、プリンシパルに追加のロールを割り当てることができます。
例として、プロバイダーが次のプロパティー・ファイルで設定されていると仮定します。
roleA=roleX,roleY
roleB=
kc_user=roleZ
プリンシパル kc_user
がロール roleA
、 roleB
および roleC
を持つアサーションから抽出される場合、プリンシパルに割り当てられるロールの最終セットは roleC
、 roleX
、 roleY
および roleZ
になります。 roleA
は roleX
と roleY
の両方にマップされ、 roleB
は空のロールにマップされているので破棄され、 roleC
はそのまま使用され、最後に追加のロールが kc_user
プリンシパル( roleZ
)に追加されるためです。
注意:マッピングのロール名にスペースを使用する場合は、スペースの代わりにUnicodeを使用してください。たとえば、受信した 'role A' は次のように表示されます。
role\u0020A=roleX,roleY
独自のロールマッピング・プロバイダーの追加
カスタム・ロールマッピング・プロバイダーを追加するには、単に org.keycloak.adapters.saml.RoleMappingsProvider
SPIを実装する必要があります。詳細については、 Server Developer Guide の SAML Role Mappings SPI
のセクションを参照してください。
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_SHA1
、RSA_SHA256
、RSA_SHA512
、DSA_SHA1
です。 この設定は OPTIONAL で、デフォルトはRSA_SHA256
です。 - signatureCanonicalizationMethod
-
IDPが署名済みのドキュメントに使用することを想定している署名の正規化方法です。この設定は OPTIONAL です。デフォルトは
http://www.w3.org/2001/10/xml-exc-c14n#
で、ほとんどのIDPに対して変更が不要です。 - metadataUrl
-
IDPメタデータを取得するために使用されるURL。現在、これは定期的に署名および暗号化鍵を取得するために使用されます。これにより、SP側を手動で変更することなく、IDPでこれらの鍵を循環できます。
IDP AllowedClockSkewサブ要素
オプションのサブ要素 AllowedClockSkew
は、IDPとSPの間で許可されるクロックスキューを定義します。デフォルト値は0です。
<AllowedClockSkew unit="MILLISECONDS">3500</AllowedClockSkew>
- unit
-
この要素の値に付加される時間単位を定義することができます。許可される値は、MICROSECONDS、MILLISECONDS、MINUTES、NANOSECONDSおよびSECONDSです。これは _OPTIONAL_です。デフォルト値は
SECONDS
です。
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サーバーにプールすべき接続数を定義します。これは 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キーストアのパブリック証明書を抽出することで作成できます。これは、disableTrustManager
がtrue
でない限り、 REQUIRED です。 - truststorePassword
-
トラストストアのパスワードです。これは REQUIRED で、
truststore
を設定すると、トラストストアはパスワードを必要とします。 - 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-method
を KEYCLOAK-SAML
に変更します。両方の方法についてこのセクションで説明します。
アダプターのインストール
各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。
今回のリリースでは、WildFlyの最新バージョンでのみアダプターのテストとメンテナンスを行っています。WildFlyの新しいバージョンがリリースされると、現在のアダプターは非推奨になり、WildFlyの次のリリース後にサポートが削除されます。もう一つの選択肢は、JBoss EAPアダプターの場合はより長期間サポートされるので、アプリケーションをWildFlyからJBoss EAPに切り替えることです。 |
WildFly 9以上、または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
ディレクトリーからスクリプトを実行します。
$ cd $JBOSS_HOME
$ ./bin/jboss-cli.sh -c --file=bin/adapter-elytron-install-saml.cli
$ cd $JBOSS_HOME
$ /bin/boss-cli.sh -c --file=bin/adapter-install-saml.cli
WildFly 11以上でもレガシーな非Elytronアダプターが使用できます。つまり、それらのバージョンでも adapter-install-saml.cli を使用することができます。ただし、新しいElytronアダプターを使用することをお勧めします。
|
スクリプトは、以下に説明するように、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>
セキュリティー・コンテキストは、EJB層に自動的に伝播されます。
JBoss SSO
WildFlyには、同じWildFlyインスタンスにデプロイされたWebアプリケーションのシングル・サインオンのサポートが組み込まれています。これは、Keycloakを使用しているときは有効にしないでください。
JSESSIONID CookieにSameSite値を設定する
各ブラウザーは、Cookieの SameSite
属性のデフォルト値を Lax
に設定することを計画しています。この設定は、リクエストが同じドメインで発生した場合にのみCookieがアプリケーションに送信されることを意味します。この動作はSAML POSTバインディングに影響を与え、機能しなくなる可能性があります。SAMLアダプターの完全な機能を保持するために、コンテナーによって作成された JSESSIONID
Cookieの SameSite
値を None
に設定することをお勧めします。そうしないと、Keycloakへのリクエストごとにコンテナーのセッションがリセットされる可能性があります。
SameSite 属性が None に設定されないようにするには、許容できる場合はREDIRECTバインディングに切り替えるか、この回避策が不要な場合はOIDCプロトコルに切り替えることを検討してください。
|
Wildfly/EAPの JSESSIONID
Cookieの SameSite
値を None
に設定するには、以下の内容のファイル undertow-handlers.conf
をアプリケーションの WEB-INF
ディレクトリーに追加します。
samesite-cookie(mode=None, cookie-pattern=JSESSIONID)
この設定のサポートは、バージョン19.1.0以降のWildFlyで利用できます。
3.1.3. RPMからのJBoss EAPアダプターのインストール
次のように、RPMからEAP 7アダプターをインストールします。
Red Hat Enterprise Linux 7では、チャンネルという用語はリポジトリーという用語に置き換えられました。これらの説明では、リポジトリーという用語のみが使用されています。 |
RPMからEAP 7アダプターをインストールする前に、JBoss EAP 7リポジトリーにサブスクライブする必要があります。
-
Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。
-
すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。
Red Hat Enterprise Linux 6、7の場合:Red Hat Subscription Managerを使用して、次のコマンドでWildFly 23リポジトリーに登録します。Red Hat Enterprise Linuxバージョンに応じて、 <RHEL_VERSION> を6または7のいずれかに置き換えてください。
$ sudo subscription-manager repos --enable=jb-eap-7-for-rhel-<RHEL_VERSION>-server-rpms
Red Hat Enterprise Linux 8の場合:Red Hat Subscription Managerを使用して、次のコマンドでWildFly 23リポジトリーに登録します。
$ sudo subscription-manager repos --enable=jb-eap-23-for-rhel-8-x86_64-rpms --enable=rhel-8-for-x86_64-baseos-rpms --enable=rhel-8-for-x86_64-appstream-rpms
次のコマンドを使用して、SAML用のEAP 7アダプターをインストールします。
$ sudo yum install eap7-keycloak-saml-adapter-sso7_4
または、次のいずれかをRed Hat Enterprise Linux 8に使用します。
$ sudo dnf install eap7-keycloak-adapter-sso7_4
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リポジトリーにサブスクライブする必要があります。
-
Red Hat Subscription Managerを使用して、Red Hat Enterprise Linuxシステムがアカウントに登録されていることを確認してください。詳細は、Red Hat Subscription Management documentationのリンクを参照してください。
-
すでに別のJBoss EAPリポジトリーに登録している場合は、まずそのリポジトリーから登録を解除する必要があります。
Red Hat Subscription Managerを使用して、次のコマンドを使用してJBoss EAP 6リポジトリーにサブスクライブします。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_4-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パッケージ内に設定を追加し、ファイルを編集することで、WARをセキュリティー保護する方法について説明します。
まず、WARの WEB-INF
ディレクトリーに keycloak-saml.xml
アダプター設定ファイルを作成します。この設定ファイルの形式は、共通アダプター設定セクションで説明しています。
次に、 web.xml
の KEYCLOAK-SAML
に auth-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.xml
に security-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-deployment
の name
属性は保護したい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 7、8、9にデプロイされたWARアプリケーションを保護するには、Keycloak Tomcat 7 SAMLアダプターまたはKeycloak Tomcat SAMLアダプターをTomcatにインストールする必要があります。その後、TomcatにデプロイするWARにもいくつかの設定を行う必要があります。これらの手順について説明します。
アダプターのインストール
アダプターはアプライアンスやwarには含まれていません。各アダプターは、Keycloakのダウンロード・サイトで個別にダウンロードできます。これらは、mavenのアーティファクトとしても利用できます。
アダプターの配布物をTomcatの lib/
ディレクトリーに解凍する必要があります。WEB-INF/libディレクトリー内にアダプターのjarを含めても動作しません!Keycloak SAMLアダプターはValveとして実装され、ValveのコードはTomcatのメインのlib/ディレクトリーに存在する必要があります。
Tomcat 7へのインストールは次のとおりです。
$ cd $TOMCAT_HOME/lib
$ unzip keycloak-saml-tomcat7-adapter-dist.zip
Tomcat 8、9へのインストールは次のとおりです。
$ cd $TOMCAT_HOME/lib
$ unzip keycloak-saml-tomcat-adapter-dist.zip
WARごとの設定
このセクションでは、直接WARパッケージ内に設定を追加し、ファイルを編集することで、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>
keycloak-saml.xml
が明示的に assertionConsumerServiceUrl
を設定しない場合、SAMLアダプターは暗黙的に /my-context-path/saml
の場所でSAMLアサーションをリッスンします。これは、IDPのレルム/クライアント設定の Master SAML Processing URL
と一致しなければなりません。例えば、 http://sp.domain.com/my-context-path/saml
。そうでない場合、Tomcatはおそらくユーザーがログインした後にSAMLアサーションを受信しないため、IDPログインサービスに無限にリダイレクトします。
JSESSIONID CookieにSameSite値を設定する
各ブラウザーは、Cookieの SameSite
属性のデフォルト値を Lax
に設定することを計画しています。この設定は、リクエストが同じドメインで発生した場合にのみCookieがアプリケーションに送信されることを意味します。この動作はSAML POSTバインディングに影響を与え、機能しなくなる可能性があります。SAMLアダプターの完全な機能を保持するために、コンテナーによって作成された JSESSIONID
Cookieの SameSite
値を None
に設定することをお勧めします。そうしないと、Keycloakへのリクエストごとにコンテナーのセッションがリセットされる可能性があります。
SameSite 属性が None に設定されないようにするには、許容できる場合はREDIRECTバインディングに切り替えるか、この回避策が不要な場合はOIDCプロトコルに切り替えることを検討してください。
|
Tomcatの JSESSIONID
Cookieの SameSite
値を None
に設定するには、アプリケーションの context.xml
に次の設定を追加します。これにより、Tomcatコンテナーによって作成されたすべてのCookieの SameSite
値が None
に設定されることに注意してください。
<CookieProcessor sameSiteCookies="None" />
SameSite 属性をCookieのサブセットのみに設定することはできません。そのため、アプリケーション用に作成されたすべてのCookieでは、この属性が None に設定されます。
|
この機能のサポートは、バージョン9.0.29および8.5.49のTomcatで利用できます。
3.1.5. Jetty SAMLアダプター
JettyにデプロイされたWARアプリケーションを保護するには、Keycloak Jetty 9.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パッケージ内に設定を追加し、ファイルを編集することで、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>
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
を登録する必要があります。
To use this filter, include this maven artifact in your WAR poms:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-servlet-filter-adapter</artifactId>
<version>13.0.1</version>
</dependency>
マルチテナンシーを使用するには、 keycloak.config.resolver
パラメーターをフィルター・パラメーターとして渡す必要があります。
<filter>
<filter-name>Keycloak Filter</filter-name>
<filter-class>org.keycloak.adapters.saml.servlet.SamlFilter</filter-class>
<init-param>
<param-name>keycloak.config.resolver</param-name>
<param-value>example.SamlMultiTenantResolver</param-value>
</init-param>
</filter>
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のクラスター内で処理されます。
-
管理者が特定のSAMLセッションのログアウト・リクエストを発行すると、そのリクエストはデータセンター2に送信されます。
データセンター2は、データセンター1(およびHTTPセッションを共有する他のすべてのデータセンター)に存在するすべてのセッションをログアウトする必要があります。
このケースをカバーするために、上記で記述されたSAMLセッション・キャッシュは、個々のクラスター内だけでなく、すべてのデータセンターにわたってレプリケーションする必要があります。例: スタンドアローンInfinispan/JDGサーバー経由:
-
スタンドアローンのInfinispan/JDGサーバーにキャッシュを追加する必要があります。
-
前の項目のキャッシュは、それぞれの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のリクエスト/レスポンスのドキュメントを見ることができます。
3.1.12. マルチテナンシー
SAMLは、マルチテナンシー についてOIDCと同じ機能を提供します。つまり、単一のターゲット・アプリケーション(WAR)を複数のKeycloakレルムで保護できます。レルムは、同じKeycloakインスタンスまたは異なるインスタンスに配置できます。
これを行うには、アプリケーションは複数の keycloak-saml.xml
アダプター設定ファイルを持つ必要があります。
異なるコンテキストパスに異なるアダプター設定ファイルをデプロイして、WARの複数のインスタンスを作成することができますが、これは不便であり、コンテキストパス以外のものに基づいてレルムを選択することもできます。
Keycloakではカスタム設定リゾルバーを持つことが可能なため、どのアダプター設定が各リクエストに使用されるかを選択することができます。SAMLでは、設定はログイン処理においてのみ関係しています。ユーザーがログインするとセッションは認証され、返される keycloak-saml.xml
が異なっていても問題ありません。そのため、同じセッションに対して同じ設定を返すことが正しい方法です。
これを実現するためには、 org.keycloak.adapters.saml.SamlConfigResolver
の実装を作成してください。次の例では Host
ヘッダーを使って適切な設定を見つけ、それとアプリケーションのJavaクラスパスから関連する要素をロードしています。
package example;
import java.io.InputStream;
import org.keycloak.adapters.saml.SamlConfigResolver;
import org.keycloak.adapters.saml.SamlDeployment;
import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.saml.common.exceptions.ParsingException;
public class SamlMultiTenantResolver implements SamlConfigResolver {
@Override
public SamlDeployment resolve(HttpFacade.Request request) {
String host = request.getHeader("Host");
String realm = null;
if (host.contains("tenant1")) {
realm = "tenant1";
} else if (host.contains("tenant2")) {
realm = "tenant2";
} else {
throw new IllegalStateException("Not able to guess the keycloak-saml.xml to load");
}
InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak-saml.xml");
if (is == null) {
throw new IllegalStateException("Not able to find the file /" + realm + "-keycloak-saml.xml");
}
ResourceLoader loader = new ResourceLoader() {
@Override
public InputStream getResourceAsStream(String path) {
return getClass().getResourceAsStream(path);
}
};
try {
return new DeploymentBuilder().build(is, loader);
} catch (ParsingException e) {
throw new IllegalStateException("Cannot load SAML deployment", e);
}
}
}
また、以下のように、 web.xml
の keycloak.config.resolver
context-paramでどの SamlConfigResolver
実装を使うかを設定する必要もあります。
<web-app>
...
<context-param>
<param-name>keycloak.config.resolver</param-name>
<param-value>example.SamlMultiTenantResolver</param-value>
</context-param>
</web-app>
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モジュールの設定を生成するには、以下のステップを実行します。
-
SAMLクライアントのインストール・ページに移動し、Mod Auth Mellon filesオプションを選択します。
mod_auth_mellon設定のダウンロード -
必要な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/private 1つだけです。
Mellonサービス・プロバイダーを設定するには、次の手順を実行します。
-
/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>
上記のコードで参照されているファイルの一部は、後の手順で作成されます。 |
3.2.2. mod_auth_mellonが使用するCookieのSameSite値を設定する
ブラウザーは、Cookieの SameSite
属性のデフォルト値を Lax
に設定することを計画しています。この設定は、リクエストが同じドメインで発生した場合にのみCookieがアプリケーションに送信されることを意味します。この動作はSAML POSTバインディングに影響を与え、機能しなくなる可能性があります。 mod_auth_mellon モジュールの完全な機能を保持するために、 mod_auth_mellon モジュールによって作成されたCookieの SameSite
値を None
に設定することをお勧めします。そうしないと、Keycloakを使用してログインできなくなる場合があります。
SameSite
の値を None
に設定するには、次の設定を mellon.conf
ファイル内の <Location / >
タグに追加します。
MellonSecureCookie On
MellonCookieSameSite none
この設定のサポートは、バージョン0.16.0以降の mod_auth_mellon モジュールで利用できます。
サービス・プロバイダーのメタデータの作成
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メタデータを作成するには、次の手順を実行します。
-
ヘルパーのシェル変数をいくつか作成します。
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')"
-
次のコマンドを実行して、Mellonメタデータ作成ツールを呼び出します。
/usr/libexec/mod_auth_mellon/mellon_create_metadata.sh $mellon_entity_id $mellon_endpoint_url
-
生成されたファイルを目的の場所に移動します(上記の/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サービス・プロバイダーを追加する
仮定: KeycloakのIdPはすでに$idp_hostにインストールされています。
Keycloakは複数のテナントをサポートしており、すべてのユーザー、クライアントなどがレルムと呼ばれる領域にグループ化されます。各レルムは他のレルムとは独立しています。Keycloakに既存のレルムを使用できますが、この例では、test_realmという新しいレルムを作成し、そのレルムを使用する方法を示しています。
これらの操作はすべて、Keycloak管理Webコンソールを使用して実行されます。$idp_hostの管理者ユーザー名とパスワードが必要です。
次の手順を完了してください。
-
管理コンソールを開き、管理者のユーザー名とパスワードを入力してログオンします。
管理コンソールにログインすると、既存のレルムが存在します。Keycloakを最初に設定すると、デフォルトでルート・レルムのmasterが作成されます。以前に作成されたレルムは、管理コンソールの左上隅にドロップダウン・リストに表示されます。
-
レルムのドロップダウン・リストから Add realm を選択します。
-
名前フィールドに
test_realm
と入力し、 Create をクリックします。
Mellonサービス・プロバイダーをレルムのクライアントとして追加する
Keycloakでは、SAML SPはクライアントと呼ばれます。SPを追加するには、レルムのクライアントのセクションに移動します。
-
左側のClientsメニュー項目をクリックし、右上の Create をクリックして新しいクライアントを作成します。
Mellon SPクライアントの追加
Mellon SPクライアントを追加するには、次の手順を実行します。
-
クライアント・プロトコルをSAMLに設定します。Client Protocolドロップダウン・リストから、 saml を選択します。
-
上記で作成したMellon SPメタデータ・ファイル(/etc/httpd/saml2/mellon_metadata.xml)を提供します。ブラウザーが実行されている場所によっては、$sp_hostからブラウザーが実行されているマシンにSPメタデータをコピーして、ブラウザーがそのファイルを見つけなければならない場合があります。
-
Save をクリックします。
Mellon SPクライアントの編集
いくつかのクライアント設定パラメータがあります。
-
"Force POST Binding"がオンになっていることを確認します。
-
有効なリダイレクトURIリストにpaosResponseを追加します。
-
"Valid Redirect URIs"内のpostResponse URLをコピーし、 "+"のすぐ下の空の追加テキスト・フィールドに貼り付けます。
-
"postResponse"を"paosResponse"に変更します(SAML ECPにはpaosResponse URLが必要です)。
-
下部の Save をクリックしてください。
-
多くのSAML SPは、グループ内のユーザーのメンバーシップに基づいて認可を決定します。KeycloakのIdPはユーザー・グループ情報を管理できますが、IdPがSAML属性としてそれを提供するように設定されていない限り、ユーザーのグループは提供されません。
ユーザーのグループをSAML属性として提供するようにIdPを設定するには、次の手順を実行します。
-
クライアントのMapperタブをクリックします。
-
Mapperページの右上にある Create をクリックします。
-
Mapper Typeのドロップダウン・リストから Group list を選択します。
-
"group list"に名前を設定します。
-
"groups"にSAML属性名を設定します。
-
Save をクリックします。
残りの手順は$sp_hostで実行されます。
アイデンティティー・プロバイダー・メタデータの取得
IdPでレルムを作成したので、それに関連付けられたIdPメタデータを取得して、Mellon SPがそれを認識できるようにする必要があります。前に作成した/etc/httpd/conf.d/mellon.confファイルでは、MellonIdPMetadataFileは/etc/httpd/saml2/idp_metadata.xmlとして指定されていますが、そのファイルは$sp_host上に存在しませんでした。そのファイルを取得するには、IdPからファイルを検索します。
-
$idp_hostを正しい値に置き換えて、IdPからファイルを取得します。
curl -k -o /etc/httpd/saml2/idp_metadata.xml \ https://$idp_host/auth/realms/test_realm/protocol/saml/descriptor
これでMellonの設定は完了となります。
-
Apache設定ファイルの構文チェックを実行するには、次のようにします。
apachectl configtest
Configtestは apachectl の -t 引数に相当します。設定テストでエラーが示された場合は、先に進む前に修正してください。 -
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/realms/master/protocol/docker-v2/auth service: docker-test issuer: http://localhost:8080/auth/realms/master
この出力は、既存のレジストリー設定ファイルにコピーできます。ファイルの設定方法の詳細については、レジストリー設定ファイルの仕様を参照してください。または、基本的な例から始めてください。
rootcertbundle フィールドにKeycloakのレルムの公開証明書の場所を設定するのを忘れないでください。auth設定は、この引数なしでは動作しません。
|
4.2. Dockerレジストリー環境変数のオーバーライド・インストール
開発やPOC用のDockerレジストリーに単純な環境変数のオーバーライドを使用することが適切な場合がよくあります。このアプローチは、通常プロダクション環境での使用では推奨されていませんが、レジストリーを立ち上げるための安上がりな方法が必要な場合に役立ちます。クライアント・インストール・タブから Variable Override Format Optionを使用するだけで、出力は次のようになります。
REGISTRY_AUTH_TOKEN_REALM: http://localhost:8080/auth/realms/master/protocol/docker-v2/auth REGISTRY_AUTH_TOKEN_SERVICE: docker-test REGISTRY_AUTH_TOKEN_ISSUER: http://localhost:8080/auth/realms/master
REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE オーバーライドをKeycloakレルムの公開証明書の場所で設定するのを忘れないでください。auth設定は、この引数なしでは動作しません。
|
4.3. Docker Compose YAMLファイル
このインストール方法は、Keycloakサーバーで認証するDockerレジストリーを構築する簡易的な方法です。これは開発目的のみを対象としており、プロダクション環境やそれと同等の環境には使用しないでください。 |
zipファイルのインストール・メカニズムは、KeycloakサーバーがDockerレジストリーとどのようにやりとりができるかを理解したい開発者のために、クイックスタートを提供します。 下記のとおりに設定します。
-
目的のレルムから、クライアント設定を作成します。この時点で、Dockerレジストリーはありません。クイックスタートがその部分を担当します。
-
インストール・タブから"Docker Compose YAML"オプションを選択し、.zipファイルをダウンロードします。
-
アーカイブを目的の場所に解凍し、ディレクトリーを開きます。
-
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のビルトインサポートが用意されています。クライアント登録サービスのエンドポイントは /auth/realms/<realm>/clients-registrations/<provider>
です。
サポートされている組み込みの provider
は以下のとおりです。
-
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リクエストを /auth/realms/<realm>/clients-registrations/default
に送信します。
登録アクセストークンを含むClient Representationが返されます。設定を取得したり、クライアントを後で更新、削除したい場合は、登録アクセストークンをどこかに保存する必要があります。
Client Representationを取得するには、HTTP GETリクエストを /auth/realms/<realm>/clients-registrations/default/<client id>
に送信します。
新しい登録アクセストークンも返します。
Client Representationを更新するには、更新したClient Representationを次のURLにHTTP PUTします: /auth/realms/<realm>/clients-registrations/default/<client id>
。
新しい登録アクセストークンも返します。
Client Representationを削除するには、次のURLにHTTP DELETEします: /auth/realms/<realm>/clients-registrations/default/<client id>
。
5.3. Keycloakアダプター設定
installation
クライアント登録プロバイダーは、クライアントのアダプター設定を取得するために使用できます。トークン認証に加えて、HTTP BASIC認証を使用してクライアント・クレデンシャルで認証することもできます。 これを行うには、リクエストに次のヘッダーを含めます。
Authorization: basic BASE64(client-id + ':' + client-secret)
アダプター設定を取得するには、HTTP GETリクエストを /auth/realms/<realm>/clients-registrations/install/<client id>
に送信します。
パブリック・クライアントは認証が要求されません。これは、JavaScriptアダプターは、上記URLを使用して、直接Keycloakからクライアント設定を読み込めることを意味します。
5.4. OpenID Connect動的クライアント登録
Keycloakは、 OAuth 2.0 Dynamic Client Registration Protocol と OAuth 2.0 Dynamic Client Registration Management Protocol を拡張した OpenID Connect Dynamic Client Registration を実装しています。
これらの仕様を使用した、Keycloakにクライアントを登録するエンドポイントは、 /auth/realms/<realm>/clients-registrations/openid-connect[/<client id>]
です。
このエンドポイントは、そのレルムのOpenID Connect Discoveryエンドポイント( /auth/realms/<realm>/.well-known/openid-configuration
)でも見つかります。
5.5. SAMLエンティティー記述子
SAMLエンティティー記述子エンドポイントは、クライアントを作成するために、SAML v2エンティティー記述子を使用することだけをサポートします。クライアントの取得、更新、削除はサポートしていません。これらの操作に対しては、Keycloak represendationのエンドポイントを使用してください。クライアントを作成すると、作成されたクライアントの詳細とともに、Keycloak Client Representationが返されます(登録アクセストークンを含みます)。
クライアントを作成するには、SAMLエンティティー記述子を使用して /auth/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で使用するための新しい正規ユーザーの設定
-
管理コンソール(たとえば、 http://localhost:8080/auth/admin)に
admin
としてログインします。 -
管理するレルムを選択します。
-
既存のユーザーを使用する場合は、編集するユーザーを選択します。それ以外の場合は、新しいユーザーを作成します。
-
Role Mappings > Client Roles > realm-management を選択します。masterレルムにいる場合は、NAME-realm を選択します。ここで、
NAME
はターゲット・レルムの名前です。masterレルム内のユーザーに他のレルムへのアクセス権を与えることができます。 -
Available Roles > manage-client を選択して、クライアント管理権限のフルセットを付与します。別の選択肢として、読み取り専用に view-clients を、または新しいクライアント作成用に create-client を選択します。
これらの権限は、ユーザーに初期アクセストークンまたは登録アクセストークンを使用せずに操作を実行できるようにします。
realm-management
ロールをユーザーに割り当てることはできません。その場合、ユーザーはクライアント登録CLIでログインできますが、初期アクセストークンなしでは使用できません。トークンなしで操作を実行しようとすると、 403 Forbidden エラーが発生します。
管理者は、管理コンソールの Realm Settings > Client Registration > Initial Access Token メニューから初期アクセストークンを発行できます。
6.2. クライアント登録CLIで使用するためのクライアントの設定
デフォルトでは、サーバーはクライアント登録CLIを admin-cli
クライアントとして認識します。これは新規レルムごとに自動的に設定されます。ユーザー名でログインする場合、追加のクライアント設定は必要ありません。
-
クライアント登録CLIに別のクライアント設定を使用したい場合は、新しいクライアントを作成します(たとえば、
reg-cli
)。 -
Standard Flow Enabled を Off に設定します。
-
クライアント
Access Type
をConfidential
に設定し、 Credentials > ClientId and Secret を選択することで、セキュリティーを強化してください。Credentials タブの下で、
Client Id and Secret
またはSigned JWT
のいずれかを設定できます。 -
クライアントに関連付けられたサービス・アカウントを使用したい場合は、
管理コンソール
の Clients セクションで編集するクライアントを選択することで、サービス・アカウントを有効にします。-
Settings で、 Access Type を Confidential に変更し、 Service Accounts Enabled の設定を On に切り替え、 Save をクリックします。
-
Service Account Roles をクリックし、目的のロールを選択してサービス・アカウントのアクセスを設定します。選択するロールの詳細については、クライアント登録CLIで使用するための新しい正規ユーザーの設定を参照してください。
-
-
サービス・アカウントの代わりに通常のユーザー・アカウントを使用する場合は、 Direct Access Grants Enabled の設定を On に切り替えます。
-
クライアントが
Confidential
として設定されている場合、--secret
オプションを使用して、kcreg config credentials
を実行する際に設定されたシークレットを提供してください。 -
kcreg config credentials
を実行する際に使用するclientId
を指定します(たとえば、--client reg-cli
)。 -
サービス・アカウントを有効にすると、
kcreg config credentials
を実行するときにユーザーを指定せずに、クライアント・シークレットまたはキーストア情報のみを提供することができます。
6.3. クライアント登録CLIのインストール
クライアント登録CLIは、Keycloakサーバーの配布物内にパッケージ化されています。実行スクリプトは bin
ディレクトリにあります。Linuxスクリプトは kcreg.sh
で、Windowsスクリプトは kcreg.bat
です。
ファイル・システム上の任意の場所からクライアントを使用できるように設定するときは、Keycloakサーバーのディレクトリーを PATH
に追加してください。
以下に例を示します。
-
Linuxの場合:
$ export PATH=$PATH:$KEYCLOAK_HOME/bin $ kcreg.sh
-
Windowsの場合:
c:\> set PATH=%PATH%;%KEYCLOAK_HOME%\bin c:\> kcreg
KEYCLOAK_HOME
は、Keycloakサーバーの配布物が解凍されたディレクトリーを示します。
6.4. クライアント登録CLIの使用
-
クレデンシャルでログインして、認証されたセッションを開始します。
-
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
プロダクション環境では、ネットワーク・スニファーへのトークンの公開を避けるため、
https:
でKeycloakにアクセスする必要があります。
-
-
サーバーの証明書が、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. ログイン
-
クライアント登録CLIを使用してログインする際は、サーバーのエンドポイントURLとレルムを指定します。
-
ユーザー名またはクライアント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つの設定ファイルに結び付けられた操作を実行するのが最も安全な方法です。
システム上の他のユーザーが設定ファイルを参照できないようにしてください。設定ファイルには、非公開にしておくべきアクセストークンとシークレットが含まれています。 |
利便性が低く、より多くのトークン要求が必要ではありますが、すべてのコマンドで --no-config
オプションを使用することで、設定ファイル内にシークレットを保存しないようにすることができます。 kcreg
呼び出しごとにすべての認証情報を指定してください。
6.4.3. 初期アクセストークンと登録アクセストークン
使用したいKeycloakサーバーで設定されたアカウントを持っていない開発者は、クライアント登録CLIを使用できます。レルム管理者が開発者に初期アクセストークンを発行したときだけ、開発者は使用することができます。これらのトークンをいつどのように発行し配布するかは、レルム管理者が決定します。レルム管理者は、初期アクセストークンの最大経過時間と、初期アクセストークンを使用して作成できるクライアントの総数を制限できます。
開発者が初期アクセストークンを取得すると、開発者はこれを使用して、 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 --help
と kcreg 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
コマンドを実行してください。
7. Token Exchange
Token Exchangeは、 テクノロジー・プレビュー であり、完全にはサポートされていません。この機能はデフォルトで無効になっています。 有効にするには、 |
Token Exchangeを使用するには、 |
Keycloakにおいて、Token Exchangeとはクレデンシャルまたはトークンのセットを使用して、全く異なるトークンを取得するプロセスです。クライアントは信頼性の低いアプリケーションを呼び出すかもしれず、現在のトークンをダウングレードしたい場合があります。クライアントは、リンクされたソーシャル・プロバイダー・アカウントのために保存されたトークンを、Keycloakトークンに交換したいことがあります。他のKeycloakのレルムや外部IDPによって作成された外部トークンを信頼することができます。クライアントはあるユーザーに成り代わる必要があるかもしれません。Token Exchangeに関するKeycloakの現在の機能の概要を簡単に説明します。
-
クライアントは、特定のクライアントに対して作成された既存のKeycloakトークンを、別のクライアントをターゲットとする新しいトークンと交換することができます
-
クライアントは、既存のKeycloakトークンを外部トークン(つまり、リンクされたFacebookアカウント)と交換できます
-
クライアントは、外部トークンをKeycloakトークンに交換できます。
-
クライアントは、ユーザーに成り代わることができます。
KeycloakのToken Exchangeは、 OAuth Token Exchange の仕様の非常にルーズな実装です。Keycloakでは、それを少し拡張し、一部を無視し、仕様の他の部分をルーズに解釈しました。これは、あるレルムのOpenID Connectトークン・エンドポイントでの単純なグラントタイプの呼び出しです。
/auth/realms/{realm}/protocol/openid-connect/token
フォーム・パラメーター( application/x-www-form-urlencoded
)を入力として受け取り、出力は交換をリクエストしたトークンのタイプに依存します。Token Exchangeはクライアント・エンドポイントであるため、リクエストは呼び出し元のクライアントに認証情報を提供する必要があります。パブリック・クライアントは、クライアント識別子をフォーム・パラメーターとして指定します。コンフィデンシャル・クライアントは、フォーム・パラメーターを使用してクライアント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
-
OPTIONAL 。
subject_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_token
とurn: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-type
と requested_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
クレームを含めることがあります。このリンクは、クライアントが開始したリンクリクエストに使用できます。
Token Exchangeのセットアップには細かい粒度の管理権限が必要です(詳細はServer Administration Guideのリンクを参照してください)。クライアントに交換の権限を付与する必要があります。これについては、この章の後半で説明します。 |
この章では、セットアップの要件について説明し、さまざまな交換のシナリオの例を示します。簡単にするために、現在のレルムで作成されたトークンを 内部 トークン、外部レルムまたはアイデンティティー・プロバイダーが作成したトークンを 外部 トークンとして呼ぶことにします。
7.1. 内部トークンから内部トークンへの交換
内部トークンから内部トークンへの交換で、特定のクライアントに発行された既存のトークンを、別のターゲット・クライアント用に作成された新しいトークンと交換する必要があります。なぜこれをしたいのでしょうか?これは一般に、クライアントはトークンを持っているが、別のアクセストークンのクレームと権限を必要とする他のアプリケーションに対して、追加のリクエストを行う必要がある場合に発生します。このタイプの交換が必要なその他の理由は、信頼性の低いアプリケーションでアプリケーションを呼び出す必要があり、現在のアクセストークンを伝播したくない場合に"権限のダウングレード"を実行する必要がある場合です。
7.1.1. 交換のための権限を付与
別のクライアントとトークンを交換したいクライアントは、管理コンソールで認可される必要があります。交換の権限を与えたいターゲット・クライアントに token-exchange
のきめ細かい権限を定義する必要があります。
Permissions Enabled
スイッチをONに切り替えます。
このページに token-exchange
のリンクがあります。クリックすると、権限の定義が開始され、このページに移動します。
この権限に対するポリシーを定義する必要があります。 Authorization
のリンクをクリックし、 Policies
タブに行き、 Client
ポリシーを作成してください。
ここでは、開始するクライアント、つまりトークン交換を要求している認証済みクライアントを入力します。このポリシーを作成したら、ターゲット・クライアントの token-exchange
の権限に戻り、今定義したクライアント・ポリシーを追加します。
これでクライアントは交換を実行する権限を持ちます。これを正しく行わないで交換しようとすると、403 Forbiddenのレスポンスが表示されます。
7.1.2. リクエストの実行
クライアントがターゲットとする別のクライアントのトークンを既存のトークンと交換しているときは、 audience
パラメーターを使用する必要があります。このパラメーターは、管理コンソールで設定したターゲット・クライアントのクライアント識別子である必要があります。
curl -X POST \
-d "client_id=starting-client" \
-d "client_secret=the client secret" \
--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
タブに移動する必要があります。
Permissions Enabled
スイッチをtrueに切り替えます。
このページに token-exchange
のリンクがあります。クリックすると、権限の定義が開始され、このページに移動します。
この権限に対するポリシーを定義する必要があります。 Authorization
のリンクをクリックし、 Policies
タブに行き、 Client
ポリシーを作成してください。
ここでは、開始するクライアント、つまりトークン交換を要求している認証済みクライアントを入力します。このポリシーを作成したら、アイデンティティー・プロバイダーの token-exchange
の権限に戻り、今定義したクライアント・ポリシーを追加します。
これでクライアントは交換を実行する権限を持ちます。これを正しく行わないで交換しようとすると、403 Forbiddenのレスポンスが表示されます。
7.2.2. リクエストの実行
クライアントが既存の内部トークンを外部トークンと交換する場合は、 requested_issuer
パラメーターを指定する必要があります。パラメーターは、設定済みのアイデンティティー・プロバイダーのエイリアスでなければなりません。
curl -X POST \
-d "client_id=starting-client" \
-d "client_secret=the client secret" \
--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_expired
か not_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=the client secret" \
--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. リクエストの実行
追加で requested_subject
パラメーターを指定している点を除いて、他の章で説明したようにリクエストを行います。このパラメーターの値は、ユーザー名またはユーザーIDでなければなりません。
curl -X POST \
-d "client_id=starting-client" \
-d "client_secret=the client secret" \
--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
タブをクリックしてください。
Permissions Enabled
スイッチをtrueに切り替えます。
ページに impersonation
リンクがあります。クリックすると、権限の定義が開始され、このページに移動します。
この権限に対するポリシーを定義する必要があります。 Authorization
のリンクをクリックし、 Policies
タブに行き、 Client
ポリシーを作成してください。
ここでは、開始するクライアント、つまりトークン交換を要求している認証済みクライアントを入力します。このポリシーを作成したら、ユーザーの impersonation
権限に戻り、今定義したクライアント・ポリシーを追加します。
クライアントにユーザーに成り代わる権限が付与されました。これを正しく行わないと、これを交換のタイプにしようとする際に、403 Forbiddenのレスポンスが表示されます。
パブリック・クライアントはダイレクト・ネイキッドな成り代わりを行うことができません。 |
7.5.2. リクエストの実行
リクエストを行うには、 requested_subject
パラメーターを指定してください。これは、有効なユーザーのユーザー名またはユーザーIDでなければなりません。また、必要に応じて audience
パラメーターを指定することもできます。
curl -X POST \
-d "client_id=starting-client" \
-d "client_secret=the client secret" \
--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. 交換の脆弱性
Token Exchangeの許可を行う上で、意識して気をつけなければならないさまざまなことがあります。
1つはパブリック・クライアントです。パブリック・クライアントは、交換を実行するためにクライアント・クレデンシャルを持たない、または必要としません。有効なトークンを持っていれば、パブリック・クライアントに偽装することができ、パブリック・クライアントに実行が許可されている交換を実行できます。レルムで管理されている信頼できないクライアントがある場合、パブリック・クライアントは許可モデルで脆弱性を公開する可能性があります。このため、ダイレクト・ネイキッド交換ではパブリック・クライアントは許可されず、呼び出し元のクライアントがパブリックの場合は、エラーで中止されます。
FacebookやGoogleなどが提供するソーシャル・トークンをレルム・トークンと交換することが可能です。これらのソーシャル・ウェブサイト上で偽のアカウントを作成するのが難しくないため、交換するトークンで何ができるのかを注意して自警してください。デフォルトのロール、グループ、およびアイデンティティー・プロバイダーのマッパーを使用して、外部ソーシャル・ユーザーに割り当てられる属性とロールを制御します。
ダイレクト・ネイキッド交換は非常に危険です。呼び出し元のクライアントに対して、クライアントのクレデンシャルが漏洩しないということを非常に信頼しています。これらのクレデンシャルが漏洩した場合、攻撃者はシステム内の誰かに偽装する可能性があります。これは、既存のトークンを持つコンフィデンシャル・クライアントとはまったく対照的です。2要素の認証(アクセストークンとクライアントのクレデンシャル)がありますが、1ユーザーしか扱っていません。したがって、ダイレクト・ネイキッド交換は控えめに使用してください。