Implement "oauth2Login()" and "httpBasic()" same page via MultiHttpSecurityConfig

Viewed 559

If the user clicks /api/*, it will load the "formLogin()" page; otherwise loads "httpBasic()." This setup works fine. Below is its code.

@Configuration
    public class SecurityConfig {

    @Configuration
    @Order(1)
    public static class SpecialSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/**")
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/api/login");         
        }
        
        @Override
        public void configure(WebSecurity web) throws Exception {
          web.ignoring().antMatchers("/", "/css/**");
        }
    }

    @Configuration
    public static class RegularSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .httpBasic();
        }
        
        @Override
        public void configure(WebSecurity web) throws Exception {
          web.ignoring().antMatchers("/", "/css/**");
        }
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user")
                .password("{noop}pass")
                .roles("USER");
    }
}

Now I want to remove "formLogin()" and replace it with "oauth2Login()." After that, When I click the google link, it loads the "httpBasic()" login page. If the user clicks google, it should go to the google login page. Please help me to fix this issue. Below is its code.

    http
    .antMatcher("/api/**")
    .authorizeRequests()
    .anyRequest().authenticated()
    .and()
    .oauth2Login()
    .loginPage("/api/oauth_login")
    .permitAll();

oauth_login.html

<body>
<div class="container">
<h1>Social Login</h1>
<p><a href="/oauth2/authorization/google">Google</a></p>
</div>
</body>
4 Answers

You are specifying that requests that match "/api/**" should be secured by SpecialSecurityConfig using OAuth 2 login and all the other requests should be secured by RegularSecurityConfig using HTTP basic.

Since "/oauth2/authorization/google" does not match "/api/**" it is secured using HTTP basic.

One option is to change the base URI used for authorization requests to start with "/api/" (the default is "/oauth2/authorization/{registrationId}").

You will likely also want to customize the loginProcessingUrl and the authorizationRequestResolver.

public void configure(HttpSecurity http) throws Exception {
    http
        .antMatcher("/api/**")
        .authorizeRequests(authorize -> authorize
            .anyRequest().authenticated()
        )
        .oauth2Login(oauth2 -> oauth2
            .loginProcessingUrl("/api/login/oauth2/code/*")
            .loginPage("/api/oauth_login")
            .authorizationEndpoint(ae -> ae
                .baseUri("/api/oauth2/authorization/{registrationId}")
                .authorizationRequestResolver(getAuthorizationRequestResolver())
            )
        );
}

private OAuth2AuthorizationRequestResolver getAuthorizationRequestResolver() {
    return new DefaultOAuth2AuthorizationRequestResolver(
        this.clientRegistrationRepository,
        "/api/oauth2/authorization");
}

You would then also update your login form

<p><a href="/api/oauth2/authorization/google">Google</a></p>

Now I able to load the google login page. After adding the credential, the page redirects to the Whitelabel Error Page.

Oauth2 code

http
            .antMatcher("/api/**")
            .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
            .oauth2Login(oauth2 -> oauth2.loginProcessingUrl("/api/login/oauth2/code/*")
                    .loginPage("/api/oauth_login").permitAll()
                    .authorizationEndpoint(a -> a.baseUri("/api/oauth2/authorization")
                            .authorizationRequestResolver(                                    
                                    getAuthorizationRequestResolver())
                            )
            );

ERROR ->

2021-03-11 15:02:53.319 DEBUG 11762 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : GET "/login/oauth2/code/google?state=Ds-x92t6fpHo8BINK_xYba3fpidheKQSHBaTdctOPRE%3D&code=4%2F0AY0e-g6i-tfqlpBREW45ufRPQEOu-aM7VjIf7VzKOBVMSXrvLkaxB5U2A72dAOxxEUnN1Q&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&hd=wearenoetic.com&prompt=consent", parameters={masked}

2021-03-11 15:02:53.321 DEBUG 11762 --- [nio-8080-exec-2] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]]

2021-03-11 15:02:53.346 DEBUG 11762 --- [nio-8080-exec-2] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found

2021-03-11 15:02:53.346 DEBUG 11762 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND

2021-03-11 15:02:53.348 DEBUG 11762 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error?state=Ds-x92t6fpHo8BINK_xYba3fpidheKQSHBaTdctOPRE%3D&code=4%2F0AY0e-g6i-tfqlpBREW45ufRPQEOu-aM7VjIf7VzKOBVMSXrvLkaxB5U2A72dAOxxEUnN1Q&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&hd=wearenoetic.com&prompt=consent", parameters={masked}

2021-03-11 15:02:53.349 DEBUG 11762 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)

2021-03-11 15:02:53.373 DEBUG 11762 --- [nio-8080-exec-2] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, text/html;q=0.8]

2021-03-11 15:02:53.374 DEBUG 11762 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 404

I refer the below URL and modify my code

Oauth2Login for only specific urls

http 
        .authorizeRequests()
        .antMatchers("/api/**").authenticated()        
        .anyRequest().authenticated()
        .and()
        .oauth2Login()
        .loginPage("/api/oauth_login")
        .defaultSuccessUrl("/api/home")
        .permitAll();

Normal URLs(other than /api/*) also load google login page.

Disable basic login and form login. Sample security config would look like;

 .formLogin()
                .disable()
            .httpBasic()
                .disable()
            .exceptionHandling()
                .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                .and()
            .authorizeRequests()
                .antMatchers("/auth/**", "/oauth2/**")
                    .permitAll()
                .anyRequest()
                    .authenticated()
                .and()
            .oauth2Login()
                .authorizationEndpoint()
                    .baseUri("/oauth2/authorize")
                    .and()
                .redirectionEndpoint()
                .baseUri("/oauth2/callback/*")

Call this endpoint from the frontend (Google/Facebook button should be linked to the below link)
http://localhost:8080/oauth2/authorize/{provider}?redirect_uri=<redirect_uri_after_login>

Follow this guide. This is exactly what are you looking for.

Related