最新の安定バージョンについては、Spring Security 6.5.3 を使用してください!

SAML 移行

次の手順は、SAML 2.0 の構成方法に関する変更に関連しています。

OpenSAML 4 を使用する

OpenSAML 3 はサポートが終了しました。そのため、Spring Security 6 はそのサポートを中止し、OpenSAML ベースラインを 4 に上げました。

アップグレードの準備として、OpenSAML 3 ではなく 4 に依存するように pom を更新します。

<dependencyManagement>
    <dependency>
        <groupId>org.opensaml</groupId>
        <artifactId>opensaml-core</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.opensaml</groupId>
        <artifactId>opensaml-saml-api</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.opensaml</groupId>
        <artifactId>opensaml-saml-impl</artifactId>
        <version>4.2.1</version>
    </dependency>
</dependencyManagement>
dependencies {
    constraints {
        api "org.opensaml:opensaml-core:4.2.1"
        api "org.opensaml:opensaml-saml-api:4.2.1"
        api "org.opensaml:opensaml-saml-impl:4.2.1"
    }
}

Spring Security 6 の SAML サポートに更新するには、少なくとも OpenSAML 4.1.1 を使用する必要があります。

OpenSaml4AuthenticationProvider を使用する

OpenSAML 3 と 4 の両方を同時にサポートするために、Spring Security は OpenSamlAuthenticationProvider と OpenSaml4AuthenticationProvider をリリースしました。6.0 では、OpenSAML3 のサポートが削除されたため、OpenSamlAuthenticationProvider も削除されました。

OpenSamlAuthenticationProvider のすべてのメソッドが OpenSaml4AuthenticationProvider に 1 対 1 で移植されたわけではありません。そのため、チャレンジするには多少の調整が必要になります。

OpenSamlAuthenticationProvider の次の代表的な使用箇所を検討してください。

  • Java

  • Kotlin

OpenSamlAuthenticationProvider versionThree = new OpenSamlAuthenticationProvider();
versionThree.setAuthoritiesExtractor(myAuthoritiesExtractor);
versionThree.setResponseTimeValidationSkew(myDuration);
val versionThree: OpenSamlAuthenticationProvider = OpenSamlAuthenticationProvider()
versionThree.setAuthoritiesExtractor(myAuthoritiesExtractor)
versionThree.setResponseTimeValidationSkew(myDuration)

これは次のように変更する必要があります。

  • Java

  • Kotlin

Converter<ResponseToken, Saml2Authentication> delegate = OpenSaml4AuthenticationProvider
        .createDefaultResponseAuthenticationConverter();
OpenSaml4AuthenticationProvider versionFour = new OpenSaml4AuthenticationProvider();
versionFour.setResponseAuthenticationConverter((responseToken) -> {
	Saml2Authentication authentication = delegate.convert(responseToken);
	Assertion assertion = responseToken.getResponse().getAssertions().get(0);
	AuthenticatedPrincipal principal = (AuthenticatedPrincipal) authentication.getPrincipal();
	Collection<GrantedAuthority> authorities = myAuthoritiesExtractor.convert(assertion);
	return new Saml2Authentication(principal, authentication.getSaml2Response(), authorities);
});
Converter<AssertionToken, Saml2ResponseValidationResult> validator = OpenSaml4AuthenticationProvider
        .createDefaultAssertionValidatorWithParameters((p) -> p.put(CLOCK_SKEW, myDuration));
versionFour.setAssertionValidator(validator);
val delegate = OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter()
val versionFour = OpenSaml4AuthenticationProvider()
versionFour.setResponseAuthenticationConverter({
    responseToken -> {
        val authentication = delegate.convert(responseToken)
        val assertion = responseToken.getResponse().getAssertions().get(0)
        val principal = (AuthenticatedPrincipal) authentication.getPrincipal()
        val authorities = myAuthoritiesExtractor.convert(assertion)
        return Saml2Authentication(principal, authentication.getSaml2Response(), authorities)
    }
})
val validator = OpenSaml4AuthenticationProvider
        .createDefaultAssertionValidatorWithParameters({ p -> p.put(CLOCK_SKEW, myDuration) })
versionFour.setAssertionValidator(validator)

SAML 2.0 Converter コンストラクターの使用をやめる

Spring Security の SAML 2.0 サポートの初期リリースでは、Saml2MetadataFilter および Saml2AuthenticationTokenConverter は型 Converter のコンストラクターと共に提供されました。このレベルの抽象化により、クラスを進化させるのが難しくなったため、専用のインターフェース RelyingPartyRegistrationResolver が後のリリースで導入されました。

6.0 では、Converter コンストラクターが削除されています。5.8 でこれに備えるには、Converter<HttpServletRequest, RelyingPartyRegistration> を実装するクラスを変更して、代わりに RelyingPartyRegistrationResolver を実装します。

Saml2AuthenticationRequestResolver を使用するように変更

Saml2AuthenticationContextResolver と Saml2AuthenticationRequestFactory は、必要とする Saml2WebSsoAuthenticationRequestFilter と同様に 6.0 で削除されます。それらは Saml2AuthenticationRequestResolver と Saml2WebSsoAuthenticationRequestFilter の新しいコンストラクターに置き換えられます。新しいインターフェースは、2 つのクラス間の不要なトランスポートオブジェクトを削除します。

ほとんどのアプリケーションは何もする必要はありません。ただし、Saml2AuthenticationRequestContextResolver または Saml2AuthenticationRequestFactory を使用または構成する場合は、次の手順を試して、代わりに Saml2AuthenticationRequestResolver を使用して変換してください。

setAuthenticationRequestContextConverter の代わりに setAuthnRequestCustomizer を使用する

たとえば、次のように OpenSaml4AuthenticationReqeustFactory#setAuthenticationRequestContextConverter を呼び出している場合:

  • Java

@Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory() {
    OpenSaml4AuthenticationRequestFactory factory = new OpenSaml4AuthenticationRequestFactory();
	factory.setAuthenticationRequestContextConverter((context) -> {
        AuthnRequestBuilder authnRequestBuilder =  ConfigurationService.get(XMLObjectProviderRegistry.class)
            .getBuilderFactory().getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);
		IssuerBuilder issuerBuilder =  ConfigurationService.get(XMLObjectProviderRegistry.class)
            .getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
        tring issuer = context.getIssuer();
		String destination = context.getDestination();
		String assertionConsumerServiceUrl = context.getAssertionConsumerServiceUrl();
		String protocolBinding = context.getRelyingPartyRegistration().getAssertionConsumerServiceBinding().getUrn();
		AuthnRequest auth = authnRequestBuilder.buildObject();
		auth.setID("ARQ" + UUID.randomUUID().toString().substring(1));
		auth.setIssueInstant(Instant.now());
		auth.setForceAuthn(Boolean.TRUE);
		auth.setIsPassive(Boolean.FALSE);
		auth.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI);
		Issuer iss = issuerBuilder.buildObject();
		iss.setValue(issuer);
		auth.setIssuer(iss);
		auth.setDestination(destination);
		auth.setAssertionConsumerServiceURL(assertionConsumerServiceUrl);
	});
	return factory;
}

ForceAuthn が true に設定されていることを確認するには、代わりに次のようにします。

  • Java

@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationResolver registrations) {
    OpenSaml4AuthenticationRequestResolver reaolver = new OpenSaml4AuthenticationRequestResolver(registrations);
	resolver.setAuthnRequestCustomizer((context) -> context.getAuthnRequest().setForceAuthn(Boolean.TRUE));
	return resolver;
}

また、setAuthnRequestCustomizer は HttpServletRequest に直接アクセスできるため、Saml2AuthenticationRequestContextResolver は必要ありません。setAuthnRequestCustomizer を使用して、必要なこの情報を HttpServletRequest から直接読み取るだけです。

setProtocolBinding の代わりに setAuthnRequestCustomizer を使用する

代わりに:

  • Java

@Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory() {
    OpenSaml4AuthenticationRequestFactory factory = new OpenSaml4AuthenticationRequestFactory();
	factory.setProtocolBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
	return factory;
}

できるよ:

  • Java

@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver() {
	OpenSaml4AuthenticationRequestResolver reaolver = new OpenSaml4AuthenticationRequestResolver(registrations);
	resolver.setAuthnRequestCustomizer((context) -> context.getAuthnRequest()
            .setProtocolBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"));
	return resolver;
}

Spring Security は認証のために POST バインディングのみをサポートするため、現時点でプロトコルバインディングをオーバーライドする価値はあまりありません。

最新の Saml2AuthenticationToken コンストラクターを使用する

初期のリリースでは、Saml2AuthenticationToken はコンストラクターのパラメーターとしていくつかの個別の設定を取りました。これにより、新しいパラメーターを追加する必要があるたびに問題が発生しました。これらの設定のほとんどは RelyingPartyRegistration の一部であるため、RelyingPartyRegistration を提供できる新しいコンストラクターが追加され、コンストラクターがより安定しました。また、OAuth2LoginAuthenticationToken の設計により近いという点でも価値があります。

Saml2WebSsoAuthenticationFilter が行うため、ほとんどのアプリケーションはこのクラスを直接構築しません。ただし、アプリケーションで作成する場合は、次のように変更してください。

  • Java

  • Kotlin

new Saml2AuthenticationToken(saml2Response, registration.getSingleSignOnServiceLocation(),
    registration.getAssertingParty().getEntityId(), registration.getEntityId(), registration.getCredentials())
Saml2AuthenticationToken(saml2Response, registration.getSingleSignOnServiceLocation(),
    registration.getAssertingParty().getEntityId(), registration.getEntityId(), registration.getCredentials())

to:

  • Java

  • Kotlin

new Saml2AuthenticationToken(saml2Response, registration)
Saml2AuthenticationToken(saml2Response, registration)

RelyingPartyRegistration の更新されたメソッドを使用する

Spring Security の SAML サポートの初期リリースでは、特定の RelyingPartyRegistration メソッドとその機能の意味が曖昧でした。RelyingPartyRegistration に機能が追加されるにつれて、メソッド名を仕様言語に合わせた名前に変更して、このあいまいさを明確にする必要が生じました。

RelyingPartyRegstration の廃止されたメソッドは削除されました。それに備えて、次の RelyingPartyRegistration の代表的な使用箇所を検討してください。

  • Java

  • Kotlin

String idpEntityId = registration.getRemoteIdpEntityId();
String assertionConsumerServiceUrl = registration.getAssertionConsumerServiceUrlTemplate();
String idpWebSsoUrl = registration.getIdpWebSsoUrl();
String localEntityId = registration.getLocalEntityIdTemplate();
List<Saml2X509Credential> verifying = registration.getCredentials().stream()
        .filter(Saml2X509Credential::isSignatureVerficationCredential)
        .collect(Collectors.toList());
val idpEntityId: String = registration.getRemoteIdpEntityId()
val assertionConsumerServiceUrl: String = registration.getAssertionConsumerServiceUrlTemplate()
val idpWebSsoUrl: String = registration.getIdpWebSsoUrl()
val localEntityId: String = registration.getLocalEntityIdTemplate()
val verifying: List<Saml2X509Credential> = registration.getCredentials()
        .filter(Saml2X509Credential::isSignatureVerficationCredential)

これは次のように変更する必要があります。

  • Java

  • Kotlin

String assertingPartyEntityId = registration.getAssertingPartyDetails().getEntityId();
String assertionConsumerServiceLocation = registration.getAssertionConsumerServiceLocation();
String singleSignOnServiceLocation = registration.getAssertingPartyDetails().getSingleSignOnServiceLocation();
String entityId = registration.getEntityId();
List<Saml2X509Credential> verifying = registration.getAssertingPartyDetails().getVerificationX509Credentials();
val assertingPartyEntityId: String = registration.getAssertingPartyDetails().getEntityId()
val assertionConsumerServiceLocation: String = registration.getAssertionConsumerServiceLocation()
val singleSignOnServiceLocation: String = registration.getAssertingPartyDetails().getSingleSignOnServiceLocation()
val entityId: String = registration.getEntityId()
val verifying: List<Saml2X509Credential> = registration.getAssertingPartyDetails().getVerificationX509Credentials()

変更されたすべてのメソッドの完全なリストについては、RelyingPartyRegistration の JavaDoc (Javadoc) を参照してください。