LDAPレルムを利用したセキュリティーの使用
このガイドでは、QuarkusアプリケーションがLDAPサーバーを使用してユーザーアイデンティティを認証・認可する方法を説明します。
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.8
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
アーキテクチャ
この例では、3つのエンドポイントを提供する非常にシンプルなマイクロサービスを構築します。 :
-
/api/public
-
/api/users/me
-
/api/admin
/api/public
エンドポイントは匿名でアクセスできます。 /api/admin
エンドポイントは RBAC (Role-Based Access Control) で保護されており、 adminRole
ロールで許可されたユーザーのみがアクセスできます。このエンドポイントでは、 @RolesAllowed
アノテーションを使用して、アクセス制約を宣言的に強制します。 /api/users/me
エンドポイントも RBAC (Role-Based Access Control) で保護されており、 standardRole
ロールで付与されたユーザーのみがアクセスできます。レスポンスとして、ユーザーに関する詳細を含むJSONドキュメントを返します。
デフォルトでは、Quarkusは、Log4Shellと同様の将来の脆弱性を軽減するための予防措置として、アプリケーション内でのJNDIの使用を制限します。LDAPベースの認証にはJNDIが必要なため、この保護機能は自動的に無効化されます。 |
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git
、 アーカイブ をダウンロードします。
ソリューションは security-ldap-quickstart
ディレクトリ にあります。
Mavenプロジェクトの作成
まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。 :
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=security-ldap-quickstart"
このコマンドはプロジェクトを生成し、Quarkusアプリケーションのための `wildfly-elytron-realm-ldap`アダプターである `elytron-security-ldap`拡張をインポートします。
すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに elytron-security-ldap
エクステンションを追加することができます。
quarkus extension add elytron-security-ldap
./mvnw quarkus:add-extension -Dextensions='elytron-security-ldap'
./gradlew addExtension --extensions='elytron-security-ldap'
これにより、ビルドファイルに以下の内容が追加されます。 :
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elytron-security-ldap</artifactId>
</dependency>
implementation("io.quarkus:quarkus-elytron-security-ldap")
アプリケーションの記述
まず、 /api/public
のエンドポイントを実装することから始めましょう。以下のソースコードからわかるように、これは通常のJakarta RESTリソースに過ぎません:
package org.acme.elytron.security.ldap;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/api/public")
public class PublicResource {
@GET
@PermitAll
@Produces(MediaType.TEXT_PLAIN)
public String publicResource() {
return "public";
}
}
/api/admin
エンドポイントのソースコードも非常にシンプルです。ここでの主な違いは、 adminRole
ロールで付与されたユーザーだけがエンドポイントにアクセスできるように @RolesAllowed
アノテーションを使用していることです。 :
package org.acme.elytron.security.ldap;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/api/admin")
public class AdminResource {
@GET
@RolesAllowed("adminRole")
@Produces(MediaType.TEXT_PLAIN)
public String adminResource() {
return "admin";
}
}
最後に、/api/users/me
エンドポイントについて考えてみましょう。以下のソースコードからわかるように、standardRole
ロールを持つユーザーのみを信頼しています。 SecurityContext` を使用して、現在認証されている Principal へのアクセスを取得し、そのユーザ名を返しています。この情報は LDAP サーバーから読み込まれます。
package org.acme.elytron.security.ldap;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;
@Path("/api/users")
public class UserResource {
@GET
@RolesAllowed("standardRole")
@Path("/me")
public String me(@Context SecurityContext securityContext) {
return securityContext.getUserPrincipal().getName();
}
}
アプリケーションの設定
quarkus.security.ldap.enabled=true
quarkus.security.ldap.dir-context.principal=uid=admin,ou=system
quarkus.security.ldap.dir-context.url=ldaps://ldap.server.local (1)
quarkus.security.ldap.dir-context.password=secret
quarkus.security.ldap.identity-mapping.rdn-identifier=uid
quarkus.security.ldap.identity-mapping.search-base-dn=ou=Users,dc=quarkus,dc=io
quarkus.security.ldap.identity-mapping.attribute-mappings."0".from=cn
quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter=(member=uid={0},ou=Users,dc=quarkus,dc=io) (2)
quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter-base-dn=ou=Roles,dc=quarkus,dc=io
%test.quarkus.security.ldap.dir-context.url=ldap://127.0.0.1:10389 (3)
1 | LDAPサーバーへのURLを提供する必要があります。この例では、LDAPサーバーが このLDIFファイル をインポートしている必要があります。 |
2 | {0} は、 uid で置換されます。 |
3 | テストリソースが使用する URL。テストは、サンプルアプリケーションのテストカバレッジで 行っている ように、Quarkus が提供する LdapServerTestResource を活用することができます。 |
elytron-security-ldap
エクステンションでは、ユーザーとそのアイデンティティを認証するために、 dir-context と、少なくとも一つの属性マッピングを持つ アイデンティティマッピング が必要です。
アプリケーションのテスト
これで、アプリケーションは保護され、ID は LDAP サーバーから提供されるようになりました。 アプリケーションを開発モードで起動してみましょう。 :
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
まず最初に確認すべきは、匿名でのアクセスが可能かどうかということです。
$ 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%
では、保護されたリソースを匿名で攻撃してみましょう。
$ 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 adminUser:adminUserPassword http://localhost:8080/api/admin
HTTP/1.1 200 OK
Content-Length: 5
Content-Type: text/plain;charset=UTF-8
admin%
adminUser:adminUserPassword
資格情報を提供することで、エクステンションはユーザーを認証し、そのロールをロードしました。 adminUser
ユーザーは、保護されたリソースへのアクセスを許可されています。
ユーザー adminUser
は、この役割を持っていないので、 @RolesAllowed("standardRole")
で保護されたリソースへのアクセスを禁止する必要があります。
$ curl -i -X GET -u adminUser:adminUserPassword http://localhost:8080/api/users/me
HTTP/1.1 403 Forbidden
Content-Length: 34
Content-Type: text/html;charset=UTF-8
Forbidden%
最後に、ユーザー standardUser
を使用すると動作し、セキュリティーコンテキストには主要な詳細(例えばユーザー名)が含まれています。
$ curl -i -X GET -u standardUser:standardUserPassword http://localhost:8080/api/users/me
HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/plain;charset=UTF-8
user%
設定リファレンス
ビルド時に固定される構成プロパティ - 他のすべての構成プロパティは実行時にオーバーライド可能
Configuration property |
型 |
デフォルト |
---|---|---|
The option to enable the ldap elytron module Environment variable: Show more |
boolean |
|
The elytron realm name Environment variable: Show more |
string |
|
Provided credentials are verified against ldap? Environment variable: Show more |
boolean |
|
The url of the ldap server Environment variable: Show more |
string |
required |
The principal: user which is used to connect to ldap server (also named "bindDn") Environment variable: Show more |
string |
|
The password which belongs to the principal (also named "bindCredential") Environment variable: Show more |
string |
|
how ldap redirects are handled Environment variable: Show more |
|
|
The connect timeout Environment variable: Show more |
|
|
The read timeout Environment variable: Show more |
|
|
If set to true, request to the LDAP server are cached Environment variable: Show more |
boolean |
|
The duration that an entry can stay in the cache Environment variable: Show more |
|
|
The maximum number of entries to keep in the cache Environment variable: Show more |
int |
|
The identifier which correlates to the provided user (also named "baseFilter") Environment variable: Show more |
string |
|
The dn where we look for users Environment variable: Show more |
string |
required |
If the child nodes are also searched for identities Environment variable: Show more |
boolean |
|
The roleAttributeId from which is mapped (e.g. "cn") Environment variable: Show more |
string |
required |
The identifier whom the attribute is mapped to (in Quarkus: "groups", in WildFly this is "Roles") Environment variable: Show more |
string |
|
The filter (also named "roleFilter") Environment variable: Show more |
string |
required |
The filter base dn (also named "rolesContextDn") Environment variable: Show more |
string |
required |
期間フォーマットについて
To write duration values, use the standard 数字で始まる簡略化した書式を使うこともできます:
その他の場合は、簡略化されたフォーマットが解析のために
|