Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security OAuth2 redirect_uri callback results in 404

I am trying to write a web-app that allows authentication by either JDBC or Google/Facebook; using Spring Security 5.0.x. I have valid Google Client Id and Secret. The OAuth2 web-flow is taking me correctly to Google for account selection and consent, but the callback to the redirect_uri is failing with a 404. I can't see what I'm doing wrong.

@Configuration
@EnableScheduling
@EnableWebSecurity
public class WebSecurityConfig
    extends WebSecurityConfigurerAdapter
{
    private static final Logger _logger = LogManager.getLogger (WebSecurityConfig.class);

    private static String
        SuccessUrl = "/api/auth/login-success",
        FailureUrl = "/api/auth/login-failure",
        LogoutUrl = "/api/auth/logout-done";

    private static String
        PGoogleId = "oauth2.google.id",
        PGoogleSecret = "oauth2.google.secret",
        PFacebookId = "oauth2.facebook.id",
        PFacebookSecret = "oauth2.google.secret";

    private final List<ClientRegistration> _regns;

    @Autowired
    private AuthSuccessHandler _success;
    @Autowired
    private AuthFailureHandler _failure;
    @Autowired
    private DataSource _source;
    @Autowired
    private MezoUserManager _userManager;

    /**
     * Sole Constructor
     */
    public WebSecurityConfig ()
    {
        _regns = new ArrayList<> ();
    }

    @Autowired
    public void setPropertiesFactory (
        PropertiesFactoryBean factory)
        throws IOException, AddressException
    {
        Properties p = factory.getObject ();
        extractIdSecret (CommonOAuth2Provider.GOOGLE.getBuilder ("google"), PGoogleId, PGoogleSecret, p);
        extractIdSecret (CommonOAuth2Provider.FACEBOOK.getBuilder ("facebook"), PFacebookId, PFacebookSecret, p);
    }

    private void extractIdSecret (
        ClientRegistration.Builder builder,
        String idKey,
        String secretKey,
        Properties properties)
    {
        String id = properties.getProperty (idKey);
        String secret = properties.getProperty (secretKey);
        if (StringUtils.isBlank (id) || StringUtils.isBlank (secret))
            return;
        _regns.add (builder.clientId (id).clientSecret (secret).build ());
    }

    @Override
    protected void configure (
        HttpSecurity http)
        throws Exception
    {
        _success.setUrl (SuccessUrl);
        _failure.setUrl (FailureUrl);

        JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl ();
        repo.setDataSource (_source);

        http
            .authorizeRequests ()
                .antMatchers ("/api/profile/**").authenticated ()
                .antMatchers ("/api/users/**").hasAuthority (Authority.ROLE_ADMIN.name ())
            .antMatchers ("/api/**").permitAll ()
            .and ()
            .exceptionHandling ()
                .authenticationEntryPoint (new Http403ForbiddenEntryPoint())
                .and ()
            .formLogin ()
                .loginProcessingUrl ("/login")
                .loginPage ("/")
                .successHandler (_success)
                .failureHandler (_failure)
                .and ()
            .logout ()
                .logoutUrl ("/logout")
                .logoutSuccessUrl (LogoutUrl)
                .and ()
            .rememberMe ()
                .tokenRepository (repo)
                .tokenValiditySeconds (1209600)
                .rememberMeParameter ("remember-me")
                .and ()
            .csrf ().disable ();

        if (!_regns.isEmpty ())
        {
            http.oauth2Login ()
                .clientRegistrationRepository (new InMemoryClientRegistrationRepository (_regns));
            _logger.debug ("OAuth2 entabled");
        }
    }

    @Override
    protected void configure (
        AuthenticationManagerBuilder builder)
        throws Exception
    {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider ();
        provider.setUserDetailsService (_userManager);
        provider.setPasswordEncoder (encoder ());

        builder.authenticationProvider (provider);
        builder.userDetailsService (_userManager);
    }

    @Bean
    public BCryptPasswordEncoder encoder ()
    {
        return new BCryptPasswordEncoder ();
    }
}

The callback from Google is going to the right place:

http://localhost:8080/mezo/login/oauth2/code/google?state=.....

But my webapp complains with:

HTTP Status 404 - /mezo/login

Can anyone see what I've missed in my config? Why hasn't Spring Security automatically setting up the filters for the callback uri?

Note that the login using JDBC currently works with this config.

like image 886
Jonathan Avatar asked Nov 08 '25 09:11

Jonathan


1 Answers

The fix was to be a bit more permissive with the antMatchers(). In particular, extending:

        .antMatchers ("/api/**").permitAll ()

with:

        .antMatchers ("/api/**", "/login/**").permitAll ()
like image 160
Jonathan Avatar answered Nov 11 '25 03:11

Jonathan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!