第4章 プロアクティブ認証


設定のカスタマイズや例外の処理を含め、Quarkus でプロアクティブ認証を管理する方法を説明します。さまざまなアプリケーションシナリオにおける実用的な洞察とストラテジーを得ることができます。

Quarkus では、プロアクティブ認証がデフォルトで有効になっています。これにより、ターゲットページで認証が不要な場合でも、認証情報を持つすべての受信リクエストが必ず認証されます。その結果、ターゲットページが公開されている場合でも、無効な認証情報を持つリクエストは拒否されます。

ターゲットページで必要な場合にのみ認証を行う場合は、このデフォルトの動作をオフにできます。ターゲットページで要求される場合にのみ認証を行うためにプロアクティブ認証をオフにするには、application.properties 設定ファイルを次のように変更します。

quarkus.http.auth.proactive=false

プロアクティブ認証をオフにすると、アイデンティティーが要求された場合にのみ認証プロセスが実行されます。ユーザーの認証を必要とするセキュリティールールがある場合、または現在のアイデンティティーへのプログラムによるアクセスが必要な場合、アイデンティティーが要求される場合があります。

プロアクティブ認証が使用されている場合、SecurityIdentity へのアクセスはブロック操作になります。これは、認証がまだ行われておらず、SecurityIdentity へのアクセスにはデータベースなどの外部システムへの呼び出しが必要になり、操作がブロックされる可能性があるためです。ブロッキングアプリケーションの場合、これは問題になりません。しかし、リアクティブアプリケーションで認証を無効にしている場合は、I/O スレッドでブロッキング操作を実行できないため、これは失敗します。この問題を回避するには、io.quarkus.security.identity.CurrentIdentityAssociation のインスタンスに対して @Inject を実行し、Uni<SecurityIdentity> getDeferredIdentity(); メソッドを呼び出す必要があります。次に、その結果として得られる Uni をサブスクライブすると、認証が完了してアイデンティティーが利用可能になった場合に通知を受け取ることができます。

注記

認証がすでに行われているため、@RolesAllowed@Authenticated、またはそれぞれの設定認可チェックでアノテーションが付けられたエンドポイントから、Quarkus REST (旧称 RESTEasy Reactive)public SecurityIdentity getIdentity() を使用して SecurityIdentity に同期的にアクセスできます。ルートレスポンスが同期的である場合、これは Reactive ルート にも当てはまります。

プロアクティブ認証が無効になっている場合、void ではない保護されたメソッドが同期的に値を返すと、CDI Bean で使用される 標準のセキュリティーアノテーション は I/O スレッドで機能しません。これらのメソッドが SecurityIdentity にアクセスする必要があるため、このような制限が生じます。

次の例では、HelloResourceHelloService を定義します。/hello へのすべての GET リクエストは I/O スレッドで実行され、BlockingOperationNotAllowedException 例外を出力します。

この例は、複数の方法で修正できます。

  • hello エンドポイントにアノテーション @Blocking を付け、ワーカースレッドに切り替えます。
  • リアクティブまたは非同期データ型を使用して、sayHello メソッドの戻り値の型を変更します。
  • @RolesAllowed アノテーションをエンドポイントに移動します。エンドポイントメソッドから SecurityIdentity にアクセスしてもブロック操作になることはないため、これは最も安全な方法の 1 つです。
import jakarta.annotation.security.PermitAll;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import io.smallrye.mutiny.Uni;

@Path("/hello")
@PermitAll
public class HelloResource {

    @Inject
    HelloService helloService;

    @GET
    public Uni<String> hello() {
        return Uni.createFrom().item(helloService.sayHello());
    }

}
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class HelloService {

    @RolesAllowed("admin")
    public String sayHello() {
        return "Hello";
    }

}

4.1. 認証例外レンスポンスをカスタマイズする

Jakarta REST ExceptionMapper を使用して、io.quarkus.security.AuthenticationFailedException などの Quarkus Security 認証例外をキャプチャーできます。以下に例を示します。

package io.quarkus.it.keycloak;

import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

import io.quarkus.security.AuthenticationFailedException;

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFailedExceptionMapper implements ExceptionMapper<AuthenticationFailedException> {

    @Context
    UriInfo uriInfo;

    @Override
    public Response toResponse(AuthenticationFailedException exception) {
        return Response.status(401).header("WWW-Authenticate", "Basic realm=\"Quarkus\"").build();
    }
}
注意

一部の HTTP 認証メカニズムでは、正しい認証チャレンジを作成するために、認証例外を自ら処理する必要があります。たとえば、OpenID Connect (OIDC) 認可コードフロー認証を管理する io.quarkus.oidc.runtime.CodeAuthenticationMechanism は、正しいリダイレクト URL を作成し、状態 Cookie を設定する必要があります。したがって、カスタム例外マッパーを使用して、このようなメカニズムによって出力される認証例外をカスタマイズしないでください。代わりのより安全なアプローチとして、プロアクティブ認証を有効にして Vert.x HTTP ルート失敗ハンドラーを使用できます。なぜなら、イベントは正しいレスポンスステータスとヘッダーとともにハンドラーに送信されるからです。次に、レンスポンスのみをカスタマイズする必要があります。以下はその例です。

package io.quarkus.it.keycloak;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;

import io.quarkus.security.AuthenticationFailedException;
import io.vertx.core.Handler;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class AuthenticationFailedExceptionHandler {

    public void init(@Observes Router router) {
        router.route().failureHandler(new Handler<RoutingContext>() {
            @Override
            public void handle(RoutingContext event) {
                if (event.failure() instanceof AuthenticationFailedException) {
                    event.response().end("CUSTOMIZED_RESPONSE");
                } else {
                    event.next();
                }
            }
        });
    }
}
Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.