The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

ウェブエンドポイントの認可

Quarkus has an integrated pluggable web security layer. If security is enabled, all HTTP requests will have a permission check performed to make sure they are allowed to continue. This means you cannot use @PermitAll to open a path if the path is blocked by the quarkus.http.auth. configuration.

If you are using JAX-RS, consider using quarkus.security.jaxrs.deny-unannotated-endpoints or quarkus.security.jaxrs.default-roles-allowed to set default security requirements instead of HTTP path-level matching because annotations can override these properties on an individual endpoint.

認可は、セキュリティ・プロバイダーが提供するユーザー・ロールに基づきます。これらのロールをカスタマイズするには、 SecurityIdentityAugmentor を作成することができます。 セキュリティ・アイデンティティのカスタマイズ を参照してください。

設定を利用した認可

Quarkusの設定では、パーミッション・セットを使用してパーミッションが定義され、各パーミッション・セットはアクセス制御のポリシーを指定します。

Table 1. Quarkus ポリシーサマリー

組込ポリシー

説明

deny

このポリシーは、すべてのユーザーを拒否します。

permit

このポリシーは、すべてのユーザーを許可します。

authenticated

このポリシーは、認証されたユーザーのみを許可します。

指定したロールを持つユーザーにリソースへのアクセスを許可するロールベースのポリシーを定義することができます。

ロールベースポリシーの例
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin                  (1)
1 This defines a role-based policy that allows users with the user and admin roles. Such a custom policy can be referenced by permission sets just like the built-in ones, as shown in the example below.

パーミッションセットは、 application.properties に以下のように定義されています:

ポリシーの設定例
quarkus.http.auth.permission.permit1.paths=/public/*                            (1)
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET

quarkus.http.auth.permission.deny1.paths=/forbidden                             (2)
quarkus.http.auth.permission.deny1.policy=deny

quarkus.http.auth.permission.roles1.paths=/roles-secured/*,/other/*,/api/*      (3)
quarkus.http.auth.permission.roles1.policy=role-policy1
1 This permission references the default permit built-in policy to allow GET methods to /public. In this case, the demonstrated setting would not affect this example because this request is allowed anyway.
2 このパーミッションは /forbidden に対する組み込みの deny ポリシーを参照します。これは * で終わらないので、完全なパスマッチとなります。
3 This is a permission set that references the previously defined policy. roles1 is an example name; you can call the permission sets whatever you want.

パスとメソッドのマッチング

Permission sets can also specify paths and methods as a comma-separated list. If a path ends with the * wildcard, the query it generates matches all sub-paths. Otherwise, it queries for an exact match and will only match that specific path:

quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD

パスはマッチするがメソッドはマッチしない場合

リクエストがパスに基づいて1つ以上のパーミッションセットにマッチするが、 メソッドの要件によりマッチしない場合、そのリクエストは拒否されます。

Given the above permission set, GET /public/foo would match both the path and method and thus be allowed, whereas POST /public/foo would match the path but not the method and would therefore be rejected.

複数のパスのマッチング:一番長いパスが勝ちます。

マッチングは常にロンゲストパス に基づいて行われ、より具体的なパーミッションセットがマッチした場合、それより具体的でないパーミッションセットは考慮されません。:

quarkus.http.auth.permission.permit1.paths=/public/*
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD

quarkus.http.auth.permission.deny1.paths=/public/forbidden-folder/*
quarkus.http.auth.permission.deny1.policy=deny
Given the above permission set, GET /public/forbidden-folder/foo would match both permission sets' paths, but because it matches the deny1 permission set’s path on a longer match, deny1 will be chosen, and the request will be rejected.

Subpath permissions always win against the root path permissions, as explained above in the deny1 versus permit1 permission example. Here is another example showing subpath permission allowing a public resource access with the root path permission requiring the authorization:

quarkus.http.auth.policy.user-policy.roles-allowed=user
quarkus.http.auth.permission.roles.paths=/api/*
quarkus.http.auth.permission.roles.policy=user-policy

quarkus.http.auth.permission.public.paths=/api/noauth/*
quarkus.http.auth.permission.public.policy=permit

複数のパスのマッチング:一番具体的なパスが勝ちます

When a path is registered with multiple permission sets, the permission sets that explicitly specify an HTTP method that matches the request will take precedence. In this instance, the permission sets without methods will only come into effect if the request method does not match permission sets with the method specification.

quarkus.http.auth.permission.permit1.paths=/public/*
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD

quarkus.http.auth.permission.deny1.paths=/public/*
quarkus.http.auth.permission.deny1.policy=deny

上記のパーミッション・セットの場合、 GET /public/foo は両方のパーミッション・セットのパスに合致しますが、 permit1 のパーミッション・セットの明示的な方法に合致するため、 permit1 が選択され、リクエストは受理されます。

一方、 PUT /public/foo permit1 のメソッドパーミッションと一致しないため、 deny1 が有効化され、リクエストが拒否されます。

複数のパスのマッチング:一番長いパスが勝ちます

Sometimes, the previously described rules allow multiple permission sets to win at the same time. In that case, for the request to proceed, all the permissions must allow access. Note that for this to happen, both have to either have specified the method or have no method. Method-specific matches take precedence.

quarkus.http.auth.policy.user-policy1.roles-allowed=user
quarkus.http.auth.policy.admin-policy1.roles-allowed=admin

quarkus.http.auth.permission.roles1.paths=/api/*,/restricted/*
quarkus.http.auth.permission.roles1.policy=user-policy1

quarkus.http.auth.permission.roles2.paths=/api/*,/admin/*
quarkus.http.auth.permission.roles2.policy=admin-policy1
上記のパーミッションセットの場合、 GET /api/foo は両方のパーミッションセットのパスにマッチするので、 useradmin の両方のロールが必要になります。

アクセスを拒否するための設定プロパティ

以下の設定により、ロールベースアクセスコントロール(RBAC)の拒否動作が変更されます:

quarkus.security.jaxrs.deny-unannotated-endpoints=true|false

If set to true, access is denied for all JAX-RS endpoints by default. If a JAX-RS endpoint does not have any security annotations, it defaults to the @DenyAll behavior. This is useful to ensure you cannot accidentally expose an endpoint that is supposed to be secured. Defaults to false.

quarkus.security.jaxrs.default-roles-allowed=role1,role2

Defines the default role requirements for unannotated endpoints. The ** role is a special role that means any authenticated user. This cannot be combined with deny-unannotated-endpoints, as deny takes the effect instead.

quarkus.security.deny-unannotated-members=true|false
  • この値をtrue に設定すると、セキュリティアノテーションを持つメソッドを含むクラスで定義されているものの、セキュリティアノテーションを持たないすべての CDI メソッドと JAX-RS エンドポイントへのアクセスが拒否されるようになります。デフォルトは false です。

パーミッションの無効化

パーミッションは、宣言された各パーミッションの enabled プロパティを使って、ビルド時に次のように無効にすることができます:

quarkus.http.auth.permission.permit1.enabled=false
quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD

パーミッションは、システムプロパティや環境変数を使って実行時に再有効化することができます(例えば、以下のように): -Dquarkus.http.auth.permission.permit1.enabled=true .

パーミッションパスとHTTPルートパス

quarkus.http.root-path 設定プロパティは、 http エンドポイントコンテキストパス を変更するために使用されます。

デフォルトでは、設定されたパーミッションのパスの前に自動的に quarkus.http.root-path 、フォワードスラッシュを使用しない場合などです。 :

quarkus.http.auth.permission.permit1.paths=public/*,css/*,js/*,robots.txt

この構成は以下に相当します。 :

quarkus.http.auth.permission.permit1.paths=${quarkus.http.root-path}/public/*,${quarkus.http.root-path}/css/*,${quarkus.http.root-path}/js/*,${quarkus.http.root-path}/robots.txt

先頭のスラッシュは、設定されたパーミッションのパスの解釈方法を変更します。設定されたURLはそのまま使用され、 quarkus.http.root-path の値が変更されても、パスは調整されません。例えば下記の形です。 :

quarkus.http.auth.permission.permit1.paths=/public/*,css/*,js/*,robots.txt

この設定は、固定/静的URL /public から提供されるリソースにのみ影響します。 quarkus.http.root-path/ 以外に設定されている場合、アプリケーションリソースと一致しない可能性があります。

詳細については、 Quarkusのパス解決 を参照してください。

アノテーションを使った認可

Quarkus comes with built-in security to allow for Role-Based Access Control (RBAC) based on the common security annotations @RolesAllowed, @DenyAll, @PermitAll on REST endpoints and CDI beans.

Table 2. Quarkus アノテーション型の概要

アノテーション型

説明

@DenyAll

どのセキュリティロールも指定されたメソッドを呼び出すことを許可されていないことを指定します。

@PermitAll

すべてのセキュリティロールが指定されたメソッドを呼び出すことを許可されているように指定します。

@PermitAll は未認証含め誰でも許可します。

@RolesAllowed

アプリケーション内のメソッドへのアクセスが許可されているセキュリティロールのリストを指定します。

@RolesAllowed("**") に相当するものとして、Quarkus は、認証されたユーザーがリソースにアクセスできるようにする io.quarkus.security.Authenticated アノテーションも提供します。

SubjectExposingResourceの例 featured in this chapter demonstrates an endpoint that uses both JAX-RS and Common Security annotations to describe and secure its endpoints.

SubjectExposingResourceの例
import java.security.Principal;

import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;

@Path("subject")
public class SubjectExposingResource {

    @GET
    @Path("secured")
    @RolesAllowed("Tester") (1)
    public String getSubjectSecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal(); (2)
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("unsecured")
    @PermitAll (3)
    public String getSubjectUnsecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal(); (4)
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("denied")
    @DenyAll (5)
    public String getSubjectDenied(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }
}
1 /subject/secured エンドポイントは、 @RolesAllowed("Tester") アノテーションを使用して"Tester"というロールを付与された認証済みユーザーが必要です。
2 エンドポイントは、JAX-RS SecurityContext からユーザー・プリンシパルを取得します。これは、保護されたエンドポイントの場合は非 null になります。
3 /subject/unsecured エンドポイントでは、 @PermitAll アノテーションを指定することで、認証されていないアクセスが可能になります。
4 ユーザープリンシパルを取得するためのこの呼び出しは、呼び出し元が認証されていない場合はnullを返し、呼び出し元が認証されている場合は非nullを返します。
5 /subject/denied エンドポイントは、 @DenyAll アノテーションを宣言しているため、呼び出すユーザーに関係なく、REST メソッドとして直接アクセスすることはすべて禁止されています。このメソッドは、このクラスの他のメソッドから内部的に呼び出すことは可能です。
Please refer to the Proactive Authentication section of the Built-In Authentication Support guide if you plan to use standard security annotations on the IO thread.

The @RolesAllowed annotation value supports Property Expressions including default values and nested Property Expressions. Configuration properties used with the annotation are resolved at runtime.

Table 3. アノテーション値の例

アノテーション

値の説明

@RolesAllowed("${admin-role}")

エンドポイントは、 admin-role プロパティの値で示されるロールを持つユーザーを許可します。

@RolesAllowed("${tester.group}-${tester.role}")

値が複数の変数を含むことができることを示す例。

@RolesAllowed("${customer:User}")

デフォルト値の実証。 必要な役割は customer プロパティの値で示されますが、そのプロパティが指定されていない場合、 User という名前のロールがデフォルトとして要求されます。

@RolesAllowed アノテーションにおけるプロパティ式の使用例
admin=Administrator
tester.group=Software
tester.role=Tester
%prod.secured=User
%dev.secured=**
import java.security.Principal;

import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;

@Path("subject")
public class SubjectExposingResource {

    @GET
    @Path("admin")
    @RolesAllowed("${admin}") (1)
    public String getSubjectSecuredAdmin(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("software-tester")
    @RolesAllowed("${tester.group}-${tester.role}") (2)
    public String getSubjectSoftwareTester(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("user")
    @RolesAllowed("${customer:User}") (3)
    public String getSubjectUser(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("secured")
    @RolesAllowed("${secured}") (4)
    public String getSubjectSecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }
}
1 @RolesAllowed アノテーション値は、 Administrator の値に設定されています。
2 This /subject/software-tester endpoint requires an authenticated user that has been granted the role "Software-Tester". It is possible to use multiple expressions in the role definition.
3 設定プロパティ customer を設定していないため、 @RolesAllowed("${customer:User}") アノテーションの使用によって、この /subject/user エンドポイントには"User"というロールを付与された認証ユーザーが必要です。
4 この /subject/secured エンドポイントは、本番環境では User のロールを与えられた認証ユーザーが必要ですが、開発モードではどのような認証ユーザーでも許可されます。