Spring Security OAuth 2.0 Google: redirect to default URL after unauthorized request instead of requested URL

1.6k Views Asked by At

I'm using Spring Security OAuth 2.0 with Google as identity provider. I have problem with proper handling of session timeout and reauthentication.

Scenario:

  • Some request to REST API after session timeout.
  • Frontend handles HTTP 403 and shows screen with link to Spring Security login endpoint.
  • User clicks on this link. Spring issues redirect to Google login page with necessary parameters (code, state, etc.). User successfully reauthenticates.

Current behaviour:

  • After login Google redirects to previously requested REST API URL. As a result user sees some JSON in browser. I simply don't understand what part of application could have been saved it. I disabled everything. (See comments below configuration class.)

Desired behaviour:

  • After login Google redirects to some starting UI screen.

My configuration class:

import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler

@Configuration
@EnableWebSecurity
class WebSecurityConfiguration: WebSecurityConfigurerAdapter() {

    @Value("\${app.security.oauth2.defaultSuccessUrl}")
    lateinit var defaultSuccessUrl: String

    @Throws(Exception::class)
    override fun configure(httpSecurity: HttpSecurity) {
        val successHandler = SimpleUrlAuthenticationSuccessHandler()
        successHandler.setUseReferer(false)
        httpSecurity
            .antMatcher("/**")
            .authorizeRequests()
            .antMatchers("/", "/login**", "/js/**", "/error**").permitAll()
            .anyRequest().authenticated()
            .and().oauth2Login()
            .successHandler(successHandler)
            .defaultSuccessUrl(defaultSuccessUrl)
            .and().logout().logoutSuccessUrl("/login").deleteCookies("JSESSIONID").permitAll()
            .and()
            .csrf().disable()
            .exceptionHandling()
            .authenticationEntryPoint(Http403ForbiddenEntryPoint())
    }

}
  • defaultSuccessUrl is set to the desired UI screen.
  • I've already changed success handler to SimpleUrlAuthenticationSuccessHandler instead of SavedRequestAwareAuthenticationSuccessHandler to turn off saving requested URL by Spring.
  • successHandler.setUseReferer(false) to disable Referer header on HTTP level.
  • I'm using Http403ForbiddenEntryPoint() to just issue HTTP 403 on session timeout. Frontend handles this and shows login screen with link to Spring Security login URL.

What I'm doing wrong?

Thanks in advance.

UPD: Updated code according to answer by Steve Riesenberg:

import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler

@Configuration
@EnableWebSecurity
class WebSecurityConfiguration: WebSecurityConfigurerAdapter() {

    @Value("\${app.security.oauth2.defaultSuccessUrl}")
    lateinit var defaultSuccessUrl: String

    @Throws(Exception::class)
    override fun configure(httpSecurity: HttpSecurity) {
        val successHandler = SimpleUrlAuthenticationSuccessHandler(defaultSuccessUrl)
        successHandler.setUseReferer(false)
        httpSecurity
            .antMatcher("/**")
            .authorizeRequests()
            .antMatchers("/", "/login**", "/js/**", "/error**").permitAll()
            .anyRequest().authenticated()
            .and().oauth2Login()
            .successHandler(successHandler)
            .and().logout().logoutSuccessUrl("/login").deleteCookies("JSESSIONID").permitAll()
            .and()
            .csrf().disable()
            .exceptionHandling()
            .authenticationEntryPoint(Http403ForbiddenEntryPoint())
    }

}
1

There are 1 best solutions below

0
On BEST ANSWER

Setting the defaultSuccessUrl will override your successHandler(), as setting the URL actually adds SavedRequestAwareAuthenticationSuccessHandler that you wanted to replace. Order matters, as there is only one successHandler in the oauth2Login configurer.

Instead, you will want to pass the defaultSuccessUrl to the constructor of SimpleUrlAuthenticationSuccessHandler, and only set the successHandler(successHandler).