8/11 (火)
Spring Boot 4.1 + Spring Security 7.1 で OIDC/SAML 認証を実施
Spring Boot + Spring Security + Thyemeleaf を使って、OIDC/SAML 認証の検証を行っている。
先に IdP に OIDC/SAML 認証のアプリケーションを作成し、そのパラメーターを github.com/nminoru/misc/blob/master/java/thymeleaf_test/src/main/resources/application.yml に記載する。
Entra ID にアプリケーションを作成する方法を記載する。
OIDC 認証用のアプリケーションを作成
- 左メニューの「App registrations」を選択する。
- 「+ New registration」をクリックする。
- Register an application で初期アプリケーションを作成する。
- 「Name」に任意のアプリケーション名を設定する
- 「Supported account types」は「Single tenant only」を選択する
- 「Register」で作成する。
- 左メニューの「App registrations」をクリックして、さきほど作成したアプリケーションを選択する。
- 中メニューから「Overview」を選択する。
- 「Application (client) ID」の UUID を保存する。 これは application.yml の client-id に記載する。
- Redirect URIs の横のリンクをクリックし、「Redirect URI configuration」でリダイレクトURLを追加する。 Redirect URI は Spring Boot + Spring Securityの場合は「https://www-test1.example.com/login/oauth2/registrationId」になる。
- 中メニューから「Certificates & secrets」を選択し、「Client secrets」タブを選択し、「+ New client secret」を作成する。 作成が終わったら画面上に表示される Value の「zXJ8Q~xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx」を保存する。 これは application.yml の client-secret に記載する。 クライアントシークレットは作成直後しか表示されないので、忘れた場合は再作成する。
- 中メニューから「API permissions」を選択する。
- 「+ Add a permission」を押して、「Microsoft Graph」→「Deletegated permissions」→ 「email/openid/profile」「User.Read」を追加する。
- 追加後に「Grant admin consent for tenantname」をクリックする。
- 左メニューの「Enterprise apps」をクリックして、中メニューの「All applications」をクリックし、作成中のアプリケーションを選択する。
OIDC 認証を誰に許可するかを指定する。
- 全てのユーザーに許可する場合は、中メニューの「Properties」をクリックし、「Assignment required?」を No にする。
- 指定のユーザーにだけ許可する場合は、中メニューの「Users and groups」を許可するユーザー/グループを指定する。 ただし Entra ID (workforce tenant) は Free 版ではグループ指定はできない。
SAML 認証用のアプリケーションを作成
SAML 認証のトラブル
Spring Boot + Spring Security を使った SAML 認証はかなりトラブルにみまわれた。 公式ドキュメントは以下のようなものがありこれを読み漁ったり、ChatGPT や Gemini に聞きまくったがうまくいかない。
- Spring | Spring Boot / Reference / Security / SAML 2.0
- Spring | Spring Boot / Appendix / Common Application Properties
- Spring | Spring Security / Servlet Applications / SAML2
どうも SAML 関係の部分がバージョンによって大きく変遷しているため、インターネット上に存在する Spring Boot + Spring Security の SAML 認証周りのドキュメントが古くなって、それを学習した AI が正しい答えを返せないようだ。
SAML 認証のための application.yml の記法
application.yml は SAML 認証を登録するには、以下のコードの赤字のように指定する必要がある。 古い書き方は認識されない。
spring:
security:
saml2:
relyingparty:
registration:
registrationId:
assertingparty:
entity-id: <entity-id>
verification.credentials:
- certificate-location: <certificate-location>
# 一部のマニュアルには single-sign-on-service-location や sso-url があるが最新版では動作しない
singlesignon.url: <single-sign-on-url>
# SAML認証要求(AuthnRequest)の署名検証を行うかどうか
# 一部のマニュアルには singlesignon.sign-request という記述もあるが最新版では動作しない
single-sign-on.sign-request: false
# single-sign-on.sign-request: true の場合は以下が必要
signing:
credentials:
- private-key-location: classpath:sp.key
certificate-location: classpath:sp.crt
# Spring Security 7.0 以降メタデータ読み込みは削除されている
# metadata-url は動作しない
application.yml で SAML 認証コードの自動構成する場合
application.yml に SAML 認証を登録しても、java.lang.IllegalArgumentException: relyingPartyRegistrationRepository cannot be null のようにエラーが出る。
Caused by: java.lang.IllegalArgumentException: relyingPartyRegistrationRepository cannot be null
at org.springframework.util.Assert.notNull(Assert.java:182) ~[spring-core-7.0.8.jar!/:7.0.8]
at org.springframework.security.saml2.provider.service.web.OpenSaml5AuthenticationTokenConverter.<init>(OpenSaml5AuthenticationTokenConverter.java:52) ~[spring-security-saml2-service-provider-7.1.0.jar!/:7.1.0]
at org.springframework.security.config.annotation.web.configurers.saml2.Saml2LoginConfigurer.getAuthenticationConverter(Saml2LoginConfigurer.java:428) ~[spring-security-config-7.1.0.jar!/:7.1.0]
at org.springframework.security.config.annotation.web.configurers.saml2.Saml2LoginConfigurer.init(Saml2LoginConfigurer.java:279) ~[spring-security-config-7.1.0.jar!/:7.1.0]
at org.springframework.security.config.annotation.web.configurers.saml2.Saml2LoginConfigurer.init(Saml2LoginConfigurer.java:117) ~[spring-security-config-7.1.0.jar!/:7.1.0]
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:371) ~[spring-security-config-7.1.0.jar!/:7.1.0]
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:333) ~[spring-security-config-7.1.0.jar!/:7.1.0]
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:38) ~[spring-security-config-7.1.0.jar!/:7.1.0]
これは application.yml に記述した SAML2 認証の記述が無視されているためである。 公式ドキュメントには RelyingPartyRegistration を手動で構築せよとある。
実際には application.yml の記述に基づく認証コードの自動構築は可能である。 Slack の以下の java - In Spring Boot 4.0.2 SAML properties cannot be read from the YAML file のスレッドに回答が記載されていたが、以下のライブラリに対する依存関係を追加すると解決した。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security-saml2</artifactId>
</dependency>