| 
					
				 | 
			
			
				@@ -4,6 +4,194 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 Spring Security 6.4 provides a number of new features. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 Below are the highlights of the release, or you can view https://github.com/spring-projects/spring-security/releases[the release notes] for a detailed listing of each feature and bug fix. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-- https://github.com/spring-projects/spring-security/issues/4186[gh-4186] - Support `RoleHierarchy` in `AclAuthorizationStrategyImpl` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-- https://github.com/spring-projects/spring-security/issues/15136[gh-15136] - Support `RoleHierarchy` Bean in `authorizeHttpRequests` Kotlin DSL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+== Method Security 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* All xref:servlet/authorization/method-security.adoc#using_metannotation-method-interceptors[method security annotations] now support {spring-framework-api-url}org/springframework/core/annotation/AliasFor.html[Framework's `@AliasFor`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `@AuthenticationPrincipal` and `@CurrentSecurityContext` now support xref:servlet/authorization/method-security.adoc#_templating_meta_annotation_expressions[annotation templates]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+This means that you can now use Spring's meta-annotation support like so: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[tabs] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Java:: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,java,role="primary"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Target(TargetType.TYPE) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Retention(RetentionPolicy.RUNTIME) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@AuthenticationPrincipal("claims['{claim}']") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@interface CurrentUsername { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	String claim() default "sub"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@GetMapping 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public String method(@CurrentUsername("username") String username) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Kotlin:: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,kotlin,role="secondary"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+annotation CurrentUsername(val claim: String = "sub") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@GetMapping 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fun method(@CurrentUsername("username") val username: String): String { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* https://github.com/spring-projects/spring-security/issues/13490[Several] https://github.com/spring-projects/spring-security/issues/13234[improvements] https://github.com/spring-projects/spring-security/issues/15097[were made] to align Security's annotation search with ``AbstractFallbackMethodSecurityMetadataSource``'s algorithm. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+This aids in migration from earlier versions of Spring Security. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+== OAuth 2.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `oauth2Login()` now accepts https://github.com/spring-projects/spring-security/pull/15237[`OAuth2AuthorizationRequestResolver` as a `@Bean`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* OIDC Back-Channel support now accepts https://github.com/spring-projects/spring-security/issues/15003[logout tokens of type `logout+jwt`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+== SAML 2.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* Added xref:servlet/saml2/opensaml.adoc[OpenSAML 5 Support]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Now you can use either OpenSAML 4 or OpenSAML 5; by default, Spring Security will select the write implementations based on what's on your classpath. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* Using EntityIDs for the `registrationId` is simplified. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+A common pattern is to identify asserting parties by their `entityID`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+In previous versions, this required directly configuring `OpenSamlAuthenticationRequestResolver`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Now, the request resolver looks by default for the `registrationId` https://github.com/spring-projects/spring-security/issues/15017[as a request parameter] in addition to looking for it in the path. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+This allows you to use `RelyingPartyRegistrations` or `OpenSaml4/5AssertingPartyMetadataRepository` without also needing to modify the `registrationId` values or customize the request resolver. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Relatedly, you can now configure your `authenticationRequestUri` to xref:servlet/saml2/login/authentication-requests.adoc#configuring-authentication-request-uri[contain a query parameter] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* Asserting Parties can now be refreshed in the background according to the metadata's expiry. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+For example, you can now use xref:servlet/saml2/metadata.adoc#using-assertingpartymetadatarepository[`OpenSaml5AssertingPartyMetadataRepository`] to do: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[tabs] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Java:: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,java,role="primary"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Component 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class RefreshableRelyingPartyRegistrationRepository implements IterableRelyingPartyRegistrationRepository { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private final AssertingPartyMetadataRepository assertingParties = OpenSaml5AssertingPartyMetadataRepository 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		.fromTrustedMetadataLocation("https://idp.example.org").build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public RelyingPartyRegistration findByRegistrationId(String registrationId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		AssertingPartyMetadata assertingParty = this.assertingParties.findByEntityId(registrationId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// relying party configurations 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Kotlin:: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,kotlin,role="secondary"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Component 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+open class RefreshableRelyingPartyRegistrationRepository: IterableRelyingPartyRegistrationRepository { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private val assertingParties: AssertingPartyMetadataRepository = OpenSaml5AssertingPartyMetadataRepository 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		.fromTrustedMetadataLocation("https://idp.example.org").build() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	override fun findByRegistrationId(String registrationId): RelyingPartyRegistration { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		val assertingParty = this.assertingParties.findByEntityId(registrationId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// relying party configurations 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			.build() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+This implementation also supports the validation of a metadata's signature. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* You can now sign https://github.com/spring-projects/spring-security/pull/14916[relying party metadata] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `RelyingPartyRegistrationRepository` results can now be javadoc:org.springframework.security.saml2.provider.service.registration.CachingRelyingPartyRegistrationRepository[cached]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+This is helpful if you want to defer the loading of the registration values til after application startup. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+It is also helpful if you want to control when metadata gets refreshed. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* To align with the SAML 2.0 standard, the metadata endpoint now https://github.com/spring-projects/spring-security/issues/15147[uses the `application/samlmetadata+xml` MIME type] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+== Web 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* CSRF BREACH tokens are now https://github.com/spring-projects/spring-security/issues/15187[more consistent] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* The Remember Me cookie now is https://github.com/spring-projects/spring-security/pull/15203[more customizable] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* Security Filter Chain is now improved. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Specifically, the following arrangement is invalid since an any request filter chain comes before all other filter chains: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[tabs] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Java:: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,java,role="primary"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Bean  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Order(0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+SecurityFilterChain api(HttpSecurity http) throws Exception { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    http 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .authorizeHttpRequests(...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .httpBasic(...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return http.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Bean  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Order(1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+SecurityFilterChain app(HttpSecurity http) throws Exception { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    http 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .securityMatcher("/app/**") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .authorizeHttpRequests(...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .formLogin(...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return http.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Kotlin:: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,kotlin,role="secondary"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Bean  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Order(0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fun api(val http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return http.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Bean  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Order(1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fun app(val http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		securityMatcher("/app/**") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return http.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+You can read more https://github.com/spring-projects/spring-security/issues/15220[in the related ticket]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+== Kotlin 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* The Kotlin DSL now supports https://github.com/spring-projects/spring-security/issues/14935[SAML 2.0] and https://github.com/spring-projects/spring-security/issues/15171[`GrantedAuthorityDefaults`] and https://github.com/spring-projects/spring-security/issues/15136[`RoleHierarchy`] ``@Bean``s 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `@PreFilter` and `@PostFilter` are https://github.com/spring-projects/spring-security/pull/15095[now supported] in Kotlin 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* The Kotlin Reactive DSL now supports https://github.com/spring-projects/spring-security/pull/15013[`SecurityContextRepository`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+== Acl 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `AclAuthorizationStrategyImpl` now https://github.com/spring-projects/spring-security/issues/4186[supports `RoleHierarchy`] 
			 |