Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security HttpSecurity Configuration Testing

I have a Spring Boot + Spring Security application that has severalantMatchers paths; some fullyAuthenticated(), some permitAll().

How to I write a test that verifies SecurityConfiguration has my endpoints under /api/** (and ultimately others) secured correctly?

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    protected void configure(HttpSecurity http) throws Exception {
        http
            //...
            .antMatchers("/api/**").fullyAuthenticated()
    }

}

Using spring-boot-1.5.2.RELEASE, spring-security-core-4.2.2-release.

Clarification1: I want to as-directly-as-possible test the SecurityConfiguration, as opposed to transitively testing via one of the /api/** endpoints, which may have their own @PreAuthorize security.

Clarification2: I would like something similar to this WebSecurityConfigurerAdapterTests.

Clarification3: I would like to @Autowire something at the Spring Security layer, ideally HttpSecurity, to test.

like image 911
JJ Zabkar Avatar asked Apr 27 '17 16:04

JJ Zabkar


People also ask

Is WebSecurityConfigurerAdapter deprecated?

The type WebSecurityConfigurerAdapter is deprecatedWell, it's because the developers of Spring framework encourage users to move towards a component-based security configuration.


2 Answers

So you want to ensure that if someone changes .antMatchers("/api/**") to .antMatchers("/WRONG_PATH/**") then you have a test that will figure it out ?

The rules you define using HttpSecurity will end up configuring a FilterChainProxy with one or more SecurityFilterChain, each with a list of filters. Each filter, such as UsernamePasswordAuthenticationFilter (used for form-based login), will have a RequestMatcher defined in the super class AbstractAuthenticationProcessingFilter. The problem is that RequestMatcher is an interface which currently have 12 different implementations, and this includes AndRequestMatcher and OrRequestMatcher, so the matching logic is not always simple. And most importantly RequestMatcher only has one method boolean matches(HttpServletRequest request), and the implementation often does not expose the configuration, so you will have to use reflection to access the private configurations of each RequestMatcher implementation (which could change in the future).

If you go down this path, and autowire FilterChainProxy into a test and use reflection to reverse-engineer the configuration, you have to consider all the implementation dependencies you have. For instance WebSecurityConfigurerAdapter has a default list of filters, which may change between releases, and unless disable it, and when it is disabled you have to define every filter explicitly. In addition new filters and RequestMatchers could be added over time, or the filter chain generated by HttpSecurity in one version of Spring Security may be slightly different in the next version (maybe not likely, but still possible).

Writing a generic test for your spring security configuration, is technically possible, but it is not exactly an easy thing to do, and the Spring Security filters certainly were not designed to support this. I have worked extensively with Spring Security since 2010, and I have never had the need for such a test, and personally I think it would be a waste of time trying to implement it. I think the time will be much better spent writing a test framework that makes it easy to write integration tests, which will implicitly test the security layer as well as the business logic.

like image 105
Klaus Groenbaek Avatar answered Sep 18 '22 09:09

Klaus Groenbaek


I see below test case can help you achieve what you want. It is an Integration Test to test the Web Security configuration and we have similar testing done for all our code that is TDD driven.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class WebConfigIT {
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Autowired
    private FilterChainProxy springSecurityFilterChain;

    @Before
    public void setup() throws Exception {
        mockMvc = webAppContextSetup(webApplicationContext)
                .addFilter(springSecurityFilterChain)
                .build();
    }

    @Test
    public void testAuthenticationAtAPIURI() throws Exception {
        mockMvc.perform(get("/api/xyz"))
                .andExpect(status.is3xxRedirection());
    }

This though looks like doing an explicit testing of the end-point (which is anyways a testing one have to do if doing TDD) but this is also bringing the Spring Security Filter Chain in context to enable you test the Security Context for the APP.

like image 35
Ashwin Gupta Avatar answered Sep 21 '22 09:09

Ashwin Gupta