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

JDBCでセキュリティーを使用する

このガイドでは、Quarkusアプリケーションがデータベースを使用してユーザーIDを保存する方法を説明します。

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 11+ がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.8.1+

  • 使用したい場合、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

アーキテクチャ

この例では、3つのエンドポイントを提供する非常にシンプルなマイクロサービスを構築します:

  • /api/public

  • /api/users/me

  • /api/admin

/api/public エンドポイントは匿名でアクセスできます。 /api/admin エンドポイントは RBAC (Role-Based Access Control) で保護されており、 admin の役割を与えられたユーザーのみがアクセスできます。このエンドポイントでは、 @RolesAllowed アノテーションを使用して、アクセス制約を宣言的に強制します。 /api/users/me エンドポイントも RBAC (Role-Based Access Control) で保護されており、 user ロールで付与されたユーザーのみがアクセスできます。レスポンスとして、ユーザーに関する詳細を含むJSONドキュメントを返します。

ソリューション

次のセクションで紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

ソリューションは security-jdbc-quickstart ディレクトリ にあります。

Mavenプロジェクトの作成

まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。

CLI
quarkus create app org.acme:security-jdbc-quickstart \
    --extension=elytron-security-jdbc,jdbc-postgresql,resteasy-reactive \
    --no-code
cd security-jdbc-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストール方法については、Quarkus CLIガイドをご参照ください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.11.1.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=security-jdbc-quickstart \
    -Dextensions="elytron-security-jdbc,jdbc-postgresql,resteasy-reactive" \
    -DnoCode
cd security-jdbc-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

選択したデータベースコネクタライブラリを追加することを忘れないでください。ここでは、PostgreSQLをIDストアとして使用しています。

このコマンドは新しいプロジェクトを生成し、 elytron-security-jdbc エクステンションをインポートします。これはQuarkusアプリケーション用の wildfly-elytron-realm-jdbc アダプターです。

すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに elytron-security-jdbc エクステンションを追加することができます:

CLI
quarkus extension add 'elytron-security-jdbc'
Maven
./mvnw quarkus:add-extension -Dextensions="elytron-security-jdbc"
Gradle
./gradlew addExtension --extensions="elytron-security-jdbc"

これにより、ビルドファイルに以下が追加されます:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-elytron-security-jdbc</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-elytron-security-jdbc")

アプリケーションの記述

/api/public エンドポイントの実装から始めましょう。以下のソースコードから分かるように、通常のJAX-RSリソースです:

package org.acme.security.jdbc;

import javax.annotation.security.PermitAll;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/api/public")
public class PublicResource {

    @GET
    @PermitAll
    @Produces(MediaType.TEXT_PLAIN)
    public String publicResource() {
        return "public";
   }
}

/api/admin エンドポイントのソースコードも非常にシンプルです。ここでの主な違いは、 admin ロールで付与されたユーザーだけがエンドポイントにアクセスできるように @RolesAllowed アノテーションを使用していることです:

package org.acme.security.jdbc;

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/api/admin")
public class AdminResource {

    @GET
    @RolesAllowed("admin")
    @Produces(MediaType.TEXT_PLAIN)
    public String adminResource() {
         return "admin";
    }
}

Finally, let’s consider the /api/users/me endpoint. As you can see from the source code below, we are trusting only users with the user role. We are using SecurityContext to get access to the current authenticated Principal, and we return the user’s name. This information is loaded from the database.

package org.acme.security.jdbc;

import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;

@Path("/api/users")
public class UserResource {

    @GET
    @RolesAllowed("user")
    @Path("/me")
    public String me(@Context SecurityContext securityContext) {
        return securityContext.getUserPrincipal().getName();
    }
}

アプリケーションの設定

elytron-security-jdbc エクステンションは、データベースにアクセスするために少なくとも一つのデータソースが必要です。

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.datasource.jdbc.url=jdbc:postgresql:elytron-security-jdbc

In our context, we are using PostgreSQL as identity store, and we initialize the database with users and roles.

CREATE TABLE test_user (
  id INT,
  username VARCHAR(255),
  password VARCHAR(255),
  role VARCHAR(255)
);

INSERT INTO test_user (id, username, password, role) VALUES (1, 'admin', 'admin', 'admin');
INSERT INTO test_user (id, username, password, role) VALUES (2, 'user','user', 'user');

It is probably useless, but we kindly remind you that you must not store clear-text passwords in production environment ;-). The elytron-security-jdbc offers a built-in bcrypt password mapper.

これで、Elytron JDBC Realmを設定することができます。

quarkus.security.jdbc.enabled=true
quarkus.security.jdbc.principal-query.sql=SELECT u.password, u.role FROM test_user u WHERE u.username=? (1)
quarkus.security.jdbc.principal-query.clear-password-mapper.enabled=true (2)
quarkus.security.jdbc.principal-query.clear-password-mapper.password-index=1
quarkus.security.jdbc.principal-query.attribute-mappings.0.index=2 (3)
quarkus.security.jdbc.principal-query.attribute-mappings.0.to=groups

elytron-security-jdbc エクステンションは、ユーザーとそのアイデンティティを認証するために、少なくとも一つのプリンシパルのクエリを必要とします。

1 ユーザーのパスワードと、ロードしたい追加情報を返却するパラメーター化されたSQL文(単一のパラメーター付)を定義しています。
2 SELECT フィールドのパスワードフィールドの位置や、ソルト、ハッシュエンコードなどの情報を使って、パスワードマッパーを設定します。
3 We use attribute-mappings to bind the SELECT projection fields (i.e. u.role here) to the target Principal representation attributes.

principal-query の設定では、 index のプロパティーはすべて 1 から始まります (0 ではなく)。

アプリケーションのテスト

アプリケーションが保護され、アイデンティティがデータベースから提供されるようになりました。非常に最初に確認しなければならないことは、匿名アクセスが機能することを確認することです。

$ curl -i -X GET http://localhost:8080/api/public
HTTP/1.1 200 OK
Content-Length: 6
Content-Type: text/plain;charset=UTF-8

public%

Now, let’s try to hit a protected resource anonymously.

$ curl -i -X GET http://localhost:8080/api/admin
HTTP/1.1 401 Unauthorized
Content-Length: 14
Content-Type: text/html;charset=UTF-8

Not authorized%

ここまでは順調ですが、今度は許可されたユーザーで試してみましょう。

$ curl -i -X GET -u admin:admin http://localhost:8080/api/admin
HTTP/1.1 200 OK
Content-Length: 5
Content-Type: text/plain;charset=UTF-8

admin%

admin:admin 資格情報を提供することで、エクステンションはユーザーを認証し、そのロールをロードしました。 admin ユーザーは、保護されたリソースへのアクセスを許可されています。

ユーザー admin は、この役割を持っていないので、 @RolesAllowed("user") で保護されたリソースへのアクセスを禁止する必要があります。

$ curl -i -X GET -u admin:admin http://localhost:8080/api/users/me
HTTP/1.1 403 Forbidden
Content-Length: 34
Content-Type: text/html;charset=UTF-8

Forbidden%

最後に、ユーザー user を使用すると動作し、セキュリティーコンテキストには主要な詳細(例えばユーザー名)が含まれています。

$ curl -i -X GET -u user:user http://localhost:8080/api/users/me
HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/plain;charset=UTF-8

user%

高度な設定

このガイドでは、簡単な使用例のみを取り上げていますが、このエクステンションは複数のデータソース、複数のプリンシパルクエリの設定、および bcrypt パスワードマッパーを提供しています。

quarkus.datasource.db-kind=postgresql quarkus.datasource.username=quarkus quarkus.datasource.password=quarkus quarkus.datasource.jdbc.url=jdbc:postgresql:multiple-data-sources-users

quarkus.datasource.permissions.db-kind=postgresql quarkus.datasource.permissions.username=quarkus quarkus.datasource.permissions.password=quarkus quarkus.datasource.permissions.jdbc.url=jdbc:postgresql:multiple-data-sources-permissions

quarkus.security.jdbc.enabled=true quarkus.security.jdbc.principal-query.sql=SELECT u.password FROM test_user u WHERE u.username=? quarkus.security.jdbc.principal-query.clear-password-mapper.enabled=true quarkus.security.jdbc.principal-query.clear-password-mapper.password-index=1

quarkus.security.jdbc.principal-query.roles.sql=SELECT r.role_name FROM test_role r, test_user_role ur WHERE ur.username=? AND ur.role_id = r.id quarkus.security.jdbc.principal-query.roles.datasource=permissions quarkus.security.jdbc.principal-query.roles.attribute-mappings.0.index=1 quarkus.security.jdbc.principal-query.roles.attribute-mappings.0.to=groups

設定リファレンス

ビルド時に固定される設定プロパティ - それ以外の設定プロパティは実行時に上書き可能

Configuration property

タイプ

デフォルト

The realm name

Environment variable: QUARKUS_SECURITY_JDBC_REALM_NAME

string

Quarkus

If the properties store is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_ENABLED

boolean

false

The sql query to find the password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_SQL

string

The data source to use

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_DATASOURCE

string

If the clear-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_CLEAR_PASSWORD_MAPPER_ENABLED

boolean

false

The index (1 based numbering) of the column containing the clear password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_CLEAR_PASSWORD_MAPPER_PASSWORD_INDEX

int

1

If the bcrypt-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_ENABLED

boolean

false

The index (1 based numbering) of the column containing the password hash

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_PASSWORD_INDEX

int

0

A string referencing the password hash encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_HASH_ENCODING

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt salt

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_SALT_INDEX

int

0

A string referencing the salt encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_SALT_ENCODING

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt iteration count

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_ITERATION_COUNT_INDEX

int

0

The index (1 based numbering) of column to map

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__INDEX

int

0

The target attribute name

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__TO

string

required

The sql query to find the password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__SQL

string

The data source to use

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__DATASOURCE

string

The index (1 based numbering) of column to map

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__INDEX

int

0

The target attribute name

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__TO

string

required

If the clear-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__CLEAR_PASSWORD_MAPPER_ENABLED

boolean

false

The index (1 based numbering) of the column containing the clear password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__CLEAR_PASSWORD_MAPPER_PASSWORD_INDEX

int

1

If the bcrypt-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_ENABLED

boolean

false

The index (1 based numbering) of the column containing the password hash

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_PASSWORD_INDEX

int

0

A string referencing the password hash encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_HASH_ENCODING

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt salt

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_SALT_INDEX

int

0

A string referencing the salt encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_SALT_ENCODING

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt iteration count

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_ITERATION_COUNT_INDEX

int

0