Consistent .server package for ServerWebExchange OAuth2

Fixes: gh-5663
This commit is contained in:
Rob Winch 2018-08-17 21:44:37 -05:00
parent cbd28cfd1e
commit 5ddb25fff8
9 changed files with 120 additions and 27 deletions

View File

@ -53,8 +53,8 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.userinfo.DefaultReactiveOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.DefaultReactiveOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectWebFilter; import org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationRequestRedirectWebFilter;
import org.springframework.security.oauth2.client.web.ServerOAuth2LoginAuthenticationTokenConverter; import org.springframework.security.oauth2.client.web.server.ServerOAuth2LoginAuthenticationTokenConverter;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager; import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.oauth2.client.web; package org.springframework.security.oauth2.client.web.server;
import java.net.URI; import java.net.URI;
import java.util.Base64; import java.util.Base64;
@ -29,6 +29,7 @@ import org.springframework.security.oauth2.client.ClientAuthorizationRequiredExc
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
@ -89,8 +90,8 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
private final ReactiveClientRegistrationRepository clientRegistrationRepository; private final ReactiveClientRegistrationRepository clientRegistrationRepository;
private final ServerRedirectStrategy authorizationRedirectStrategy = new DefaultServerRedirectStrategy(); private final ServerRedirectStrategy authorizationRedirectStrategy = new DefaultServerRedirectStrategy();
private final StringKeyGenerator stateGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder()); private final StringKeyGenerator stateGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder());
private ReactiveAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
new WebSessionOAuth2ReactiveAuthorizationRequestRepository(); new WebSessionOAuth2ServerAuthorizationRequestRepository();
/** /**
* Constructs an {@code OAuth2AuthorizationRequestRedirectFilter} using the provided parameters. * Constructs an {@code OAuth2AuthorizationRequestRedirectFilter} using the provided parameters.
@ -122,7 +123,8 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
* *
* @param authorizationRequestRepository the repository used for storing {@link OAuth2AuthorizationRequest}'s * @param authorizationRequestRepository the repository used for storing {@link OAuth2AuthorizationRequest}'s
*/ */
public final void setAuthorizationRequestRepository(ReactiveAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) { public final void setAuthorizationRequestRepository(
ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) {
Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null"); Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null");
this.authorizationRequestRepository = authorizationRequestRepository; this.authorizationRequestRepository = authorizationRequestRepository;
} }

View File

@ -0,0 +1,85 @@
/*
* 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.OAuth2AuthorizationResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.util.Map;
/**
* Utility methods for an OAuth 2.0 Authorization Response.
*
* @author Joe Grandja
* @since 5.1
* @see OAuth2AuthorizationResponse
*/
final class OAuth2AuthorizationResponseUtils {
private OAuth2AuthorizationResponseUtils() {
}
static MultiValueMap<String, String> toMultiMap(Map<String, String[]> map) {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>(map.size());
map.forEach((key, values) -> {
if (values.length > 0) {
for (String value : values) {
params.add(key, value);
}
}
});
return params;
}
static boolean isAuthorizationResponse(MultiValueMap<String, String> request) {
return isAuthorizationResponseSuccess(request) || isAuthorizationResponseError(request);
}
static boolean isAuthorizationResponseSuccess(MultiValueMap<String, String> request) {
return StringUtils.hasText(request.getFirst(OAuth2ParameterNames.CODE)) &&
StringUtils.hasText(request.getFirst(OAuth2ParameterNames.STATE));
}
static boolean isAuthorizationResponseError(MultiValueMap<String, String> request) {
return StringUtils.hasText(request.getFirst(OAuth2ParameterNames.ERROR)) &&
StringUtils.hasText(request.getFirst(OAuth2ParameterNames.STATE));
}
static OAuth2AuthorizationResponse convert(MultiValueMap<String, String> request, String redirectUri) {
String code = request.getFirst(OAuth2ParameterNames.CODE);
String errorCode = request.getFirst(OAuth2ParameterNames.ERROR);
String state = request.getFirst(OAuth2ParameterNames.STATE);
if (StringUtils.hasText(code)) {
return OAuth2AuthorizationResponse.success(code)
.redirectUri(redirectUri)
.state(state)
.build();
} else {
String errorDescription = request.getFirst(OAuth2ParameterNames.ERROR_DESCRIPTION);
String errorUri = request.getFirst(OAuth2ParameterNames.ERROR_URI);
return OAuth2AuthorizationResponse.error(errorCode)
.redirectUri(redirectUri)
.errorDescription(errorDescription)
.errorUri(errorUri)
.state(state)
.build();
}
}
}

View File

@ -14,8 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.oauth2.client.web; package org.springframework.security.oauth2.client.web.server;
import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter;
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
@ -38,7 +41,7 @@ import reactor.core.publisher.Mono;
* *
* @param <T> The type of OAuth 2.0 Authorization Request * @param <T> The type of OAuth 2.0 Authorization Request
*/ */
public interface ReactiveAuthorizationRequestRepository<T extends OAuth2AuthorizationRequest> { public interface ServerAuthorizationRequestRepository<T extends OAuth2AuthorizationRequest> {
/** /**
* Returns the {@link OAuth2AuthorizationRequest} associated to the provided {@code HttpServletRequest} * Returns the {@link OAuth2AuthorizationRequest} associated to the provided {@code HttpServletRequest}

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.oauth2.client.web; package org.springframework.security.oauth2.client.web.server;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
@ -47,8 +47,8 @@ public class ServerOAuth2LoginAuthenticationTokenConverter
static final String CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE = "client_registration_not_found"; static final String CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE = "client_registration_not_found";
private ReactiveAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
new WebSessionOAuth2ReactiveAuthorizationRequestRepository(); new WebSessionOAuth2ServerAuthorizationRequestRepository();
private final ReactiveClientRegistrationRepository clientRegistrationRepository; private final ReactiveClientRegistrationRepository clientRegistrationRepository;
@ -59,12 +59,12 @@ public class ServerOAuth2LoginAuthenticationTokenConverter
} }
/** /**
* Sets the {@link ReactiveAuthorizationRequestRepository} to be used. The default is * Sets the {@link ServerAuthorizationRequestRepository} to be used. The default is
* {@link WebSessionOAuth2ReactiveAuthorizationRequestRepository}. * {@link WebSessionOAuth2ServerAuthorizationRequestRepository}.
* @param authorizationRequestRepository the repository to use. * @param authorizationRequestRepository the repository to use.
*/ */
public void setAuthorizationRequestRepository( public void setAuthorizationRequestRepository(
ReactiveAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) { ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) {
Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null"); Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null");
this.authorizationRequestRepository = authorizationRequestRepository; this.authorizationRequestRepository = authorizationRequestRepository;
} }
@ -110,6 +110,7 @@ public class ServerOAuth2LoginAuthenticationTokenConverter
.build() .build()
.toUriString(); .toUriString();
return OAuth2AuthorizationResponseUtils.convert(queryParams, redirectUri); return OAuth2AuthorizationResponseUtils
.convert(queryParams, redirectUri);
} }
} }

View File

@ -14,12 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.oauth2.client.web; package org.springframework.security.oauth2.client.web.server;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -29,7 +30,7 @@ import org.springframework.web.server.WebSession;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
/** /**
* An implementation of an {@link ReactiveAuthorizationRequestRepository} that stores * An implementation of an {@link ServerAuthorizationRequestRepository} that stores
* {@link OAuth2AuthorizationRequest} in the {@code WebSession}. * {@link OAuth2AuthorizationRequest} in the {@code WebSession}.
* *
* @author Rob Winch * @author Rob Winch
@ -37,10 +38,11 @@ import reactor.core.publisher.Mono;
* @see AuthorizationRequestRepository * @see AuthorizationRequestRepository
* @see OAuth2AuthorizationRequest * @see OAuth2AuthorizationRequest
*/ */
public final class WebSessionOAuth2ReactiveAuthorizationRequestRepository implements ReactiveAuthorizationRequestRepository<OAuth2AuthorizationRequest> { public final class WebSessionOAuth2ServerAuthorizationRequestRepository
implements ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> {
private static final String DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME = private static final String DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME =
WebSessionOAuth2ReactiveAuthorizationRequestRepository.class.getName() + ".AUTHORIZATION_REQUEST"; WebSessionOAuth2ServerAuthorizationRequestRepository.class.getName() + ".AUTHORIZATION_REQUEST";
private final String sessionAttributeName = DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME; private final String sessionAttributeName = DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME;

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.oauth2.client.web; package org.springframework.security.oauth2.client.web.server;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -52,7 +52,7 @@ public class OAuth2AuthorizationRequestRedirectWebFilterTests {
private ReactiveClientRegistrationRepository clientRepository; private ReactiveClientRegistrationRepository clientRepository;
@Mock @Mock
private ReactiveAuthorizationRequestRepository<OAuth2AuthorizationRequest> authzRequestRepository; private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authzRequestRepository;
private ClientRegistration github = ClientRegistration.withRegistrationId("github") private ClientRegistration github = ClientRegistration.withRegistrationId("github")
.redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}") .redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}")

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.oauth2.client.web; package org.springframework.security.oauth2.client.web.server;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
@ -52,7 +52,7 @@ public class ServerOAuth2LoginAuthenticationTokenConverterTest {
private ReactiveClientRegistrationRepository clientRegistrationRepository; private ReactiveClientRegistrationRepository clientRegistrationRepository;
@Mock @Mock
private ReactiveAuthorizationRequestRepository authorizationRequestRepository; private ServerAuthorizationRequestRepository authorizationRequestRepository;
private String clientRegistrationId = "github"; private String clientRegistrationId = "github";

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.oauth2.client.web; package org.springframework.security.oauth2.client.web.server;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
@ -40,10 +40,10 @@ import reactor.test.StepVerifier;
* @author Rob Winch * @author Rob Winch
* @since 5.1 * @since 5.1
*/ */
public class WebSessionOAuth2ReactiveAuthorizationRequestRepositoryTests { public class WebSessionOAuth2ServerAuthorizationRequestRepositoryTests {
private WebSessionOAuth2ReactiveAuthorizationRequestRepository repository = private WebSessionOAuth2ServerAuthorizationRequestRepository repository =
new WebSessionOAuth2ReactiveAuthorizationRequestRepository(); new WebSessionOAuth2ServerAuthorizationRequestRepository();
private OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode() private OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri("https://example.com/oauth2/authorize") .authorizationUri("https://example.com/oauth2/authorize")