2016-09-10 1 views
2

Ich möchte einen einfachen Test schreiben, aber meine SecurityConfig gibt mir immer Zugriff verweigert. Hier ist mein config:Mocking ein Benutzer im Frühjahr

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private UserService userService; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.addFilterBefore(new TokenAuthenticationFilter(userService), AnonymousAuthenticationFilter.class); 
     http.csrf().disable(); 
     http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER); 

     //Options preflight 
     http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll(); 

     //ACL 
     http.authorizeRequests().antMatchers(HttpMethod.POST, "/auth/password").hasAnyRole("ADMIN", "CUSTOMER", "REFUGEE"); 
     http.authorizeRequests().antMatchers("/auth/**").anonymous(); 

     //Tags 
    http.authorizeRequests().antMatchers(HttpMethod.GET, "/tags").hasAnyRole("ADMIN", "CUSTOMER", "REFUGEE"); 
    http.authorizeRequests().antMatchers(HttpMethod.GET, "/tags/recommendation").hasAnyRole("ADMIN", "CUSTOMER", "REFUGEE"); 
    http.authorizeRequests().antMatchers(HttpMethod.POST, "/tags").hasAnyRole("ADMIN", "REFUGEE"); 
    http.authorizeRequests().antMatchers(HttpMethod.GET, "/tags/recommendation/random").hasAnyRole("ADMIN", "CUSTOMER", "REFUGEE"); 
    http.authorizeRequests().antMatchers(HttpMethod.PUT, "/tags").hasAnyRole("ADMIN"); 
    http.authorizeRequests().antMatchers(HttpMethod.GET, "/tags/notapproved").hasAnyRole("ADMIN"); 
    http.authorizeRequests().antMatchers(HttpMethod.PUT, "/tags/approve/{id}").hasAnyRole("ADMIN"); 
    } 

Und die AuthenticationFilter:

public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 

    private UserService userService; 

    public TokenAuthenticationFilter(UserService userService) { 
     super("/"); 
     this.userService = userService; 
    } 

    private final String HEADER_SECURITY_TOKEN = "Authorization"; 
    private final String PARAMETER_SECURITY_TOKEN = "access_token"; 
    private String token = ""; 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
     HttpServletRequest request = (HttpServletRequest) req; 
     HttpServletResponse response = (HttpServletResponse) res; 

     this.token = request.getHeader(HEADER_SECURITY_TOKEN); 
     if ("".equals(this.token) || this.token == null) { 
      this.token = request.getParameter(PARAMETER_SECURITY_TOKEN); 
     } 

     //Attempt to authenticate 
     Authentication authResult; 
     authResult = attemptAuthentication(request, response); 
     if (authResult == null) { 
      chain.doFilter(request, response); 
     } else { 
      successfulAuthentication(request, response, chain, authResult); 
     } 
    } 

    /** 
    * Attempt to authenticate request - basically just pass over to another 
    * method to authenticate request headers 
    */ 
    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { 
     Authentication userAuthenticationToken = authUserByToken(); 
     if (userAuthenticationToken == null) { 
      //throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token")); 
     } 
     return userAuthenticationToken; 
    } 

    /** 
    * authenticate the user based on token, mobile app secret & user agent 
    * 
    * @return 
    */ 
    private Authentication authUserByToken() { 
     Authentication securityToken = null; 
     try { 
      User user = userService.findUserByAccessToken(this.token); 
      securityToken = new PreAuthenticatedAuthenticationToken(
        user, null, user.getAuthorities()); 
     } catch (Exception e) { 
      logger.error("Authenticate user by token error: ", e); 
     } 
     return securityToken; 
    } 

    @Override 
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, 
      Authentication authResult) throws IOException, ServletException { 
     SecurityContextHolder.getContext().setAuthentication(authResult); 
     chain.doFilter(request, response); 
    } 

Und der einfache Test:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = {"classpath*:spring/test/test-servlet.xml"}) 
@WebAppConfiguration 
public class TagControllerTest { 

    private MockMvc mockMvc; 

    private TagService tagServiceMock; 

    @Autowired 
    private FilterChainProxy springSecurityFilterChain; 

    @Resource 
    private WebApplicationContext webApplicationContext; 

    @Before 
    public void setUp() { 
     tagServiceMock = mock(TagService.class); 
     this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) 
       .addFilters(this.springSecurityFilterChain) 
       .build(); 
    } 

    public TagControllerTest() { 
    } 

    /** 
    * Test of getAllTags method, of class TagController. 
    */ 
    @Test 
    public void testGetAllTags() throws Exception { 
     List<Tags> tagsList = new ArrayList<>(); 
     tagsList.add(new Tags((long) 1, "test", 2, 1)); 
     tagsList.add(new Tags((long) 2, "test2", 4, 0)); 
     User user = TestUtil.EMPTY_USER; 
     String query = ""; 
     String notIncluded = ""; 
     Integer limit = 8; 
     Integer start = 0; 
     Language language = new Language(0); 
     Boolean approved = false; 

     when(tagServiceMock.findTagsByQuery(user, query, limit, start, language, approved)).thenReturn(tagsList); 
     when(tagServiceMock.findTags(user, limit, start, language)).thenReturn(tagsList); 



     SecurityContextHolder.getContext().setAuthentication(TestUtil.getPrincipal("ROLE_ADMIN")); 

     mockMvc.perform(get("/tags").with(securityContext(SecurityContextHolder.getContext())).header("host", "localhost:80")) 
       .andExpect(status().isOk()) 
       .andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8)) 
       .andExpect(jsonPath("$", hasSize(2))) 
       .andExpect(jsonPath("$[0].id", is(1))) 
       .andExpect(jsonPath("$[1].id", is(2))) 
       .andExpect(jsonPath("$[0].label", is("test"))) 
       .andExpect(jsonPath("$[1].label", is("test2"))) 
       .andExpect(jsonPath("$[0].count", is(2))) 
       .andExpect(jsonPath("$[1].count", is(4))) 
       .andExpect(jsonPath("$[0].approved", is(1))) 
       .andExpect(jsonPath("$[1].approved", is(0))); 

     verify(tagServiceMock, times(1)).findTagsByQuery(user, query, limit, start, language, approved); 
     verifyNoMoreInteractions(tagServiceMock); 

    } 

Das Problem ist, dass ich immer einen 403 -> Zugriff verweigert. Es ist wegen des TokenAuthenticationFilter. Wenn ich eine Kopfzeile mit dem Namen "Authorization" mit einem accesstoken setze, das korrekt ist (korrekt bedeutet, dass es von einem tatsächlichen Benutzer verwendet wird), dann funktioniert es. Aber ich denke, das ist nicht so, wie es für Komponententests sein sollte. Also was zu tun? Wie setze ich eine Rolle und übergebe den SecurityFilter?

Antwort

1

Sie sollten die Spring-Sicherheit für die Zwecke der Tests deaktivieren, wenn Sie keine Integrationstests durchführen, die sie enthalten sollten.