セキュリティーのテスト
このドキュメントでは、Quarkus Security のテスト方法について説明します。
ユーザー情報の設定
セキュリティーのテストには quarkus-elytron-security-properties-file を使用できます。これは、 application.properties へのユーザー情報の埋め込みと、スタンドアロンのプロパティーファイルの両方をサポートしています。
たとえば、以下の設定では、設定プロファイル を使用して、OAuth2 が必要な本番モードと開発モードの両方でユーザーを設定できます。
# Configure embedded authentication
%dev.quarkus.security.users.embedded.enabled=true
%dev.quarkus.security.users.embedded.plain-text=true
%dev.quarkus.security.users.embedded.users.scott=reader
%dev.quarkus.security.users.embedded.users.stuart=writer
%dev.quarkus.security.users.embedded.roles.scott=READER
%dev.quarkus.security.users.embedded.roles.stuart=READER,WRITER
# Configure OAuth2
quarkus.oauth2.enabled=true
%dev.quarkus.oauth2.enabled=false
quarkus.oauth2.client-id=client-id
quarkus.oauth2.client-secret=client-secret
quarkus.oauth2.introspection-url=http://host:port/introspect
セキュリティーエクステンションのテスト
Quarkus は、異なるユーザーでのテストや、セキュリティーサブシステムを無効にした状態でのテストを明示的にサポートしています。これを使用するには、 quarkus-test-security の依存関係を含める必要があります。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.quarkus:quarkus-test-security")
このアーティファクトは io.quarkus.test.security.TestSecurity アノテーションを提供します。これをテストメソッドやテストクラスに適用することで、テストが実行されるセキュリティーコンテキストを制御できます。これにより、2つのことができます。認証を無効にして、テストが認証なしで保護されたエンドポイントにアクセスできるようにしたり、テストを実行する際の ID を指定したりすることができます。
認可が無効な状態で実行されるテストでは、enabled プロパティーを false に設定するだけです。
@Test
@TestSecurity(authorizationEnabled = false)
void someTestMethod() {
...
}
これにより、すべてのアクセスチェックが無効になり、テストは認証を必要とせずに保護されたエンドポイントにアクセスできるようになります。
これを使用して、テストを実行する現在のユーザーを設定することもできます。
@Test
@TestSecurity(user = "testUser", roles = {"admin", "user"})
void someTestMethod() {
...
}
これは、指定されたユーザー名とロールを持つ ID でテストを実行します。これらを組み合わせることができるため、認証を無効にしながらテストを実行するための ID を提供することも可能です。これは、エンドポイントが ID の存在を期待する場合に役立つことがあります。
注入された JsonWebToken に依存するエンドポイントコードのテストの詳細は、OpenID Connect ベアラートークン結合テスト、OpenID Connect 認可コードフロー結合テスト、および SmallRye JWT 結合テスト を参照してください。
さらに、ID の属性、たとえば ID オーグメンテーションで追加されたカスタム項目を指定することもできます。
@Inject
SecurityIdentity identity;
@Test
@TestSecurity(
user = "testUser",
roles = {"admin", "user"},
attributes = { @SecurityAttribute(key = "answer", value = "42", type = AttributeType.LONG) })
void someTestMethod() {
Long answer = identity.<Long>getAttribute("answer");
...
}
これにより、answer という名前の Long 型の属性を持つ ID を使用してテストが実行されます。
|
この機能は |
|
これは、同じセキュリティー設定のセットを複数のテストメソッドで使用する必要がある場合に特に便利です。 |
@TestSecurity アノテーションは @PermissionsAllowed セキュリティーアノテーションでも機能します。
次の例を考えてみましょう。
@Test
@TestSecurity(user = "testUser", permissions = "see:detail")
void someTestMethod() {
...
}
これにより、権限が see でアクションが detail の ID を持つテストが実行されます。
その結果、以下の例で宣言されている getDetail メソッドの呼び出しは成功します。
@PermissionsAllowed("see:detail")
public String getDetail() {
return "detail";
}
以下の例のようにカスタム権限を設定することも可能です。
@PermissionsAllowed("see", permission = CustomPermission.class)
public String getDetail() {
return "detail";
}
CustomPermission は、SecurityIdentityAugmentor CDI Bean を使用した @TestSecurity アノテーションによって作成された SecurityIdentity に付与する必要があります。
@ApplicationScoped
public class CustomSecurityIdentityAugmentor implements SecurityIdentityAugmentor {
@Override
public Uni<SecurityIdentity> augment(SecurityIdentity securityIdentity,
AuthenticationRequestContext authenticationRequestContext) {
final SecurityIdentity augmentedIdentity;
if (shouldGrantCustomPermission(securityIdentity) {
augmentedIdentity = QuarkusSecurityIdentity.builder(securityIdentity)
.addPermission(new CustomPermission("see")).build();
} else {
augmentedIdentity = securityIdentity;
}
return Uni.createFrom().item(augmentedIdentity);
}
}
Quarkus は、@TestSecurity#augmentors アノテーション属性を次のように CustomSecurityIdentityAugmentor.class に設定した場合にのみ、@TestSecurity アノテーションで作成された SecurityIdentity を拡張します。
@Test
@TestSecurity(user = "testUser", permissions = "see:detail", augmentors = CustomSecurityIdentityAugmentor.class)
void someTestMethod() {
...
}
セキュリティーテストの混合
@TestSecurity と Basic 認証 (何も定義されていない場合のフォールバック認証メカニズム) の両方を使用してセキュリティー機能をテストする必要が生じた場合、Basic 認証を明示的に有効にする必要があります。
たとえば、quarkus.http.auth.basic=true または %test.quarkus.http.auth.basic=true を設定します。
同様に、@TestSecurity とベアラートークン認証の両方を使用してセキュリティー機能をテストする必要がある場合、
以下の例のように両方を活用できます。
@Test
@TestSecurity(user = "Bob")
public void testSecurityMetaAnnotation {
RestAssured.given()
.auth().oauth2(getTokenForUser("Alice")) (1)
.get("hello")
.then()
.statusCode(200)
.body(Matchers.is("Hello Alice"));
RestAssured.given()
.get("hello")
.then()
.statusCode(200)
.body(Matchers.is("Hello Bob")); (2)
}
@Path("hello")
public static class HelloResource {
@Inject
SecurityIdentity identity;
@Authenticated
@GET
public String sayHello() {
return "Hello " + identity.getPrincipal().getName();
}
}
| 1 | ベアラーアクセストークンが HTTP リクエストとともに送信されるため、ベアラートークン認証メカニズムが使用されます。 |
| 2 | 認証ヘッダーが存在しないため、テストセキュリティーエクステンションによってユーザー Bob が作成されます。 |
パスベースの認証
@TestSecurity は、認証メカニズムを組み合わせる必要がある 場合にも使用できます。
以下の例は、パスベースの認証が有効な場合に認証メカニズムを選択する方法を示しています。
@Test
@TestSecurity(user = "testUser", roles = {"admin", "user"}, authMechanism = "basic") (1)
void basicTestMethod() {
...
}
@Test
@TestSecurity(user = "testUser", roles = {"admin", "user"}, authMechanism = "form") (2)
void formTestMethod() {
...
}
| 1 | 'authMechanism' 属性は Basic 認証を選択します。 |
| 2 | 'authMechanism' 属性はフォームベースの認証を選択します。 |
Quarkus アプリケーションでは、アノテーションを使用して、各 Jakarta REST エンドポイントに固有の認証メカニズムを選択できます。
package org.acme.security.testing;
import io.quarkus.vertx.http.runtime.security.annotation.BasicAuthentication;
import io.quarkus.vertx.http.runtime.security.annotation.FormAuthentication;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/")
public class TestSecurityResource {
@BasicAuthentication (1)
@GET
@Path("basic-only")
public String basicOnly() {
return "basic-only";
}
@FormAuthentication (2)
@GET
@Path("form-only")
public String formOnly() {
return "form-only";
}
}
| 1 | basicTestMethod テストからの /basic-only パスへのすべての HTTP リクエストが正常に認証されます。 |
| 2 | Basic 認証が必要なため、formTestMethod テストから呼び出された場合、同じ HTTP リクエストは失敗します。 |
または、HTTP セキュリティーポリシーを使用してパス固有の認証メカニズムを選択することもできます。
# require basic authentication for the '/basic-only' path
quarkus.http.auth.permission.basic.paths=/basic-only
quarkus.http.auth.permission.basic.policy=authenticated
quarkus.http.auth.permission.basic.auth-mechanism=basic
# require form-based authentication for the '/form-only' path
quarkus.http.auth.permission.form.paths=/form-only
quarkus.http.auth.permission.form.policy=authenticated
quarkus.http.auth.permission.form.auth-mechanism=form
最後に、上記の Wiremock セクションで説明されているのと同じ方法でテストコードを記述します。
唯一の違いは、@QuarkusTestResource が不要になったことです。
Wiremock を使用して認可 OAuth2 および OIDC サービスをモックすることもできます。 詳細は OAuth2 結合テスト、OpenID Connect ベアラートークン結合テスト、OpenID Connect 認可コードフロー結合テスト、および SmallRye JWT 結合テスト を参照してください。