浏览代码

OidcUserService leverages DefaultOAuth2UserService

Fixes gh-5390
Joe Grandja 7 年之前
父节点
当前提交
fe979aa996

+ 0 - 168
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/userinfo/NimbusUserInfoResponseClient.java

@@ -1,168 +0,0 @@
-/*
- * 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.oidc.userinfo;
-
-import com.nimbusds.oauth2.sdk.ErrorObject;
-import com.nimbusds.oauth2.sdk.ParseException;
-import com.nimbusds.oauth2.sdk.http.HTTPRequest;
-import com.nimbusds.oauth2.sdk.http.HTTPResponse;
-import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
-import com.nimbusds.openid.connect.sdk.UserInfoErrorResponse;
-import com.nimbusds.openid.connect.sdk.UserInfoRequest;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.client.AbstractClientHttpResponse;
-import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.http.converter.GenericHttpMessageConverter;
-import org.springframework.http.converter.HttpMessageNotReadableException;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import org.springframework.security.authentication.AuthenticationServiceException;
-import org.springframework.security.oauth2.client.registration.ClientRegistration;
-import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
-import org.springframework.security.oauth2.core.OAuth2AccessToken;
-import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.core.OAuth2Error;
-import org.springframework.util.Assert;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.nio.charset.Charset;
-
-/**
- * NOTE: This is a straight copy of org.springframework.security.oauth2.client.userinfo.NimbusUserInfoResponseClient
- *
- * @author Joe Grandja
- * @since 5.0
- */
-final class NimbusUserInfoResponseClient {
-	private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
-	private final GenericHttpMessageConverter genericHttpMessageConverter = new MappingJackson2HttpMessageConverter();
-
-	<T> T getUserInfoResponse(OAuth2UserRequest userInfoRequest, Class<T> returnType) throws OAuth2AuthenticationException {
-		ClientHttpResponse userInfoResponse = this.getUserInfoResponse(
-			userInfoRequest.getClientRegistration(), userInfoRequest.getAccessToken());
-		try {
-			return (T) this.genericHttpMessageConverter.read(returnType, userInfoResponse);
-		} catch (IOException | HttpMessageNotReadableException ex) {
-			OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
-				"An error occurred reading the UserInfo Success response: " + ex.getMessage(), null);
-			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
-		}
-	}
-
-	<T> T getUserInfoResponse(OAuth2UserRequest userInfoRequest, ParameterizedTypeReference<T> typeReference) throws OAuth2AuthenticationException {
-		ClientHttpResponse userInfoResponse = this.getUserInfoResponse(
-			userInfoRequest.getClientRegistration(), userInfoRequest.getAccessToken());
-		try {
-			return (T) this.genericHttpMessageConverter.read(typeReference.getType(), null, userInfoResponse);
-		} catch (IOException | HttpMessageNotReadableException ex) {
-			OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
-				"An error occurred reading the UserInfo Success response: " + ex.getMessage(), null);
-			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
-		}
-	}
-
-	private ClientHttpResponse getUserInfoResponse(ClientRegistration clientRegistration,
-													OAuth2AccessToken oauth2AccessToken) throws OAuth2AuthenticationException {
-		URI userInfoUri = URI.create(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri());
-		BearerAccessToken accessToken = new BearerAccessToken(oauth2AccessToken.getTokenValue());
-
-		UserInfoRequest userInfoRequest = new UserInfoRequest(userInfoUri, accessToken);
-		HTTPRequest httpRequest = userInfoRequest.toHTTPRequest();
-		httpRequest.setAccept(MediaType.APPLICATION_JSON_VALUE);
-		httpRequest.setConnectTimeout(30000);
-		httpRequest.setReadTimeout(30000);
-		HTTPResponse httpResponse;
-
-		try {
-			httpResponse = httpRequest.send();
-		} catch (IOException ex) {
-			throw new AuthenticationServiceException("An error occurred while sending the UserInfo Request: " +
-				ex.getMessage(), ex);
-		}
-
-		if (httpResponse.getStatusCode() == HTTPResponse.SC_OK) {
-			return new NimbusClientHttpResponse(httpResponse);
-		}
-
-		UserInfoErrorResponse userInfoErrorResponse;
-		try {
-			userInfoErrorResponse = UserInfoErrorResponse.parse(httpResponse);
-		} catch (ParseException ex) {
-			OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
-				"An error occurred parsing the UserInfo Error response: " + ex.getMessage(), null);
-			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
-		}
-		ErrorObject errorObject = userInfoErrorResponse.getErrorObject();
-
-		StringBuilder errorDescription = new StringBuilder();
-		errorDescription.append("An error occurred while attempting to access the UserInfo Endpoint -> ");
-		errorDescription.append("Error details: [");
-		errorDescription.append("UserInfo Uri: ").append(userInfoUri.toString());
-		errorDescription.append(", Http Status: ").append(errorObject.getHTTPStatusCode());
-		if (errorObject.getCode() != null) {
-			errorDescription.append(", Error Code: ").append(errorObject.getCode());
-		}
-		if (errorObject.getDescription() != null) {
-			errorDescription.append(", Error Description: ").append(errorObject.getDescription());
-		}
-		errorDescription.append("]");
-
-		OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, errorDescription.toString(), null);
-		throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
-	}
-
-	private static class NimbusClientHttpResponse extends AbstractClientHttpResponse {
-		private final HTTPResponse httpResponse;
-		private final HttpHeaders headers;
-
-		private NimbusClientHttpResponse(HTTPResponse httpResponse) {
-			Assert.notNull(httpResponse, "httpResponse cannot be null");
-			this.httpResponse = httpResponse;
-			this.headers = new HttpHeaders();
-			this.headers.setAll(httpResponse.getHeaders());
-		}
-
-		@Override
-		public int getRawStatusCode() throws IOException {
-			return this.httpResponse.getStatusCode();
-		}
-
-		@Override
-		public String getStatusText() throws IOException {
-			return String.valueOf(this.getRawStatusCode());
-		}
-
-		@Override
-		public void close() {
-		}
-
-		@Override
-		public InputStream getBody() throws IOException {
-			InputStream inputStream = new ByteArrayInputStream(
-				this.httpResponse.getContent().getBytes(Charset.forName("UTF-8")));
-			return inputStream;
-		}
-
-		@Override
-		public HttpHeaders getHeaders() {
-			return this.headers;
-		}
-	}
-}

+ 7 - 8
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/userinfo/OidcUserService.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2017 the original author or authors.
+ * 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.
@@ -15,8 +15,9 @@
  */
 package org.springframework.security.oauth2.client.oidc.userinfo;
 
-import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
+import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
 import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
@@ -26,12 +27,12 @@ import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
 import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
 import org.springframework.security.oauth2.core.oidc.user.OidcUser;
 import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
+import org.springframework.security.oauth2.core.user.OAuth2User;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
 import java.util.Arrays;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -49,17 +50,15 @@ public class OidcUserService implements OAuth2UserService<OidcUserRequest, OidcU
 	private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
 	private final Set<String> userInfoScopes = new HashSet<>(
 		Arrays.asList(OidcScopes.PROFILE, OidcScopes.EMAIL, OidcScopes.ADDRESS, OidcScopes.PHONE));
-	private NimbusUserInfoResponseClient userInfoResponseClient = new NimbusUserInfoResponseClient();
+	private final OAuth2UserService<OAuth2UserRequest, OAuth2User> defaultUserService = new DefaultOAuth2UserService();
 
 	@Override
 	public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
 		Assert.notNull(userRequest, "userRequest cannot be null");
 		OidcUserInfo userInfo = null;
 		if (this.shouldRetrieveUserInfo(userRequest)) {
-			ParameterizedTypeReference<Map<String, Object>> typeReference =
-				new ParameterizedTypeReference<Map<String, Object>>() {};
-			Map<String, Object> userAttributes = this.userInfoResponseClient.getUserInfoResponse(userRequest, typeReference);
-			userInfo = new OidcUserInfo(userAttributes);
+			OAuth2User oauth2User = this.defaultUserService.loadUser(userRequest);
+			userInfo = new OidcUserInfo(oauth2User.getAttributes());
 
 			// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
 			// Due to the possibility of token substitution attacks (see Section 16.11),

+ 2 - 0
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/userinfo/OidcUserServiceTests.java

@@ -79,6 +79,8 @@ public class OidcUserServiceTests {
 		when(this.providerDetails.getUserInfoEndpoint()).thenReturn(this.userInfoEndpoint);
 		when(this.clientRegistration.getAuthorizationGrantType()).thenReturn(AuthorizationGrantType.AUTHORIZATION_CODE);
 
+		when(this.userInfoEndpoint.getUserNameAttributeName()).thenReturn(StandardClaimNames.SUB);
+
 		this.accessToken = mock(OAuth2AccessToken.class);
 		Set<String> authorizedScopes = new LinkedHashSet<>(Arrays.asList(OidcScopes.OPENID, OidcScopes.PROFILE));
 		when(this.accessToken.getScopes()).thenReturn(authorizedScopes);