Skip to content

Commit 8c297b1

Browse files
Selene Feigljgrandja
authored andcommitted
Fix verification_uri in device authorization response when context path exists
Closes gh-1714
1 parent bb36dce commit 8c297b1

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2DeviceAuthorizationEndpointFilter.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
4747
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
4848
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
49+
import org.springframework.security.web.util.RedirectUrlBuilder;
4950
import org.springframework.security.web.util.UrlUtils;
5051
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
5152
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -220,9 +221,7 @@ private void sendDeviceAuthorizationResponse(HttpServletRequest request, HttpSer
220221
OAuth2UserCode userCode = deviceAuthorizationRequestAuthentication.getUserCode();
221222

222223
// Generate the fully-qualified verification URI
223-
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder
224-
.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
225-
.replacePath(this.verificationUri);
224+
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(resolveVerificationUri(request));
226225
String verificationUri = uriComponentsBuilder.build().toUriString();
227226
// @formatter:off
228227
String verificationUriComplete = uriComponentsBuilder
@@ -242,4 +241,17 @@ private void sendDeviceAuthorizationResponse(HttpServletRequest request, HttpSer
242241
this.deviceAuthorizationHttpResponseConverter.write(deviceAuthorizationResponse, null, httpResponse);
243242
}
244243

244+
private String resolveVerificationUri(HttpServletRequest request) {
245+
if (UrlUtils.isAbsoluteUrl(this.verificationUri)) {
246+
return this.verificationUri;
247+
}
248+
RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
249+
urlBuilder.setScheme(request.getScheme());
250+
urlBuilder.setServerName(request.getServerName());
251+
urlBuilder.setPort(request.getServerPort());
252+
urlBuilder.setContextPath(request.getContextPath());
253+
urlBuilder.setPathInfo(this.verificationUri);
254+
return urlBuilder.getUrl();
255+
}
256+
245257
}

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2DeviceAuthorizationEndpointFilterTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,39 @@ public void doFilterWhenDeviceAuthorizationRequestThenDeviceAuthorizationRespons
241241
assertThat(deviceCode.getExpiresAt()).isAfter(deviceCode.getIssuedAt());
242242
}
243243

244+
@Test
245+
public void doFilterWhenDeviceAuthorizationRequestWithContextPathThenDeviceAuthorizationResponse() throws Exception {
246+
Authentication authenticationResult = createAuthentication();
247+
given(this.authenticationManager.authenticate(any(Authentication.class))).willReturn(authenticationResult);
248+
249+
Authentication clientPrincipal = (Authentication) authenticationResult.getPrincipal();
250+
mockSecurityContext(clientPrincipal);
251+
252+
MockHttpServletRequest request = createRequest();
253+
request.setContextPath("/contextPath");
254+
MockHttpServletResponse response = new MockHttpServletResponse();
255+
FilterChain filterChain = mock(FilterChain.class);
256+
this.filter.doFilter(request, response, filterChain);
257+
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
258+
259+
ArgumentCaptor<OAuth2DeviceAuthorizationRequestAuthenticationToken> deviceAuthorizationRequestAuthenticationCaptor = ArgumentCaptor
260+
.forClass(OAuth2DeviceAuthorizationRequestAuthenticationToken.class);
261+
verify(this.authenticationManager).authenticate(deviceAuthorizationRequestAuthenticationCaptor.capture());
262+
verifyNoInteractions(filterChain);
263+
264+
OAuth2DeviceAuthorizationResponse deviceAuthorizationResponse = readDeviceAuthorizationResponse(response);
265+
String verificationUri = ISSUER_URI + "/contextPath" + VERIFICATION_URI;
266+
assertThat(deviceAuthorizationResponse.getVerificationUri()).isEqualTo(verificationUri);
267+
assertThat(deviceAuthorizationResponse.getVerificationUriComplete())
268+
.isEqualTo("%s?%s=%s".formatted(verificationUri, OAuth2ParameterNames.USER_CODE, USER_CODE));
269+
OAuth2DeviceCode deviceCode = deviceAuthorizationResponse.getDeviceCode();
270+
assertThat(deviceCode.getTokenValue()).isEqualTo(DEVICE_CODE);
271+
assertThat(deviceCode.getExpiresAt()).isAfter(deviceCode.getIssuedAt());
272+
OAuth2UserCode userCode = deviceAuthorizationResponse.getUserCode();
273+
assertThat(userCode.getTokenValue()).isEqualTo(USER_CODE);
274+
assertThat(deviceCode.getExpiresAt()).isAfter(deviceCode.getIssuedAt());
275+
}
276+
244277
@Test
245278
public void doFilterWhenInvalidRequestErrorThenBadRequest() throws Exception {
246279
AuthenticationConverter authenticationConverter = mock(AuthenticationConverter.class);

0 commit comments

Comments
 (0)