Summary
Improve org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2LoginSpec
for more configuration options.
Actual Behavior
- Chaining of
OAuth2LoginSpecnot available, missingpublic ServerHttpSecurity and() { return ServerHttpSecurity.this; } - Static routes for
>
/oauth2/authorization/{registrationId}>/login/oauth2/code/{registrationId}
Expected Behavior
-
allow chaining
-
- allow to override/configure
oauthRedirectFilter(orauthorizationRequestBaseUriin particular) - allow to override/configure
AuthenticationWebFilter.requiresAuthenticationMatcher(orPathPatternParserServerWebExchangeMatcher->pattern=>requestBaseUriin particular)
- allow to override/configure
Configuration
http.oauth2Login();
Version
Boot 2.1.0.SNAPSHOT Spring Security 5.1.0.M2
Comment From: rwinch
The first part was easy so I fixed it in a separate issue. The next pieces are going to need to wait until we get #5610 resolved
Comment From: VijaySidhu
I am writing Service with WebFlux Framework Below are Technologies i am trying to use Spring Boot 2.1.0.M3 Spring Security 5.1.0.RC2 In Spring Security It's trying to match /oauth2/authorization/{registrationId} with Path i configured which is different and it's not matching and throwing 401. Is there any way to override /oauth2/authorization/{registrationId} this with value i am using
Comment From: nickbr23
Have the static routes:
/oauth2/authorization/{registrationId} /login/oauth2/code/{registrationId}
Been made overridable or configurable yet?
Comment From: jgrandja
@nickbr23 @VijaySidhu The configuration points for overriding the authorization request and authorization response base uri's is not available as of yet. Is anyone interested in submitting a PR for this?
At the moment I'm think we need the following:
OAuth2LoginSpec.authenticationMatcher(ServerWebExchangeMatcher matcher)
OAuth2LoginSpec.authorizationRequestResolver(ServerOAuth2AuthorizationRequestResolver resolver)
Comment From: hartmut-co-uk
I succeeded getting it working, see following snippet:
private fun oauth2Login(
http: ServerHttpSecurity,
authBaseUri: String = "/api/auth/oauth2/authorization",
loginBaseUri: String = "/api/auth/oauth2/code") {
val clientRegistrationRepository = getClientRegistrationRepository()
val oauthRedirectFilter = OAuth2AuthorizationRequestRedirectWebFilter(
DefaultServerOAuth2AuthorizationRequestResolver(
clientRegistrationRepository,
PathPatternParserServerWebExchangeMatcher("$authBaseUri/{registrationId}")))
val client = WebClientReactiveAuthorizationCodeTokenResponseClient()
val userService = DefaultReactiveOAuth2UserService()
var manager: ReactiveAuthenticationManager = MyOAuth2LoginReactiveAuthenticationManager(client, userService,
accountService)
val oidcAuthenticationProviderEnabled = ClassUtils.isPresent(
"org.springframework.security.oauth2.jwt.JwtDecoder", this.javaClass.classLoader)
if (oidcAuthenticationProviderEnabled) {
val oidc = OidcAuthorizationCodeReactiveAuthenticationManager(client, OidcReactiveOAuth2UserService())
manager = DelegatingReactiveAuthenticationManager(oidc, manager)
}
val authenticationFilter = AuthenticationWebFilter(manager)
authenticationFilter.setRequiresAuthenticationMatcher(PathPatternParserServerWebExchangeMatcher("$loginBaseUri/{registrationId}"))
authenticationFilter.setServerAuthenticationConverter(ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository))
authenticationFilter.setAuthenticationSuccessHandler(OAuth2CodeAuthenticationSuccessHandler())
authenticationFilter.setAuthenticationFailureHandler { _, exception -> Mono.error(exception) } // TODO: metrics
authenticationFilter.setSecurityContextRepository(WebSessionServerSecurityContextRepository())
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC)
http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION)
}
Please note MyOAuth2LoginReactiveAuthenticationManager and accountService are custom..
var manager: ReactiveAuthenticationManager = MyOAuth2LoginReactiveAuthenticationManager(client, userService,
accountService)
PS: that's on spring boot version 2.1.1.RELEASE, not SNAPSHOT as above in the original issue description.
Comment From: nickbr23
At the moment I'm think we need the following:
OAuth2LoginSpec.authenticationMatcher(ServerWebExchangeMatcher matcher)
OAuth2LoginSpec.authorizationRequestResolver(ServerOAuth2AuthorizationRequestResolver resolver)
That would work.
For just overriding the uri's, it should be as simple as providing:
OAuth2LoginSpec.authorizationRequestBaseUri(String authorizationRequestBaseUri)
OAuth2LoginSpec.loginProcessingUrl(String loginProcessingUrl)
So that it mirrors the servlets builder.
If you're happy with just providing the uri's then feel free to assign it to me and I'll handle the PR.
Comment From: jgrandja
Thanks for the feedback @nickbr23
So that it mirrors the servlets builder.
OAuth2LoginSpec.authorizationRequestBaseUri(String authorizationRequestBaseUri)
OAuth2LoginSpec.loginProcessingUrl(String loginProcessingUrl)
This does not actually mirror the DSL in OAuth2LoginConfigurer. Check out the full DSL here
The preference is to use ServerOAuth2AuthorizationRequestResolver over just configuring the authorization request URI as it provides more flexibility. This is how http.oauth2Client().authorizationCodeGrant().authorizationRequestResolver() has been designed as well. Also, we are considering deprecating authorizationEndpoint.baseUri().
The new configuration API's we would want to introduce are as follows:
OAuth2LoginSpec.authorizationRequestResolver(ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver)
OAuth2LoginSpec.authenticationMatcher(ServerWebExchangeMatcher authenticationMatcher)
Let me know if you're still interested in submitting a PR for this improvement.
Comment From: nickbr23
Let me know if you're still interested in submitting a PR for this improvement.
Sure, I'm happy to do it.
If we introduce
OAuth2LoginSpec.authorizationRequestResolver(ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) won't there still be an issue with changing the path from method OAuth2LoginSpec.getLinks as this should match the path in the new request resolver?
Comment From: jgrandja
OAuth2LoginSpec.getLinks is used for the default login page. If the user provides a customAuthorizationRequestResolver, it is also their responsibility to provide a custom login page that uses the custom authorization request base uri used by customAuthorizationRequestResolver. So this is not an issue as OAuth2LoginSpec.getLinks does not need to be updated as part of the changes required for this PR. Also keep in mind that the default login page is generally used for development/testing/samples as a convenience. Production applications typically provide a custom login page.
The PR is yours @nickbr23. Let me know if you have any other questions. Thanks for taking this on!
Comment From: nickbr23
PR has been created: https://github.com/spring-projects/spring-security/pull/6462
Comment From: deeplights
OAuth2LoginSpec.getLinksis used for the default login page. If the user provides acustomAuthorizationRequestResolver, it is also their responsibility to provide a custom login page that uses the custom authorization request base uri used bycustomAuthorizationRequestResolver. So this is not an issue asOAuth2LoginSpec.getLinksdoes not need to be updated as part of the changes required for this PR. Also keep in mind that the default login page is generally used for development/testing/samples as a convenience. Production applications typically provide a custom login page.
@jgrandja Is there a way to customize the login page and override the behavior OAuth2LoginSpec.getLinks provides?
Comment From: saurabhgour
@nickbr23 @jgrandja
I still could'nt figure out how to customize the baseUri in the reactive stack. For the servlet stack I can customize it as follows:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login()
.redirectionEndpoint()
.baseUri("/auth/custom/sso");
}
Could you please provide a sample of the equivalent code for the reactive stack ?
Comment From: luqmanulkhair
@nickbr23 @jgrandja can you please provide a documentation link, thanks!
Comment From: jgrandja
@saurabhgour @luqmanulkhair Here is a sample configuration:
@EnableWebFluxSecurity
public class SecurityConfig {
@Autowired
private ReactiveClientRegistrationRepository clientRegistrationRepository;
@Bean
SecurityWebFilterChain configure(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges ->
exchanges
.anyExchange().authenticated()
)
.oauth2Login(oauth2Login ->
oauth2Login
.authorizationRequestResolver(getAuthorizationRequestResolver()));
return http.build();
}
private ServerOAuth2AuthorizationRequestResolver getAuthorizationRequestResolver() {
return new DefaultServerOAuth2AuthorizationRequestResolver(
this.clientRegistrationRepository,
new PathPatternParserServerWebExchangeMatcher(
"/auth/custom/sso/{registrationId}"));
}
}
Given the above configuration, the URL http://localhost:8080/auth/custom/sso/google would trigger the authentication for Google.
Comment From: luqmanulkhair
@jgrandja thanks for your response, Is this code for .authoriationEndpoint().baseurl() or for .redirectionEndpoint() .baseUri(""), my problem is to handle the redirect from authorization-server after login with code, I think I need to use authenticationMatcher(), I have implemented my custom logic but it not standardized.
Example: redirect_url: custom/login instead of {baseUrl}/login/oauth2/code/{registrationId} (does not work) if i use {baseUrl}/login/oauth2/code/{registrationId} as a redirect uri everything works.
Comment From: jgrandja
@luqmanulkhair The sample code provided is for .authoriationEndpoint().baseurl().
For redirectionEndpoint() .baseUri(), that is correct, you need to configure authenticationMatcher(). The default authenticationMatcher is:
new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}")
Configure this, with whatever path you require.
Comment From: SMakhrov
@jgrandja solution doesn't work for me. After copy/paste your Java class I have redirect loop to /auth/custom/sso/{registrationId}
Could I ask you for help, please?
My application.yaml in Spring Cloud Gateway (extremely simple - only this yaml and your SecurityConfig):
server:
port: 80
spring:
cloud:
gateway:
default-filters:
- TokenRelay
routes:
- id: root
uri: http://origin
predicates:
- Path=/**
filters:
- RemoveRequestHeader=Cookie
security:
oauth2:
client:
registration:
smart_hub_client:
provider: wso2is
client-id: clientid
client-secret: clientsecret
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/redirect_uri"
scope: sso,openid
provider:
wso2is:
authorization-uri: http://localhost:8080/oauth2/authorize?loginPage=login.jsp
token-uri: http://localhost:8080/oauth2/token
user-info-uri: http://localhost:8080/oauth2/userinfo
user-name-attribute: sub
jwk-set-uri: http://localhost:8080/oauth2/jwks