Azure Active Directory B2C を使用したサインインを Spring Web アプリに追加する

この記事では、Microsoft Entra ID 用 Spring Boot Starter 搭載の Spring Initializr を使用して、サインイン機能を備えた Java アプリを作成する方法について説明します。

このチュートリアルでは、次の作業を行う方法について説明します。

  • Spring Initializr を使用して Java アプリケーションを作成する
  • Azure Active Directory B2C を構成する
  • Spring Boot クラスと注釈を使用してアプリケーションをセキュリティで保護する
  • Java アプリケーションをビルドしてテストする

Microsoft Entra ID は、Microsoft のクラウドスケールのエンタープライズ ID ソリューションです。 Azure Active Directory B2C は、Microsoft Entra ID の機能セットを補完することにより、御社がその企業-消費者間 (B2C) アプリケーションを管理して、顧客や消費者、市民にアクセスを提供できるようにします。

前提条件

重要

この記事の手順を完了するには、Spring Boot 2.5 以降のバージョンが必要です。

Spring Initializr を使用したアプリの作成

  1. https://start.spring.io/ にアクセスします。

  2. このガイダンスに従って、値を入力します。 ラベルとレイアウトは、ここに示されている画像とは異なる場合があります。

    • [プロジェクト] で、[Maven プロジェクト] を選択します。
    • [言語] で、[Java] を選択します。
    • [Spring Boot] で、[2.7.11] を選択します。
    • [グループ][アーティファクト] および [名前] で、短い説明の文字列を使用して同じ値を入力します。 入力するにつれ、一部が UI に自動的に入力される場合があります。
    • [依存関係] ペインで、[依存関係の追加] を選択します。 UI を使用して Spring Web と、Spring Security に対する依存関係を追加します。

    Note

    Spring Security 5.5.1、5.4.7、5.3.10、5.2.11 が、CVE レポート 「CVE-2021-22119: Denial-of-Service attack with spring-security-oauth2-client」に対応するためにリリースされています。 これより古いバージョンを使用している場合は、アップグレードしてください。

  3. [プロジェクトの生成] を選択してから、ローカル コンピューター上のパスにプロジェクトをダウンロードします。 ダウンロードしたファイルを、プロジェクトに基づいて名前が付けられたディレクトリに移動し、そのファイルを解凍します。 ファイルのレイアウトは以下のようになるはずです。yourProject の代わりに、[グループ] に入力した値が示されます。

    .
    ├── HELP.md
    ├── mvnw
    ├── mvnw.cmd
    ├── pom.xml
    └── src
        ├── main
        │   ├── java
        │   │   └── yourProject
        │   │       └── yourProject
        │   │           └── YourProjectApplication.java
        │   └── resources
        │       ├── application.properties
        │       ├── static
        │       └── templates
        └── test
            └── java
                └── yourProject
                    └── yourProject
                        └── YourProjectApplicationTests.java
    

Microsoft Entra インスタンスの作成と初期化

Active Directory インスタンスを作成する

  1. https://portal.azure.com にログインします。

  2. [リソースの作成] を選択します。 Azure Active Directory B2C を検索します。

    Azure portal を使用して新しい Azure Active Directory B2C インスタンスを作成する。

  3. [作成] を選択します

    Azure Active Directory B2C の Azure Marketplace エントリ。

  4. [Create a new Azure AD B2C Tenant](新しい Azure AD B2C テナントの作成) を選択します。

    新しい Azure AD B2C テナントを作成する Azure portal オプション。

  5. [組織名][初期ドメイン名] では、適切な値を指定してから [作成] を選択します。

    Azure AD B2C のテナント作成画面。

  6. Active Directory の作成が完了したら、右上隅にある自分のアカウントを選択し、[ディレクトリの切り替え] を選択してから、作成したディレクトリを選択します。 新しいテナント ホーム ページにリダイレクトされます。 次に b2c を検索して [Azure AD B2C] を選択します。

    Azure AD B2C サービスを見つける。

Spring Boot アプリのアプリケーション登録を追加する

  1. [管理] ペインで、[アプリの登録] を選択し、次に [新しい登録] を選択します。

    Azure AD B2C アプリの登録画面を示す Azure portal のスクリーンショット。

  2. [名前] フィールドに、アプリの名前を入力して、[登録] を選択します。

    Azure AD B2C アプリケーション登録フォーム。

  3. [管理] ペインに戻り、[アプリの登録] を選択し、作成したアプリケーション名を選択します。

    表示名を選択したアプリ登録画面。

  4. [認証][プラットフォームの追加][Web] の順に選択します。 [リダイレクト URI]http://localhost:8080/login/oauth2/code/ に設定し、[構成] を選択します。

    認証で選択されたオプション、[プラットフォームの追加]、[Web]。

    [リダイレクト URI] フィールドが選択された [Web の構成] 画面。

アプリのアプリ シークレットを追加する

[証明書とシークレット] を選択し、[新しいクライアント シークレット] を選択します。 シークレットの説明を入力し、[追加] を選択します。 シークレットを作成した後、シークレット値の横にあるコピー アイコンを選択して値をコピーして、この記事で後半で使用します。

クライアント シークレットの追加画面。

[コピー] ボタンが選択されている [証明書とシークレット] 画面。

Note

[認定資格証&シークレット] セクションから移動して再び戻ると、シークレットの値を表示できなくなります。 その場合は、別のシークレットを作成し、今後の使用のためにコピーする必要があります。 場合によっては、生成されたシークレット値に、application.yml ファイルに含める場合に問題となる文字 (円記号やバッククォートなど) が含まれていることがあります。 その場合は、そのシークレットを破棄し、別のものを生成します。

ユーザー フローの追加

  1. お使いのテナント メイン ページに移動します。 左ペインの [ポリシー] セクションで、[ユーザー フロー][新しいユーザー フロー] の順に選択します。

  2. このチュートリアルから離れて、別のチュートリアルを実行し、完了したらこのチュートリアルに戻ります。 他のチュートリアルに移動するときに注意すべきいくつかの点を以下に示します。

    • [新しいユーザー フロー] を選択するよう求める手順から開始します。
    • このチュートリアルで webapp1 が示された場合は、代わりに [グループ] に入力した値を使用します。
    • フローから返される要求を選択する場合は、確実に [表示名] が選択されるようにしてください。 この要求がないと、このチュートリアルでビルドされるアプリは機能しません。
    • ユーザー フローを実行するように求められた場合は、以前に指定したリダイレクト URL がまだアクティブになっていません。 フローは引き続き実行できますが、リダイレクトは正常に完了しません。 これは予期されることです。
    • 「次のステップ」に到達したら、このチュートリアルに戻ります。

    チュートリアル: Azure Active Directory B2C でユーザー フローを作成する のすべての手順を実行して、「サインアップとサインイン」、「プロファイルの編集」、「パスワードのリセット」のユーザー フローを作成します。

    Azure AD B2C は、ローカル アカウントとソーシャル ID プロバイダーをサポートしています。 GitHub ID プロバイダーを作成する例については、「Azure Active Directory B2C を使用して GitHub アカウントでのサインアップおよびサインインを設定する」を参照してください。

アプリの構成およびコンパイル

Azure AD B2C インスタンスといくつかのユーザー フローを作成したので、Spring アプリを Azure AD B2C インスタンスに接続します。

  1. コマンド ラインで、Spring Initializr からダウンロードした .zip ファイルを解凍したディレクトリに移動します。

  2. プロジェクトの親フォルダーに移動し、テキスト エディターで pom.xml Maven プロジェクト ファイルを開きます。

  3. Spring OAuth2 セキュリティの依存関係を pom.xml に追加します。

    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory-b2c</artifactId>
        <version>See Below</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
        <version>See Below</version>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        <version>See Below</version>
    </dependency>
    

    spring-cloud-azure-starter-active-directory-b2c には、使用可能な最新バージョンを使用します。 mvnrepository.com を使用して、これを確認できる場合があります。

    spring-boot-starter-thymeleaf には、先ほど選択した Spring Boot のバージョン (2.3.4.RELEASE など) に対応するバージョンを使用します。

    thymeleaf-extras-springsecurity5 には、使用可能な最新バージョンを使用します。 mvnrepository.com を使用して、これを確認できる場合があります。 このドキュメントの執筆時点では、最新バージョンは 3.0.4.RELEASE です。

  4. pom.xml ファイルを保存して閉じます。

    • mvn -DskipTests clean install を実行して、依存関係が正しいことを確認します。 そうでない場合は、「BUILD SUCCESS」を参照して、問題をトラブルシューティングし、解決してから続行してください。
  5. プロジェクトの src/main/resources フォルダーに移動し、テキスト エディターで application.yml ファイルを作成します。

  6. 前に作成した値を使用して、アプリ登録の設定を指定します。たとえば、以下のとおりです。

    spring:
      cloud:
        azure:
          active-directory:
            b2c:
              enabled: true
              base-uri: https://<your-tenant-initial-domain-name>.b2clogin.com/<your-tenant-initial-domain-name>.onmicrosoft.com/
              credential:
                client-id: <your-application-ID>
                client-secret: '<secret-value>'
              login-flow: sign-up-or-sign-in
              logout-success-url: <your-logout-success-URL>
              user-flows:
                sign-up-or-sign-in: <your-sign-up-or-sign-in-user-flow-name> 
                profile-edit: <your-profile-edit-user-flow-name> 
                password-reset: <your-password-reset-user-flow-name> 
              user-name-attribute-name: <your-user-name-attribute-name> 
    

    client-secret 値が単一引用符で囲まれていることに注目してください。 これが必要なのは、<secret-value> の値には、YAML に存在する場合に単一引用符で囲む必要があるいくつかの文字がほぼ確実に含まれるためです。

    Note

    このドキュメントの執筆時点で、application.yml で使用できる Active Directory B2C Spring の統合の値の完全な一覧を以下に示します。

    spring:
      cloud:
        azure:
          active-directory:
            b2c:
              enabled: true
              base-uri:
              credential:
                client-id:
                client-secret:
              login-flow:  
              logout-success-url:
              user-flows:
                sign-up-or-sign-in:
                profile-edit: # optional
                password-reset: # optional
              user-name-attribute-name:
    

    application.yml ファイルは、GitHub 上の spring-cloud-azure-starter-active-directory-b2c サンプル: aad-b2c-web-application で入手できます。

  7. application.yml ファイルを保存して閉じます。

  8. src/main/java/<yourGroupId>/<yourGroupId>controller という名前のフォルダーを作成し、<yourGroupId> を、[グループ] で入力した値に置き換えます。

  9. controller フォルダーに "java" という名前の新しい Java ファイルを作成し、テキスト エディターで開きます。

  10. 次のコードを入力し、適宜、yourGroupId を変更してから、ファイルを保存して閉じます。

    package yourGroupId.yourGroupId.controller;
    
    import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
    import org.springframework.security.oauth2.core.user.OAuth2User;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class WebController {
    
        private void initializeModel(Model model, OAuth2AuthenticationToken token) {
            if (token != null) {
                final OAuth2User user = token.getPrincipal();
    
                model.addAttribute("grant_type", user.getAuthorities());
                model.addAllAttributes(user.getAttributes());
            }
        }
    
        @GetMapping(value = "/")
        public String index(Model model, OAuth2AuthenticationToken token) {
            initializeModel(model, token);
    
            return "home";
        }
    
        @GetMapping(value = "/greeting")
        public String greeting(Model model, OAuth2AuthenticationToken token) {
            initializeModel(model, token);
    
            return "greeting";
        }
    
        @GetMapping(value = "/home")
        public String home(Model model, OAuth2AuthenticationToken token) {
            initializeModel(model, token);
    
            return "home";
        }
    }
    

    コントローラー内のすべてのメソッドで initializeModel() が呼び出され、そのメソッドで model.addAllAttributes(user.getAttributes()); が呼び出されるため、src/main/resources/templates 内の任意の HTML ページから、${name}${grant_type}${auth_time} など、それらの属性のいずれかにアクセスできます。 user.getAttributes() から返される値は、実際には認証用の id_token の要求です。 使用可能な要求の完全な一覧については、「Microsoft ID プラットフォームの ID トークン」を参照してください。

  11. src/main/java/<yourGroupId>/<yourGroupId>security という名前のフォルダーを作成し、yourGroupId を、[グループ] で入力した値に置き換えます。

  12. security フォルダーに "WebSecurityConfiguration.java" という名前の新しい Java ファイルを作成し、テキスト エディターで開きます。

  13. 次のコードを入力し、適宜、yourGroupId を変更してから、ファイルを保存して閉じます。

    package yourGroupId.yourGroupId.security;
    
    import com.azure.spring.cloud.autoconfigure.aadb2c.AadB2cOidcLoginConfigurer;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @EnableWebSecurity
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        private final AadB2cOidcLoginConfigurer configurer;
    
        public WebSecurityConfiguration(AadB2cOidcLoginConfigurer configurer) {
            this.configurer = configurer;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .apply(configurer)
            ;
        }
    }
    
  14. home.html ファイルを spring-cloud-azure-starter-active-directory-b2c sample: aad-b2c-web-application から src/main/resources/templates にコピーし、${your-profile-edit-user-flow}${your-password-reset-user-flow} を以前に作成したユーザー フローの名前で置き換えます。

アプリのビルドとテスト

  1. コマンド プロンプトを開き、ディレクトリをアプリの pom.xml ファイルがあるフォルダーに変更します。

  2. Spring Boot アプリケーションを Maven でビルドし、実行します。次に例を示します。

    Note

    ローカルの Spring Boot アプリの実行に使用されるシステム クロックに準じた時刻が正確であることは、非常に重要です。 OAuth 2.0 を使用する場合、クロックのずれの許容範囲はごくわずかです。 誤差が 3 分でもサインインは失敗し、[invalid_id_token] An error occurred while attempting to decode the Jwt: Jwt used before 2020-05-19T18:52:10Z のようなエラーが示されることがあります。 このドキュメントの執筆時点では、time.gov に、クロックが実際の時刻からどれくらいずれているかを示すインジケーターがあります。 アプリは、+0.019 秒のずれで正常に実行されました。

    mvn -DskipTests clean package
    mvn -DskipTests spring-boot:run
    
  3. Maven によってアプリケーションがビルドされ、起動したら、Web ブラウザーで http://localhost:8080/ を開きます。ログイン ページにリダイレクトされます。

    Web アプリのログインページ。

  4. サインインに関するテキストを含むリンクを選択します。 Azure AD B2C にリダイレクトされ、認証プロセスが開始されるはずです。

  5. 正常にログインすると、ブラウザーにサンプルの home page が表示されます。

    Web アプリのログインが成功。

トラブルシューティング

以下のセクションでは、発生する可能性のあるいくつかの問題の解決方法について説明します。

属性に属性名がない

サンプルを実行しているとき、Missing attribute 'name' in attributes メッセージの例外が発生することがあります。 この例外のログは、次の出力のようになります。

java.lang.IllegalArgumentException: Missing attribute 'name' in attributes
at org.springframework.security.oauth2.core.user.DefaultOAuth2User.<init>(DefaultOAuth2User.java:67) ~[spring-security-oauth2-core-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.<init>(DefaultOidcUser.java:89) ~[spring-security-oauth2-core-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService.loadUser(OidcUserService.java:144) ~[spring-security-oauth2-client-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService.loadUser(OidcUserService.java:63) ~[spring-security-oauth2-client-5.3.6.RELEASE.jar:5.3.6.RELEASE]

このエラーが発生した場合は、「チュートリアル: Azure Active Directory B2C 内にユーザー フローを作成する」で作成したユーザー ワークフローをよく調べてください。 ユーザー ワークフローを作成するとき、[ユーザー属性と要求] で、必ず [表示名] の属性と要求を選択してください。 また、必ず application.yml ファイルで user-name-attribute-name を正しく構成してください。

B2C エンドポイントへのサインインがループになる

この問題の原因として、localhost の Cookie が汚れていることが考えられます。 localhost の Cookie をクリーンアップしてから、もう一度お試しください。

まとめ

このチュートリアルでは、Azure Active Directory B2C スターターを使用した新しい Java Web アプリケーションの作成、新しい Azure AD B2C テナントの構成とそこでの新しいアプリケーションの登録を行ってから、Spring の注釈とクラスを使用して Web アプリを保護するようにアプリケーションを構成しました。

リソースをクリーンアップする

予想外の課金を防ぐために、この記事で作成したリソースが不要になったら、Azure portal を使用して削除してください。

次のステップ

Spring および Azure の詳細については、Azure ドキュメント センターで引き続き Spring に関するドキュメントをご確認ください。