Skip to content

Commit 8813f70

Browse files
committed
Merge pull request #35368 from sjohnr
* pr/35368: Fix redirect to login page for token requests Closes gh-35368
2 parents 19b81c2 + 10feecb commit 8813f70

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/server/servlet/OAuth2AuthorizationServerWebSecurityConfiguration.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,25 @@
1616

1717
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
1818

19+
import java.util.Set;
20+
1921
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2022
import org.springframework.boot.autoconfigure.security.ConditionalOnDefaultWebSecurity;
2123
import org.springframework.boot.autoconfigure.security.SecurityProperties;
2224
import org.springframework.context.annotation.Bean;
2325
import org.springframework.context.annotation.Configuration;
2426
import org.springframework.core.Ordered;
2527
import org.springframework.core.annotation.Order;
28+
import org.springframework.http.MediaType;
2629
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2730
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
2831
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
2932
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
3033
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
3134
import org.springframework.security.web.SecurityFilterChain;
3235
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
36+
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
37+
import org.springframework.security.web.util.matcher.RequestMatcher;
3338

3439
import static org.springframework.security.config.Customizer.withDefaults;
3540

@@ -49,8 +54,8 @@ SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) th
4954
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
5055
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(withDefaults());
5156
http.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults()));
52-
http.exceptionHandling(
53-
(exceptions) -> exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")));
57+
http.exceptionHandling((exceptions) -> exceptions.defaultAuthenticationEntryPointFor(
58+
new LoginUrlAuthenticationEntryPoint("/login"), createRequestMatcher()));
5459
return http.build();
5560
}
5661

@@ -61,4 +66,10 @@ SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Excepti
6166
return http.build();
6267
}
6368

69+
private static RequestMatcher createRequestMatcher() {
70+
MediaTypeRequestMatcher requestMatcher = new MediaTypeRequestMatcher(MediaType.TEXT_HTML);
71+
requestMatcher.setIgnoredMediaTypes(Set.of(MediaType.ALL));
72+
return requestMatcher;
73+
}
74+
6475
}

spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-oauth2-authorization-server/src/test/java/smoketest/oauth2/server/SampleOAuth2AuthorizationServerApplicationTests.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package smoketest.oauth2.server;
1818

1919
import java.net.URI;
20+
import java.util.List;
2021
import java.util.Map;
2122
import java.util.Objects;
2223

@@ -31,6 +32,7 @@
3132
import org.springframework.http.HttpHeaders;
3233
import org.springframework.http.HttpMethod;
3334
import org.springframework.http.HttpStatus;
35+
import org.springframework.http.MediaType;
3436
import org.springframework.http.ResponseEntity;
3537
import org.springframework.security.oauth2.core.AuthorizationGrantType;
3638
import org.springframework.security.oauth2.core.OAuth2AccessToken;
@@ -118,4 +120,49 @@ void validTokenRequestShouldReturnTokenResponse() {
118120
.isEqualTo(OAuth2AccessToken.TokenType.BEARER.getValue());
119121
}
120122

123+
@Test
124+
void anonymousTokenRequestShouldReturnUnauthorized() {
125+
HttpHeaders headers = new HttpHeaders();
126+
HttpEntity<Object> request = new HttpEntity<>(headers);
127+
String requestUri = UriComponentsBuilder.fromUriString("/token")
128+
.queryParam(OAuth2ParameterNames.CLIENT_ID, "messaging-client")
129+
.queryParam(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
130+
.queryParam(OAuth2ParameterNames.SCOPE, "message.read+message.write")
131+
.toUriString();
132+
ResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(requestUri, HttpMethod.POST, request,
133+
MAP_TYPE_REFERENCE);
134+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
135+
}
136+
137+
@Test
138+
void anonymousTokenRequestWithAcceptHeaderAllShouldReturnUnauthorized() {
139+
HttpHeaders headers = new HttpHeaders();
140+
headers.setAccept(List.of(MediaType.ALL));
141+
HttpEntity<Object> request = new HttpEntity<>(headers);
142+
String requestUri = UriComponentsBuilder.fromUriString("/token")
143+
.queryParam(OAuth2ParameterNames.CLIENT_ID, "messaging-client")
144+
.queryParam(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
145+
.queryParam(OAuth2ParameterNames.SCOPE, "message.read+message.write")
146+
.toUriString();
147+
ResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(requestUri, HttpMethod.POST, request,
148+
MAP_TYPE_REFERENCE);
149+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
150+
}
151+
152+
@Test
153+
void anonymousTokenRequestWithAcceptHeaderTextHtmlShouldRedirectToLogin() {
154+
HttpHeaders headers = new HttpHeaders();
155+
headers.setAccept(List.of(MediaType.TEXT_HTML));
156+
HttpEntity<Object> request = new HttpEntity<>(headers);
157+
String requestUri = UriComponentsBuilder.fromUriString("/token")
158+
.queryParam(OAuth2ParameterNames.CLIENT_ID, "messaging-client")
159+
.queryParam(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
160+
.queryParam(OAuth2ParameterNames.SCOPE, "message.read+message.write")
161+
.toUriString();
162+
ResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(requestUri, HttpMethod.POST, request,
163+
MAP_TYPE_REFERENCE);
164+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
165+
assertThat(entity.getHeaders().getLocation()).isEqualTo(URI.create("http://localhost:" + this.port + "/login"));
166+
}
167+
121168
}

0 commit comments

Comments
 (0)