11/*
2- * Copyright 2002-2018 the original author or authors.
2+ * Copyright 2002-2019 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1515 */
1616package org .springframework .security .config .annotation .web .configuration ;
1717
18+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
19+ import static org .mockito .ArgumentMatchers .any ;
20+ import static org .mockito .ArgumentMatchers .eq ;
21+ import static org .mockito .Mockito .mock ;
22+ import static org .mockito .Mockito .times ;
23+ import static org .mockito .Mockito .verify ;
24+ import static org .mockito .Mockito .verifyZeroInteractions ;
25+ import static org .mockito .Mockito .when ;
26+ import static org .springframework .security .oauth2 .client .registration .TestClientRegistrations .clientCredentials ;
27+ import static org .springframework .security .test .web .servlet .request .SecurityMockMvcRequestPostProcessors .authentication ;
28+ import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .get ;
29+ import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .content ;
30+ import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .status ;
31+
32+ import javax .servlet .http .HttpServletRequest ;
1833import org .junit .Rule ;
1934import org .junit .Test ;
2035import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
2641import org .springframework .security .config .test .SpringTestRule ;
2742import org .springframework .security .oauth2 .client .OAuth2AuthorizedClient ;
2843import org .springframework .security .oauth2 .client .annotation .RegisteredOAuth2AuthorizedClient ;
44+ import org .springframework .security .oauth2 .client .endpoint .OAuth2AccessTokenResponseClient ;
45+ import org .springframework .security .oauth2 .client .endpoint .OAuth2ClientCredentialsGrantRequest ;
46+ import org .springframework .security .oauth2 .client .registration .ClientRegistration ;
2947import org .springframework .security .oauth2 .client .registration .ClientRegistrationRepository ;
3048import org .springframework .security .oauth2 .client .web .OAuth2AuthorizedClientRepository ;
3149import org .springframework .security .oauth2 .core .OAuth2AccessToken ;
50+ import org .springframework .security .oauth2 .core .endpoint .OAuth2AccessTokenResponse ;
3251import org .springframework .test .web .servlet .MockMvc ;
3352import org .springframework .web .bind .annotation .GetMapping ;
3453import org .springframework .web .bind .annotation .RestController ;
3554import org .springframework .web .servlet .config .annotation .EnableWebMvc ;
3655
37- import javax .servlet .http .HttpServletRequest ;
38-
39- import static org .assertj .core .api .Assertions .assertThatThrownBy ;
40- import static org .mockito .ArgumentMatchers .any ;
41- import static org .mockito .ArgumentMatchers .eq ;
42- import static org .mockito .Mockito .mock ;
43- import static org .mockito .Mockito .when ;
44- import static org .springframework .security .test .web .servlet .request .SecurityMockMvcRequestPostProcessors .authentication ;
45- import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .get ;
46- import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .content ;
47- import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .status ;
48-
4956/**
5057 * Tests for {@link OAuth2ClientConfiguration}.
5158 *
@@ -64,26 +71,66 @@ public void requestWhenAuthorizedClientFoundThenMethodArgumentResolved() throws
6471 String principalName = "user1" ;
6572 TestingAuthenticationToken authentication = new TestingAuthenticationToken (principalName , "password" );
6673
74+ ClientRegistrationRepository clientRegistrationRepository = mock (ClientRegistrationRepository .class );
6775 OAuth2AuthorizedClientRepository authorizedClientRepository = mock (OAuth2AuthorizedClientRepository .class );
6876 OAuth2AuthorizedClient authorizedClient = mock (OAuth2AuthorizedClient .class );
6977 when (authorizedClientRepository .loadAuthorizedClient (
70- eq (clientRegistrationId ), eq (authentication ), any (HttpServletRequest .class ))).thenReturn (authorizedClient );
78+ eq (clientRegistrationId ), eq (authentication ), any (HttpServletRequest .class )))
79+ .thenReturn (authorizedClient );
7180
7281 OAuth2AccessToken accessToken = mock (OAuth2AccessToken .class );
7382 when (authorizedClient .getAccessToken ()).thenReturn (accessToken );
7483
84+ OAuth2AccessTokenResponseClient accessTokenResponseClient = mock (OAuth2AccessTokenResponseClient .class );
85+
86+ OAuth2AuthorizedClientArgumentResolverConfig .CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository ;
7587 OAuth2AuthorizedClientArgumentResolverConfig .AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository ;
88+ OAuth2AuthorizedClientArgumentResolverConfig .ACCESS_TOKEN_RESPONSE_CLIENT = accessTokenResponseClient ;
7689 this .spring .register (OAuth2AuthorizedClientArgumentResolverConfig .class ).autowire ();
7790
7891 this .mockMvc .perform (get ("/authorized-client" ).with (authentication (authentication )))
79- .andExpect (status ().isOk ())
80- .andExpect (content ().string ("resolved" ));
92+ .andExpect (status ().isOk ())
93+ .andExpect (content ().string ("resolved" ));
94+ verifyZeroInteractions (accessTokenResponseClient );
95+ }
96+
97+ @ Test
98+ public void requestWhenAuthorizedClientNotFoundAndClientCredentialsThenTokenResponseClientIsUsed () throws Exception {
99+ String clientRegistrationId = "client1" ;
100+ String principalName = "user1" ;
101+ TestingAuthenticationToken authentication = new TestingAuthenticationToken (principalName , "password" );
102+
103+ ClientRegistrationRepository clientRegistrationRepository = mock (ClientRegistrationRepository .class );
104+ OAuth2AuthorizedClientRepository authorizedClientRepository = mock (OAuth2AuthorizedClientRepository .class );
105+ OAuth2AccessTokenResponseClient accessTokenResponseClient = mock (OAuth2AccessTokenResponseClient .class );
106+
107+ ClientRegistration clientRegistration = clientCredentials ().registrationId (clientRegistrationId ).build ();
108+ when (clientRegistrationRepository .findByRegistrationId (clientRegistrationId )).thenReturn (clientRegistration );
109+
110+ OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse .withToken ("access-token-1234" )
111+ .tokenType (OAuth2AccessToken .TokenType .BEARER )
112+ .expiresIn (300 )
113+ .build ();
114+ when (accessTokenResponseClient .getTokenResponse (any (OAuth2ClientCredentialsGrantRequest .class )))
115+ .thenReturn (accessTokenResponse );
116+
117+ OAuth2AuthorizedClientArgumentResolverConfig .CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository ;
118+ OAuth2AuthorizedClientArgumentResolverConfig .AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository ;
119+ OAuth2AuthorizedClientArgumentResolverConfig .ACCESS_TOKEN_RESPONSE_CLIENT = accessTokenResponseClient ;
120+ this .spring .register (OAuth2AuthorizedClientArgumentResolverConfig .class ).autowire ();
121+
122+ this .mockMvc .perform (get ("/authorized-client" ).with (authentication (authentication )))
123+ .andExpect (status ().isOk ())
124+ .andExpect (content ().string ("resolved" ));
125+ verify (accessTokenResponseClient , times (1 )).getTokenResponse (any (OAuth2ClientCredentialsGrantRequest .class ));
81126 }
82127
83128 @ EnableWebMvc
84129 @ EnableWebSecurity
85130 static class OAuth2AuthorizedClientArgumentResolverConfig extends WebSecurityConfigurerAdapter {
131+ static ClientRegistrationRepository CLIENT_REGISTRATION_REPOSITORY ;
86132 static OAuth2AuthorizedClientRepository AUTHORIZED_CLIENT_REPOSITORY ;
133+ static OAuth2AccessTokenResponseClient <OAuth2ClientCredentialsGrantRequest > ACCESS_TOKEN_RESPONSE_CLIENT ;
87134
88135 @ Override
89136 protected void configure (HttpSecurity http ) throws Exception {
@@ -100,13 +147,18 @@ public String authorizedClient(@RegisteredOAuth2AuthorizedClient("client1") OAut
100147
101148 @ Bean
102149 public ClientRegistrationRepository clientRegistrationRepository () {
103- return mock ( ClientRegistrationRepository . class ) ;
150+ return CLIENT_REGISTRATION_REPOSITORY ;
104151 }
105152
106153 @ Bean
107154 public OAuth2AuthorizedClientRepository authorizedClientRepository () {
108155 return AUTHORIZED_CLIENT_REPOSITORY ;
109156 }
157+
158+ @ Bean
159+ public OAuth2AccessTokenResponseClient <OAuth2ClientCredentialsGrantRequest > accessTokenResponseClient () {
160+ return ACCESS_TOKEN_RESPONSE_CLIENT ;
161+ }
110162 }
111163
112164 // gh-5321
@@ -147,6 +199,11 @@ public OAuth2AuthorizedClientRepository authorizedClientRepository1() {
147199 public OAuth2AuthorizedClientRepository authorizedClientRepository2 () {
148200 return mock (OAuth2AuthorizedClientRepository .class );
149201 }
202+
203+ @ Bean
204+ public OAuth2AccessTokenResponseClient <OAuth2ClientCredentialsGrantRequest > accessTokenResponseClient () {
205+ return mock (OAuth2AccessTokenResponseClient .class );
206+ }
150207 }
151208
152209 @ Test
@@ -208,5 +265,53 @@ public ClientRegistrationRepository clientRegistrationRepository2() {
208265 public OAuth2AuthorizedClientRepository authorizedClientRepository () {
209266 return mock (OAuth2AuthorizedClientRepository .class );
210267 }
268+
269+ @ Bean
270+ public OAuth2AccessTokenResponseClient <OAuth2ClientCredentialsGrantRequest > accessTokenResponseClient () {
271+ return mock (OAuth2AccessTokenResponseClient .class );
272+ }
273+ }
274+
275+ @ Test
276+ public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException () {
277+ assertThatThrownBy (() -> this .spring .register (AccessTokenResponseClientRegisteredTwiceConfig .class ).autowire ())
278+ .hasRootCauseInstanceOf (NoUniqueBeanDefinitionException .class )
279+ .hasMessageContaining ("expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2" );
280+ }
281+
282+ @ EnableWebMvc
283+ @ EnableWebSecurity
284+ static class AccessTokenResponseClientRegisteredTwiceConfig extends WebSecurityConfigurerAdapter {
285+
286+ @ Override
287+ protected void configure (HttpSecurity http ) throws Exception {
288+ // @formatter:off
289+ http
290+ .authorizeRequests ()
291+ .anyRequest ().authenticated ()
292+ .and ()
293+ .oauth2Login ();
294+ // @formatter:on
295+ }
296+
297+ @ Bean
298+ public ClientRegistrationRepository clientRegistrationRepository () {
299+ return mock (ClientRegistrationRepository .class );
300+ }
301+
302+ @ Bean
303+ public OAuth2AuthorizedClientRepository authorizedClientRepository () {
304+ return mock (OAuth2AuthorizedClientRepository .class );
305+ }
306+
307+ @ Bean
308+ public OAuth2AccessTokenResponseClient <OAuth2ClientCredentialsGrantRequest > accessTokenResponseClient1 () {
309+ return mock (OAuth2AccessTokenResponseClient .class );
310+ }
311+
312+ @ Bean
313+ public OAuth2AccessTokenResponseClient <OAuth2ClientCredentialsGrantRequest > accessTokenResponseClient2 () {
314+ return mock (OAuth2AccessTokenResponseClient .class );
315+ }
211316 }
212317}
0 commit comments