Warum erhielt ich eine Error 403 mit MockMvc und JUnit?
Ich habe eine spring mvc (3.2.5) - Anwendung mit spring security (3.2).
Konfiguriert habe SecurityConfig.class mit dieser Methode :
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/*").permitAll().and()
.formLogin().successHandler(successHandler)
.defaultSuccessUrl("/")
.failureHandler(failureHandler).failureUrl("/login?error=true")
.permitAll().and().logout()
.permitAll();
http.authorizeRequests().antMatchers("/resources/**").permitAll();
http.authorizeRequests().antMatchers("/welcome").permitAll();
http.authorizeRequests().antMatchers("/secure/*").authenticated();
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated();
}
Mit Spring security (3.2) habe ich CSRF aktiviert. Ich denke, es ist eine gute Idee, lassen Sie es aktiviert.
Mein controller SignInController enthält 2 Methoden mit params :
BEARBEITEN : hinzufügen action=
in params
@RequestMapping(value = "/signup")
public ModelAndView signup() {
boolean auth = SecurityContextHolder.getContext().getAuthentication() == null ? false
: SecurityContextHolder.getContext().getAuthentication()
.isAuthenticated()
&& (SecurityContextHolder.getContext()
.getAuthentication().getPrincipal() instanceof User);
ModelAndView result = null;
if (auth) {
result = new ModelAndView("redirect:" + "/");
} else {
UserForm user = new UserForm();
result = new ModelAndView("registration", "userForm", user);
}
return result;
}
@RequestMapping(value = "/register", params = "action=signup")
public ModelAndView registration(
@ModelAttribute(value = "userForm") @Valid UserForm userForm,
BindingResult result, HttpServletRequest request) {
if (result.hasErrors()) {
return new ModelAndView("registration");
}
Member member = profileFacade.registerNewUser(userForm);
return new ModelAndView("registration", "member", member);
}
@RequestMapping(value = "/register", params = "action=cancel")
public ModelAndView cancelRegistration() {
return new ModelAndView("redirect:" + "/");
}
und schließlich habe ich JUnit-test :
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { WebConfiguration.class,
JpaConfiguration.class, LoggingConfiguration.class,
SecurityConfig.class, DataSourceEmbeddedConfiguration.class,
DataSourceMySqlConfig.class, BaseValidatorConfiguration.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@ActiveProfiles("dev")
public class SignInControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private MockHttpSession session;
@Autowired
private MockHttpServletRequest request;
@Autowired
private FilterChainProxy springSecurityFilterChain;
private MockMvc mockMvc;
@Before
public void setUp() throws ServletException {
SecurityContextHolderAwareRequestFilter scharf = new SecurityContextHolderAwareRequestFilter();
scharf.afterPropertiesSet();
this.mockMvc = MockMvcBuilders
.webAppContextSetup(this.webApplicationContext)
.addFilters(springSecurityFilterChain).dispatchOptions(true).build();
SecurityContextHolder.getContext().setAuthentication(null);
}
@Test
public void signup() throws Exception {
mockMvc.perform(get("/signup")).andExpect(status().isOk())
.andExpect(model().attributeExists("userForm"));
}
@Test
@Transactional
@Rollback(true)
public void register() throws Exception {
UserForm form = new UserForm();
form.setEmail("[email protected]");
form.setUsername("aokije");
form.setPassword("klo,ksff");
form.setConfirmedPassword("klo,ksff");
mockMvc.perform(post("/register").param("action", "signup")).andExpect(status().isOk());
}
}
BEARBEITEN : update mockMvc.ausführen, denn es ist in Ordnung arbeiten mit http.csrf().disable()
im SecurityConfig.class
Test Anmeldung perfekt laufen, aber registrieren Rückkehr ein Fehler 403.
Ich habe versucht, eine Menge Dinge, aber ich bekam immer diese Fehlermeldung.
Wenn ich versuche http://localhost:8080/register?signup
im browser, es ist in Ordnung.
_BEARBEITEN_
Protokolle :
2014-02-13 22:00:14,695 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@52ee705c
2014-02-13 22:00:14,696 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@2412d28d
2014-02-13 22:00:14,697 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@4fbd397b
2014-02-13 22:00:14,697 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/logout']
2014-02-13 22:00:14,698 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@1008e323
2014-02-13 22:00:14,699 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/*']
2014-02-13 22:00:14,700 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/resources/**']
2014-02-13 22:00:14,700 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/welcome']
2014-02-13 22:00:14,700 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'authenticated', for Ant [pattern='/secure/*']
2014-02-13 22:00:14,701 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'hasRole('ROLE_ADMIN')', for Ant [pattern='/admin/**']
2014-02-13 22:00:14,701 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'authenticated', for org.springframework.security.web.util.matcher.AnyRequestMatcher@1
2014-02-13 22:00:14,703 [FilterSecurityInterceptor] afterPropertiesSet Validated configuration attributes
2014-02-13 22:00:14,704 [FilterSecurityInterceptor] afterPropertiesSet Validated configuration attributes
2014-02-13 22:00:14,734 [DefaultSecurityFilterChain] <init> Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@10174779, org.springframework.security.web.context.SecurityContextPersistenceFilter@68736a7e, org.springframework.security.web.header.HeaderWriterFilter@728e5d0d, org.springframework.security.web.csrf.CsrfFilter@6e7a918b, org.springframework.security.web.authentication.logout.LogoutFilter@430e85e7, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@55eda087, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@290c7ca, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6dd90afc, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@12eb6a0f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6855612f, org.springframework.security.web.session.SessionManagementFilter@410a11a2, org.springframework.security.web.access.ExceptionTranslationFilter@59e15580, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2257a0]
2014-02-13 22:00:14,859 [FilterChainProxy] doFilter /register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2014-02-13 22:00:14,863 [FilterChainProxy] doFilter /register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2014-02-13 22:00:14,863 [HttpSessionSecurityContextRepository] readSecurityContextFromSession HttpSession returned null object for SPRING_SECURITY_CONTEXT
2014-02-13 22:00:14,863 [HttpSessionSecurityContextRepository] loadContext No SecurityContext was available from the HttpSession: org.springframework.mock.web.MockHttpSession@4c4b529f. A new one will be created.
2014-02-13 22:00:14,864 [FilterChainProxy] doFilter /register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2014-02-13 22:00:14,865 [HstsHeaderWriter] writeHeaders Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5ab39e58
2014-02-13 22:00:14,865 [FilterChainProxy] doFilter /register at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2014-02-13 22:00:14,866 [CsrfFilter] doFilterInternal Invalid CSRF token found for http://localhost/register
2014-02-13 22:00:14,866 [HttpSessionSecurityContextRepository] saveContext SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2014-02-13 22:00:14,866 [SecurityContextPersistenceFilter] doFilter SecurityContextHolder now cleared, as request processing completed
Könnten Sie mir helfen ?
Vielen Dank
BEARBEITEN
Schließlich hatte ich einen Fehler in einer anderen Klasse (annotation). Ich fix mit dabei :
HttpSessionCsrfTokenRepository httpSessionCsrfTokenRepository = new HttpSessionCsrfTokenRepository();
CsrfToken csrfToken = httpSessionCsrfTokenRepository
.generateToken(request);
Map map = new HashMap();
map.put("userForm", form);
map.put("org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN",
csrfToken);
this.mockMvc
.perform(
post("/register")
.param("signup", "")
.param("_csrf", csrfToken.getToken())
.sessionAttrs(map)).andExpect(status().isOk());
Params csrf und sessionAttrs sind obligatorisch.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Post-requests müssen csrf-token Hinzugefügt werden, zu bilden. So müssen Sie es während des Tests, code: ("it works on my machine" :))
2. Sache: sind Sie sicher, dass die Registrierung" - Methode verarbeitet Ihre post-Anforderung? Nicht RequestMapping konfiguriert für "BEKOMMEN" standardmäßig? (Darf ich das hier falsch sein)
mockMvc.perform(post("/register").param("action", "signup").session(session).sessionAttr("_csrf", csrfToken)).andExpect( status().isOk());
ich erhielt die gleiche Fehlermeldung. Wenn ich deaktivieren Sie csrf-Angriffe mit http.csrf().disable() in meinem SecurityConfig, es ist in Ordnung, die (ohne .sessionAttr())Ich weiß, diese Frage ist schon ziemlich alt, aber dies ist eines der ersten Ergebnisse auf Google für einige Abfragen und ich glaube, dieser Ansatz ist viel besser, und es ist beschrieben auf Frühling.io-blog
1) Sie können Ihre
mockMvc
mit Spring Security support einfacher, so dass IhrsetUp()
bekommt viel kürzer:2) können Sie
org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf()
füllen Sie Ihre test-Anforderung mit den richtigen CSRF-token wie diese:http.csrf().disable()
im security config.@Autowired MockMvc mvc
und @WithMockUser auf Ihrem Test-Methode.