Skip to content

Commit 521706d

Browse files
deniswjgrandja
authored andcommitted
Limit oauth2Login() links to redirect-based flows
This prevents the generated login page from showing links for authorization grant types like "client_credentials" which are not redirect-based, and thus not meant for interactive use in the browser. Closes gh-9457
1 parent ea19b31 commit 521706d

File tree

4 files changed

+82
-9
lines changed

4 files changed

+82
-9
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -57,6 +57,7 @@
5757
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
5858
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
5959
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
60+
import org.springframework.security.oauth2.core.AuthorizationGrantType;
6061
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
6162
import org.springframework.security.oauth2.core.OAuth2Error;
6263
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
@@ -686,10 +687,12 @@ private Map<String, String> getLoginLinks() {
686687
this.authorizationEndpointConfig.authorizationRequestBaseUri :
687688
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI;
688689
Map<String, String> loginUrlToClientName = new HashMap<>();
689-
clientRegistrations.forEach(registration -> loginUrlToClientName.put(
690-
authorizationRequestBaseUri + "/" + registration.getRegistrationId(),
691-
registration.getClientName()));
692-
690+
clientRegistrations.forEach((registration) -> {
691+
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(registration.getAuthorizationGrantType())) {
692+
String authorizationRequestUri = authorizationRequestBaseUri + "/" + registration.getRegistrationId();
693+
loginUrlToClientName.put(authorizationRequestUri, registration.getClientName());
694+
}
695+
});
693696
return loginUrlToClientName;
694697
}
695698

config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -85,6 +85,7 @@
8585
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
8686
import org.springframework.security.oauth2.client.web.server.WebSessionOAuth2ServerAuthorizationRequestRepository;
8787
import org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter;
88+
import org.springframework.security.oauth2.core.AuthorizationGrantType;
8889
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
8990
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
9091
import org.springframework.security.oauth2.core.user.OAuth2User;
@@ -1285,7 +1286,11 @@ private Map<String, String> getLinks() {
12851286
return Collections.emptyMap();
12861287
}
12871288
Map<String, String> result = new HashMap<>();
1288-
registrations.iterator().forEachRemaining(r -> result.put("/oauth2/authorization/" + r.getRegistrationId(), r.getClientName()));
1289+
registrations.iterator().forEachRemaining((r) -> {
1290+
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(r.getAuthorizationGrantType())) {
1291+
result.put("/oauth2/authorization/" + r.getRegistrationId(), r.getClientName());
1292+
}
1293+
});
12891294
return result;
12901295
}
12911296

config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -116,6 +116,11 @@ public class OAuth2LoginConfigurerTests {
116116
.getBuilder("github").clientId("clientId").clientSecret("clientSecret")
117117
.build();
118118

119+
// @formatter:off
120+
private static final ClientRegistration CLIENT_CREDENTIALS_REGISTRATION = TestClientRegistrations.clientCredentials()
121+
.build();
122+
// @formatter:on
123+
119124
private ConfigurableApplicationContext context;
120125

121126
@Autowired
@@ -431,6 +436,18 @@ public void oauth2LoginWithOneClientConfiguredAndRequestXHRNotAuthenticatedThenD
431436
assertThat(this.response.getRedirectedUrl()).doesNotMatch("http://localhost/oauth2/authorization/google");
432437
}
433438

439+
// gh-9457
440+
@Test
441+
public void oauth2LoginWithOneAuthorizationCodeClientAndOtherClientsConfiguredThenRedirectForAuthorization()
442+
throws Exception {
443+
loadConfig(OAuth2LoginConfigAuthorizationCodeClientAndOtherClients.class);
444+
String requestUri = "/";
445+
this.request = new MockHttpServletRequest("GET", requestUri);
446+
this.request.setServletPath(requestUri);
447+
this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
448+
assertThat(this.response.getRedirectedUrl()).matches("http://localhost/oauth2/authorization/google");
449+
}
450+
434451
@Test
435452
public void oauth2LoginWithCustomLoginPageThenRedirectCustomLoginPage() throws Exception {
436453
loadConfig(OAuth2LoginConfigCustomLoginPage.class);
@@ -801,6 +818,23 @@ protected void configure(HttpSecurity http) throws Exception {
801818
}
802819
}
803820

821+
@EnableWebSecurity
822+
static class OAuth2LoginConfigAuthorizationCodeClientAndOtherClients extends CommonWebSecurityConfigurerAdapter {
823+
824+
@Override
825+
protected void configure(HttpSecurity http) throws Exception {
826+
// @formatter:off
827+
http
828+
.oauth2Login()
829+
.clientRegistrationRepository(
830+
new InMemoryClientRegistrationRepository(
831+
GOOGLE_CLIENT_REGISTRATION, CLIENT_CREDENTIALS_REGISTRATION));
832+
// @formatter:on
833+
super.configure(http);
834+
}
835+
836+
}
837+
804838
@EnableWebSecurity
805839
static class OAuth2LoginConfigCustomLoginPage extends CommonWebSecurityConfigurerAdapter {
806840
@Override

config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -136,6 +136,11 @@ public class OAuth2LoginTests {
136136
.clientSecret("secret")
137137
.build();
138138

139+
// @formatter:off
140+
private static ClientRegistration clientCredentials = TestClientRegistrations.clientCredentials()
141+
.build();
142+
// @formatter:on
143+
139144
@Autowired
140145
public void setApplicationContext(ApplicationContext context) {
141146
if (context.getBeanNamesForType(WebHandler.class).length > 0) {
@@ -214,6 +219,32 @@ InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
214219
}
215220
}
216221

222+
// gh-9457
223+
@Test
224+
public void defaultLoginPageWithAuthorizationCodeAndClientCredentialsClientRegistrationThenRedirect() {
225+
this.spring.register(OAuth2LoginWithAuthorizationCodeAndClientCredentialsClientRegistration.class).autowire();
226+
// @formatter:off
227+
WebTestClient webTestClient = WebTestClientBuilder
228+
.bindToWebFilters(new GitHubWebFilter(), this.springSecurity)
229+
.build();
230+
WebDriver driver = WebTestClientHtmlUnitDriverBuilder
231+
.webTestClientSetup(webTestClient)
232+
.build();
233+
// @formatter:on
234+
driver.get("http://localhost/");
235+
assertThat(driver.getCurrentUrl()).startsWith("https://github.com/login/oauth/authorize");
236+
}
237+
238+
@EnableWebFluxSecurity
239+
static class OAuth2LoginWithAuthorizationCodeAndClientCredentialsClientRegistration {
240+
241+
@Bean
242+
InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
243+
return new InMemoryReactiveClientRegistrationRepository(github, clientCredentials);
244+
}
245+
246+
}
247+
217248
@Test
218249
public void oauth2AuthorizeWhenCustomObjectsThenUsed() {
219250
this.spring.register(OAuth2LoginWithSingleClientRegistrations.class,

0 commit comments

Comments
 (0)