第1章 OpenID Connect (OIDC) ベアラートークン認証
Quarkus OpenID Connect (OIDC) エクステンションを使用して、ベアラートークン認証により、アプリケーション内の Jakarta REST (旧称 JAX-RS) エンドポイントへの HTTP アクセスを保護します。
1.1. Quarkus のベアラートークン認証メカニズムの概要 リンクのコピーリンクがクリップボードにコピーされました!
Quarkus は、Quarkus OpenID Connect (OIDC) エクステンションを通じて、ベアラートークン認証メカニズムをサポートします。
ベアラートークンは、OIDC と、Keycloak などの OAuth 2.0 準拠の認可サーバーによって発行されます。
ベアラートークン認証は、ベアラートークンの存在と有効性に基づいて HTTP リクエストを承認するプロセスです。ベアラートークンは、呼び出しのサブジェクトに関する情報を提供します。これは、HTTP リソースにアクセスできるかどうかを判断するために使用されます。
次の図は、Quarkus のベアラートークン認証メカニズムの概要を示しています。
図1.1 シングルページアプリケーションを使用した Quarkus のベアラートークン認証メカニズム
- Quarkus サービスは、OIDC プロバイダーから検証キーを取得します。検証キーは、ベアラーアクセストークンの署名を検証するために使用されます。
- Quarkus ユーザーは、シングルページアプリケーション (SPA) にアクセスします。
- 単一ページアプリケーションは、Authorization Code Flow を使用してユーザーを認証し、OIDC プロバイダーからトークンを取得します。
- シングルページアプリケーションは、アクセストークンを使用して、Quarkus サービスからサービスデータを取得します。
- Quarkus サービスは、検証キーを使用してベアラーアクセストークンの署名を検証し、トークンの有効期限やその他のリクエストをチェックします。トークンが有効な場合はリクエストを続行できるようにし、シングルページアプリケーションにサービス応答を返します。
- シングルページアプリケーションは、Quarkus ユーザーに同じデータを返します。
図1.2 Java またはコマンドラインクライアントを使用した Quarkus のベアラートークン認証メカニズム
- Quarkus サービスは、OIDC プロバイダーから検証キーを取得します。検証キーは、ベアラーアクセストークンの署名を検証するために使用されます。
-
クライアントが、
client_credentialsかパスワードグラントを使用して、OIDC プロバイダーからアクセストークンを取得します。client_credentials には、クライアント ID とシークレットが必要です。パスワードグラントには、クライアント ID、シークレット、ユーザー名、およびパスワードが必要です。 - クライアントはアクセストークンを使用して、Quarkus サービスからサービスデータを取得します。
- Quarkus サービスは、検証キーを使用してベアラーアクセストークンの署名を検証し、トークンの有効期限やその他のクレームをチェックして、トークンが有効な場合はリクエストの続行を許可し、サービスレスポンスをクライアントに返します。
OIDC 認可コードフローを使用してユーザーを認証および認可する必要がある場合は、Quarkus の Web アプリケーションを保護するための OpenID Connect 認可コードフローメカニズム ガイドを参照してください。また、Keycloak およびベアラートークンを使用する場合は、Quarkus の Keycloak を使用して認証を一元化する ガイドを参照してください。
OIDC ベアラートークン認証を使用してサービスアプリケーションを保護する方法については、次のチュートリアルを参照してください。
複数のテナントをサポートする方法の詳細は、Quarkus の OpenID Connect マルチテナンシーの使用 ガイドを参照してください。
1.1.1. JWT クレームへのアクセス リンクのコピーリンクがクリップボードにコピーされました!
JWT トークンクレームにアクセスする必要がある場合は、JsonWebToken を注入します。
JsonWebToken の注入は、@ApplicationScoped、@Singleton、および @RequestScoped スコープでサポートされています。ただし、個々のクレームが単純な型として注入される場合は、@RequestScoped を使用する必要があります。詳細は、Quarkus の「JWT RBAC の使用」ガイドの サポートされている注入スコープ セクションを参照してください。
1.1.2. UserInfo リンクのコピーリンクがクリップボードにコピーされました!
OIDC UserInfo エンドポイントから UserInfo JSON オブジェクトをリクエストする必要がある場合は、quarkus.oidc.authentication.user-info-required=true を設定します。OIDC プロバイダーの UserInfo エンドポイントにリクエストが送信され、io.quarkus.oidc.UserInfo (単純な javax.json.JsonObject ラッパー) オブジェクトが作成されます。io.quarkus.oidc.UserInfo は、SecurityIdentity userinfo 属性として注入またはアクセスできます。
quarkus.oidc.authentication.user-info-required は、次のいずれかの条件が満たされた場合に自動的に有効になります。
-
quarkus.oidc.roles.sourceがuserinfoに設定されている場合、またはquarkus.oidc.token.verify-access-token-with-user-infoがtrueに設定されている場合、またはquarkus.oidc.authentication.id-token-requiredがfalseに設定されている場合。このような場合、現在の OIDC テナントが UserInfo エンドポイントをサポートしている必要があります。 -
io.quarkus.oidc.UserInfoインジェクションポイントが検出された場合。ただし、有効になるのは、現在の OIDC テナントが UserInfo エンドポイントをサポートしている場合だけです。
1.1.3. 設定メタデータ リンクのコピーリンクがクリップボードにコピーされました!
現在のテナントの検出された OpenID Connect 設定メタデータ は、io.quarkus.oidc.OidcConfigurationMetadata で表され、SecurityIdentity configuration-metadata 属性として注入またはアクセスできます。
エンドポイントがパブリックの場合、デフォルトのテナントの OidcConfigurationMetadata が注入されます。
1.1.4. トークンクレームと SecurityIdentity ロール リンクのコピーリンクがクリップボードにコピーされました!
検証済みの JWT アクセストークンから SecurityIdentity ロールを次のようにマップできます。
-
quarkus.oidc.roles.role-claim-pathプロパティーが設定されており、一致する配列または文字列のクレームが見つかった場合、これらのクレームからロールが展開されます。たとえば、customroles、customroles/array、scope、"http://namespace-qualified-custom-claim"/roles、"http://namespace-qualified-roles"などです。 -
groupsクレームが利用可能な場合は、その値が使用されます。 -
realm_access/rolesまたはresource_access/client_id/roles(client_idはquarkus.oidc.client-idプロパティーの値) クレームが利用可能な場合は、その値が使用されます。このチェックは、Keycloak によって発行されたトークンをサポートします。
たとえば、次の JWT トークンには、ロールを含む roles 配列のある複雑な groups クレームがあります。
microprofile_jwt_user ロールを SecurityIdentity ロールにマップする必要があります。これは、quarkus.oidc.roles.role-claim-path=groups/roles という設定で実行できます。
トークンが不透明 (バイナリー) の場合、リモートトークンイントロスペクション応答の scope プロパティーが使用されます。
UserInfo がロールのソースである場合は、quarkus.oidc.authentication.user-info-required=true および quarkus.oidc.roles.source=userinfo を設定し、必要に応じて quarkus.oidc.roles.role-claim-path を設定します。
さらに、カスタム SecurityIdentityAugmentor を使用して、ロールを追加することもできます。詳細は、Quarkus の「Security tips and tricks」ガイドの Security identity customization セクションを参照してください。
HTTP セキュリティーポリシー を使用して、トークンクレームから作成された SecurityIdentity ロールをデプロイメント固有のロールにマップすることもできます。
1.1.5. トークンスコープと SecurityIdentity 権限 リンクのコピーリンクがクリップボードにコピーされました!
SecurityIdentity 権限は、ロールのソース のスコープパラメーターから io.quarkus.security.StringPermission の形式でマッピングされ、同じクレームセパレーターが使用されます。
io.quarkus.security.PermissionsAllowed アノテーションの詳細は、「Web エンドポイントの認可」ガイドの 権限のアノテーション セクションを参照してください。
1.1.6. トークンの検証とイントロスペクション リンクのコピーリンクがクリップボードにコピーされました!
トークンが JWT トークンの場合、デフォルトでは、OIDC プロバイダーの JWK エンドポイントから取得されたローカル JsonWebKeySet の JsonWebKey (JWK) キーを使用して検証されます。トークンのキー識別子 (kid) ヘッダー値は、一致する JWK キーを見つけるために使用されます。一致する JWK がローカルで利用できない場合は、JWK エンドポイントから現在のキーセットを取得して JsonWebKeySet が更新されます。JsonWebKeySet の更新は、quarkus.oidc.token.forced-jwk-refresh-interval の有効期限が切れた後にのみ、繰り返すことができます。デフォルトの有効期限は 10 分です。更新後に一致する JWK が利用できない場合は、JWT トークンが OIDC プロバイダーのトークンイントロスペクションエンドポイントに送信されます。
トークンが不透明である場合は、それがバイナリートークンまたは暗号化された JWT トークンである可能性があり、そのトークンは常に OIDC プロバイダーのトークンイントロスペクションエンドポイントに送信されます。
JWT トークンのみを使用しており、一致する JsonWebKey が常に使用可能であることが予想される場合 (たとえば、キーセットを更新した後など)、次の例に示すように、トークンイントロスペクションを無効にする必要があります。
quarkus.oidc.token.allow-jwt-introspection=false quarkus.oidc.token.allow-opaque-token-introspection=false
quarkus.oidc.token.allow-jwt-introspection=false
quarkus.oidc.token.allow-opaque-token-introspection=false
JWT トークンをイントロスペクションのみで検証する必要がある場合があります。これは、イントロスペクションエンドポイントアドレスのみを設定することで強制できます。次のプロパティー設定は、Keycloak を使用してこれを実現する方法の例を示しています。
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus quarkus.oidc.discovery-enabled=false # Token Introspection endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/tokens/introspect quarkus.oidc.introspection-path=/protocol/openid-connect/tokens/introspect
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.discovery-enabled=false
# Token Introspection endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/tokens/introspect
quarkus.oidc.introspection-path=/protocol/openid-connect/tokens/introspect
JWT トークンのイントロスペクションをリモートで間接的に実施することには、利点と欠点があります。利点は、2 つのリモート呼び出し (リモート OIDC メタデータ検出呼び出しと、それに続く使用されない検証キーを取得するための別のリモート呼び出し) が不要になることです。欠点は、イントロスペクションエンドポイントアドレスを知って、手動で設定する必要があることです。
この他にも、OIDC メタデータ検出のデフォルトオプションを許可しながら、リモート JWT イントロスペクションのみの実行を要求する方法があります (次の例を参照)。
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus quarkus.oidc.token.require-jwt-introspection-only=true
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.token.require-jwt-introspection-only=true
このアプローチの利点は、設定がよりシンプルで理解しやすいことです。欠点は、検証キーが取得されない場合でも、イントロスペクションエンドポイントアドレスを検出するためにリモート OIDC メタデータ検出呼び出しが必要になることです。
シンプルな jakarta.json.JsonObject ラッパーオブジェクトである io.quarkus.oidc.TokenIntrospection が作成されます。JWT または不透明トークンのいずれかが正常にイントロスペクトされている場合、SecurityIdentity introspection 属性として注入またはアクセスできます。
1.1.7. トークンイントロスペクションと UserInfo キャッシュ リンクのコピーリンクがクリップボードにコピーされました!
すべての不透明アクセストークンは、リモートでイントロスペクトする必要があります。場合によっては、JWT アクセストークンをイントロスペクトする必要もあります。UserInfo も必要な場合は、OIDC プロバイダーへの後続のリモート呼び出しで同じアクセストークンが使用されます。したがって、UserInfo が必要で、現在のアクセストークンが不透明である場合、そのようなトークンごとに 2 つのリモート呼び出しが行われます。1 つのリモート呼び出しはトークンをイントロスペクトするためのもので、もう 1 つは UserInfo を取得するためのものです。トークンが JWT の場合、イントロスペクトもされている必要がない限り、UserInfo を取得するためのリモート呼び出しは 1 回だけ必要です。
着信ベアラーまたはコードフローアクセストークンごとに最大 2 回のリモート呼び出しを実行するコストが問題になる場合があります。
実稼働環境でこれが当てはまる場合は、トークンイントロスペクションと UserInfo データを 3 分または 5 分などの短期間キャッシュすることを検討してください。
quarkus-oidc は、@ApplicationScoped キャッシュ実装に使用できる quarkus.oidc.TokenIntrospectionCache および quarkus.oidc.UserInfoCache インターフェイスを提供します。次の例に示すように、@ApplicationScoped キャッシュ実装を使用して、quarkus.oidc.TokenIntrospection オブジェクトや quarkus.oidc.UserInfo オブジェクトを保存および取得します。
各 OIDC テナントは、quarkus.oidc.TokenIntrospection データ、quarkus.oidc.UserInfo データ、またはその両方の保存を許可または拒否できます。これには、ブール値 quarkus.oidc."tenant".allow-token-introspection-cache および quarkus.oidc."tenant".allow-user-info-cache プロパティーを使用します。
さらに、quarkus-oidc は quarkus.oidc.TokenIntrospectionCache と quarkus.oidc.UserInfoCache の両方のインターフェイスを実装する、シンプルなデフォルトのメモリーベースのトークンキャッシュを提供します。
デフォルトの OIDC トークンキャッシュは、次のように設定してアクティブ化できます。
デフォルトのキャッシュはトークンをキーとして使用し、各エントリーには TokenIntrospection、UserInfo、またはその両方を含めることができます。max-size のエントリー数までのみが保持されます。新しいエントリーを追加するときにキャッシュがすでにいっぱいになっている場合は、期限切れのエントリーを 1 つ削除してスペースを見つけようとします。さらに、クリーンアップタイマーをアクティベートにすると、期限切れのエントリーが定期的にチェックされ、削除されます。
デフォルトのキャッシュ実装を試したり、カスタムのキャッシュ実装を登録したりできます。
1.1.8. JSON Web Token のクレームの検証 リンクのコピーリンクがクリップボードにコピーされました!
ベアラー JWT トークンの署名が検証され、その expires at (exp) クレームがチェックされた後、次に iss (issuer) クレーム値が検証されます。
デフォルトでは、iss クレーム値は、周知のプロバイダー設定で検出された可能性のある issuer プロパティーと比較されます。ただし、quarkus.oidc.token.issuer プロパティーが設定されている場合は、代わりに iss クレーム値がそれと比較されます。
場合によっては、この ISS クレーム検証が機能しないことがあります。たとえば、検出された issuer プロパティーに内部 HTTP/IP アドレスが含まれているのに、トークンの iss クレーム値に外部 HTTP/IP アドレスが含まれている場合などです。または、検出された issuer プロパティーにテンプレートテナント変数が含まれているが、トークンの iss クレーム値には完全なテナント固有の発行者値が含まれている場合などです。
このような場合は、quarkus.oidc.token.issuer=any を設定して発行者の検証をスキップすることを検討してください。他のオプションが利用できない場合にのみ、発行者の検証をスキップします。
-
Keycloak を使用しており、異なるホストアドレスによって発行者検証エラーが発生する場合は、
KEYCLOAK_FRONTEND_URLプロパティーを使用して Keycloak を設定し、同じホストアドレスが使用されるようにします。 -
マルチテナントデプロイメントで
issプロパティーがテナント固有である場合は、SecurityIdentitytenant-id属性を使用して、エンドポイントまたはカスタム Jakarta フィルターで発行者が正しいことを確認します。以下に例を示します。
quarkus.oidc.token.audience プロパティーを使用して、トークン aud (audience) クレーム値を検証することを検討してください。
1.1.9. Jose4j Validator リンクのコピーリンクがクリップボードにコピーされました!
org.eclipse.microprofile.jwt.JsonWebToken が初期化される前に、カスタムの Jose4j Validator を登録して、JWT クレーム検証プロセスをカスタマイズできます。以下に例を示します。
カスタム Validator を特定の OIDC テナントにのみバインドするには、@quarkus.oidc.TenantFeature アノテーションを使用します。
1.1.10. Cross-Origin Resource Sharing リンクのコピーリンクがクリップボードにコピーされました!
別のドメインで実行されているシングルページアプリケーションから OIDC サービス アプリケーションを使用する予定の場合は、Cross-Origin Resource Sharing (CORS) を設定する必要があります。詳細は、「クロスオリジンリソース共有」ガイドの CORS フィルター セクションを参照してください。
1.1.11. プロバイダーエンドポイントの設定 リンクのコピーリンクがクリップボードにコピーされました!
OIDC service アプリケーションは、OIDC プロバイダーのトークン、JsonWebKey (JWK) セット、そして場合によっては UserInfo およびイントロスペクションエンドポイントアドレスを認識している必要があります。
デフォルトでは、設定された quarkus.oidc.auth-server-url に /.well-known/openid-configuration パスを追加することによって検出されます。
あるいは、検出エンドポイントが利用できない場合、または検出エンドポイントのラウンドトリップを節約したい場合は、検出を無効にして、相対パス値で設定することができます。以下に例を示します。
1.1.12. トークンの伝播 リンクのコピーリンクがクリップボードにコピーされました!
ダウンストリームサービスへのベアラーアクセストークンの伝播に関する詳細は、Quarkus の「OpenID Connect (OIDC) と OAuth2 クライアントおよびフィルターのリファレンス」ガイドの トークンの伝播 セクションを参照してください。
1.1.13. JWT トークン証明書チェーン リンクのコピーリンクがクリップボードにコピーされました!
場合によっては、JWT ベアラートークンには x5c ヘッダーがあります。このヘッダーは X509 証明書チェーンを表します。この証明書チェーンのリーフ証明書には、このトークンの署名を検証するために使用する必要がある公開鍵が含まれています。この公開鍵を受け入れて署名を検証する前に、まず証明書チェーンを検証する必要があります。証明書チェーンの検証には、次のようにいくつかのステップがあります。
- ルート証明書以外のすべての証明書が親証明書によって署名されていることを確認します。
- チェーンのルート証明書もトラストストアにインポートされていることを確認します。
-
チェーンのリーフ証明書を検証します。リーフ証明書のコモンネームが設定されている場合、チェーンのリーフ証明書のコモンネームがそれに一致する必要があります。設定されていない場合、1 つ以上のカスタムの
TokenCertificateValidator実装が登録されていない限り、チェーンのリーフ証明書もトラストストアで使用可能である必要があります。 -
quarkus.oidc.TokenCertificateValidatorを使用すると、カスタムの証明書チェーン検証ステップを追加できます。これは、証明書チェーンを持つトークンを要求するすべてのテナント、または@quarkus.oidc.TenantFeatureアノテーションを使用して特定の OIDC テナントにバインドされたすべてのテナントで使用できます。
たとえば、quarkus.oidc.TokenCertificateValidator を使用せずにトークンの証明書チェーンを検証するように Quarkus OIDC を設定する方法は次のとおりです。
quarkus.oidc.certificate-chain.trust-store-file=truststore-rootcert.p12 quarkus.oidc.certificate-chain.trust-store-password=storepassword quarkus.oidc.certificate-chain.leaf-certificate-name=www.quarkusio.com
quarkus.oidc.certificate-chain.trust-store-file=truststore-rootcert.p12
quarkus.oidc.certificate-chain.trust-store-password=storepassword
quarkus.oidc.certificate-chain.leaf-certificate-name=www.quarkusio.com
カスタムの quarkus.oidc.TokenCertificateValidator を登録することで、カスタムの証明書チェーン検証ステップを追加できます。次に例を示します。
- 1
- 証明書チェーンのルート証明書がカスタム JWT トークンのクレームにバインドされていることを確認します。
1.1.14. OIDC プロバイダークライアント認証 リンクのコピーリンクがクリップボードにコピーされました!
quarkus.oidc.runtime.OidcProviderClient は、OIDC プロバイダーへのリモートリクエストが必要な場合に使用されます。ベアラートークンのイントロスペクションが必要な場合は、OidcProviderClient が OIDC プロバイダーに対して認証する必要があります。サポートされている認証オプションの詳細は、Quarkus の「Web アプリケーションを保護するための OpenID Connect 認可コードフローメカニズム」ガイドの OIDC プロバイダークライアント認証 セクションを参照してください。
1.1.15. テスト リンクのコピーリンクがクリップボードにコピーされました!
Keycloak 認証 を必要とする Quarkus OIDC サービスエンドポイントをテストする必要がある場合は、Keycloak 認可のテスト セクションに従ってください。
次の依存関係をテストプロジェクトに追加することで、テストを開始できます。
Maven を使用:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Gradle を使用:
testImplementation("io.rest-assured:rest-assured") testImplementation("io.quarkus:quarkus-junit5")testImplementation("io.rest-assured:rest-assured") testImplementation("io.quarkus:quarkus-junit5")Copy to Clipboard Copied! Toggle word wrap Toggle overflow
1.1.15.1. WireMock リンクのコピーリンクがクリップボードにコピーされました!
テストプロジェクトに次の依存関係を追加します。
Maven を使用:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-test-oidc-server</artifactId> <scope>test</scope> </dependency><dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-test-oidc-server</artifactId> <scope>test</scope> </dependency>Copy to Clipboard Copied! Toggle word wrap Toggle overflow Gradle を使用:
testImplementation("io.quarkus:quarkus-test-oidc-server")testImplementation("io.quarkus:quarkus-test-oidc-server")Copy to Clipboard Copied! Toggle word wrap Toggle overflow
REST テストエンドポイントを準備し、application.properties を設定します。以下に例を示します。
keycloak.url is set by OidcWiremockTestResource
quarkus.oidc.auth-server-url=${keycloak.url:replaced-by-test-resource}/realms/quarkus/
quarkus.oidc.client-id=quarkus-service-app
quarkus.oidc.application-type=service
# keycloak.url is set by OidcWiremockTestResource
quarkus.oidc.auth-server-url=${keycloak.url:replaced-by-test-resource}/realms/quarkus/
quarkus.oidc.client-id=quarkus-service-app
quarkus.oidc.application-type=service
最後にテストコードを記述します。以下に例を示します。
quarkus-test-oidc-server エクステンションには、JSON Web Key (JWK) 形式の署名 RSA 秘密鍵ファイルが含まれており、smallrye.jwt.sign.key.location 設定プロパティーでそのファイルを指します。引数なしの sign() 操作を使用してトークンに署名できます。
OidcWiremockTestResource を使用して quarkus-oidc service アプリケーションをテストすると、通信チャネルも WireMock HTTP スタブに対してテストされるため、最高のカバレッジが提供されます。OidcWiremockTestResource でまだサポートされていない WireMock スタブを使用してテストを実行する必要がある場合は、次の例に示すように、テストクラスに WireMockServer インスタンスを注入できます。
OidcWiremockTestResource は、Docker コンテナーに対して @QuarkusIntegrationTest では機能しません。これは、WireMock サーバーがテストを実行する JVM で実行され、Quarkus アプリケーションを実行する Docker コンテナーからはアクセスできないためです。
1.1.16. OidcTestClient リンクのコピーリンクがクリップボードにコピーされました!
Auth0 などの SaaS OIDC プロバイダーを使用していて、テスト (開発) ドメインに対してテストを実行したり、リモート Keycloak テストレルムに対してテストを実行したりする場合、quarkus.oidc.auth-server-url がすでに設定されている場合は、OidcTestClient を使用できます。
たとえば、次のような設定があるとします。
%test.quarkus.oidc.auth-server-url=https://dev-123456.eu.auth0.com/ %test.quarkus.oidc.client-id=test-auth0-client %test.quarkus.oidc.credentials.secret=secret
%test.quarkus.oidc.auth-server-url=https://dev-123456.eu.auth0.com/
%test.quarkus.oidc.client-id=test-auth0-client
%test.quarkus.oidc.credentials.secret=secret
まず、WireMock セクションで説明されているものと同じ依存関係 quarkus-test-oidc-server を追加します。
次に、次のようにテストコードを記述します。
このテストコードは、クライアント ID test-auth0-client でアプリケーションを登録し、パスワード alice でユーザー alice を作成したテスト Auth0 ドメインから password 付与を使用してトークンを取得します。このようなテストが機能するには、テスト Auth0 アプリケーションで password 付与が有効になっている必要があります。このサンプルコードでは、追加のパラメーターを渡す方法も示しています。Auth0 の場合、これらは audience と scope パラメーターです。
1.1.16.1. Dev Services for Keycloak リンクのコピーリンクがクリップボードにコピーされました!
Keycloak に対する結合テストを行う際に推奨される手法は、Dev Services for Keycloak です。Dev Services for Keycloak が起動し、テストコンテナーを初期化します。次に、quarkus レルムと quarkus-app クライアント (secret シークレット) を作成し、alice (admin および user ロール) および bob (user ロール) ユーザーを追加します。これらのプロパティーはすべてカスタマイズできます。
まず、アクセストークンを取得するためのテストで使用できるユーティリティークラス io.quarkus.test.keycloak.client.KeycloakTestClient を提供する次の依存関係を追加します。
Maven を使用:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-test-keycloak-server</artifactId> <scope>test</scope> </dependency><dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-test-keycloak-server</artifactId> <scope>test</scope> </dependency>Copy to Clipboard Copied! Toggle word wrap Toggle overflow Gradle を使用:
testImplementation("io.quarkus:quarkus-test-keycloak-server")testImplementation("io.quarkus:quarkus-test-keycloak-server")Copy to Clipboard Copied! Toggle word wrap Toggle overflow
次に、application.properties 設定ファイルを準備します。Dev Services for Keycloak は quarkus.oidc.auth-server-url を登録し、それを実行中のテストコンテナー quarkus.oidc.client-id=quarkus-app および quarkus.oidc.credentials.secret=secret を指すため、空の application.properties ファイルから開始できます。
ただし、必要な quarkus-oidc プロパティーをすでに設定している場合は、次の例に示すように、quarkus.oidc.auth-server-url を `Dev Services for Keycloak` の prod プロファイルに関連付けるだけでコンテナーを起動できます。
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
テストを実行する前にカスタムレルムファイルを Keycloak にインポートする必要がある場合は、次のように Dev Services for Keycloak を設定します。
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus quarkus.keycloak.devservices.realm-path=quarkus-realm.json
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.keycloak.devservices.realm-path=quarkus-realm.json
最後に、次の例に示すように、JVM モードで実行されるテストを記述します。
JVM モードで実行されたテストの例:
ネイティブモードで実行されたテストの例:
Dev Services for Keycloak の初期化と設定の詳細は、Dev Services for Keycloak ガイドを参照してください。
1.1.16.2. ローカル公開鍵 リンクのコピーリンクがクリップボードにコピーされました!
次の例に示すように、ローカルのインライン公開鍵を使用して quarkus-oidc service アプリケーションをテストできます。
quarkus.oidc.client-id=test quarkus.oidc.public-key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9xnQIDAQAB smallrye.jwt.sign.key.location=/privateKey.pem
quarkus.oidc.client-id=test
quarkus.oidc.public-key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9xnQIDAQAB
smallrye.jwt.sign.key.location=/privateKey.pem
JWT トークンを生成するには、main Quarkus リポジトリーの integration-tests/oidc-tenancy から privateKey.pem をコピーし、前の WireMock セクションのものと同様のテストコードを使用します。必要に応じて、独自のテストキーを使用することもできます。
このアプローチでは、WireMock アプローチと比較してカバレッジが制限されます。たとえば、リモート通信コードはカバーされません。
1.1.16.3. TestSecurity アノテーション リンクのコピーリンクがクリップボードにコピーされました!
@TestSecurity および @OidcSecurity アノテーションを使用して、次のインジェクションのいずれか 1 つまたは 3 つすべてに依存する service アプリケーションエンドポイントコードをテストできます。
-
JsonWebToken -
UserInfo -
OidcConfigurationMetadata
まず、次の依存関係を追加します。
Maven を使用:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-test-security-oidc</artifactId> <scope>test</scope> </dependency><dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-test-security-oidc</artifactId> <scope>test</scope> </dependency>Copy to Clipboard Copied! Toggle word wrap Toggle overflow Gradle を使用:
testImplementation("io.quarkus:quarkus-test-security-oidc")testImplementation("io.quarkus:quarkus-test-security-oidc")Copy to Clipboard Copied! Toggle word wrap Toggle overflow
次の例に示すようにテストコードを記述します。
このコード例で使用されている ProtectedResource クラスは、次のようになります。
常に @TestSecurity アノテーションを使用する必要があります。その user プロパティーは JsonWebToken.getName() として返され、その roles プロパティーは JsonWebToken.getGroups() として返されます。@OidcSecurity アノテーションは任意です。これを使用すると、追加のトークンクレームと UserInfo および OidcConfigurationMetadata プロパティーを設定できます。さらに、quarkus.oidc.token.issuer プロパティーが設定されている場合は、OidcConfigurationMetadata issuer プロパティー値として使用されます。
不透明なトークンを使用する場合は、次のコード例に示すようにテストできます。
このコード例で使用されている ProtectedResource クラスは、次のようになります。
@TestSecurity、user、および roles 属性は、TokenIntrospection、username、および scope プロパティーとして使用できます。io.quarkus.test.security.oidc.TokenIntrospection を使用して、email などの追加のイントロスペクション応答プロパティーを追加します。
@TestSecurity と @OidcSecurity は、次の例に示すように、メタアノテーションで組み合わせることができます。
これは、複数のテスト方法で同じセキュリティー設定セットを使用する必要がある場合に特に便利です。
1.1.17. ログエラーの確認 リンクのコピーリンクがクリップボードにコピーされました!
トークン検証エラーの詳細を確認するには、io.quarkus.oidc.runtime.OidcProvider と TRACE レベルのロギングを有効にします。
quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".level=TRACE quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".min-level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".min-level=TRACE
OidcProvider クライアント初期化エラーの詳細を確認するには、次のように io.quarkus.oidc.runtime.OidcRecorder と TRACE レベルのロギングを有効にします。
quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".level=TRACE quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".min-level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".min-level=TRACE
1.1.18. OIDC プロバイダーへの外部および内部アクセス リンクのコピーリンクがクリップボードにコピーされました!
OIDC プロバイダーおよびその他のエンドポイントの外部アクセス可能なトークンは、quarkus.oidc.auth-server-url 内部 URL を基準として自動検出された URL または設定された URL とは異なる HTTP(S) URL を持つ場合があります。たとえば、SPA が外部トークンエンドポイントアドレスからトークンを取得し、それをベアラートークンとして Quarkus に送信するとします。その場合、エンドポイントは発行者の検証の失敗を報告する可能性があります。
このような場合、Keycloak を使用する場合は、KEYCLOAK_FRONTEND_URL システムプロパティーを外部からアクセス可能なベース URL に設定して起動します。他の OIDC プロバイダーを使用する場合は、プロバイダーのドキュメントを参照してください。
1.1.19. client-id プロパティーの使用 リンクのコピーリンクがクリップボードにコピーされました!
quarkus.oidc.client-id プロパティーは、現在のベアラートークンをリクエストした OIDC クライアントを識別します。OIDC クライアントは、ブラウザーで実行される SPA アプリケーション、または Quarkus service アプリケーションにアクセストークンを伝播する Quarkus web-app の機密クライアントアプリケーションです。
service アプリケーションがトークンをリモートでイントロスペクトすることが予想される場合、このプロパティーは必須です。これは、不透明トークンの場合は常に該当します。このプロパティーは、ローカル JSON Web Token (JWT) 検証の場合のみのオプションです。
エンドポイントがリモートイントロスペクションエンドポイントへのアクセスを必要としない場合でも、quarkus.oidc.client-id プロパティーを設定することを推奨します。これは、client-id が設定されている場合、それを使用してトークン audience を検証できるためです。また、トークンの検証が失敗した場合にもログに含まれるため、特定のクライアントに発行されたトークンの追跡可能性が向上し、より長い期間にわたる分析が可能になります。
たとえば、OIDC プロバイダーがトークン audience を設定する場合は、次の設定パターンを検討してください。
# Set client-id
quarkus.oidc.client-id=quarkus-app
# Token audience claim must contain 'quarkus-app'
quarkus.oidc.token.audience=${quarkus.oidc.client-id}
# Set client-id
quarkus.oidc.client-id=quarkus-app
# Token audience claim must contain 'quarkus-app'
quarkus.oidc.token.audience=${quarkus.oidc.client-id}
quarkus.oidc.client-id を設定したが、エンドポイントが OIDC プロバイダーエンドポイントの 1 つへのリモートアクセスを必要としない場合 (イントロスペクション、トークンの取得など) は、quarkus.oidc.credentials または同様のプロパティーを使用してクライアントシークレットを設定しないでください (このプロパティーは使用されないため)。
Quarkus web-app アプリケーションには常に quarkus.oidc.client-id プロパティーが必要です。