Microsoft Entra ID を使用して Java Spring Boot アプリをセキュリティで保護する

この記事では、Java 用 Microsoft Entra ID Spring Boot Starterクライアント ライブラリを使用して Microsoft Entra ID テナントのユーザーのサインインを行う Java Spring Boot Web アプリについて説明します。 OpenID Connect プロトコルを使用します。

次の図は、アプリのトポロジを示しています。

アプリのトポロジを示す図。

クライアント アプリは、Java 用 Microsoft Entra ID Spring Boot Starter クライアント ライブラリを使用してユーザーのサインインを行い、Microsoft Entra ID から ID トークンを取得します。 ID トークンにより、ユーザーが Microsoft Entra ID で認証され、保護されたルートにアクセスできることが証明されます。

前提条件

推奨事項

  • Spring Framework に関するある程度の知識
  • Linux/OSX terminal ターミナルまたは Windows PowerShell に関するある程度の知識
  • トークンの検査に必要な jwt.ms
  • ネットワークの活動監視とトラブルシューティングに必要な Fiddler
  • 開発に関する最新の情報について、Microsoft Entra ID ブログを確認してください。

サンプルのセットアップ

次のセクションでは、サンプル アプリケーションを設定する方法を示します。

サンプル リポジトリを複製またはダウンロードする

サンプルを複製するには、Bash ウィンドウを開き、次のコマンドを使用します。

git clone https://github.com/Azure-Samples/ms-identity-java-spring-tutorial.git
cd ms-identity-java-spring-tutorial
cd 1-Authentication/sign-in

または、ms-identity-java-spring-tutorial レポジトリに移動し、.zip ファイルでダウンロードして、ハード ドライブに展開します。

重要

Windows のパスの長さ制限によって発生するエラーを回避するために、ドライブのルート近くのディレクトリにクローンを作成することをお勧めします。

Microsoft Entra ID テナントにサンプル アプリケーションを登録する

このサンプルには、プロジェクトが 1 つ存在します。 アプリを Azure portal に登録するには、手順に従って手動で登録するか、PowerShell スクリプトを使用します。 スクリプトでは次のタスクを実行します。

  • Microsoft Entra ID アプリケーションと、パスワード、アクセス許可、依存関係などの関連オブジェクトを作成します。
  • プロジェクトの構成ファイルを変更します。
  • 既定では、組織のディレクトリ内のアカウントでのみ動作するアプリケーションが設定されます。

次の手順を使用して、PowerShell スクリプトを実行します。

  1. Windows で PowerShell を開き、クローンされたディレクトリのルートに移動します。

  2. PowerShell の実行ポリシーを設定するには、次のコマンドを使用します。

    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
    
  3. 次のコマンドを使用して構成スクリプトを完了します。

    cd .\AppCreationScripts\
    .\Configure.ps1
    

    Note

    スクリプトを実行するその他の方法については、「アプリ作成スクリプト」に記載された説明を参照してください。 このスクリプトにより、アプリケーションの登録、構成、および削除に関する自動化されたガイドも行われます。これは CI/CD のシナリオに便利です。

アプリ登録を使用するようにアプリ (java-spring-webapp-auth) を構成する

アプリを構成するには、次の手順に従います。

Note

以降の手順では、ClientIDApplication ID または AppId と同じです。

  1. IDE でプロジェクトを開きます。

  2. src\main\resources\application.yml ファイルを開きます。

  3. プレースフォルダー Enter_Your_Tenant_ID_Here を見つけて、既存の値を Microsoft Entra テナント ID に置き換えます。

  4. Enter_Your_Client_ID_Here のプレースフォルダーを見つけて、既存の値をアプリケーション ID または Azure portal からコピーした java-spring-webapp-auth アプリの clientId に変更します。

  5. Enter_Your_Client_Secret_Here のプレースフォルダーを見つけて、既存の値を Azure portal からコピーした、java-spring-webapp-auth の作成時に保存した値に置き換えます。

サンプルの実行

以降のセクションでは、サンプルを Azure Spring Apps にデプロイする方法を紹介します。

前提条件

Spring プロジェクトを準備する

次の手順を実行して、プロジェクトを準備します。

  1. 次の Maven コマンドを使用して、プロジェクトをビルドします。

    mvn clean package
    
  2. 次のコマンドを使用して、サンプル プロジェクトをローカルで実行します。

    mvn spring-boot:run
    

Maven プラグインを構成する

プロジェクトのルートで次のコマンドを実行し、Maven plugin for Azure Spring Apps を使用してアプリを構成します。

mvn com.microsoft.azure:azure-spring-apps-maven-plugin:1.19.0:config

次の一覧に、コマンド対話を記載します。

  • OAuth2 ログイン: OAuth2 プロトコルに基づいて Azure へのサインインを承認する必要があります。
  • サブスクリプションを選択: Azure Spring Apps インスタンスを作成するサブスクリプション リスト番号 (既定ではリストの最初のサブスクリプション) を選択します。 デフォルトの番号を使用する場合は、Enter を押します。
  • Azure Spring Apps の名前を入力: 作成する Spring Apps インスタンスの名前を入力します。 デフォルトの名前を使用する場合は、Enter を押します。
  • リソース グループ名を入力: Spring Apps インスタンスを作成するリソース グループの名前を入力します。 デフォルトの名前を使用する場合は、Enter を押します。
  • SKU: Spring Apps インスタンスに使用する SKU を選択します。 デフォルトの番号を使用する場合は、Enter を押します。
  • [Input the app name (demo)] (アプリ名 (デモ) を入力する): アプリ名を指定します。 デフォルトのプロジェクト成果物 ID を使用する場合は、Enter キーを押します。
  • ランタイム: Spring Apps インスタンスに使用するランタイムを選択します。 この場合は、既定の数値を使用する必要があるため、Enter を押します。
  • [Expose public access for this app (boot-for-azure)] (このアプリ (boot-for-azure) のパブリック アクセスを公開する): y を押します。
  • 上記のすべての構成の保存を確定する: y キーを押します。 n を押した場合、構成は .pom ファイルに保存されません。

デプロイ プロセスの出力例を次に示します。

Summary of properties:
Subscription id   : 12345678-1234-1234-1234-123456789101
Resource group name : rg-ms-identity-spring-boot-webapp
Azure Spring Apps name : cluster-ms-identity-spring-boot-webapp
Runtime Java version : Java 11
Region            : eastus
Sku               : Standard
App name          : ms-identity-spring-boot-webapp
Public access     : true
Instance count/max replicas : 1
CPU count         : 1
Memory size(GB)   : 2
Confirm to save all the above configurations (Y/n):
[INFO] Configurations are saved to: /home/user/ms-identity-java-spring-tutorial/1-Authentication/sign-in/pom.    xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:57 min
[INFO] Finished at: 2024-02-14T13:50:44Z
[INFO] ------------------------------------------------------------------------

選択内容の確認後、プラグインによって、アプリを Azure Spring Apps で実行するよう構成するのに必要なプラグイン要素および設定が、プロジェクトの pom.xml ファイルに追加されます。

pom.xml ファイルの関連部分は、次の例のようになります。

<plugin>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-spring-apps-maven-plugin</artifactId>
    <version>1.19.0</version>
    <configuration>
        <subscriptionId>12345678-1234-1234-1234-123456789101</subscriptionId>
        <resourceGroup>rg-ms-identity-spring-boot-webapp</resourceGroup>
        <clusterName>cluster-ms-identity-spring-boot-webapp</clusterName>
        <region>eastus</region>
        <sku>Standard</sku>
        <appName>ms-identity-spring-boot-webapp</appName>
        <isPublic>true</isPublic>
        <deployment>
            <cpu>1</cpu>
            <memoryInGB>2</memoryInGB>
            <instanceCount>1</instanceCount>
            <runtimeVersion>Java 11</runtimeVersion>
            <resources>
                <resource>
                    <directory>${project.basedir}/target</directory>
                    <includes>
                        <include>*.jar</include>
                    </includes>
                </resource>
            </resources>
        </deployment>
    </configuration>
</plugin>

Azure Spring Apps の構成は、pom.xml ファイル内で直接変更できます。 一般的な構成をいくつか次の表に示します。

プロパティ Required 説明
subscriptionId false サブスクリプション ID です。
resourceGroup true Azure Spring Apps インスタンスの Azure リソース グループ。
clusterName true Azure Spring Apps のクラスター名。 Azure Spring Apps インスタンスが既にデプロイされているサブスクリプションとリソース グループを使用している場合は、この既存のクラスターを使用してデプロイすることもできます。
appName true Azure Spring Apps のアプリの名前。
region false Azure Spring Apps インスタンスをホストするリージョン。 既定値は eastus です。 有効なリージョンについては、「サポートされているリージョン」を参照してください。
sku false Azure Spring Apps インスタンスの価格レベル。 既定値は Basic。これは開発環境とテスト環境にのみ使用してください。
runtime false ランタイム環境の構成。 詳細については、「構成の詳細」を参照してください。
deployment false デプロイの構成。 詳細については、「構成の詳細」を参照してください。

構成の完全な一覧については、プラグインのリファレンス ドキュメントを参照してください。 すべての Azure Maven プラグインでは、一連の構成が共通しています。 これらの構成については、「共通の構成」を参照してください。 Azure Spring Apps に固有の構成については、「Azure Spring Apps: 構成の詳細」を参照してください。

後で使用するために clusterNameappName の値を保存しておいてください。

アプリのデプロイを準備する

アプリケーションを Azure Spring Apps にデプロイすると、Azure Spring Apps にデプロイされたアプリ インスタンスのリダイレクト URL にリダイレクト URL が変更されます。 application.yml ファイルでこれらの設定を変更するには、次の手順に従います。

  1. アプリの src\main\resources\application.yml ファイルに移動し、post-logout-redirect-uri の値をデプロイされたアプリのドメイン名に変更します (次の例を参照)。 たとえば、前の手順で Azure Spring Apps インスタンスに cluster-ms-identity-spring-boot-webapp を選択し、アプリ名に ms-identity-spring-boot-webapp を選択している場合は、ここで post-logout-redirect-uri の値に https://cluster-ms-identity-spring-boot-webapp-ms-identity-spring-boot-webapp.azuremicroservices.io を使用する必要があります。

    post-logout-redirect-uri: https://<cluster-name>-<app-name>.azuremicroservices.io
    
  2. このファイルを保存した後、次のコマンドを使用してアプリをリビルドします。

    mvn clean package
    

重要

アプリケーションの application.yml ファイルには、クライアント シークレットの値が client-secret パラメーターに格納されています。 この値をこのファイルに保持しないでください。 Git リポジトリにコミットした場合にリスクが発生します。

セキュリティを強化するために、この値を Azure Key Vault に格納し、シークレットを Key Vault から読み込んでアプリケーションで使用することができます。

Microsoft Entra IDアプリの登録を更新する

リダイレクト URI は Azure Spring Apps にデプロイされたアプリに変更されるため、Microsoft Entra ID アプリの登録でも、リダイレクト URI を変更する必要があります。 次の手順に従って、この変更を行います。

  1. 開発者用の Microsoft ID プラットフォームの [アプリの登録] ページに移動します。

  2. 検索ボックスを使用してアプリの登録を検索します (例: java-servlet-webapp-authentication)。

  3. 名前を選択して、アプリの登録を開きます。

  4. コマンドメニューから 認証 を選択します。

  5. Web - リダイレクト URI セクションで、URI の追加を選択します。

  6. アプリの URI を、/login/oauth2/code/ を追加して入力します。たとえば https://<cluster-name>-<app-name>.azuremicroservices.io/login/oauth2/code/ のようになります。

  7. [保存] を選択します。

アプリケーションのデプロイ

次のコマンドを使用して、アプリをデプロイします。

mvn azure-spring-apps:deploy

次の一覧に、コマンド対話を記載します:

  • OAuth2 ログイン: OAuth2 プロトコルに基づいて Azure へのサインインを承認する必要があります。

コマンドが実行されると、デプロイが成功したことを示す次のログ メッセージが表示されます。

[INFO] Deployment(default) is successfully created
[INFO] Starting Spring App after deploying artifacts...
[INFO] Deployment Status: Running
[INFO]   InstanceName:demo-default-x-xxxxxxxxxx-xxxxx  Status:Running Reason:null       DiscoverStatus:UNREGISTERED
[INFO]   InstanceName:demo-default-x-xxxxxxxxx-xxxxx  Status:Terminating Reason:null       DiscoverStatus:UNREGISTERED
[INFO] Getting public url of app(demo)...
[INFO] Application url: https://<your-Azure-Spring-Apps-instance-name>-demo.azuremicroservices.io

アプリを検証する

デプロイが完了したら、出力のアプリケーション URL を使用してアプリケーションにアクセスします。 次の手順を使用して、アプリのログをチェックし、デプロイの問題があれば調査します。

  1. デプロイメント セクションの出力ページから出力アプリケーションの URL にアクセスします。

  2. Azure Spring Apps インスタンスの[概要] ページのナビゲーション ウィンドウで、[ログ] を選択してアプリのログを確認します。

サンプルの確認

次の手順に従ってサンプルを操作します。

  1. サインインまたはサインアウトの状態が、画面の中央に表示されます。
  2. 画面の隅にある状況依存ボタンを選択します。 このボタンは、アプリを最初に実行するときにサインインと表示します。 または、トークンの詳細を選択します。 このページは保護されており、認証が必要であるため、サインイン ページに自動でリダイレクトされます。
  3. 次のページに記載された指示に従い、Microsoft Entra ID テナントのアカウントでサインインします。
  4. 同意画面に、必要となるスコープが表示されます。
  5. サインイン フローが正常に完了するとホーム ページにリダイレクトされ、どのボタンでサインイン フローをトリガーした化に応じて、サインインの状態ページまたはトークンの詳細ページが表示されます。
  6. 状況依存ボタンの表示がサインアウトに変わり、ユーザー名が表示されます。
  7. ホーム ページを表示している場合は、IDトークンの詳細を選択して、IDトークンのデコードされた要求の一部を表示します。
  8. 隅にあるボタンを使用してサインアウトします。新しい状態が状態ページに反映されます。

コードについて

このサンプルでは、Java 用 Microsoft Entra ID Spring Boot Starter クライアント ライブラリを使用して Microsoft Entra ID テナントへのユーザーのサインインを行う方法を説明します。 このサンプルでは、Spring Oauth2 クライアントと Spring Web ブート スターターも使用します。 このサンプルは Microsoft Entra ID から取得した ID トークンにある要求を使用して、サインインしているユーザーの詳細を表示します。

内容

次の表に、サンプル プロジェクト フォルダーの内容を示します。

ファイル/フォルダー 説明
AppCreationScripts/ Microsoft Entra ID アプリの登録を自動で構成するスクリプト。
pom.xml アプリケーションの依存関係。
src/main/resources/templates/ UI 用の Thymeleaf テンプレート。
src/main/resources/application.yml アプリケーションと Microsoft Entra ID Boot Starter ライブラリの構成。
src/main/java/com/microsoft/azuresamples/msal4j/msidentityspringbootwebapp/ このディレクトリには、メイン アプリケーションのエントリ ポイント、コントローラー、および構成のクラスが含まれています。
.../MsIdentitySpringBootWebappApplication.java Main クラス。
.../SampleController.java エンドポイントをマッピングするコントローラー。
.../SecurityConfig.java セキュリティ構成 - たとえば、認証が必要なルートを構成します。
.../Utilities.java ユーティリティ クラス - たとえば、ID トークン要求をフィルター処理します。
CHANGELOG.md サンプルに対する変更の一覧。
CONTRIBUTING.md サンプルに貢献するためのガイドライン。
ライセンス サンプルのライセンス。

ID トークン要求

アプリはトークンの詳細を抽出するために、要求マッピングで Spring Security の AuthenticationPrincipalOidcUser のオブジェクトを使用します (次の例を参照)。 このアプリで ID トークン要求を使用する方法については、サンプル コントローラーを参照してください。

import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
//...
@GetMapping(path = "/some_path")
public String tokenDetails(@AuthenticationPrincipal OidcUser principal) {
    Map<String, Object> claims = principal.getIdToken().getClaims();
}

アプリはサインインを行う際に、Java 用 Microsoft Entra ID Spring Boot Starter クライアント ライブラリで自動的に構成された Microsoft Entra ID サインイン エンドポイントに対して要求を行います (次の例を参照)。

<a class="btn btn-success" href="/oauth2/authorization/azure">Sign In</a>

アプリはサインアウトを行う際に、logout エンドポイントへの POST 要求を行います (次の例を参照)。

<form action="#" th:action="@{/logout}" method="post">
  <input class="btn btn-warning" type="submit" value="Sign Out" />
</form>

認証に依存する UI 要素

アプリの UI テンプレート ページに、ユーザーが認証済みかどうかに応じて表示するコンテンツを決定するためのシンプルなロジックがあります (Spring Security Thymeleaf タグを使用した次の例を参照)。

<div sec:authorize="isAuthenticated()">
  this content only shows to authenticated users
</div>
<div sec:authorize="isAnonymous()">
  this content only shows to not-authenticated users
</div>

AADWebSecurityConfigurerAdapter を使用してルートを保護する

既定では、ID トークンの詳細ページを保護するために、サインインしているユーザーのみにアクセスを許可します。 アプリは、application.yml ファイルにある app.protect.authenticated プロパティを使用して、これらのルートを構成します。 アプリの特定の要件を構成するには、HttpSecurity インスタンスに AadWebApplicationHttpSecurityConfigurer#aadWebApplication メソッドを適用します。 例については、このアプリの SecurityConfig クラスを参照してください (次の例を参照)。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig  {
    
    @Value("${app.protect.authenticated}")
    private String[] allowedOrigins;
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
            .and()
            .authorizeHttpRequests(auth -> auth
                .requestMatchers(allowedOrigins).authenticated()
                .anyRequest().permitAll()
                );
        // @formatter:on
        return http.build();
    }

    @Bean
    @RequestScope
    public ServletUriComponentsBuilder urlBuilder() {
        return ServletUriComponentsBuilder.fromCurrentRequest();
    }    
}

詳細

このシナリオおよびその他のシナリオでの OAuth 2.0 プロトコルの動作の詳細については、「Microsoft Entra ID の認証シナリオ」を参照してください。