Search code examples
spring-bootspring-securityform-authentication

Configuring Spring Security To Work With Two Different Login Pages


One of the situations in which we may need two login pages is when we have one page for administrators of an application and a different page for normal users. Each http element will have a different login page and a different login processing URL

I have got this Spring boot security config for allowing login for multiple page.

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

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

        public App1ConfigurationAdapter() {
            super();
        }

        @Autowired
        private BCryptPasswordEncoder bCryptPasswordEncoder;

        @Autowired
        private DataSource dataSource;

        @Value("${admin-users-query}")
        private String usersQuery;

        @Value("${admin-roles-query}")
        private String rolesQuery;

        @Override
        protected void configure(AuthenticationManagerBuilder auth)
                throws Exception {
            auth.
                    jdbcAuthentication()
                    .usersByUsernameQuery(usersQuery)
                    .authoritiesByUsernameQuery(rolesQuery)
                    .dataSource(dataSource)
                    .passwordEncoder(bCryptPasswordEncoder);
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/admin*")
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/admin/temp/login")
                    .failureUrl("//admin/temp?error=loginError")
                    .defaultSuccessUrl("/")
                    .usernameParameter("email")
                    .passwordParameter("password")
                    .permitAll()
                    .and()
                    .logout()
                    .logoutUrl("/admin/temp/logout")
                    .logoutSuccessUrl("/admin/temp")
                    .and()
                    .exceptionHandling()
                    .accessDeniedPage("/403").and().csrf();
        }
    }

    @Configuration
    @Order(2)
    public static class App2ConfigurationAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private BCryptPasswordEncoder bCryptPasswordEncoder;

        @Autowired
        private DataSource dataSource;

        @Value("${user-users-query}")
        private String usersQuery;

        @Value("${user-roles-query}")
        private String rolesQuery;

        @Override
        protected void configure(AuthenticationManagerBuilder auth)
                throws Exception {
            auth.
                    jdbcAuthentication()
                    .usersByUsernameQuery(usersQuery)
                    .authoritiesByUsernameQuery(rolesQuery)
                    .dataSource(dataSource)
                    .passwordEncoder(bCryptPasswordEncoder);
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/user*")
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/user/temp/login")
                    .failureUrl("/user/temp/?error=loginError")
                    .defaultSuccessUrl("/user/temp")
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .permitAll()
                    .and()
                    .logout()
                    .logoutUrl("/user/temp/logout")
                    .logoutSuccessUrl("/user/temp/login")
                    .and()
                    .exceptionHandling()enter code here
                    .accessDeniedPage("/403").and().csrf();
        }
    }

    @Configuration
    @Order(3)
    public static class guestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .anyRequest().permitAll();

        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web
                    .ignoring().antMatchers("/js/**", "/js/***", "/js/****");
        }
    }

Admin login form /admin/temp/login

<form th:action="@{/admin/temp/login}" method="post">
                                        <div class="input-group mb-3">
                                            <span class="input-group-addon"><i class="icon-envelope"></i></span>
                                            <input type="text" class="form-control" placeholder="Email" name="email" data-validation="required" />
                                        </div>
                                        <div class="input-group mb-4">
                                            <span class="input-group-addon"><i class="icon-lock"></i></span>
                                            <input type="password" class="form-control" placeholder="Password" name="password"  data-validation="required" />
                                        </div>
                                        <div class="row">
                                            <div class="col-6">
                                                <input type="submit" class="btn btn-primary px-4" value="Login">
                                            </div>
                                            <div class="col-6 text-right">
                                                <a href="#" class="btn btn-link px-0">Forgot password?</a>
                                            </div>
                                        </div>
                                    </form>

User login form /user/temp/login

<form th:action="@{/user/temp/login}" method="post">
                                        <div class="input-group mb-3">
                                            <span class="input-group-addon"><i class="icon-envelope"></i></span>
                                            <input type="text" class="form-control" placeholder="Email" name="username" data-validation="required" />
                                        </div>
                                        <div class="input-group mb-4">
                                            <span class="input-group-addon"><i class="icon-lock"></i></span>
                                            <input type="password" class="form-control" placeholder="Password" name="password"  data-validation="required" />
                                        </div>
                                        <div class="row">
                                            <div class="col-6">
                                                <input type="submit" class="btn btn-primary px-4" value="Login">
                                            </div>
                                            <div class="col-6 text-right">
                                                <a href="#" class="btn btn-link px-0">Forgot password?</a>
                                            </div>
                                        </div>
                                    </form>

When I Submit the form I get

**Code: 405
(Method Not Allowed)**

When I use single form the form get submted.

Does anyone has an idea on whats happening her?

Solution

  • By default Spring assumes that URL to validate the credentials is /login. To change it you should set up loginProcessingUrl for both formLogin configurations.

    It should be something like:

    .formLogin()
    .loginPage("/user/temp/login")
    .failureUrl("/user/temp/?error=loginError")
    .defaultSuccessUrl("/user/temp")
    .usernameParameter("username")
    .passwordParameter("password")
    .loginProcessingUrl("/user/temp/login") # missing line