2017-05-21 3 views
1

커스텀 MySql 데이터베이스를 사용하여 스프링 보안으로 설정 한 간단한 어플리케이션이 있습니다. 지금은 테스트 케이스를 작성 중이며 로그인 페이지 및 로그인 후에 작동하는 모든 것이 실패하는 것 같습니다. 내 질문은 성공적인 로그인 및 후속 요청을 확인하기위한 테스트 케이스를 작성하는 방법입니다.스프링 보안을 이용한 스프링 부트 유닛 테스트

내 보안 구성 :

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private BCryptPasswordEncoder bCryptPasswordEncoder; 

    @Autowired 
    private DataSource dataSource; 

    @Value("${spring.queries.users-query}") 
    private String usersQuery; 

    @Value("${spring.queries.roles-query}") 
    private String rolesQuery; 

    @Autowired 
    private CustomAuthenticationSuccessHandler successHandler; 

    /** Providing the queries and data source for security*/ 
    @Override 
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception 
    { 
     auth. 
      jdbcAuthentication() 
       .usersByUsernameQuery(usersQuery) 
       .authoritiesByUsernameQuery(rolesQuery) 
       .dataSource(dataSource) 
       .passwordEncoder(bCryptPasswordEncoder); 
    } 

    /** Defining fine grained access for ADMIN and CUSTOMER user */ 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 

     http. 
      authorizeRequests() 
       .antMatchers("/").permitAll() 
       .antMatchers("/login").permitAll() 
       .antMatchers("/registration").permitAll() 
       .antMatchers("/user/**").hasAuthority(AppRole.CUSTOMER.toString()) 
       .antMatchers("/health/**").hasAuthority(AppRole.ADMIN.toString()) 
       .antMatchers("/admin/**").hasAuthority(AppRole.ADMIN.toString()).anyRequest() 
       .authenticated().and().csrf().disable().formLogin() 
       .loginPage("/login").failureUrl("/login?error=true") 
       .successHandler(successHandler) 
       .usernameParameter("username") 
       .passwordParameter("password") 
       .and().logout() 
       .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) 
       .logoutSuccessUrl("/").and().exceptionHandling() 
       .accessDeniedPage("/access-denied"); 
    } 

    /** Defining ant matchers that should ignore the paths and provide no access to any one */ 
    @Override 
    public void configure(WebSecurity web) throws Exception 
    { 
     web 
      .ignoring() 
      .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**"); 
    } 

} 

내 사용자 정의 성공 처리기 :

@Component 
@Configuration 
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler 
{ 
    /** Getting reference to UserService */ 
    @Autowired 
    private UserService userService; 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, 
      HttpServletResponse httpServletResponse, Authentication authentication) 
        throws IOException, ServletException, RuntimeException 
    { 
     HttpSession session = httpServletRequest.getSession(); 
     User authUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
     com.crossover.techtrial.java.se.model.User user = userService.findUserByUsername(authUser.getUsername()); 
     session.setAttribute("userId", user.getUserId()); 
     session.setAttribute("username", authUser.getUsername()); 
     session.setAttribute("accountId", user.getAccountId()); 
     //set our response to OK status 
     httpServletResponse.setStatus(HttpServletResponse.SC_OK); 
     Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); 
     authorities.forEach(authority -> 
           { 
            if(authority.getAuthority().equals(AppRole.ADMIN.toString())) 
            { 
             session.setAttribute("role", AppRole.ADMIN); 
             try 
             { 
              //since we have created our custom success handler, its up to us to where 
              //we will redirect the user after successfully login 
              httpServletResponse.sendRedirect("/admin/home"); 
             } 
             catch (IOException e) 
             { 
              throw new RuntimeException(e); 
             }                   
            } 
            else if (authority.getAuthority().equals(AppRole.CUSTOMER.toString())) 
            { 
             session.setAttribute("role", AppRole.CUSTOMER); 
             try 
             { 
              //since we have created our custom success handler, its up to us to where 
              //we will redirect the user after successfully login 
              httpServletResponse.sendRedirect("/user/home"); 
             } 
             catch (IOException e) 
             { 
              throw new RuntimeException(e); 
             } 
            } 
           }); 

    } 

} 

이 같은 테스트 케이스를 작성하려하지만 그들은 보이지 않는 일부 seraching가 작동 할 후 :

@RunWith(SpringRunner.class) 
    @SpringBootTest 
    public class TrialApplicationTests 
    { 
     @Autowired 
     private WebApplicationContext webApplicationContext; 

     @Autowired 
     private FilterChainProxy springSecurityFilterChain; 

     @Autowired 
     private MockHttpServletRequest request; 

     private MockMvc mockMvc; 


     @Test 
     public void contextLoads() 
     { 
     } 

     @Before 
     public void setup() 
     { 
      mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) 
        .addFilters(springSecurityFilterChain) 
        .build(); 
     } 
     @Test 
     public void verifiesLoginPageLoads() throws Exception 
     { 
      mockMvc.perform(MockMvcRequestBuilders.get("/")) 
        .andExpect(MockMvcResultMatchers.model().hasNoErrors()) 
        .andExpect(MockMvcResultMatchers.view().name("login")) 
        .andExpect(MockMvcResultMatchers.status().isOk()); 
     } 

     @Test 
     public void testUserLogin() throws Exception 
     { 
      HttpSession session = mockMvc.perform(post("/login") 
        .contentType(MediaType.APPLICATION_FORM_URLENCODED) 
        .param("username", "test") 
        .param("password", "test123") 
        ) 
        .andExpect(MockMvcResultMatchers.status().isOk()) 
        //.andExpect(redirectedUrl("/user/home")) 
        .andReturn() 
        .getRequest() 
        .getSession(); 

      request.setSession(session); 

      SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); 

      SecurityContextHolder.setContext(securityContext); 
     } 

     @Test 
     public void testRetrieveUserBookings() throws Exception 
     { 
      testUserLogin(); 

      mockMvc.perform(MockMvcRequestBuilders.get("user/bookings")) 
       .andExpect(MockMvcResultMatchers.model().hasNoErrors()) 
       .andExpect(MockMvcResultMatchers.model().attributeExists("bookings")) 
       .andExpect(MockMvcResultMatchers.view().name("user/bookings")) 
       .andExpect(content().string(containsString("Booking"))); 
     } 

    } 

I searched on the net and there are links WithMockUser and UserDetails, but the problem is as you can see I'm setting a my primary key userId in the session in my custom success handler. So I would also need to get the session in my test. Please tell me the simplest way to write tests that will work, possibly with code since I'm new with security and all such. 

UPDATE: 

I changed the code as suggested but still getting the 404 error on my testRetrieveUserBookings. Any more ideas? 

@RunWith(SpringRunner.class) 
@ContextConfiguration 
@SpringBootTest 
@FixMethodOrder(MethodSorters.NAME_ASCENDING) 
@TestExecutionListeners(listeners={ServletTestExecutionListener.class, 
     DependencyInjectionTestExecutionListener.class, 
     DirtiesContextTestExecutionListener.class, 
     TransactionalTestExecutionListener.class, 
     WithSecurityContextTestExecutionListener.class}) 
public class TrialApplicationTests 
{ 
    @Autowired 
    private WebApplicationContext webApplicationContext; 

    MockMvc mockMvc; 

    @Autowired 
    ForestApiClient apiClient; 

    @Autowired 
    AccountClient accountClient; 

    @Autowired 
    AirlineClient airlineClient; 

    @Autowired 
    UserService userService; 

    private final String INTEGRATION_ACCOUNT = "account1"; 

    private MockHttpSession mockSession; 

    private Authentication authentication; 

    @Test 
    public void contextLoads() 
    { 
    } 

    @Before 
    public void setup() 
    { 
     mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) 
       //.addFilters(springSecurityFilterChain) 
       .build(); 

     mockSession = new MockHttpSession(webApplicationContext.getServletContext(), UUID.randomUUID().toString()); 
     mockSession.setAttribute("userId", 3); 
     mockSession.setAttribute("accountId", "ZWR26539"); 
    } 

    @Test 
    public void testVerifiesLoginPageLoads() throws Exception 
    { 
     mockMvc.perform(MockMvcRequestBuilders.get("/")) 
       .andExpect(MockMvcResultMatchers.model().hasNoErrors()) 
       .andExpect(MockMvcResultMatchers.view().name("login")) 
       .andExpect(MockMvcResultMatchers.status().isOk()); 
    } 

    @Test 
    public void testRegistration() throws Exception 
    { 
     mockMvc.perform(post("/registration") 
       .contentType(MediaType.APPLICATION_FORM_URLENCODED) 
       .param("username", "test2") 
       .param("password", "test123") 
       .param("email", "[email protected]") 
       .param("address", "Some Address") 
       .param("accountCurrency", "USD") 
       ) 
       .andExpect(MockMvcResultMatchers.status().isOk()) 
       .andExpect(MockMvcResultMatchers.model().hasNoErrors()) 
       .andExpect(MockMvcResultMatchers.model().attributeExists("user")) 
       .andExpect(MockMvcResultMatchers.view().name("registration")) 
       .andExpect(content().string(containsString("User has been registered successfully"))); 
    } 

    @Test 
    @WithMockUser(username="test",roles={"USER","ADMIN"}) 
    public void testRetrieveUserBookings() throws Exception 
    { 

     mockMvc.perform(MockMvcRequestBuilders.get("user/bookings")) 
      .andExpect(MockMvcResultMatchers.model().hasNoErrors()) 
      .andExpect(MockMvcResultMatchers.model().attributeExists("bookings")) 
      .andExpect(MockMvcResultMatchers.view().name("user/bookings")) 
      .andExpect(content().string(containsString("Booking"))); 
    } 
} 

답변

0

문제가 세션 내에서만 테스트 중이면 MockHttpSession으로 이동할 수 있습니다.

+0

나는 당신이 나에게 말한대로했으나 세션에서 값을 가져 오지 않았습니다. 404 오류가 발생합니다. 업데이트 된 코드에 대한 편집을 참조하십시오. – zhaider

관련 문제