فهرست منبع

Fix verification_uri in device authorization response when context path exists

Closes gh-1714
Selene Feigl 11 ماه پیش
والد
کامیت
8c297b1252

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

@@ -46,6 +46,7 @@ import org.springframework.security.web.authentication.AuthenticationConverter;
 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.security.web.util.RedirectUrlBuilder;
 import org.springframework.security.web.util.UrlUtils;
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -220,9 +221,7 @@ public final class OAuth2DeviceAuthorizationEndpointFilter extends OncePerReques
 		OAuth2UserCode userCode = deviceAuthorizationRequestAuthentication.getUserCode();
 
 		// Generate the fully-qualified verification URI
-		UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder
-			.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
-			.replacePath(this.verificationUri);
+		UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(resolveVerificationUri(request));
 		String verificationUri = uriComponentsBuilder.build().toUriString();
 		// @formatter:off
 		String verificationUriComplete = uriComponentsBuilder
@@ -242,4 +241,17 @@ public final class OAuth2DeviceAuthorizationEndpointFilter extends OncePerReques
 		this.deviceAuthorizationHttpResponseConverter.write(deviceAuthorizationResponse, null, httpResponse);
 	}
 
+	private String resolveVerificationUri(HttpServletRequest request) {
+		if (UrlUtils.isAbsoluteUrl(this.verificationUri)) {
+			return this.verificationUri;
+		}
+		RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
+		urlBuilder.setScheme(request.getScheme());
+		urlBuilder.setServerName(request.getServerName());
+		urlBuilder.setPort(request.getServerPort());
+		urlBuilder.setContextPath(request.getContextPath());
+		urlBuilder.setPathInfo(this.verificationUri);
+		return urlBuilder.getUrl();
+	}
+
 }

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

@@ -241,6 +241,39 @@ public class OAuth2DeviceAuthorizationEndpointFilterTests {
 		assertThat(deviceCode.getExpiresAt()).isAfter(deviceCode.getIssuedAt());
 	}
 
+	@Test
+	public void doFilterWhenDeviceAuthorizationRequestWithContextPathThenDeviceAuthorizationResponse() throws Exception {
+		Authentication authenticationResult = createAuthentication();
+		given(this.authenticationManager.authenticate(any(Authentication.class))).willReturn(authenticationResult);
+
+		Authentication clientPrincipal = (Authentication) authenticationResult.getPrincipal();
+		mockSecurityContext(clientPrincipal);
+
+		MockHttpServletRequest request = createRequest();
+		request.setContextPath("/contextPath");
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		FilterChain filterChain = mock(FilterChain.class);
+		this.filter.doFilter(request, response, filterChain);
+		assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+
+		ArgumentCaptor<OAuth2DeviceAuthorizationRequestAuthenticationToken> deviceAuthorizationRequestAuthenticationCaptor = ArgumentCaptor
+				.forClass(OAuth2DeviceAuthorizationRequestAuthenticationToken.class);
+		verify(this.authenticationManager).authenticate(deviceAuthorizationRequestAuthenticationCaptor.capture());
+		verifyNoInteractions(filterChain);
+
+		OAuth2DeviceAuthorizationResponse deviceAuthorizationResponse = readDeviceAuthorizationResponse(response);
+		String verificationUri = ISSUER_URI + "/contextPath" + VERIFICATION_URI;
+		assertThat(deviceAuthorizationResponse.getVerificationUri()).isEqualTo(verificationUri);
+		assertThat(deviceAuthorizationResponse.getVerificationUriComplete())
+				.isEqualTo("%s?%s=%s".formatted(verificationUri, OAuth2ParameterNames.USER_CODE, USER_CODE));
+		OAuth2DeviceCode deviceCode = deviceAuthorizationResponse.getDeviceCode();
+		assertThat(deviceCode.getTokenValue()).isEqualTo(DEVICE_CODE);
+		assertThat(deviceCode.getExpiresAt()).isAfter(deviceCode.getIssuedAt());
+		OAuth2UserCode userCode = deviceAuthorizationResponse.getUserCode();
+		assertThat(userCode.getTokenValue()).isEqualTo(USER_CODE);
+		assertThat(deviceCode.getExpiresAt()).isAfter(deviceCode.getIssuedAt());
+	}
+
 	@Test
 	public void doFilterWhenInvalidRequestErrorThenBadRequest() throws Exception {
 		AuthenticationConverter authenticationConverter = mock(AuthenticationConverter.class);