|
15 | 15 | */
|
16 | 16 | package org.springframework.security.oauth2.client.oidc.userinfo;
|
17 | 17 |
|
| 18 | +import java.time.Instant; |
| 19 | +import java.util.Arrays; |
| 20 | +import java.util.Collections; |
| 21 | +import java.util.HashMap; |
| 22 | +import java.util.Iterator; |
| 23 | +import java.util.Map; |
| 24 | +import java.util.concurrent.TimeUnit; |
| 25 | +import java.util.function.Function; |
| 26 | + |
18 | 27 | import okhttp3.mockwebserver.MockResponse;
|
19 | 28 | import okhttp3.mockwebserver.MockWebServer;
|
20 | 29 | import okhttp3.mockwebserver.RecordedRequest;
|
|
23 | 32 | import org.junit.Rule;
|
24 | 33 | import org.junit.Test;
|
25 | 34 | import org.junit.rules.ExpectedException;
|
| 35 | + |
| 36 | +import org.springframework.core.ParameterizedTypeReference; |
26 | 37 | import org.springframework.core.convert.converter.Converter;
|
27 | 38 | import org.springframework.http.HttpHeaders;
|
28 | 39 | import org.springframework.http.HttpMethod;
|
| 40 | +import org.springframework.http.HttpStatus; |
29 | 41 | import org.springframework.http.MediaType;
|
| 42 | +import org.springframework.http.RequestEntity; |
| 43 | +import org.springframework.http.ResponseEntity; |
| 44 | +import org.springframework.security.core.GrantedAuthority; |
| 45 | +import org.springframework.security.core.authority.SimpleGrantedAuthority; |
30 | 46 | import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
31 | 47 | import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
| 48 | +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; |
32 | 49 | import org.springframework.security.oauth2.core.AuthenticationMethod;
|
33 | 50 | import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
34 | 51 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|
39 | 56 | import org.springframework.security.oauth2.core.oidc.StandardClaimNames;
|
40 | 57 | import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
41 | 58 | import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
|
42 |
| - |
43 |
| -import java.time.Instant; |
44 |
| -import java.util.Collections; |
45 |
| -import java.util.HashMap; |
46 |
| -import java.util.Map; |
47 |
| -import java.util.concurrent.TimeUnit; |
48 |
| -import java.util.function.Function; |
| 59 | +import org.springframework.web.client.RestOperations; |
49 | 60 |
|
50 | 61 | import static org.assertj.core.api.Assertions.assertThat;
|
51 | 62 | import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
52 | 63 | import static org.hamcrest.CoreMatchers.containsString;
|
53 |
| -import static org.mockito.Mockito.*; |
| 64 | +import static org.mockito.Mockito.any; |
| 65 | +import static org.mockito.Mockito.mock; |
| 66 | +import static org.mockito.Mockito.nullable; |
| 67 | +import static org.mockito.Mockito.same; |
| 68 | +import static org.mockito.Mockito.verify; |
| 69 | +import static org.mockito.Mockito.when; |
54 | 70 | import static org.springframework.security.oauth2.client.registration.TestClientRegistrations.clientRegistration;
|
55 | 71 | import static org.springframework.security.oauth2.core.TestOAuth2AccessTokens.scopes;
|
| 72 | +import static org.springframework.security.oauth2.core.oidc.TestOidcIdTokens.idToken; |
56 | 73 |
|
57 | 74 | /**
|
58 | 75 | * Tests for {@link OidcUserService}.
|
@@ -481,6 +498,73 @@ public void loadUserWhenCustomClaimTypeConverterFactorySetThenApplied() {
|
481 | 498 | verify(customClaimTypeConverterFactory).apply(same(clientRegistration));
|
482 | 499 | }
|
483 | 500 |
|
| 501 | + @Test |
| 502 | + public void loadUserWhenAttributesContainScopeThenIndividualScopeAuthorities() { |
| 503 | + Map<String, Object> body = new HashMap<>(); |
| 504 | + body.put("id", "id"); |
| 505 | + body.put("sub", "test-subject"); |
| 506 | + body.put("scope", "message:read message:write"); |
| 507 | + OidcUserService userService = new OidcUserService(); |
| 508 | + userService.setOauth2UserService(withMockResponse(body)); |
| 509 | + OidcUserRequest request = new OidcUserRequest(clientRegistration(). |
| 510 | + userInfoUri("uri").build(), scopes("profile"), idToken(body)); |
| 511 | + OidcUser user = userService.loadUser(request); |
| 512 | + |
| 513 | + assertThat(user.getAuthorities()).hasSize(3); |
| 514 | + Iterator<? extends GrantedAuthority> authorities = user.getAuthorities().iterator(); |
| 515 | + assertThat(authorities.next()).isInstanceOf(OidcUserAuthority.class); |
| 516 | + assertThat(authorities.next()).isEqualTo(new SimpleGrantedAuthority("SCOPE_message:read")); |
| 517 | + assertThat(authorities.next()).isEqualTo(new SimpleGrantedAuthority("SCOPE_message:write")); |
| 518 | + } |
| 519 | + |
| 520 | + @Test |
| 521 | + public void loadUserWhenAttributesContainScpThenIndividualScopeAuthorities() { |
| 522 | + Map<String, Object> body = new HashMap<>(); |
| 523 | + body.put("id", "id"); |
| 524 | + body.put("sub", "test-subject"); |
| 525 | + body.put("scp", Arrays.asList("message:read", "message:write")); |
| 526 | + OidcUserService userService = new OidcUserService(); |
| 527 | + userService.setOauth2UserService(withMockResponse(body)); |
| 528 | + OidcUserRequest request = new OidcUserRequest(clientRegistration(). |
| 529 | + userInfoUri("uri").build(), scopes("profile"), idToken(body)); |
| 530 | + OidcUser user = userService.loadUser(request); |
| 531 | + |
| 532 | + assertThat(user.getAuthorities()).hasSize(3); |
| 533 | + Iterator<? extends GrantedAuthority> authorities = user.getAuthorities().iterator(); |
| 534 | + assertThat(authorities.next()).isInstanceOf(OidcUserAuthority.class); |
| 535 | + assertThat(authorities.next()).isEqualTo(new SimpleGrantedAuthority("SCOPE_message:read")); |
| 536 | + assertThat(authorities.next()).isEqualTo(new SimpleGrantedAuthority("SCOPE_message:write")); |
| 537 | + } |
| 538 | + |
| 539 | + @Test |
| 540 | + public void loadUserWhenAttributesDoesNotContainScopesThenNoScopeAuthorities() { |
| 541 | + Map<String, Object> body = new HashMap<>(); |
| 542 | + body.put("id", "id"); |
| 543 | + body.put("sub", "test-subject"); |
| 544 | + body.put("authorities", Arrays.asList("message:read", "message:write")); |
| 545 | + OidcUserService userService = new OidcUserService(); |
| 546 | + userService.setOauth2UserService(withMockResponse(body)); |
| 547 | + OidcUserRequest request = new OidcUserRequest(clientRegistration(). |
| 548 | + userInfoUri("uri").build(), scopes("profile"), idToken(body)); |
| 549 | + OidcUser user = userService.loadUser(request); |
| 550 | + |
| 551 | + assertThat(user.getAuthorities()).hasSize(1); |
| 552 | + Iterator<? extends GrantedAuthority> authorities = user.getAuthorities().iterator(); |
| 553 | + assertThat(authorities.next()).isInstanceOf(OidcUserAuthority.class); |
| 554 | + } |
| 555 | + |
| 556 | + private DefaultOAuth2UserService withMockResponse(Map<String, Object> response) { |
| 557 | + ResponseEntity<Map<String, Object>> responseEntity = new ResponseEntity<>(response, HttpStatus.OK); |
| 558 | + Converter<OAuth2UserRequest, RequestEntity<?>> requestEntityConverter = mock(Converter.class); |
| 559 | + RestOperations rest = mock(RestOperations.class); |
| 560 | + when(rest.exchange(nullable(RequestEntity.class), any(ParameterizedTypeReference.class))) |
| 561 | + .thenReturn(responseEntity); |
| 562 | + DefaultOAuth2UserService userService = new DefaultOAuth2UserService(); |
| 563 | + userService.setRequestEntityConverter(requestEntityConverter); |
| 564 | + userService.setRestOperations(rest); |
| 565 | + return userService; |
| 566 | + } |
| 567 | + |
484 | 568 | private MockResponse jsonResponse(String json) {
|
485 | 569 | return new MockResponse()
|
486 | 570 | .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
|
0 commit comments