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に進むことができます。

@Before 
public void setUp() throws Exception { 
    mock = MockMvcBuilders.webAppContextSetup(wac).addFilters(springSecurityFilterChain).build();   
    MockHttpSession httpSession = new MockHttpSession(webAppContext.getServletContext(), UUID.randomUUID().toString()); 
} 

@Test 
public void test1(){ 
    mock.perform(get("/").session(mockSession)).perfor(); 
} 
+0

私はあなたが私に言ったことをしましたが、それはセッションから値を選んでいないようです。 404エラーが出ます。更新されたコードの編集をご覧ください。 – zhaider

関連する問題