parent
ec970c9b8e
commit
d32aa3c6d6
|
|
@ -15,10 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.oauth2.client.oidc.userinfo;
|
package org.springframework.security.oauth2.client.oidc.userinfo;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||||
|
|
@ -36,6 +32,10 @@ import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of an {@link OAuth2UserService} that supports OpenID Connect 1.0 Provider's.
|
* An implementation of an {@link OAuth2UserService} that supports OpenID Connect 1.0 Provider's.
|
||||||
*
|
*
|
||||||
|
|
@ -62,7 +62,14 @@ public class OidcUserService implements OAuth2UserService<OidcUserRequest, OidcU
|
||||||
userInfo = new OidcUserInfo(oauth2User.getAttributes());
|
userInfo = new OidcUserInfo(oauth2User.getAttributes());
|
||||||
|
|
||||||
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||||
// Due to the possibility of token substitution attacks (see Section 16.11),
|
|
||||||
|
// 1) The sub (subject) Claim MUST always be returned in the UserInfo Response
|
||||||
|
if (userInfo.getSubject() == null) {
|
||||||
|
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE);
|
||||||
|
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Due to the possibility of token substitution attacks (see Section 16.11),
|
||||||
// the UserInfo Response is not guaranteed to be about the End-User
|
// the UserInfo Response is not guaranteed to be about the End-User
|
||||||
// identified by the sub (subject) element of the ID Token.
|
// identified by the sub (subject) element of the ID Token.
|
||||||
// The sub Claim in the UserInfo Response MUST be verified to exactly match
|
// The sub Claim in the UserInfo Response MUST be verified to exactly match
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,37 @@ public class OidcUserServiceTests {
|
||||||
assertThat(userAuthority.getUserInfo()).isEqualTo(user.getUserInfo());
|
assertThat(userAuthority.getUserInfo()).isEqualTo(user.getUserInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-5447
|
||||||
|
@Test
|
||||||
|
public void loadUserWhenUserInfoSuccessResponseAndUserInfoSubjectIsNullThenThrowOAuth2AuthenticationException() throws Exception {
|
||||||
|
this.exception.expect(OAuth2AuthenticationException.class);
|
||||||
|
this.exception.expectMessage(containsString("invalid_user_info_response"));
|
||||||
|
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
|
||||||
|
String userInfoResponse = "{\n" +
|
||||||
|
" \"email\": \"full_name@provider.com\",\n" +
|
||||||
|
" \"name\": \"full name\"\n" +
|
||||||
|
"}\n";
|
||||||
|
server.enqueue(new MockResponse()
|
||||||
|
.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.setBody(userInfoResponse));
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
String userInfoUri = server.url("/user").toString();
|
||||||
|
|
||||||
|
when(this.userInfoEndpoint.getUri()).thenReturn(userInfoUri);
|
||||||
|
when(this.userInfoEndpoint.getUserNameAttributeName()).thenReturn(StandardClaimNames.EMAIL);
|
||||||
|
when(this.accessToken.getTokenValue()).thenReturn("access-token");
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.userService.loadUser(new OidcUserRequest(this.clientRegistration, this.accessToken, this.idToken));
|
||||||
|
} finally {
|
||||||
|
server.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loadUserWhenUserInfoSuccessResponseAndUserInfoSubjectNotSameAsIdTokenSubjectThenThrowOAuth2AuthenticationException() throws Exception {
|
public void loadUserWhenUserInfoSuccessResponseAndUserInfoSubjectNotSameAsIdTokenSubjectThenThrowOAuth2AuthenticationException() throws Exception {
|
||||||
this.exception.expect(OAuth2AuthenticationException.class);
|
this.exception.expect(OAuth2AuthenticationException.class);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue