فهرست منبع

Remove deprecated CustomUserTypesOAuth2UserService

Closes gh-11511
Joe Grandja 3 سال پیش
والد
کامیت
42683693c0

+ 1 - 33
config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java

@@ -17,11 +17,9 @@
 package org.springframework.security.config.annotation.web.configurers.oauth2.client;
 
 import java.lang.reflect.Field;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 
 import org.springframework.beans.factory.BeanFactoryUtils;
@@ -48,9 +46,7 @@ import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
 import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
-import org.springframework.security.oauth2.client.userinfo.CustomUserTypesOAuth2UserService;
 import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
-import org.springframework.security.oauth2.client.userinfo.DelegatingOAuth2UserService;
 import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
 import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
 import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;
@@ -438,16 +434,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
 		ResolvableType type = ResolvableType.forClassWithGenerics(OAuth2UserService.class, OAuth2UserRequest.class,
 				OAuth2User.class);
 		OAuth2UserService<OAuth2UserRequest, OAuth2User> bean = getBeanOrNull(type);
-		if (bean != null) {
-			return bean;
-		}
-		if (this.userInfoEndpointConfig.customUserTypes.isEmpty()) {
-			return new DefaultOAuth2UserService();
-		}
-		List<OAuth2UserService<OAuth2UserRequest, OAuth2User>> userServices = new ArrayList<>();
-		userServices.add(new CustomUserTypesOAuth2UserService(this.userInfoEndpointConfig.customUserTypes));
-		userServices.add(new DefaultOAuth2UserService());
-		return new DelegatingOAuth2UserService<>(userServices);
+		return (bean != null) ? bean : new DefaultOAuth2UserService();
 	}
 
 	private <T> T getBeanOrNull(ResolvableType type) {
@@ -666,8 +653,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
 
 		private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
 
-		private Map<String, Class<? extends OAuth2User>> customUserTypes = new HashMap<>();
-
 		private UserInfoEndpointConfig() {
 		}
 
@@ -697,23 +682,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
 			return this;
 		}
 
-		/**
-		 * Sets a custom {@link OAuth2User} type and associates it to the provided client
-		 * {@link ClientRegistration#getRegistrationId() registration identifier}.
-		 * @param customUserType a custom {@link OAuth2User} type
-		 * @param clientRegistrationId the client registration identifier
-		 * @return the {@link UserInfoEndpointConfig} for further configuration
-		 * @deprecated See {@link CustomUserTypesOAuth2UserService} for alternative usage.
-		 */
-		@Deprecated
-		public UserInfoEndpointConfig customUserType(Class<? extends OAuth2User> customUserType,
-				String clientRegistrationId) {
-			Assert.notNull(customUserType, "customUserType cannot be null");
-			Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty");
-			this.customUserTypes.put(clientRegistrationId, customUserType);
-			return this;
-		}
-
 		/**
 		 * Sets the {@link GrantedAuthoritiesMapper} used for mapping
 		 * {@link OAuth2User#getAuthorities()}.

+ 1 - 30
config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/login/UserInfoEndpointDsl.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -20,7 +20,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity
 import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer
 import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper
 import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest
-import org.springframework.security.oauth2.client.registration.ClientRegistration
 import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest
 import org.springframework.security.oauth2.client.userinfo.OAuth2UserService
 import org.springframework.security.oauth2.core.oidc.user.OidcUser
@@ -44,39 +43,11 @@ class UserInfoEndpointDsl {
     var oidcUserService: OAuth2UserService<OidcUserRequest, OidcUser>? = null
     var userAuthoritiesMapper: GrantedAuthoritiesMapper? = null
 
-    private var customUserTypePair: Pair<Class<out OAuth2User>, String>? = null
-
-    /**
-     * Sets a custom [OAuth2User] type and associates it to the provided
-     * client [ClientRegistration.getRegistrationId] registration identifier.
-     *
-     * @param customUserType a custom [OAuth2User] type
-     * @param clientRegistrationId the client registration identifier
-     */
-    @Deprecated("Use 'customUserType<T>(clientRegistrationId)' instead.")
-    fun customUserType(customUserType: Class<out OAuth2User>, clientRegistrationId: String) {
-        customUserTypePair = Pair(customUserType, clientRegistrationId)
-    }
-
-    /**
-     * Sets a custom [OAuth2User] type and associates it to the provided
-     * client [ClientRegistration.getRegistrationId] registration identifier.
-     * Variant that is leveraging Kotlin reified type parameters.
-     *
-     * @param T a custom [OAuth2User] type
-     * @param clientRegistrationId the client registration identifier
-     */
-    @Suppress("DEPRECATION")
-    inline fun <reified T: OAuth2User> customUserType(clientRegistrationId: String) {
-        customUserType(T::class.java, clientRegistrationId)
-    }
-
     internal fun get(): (OAuth2LoginConfigurer<HttpSecurity>.UserInfoEndpointConfig) -> Unit {
         return { userInfoEndpoint ->
             userService?.also { userInfoEndpoint.userService(userService) }
             oidcUserService?.also { userInfoEndpoint.oidcUserService(oidcUserService) }
             userAuthoritiesMapper?.also { userInfoEndpoint.userAuthoritiesMapper(userAuthoritiesMapper) }
-            customUserTypePair?.also { userInfoEndpoint.customUserType(customUserTypePair!!.first, customUserTypePair!!.second) }
         }
     }
 }

+ 0 - 139
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/CustomUserTypesOAuth2UserService.java

@@ -1,139 +0,0 @@
-/*
- * Copyright 2002-2020 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
- *
- *      https://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.userinfo;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.http.RequestEntity;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
-import org.springframework.security.oauth2.client.registration.ClientRegistration;
-import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.core.OAuth2Error;
-import org.springframework.security.oauth2.core.user.OAuth2User;
-import org.springframework.util.Assert;
-import org.springframework.web.client.ResponseErrorHandler;
-import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestOperations;
-import org.springframework.web.client.RestTemplate;
-
-/**
- * An implementation of an {@link OAuth2UserService} that supports custom
- * {@link OAuth2User} types.
- * <p>
- * The custom user type(s) is supplied via the constructor, using a {@code Map} of
- * {@link OAuth2User} type(s) keyed by {@code String}, which represents the
- * {@link ClientRegistration#getRegistrationId() Registration Id} of the Client.
- *
- * @author Joe Grandja
- * @since 5.0
- * @see OAuth2UserService
- * @see OAuth2UserRequest
- * @see OAuth2User
- * @see ClientRegistration
- * @deprecated It is recommended to use a delegation-based strategy of an
- * {@link OAuth2UserService} to support custom {@link OAuth2User} types, as it provides
- * much greater flexibility compared to this implementation. See the
- * <a target="_blank" href=
- * "https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2login-advanced-map-authorities-oauth2userservice">reference
- * manual</a> for details on how to implement.
- */
-@Deprecated
-public class CustomUserTypesOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
-
-	private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
-
-	private final Map<String, Class<? extends OAuth2User>> customUserTypes;
-
-	private Converter<OAuth2UserRequest, RequestEntity<?>> requestEntityConverter = new OAuth2UserRequestEntityConverter();
-
-	private RestOperations restOperations;
-
-	/**
-	 * Constructs a {@code CustomUserTypesOAuth2UserService} using the provided
-	 * parameters.
-	 * @param customUserTypes a {@code Map} of {@link OAuth2User} type(s) keyed by
-	 * {@link ClientRegistration#getRegistrationId() Registration Id}
-	 */
-	public CustomUserTypesOAuth2UserService(Map<String, Class<? extends OAuth2User>> customUserTypes) {
-		Assert.notEmpty(customUserTypes, "customUserTypes cannot be empty");
-		this.customUserTypes = Collections.unmodifiableMap(new LinkedHashMap<>(customUserTypes));
-		RestTemplate restTemplate = new RestTemplate();
-		restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
-		this.restOperations = restTemplate;
-	}
-
-	@Override
-	public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
-		Assert.notNull(userRequest, "userRequest cannot be null");
-		String registrationId = userRequest.getClientRegistration().getRegistrationId();
-		Class<? extends OAuth2User> customUserType = this.customUserTypes.get(registrationId);
-		if (customUserType == null) {
-			return null;
-		}
-		RequestEntity<?> request = this.requestEntityConverter.convert(userRequest);
-		ResponseEntity<? extends OAuth2User> response = getResponse(customUserType, request);
-		OAuth2User oauth2User = response.getBody();
-		return oauth2User;
-	}
-
-	private ResponseEntity<? extends OAuth2User> getResponse(Class<? extends OAuth2User> customUserType,
-			RequestEntity<?> request) {
-		try {
-			return this.restOperations.exchange(request, customUserType);
-		}
-		catch (RestClientException ex) {
-			OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
-					"An error occurred while attempting to retrieve the UserInfo Resource: " + ex.getMessage(), null);
-			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
-		}
-	}
-
-	/**
-	 * Sets the {@link Converter} used for converting the {@link OAuth2UserRequest} to a
-	 * {@link RequestEntity} representation of the UserInfo Request.
-	 * @param requestEntityConverter the {@link Converter} used for converting to a
-	 * {@link RequestEntity} representation of the UserInfo Request
-	 * @since 5.1
-	 */
-	public final void setRequestEntityConverter(Converter<OAuth2UserRequest, RequestEntity<?>> requestEntityConverter) {
-		Assert.notNull(requestEntityConverter, "requestEntityConverter cannot be null");
-		this.requestEntityConverter = requestEntityConverter;
-	}
-
-	/**
-	 * Sets the {@link RestOperations} used when requesting the UserInfo resource.
-	 *
-	 * <p>
-	 * <b>NOTE:</b> At a minimum, the supplied {@code restOperations} must be configured
-	 * with the following:
-	 * <ol>
-	 * <li>{@link ResponseErrorHandler} - {@link OAuth2ErrorResponseErrorHandler}</li>
-	 * </ol>
-	 * @param restOperations the {@link RestOperations} used when requesting the UserInfo
-	 * resource
-	 * @since 5.1
-	 */
-	public final void setRestOperations(RestOperations restOperations) {
-		Assert.notNull(restOperations, "restOperations cannot be null");
-		this.restOperations = restOperations;
-	}
-
-}

+ 0 - 266
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/userinfo/CustomUserTypesOAuth2UserServiceTests.java

@@ -1,266 +0,0 @@
-/*
- * Copyright 2002-2019 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
- *
- *      https://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.userinfo;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.MockWebServer;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.oauth2.client.registration.ClientRegistration;
-import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
-import org.springframework.security.oauth2.core.AuthorizationGrantType;
-import org.springframework.security.oauth2.core.OAuth2AccessToken;
-import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
-import org.springframework.security.oauth2.core.user.OAuth2User;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-
-/**
- * Tests for {@link CustomUserTypesOAuth2UserService}.
- *
- * @author Joe Grandja
- * @author Eddú Meléndez
- */
-public class CustomUserTypesOAuth2UserServiceTests {
-
-	private ClientRegistration.Builder clientRegistrationBuilder;
-
-	private OAuth2AccessToken accessToken;
-
-	private CustomUserTypesOAuth2UserService userService;
-
-	private MockWebServer server;
-
-	@BeforeEach
-	public void setUp() throws Exception {
-		this.server = new MockWebServer();
-		this.server.start();
-		String registrationId = "client-registration-id-1";
-		// @formatter:off
-		this.clientRegistrationBuilder = TestClientRegistrations.clientRegistration()
-				.registrationId(registrationId);
-		// @formatter:on
-		this.accessToken = TestOAuth2AccessTokens.noScopes();
-		Map<String, Class<? extends OAuth2User>> customUserTypes = new HashMap<>();
-		customUserTypes.put(registrationId, CustomOAuth2User.class);
-		this.userService = new CustomUserTypesOAuth2UserService(customUserTypes);
-	}
-
-	@AfterEach
-	public void cleanup() throws Exception {
-		this.server.shutdown();
-	}
-
-	@Test
-	public void constructorWhenCustomUserTypesIsNullThenThrowIllegalArgumentException() {
-		assertThatIllegalArgumentException().isThrownBy(() -> new CustomUserTypesOAuth2UserService(null));
-	}
-
-	@Test
-	public void constructorWhenCustomUserTypesIsEmptyThenThrowIllegalArgumentException() {
-		assertThatIllegalArgumentException()
-				.isThrownBy(() -> new CustomUserTypesOAuth2UserService(Collections.emptyMap()));
-	}
-
-	@Test
-	public void setRequestEntityConverterWhenNullThenThrowIllegalArgumentException() {
-		assertThatIllegalArgumentException().isThrownBy(() -> this.userService.setRequestEntityConverter(null));
-	}
-
-	@Test
-	public void setRestOperationsWhenNullThenThrowIllegalArgumentException() {
-		assertThatIllegalArgumentException().isThrownBy(() -> this.userService.setRestOperations(null));
-	}
-
-	@Test
-	public void loadUserWhenUserRequestIsNullThenThrowIllegalArgumentException() {
-		assertThatIllegalArgumentException().isThrownBy(() -> this.userService.loadUser(null));
-	}
-
-	@Test
-	public void loadUserWhenCustomUserTypeNotFoundThenReturnNull() {
-		// @formatter:off
-		ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration()
-				.registrationId("other-client-registration-id-1")
-				.build();
-		// @formatter:on
-		OAuth2User user = this.userService.loadUser(new OAuth2UserRequest(clientRegistration, this.accessToken));
-		assertThat(user).isNull();
-	}
-
-	@Test
-	public void loadUserWhenUserInfoSuccessResponseThenReturnUser() {
-		// @formatter:off
-		String userInfoResponse = "{\n"
-			+ "   \"id\": \"12345\",\n"
-			+ "   \"name\": \"first last\",\n"
-			+ "   \"login\": \"user1\",\n"
-			+ "   \"email\": \"user1@example.com\"\n"
-			+ "}\n";
-		// @formatter:on
-		this.server.enqueue(jsonResponse(userInfoResponse));
-		String userInfoUri = this.server.url("/user").toString();
-		ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
-		OAuth2User user = this.userService.loadUser(new OAuth2UserRequest(clientRegistration, this.accessToken));
-		assertThat(user.getName()).isEqualTo("first last");
-		assertThat(user.getAttributes().size()).isEqualTo(4);
-		assertThat((String) user.getAttribute("id")).isEqualTo("12345");
-		assertThat((String) user.getAttribute("name")).isEqualTo("first last");
-		assertThat((String) user.getAttribute("login")).isEqualTo("user1");
-		assertThat((String) user.getAttribute("email")).isEqualTo("user1@example.com");
-		assertThat(user.getAuthorities().size()).isEqualTo(1);
-		assertThat(user.getAuthorities().iterator().next().getAuthority()).isEqualTo("ROLE_USER");
-	}
-
-	@Test
-	public void loadUserWhenUserInfoSuccessResponseInvalidThenThrowOAuth2AuthenticationException() {
-		// @formatter:off
-		String userInfoResponse = "{\n"
-			+ "   \"id\": \"12345\",\n"
-			+ "   \"name\": \"first last\",\n"
-
-			+ "   \"login\": \"user1\",\n"
-			+ "   \"email\": \"user1@example.com\"\n";
-			// "}\n"; // Make the JSON invalid/malformed
-		// @formatter:on
-		this.server.enqueue(jsonResponse(userInfoResponse));
-		String userInfoUri = this.server.url("/user").toString();
-		ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
-		assertThatExceptionOfType(OAuth2AuthenticationException.class)
-				.isThrownBy(
-						() -> this.userService.loadUser(new OAuth2UserRequest(clientRegistration, this.accessToken)))
-				.withMessageContaining(
-						"[invalid_user_info_response] An error occurred while attempting to retrieve the UserInfo Resource");
-	}
-
-	@Test
-	public void loadUserWhenServerErrorThenThrowOAuth2AuthenticationException() {
-		this.server.enqueue(new MockResponse().setResponseCode(500));
-		String userInfoUri = this.server.url("/user").toString();
-		ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
-		assertThatExceptionOfType(OAuth2AuthenticationException.class)
-				.isThrownBy(
-						() -> this.userService.loadUser(new OAuth2UserRequest(clientRegistration, this.accessToken)))
-				.withMessageContaining(
-						"[invalid_user_info_response] An error occurred while attempting to retrieve the UserInfo Resource: 500 Server Error");
-	}
-
-	@Test
-	public void loadUserWhenUserInfoUriInvalidThenThrowOAuth2AuthenticationException() {
-		String userInfoUri = "https://invalid-provider.com/user";
-		ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
-		assertThatExceptionOfType(OAuth2AuthenticationException.class)
-				.isThrownBy(
-						() -> this.userService.loadUser(new OAuth2UserRequest(clientRegistration, this.accessToken)))
-				.withMessageContaining(
-						"[invalid_user_info_response] An error occurred while attempting to retrieve the UserInfo Resource");
-	}
-
-	private ClientRegistration.Builder withRegistrationId(String registrationId) {
-		// @formatter:off
-		return ClientRegistration.withRegistrationId(registrationId)
-				.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
-				.clientId("client")
-				.tokenUri("/token");
-		// @formatter:on
-	}
-
-	private MockResponse jsonResponse(String json) {
-		return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(json);
-	}
-
-	public static class CustomOAuth2User implements OAuth2User {
-
-		private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
-
-		private String id;
-
-		private String name;
-
-		private String login;
-
-		private String email;
-
-		public CustomOAuth2User() {
-		}
-
-		@Override
-		public Collection<? extends GrantedAuthority> getAuthorities() {
-			return this.authorities;
-		}
-
-		@Override
-		public Map<String, Object> getAttributes() {
-			Map<String, Object> attributes = new HashMap<>();
-			attributes.put("id", this.getId());
-			attributes.put("name", this.getName());
-			attributes.put("login", this.getLogin());
-			attributes.put("email", this.getEmail());
-			return attributes;
-		}
-
-		public String getId() {
-			return this.id;
-		}
-
-		public void setId(String id) {
-			this.id = id;
-		}
-
-		@Override
-		public String getName() {
-			return this.name;
-		}
-
-		public void setName(String name) {
-			this.name = name;
-		}
-
-		public String getLogin() {
-			return this.login;
-		}
-
-		public void setLogin(String login) {
-			this.login = login;
-		}
-
-		public String getEmail() {
-			return this.email;
-		}
-
-		public void setEmail(String email) {
-			this.email = email;
-		}
-
-	}
-
-}