Skip to content

Commit 09810b8

Browse files
committed
oidcLogin Test Configuration Flow
Fixes gh-7794
1 parent 84ba3dd commit 09810b8

File tree

4 files changed

+74
-21
lines changed

4 files changed

+74
-21
lines changed

test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ public final static class OidcLoginMutator implements WebTestClientConfigurer, M
471471
private OAuth2AccessToken accessToken;
472472
private OidcIdToken idToken;
473473
private OidcUserInfo userInfo;
474-
private OidcUser oidcUser;
474+
private Supplier<OidcUser> oidcUser = this::defaultPrincipal;
475475
private Collection<GrantedAuthority> authorities;
476476

477477
ServerOAuth2AuthorizedClientRepository authorizedClientRepository =
@@ -491,6 +491,7 @@ private OidcLoginMutator(OAuth2AccessToken accessToken) {
491491
public OidcLoginMutator authorities(Collection<GrantedAuthority> authorities) {
492492
Assert.notNull(authorities, "authorities cannot be null");
493493
this.authorities = authorities;
494+
this.oidcUser = this::defaultPrincipal;
494495
return this;
495496
}
496497

@@ -503,6 +504,7 @@ public OidcLoginMutator authorities(Collection<GrantedAuthority> authorities) {
503504
public OidcLoginMutator authorities(GrantedAuthority... authorities) {
504505
Assert.notNull(authorities, "authorities cannot be null");
505506
this.authorities = Arrays.asList(authorities);
507+
this.oidcUser = this::defaultPrincipal;
506508
return this;
507509
}
508510

@@ -517,6 +519,7 @@ public OidcLoginMutator idToken(Consumer<OidcIdToken.Builder> idTokenBuilderCons
517519
builder.subject("test-subject");
518520
idTokenBuilderConsumer.accept(builder);
519521
this.idToken = builder.build();
522+
this.oidcUser = this::defaultPrincipal;
520523
return this;
521524
}
522525

@@ -530,6 +533,7 @@ public OidcLoginMutator userInfoToken(Consumer<OidcUserInfo.Builder> userInfoBui
530533
OidcUserInfo.Builder builder = OidcUserInfo.builder();
531534
userInfoBuilderConsumer.accept(builder);
532535
this.userInfo = builder.build();
536+
this.oidcUser = this::defaultPrincipal;
533537
return this;
534538
}
535539

@@ -543,7 +547,7 @@ public OidcLoginMutator userInfoToken(Consumer<OidcUserInfo.Builder> userInfoBui
543547
* @return the {@link OidcLoginMutator} for further configuration
544548
*/
545549
public OidcLoginMutator oidcUser(OidcUser oidcUser) {
546-
this.oidcUser = oidcUser;
550+
this.oidcUser = () -> oidcUser;
547551
return this;
548552
}
549553

@@ -601,7 +605,7 @@ private ClientRegistration.Builder clientRegistrationBuilder() {
601605
}
602606

603607
private OAuth2AuthenticationToken getToken() {
604-
OidcUser oidcUser = getOidcUser();
608+
OidcUser oidcUser = this.oidcUser.get();
605609
return new OAuth2AuthenticationToken(oidcUser, oidcUser.getAuthorities(), this.clientRegistration.getRegistrationId());
606610
}
607611

@@ -634,12 +638,8 @@ private OidcUserInfo getOidcUserInfo() {
634638
return this.userInfo;
635639
}
636640

637-
private OidcUser getOidcUser() {
638-
if (this.oidcUser == null) {
639-
return new DefaultOidcUser(getAuthorities(), getOidcIdToken(), this.userInfo);
640-
} else {
641-
return this.oidcUser;
642-
}
641+
private OidcUser defaultPrincipal() {
642+
return new DefaultOidcUser(getAuthorities(), getOidcIdToken(), this.userInfo);
643643
}
644644
}
645645
}

test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,7 +1432,7 @@ public final static class OidcLoginRequestPostProcessor implements RequestPostPr
14321432
private OAuth2AccessToken accessToken;
14331433
private OidcIdToken idToken;
14341434
private OidcUserInfo userInfo;
1435-
private OidcUser oidcUser;
1435+
private Supplier<OidcUser> oidcUser = this::defaultPrincipal;
14361436
private Collection<GrantedAuthority> authorities;
14371437

14381438
private OidcLoginRequestPostProcessor(OAuth2AccessToken accessToken) {
@@ -1449,6 +1449,7 @@ private OidcLoginRequestPostProcessor(OAuth2AccessToken accessToken) {
14491449
public OidcLoginRequestPostProcessor authorities(Collection<GrantedAuthority> authorities) {
14501450
Assert.notNull(authorities, "authorities cannot be null");
14511451
this.authorities = authorities;
1452+
this.oidcUser = this::defaultPrincipal;
14521453
return this;
14531454
}
14541455

@@ -1461,6 +1462,7 @@ public OidcLoginRequestPostProcessor authorities(Collection<GrantedAuthority> au
14611462
public OidcLoginRequestPostProcessor authorities(GrantedAuthority... authorities) {
14621463
Assert.notNull(authorities, "authorities cannot be null");
14631464
this.authorities = Arrays.asList(authorities);
1465+
this.oidcUser = this::defaultPrincipal;
14641466
return this;
14651467
}
14661468

@@ -1475,6 +1477,7 @@ public OidcLoginRequestPostProcessor idToken(Consumer<OidcIdToken.Builder> idTok
14751477
builder.subject("test-subject");
14761478
idTokenBuilderConsumer.accept(builder);
14771479
this.idToken = builder.build();
1480+
this.oidcUser = this::defaultPrincipal;
14781481
return this;
14791482
}
14801483

@@ -1488,20 +1491,19 @@ public OidcLoginRequestPostProcessor userInfoToken(Consumer<OidcUserInfo.Builder
14881491
OidcUserInfo.Builder builder = OidcUserInfo.builder();
14891492
userInfoBuilderConsumer.accept(builder);
14901493
this.userInfo = builder.build();
1494+
this.oidcUser = this::defaultPrincipal;
14911495
return this;
14921496
}
14931497

14941498
/**
14951499
* Use the provided {@link OidcUser} as the authenticated user.
14961500
*
1497-
* Supplying an {@link OidcUser} will take precedence over {@link #idToken}, {@link #userInfo},
1498-
* and list of {@link GrantedAuthority}s to use.
14991501
*
15001502
* @param oidcUser the {@link OidcUser} to use
15011503
* @return the {@link OidcLoginRequestPostProcessor} for further configuration
15021504
*/
15031505
public OidcLoginRequestPostProcessor oidcUser(OidcUser oidcUser) {
1504-
this.oidcUser = oidcUser;
1506+
this.oidcUser = () -> oidcUser;
15051507
return this;
15061508
}
15071509

@@ -1524,7 +1526,7 @@ public OidcLoginRequestPostProcessor clientRegistration(ClientRegistration clien
15241526

15251527
@Override
15261528
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
1527-
OidcUser oidcUser = getOidcUser();
1529+
OidcUser oidcUser = this.oidcUser.get();
15281530
return new OAuth2LoginRequestPostProcessor(this.accessToken)
15291531
.oauth2User(oidcUser)
15301532
.clientRegistration(this.clientRegistration)
@@ -1553,7 +1555,8 @@ private Collection<GrantedAuthority> getAuthorities() {
15531555

15541556
private OidcIdToken getOidcIdToken() {
15551557
if (this.idToken == null) {
1556-
return new OidcIdToken("id-token", null, null, Collections.singletonMap(IdTokenClaimNames.SUB, "test-subject"));
1558+
return new OidcIdToken("id-token", null, null,
1559+
Collections.singletonMap(IdTokenClaimNames.SUB, "test-subject"));
15571560
} else {
15581561
return this.idToken;
15591562
}
@@ -1563,12 +1566,8 @@ private OidcUserInfo getOidcUserInfo() {
15631566
return this.userInfo;
15641567
}
15651568

1566-
private OidcUser getOidcUser() {
1567-
if (this.oidcUser == null) {
1568-
return new DefaultOidcUser(getAuthorities(), getOidcIdToken(), this.userInfo);
1569-
} else {
1570-
return this.oidcUser;
1571-
}
1569+
private OidcUser defaultPrincipal() {
1570+
return new DefaultOidcUser(getAuthorities(), getOidcIdToken(), this.userInfo);
15721571
}
15731572
}
15741573

test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersOidcLoginTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.http.HttpHeaders;
2828
import org.springframework.http.MediaType;
2929
import org.springframework.security.core.GrantedAuthority;
30+
import org.springframework.security.core.authority.AuthorityUtils;
3031
import org.springframework.security.core.authority.SimpleGrantedAuthority;
3132
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
3233
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
@@ -35,13 +36,15 @@
3536
import org.springframework.security.oauth2.client.web.reactive.result.method.annotation.OAuth2AuthorizedClientArgumentResolver;
3637
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
3738
import org.springframework.security.oauth2.client.web.server.WebSessionServerOAuth2AuthorizedClientRepository;
39+
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
3840
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
3941
import org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter;
4042
import org.springframework.test.web.reactive.server.WebTestClient;
4143
import org.springframework.web.bind.annotation.GetMapping;
4244
import org.springframework.web.bind.annotation.RestController;
4345

4446
import static org.assertj.core.api.Assertions.assertThat;
47+
import static org.springframework.security.oauth2.core.oidc.TestOidcIdTokens.idToken;
4548
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOidcLogin;
4649
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
4750

@@ -143,6 +146,35 @@ public void oidcLoginWhenUserInfoSpecifiedThenUserHasClaims() throws Exception {
143146
.containsEntry("email", "email@email");
144147
}
145148

149+
// gh-7794
150+
@Test
151+
public void oidcLoginWhenOidcUserSpecifiedThenLastCalledTakesPrecedence() throws Exception {
152+
OidcUser oidcUser = new DefaultOidcUser(
153+
AuthorityUtils.createAuthorityList("SCOPE_user"), idToken().build());
154+
155+
this.client.mutateWith(mockOidcLogin()
156+
.idToken(i -> i.subject("foo"))
157+
.oidcUser(oidcUser))
158+
.get().uri("/token")
159+
.exchange()
160+
.expectStatus().isOk();
161+
162+
OAuth2AuthenticationToken token = this.controller.token;
163+
assertThat(token.getPrincipal().getAttributes())
164+
.containsEntry("sub", "subject");
165+
166+
this.client.mutateWith(mockOidcLogin()
167+
.oidcUser(oidcUser)
168+
.idToken(i -> i.subject("bar")))
169+
.get().uri("/token")
170+
.exchange()
171+
.expectStatus().isOk();
172+
173+
token = this.controller.token;
174+
assertThat(token.getPrincipal().getAttributes())
175+
.containsEntry("sub", "bar");
176+
}
177+
146178
@RestController
147179
static class OAuth2LoginController {
148180
volatile OAuth2AuthenticationToken token;

test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOidcLoginTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@
3131
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
3232
import org.springframework.security.core.GrantedAuthority;
3333
import org.springframework.security.core.annotation.AuthenticationPrincipal;
34+
import org.springframework.security.core.authority.AuthorityUtils;
3435
import org.springframework.security.core.authority.SimpleGrantedAuthority;
3536
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
3637
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
3738
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
3839
import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository;
3940
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
41+
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
4042
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
4143
import org.springframework.security.test.context.TestSecurityContextHolder;
4244
import org.springframework.test.context.ContextConfiguration;
@@ -51,6 +53,7 @@
5153
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
5254

5355
import static org.mockito.Mockito.mock;
56+
import static org.springframework.security.oauth2.core.oidc.TestOidcIdTokens.idToken;
5457
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oidcLogin;
5558
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
5659
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -126,6 +129,25 @@ public void oidcLoginWhenUserInfoSpecifiedThenUserHasClaims() throws Exception {
126129
.andExpect(content().string("email@email"));
127130
}
128131

132+
// gh-7794
133+
@Test
134+
public void oidcLoginWhenOidcUserSpecifiedThenLastCalledTakesPrecedence() throws Exception {
135+
OidcUser oidcUser = new DefaultOidcUser(
136+
AuthorityUtils.createAuthorityList("SCOPE_user"), idToken().build());
137+
138+
this.mvc.perform(get("/id-token/sub")
139+
.with(oidcLogin()
140+
.idToken(i -> i.subject("foo"))
141+
.oidcUser(oidcUser)))
142+
.andExpect(status().isOk())
143+
.andExpect(content().string("subject"));
144+
this.mvc.perform(get("/id-token/sub")
145+
.with(oidcLogin()
146+
.oidcUser(oidcUser)
147+
.idToken(i -> i.subject("bar"))))
148+
.andExpect(content().string("bar"));
149+
}
150+
129151
@EnableWebSecurity
130152
@EnableWebMvc
131153
static class OAuth2LoginConfig extends WebSecurityConfigurerAdapter {

0 commit comments

Comments
 (0)