Sunday, July 30, 2017

Spring boot test does not respect web security configuration

Leave a Comment

I'm writing test for a Rest API controller. This endpoint is accessible without any authorization:

@EnableWebSecurity @Configuration @Import(AppConfig.class) class WebSecurityConfig extends WebSecurityConfigurerAdapter {  @Autowired  private UserDetailsRepository accountRepository;  @Autowired private CustomUserDetailsService customUserDetailsService;  @Autowired private JWTAuthenticationFilter jwtAuthenticationFilter;  @Override protected void configure(HttpSecurity http) throws Exception {     http         .csrf().disable()         .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)         .authorizeRequests()             .anyRequest().authenticated().and()         .sessionManagement()             .sessionCreationPolicy(SessionCreationPolicy.STATELESS); }  /*  * Apparently, permitAll() doesn't work for custom filters, therefore we ignore the signup and login endpoints   * here  */ @Override public void configure(WebSecurity web)         throws Exception {     web.ignoring()         .antMatchers(HttpMethod.POST, "/login")         .antMatchers(HttpMethod.POST, "/signup"); }  /*  * set user details services and password encoder  */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {     auth.userDetailsService(userDetailsServiceBean()).passwordEncoder(passwordEncoder()); }  @Bean public PasswordEncoder passwordEncoder() {     return new BCryptPasswordEncoder(); }  /* Stopping spring from adding filter by default */ @Bean public FilterRegistrationBean rolesAuthenticationFilterRegistrationDisable(JWTAuthenticationFilter filter) {     FilterRegistrationBean registration = new FilterRegistrationBean(filter);     registration.setEnabled(false);     return registration; } 

}

The JWTAuthenticationFilter class:

@Component public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {      @Autowired     private UserDetailsService customUserDetailsService;      private static Logger logger = LoggerFactory.getLogger(JWTAuthenticationFilter.class);     private final static UrlPathHelper urlPathHelper = new UrlPathHelper();      final static String defaultFilterProcessesUrl = "/**";      public JWTAuthenticationFilter() {         super(defaultFilterProcessesUrl);         super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(defaultFilterProcessesUrl)); //Authentication will only be initiated for the request url matching this pattern         setAuthenticationManager(new NoOpAuthenticationManager());     }      @Override     public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {         Authentication authentication = AuthenticationService.getAuthentication(request, customUserDetailsService);         return getAuthenticationManager().authenticate(authentication);     }      @Override     protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {         logger.debug("failed authentication while attempting to access "+ urlPathHelper.getPathWithinApplication((HttpServletRequest) request));         response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Authentication Failed");     }      @Override     protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {         SecurityContextHolder.getContext().setAuthentication(authResult);         chain.doFilter(request, response);     }      @Override     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {         super.doFilter(req, res, chain);     } }  

When I make a request (using postman) to 'signup' endpoint it works fine. But when I run the test, it hits doFilter and fails, as it doesn't get authenticated.

@RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public class AuthenticationControllerFTest {      @Autowired      private MockMvc mockMvc;      @MockBean     private AuthenticationManager authenticationManager;      @Test     public void testCreate() throws Exception {         Authentication authentication = Mockito.mock(Authentication.class);         Mockito.when(authentication.getName()).thenReturn("DUMMY_USERNAME");         Mockito.when(                 authenticationManager.authenticate(Mockito                         .any(UsernamePasswordAuthenticationToken.class)))                 .thenReturn(authentication);          String exampleUserInfo = "{\"name\":\"Test1234\",\"username\":\"test@test.com\",\"password\":\"Salam12345\"}";         RequestBuilder requestBuilder = MockMvcRequestBuilders                 .post("/signup")                 .accept(MediaType.APPLICATION_JSON).content(exampleUserInfo)                 .contentType(MediaType.APPLICATION_JSON);          MvcResult result = mockMvc.perform(requestBuilder).andReturn();          MockHttpServletResponse response = result.getResponse();         int status = response.getStatus();         String content = response.getContentAsString();         System.out.println(content);         Assert.assertEquals("http response status is wrong", 200, status);     } } 

Any idea on how to fix this issue ?

2 Answers

Answers 1

The issue was resolved by adding the following code to the test class:

@Autowired private WebApplicationContext context;  @Autowired private Filter springSecurityFilterChain;  @Before public void setup() {     mockMvc = MockMvcBuilders.webAppContextSetup(context)             .addFilters(springSecurityFilterChain).build(); } 

Answers 2

@Override protected void configure(HttpSecurity http) throws Exception {     http.csrf().disable().authorizeRequests()             .antMatchers("/**").permitAll()             .anyRequest().authenticated(); } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment