mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-14 08:02:22 +00:00
Merge branch '6.5.x'
This commit is contained in:
commit
9c357984d7
7
docs/modules/ROOT/pages/migration-7/acl.adoc
Normal file
7
docs/modules/ROOT/pages/migration-7/acl.adoc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
= ACL
|
||||||
|
|
||||||
|
== Favor `AclPermissionEvaluator`
|
||||||
|
|
||||||
|
`AclEntryVoter`, `AclEntryAfterInvocationProvider`, and `AclPermissionEvaluator` provide the same service, plugged into different Spring Security APIs. Now that `AccessDecisionVoter` and `AfterInvocationProvider` are both deprecated, the corresponding ACL plugins are obsolete.
|
||||||
|
|
||||||
|
As such, begin using `AclPermissionEvaluator` before updating to Spring Security 7.
|
@ -1,68 +1,2 @@
|
|||||||
= Authentication Changes
|
= Authentication Changes
|
||||||
|
|
||||||
== Opaque Token Credentials Will Be Encoded For You
|
|
||||||
|
|
||||||
In order to comply more closely with the Introspection RFC, Spring Security's opaque token support will encode the client id and secret before creating the authorization header.
|
|
||||||
This change means you will no longer have to encode the client id and secret yourself.
|
|
||||||
|
|
||||||
If your client id or secret contain URL-unsafe characters, then you can prepare yourself for this change by doing the following:
|
|
||||||
|
|
||||||
=== Replace Usage of `introspectionClientCredentials`
|
|
||||||
|
|
||||||
Since Spring Security can now do the encoding for you, replace xref:servlet/oauth2/resource-server/opaque-token.adoc#oauth2resourceserver-opaque-introspectionuri-dsl[using `introspectionClientCredentials`] with publishing the following `@Bean`:
|
|
||||||
|
|
||||||
[tabs]
|
|
||||||
======
|
|
||||||
Java::
|
|
||||||
+
|
|
||||||
[source,java,role="primary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
OpaqueTokenIntrospector introspector() {
|
|
||||||
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
|
||||||
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build();
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
Kotlin::
|
|
||||||
+
|
|
||||||
[source,kotlin,role="secondary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
fun introspector(): OpaqueTokenIntrospector {
|
|
||||||
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
|
||||||
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build()
|
|
||||||
}
|
|
||||||
----
|
|
||||||
======
|
|
||||||
|
|
||||||
The above will be the default in 7.0.
|
|
||||||
|
|
||||||
If this setting gives you trouble or you cannot apply it for now, you can use the `RestOperations` constructor instead:
|
|
||||||
|
|
||||||
[tabs]
|
|
||||||
======
|
|
||||||
Java::
|
|
||||||
+
|
|
||||||
[source,java,role="primary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
OpaqueTokenIntrospector introspector() {
|
|
||||||
RestTemplate rest = new RestTemplate();
|
|
||||||
rest.addInterceptor(new BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret));
|
|
||||||
return new SpringOpaqueTokenIntrospector(introspectionUri, rest);
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
Kotlin::
|
|
||||||
+
|
|
||||||
[source,kotlin,role="secondary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
fun introspector(): OpaqueTokenIntrospector {
|
|
||||||
val rest = RestTemplate()
|
|
||||||
rest.addInterceptor(BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret))
|
|
||||||
return SpringOpaqueTokenIntrospector(introspectionUri, rest)
|
|
||||||
}
|
|
||||||
----
|
|
||||||
======
|
|
||||||
|
@ -22,3 +22,82 @@ public void doSomething(Long id) {
|
|||||||
|
|
||||||
You must compile with `-parameters` to ensure that the parameter names are available at runtime.
|
You must compile with `-parameters` to ensure that the parameter names are available at runtime.
|
||||||
For more information about this, please visit the https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#core-container[Upgrading to Spring Framework 6.1 page].
|
For more information about this, please visit the https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#core-container[Upgrading to Spring Framework 6.1 page].
|
||||||
|
|
||||||
|
=== Favor `AnnotationTemplateExpressionDefaults` over `PrePostTemplateDefaults`
|
||||||
|
|
||||||
|
In Spring Security 7, `AnnotationTemplateExpressionDefaults` will be included by default.
|
||||||
|
|
||||||
|
If you are customizing `PrePostTemplateDefaults` or simply want to see how your application responds to `AnnotationTemplateExpressionDefaults`, you can publish an `AnnotationTemplateExpressionDefaults` bean instead of a `PrePostTemplateDefaults` method:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
static AnnotationTemplateExpressionDefaults templateExpressionDefaults() {
|
||||||
|
return new AnnotationTemplateExpressionDefaults();
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
companion object {
|
||||||
|
@Bean
|
||||||
|
fun templateExpressionDefaults() = AnnotationTemplateExpressionDefaults()
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Xml::
|
||||||
|
+
|
||||||
|
[source,xml,role="secondary"]
|
||||||
|
----
|
||||||
|
<b:bean id="templateExpressionDefaults" class="org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults"/>
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
==== I Am Publishing an AuthorizationAdvisor Bean
|
||||||
|
|
||||||
|
If you are publishing an `AuthorizationAdvisor` bean, like `AuthorizationManagerBeforeMethodInterceptor`, `AuthorizationManagerAfterMethodInterceptor`, `PreFilterAuthorizationMethodInterceptor`, or `PostFilterAuthorizationMethodInterceptor`, you can do the same by calling `setTemplateDefaults` with an `AnnotationTemplateExpressionDefaults` instance instead:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDescription.ROLE_INFRASTRUCTURE)
|
||||||
|
static Advisor preFilter() {
|
||||||
|
PreFilterAuthorizationMethodInterceptor interceptor = new PreFilterAuthorizationMethodInterceptor();
|
||||||
|
interceptor.setTemplateDefaults(new AnnotationTemplateExpressionDefaults());
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
companion object {
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDescription.ROLE_INFRASTRUCTURE)
|
||||||
|
fun preFilter(): Advisor {
|
||||||
|
val interceptor = PreFilterAuthorizationMethodInterceptor()
|
||||||
|
interceptor.setTemplateDefaults(AnnotationTemplateExpressionDefaults)
|
||||||
|
return interceptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
=== Publish `AuthorizationAdvisor` instances instead of adding them in a `Customizer<AuthorizationAdvisorProxyFactory>`
|
||||||
|
|
||||||
|
While the ability to customize the `AuthorizationAdvisorProxyFactory` instance will remain in Spring Security 7, the ability to add advisors will be removed in favor of picking up published `AuthorizationAdvisor` beans.
|
||||||
|
|
||||||
|
If you are not calling `AuthorizationAdvisorProxyFactory#setAdvisors` or `AuthorizationAdvisorProxyFactory#addAdvisor`, you need do nothing.
|
||||||
|
|
||||||
|
If you are, publish the `AuthorizationAdvisor` bean instead and Spring Security will pick it up and apply it automatically.
|
||||||
|
@ -123,3 +123,60 @@ In versions prior to 6.2, if you had a xref:servlet/configuration/java.adoc#jc-c
|
|||||||
However, starting from version 6.2, this method is deprecated and will be removed in 7.0 because it will no longer be possible to chain configurations using `.and()` once `.and()` is removed (see https://github.com/spring-projects/spring-security/issues/13067).
|
However, starting from version 6.2, this method is deprecated and will be removed in 7.0 because it will no longer be possible to chain configurations using `.and()` once `.and()` is removed (see https://github.com/spring-projects/spring-security/issues/13067).
|
||||||
Instead, it is recommended to use the new `.with(...)` method.
|
Instead, it is recommended to use the new `.with(...)` method.
|
||||||
For more information about how to use `.with(...)` please refer to the xref:servlet/configuration/java.adoc#jc-custom-dsls[Custom DSLs section].
|
For more information about how to use `.with(...)` please refer to the xref:servlet/configuration/java.adoc#jc-custom-dsls[Custom DSLs section].
|
||||||
|
|
||||||
|
== Use `dispatcherTypeMatchers` instead of `shouldFilterAllDispatcherTypes`
|
||||||
|
|
||||||
|
If you are permitting the ERROR dispatch, you may be using `shouldFilterAllDispatcherTypes(false)` in the `auhorizeHttpRequests` DSL:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
http
|
||||||
|
.authorizeHttpRequests((authorize) -> authorize
|
||||||
|
.shouldFilterAllDispatcherTypes(false)
|
||||||
|
// ...
|
||||||
|
)
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
http {
|
||||||
|
authorizeHttpRequests {
|
||||||
|
shouldFilterAllDispatcherTypes = false
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
In preparation for 7, change this to use `dispatcherTypeMatchers`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
http
|
||||||
|
.authorizHttpRequests((authorize) -> authorize
|
||||||
|
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
|
||||||
|
// ...
|
||||||
|
)
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
http {
|
||||||
|
authorizeHttpRequests {
|
||||||
|
authorize(new DispatcherTypeRequestMatcher(DispatcherType.ERROR), permitAll())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
@ -170,3 +170,70 @@ fun jwtDecoder(): JwtDecoder {
|
|||||||
<2> - specify the list of validators you need, excluding `JwtTypeValidator`
|
<2> - specify the list of validators you need, excluding `JwtTypeValidator`
|
||||||
|
|
||||||
For additional guidance, please see the xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-validation[JwtDecoder Validators] section in the reference.
|
For additional guidance, please see the xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-validation[JwtDecoder Validators] section in the reference.
|
||||||
|
|
||||||
|
== Opaque Token Credentials Will Be Encoded For You
|
||||||
|
|
||||||
|
In order to comply more closely with the Introspection RFC, Spring Security's opaque token support will encode the client id and secret before creating the authorization header.
|
||||||
|
This change means you will no longer have to encode the client id and secret yourself.
|
||||||
|
|
||||||
|
If your client id or secret contain URL-unsafe characters, then you can prepare yourself for this change by doing the following:
|
||||||
|
|
||||||
|
=== Replace Usage of `introspectionClientCredentials`
|
||||||
|
|
||||||
|
Since Spring Security can now do the encoding for you, replace xref:servlet/oauth2/resource-server/opaque-token.adoc#oauth2resourceserver-opaque-introspectionuri-dsl[using `introspectionClientCredentials`] with publishing the following `@Bean`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
OpaqueTokenIntrospector introspector() {
|
||||||
|
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||||
|
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build();
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun introspector(): OpaqueTokenIntrospector {
|
||||||
|
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||||
|
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build()
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
The above will be the default in 7.0.
|
||||||
|
|
||||||
|
If this setting gives you trouble or you cannot apply it for now, you can use the `RestOperations` constructor instead:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
OpaqueTokenIntrospector introspector() {
|
||||||
|
RestTemplate rest = new RestTemplate();
|
||||||
|
rest.addInterceptor(new BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret));
|
||||||
|
return new SpringOpaqueTokenIntrospector(introspectionUri, rest);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun introspector(): OpaqueTokenIntrospector {
|
||||||
|
val rest = RestTemplate()
|
||||||
|
rest.addInterceptor(BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret))
|
||||||
|
return SpringOpaqueTokenIntrospector(introspectionUri, rest)
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
@ -1,5 +1,17 @@
|
|||||||
= Saml 2.0 Migrations
|
= Saml 2.0 Migrations
|
||||||
|
|
||||||
|
== Use OpenSAML 5 By Default
|
||||||
|
|
||||||
|
OpenSAML 4.x is no longer supported by the OpenSAML team.
|
||||||
|
As such, Spring Security will default to using its `OpenSaml5` components in all cases.
|
||||||
|
|
||||||
|
If you want to see how well your application will respond to this, do the following:
|
||||||
|
|
||||||
|
1. Update your OpenSAML dependencies to 5.x
|
||||||
|
2. If you are constructing an `OpenSaml4XXX` Spring Security component, change it to `OpenSaml5`.
|
||||||
|
|
||||||
|
If you cannot opt-in, then add the `opensaml-saml-api` and `opensaml-saml-impl` 4.x dependencies and exclude the 5.x dependencies from `spring-security-saml2-service-provider`.
|
||||||
|
|
||||||
== Continue Filter Chain When No Relying Party Found
|
== Continue Filter Chain When No Relying Party Found
|
||||||
|
|
||||||
In Spring Security 6, `Saml2WebSsoAuthenticationFilter` throws an exception when the request URI matches, but no relying party registration is found.
|
In Spring Security 6, `Saml2WebSsoAuthenticationFilter` throws an exception when the request URI matches, but no relying party registration is found.
|
||||||
@ -163,3 +175,230 @@ val responseValidator = ResponseValidator.withDefaults { responseToken: Response
|
|||||||
provider.setResponseValidator(responseValidator)
|
provider.setResponseValidator(responseValidator)
|
||||||
----
|
----
|
||||||
======
|
======
|
||||||
|
|
||||||
|
== `RelyingPartyRegistration` Improvements
|
||||||
|
|
||||||
|
`RelyingPartyRegistration` links metadata from a relying party to metadata from an asserting party.
|
||||||
|
|
||||||
|
To prepare for some improvements to the API, please take the following steps:
|
||||||
|
|
||||||
|
1. If you are mutating a registration by using `RelyingPartyRegistration#withRelyingPartyRegistration`, instead call `RelyingPartyRegistration#mutate`
|
||||||
|
2. If you are providing or retrieving `AssertingPartyDetails`, use `getAssertingPartyMetadata` or `withAssertingPartyMetadata` instead.
|
||||||
|
|
||||||
|
== `OpenSaml5AuthenticationProvider` Improvements
|
||||||
|
|
||||||
|
Spring Security 7 will remove a handful of static factories from `OpenSaml5AuthenticationProvider` in favor of inner classes.
|
||||||
|
These inner classes simplify customization of the response validator, the assertion validator, and the response authentication converter.
|
||||||
|
|
||||||
|
=== Response Validation
|
||||||
|
|
||||||
|
Instead of doing:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||||
|
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||||
|
saml2.setResponseValidator((responseToken) -> OpenSamlAuthenticationProvider.createDefaultResponseValidator()
|
||||||
|
.andThen((result) -> result
|
||||||
|
.concat(myCustomValidator.convert(responseToken))
|
||||||
|
));
|
||||||
|
return saml2;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||||
|
val saml2 = OpenSaml5AuthenticationProvider()
|
||||||
|
saml2.setResponseValidator { responseToken -> OpenSamlAuthenticationProvider.createDefaultResponseValidator()
|
||||||
|
.andThen { result -> result
|
||||||
|
.concat(myCustomValidator.convert(responseToken))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return saml2
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
use `OpenSaml5AuthenticationProvider.ResponseValidator`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||||
|
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||||
|
saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator));
|
||||||
|
return saml2;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||||
|
val saml2 = OpenSaml5AuthenticationProvider()
|
||||||
|
saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator))
|
||||||
|
return saml2
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
=== Assertion Validation
|
||||||
|
|
||||||
|
Instead of doing:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||||
|
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||||
|
authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider
|
||||||
|
.createDefaultAssertionValidatorWithParameters(assertionToken -> {
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis());
|
||||||
|
// ... other validation parameters
|
||||||
|
return new ValidationContext(params);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return saml2;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||||
|
val saml2 = OpenSaml5AuthenticationProvider()
|
||||||
|
authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider
|
||||||
|
.createDefaultAssertionValidatorWithParameters { ->
|
||||||
|
val params = HashMap<String, Object>()
|
||||||
|
params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis())
|
||||||
|
// ... other validation parameters
|
||||||
|
return ValidationContext(params)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return saml2
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
use `OpenSaml5AuthenticationProvider.AssertionValidator`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||||
|
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||||
|
Duration tenMinutes = Duration.ofMinutes(10);
|
||||||
|
authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build());
|
||||||
|
return saml2;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||||
|
val saml2 = OpenSaml5AuthenticationProvider()
|
||||||
|
val tenMinutes = Duration.ofMinutes(10)
|
||||||
|
authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build())
|
||||||
|
return saml2
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
== Response Authentication Converter
|
||||||
|
|
||||||
|
Instead of doing:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
Converter<ResponseToken, Saml2Authentication> authenticationConverter() {
|
||||||
|
return (responseToken) -> {
|
||||||
|
Saml2Authentication authentication = OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter()
|
||||||
|
.convert(responseToken);
|
||||||
|
// ... work with OpenSAML's Assertion object to extract the principal
|
||||||
|
return new Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun authenticationConverter(): Converter<ResponseToken, Saml2Authentication> {
|
||||||
|
return { responseToken ->
|
||||||
|
val authentication =
|
||||||
|
OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter().convert(responseToken)
|
||||||
|
// ... work with OpenSAML's Assertion object to extract the principal
|
||||||
|
return Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
use `OpenSaml5AuthenticationProvider.ResponseAuthenticationConverter`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
ResponseAuthenticationConverter authenticationConverter() {
|
||||||
|
ResponseAuthenticationConverter authenticationConverter = new ResponseAuthenticationConverter();
|
||||||
|
authenticationConverter.setPrincipalNameConverter((assertion) -> {
|
||||||
|
// ... work with OpenSAML's Assertion object to extract the principal
|
||||||
|
});
|
||||||
|
return authenticationConverter;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun authenticationConverter(): ResponseAuthenticationConverter {
|
||||||
|
val authenticationConverter = ResponseAuthenticationConverter()
|
||||||
|
authenticationConverter.setPrincipalNameConverter { assertion ->
|
||||||
|
// ... work with OpenSAML's Assertion object to extract the principal
|
||||||
|
}
|
||||||
|
return authenticationConverter
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
@ -521,3 +521,49 @@ Xml::
|
|||||||
=====
|
=====
|
||||||
If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance.
|
If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance.
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
== Use `setCookieCustomizer` instead of individual setters
|
||||||
|
|
||||||
|
In favor of a simpler API, `CookieCsrfTokenRepository#setCookieCustomizer` allows you to change any aspect of the cookie, replacing `setCookieHttpOnly`, `setCookieMaxAge`, `setSecure`, and `setCookieDomain`.
|
||||||
|
|
||||||
|
Change this:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
|
||||||
|
csrf.setCookieMaxAge(86400)
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
|
||||||
|
csrf.setCookieMaxAge(86400)
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
to this:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
|
||||||
|
csrf.setCookieCustomizer((c) -> c.maxAge(86400));
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
|
||||||
|
csrf.setCookieCustomizer { -> it.maxAge(86400) }
|
||||||
|
----
|
||||||
|
======
|
||||||
|
Loading…
x
Reference in New Issue
Block a user