@@ -1071,6 +1071,94 @@ public void requestWhenPushedAuthorizationRequestThenReturnAccessTokenResponse()
10711071 .isEqualTo (true );
10721072 }
10731073
1074+ // gh-2182
1075+ @ Test
1076+ public void requestWhenPushedAuthorizationRequestAndRequiresConsentThenDisplaysConsentPage () throws Exception {
1077+ this .spring .register (AuthorizationServerConfigurationWithPushedAuthorizationRequests .class ).autowire ();
1078+
1079+ RegisteredClient registeredClient = TestRegisteredClients .registeredClient ().scopes ((scopes ) -> {
1080+ scopes .clear ();
1081+ scopes .add ("message.read" );
1082+ scopes .add ("message.write" );
1083+ }).clientSettings (ClientSettings .builder ().requireAuthorizationConsent (true ).build ()).build ();
1084+ this .registeredClientRepository .save (registeredClient );
1085+
1086+ MvcResult mvcResult = this .mvc
1087+ .perform (post ("/oauth2/par" ).params (getAuthorizationRequestParameters (registeredClient ))
1088+ .header (HttpHeaders .AUTHORIZATION , getAuthorizationHeader (registeredClient )))
1089+ .andExpect (header ().string (HttpHeaders .CACHE_CONTROL , containsString ("no-store" )))
1090+ .andExpect (header ().string (HttpHeaders .PRAGMA , containsString ("no-cache" )))
1091+ .andExpect (status ().isCreated ())
1092+ .andExpect (jsonPath ("$.request_uri" ).isNotEmpty ())
1093+ .andExpect (jsonPath ("$.expires_in" ).isNotEmpty ())
1094+ .andReturn ();
1095+
1096+ String requestUri = JsonPath .read (mvcResult .getResponse ().getContentAsString (), "$.request_uri" );
1097+
1098+ String consentPage = this .mvc
1099+ .perform (get (DEFAULT_AUTHORIZATION_ENDPOINT_URI )
1100+ .queryParam (OAuth2ParameterNames .CLIENT_ID , registeredClient .getClientId ())
1101+ .queryParam (OAuth2ParameterNames .REQUEST_URI , requestUri )
1102+ .with (user ("user" )))
1103+ .andExpect (status ().is2xxSuccessful ())
1104+ .andReturn ()
1105+ .getResponse ()
1106+ .getContentAsString ();
1107+
1108+ assertThat (consentPage ).contains ("Consent required" );
1109+ assertThat (consentPage ).contains (scopeCheckbox ("message.read" ));
1110+ assertThat (consentPage ).contains (scopeCheckbox ("message.write" ));
1111+ }
1112+
1113+ // gh-2182
1114+ @ Test
1115+ public void requestWhenPushedAuthorizationRequestAndCustomConsentPageConfiguredThenRedirect () throws Exception {
1116+ this .spring .register (AuthorizationServerConfigurationWithPushedAuthorizationRequestsAndCustomConsentPage .class )
1117+ .autowire ();
1118+
1119+ RegisteredClient registeredClient = TestRegisteredClients .registeredClient ().scopes ((scopes ) -> {
1120+ scopes .clear ();
1121+ scopes .add ("message.read" );
1122+ scopes .add ("message.write" );
1123+ }).clientSettings (ClientSettings .builder ().requireAuthorizationConsent (true ).build ()).build ();
1124+ this .registeredClientRepository .save (registeredClient );
1125+
1126+ MvcResult mvcResult = this .mvc
1127+ .perform (post ("/oauth2/par" ).params (getAuthorizationRequestParameters (registeredClient ))
1128+ .header (HttpHeaders .AUTHORIZATION , getAuthorizationHeader (registeredClient )))
1129+ .andExpect (header ().string (HttpHeaders .CACHE_CONTROL , containsString ("no-store" )))
1130+ .andExpect (header ().string (HttpHeaders .PRAGMA , containsString ("no-cache" )))
1131+ .andExpect (status ().isCreated ())
1132+ .andExpect (jsonPath ("$.request_uri" ).isNotEmpty ())
1133+ .andExpect (jsonPath ("$.expires_in" ).isNotEmpty ())
1134+ .andReturn ();
1135+
1136+ String requestUri = JsonPath .read (mvcResult .getResponse ().getContentAsString (), "$.request_uri" );
1137+
1138+ mvcResult = this .mvc
1139+ .perform (get (DEFAULT_AUTHORIZATION_ENDPOINT_URI )
1140+ .queryParam (OAuth2ParameterNames .CLIENT_ID , registeredClient .getClientId ())
1141+ .queryParam (OAuth2ParameterNames .REQUEST_URI , requestUri )
1142+ .with (user ("user" )))
1143+ .andExpect (status ().is3xxRedirection ())
1144+ .andReturn ();
1145+ String redirectedUrl = mvcResult .getResponse ().getRedirectedUrl ();
1146+ assertThat (redirectedUrl ).matches ("http://localhost/oauth2/consent\\ ?scope=.+&client_id=.+&state=.+" );
1147+
1148+ String locationHeader = URLDecoder .decode (redirectedUrl , StandardCharsets .UTF_8 .name ());
1149+ UriComponents uriComponents = UriComponentsBuilder .fromUriString (locationHeader ).build ();
1150+ MultiValueMap <String , String > redirectQueryParams = uriComponents .getQueryParams ();
1151+
1152+ assertThat (uriComponents .getPath ()).isEqualTo (consentPage );
1153+ assertThat (redirectQueryParams .getFirst (OAuth2ParameterNames .SCOPE )).isEqualTo ("message.read message.write" );
1154+ assertThat (redirectQueryParams .getFirst (OAuth2ParameterNames .CLIENT_ID ))
1155+ .isEqualTo (registeredClient .getClientId ());
1156+
1157+ String state = extractParameterFromRedirectUri (redirectedUrl , "state" );
1158+ OAuth2Authorization authorization = this .authorizationService .findByToken (state , STATE_TOKEN_TYPE );
1159+ assertThat (authorization ).isNotNull ();
1160+ }
1161+
10741162 private static OAuth2Authorization createAuthorization (RegisteredClient registeredClient ) {
10751163 Map <String , Object > additionalParameters = new HashMap <>();
10761164 additionalParameters .put (PkceParameterNames .CODE_CHALLENGE , S256_CODE_CHALLENGE );
@@ -1125,8 +1213,8 @@ private static MultiValueMap<String, String> getTokenRequestParameters(Registere
11251213 private static String getAuthorizationHeader (RegisteredClient registeredClient ) throws Exception {
11261214 String clientId = registeredClient .getClientId ();
11271215 String clientSecret = registeredClient .getClientSecret ();
1128- clientId = URLEncoder .encode (clientId , StandardCharsets .UTF_8 . name () );
1129- clientSecret = URLEncoder .encode (clientSecret , StandardCharsets .UTF_8 . name () );
1216+ clientId = URLEncoder .encode (clientId , StandardCharsets .UTF_8 );
1217+ clientSecret = URLEncoder .encode (clientSecret , StandardCharsets .UTF_8 );
11301218 String credentialsString = clientId + ":" + clientSecret ;
11311219 byte [] encodedBytes = Base64 .getEncoder ().encode (credentialsString .getBytes (StandardCharsets .UTF_8 ));
11321220 return "Basic " + new String (encodedBytes , StandardCharsets .UTF_8 );
@@ -1496,4 +1584,28 @@ SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) th
14961584
14971585 }
14981586
1587+ @ EnableWebSecurity
1588+ @ Configuration (proxyBeanMethods = false )
1589+ static class AuthorizationServerConfigurationWithPushedAuthorizationRequestsAndCustomConsentPage
1590+ extends AuthorizationServerConfiguration {
1591+
1592+ // @formatter:off
1593+ @ Bean
1594+ SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http ) throws Exception {
1595+ http
1596+ .oauth2AuthorizationServer ((authorizationServer ) ->
1597+ authorizationServer
1598+ .pushedAuthorizationRequestEndpoint (Customizer .withDefaults ())
1599+ .authorizationEndpoint ((authorizationEndpoint ) ->
1600+ authorizationEndpoint .consentPage (consentPage ))
1601+ )
1602+ .authorizeHttpRequests ((authorize ) ->
1603+ authorize .anyRequest ().authenticated ()
1604+ );
1605+ return http .build ();
1606+ }
1607+ // @formatter:on
1608+
1609+ }
1610+
14991611}
0 commit comments