From 6ee55470b6948aa43d368b26dbd0e9ecc9968bdc Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Thu, 9 Jan 2025 00:57:07 +0300 Subject: [PATCH] Add Support OAuth2AuthorizationRequestResolver As Bean Closes gh-16380 Signed-off-by: Max Batischev --- .../oauth2/client/OAuth2LoginConfigurer.java | 37 ++++++++------ .../client/OAuth2LoginConfigurerTests.java | 51 ++++++++++++++++++- 2 files changed, 72 insertions(+), 16 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 d191bb740be..1c6f9d1cb7a 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-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -68,6 +68,7 @@ import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository; +import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; @@ -396,20 +397,8 @@ public void init(B http) throws Exception { @Override public void configure(B http) throws Exception { - OAuth2AuthorizationRequestRedirectFilter authorizationRequestFilter; - if (this.authorizationEndpointConfig.authorizationRequestResolver != null) { - authorizationRequestFilter = new OAuth2AuthorizationRequestRedirectFilter( - this.authorizationEndpointConfig.authorizationRequestResolver); - } - else { - String authorizationRequestBaseUri = this.authorizationEndpointConfig.authorizationRequestBaseUri; - if (authorizationRequestBaseUri == null) { - authorizationRequestBaseUri = OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; - } - authorizationRequestFilter = new OAuth2AuthorizationRequestRedirectFilter( - OAuth2ClientConfigurerUtils.getClientRegistrationRepository(this.getBuilder()), - authorizationRequestBaseUri); - } + OAuth2AuthorizationRequestRedirectFilter authorizationRequestFilter = new OAuth2AuthorizationRequestRedirectFilter( + getAuthorizationRequestResolver()); if (this.authorizationEndpointConfig.authorizationRequestRepository != null) { authorizationRequestFilter .setAuthorizationRequestRepository(this.authorizationEndpointConfig.authorizationRequestRepository); @@ -440,6 +429,24 @@ protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingU return new AntPathRequestMatcher(loginProcessingUrl); } + private OAuth2AuthorizationRequestResolver getAuthorizationRequestResolver() { + if (this.authorizationEndpointConfig.authorizationRequestResolver != null) { + return this.authorizationEndpointConfig.authorizationRequestResolver; + } + ClientRegistrationRepository clientRegistrationRepository = OAuth2ClientConfigurerUtils + .getClientRegistrationRepository(getBuilder()); + ResolvableType resolvableType = ResolvableType.forClass(OAuth2AuthorizationRequestResolver.class); + OAuth2AuthorizationRequestResolver bean = getBeanOrNull(resolvableType); + if (bean != null) { + return bean; + } + String authorizationRequestBaseUri = this.authorizationEndpointConfig.authorizationRequestBaseUri; + if (authorizationRequestBaseUri == null) { + authorizationRequestBaseUri = OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; + } + return new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, authorizationRequestBaseUri); + } + @SuppressWarnings("unchecked") private JwtDecoderFactory getJwtDecoderFactoryBean() { ResolvableType type = ResolvableType.forClassWithGenerics(JwtDecoderFactory.class, ClientRegistration.class); 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 b56d047a5f7..770a8a17be5 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-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -379,6 +379,19 @@ public void oauth2LoginWithCustomAuthorizationRequestParameters() throws Excepti "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1"); } + @Test + public void oauth2LoginWithCustomAuthorizationRequestParametersAndResolverAsBean() throws Exception { + loadConfig(OAuth2LoginConfigCustomAuthorizationRequestResolverBean.class); + // @formatter:off + // @formatter:on + String requestUri = "/oauth2/authorization/google"; + this.request = new MockHttpServletRequest("GET", requestUri); + this.request.setServletPath(requestUri); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); + assertThat(this.response.getRedirectedUrl()).isEqualTo( + "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1"); + } + @Test public void requestWhenOauth2LoginWithCustomAuthorizationRequestParametersThenParametersInRedirectedUrl() throws Exception { @@ -940,6 +953,42 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception { } + @Configuration + @EnableWebSecurity + static class OAuth2LoginConfigCustomAuthorizationRequestResolverBean extends CommonSecurityFilterChainConfig { + + private ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository( + GOOGLE_CLIENT_REGISTRATION); + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .oauth2Login() + .clientRegistrationRepository(this.clientRegistrationRepository) + .authorizationEndpoint(); + // @formatter:on + return super.configureFilterChain(http); + } + + @Bean + OAuth2AuthorizationRequestResolver resolver() { + OAuth2AuthorizationRequestResolver resolver = mock(OAuth2AuthorizationRequestResolver.class); + // @formatter:off + OAuth2AuthorizationRequest result = OAuth2AuthorizationRequest.authorizationCode() + .authorizationUri("https://accounts.google.com/authorize") + .clientId("client-id") + .state("adsfa") + .authorizationRequestUri( + "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1") + .build(); + given(resolver.resolve(any())).willReturn(result); + // @formatter:on + return resolver; + } + + } + @Configuration @EnableWebSecurity static class OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda