From 79c2b8709bd8869841bdb78a35b01f8adf3c117e Mon Sep 17 00:00:00 2001 From: Steve Riesenberg Date: Thu, 27 May 2021 12:33:49 -0500 Subject: [PATCH] Allow form login when single OAuth2 Provider is configured Closes gh-6802 --- .../oauth2/client/OAuth2LoginConfigurer.java | 23 +++++++++++-- .../client/OAuth2LoginConfigurerTests.java | 33 ++++++++++++++++++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 5bdb85f3eb..be1707e394 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.client; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -73,12 +74,14 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.util.matcher.AndRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.NegatedRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; /** * An {@link AbstractHttpConfigurer} for OAuth 2.0 Login, which leverages the OAuth 2.0 @@ -503,14 +506,28 @@ public final class OAuth2LoginConfigurer> new OrRequestMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher); RequestMatcher notXRequestedWith = new NegatedRequestMatcher( new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest")); + RequestMatcher formLoginNotEnabled = getFormLoginNotEnabledRequestMatcher(http); LinkedHashMap entryPoints = new LinkedHashMap<>(); - entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher)), - new LoginUrlAuthenticationEntryPoint(providerLoginPage)); + entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher), + formLoginNotEnabled), new LoginUrlAuthenticationEntryPoint(providerLoginPage)); DelegatingAuthenticationEntryPoint loginEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints); loginEntryPoint.setDefaultEntryPoint(this.getAuthenticationEntryPoint()); return loginEntryPoint; } + private RequestMatcher getFormLoginNotEnabledRequestMatcher(B http) { + DefaultLoginPageGeneratingFilter defaultLoginPageGeneratingFilter = http + .getSharedObject(DefaultLoginPageGeneratingFilter.class); + Field formLoginEnabledField = (defaultLoginPageGeneratingFilter != null) + ? ReflectionUtils.findField(DefaultLoginPageGeneratingFilter.class, "formLoginEnabled") : null; + if (formLoginEnabledField != null) { + ReflectionUtils.makeAccessible(formLoginEnabledField); + return (request) -> Boolean.FALSE + .equals(ReflectionUtils.getField(formLoginEnabledField, defaultLoginPageGeneratingFilter)); + } + return AnyRequestMatcher.INSTANCE; + } + /** * Configuration options for the Authorization Server's Authorization Endpoint. */ diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index 1fde85ca40..d591b9b107 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -368,6 +368,17 @@ public class OAuth2LoginConfigurerTests { assertThat(this.response.getRedirectedUrl()).matches("http://localhost/oauth2/authorization/google"); } + // gh-6802 + @Test + public void oauth2LoginWithOneClientConfiguredAndFormLoginThenRedirectDefaultLoginPage() throws Exception { + loadConfig(OAuth2LoginConfigFormLogin.class); + String requestUri = "/"; + this.request = new MockHttpServletRequest("GET", requestUri); + this.request.setServletPath(requestUri); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); + assertThat(this.response.getRedirectedUrl()).matches("http://localhost/login"); + } + // gh-5347 @Test public void oauth2LoginWithOneClientConfiguredAndRequestFaviconNotAuthenticatedThenRedirectDefaultLoginPage() @@ -642,6 +653,26 @@ public class OAuth2LoginConfigurerTests { } + @EnableWebSecurity + static class OAuth2LoginConfigFormLogin extends CommonWebSecurityConfigurerAdapter { + + private final InMemoryClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository( + GOOGLE_CLIENT_REGISTRATION); + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .oauth2Login() + .clientRegistrationRepository(this.clientRegistrationRepository) + .and() + .formLogin(); + // @formatter:on + super.configure(http); + } + + } + @EnableWebSecurity static class OAuth2LoginInLambdaConfig extends CommonLambdaWebSecurityConfigurerAdapter implements ApplicationListener {