ウェブエンドポイントの認可
Quarkusには、プラグイン可能なウェブセキュリティーレイヤーが統合されています。セキュリティーが有効になっている場合、すべてのHTTPリクエストは、処理の継続が許可されているかどうかを確認するためのパーミッションチェックが実行されます。
設定の認可チェックは、アノテーションベースの認可チェックが行われる前に実行されるため、リクエストを許可するには両方のチェックが通る必要があります。つまり、 quarkus.http.auth. の設定でパスがブロックされている場合、 @PermitAll を使ってパスを開くことはできません。JAX-RSを使用している場合は、HTTPパスレベルのマッチングではなく、 quarkus.security.jaxrs.deny-unannotated-endpoints または quarkus.security.jaxrs.default-roles-allowed を使用してデフォルトのセキュリティ要件を設定することを検討するとよいでしょう。これらのプロパティは、個々のエンドポイント上のアノテーションによって上書きすることができるからです。
|
認可は、セキュリティプロバイダが提供するユーザーロールに基づいて行われます。 これらのロールをカスタマイズするために、 SecurityIdentityAugmentor
を作成することができます。Security Identity Customization を参照してください。
設定を利用した認可
デフォルトの実装では、 application.properties
の 設定を使用してパーミッションを定義することができます。以下に config の例を示します。 :
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin (1)
quarkus.http.auth.permission.roles1.paths=/roles-secured/*,/other/*,/api/* (2)
quarkus.http.auth.permission.roles1.policy=role-policy1
quarkus.http.auth.permission.permit1.paths=/public/* (3)
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET
quarkus.http.auth.permission.deny1.paths=/forbidden (4)
quarkus.http.auth.permission.deny1.policy=deny
1 | これは、 user と admin のロールを持つユーザーを許可するロールベースのポリシーを定義します。これは後のルールで参照されます。 |
2 | これは以前に定義されたポリシーを参照するパーミッションセットです。 roles1 は任意の名前ですので、好きなようにパーミッションセットを呼び出すことができます。 |
3 | このパーミッションはデフォルトの permit ビルトインポリシーを参照して、 /public への GET メソッドを許可します。この例では、このリクエストはいずれにせよ許可されているはずなので、これは実際には no-op です。 |
4 | このパーミッションは /forbidden に対する組み込みの deny ポリシーを参照します。これは * で終わらないので、完全なパスマッチとなります。 |
パーミッションは、パーミッションセットを使ってコンフィグで定義されます。これらは任意の名前のパーミッション・グルーピングです。各パーミッションセットには、アクセスを制御するためのポリシーを指定する必要があります。組み込みのポリシーには, deny
, permit
, authenticated
の3種類があり,それぞれ,すべてを許可,すべてを拒否,認証されたユーザのみを許可 となります。
また、例に示すように、ロールベースのポリシーを定義することも可能です。これらのポリシーでは、指定されたロールを持つユーザーにのみ、リソースへのアクセスを許可します。
パス、メソッドでのマッチング
パーミッションセットでは、パスとメソッドをカンマ区切りのリストで指定することもできます。パスの末尾が *
である場合はワイルドカードマッチとみなされ、すべてのサブパスにマッチしますが、そうでない場合は完全一致となり、特定のパスにのみマッチします。 :
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つ以上のパーミッションセットにマッチするが、 メソッドの要件によりマッチしない場合、そのリクエストは拒否されます。
上記のパーミッションセットの場合、GET /public/foo はパスとメソッドの両方にマッチするので許可されますが、POST /public/foo はパスにマッチしますがメソッドにはマッチしないので拒否されます。
|
複数のパスのマッチング:一番長いパスが勝ちます
マッチングは常にロンゲストパス に基づいて行われ、より具体的なパーミッションセットがマッチした場合、それより具体的でないパーミッションセットは考慮されません。:
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
上記のパーミッションセットを考えると、GET /public/forbidden-folder/foo は両方のパーミッションセットのパスにマッチしますが、より長いマッチで deny1 パーミッションセットのパスにマッチするので、 deny1 が選択されてリクエストは拒否されます。
|
サブパス パーミッションは、上述の
|
複数のパスのマッチング:一番具体的なパスが勝ちます
パスが複数の許可セットで登録されている場合、HTTPメソッドを指定する許可セットが優先され、メソッドを持たない許可セットは考慮されません(もちろん、メソッドが一致することを前提としています)。この例では、メソッドを持たないパーミッションセットは、 リクエストメソッドがメソッドパーミッションセットのいずれにもマッチしない場合にのみ 有効になります。
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 が有効になり、リクエストが拒否されます。
|
複数のパスのマッチング:一番長いパスが勝ちます
複数のパーミッションセットが同じパスとメソッドを指定している場合(または複数のパーミッションがメソッドを持たない場合)、リクエストを進めるためには両方のパーミッションがアクセスを許可しなければなりません。これを実現するためには、両方がメソッドを指定しているか、メソッドを持たないかのいずれかでなければならないことに注意してください、メソッド固有のマッチは上記のように優先されます。 :
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 は両方のパーミッションセットのパスにマッチするので、 user と admin の両方のロールが必要になります。
|
アクセスを拒否する設定プロパティー
RBACのDeny動作を変更する設定は3つあります。 :
quarkus.security.jaxrs.deny-unannotated-endpoints=true|false
-
この値をtrue に設定すると、デフォルトですべての JAX-RS エンドポイントに対してアクセスが拒否されます。したがって、JAX-RS エンドポイントがセキュリティアノテーションを持っていない場合、デフォルトで
@DenyAll
の動作になります。これは、セキュリティで保護されているはずのエンドポイントを誤って公開してしまわないようにするために有用です。デフォルトはfalse
です。 quarkus.security.jaxrs.default-roles-allowed=role1,role2
-
アノテーションされていないエンドポイントのデフォルトのロール要件を定義します。ロール「**」は、認証された任意のユーザを意味する特別なロールです。これは、代わりにdenyが有効になるため、
deny-unannotated-endpoints
と組み合わせることはできません。 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 rootパス
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には、共通のセキュリティーアノテーション( @RolesAllowed
, @DenyAll
, @PermitAll
)に基づいたロールベースのアクセス制御 (RBAC )をRESTエンドポイントとCDI Bean上で可能にするためのビルトインセキュリティーが搭載されています。JAX-RSとCommon Securityアノテーションの両方を利用してエンドポイントを記述し、セキュリティーを確保するエンドポイントの例は、 SubjectExposingResourceの例 に記載されています。Quarkusはまた、認証済みのユーザーがリソースにアクセスすることを許可する io.quarkus.security.Authenticated
アノテーションも提供しています( @RolesAllowed("**")
と同等です)。
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 アノテーションを指定することで、呼出が認証されているかどうかにかかわらず、あらゆるアクセスを禁止します。 |