Browse Source

Add ServerOAuth2AuthorizationRequestResolver

Fixes: gh-5610
Rob Winch 7 years ago
parent
commit
85d5d4083f

+ 168 - 0
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolver.java

@@ -0,0 +1,168 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.oauth2.client.web.server;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
+import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
+import org.springframework.security.crypto.keygen.StringKeyGenerator;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
+import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
+import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
+import org.springframework.util.Assert;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.util.UriComponentsBuilder;
+import reactor.core.publisher.Mono;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The default implementation of {@link ServerOAuth2AuthorizationRequestResolver}.
+ *
+ * The {@link ClientRegistration#getRegistrationId()} is extracted from the request using the
+ * {@link #DEFAULT_AUTHORIZATION_REQUEST_PATTERN}. The injected {@link ReactiveClientRegistrationRepository} is then
+ * used to resolve the {@link ClientRegistration} and create the {@link OAuth2AuthorizationRequest}.
+ *
+ * @author Rob Winch
+ * @since 5.1
+ */
+public class DefaultServerOAuth2AuthorizationRequestResolver
+		implements ServerOAuth2AuthorizationRequestResolver {
+
+	/**
+	 * The name of the path variable that contains the {@link ClientRegistration#getRegistrationId()}
+	 */
+	public static final String DEFAULT_REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
+
+	/**
+	 * The default pattern used to resolve the {@link ClientRegistration#getRegistrationId()}
+	 */
+	public static final String DEFAULT_AUTHORIZATION_REQUEST_PATTERN = "/oauth2/authorization/{" + DEFAULT_REGISTRATION_ID_URI_VARIABLE_NAME
+			+ "}";
+
+	private final ServerWebExchangeMatcher authorizationRequestMatcher;
+
+	private final ReactiveClientRegistrationRepository clientRegistrationRepository;
+
+	private final StringKeyGenerator stateGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder());
+
+	/**
+	 * Creates a new instance
+	 * @param clientRegistrationRepository the repository to resolve the {@link ClientRegistration}
+	 */
+	public DefaultServerOAuth2AuthorizationRequestResolver(ReactiveClientRegistrationRepository clientRegistrationRepository) {
+		this(clientRegistrationRepository, new PathPatternParserServerWebExchangeMatcher(
+				DEFAULT_AUTHORIZATION_REQUEST_PATTERN));
+	}
+
+	/**
+	 * Creates a new instance
+	 * @param clientRegistrationRepository the repository to resolve the {@link ClientRegistration}
+	 * @param authorizationRequestMatcher the matcher that determines if the request is a match and extracts the
+	 * {@link #DEFAULT_REGISTRATION_ID_URI_VARIABLE_NAME} from the path variables.
+	 */
+	public DefaultServerOAuth2AuthorizationRequestResolver(ReactiveClientRegistrationRepository clientRegistrationRepository,
+			ServerWebExchangeMatcher authorizationRequestMatcher) {
+		Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
+		Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null");
+		this.clientRegistrationRepository = clientRegistrationRepository;
+		this.authorizationRequestMatcher = authorizationRequestMatcher;
+	}
+
+	@Override
+	public Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange) {
+		return this.authorizationRequestMatcher.matches(exchange)
+				.filter(matchResult -> matchResult.isMatch())
+				.map(ServerWebExchangeMatcher.MatchResult::getVariables)
+				.map(variables -> variables.get(DEFAULT_REGISTRATION_ID_URI_VARIABLE_NAME))
+				.cast(String.class)
+				.flatMap(clientRegistrationId -> resolve(exchange, clientRegistrationId));
+	}
+
+	@Override
+	public Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange,
+			String clientRegistrationId) {
+		return this.findByRegistrationId(exchange, clientRegistrationId)
+			.map(clientRegistration -> authorizationRequest(exchange, clientRegistration));
+	}
+
+	private Mono<ClientRegistration> findByRegistrationId(ServerWebExchange exchange, String clientRegistration) {
+		return this.clientRegistrationRepository.findByRegistrationId(clientRegistration)
+				.switchIfEmpty(Mono.error(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid client registration id")));
+	}
+
+	private OAuth2AuthorizationRequest authorizationRequest(ServerWebExchange exchange,
+			ClientRegistration clientRegistration) {
+		String redirectUriStr = this
+					.expandRedirectUri(exchange.getRequest(), clientRegistration);
+
+		Map<String, Object> additionalParameters = new HashMap<>();
+		additionalParameters.put(OAuth2ParameterNames.REGISTRATION_ID,
+				clientRegistration.getRegistrationId());
+
+		OAuth2AuthorizationRequest.Builder builder;
+		if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(clientRegistration.getAuthorizationGrantType())) {
+			builder = OAuth2AuthorizationRequest.authorizationCode();
+		}
+		else if (AuthorizationGrantType.IMPLICIT.equals(clientRegistration.getAuthorizationGrantType())) {
+			builder = OAuth2AuthorizationRequest.implicit();
+		}
+		else {
+			throw new IllegalArgumentException(
+					"Invalid Authorization Grant Type (" + clientRegistration.getAuthorizationGrantType().getValue()
+							+ ") for Client Registration with Id: " + clientRegistration.getRegistrationId());
+		}
+		return builder
+				.clientId(clientRegistration.getClientId())
+				.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
+				.redirectUri(redirectUriStr).scopes(clientRegistration.getScopes())
+				.state(this.stateGenerator.generateKey())
+				.additionalParameters(additionalParameters)
+				.build();
+	}
+
+	private String expandRedirectUri(ServerHttpRequest request, ClientRegistration clientRegistration) {
+		// Supported URI variables -> baseUrl, action, registrationId
+		// Used in -> CommonOAuth2Provider.DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}"
+		Map<String, String> uriVariables = new HashMap<>();
+		uriVariables.put("registrationId", clientRegistration.getRegistrationId());
+
+		String baseUrl = UriComponentsBuilder.fromHttpRequest(new ServerHttpRequestDecorator(request))
+				.replacePath(request.getPath().contextPath().value())
+				.replaceQuery(null)
+				.build()
+				.toUriString();
+		uriVariables.put("baseUrl", baseUrl);
+
+		if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(clientRegistration.getAuthorizationGrantType())) {
+			String loginAction = "login";
+			uriVariables.put("action", loginAction);
+		}
+
+		return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUriTemplate())
+				.buildAndExpand(uriVariables)
+				.toUriString();
+	}
+}

+ 11 - 104
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationRequestRedirectWebFilter.java

@@ -15,16 +15,6 @@
  */
 package org.springframework.security.oauth2.client.web.server;
 
-import java.net.URI;
-import java.util.Base64;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
-import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
-import org.springframework.security.crypto.keygen.StringKeyGenerator;
 import org.springframework.security.oauth2.client.ClientAuthorizationRequiredException;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
@@ -32,19 +22,17 @@ import org.springframework.security.oauth2.client.registration.ReactiveClientReg
 import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
-import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 import org.springframework.security.web.server.DefaultServerRedirectStrategy;
 import org.springframework.security.web.server.ServerRedirectStrategy;
-import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
-import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
 import org.springframework.util.Assert;
 import org.springframework.web.server.ServerWebExchange;
 import org.springframework.web.server.WebFilter;
 import org.springframework.web.server.WebFilterChain;
 import org.springframework.web.util.UriComponentsBuilder;
-
 import reactor.core.publisher.Mono;
 
+import java.net.URI;
+
 /**
  * This {@code WebFilter} initiates the authorization code grant or implicit grant flow
  * by redirecting the End-User's user-agent to the Authorization Server's Authorization Endpoint.
@@ -63,10 +51,6 @@ import reactor.core.publisher.Mono;
  * {@link ClientRegistration#getRegistrationId() registration identifier} of the client
  * that is used for initiating the OAuth 2.0 Authorization Request.
  *
- * <p>
- * <b>NOTE:</b> The default base {@code URI} {@code /oauth2/authorization} may be overridden
- * via it's constructor {@link #OAuth2AuthorizationRequestRedirectWebFilter(ReactiveClientRegistrationRepository, String)}.
-
  * @author Rob Winch
  * @since 5.1
  * @see OAuth2AuthorizationRequest
@@ -79,17 +63,8 @@ import reactor.core.publisher.Mono;
  * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.2.1">Section 4.2.1 Authorization Request (Implicit)</a>
  */
 public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
-	/**
-	 * The default base {@code URI} used for authorization requests.
-	 */
-	public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";
-	private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
-	private static final String AUTHORIZATION_REQUIRED_EXCEPTION_ATTR_NAME =
-			ClientAuthorizationRequiredException.class.getName() + ".AUTHORIZATION_REQUIRED_EXCEPTION";
-	private final ServerWebExchangeMatcher authorizationRequestMatcher;
-	private final ReactiveClientRegistrationRepository clientRegistrationRepository;
 	private final ServerRedirectStrategy authorizationRedirectStrategy = new DefaultServerRedirectStrategy();
-	private final StringKeyGenerator stateGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder());
+	private final ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver;
 	private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
 		new WebSessionOAuth2ServerAuthorizationRequestRepository();
 
@@ -99,23 +74,17 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
 	 * @param clientRegistrationRepository the repository of client registrations
 	 */
 	public OAuth2AuthorizationRequestRedirectWebFilter(ReactiveClientRegistrationRepository clientRegistrationRepository) {
-		this(clientRegistrationRepository, DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
+		this.authorizationRequestResolver = new DefaultServerOAuth2AuthorizationRequestResolver(clientRegistrationRepository);
 	}
 
 	/**
 	 * Constructs an {@code OAuth2AuthorizationRequestRedirectFilter} using the provided parameters.
 	 *
-	 * @param clientRegistrationRepository the repository of client registrations
-	 * @param authorizationRequestBaseUri the base {@code URI} used for authorization requests
+	 * @param authorizationRequestResolver the resolver to use
 	 */
-	public OAuth2AuthorizationRequestRedirectWebFilter(
-		ReactiveClientRegistrationRepository clientRegistrationRepository, String authorizationRequestBaseUri) {
-
-		Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty");
-		Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
-		this.authorizationRequestMatcher = new PathPatternParserServerWebExchangeMatcher(
-			authorizationRequestBaseUri + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}");
-		this.clientRegistrationRepository = clientRegistrationRepository;
+	public OAuth2AuthorizationRequestRedirectWebFilter(ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) {
+		Assert.notNull(authorizationRequestResolver, "authorizationRequestResolver cannot be null");
+		this.authorizationRequestResolver = authorizationRequestResolver;
 	}
 
 	/**
@@ -131,54 +100,15 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
 
 	@Override
 	public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
-		return this.authorizationRequestMatcher.matches(exchange)
-			.filter(matchResult -> matchResult.isMatch())
+		return this.authorizationRequestResolver.resolve(exchange)
 			.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
-			.map(ServerWebExchangeMatcher.MatchResult::getVariables)
-			.map(variables -> variables.get(REGISTRATION_ID_URI_VARIABLE_NAME))
-			.cast(String.class)
-			.onErrorResume(ClientAuthorizationRequiredException.class, e -> Mono.just(e.getClientRegistrationId()))
-			.flatMap(clientRegistrationId -> this.findByRegistrationId(exchange, clientRegistrationId))
+			.onErrorResume(ClientAuthorizationRequiredException.class, e -> this.authorizationRequestResolver.resolve(exchange, e.getClientRegistrationId()))
 			.flatMap(clientRegistration -> sendRedirectForAuthorization(exchange, clientRegistration));
 	}
 
-	private Mono<ClientRegistration> findByRegistrationId(ServerWebExchange exchange, String clientRegistration) {
-		return this.clientRegistrationRepository.findByRegistrationId(clientRegistration)
-			.switchIfEmpty(Mono.defer(() -> {
-				exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
-				return exchange.getResponse().setComplete().then(Mono.empty());
-			}));
-	}
-
 	private Mono<Void> sendRedirectForAuthorization(ServerWebExchange exchange,
-												ClientRegistration clientRegistration) {
+			OAuth2AuthorizationRequest authorizationRequest) {
 		return Mono.defer(() -> {
-			String redirectUriStr = this
-					.expandRedirectUri(exchange.getRequest(), clientRegistration);
-
-			Map<String, Object> additionalParameters = new HashMap<>();
-			additionalParameters.put(OAuth2ParameterNames.REGISTRATION_ID,
-					clientRegistration.getRegistrationId());
-
-			OAuth2AuthorizationRequest.Builder builder;
-			if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(clientRegistration.getAuthorizationGrantType())) {
-				builder = OAuth2AuthorizationRequest.authorizationCode();
-			}
-			else if (AuthorizationGrantType.IMPLICIT.equals(clientRegistration.getAuthorizationGrantType())) {
-				builder = OAuth2AuthorizationRequest.implicit();
-			}
-			else {
-				throw new IllegalArgumentException(
-						"Invalid Authorization Grant Type (" + clientRegistration.getAuthorizationGrantType().getValue()
-								+ ") for Client Registration with Id: " + clientRegistration.getRegistrationId());
-			}
-			OAuth2AuthorizationRequest authorizationRequest = builder
-					.clientId(clientRegistration.getClientId())
-					.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
-					.redirectUri(redirectUriStr).scopes(clientRegistration.getScopes())
-					.state(this.stateGenerator.generateKey())
-					.additionalParameters(additionalParameters).build();
-
 			Mono<Void> saveAuthorizationRequest = Mono.empty();
 			if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(authorizationRequest.getGrantType())) {
 				saveAuthorizationRequest = this.authorizationRequestRepository
@@ -192,27 +122,4 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
 					.then(this.authorizationRedirectStrategy.sendRedirect(exchange, redirectUri));
 		});
 	}
-
-	private String expandRedirectUri(ServerHttpRequest request, ClientRegistration clientRegistration) {
-		// Supported URI variables -> baseUrl, action, registrationId
-		// Used in -> CommonOAuth2Provider.DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}"
-		Map<String, String> uriVariables = new HashMap<>();
-		uriVariables.put("registrationId", clientRegistration.getRegistrationId());
-
-		String baseUrl = UriComponentsBuilder.fromHttpRequest(new ServerHttpRequestDecorator(request))
-				.replacePath(request.getPath().contextPath().value())
-				.replaceQuery(null)
-				.build()
-				.toUriString();
-		uriVariables.put("baseUrl", baseUrl);
-
-		if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(clientRegistration.getAuthorizationGrantType())) {
-			String loginAction = "login";
-			uriVariables.put("action", loginAction);
-		}
-
-		return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUriTemplate())
-			.buildAndExpand(uriVariables)
-			.toUriString();
-	}
 }

+ 53 - 0
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/ServerOAuth2AuthorizationRequestResolver.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.oauth2.client.web.server;
+
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * Implementations of this interface are capable of resolving
+ * an {@link OAuth2AuthorizationRequest} from the provided {@code ServerWebExchange}.
+ * Used by the {@link OAuth2AuthorizationRequestRedirectWebFilter} for resolving Authorization Requests.
+ *
+ * @author Rob Winch
+ * @since 5.1
+ * @see OAuth2AuthorizationRequest
+ * @see OAuth2AuthorizationRequestRedirectWebFilter
+ */
+public interface ServerOAuth2AuthorizationRequestResolver {
+
+	/**
+	 * Returns the {@link OAuth2AuthorizationRequest} resolved from
+	 * the provided {@code HttpServletRequest} or {@code null} if not available.
+	 *
+	 * @param exchange the {@code ServerWebExchange}
+	 * @return the resolved {@link OAuth2AuthorizationRequest} or {@code null} if not available
+	 */
+	Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange);
+
+	/**
+	 * Returns the {@link OAuth2AuthorizationRequest} resolved from
+	 * the provided {@code HttpServletRequest} or {@code null} if not available.
+	 *
+	 * @param exchange the {@code ServerWebExchange}
+	 * @param clientRegistrationId the client registration id
+	 * @return the resolved {@link OAuth2AuthorizationRequest} or {@code null} if not available
+	 */
+	Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange, String clientRegistrationId);
+
+}

+ 87 - 0
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolverTests.java

@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.oauth2.client.web.server;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
+import org.springframework.mock.web.server.MockServerWebExchange;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
+import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowableOfType;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author Rob Winch
+ * @since 5.1
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultServerOAuth2AuthorizationRequestResolverTests {
+	@Mock
+	private ReactiveClientRegistrationRepository clientRegistrationRepository;
+
+	private DefaultServerOAuth2AuthorizationRequestResolver resolver;
+
+	private ClientRegistration registration = TestClientRegistrations.clientRegistration().build();
+
+	@Before
+	public void setup() {
+		this.resolver = new DefaultServerOAuth2AuthorizationRequestResolver(this.clientRegistrationRepository);
+	}
+
+	@Test
+	public void resolveWhenNotMatchThenNull() {
+		assertThat(resolve("/")).isNull();
+	}
+
+	@Test
+	public void resolveWhenClientRegistrationNotFoundMatchThenBadRequest() {
+		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(
+				Mono.empty());
+
+		ResponseStatusException expected = catchThrowableOfType(() -> resolve("/oauth2/authorization/not-found-id"), ResponseStatusException.class);
+
+		assertThat(expected.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST);
+	}
+
+	@Test
+	public void resolveWhenClientRegistrationFoundThenWorks() {
+		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(
+				Mono.just(this.registration));
+
+		OAuth2AuthorizationRequest request = resolve("/oauth2/authorization/not-found-id");
+
+		assertThat(request.getAuthorizationRequestUri()).matches("https://example.com/login/oauth/authorize\\?response_type=code&client_id=client-id&scope=read%3Auser&state=.*?&redirect_uri=%2Flogin%2Foauth2%2Fcode%2Fregistration-id");
+	}
+
+	private OAuth2AuthorizationRequest resolve(String path) {
+		ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(path));
+		return this.resolver.resolve(exchange).block();
+	}
+}

+ 0 - 14
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationRequestRedirectWebFilterTests.java

@@ -79,20 +79,6 @@ public class OAuth2AuthorizationRequestRedirectWebFilterTests {
 			.isInstanceOf(IllegalArgumentException.class);
 	}
 
-	@Test
-	public void constructorWhenAuthorizationRequestBaseUriNullThenIllegalArgumentException() {
-		String authorizationRequestBaseUri = null;
-		assertThatThrownBy(() -> new OAuth2AuthorizationRequestRedirectWebFilter(this.clientRepository, authorizationRequestBaseUri))
-				.isInstanceOf(IllegalArgumentException.class);
-	}
-
-	@Test
-	public void constructorWhenAuthorizationRequestBaseUriEmptyThenIllegalArgumentException() {
-		String authorizationRequestBaseUri = "";
-		assertThatThrownBy(() -> new OAuth2AuthorizationRequestRedirectWebFilter(this.clientRepository, authorizationRequestBaseUri))
-				.isInstanceOf(IllegalArgumentException.class);
-	}
-
 	@Test
 	public void filterWhenDoesNotMatchThenClientRegistrationRepositoryNotSubscribed() {
 		this.client.get()