0

I have followed the instructions below to create two different http security blocks for admin and user. docs.spring.io/spring-security-multiple-httpsecurity

As document says , if the URL does not start with /aaa, another configuration will be used to pattern.

But when i put @Order(1) at admin block ,admin page works fine , user page will not redirect to login page /login/user

while i put @Order(1) at user block , user page works fine , admin page will not redirect to login page /login/admin either.

here is my java code

@EnableWebSecurity
public class MultiHttpSecurityConfig {

    /**
     * intercept user url
     */
    @Configuration
    @Order(1)
    public static class UserWebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        CustomAuthenticationSuccessHandler successHandler;

        @Autowired
        CustomAuthenticationFailureHandler failureHandler;

        @Autowired
        private CustomAuthenticationProvider customAuthProvider;

        @Autowired
        private CustomUserDetailsService userDetailsService;

        @Value("${my.cookie.timeout}")
        private int cookieTimeOut;


        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
            http.authorizeRequests()
                .antMatchers("/css/**", "/js/**", "/images/**, /fonts/**").permitAll()
                .antMatchers("/bbb/**","/aaaa/**").hasAnyRole("USER");
            http.formLogin()
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .loginPage("/login/user").permitAll();
            http.logout().permitAll();

            http.rememberMe().key("uniqueAndSecret").tokenValiditySeconds(cookieTimeOut);
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(customAuthProvider);
            auth.userDetailsService(userDetailsService);
        }
    }


    /**
     * intercept admin url
     */
    @Configuration
    public static class AdminWebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        CustomAuthenticationSuccessHandler successHandler;

        @Autowired
        CustomAuthenticationFailureHandler failureHandler;

        @Value("${my.cookie.timeout}")
        private int cookieTimeOut;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
            http.authorizeRequests()
                .antMatchers("/css/**", "/js/**", "/images/**, /fonts/**").permitAll()
                .antMatchers("/ccc/**","/dddd").hasAnyRole("ADMIN");
            http.formLogin()
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .loginPage("/login/admin").permitAll();
            http.logout().permitAll();

            http.rememberMe().key("uniqueAndSecret").tokenValiditySeconds(cookieTimeOut);
        }

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                .withUser("test").password("test").roles("ADMIN");
        }
    }
}

update:

As dur says below,the key reason is authorizeRequests() method matches all urls in Order(1) , so i need to add antMatcher("/bbb/*")** at first before authorizeRequests().

But antMatcher() only matches just only one kind of url , if i have one more kinds of urls to match like "/bbb/" , "/aaa/*" , how to achieve this ? Then i need to add one more WebSecurityConfigurerAdapter configuration ? Is there any better way to do this to reduce code ?

I have found solution in spring-security SDK requestMatchers() method, it provides a example above the requestMatchers() method.

Here is my code below for match user's urls at Order(1)

http.csrf().disable();
            http.requestMatchers()
                .antMatchers("/bbb/**", "/aaa/**")
                .and()
                .authorizeRequests()
                .antMatchers("/**").hasAnyRole("USER");
            http.formLogin()
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .loginPage("/login/user").permitAll();
            http.logout().permitAll();

Then both bbb and aaa have been matched and don't need to create another configuration

But another problem occurs , it will show "405 method not allowed" when post username and password to login/user interface at user login page , while admin page works fine

I have searched google ,it tells to disable csrf , but i have already disable csrf...

Buffer
  • 101
  • 1
  • 8
  • Both configruations are applied for `/**` (any request), so the first one is used. If you add an order, the one with the lowest order is used. – dur Sep 01 '19 at 13:00

1 Answers1

0

In one of my project I did not use form login, but implemented a custom AccessDeniedHandler and AuthenticationEntryPoint that can redirect to different login pages with some custom logic I needed. However, loginPage() is also an AuthenticationEntryPoint in the end.

They can be added via:

.exceptionHandling().authenticationEntryPoint(new YourCustomAuthEntryHandler()).and()
.exceptionHandling().accessDeniedHandler(new YourCustomAccessDeniedHandler())

It's just an idea, maybe it worth checking them.

Moreover, I think you will need authenticate all requests, add this line for both configs in the authorizeRequests() block:

.anyRequest().authenticated()
mrkurtan
  • 573
  • 2
  • 13
  • Just thinking now, you can actually have one security config: in the auth entry handler check for the request url if any is from the admin sites, you can redirect it to admin login, however it is not the nicest solution, but should work. – mrkurtan Sep 01 '19 at 09:51
  • Thanks a lot for your reply , i will consider to use it :) – Buffer Sep 02 '19 at 05:01