瀏覽代碼

Polish gh-1723

Joe Grandja 10 月之前
父節點
當前提交
4d1e2d9711

+ 48 - 1
docs/modules/ROOT/pages/protocol-endpoints.adoc

@@ -557,15 +557,62 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h
 [[oidc-logout-endpoint-customizing-logout-request-validation]]
 === Customizing Logout Request Validation
 
-`OidcLogoutAuthenticationValidator` is the default validator used for validating specific OpenID Connect Logout request parameters used in the RP-Initiated Logout flow.
+`OidcLogoutAuthenticationValidator` is the default validator used for validating specific OpenID Connect RP-Initiated Logout Request parameters.
 The default implementation validates the `post_logout_redirect_uri` parameter.
 If validation fails, an `OAuth2AuthenticationException` is thrown.
 
 `OidcLogoutAuthenticationProvider` provides the ability to override the default logout request validation by supplying a custom authentication validator of type `Consumer<OidcLogoutAuthenticationContext>` to `setAuthenticationValidator()`.
 
+[TIP]
+`OidcLogoutAuthenticationContext` holds the `OidcLogoutAuthenticationToken`, which contains the logout request parameters.
+
 [IMPORTANT]
 If validation fails, the authentication validator *MUST* throw `OAuth2AuthenticationException`.
 
+The following example shows how to configure `OidcLogoutAuthenticationProvider` with a custom authentication validator:
+
+[source,java]
+----
+@Bean
+public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
+	OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
+			new OAuth2AuthorizationServerConfigurer();
+	http.apply(authorizationServerConfigurer);
+
+	authorizationServerConfigurer
+		.oidc(oidc ->
+			oidc
+				.logoutEndpoint(logoutEndpoint ->
+					logoutEndpoint.authenticationProviders(configureAuthenticationValidator()))
+		);
+
+	return http.build();
+}
+
+private Consumer<List<AuthenticationProvider>> configureAuthenticationValidator() {
+	return (authenticationProviders) ->
+			authenticationProviders.forEach((authenticationProvider) -> {
+				if (authenticationProvider instanceof OidcLogoutAuthenticationProvider oidcLogoutAuthenticationProvider) {
+					Consumer<OidcLogoutAuthenticationContext> authenticationValidator = new CustomPostLogoutRedirectUriValidator();
+					oidcLogoutAuthenticationProvider.setAuthenticationValidator(authenticationValidator);
+				}
+			});
+}
+
+static class CustomPostLogoutRedirectUriValidator implements Consumer<OidcLogoutAuthenticationContext> {
+
+	@Override
+	public void accept(OidcLogoutAuthenticationContext authenticationContext) {
+		OidcLogoutAuthenticationToken oidcLogoutAuthentication =
+				authenticationContext.getAuthentication();
+		RegisteredClient registeredClient = authenticationContext.getRegisteredClient();
+
+		// TODO
+
+	}
+}
+----
+
 [[oidc-user-info-endpoint]]
 == OpenID Connect 1.0 UserInfo Endpoint
 

+ 5 - 3
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationContext.java

@@ -15,11 +15,12 @@
  */
 package org.springframework.security.oauth2.server.authorization.oidc.authentication;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.function.Consumer;
 
 import org.springframework.lang.Nullable;
-import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthenticationContext;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.util.Assert;
@@ -40,7 +41,7 @@ public final class OidcLogoutAuthenticationContext implements OAuth2Authenticati
 	private final Map<Object, Object> context;
 
 	private OidcLogoutAuthenticationContext(Map<Object, Object> context) {
-		this.context = context;
+		this.context = Collections.unmodifiableMap(new HashMap<>(context));
 	}
 
 	@SuppressWarnings("unchecked")
@@ -79,7 +80,7 @@ public final class OidcLogoutAuthenticationContext implements OAuth2Authenticati
 	 */
 	public static final class Builder extends AbstractBuilder<OidcLogoutAuthenticationContext, Builder> {
 
-		private Builder(Authentication authentication) {
+		private Builder(OidcLogoutAuthenticationToken authentication) {
 			super(authentication);
 		}
 
@@ -98,6 +99,7 @@ public final class OidcLogoutAuthenticationContext implements OAuth2Authenticati
 		 */
 		@Override
 		public OidcLogoutAuthenticationContext build() {
+			Assert.notNull(get(RegisteredClient.class), "registeredClient cannot be null");
 			return new OidcLogoutAuthenticationContext(getContext());
 		}
 

+ 2 - 2
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProvider.java

@@ -188,7 +188,7 @@ public final class OidcLogoutAuthenticationProvider implements AuthenticationPro
 	/**
 	 * Sets the {@code Consumer} providing access to the
 	 * {@link OidcLogoutAuthenticationContext} and is responsible for validating specific
-	 * Open ID Connect RP-Initiated Logout Request parameters associated in the
+	 * OpenID Connect RP-Initiated Logout Request parameters associated in the
 	 * {@link OidcLogoutAuthenticationToken}. The default authentication validator is
 	 * {@link OidcLogoutAuthenticationValidator}.
 	 *
@@ -197,7 +197,7 @@ public final class OidcLogoutAuthenticationProvider implements AuthenticationPro
 	 * {@link OAuth2AuthenticationException} if validation fails.
 	 * @param authenticationValidator the {@code Consumer} providing access to the
 	 * {@link OidcLogoutAuthenticationContext} and is responsible for validating specific
-	 * Open ID Connect RP-Initiated Logout Request parameters
+	 * OpenID Connect RP-Initiated Logout Request parameters
 	 * @since 1.4
 	 */
 	public void setAuthenticationValidator(Consumer<OidcLogoutAuthenticationContext> authenticationValidator) {

+ 2 - 3
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationValidator.java

@@ -20,7 +20,6 @@ import java.util.function.Consumer;
 import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
-import org.springframework.security.oauth2.core.oidc.OidcIdToken;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.util.StringUtils;
 
@@ -29,10 +28,10 @@ import org.springframework.util.StringUtils;
  * containing an {@link OidcLogoutAuthenticationToken} and is the default
  * {@link OidcLogoutAuthenticationProvider#setAuthenticationValidator(Consumer)
  * authentication validator} used for validating specific OpenID Connect RP-Initiated
- * Logout parameters used in the Authorization Code Grant.
+ * Logout Request parameters.
  *
  * <p>
- * The default implementation first validates {@link OidcIdToken#getAudience()}, and then
+ * The default implementation validates
  * {@link OidcLogoutAuthenticationToken#getPostLogoutRedirectUri()}. If validation fails,
  * an {@link OAuth2AuthenticationException} is thrown.
  *

+ 2 - 2
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProviderTests.java

@@ -317,7 +317,7 @@ public class OidcLogoutAuthenticationProviderTests {
 	}
 
 	@Test
-	void setAuthenticationValidatorWhenNullThenThrowIllegalArgumentException() {
+	public void setAuthenticationValidatorWhenNullThenThrowIllegalArgumentException() {
 		assertThatThrownBy(() -> this.authenticationProvider.setAuthenticationValidator(null))
 			.isInstanceOf(IllegalArgumentException.class)
 			.hasMessage("authenticationValidator cannot be null");
@@ -342,7 +342,7 @@ public class OidcLogoutAuthenticationProviderTests {
 		this.authenticationProvider.setAuthenticationValidator(authenticationValidator);
 
 		authenticateValidIdToken(principal, registeredClient, sessionId, idToken);
-		verify(authenticationValidator).accept(any());
+		verify(authenticationValidator).accept(any(OidcLogoutAuthenticationContext.class));
 	}
 
 	@Test