Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve OAuth2LoginSpec with more configuration options #5598

Closed
hartmut-co-uk opened this issue Jul 28, 2018 · 17 comments
Closed

Improve OAuth2LoginSpec with more configuration options #5598

hartmut-co-uk opened this issue Jul 28, 2018 · 17 comments
Assignees
Labels
in: config An issue in spring-security-config in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Milestone

Comments

@hartmut-co-uk
Copy link

hartmut-co-uk commented Jul 28, 2018

Summary

Improve org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2LoginSpec
for more configuration options.

Actual Behavior

  1. Chaining of OAuth2LoginSpec not available, missing public ServerHttpSecurity and() { return ServerHttpSecurity.this; }
  2. Static routes for

    /oauth2/authorization/{registrationId}
    /login/oauth2/code/{registrationId}

Expected Behavior

  1. allow chaining

    1. allow to override/configure oauthRedirectFilter (or authorizationRequestBaseUri in particular)
    2. allow to override/configure AuthenticationWebFilter.requiresAuthenticationMatcher (or PathPatternParserServerWebExchangeMatcher -> pattern => requestBaseUri in particular)

Configuration

http.oauth2Login();

Version

Boot 2.1.0.SNAPSHOT
Spring Security 5.1.0.M2

@rwinch rwinch self-assigned this Jul 30, 2018
@rwinch rwinch added Reactive in: config An issue in spring-security-config in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement labels Jul 30, 2018
@rwinch rwinch added this to the 5.1.0.RC1 milestone Jul 30, 2018
@rwinch
Copy link
Member

rwinch commented Jul 30, 2018

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

@VijaySidhu
Copy link

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

@nickbr23
Copy link
Contributor

Have the static routes:

/oauth2/authorization/{registrationId}
/login/oauth2/code/{registrationId}

Been made overridable or configurable yet?

@rwinch rwinch removed their assignment Jan 16, 2019
@jgrandja jgrandja self-assigned this Jan 16, 2019
@jgrandja
Copy link
Contributor

@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)

@hartmut-co-uk
Copy link
Author

hartmut-co-uk commented Jan 17, 2019

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.

@nickbr23
Copy link
Contributor

nickbr23 commented Jan 17, 2019

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.

@jgrandja
Copy link
Contributor

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.

@nickbr23
Copy link
Contributor

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?

@jgrandja
Copy link
Contributor

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!

@jgrandja jgrandja changed the title ServerHttpSecurity.OAuth2LoginSpec Webflux - Add Chaining, More Options to Customise Enable more customizations for OAuth2LoginSpec Jan 19, 2019
@jgrandja jgrandja modified the milestones: General Backlog, 5.2.0.M2 Jan 19, 2019
@jgrandja jgrandja changed the title Enable more customizations for OAuth2LoginSpec Improve OAuth2LoginSpec with more configuration options Jan 19, 2019
@nickbr23
Copy link
Contributor

PR has been created: #6462

nickbr23 added a commit to nickbr23/spring-security that referenced this issue Jan 24, 2019
@deeplights
Copy link

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.

@jgrandja Is there a way to customize the login page and override the behavior OAuth2LoginSpec.getLinks provides?

@saurabhgour
Copy link

saurabhgour commented Oct 17, 2020

@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 ?

@luqmanulkhair
Copy link

@nickbr23 @jgrandja can you please provide a documentation link, thanks!

@jgrandja
Copy link
Contributor

@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.

@luqmanulkhair
Copy link

luqmanulkhair commented Oct 23, 2020

@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.

@jgrandja
Copy link
Contributor

@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.

@SMakhrov
Copy link

SMakhrov commented Dec 4, 2020

@jgrandja solution doesn't work for me. After copy/paste your Java class I have redirect loop to /auth/custom/sso/{registrationId}
image
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: config An issue in spring-security-config in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

9 participants