-1

I have a web application - built using Java, Spring and Spring Security - that needs to support two different methods of authentication. The difficulty I have is that I want to use one authentication method on one set of controller end-points and the other method on the remaining end-points.

This is a difficulty because all the documentation I've read about multiple authentication providers seems to assume that you want all the providers to apply to all the end-points and you iterate through the providers until you find one that will authenticate the user.

I'm using Java annotation-base configuration (as opposed to XML configuration). Here are a few of the approaches I've explored without success:

  • configuring a provider with a pattern matcher to limit the end-points it applies
  • configuring a provider to only be triggered for certain authentication types, eg. if Digest credentials are present, trigger the Digest-based authentication provider

Can anyone suggest what is the best way to go about this? Is one of the above methods the correct way (and I've simply got it wrong)? Or is there another preferred way?

(I'm aware I've provided no specific code to review for an issue. This is because I'm only after guidance about the appropriate way of doing things in Spring.)

dave
  • 11,641
  • 5
  • 47
  • 65
  • This question is very broad. That said, look at [this question](https://stackoverflow.com/questions/49225035/how-to-provide-multiple-ways-of-authentication-with-spring-security/49229494#49229494), which is similar. – manish May 10 '18 at 05:44
  • Thanks for the link - it looks promising. I agree the question is broad and I tried to keep it narrow by asking for a specific approach (rather than code). – dave May 10 '18 at 06:42

1 Answers1

1

I'm using Spring Boot 2.0. I don't know about the best way but here's a way that worked for me. I had to break it out into to separate configuration classes and the second configuration needed to have the @Order annotation on it.

For my particular case I needed some administrative REST methods secured by HTTP basic authentication (username/password), and the remaining REST methods needed to be secured by custom logic.

@Configuration
@EnableWebSecurity
public class TestSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().permitAll();

        // anything that is NOT /admin/**
        RequestMatcher requestMatcher = new NegatedRequestMatcher(new AntPathRequestMatcher("/admin/**", "GET"));

        // MyCustomFilter is my class that performs custom authentication logic
        http.requestMatcher(requestMatcher)
            .addFilterAfter(new MyCustomFilter(), BasicAuthenticationFilter.class);
    }


    @Order(1)
    @Configuration
    public static class AdminServiceConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //this time anything that IS /admin/**
            http.requestMatchers()
                .antMatchers("/admin/**").and()
                .httpBasic().and()
                .authorizeRequests().antMatchers("/admin/**").fullyAuthenticated();
        }

        @Override
        protected void configure(AuthenticationManagerBuilder authBuilder) throws Exception {
            authBuilder.inMemoryAuthentication()
                .passwordEncoder(NoOpPasswordEncoder.getInstance())
                .withUser("username")
                .password("password")
                .roles("ADMIN");
        }
    }
}
ArmedChef
  • 106
  • 10
  • I took a slightly different approach to the above. However, the key takeaway is that you use a different _adapter_ for each set of end-points and attach the necessary filter, authentication method, etc. to it. – dave May 11 '18 at 07:22