Kieveli Kieveli - 6 months ago 127
Java Question

MockMvc using a mock session to bypass security

I'm working on a spring-boot micro-service in a suite of micro-services. The service endpoints are all protected using two features: a @PreAuthorize annotation, and a custom GenericFilterBean that provides extra stateless authentication.

There are examples of people using the MockMvc to first post to a login url, and then get from a specified endpoint. This is a problem for me because the login is performed by a different micro-service.

I have made different attempts without a complete understanding which can be summed up as:


  1. Login via the other micro-service to acquire a session with cookies set

  2. Mock the session to use fake cookies

  3. Disable the Security and custom filter



MockMvc doesn't allow for calling external urls to perform the login, so the first is ruled out. Mocking the session doesn't appear to give me a way to set cookies - I only see addCookie on the response object. Disabling the custom filter has resulted in nothing happening (maybe I'm doing this wrong).

It seems to me that the proper way to test is to have a valid mock session and allow the security to remain in place. I'm stumped as to how to proceed.

The spring-boot parent pom is: spring-cloud-starter-parent - Brixton.M4

How can I test a single micro-service and bypass security?

Answer

I've had a similar problem a while ago and it took me some time to find an answer, not sure if this will solve your problem, but I could manage to authenticate using mockMvc using the following approach

Create a class that will be responsible for authentication. It could be something like this

public class Auth {  

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    private FilterChainProxy springSecurityFilter;

    protected MockMvc mockMvc;
    protected MockHttpSession session;

    public void setup() throws Exception{
        this.session = new MockHttpSession();
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
                .addFilters(springSecurityFilter)
                .build();
    }

    protected void setAuthentication(String user, String password, MockHttpSession session){
        Authentication authentication = new UsernamePasswordAuthenticationToken(user, password);
        SecurityContext securityContext = SecurityContextHolder.getContext();
        securityContext.setAuthentication(authentication);

        session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,securityContext);
    }
}

Now you can simply extend this class and use the method setAuthenticatio to login and perform the test. For instance

public class myTest extends Auth {
     @Test
     public void test{ 
         setAuthentication('user', 'password', session);
         // perform you tests using mockmvc
         // mockMvc.perform(post('url')...

     }

}