首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么使用MockMVC MockMvc时检查失败

为什么使用MockMVC MockMvc时检查失败
EN

Stack Overflow用户
提问于 2020-12-23 02:28:45
回答 1查看 1.2K关注 0票数 0

对不起,信息过载了,我认为这里的信息比需要的多得多。

所以我有这个测试代码

代码语言:javascript
运行
复制
package com.myapp.ui.controller.user;

import static com.myapp.ui.controller.user.PasswordResetController.PASSWORD_RESET_PATH;
import static com.myapp.ui.controller.user.PasswordResetController.ResetPasswordAuthenticatedDto;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.MediaType;
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myapp.db.liquibase.LiquibaseService;
import com.myapp.sample.ModelBuilderFactory;

@ComponentScan( "com.myapp.ui")
@SpringJUnitWebConfig(  classes = { LiquibaseService.class, ControllerTestBaseConfig.class }  )
public class PasswordResetControllerTest  {

    @Autowired
    private ModelBuilderFactory mbf;

    private final ObjectMapper mapper = new ObjectMapper();
    private MockMvc mockMvc;
    private String username;

    @BeforeEach
    void setup( WebApplicationContext wac) throws Exception {
        username = mbf.siteUser().get().getUsername();
        this.mockMvc = MockMvcBuilders.webAppContextSetup( wac )
            .apply( SecurityMockMvcConfigurers.springSecurity() )
            .defaultRequest( get( "/" ).with( user(username) ) )
            .alwaysDo( print() )
            .build();
    }

    @ParameterizedTest
    @NullAndEmptySource
    @ValueSource(strings = "abcd")
    void testPasswordResetInvalidate( String password ) throws Exception {
        ResetPasswordAuthenticatedDto dto = new ResetPasswordAuthenticatedDto( username, password );

        RequestBuilder builder = MockMvcRequestBuilders.patch( PASSWORD_RESET_PATH )
            .contentType( MediaType.APPLICATION_JSON )
            .content( mapper.writer().writeValueAsString( dto ) );

        mockMvc.perform( builder )
            .andExpect( MockMvcResultMatchers.status().isNoContent() );
    }

}

这是相关的调试输出。

代码语言:javascript
运行
复制
[INFO ] PATCH /ui/authn/user/password-reset for user null (session 1, csrf f47a7f39-c310-4e5d-a4be-cc9bd120229f) with session cookie (null) will be validated against CSRF [main] com.myapp.config.MyCsrfRequestMatcher.matches(MyCsrfRequestMatcher.java:76) 
[DEBUG] Invalid CSRF token found for http://localhost/ui/authn/user/password-reset            [main] org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:127) 
[DEBUG] Starting new session (if required) and redirecting to '/login?error=timeout'          [main] org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy.onInvalidSessionDetected(SimpleRedirectInvalidSessionStrategy.java:49) 
[DEBUG] Redirecting to '/login?error=timeout'                                                 [main] org.springframework.security.web.DefaultRedirectStrategy.sendRedirect(DefaultRedirectStrategy.java:54) 
[DEBUG] Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@4b367665 [main] org.springframework.security.web.header.writers.HstsHeaderWriter.writeHeaders(HstsHeaderWriter.java:169) 
[DEBUG] SecurityContextHolder now cleared, as request processing completed                    [main] org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:119) 

MockHttpServletRequest:
      HTTP Method = PATCH
      Request URI = /ui/authn/user/password-reset
       Parameters = {}
          Headers = [Content-Type:"application/json", Content-Length:"68"]
             Body = <no character encoding set>
    Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@55b1156b, SPRING_SECURITY_CONTEXT=org.springframework.security.core.context.SecurityContextImpl@12919b87: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@12919b87: Principal: org.springframework.security.core.userdetails.User@1e05232c: Username: lab_admin4oyc8tkytxu4zllguk-1qg; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER}

Handler:
             Type = null

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 302
    Error message = null
          Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"SAMEORIGIN", Location:"/login?error=timeout"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = /login?error=timeout
          Cookies = []

java.lang.AssertionError: Status expected:<204> but was:<302>
Expected :204
Actual   :302

这是我们的相关SecurityConfig

代码语言:javascript
运行
复制
    @Override
    protected void configure( HttpSecurity http ) throws Exception {

        ApplicationContext ctx = getApplicationContext();
        http
            .addFilterAfter( ctx.getBean( TimeoutFilter.class ), SecurityContextPersistenceFilter.class )
            .addFilterAt( ctx.getBean( "myLogoutFilter", LogoutFilter.class ), LogoutFilter.class )
            .addFilterBefore( ctx.getBean( IpAddressAuditFilter.class ), FilterSecurityInterceptor.class )
            .addFilterAt( ctx.getBean( MyConcurrentSessionFilter.class ), ConcurrentSessionFilter.class )
            .addFilterAfter( ctx.getBean( RequestLogFilter.class ), FilterSecurityInterceptor.class )
            .headers().xssProtection().and().frameOptions().sameOrigin().and()
            .authorizeRequests()
            .antMatchers(
                HttpMethod.GET,
                "/styles/**.css",
                "/fonts/**",
                "/scripts/**.js",
                "/VAADIN/**",
                "/jsp/**",
                "/*.css",
                "/help/**",
                "/public/error/**"
            ).permitAll()
            .antMatchers( "/app/**", "/downloads/**", "/ui/authn/**" ).fullyAuthenticated()
            .antMatchers(
                "/login**",
                "/register/**",
                "/public/**",
                "/sso_logout",
                "/sso_auth_failure",
                "/sso_concurrent_session",
                "/sso_timeout"
            ).anonymous()
            .anyRequest().denyAll()
            .and()
            .formLogin()
            .loginPage( "/login" )
            .loginProcessingUrl( SecurityConstants.loginPath() )
            .defaultSuccessUrl( "/app", true )
            .failureUrl( "/login?error=badCredentials" )
            .usernameParameter( SecurityConstants.usernameField() )
            .passwordParameter( SecurityConstants.passwordField())
            .permitAll()
            .and()
            .exceptionHandling()
            .accessDeniedHandler( new MyAccessDeniedHandler() )
            .authenticationEntryPoint( new LoginUrlAuthenticationEntryPoint( "/login" ) )
            .and()
            .csrf().requireCsrfProtectionMatcher( csrfRequestMatcher )
            .and()
            .sessionManagement().sessionFixation().newSession().invalidSessionUrl( "/login?error=timeout" )
            .maximumSessions( 1 ).sessionRegistry( sessionRegistry )
            .expiredUrl( "/login?error=concurrentSession"  );
    }

测试重定向到timeout,因为它认为会话无效。

我们仅将spring引导父BOM用于依赖关系管理,但尚未转换为spring启动(WIP)。包括信息这样你就能知道我们的版本了。

代码语言:javascript
运行
复制
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.8.RELEASE</version>
    <relativePath />
  </parent>

考虑到我使用spring安全user()springSecurity()来设置MockMvc,我不知道为什么CSRF是不正确的。我将我的路径添加到我们在检查CSRF时排除的路径中,这个问题就消失了。我需要做什么才能拿到中央应急基金的支票?

EN

回答 1

Stack Overflow用户

发布于 2020-12-24 07:41:38

看起来您并没有为测试中的任何地方的请求生成CSRF令牌。日志确实显示您有一些CSRF令牌,但是如果您没有在请求中提供这样的令牌,CsrfFilter将创建您的令牌并将其与该令牌进行比较,我希望以您报告的方式失败。

您可以为mockMvc请求创建csrf令牌,方法是将SecurityMockMvcRequestPostProcessors.csrf()作为mockMvc.perform(builder).with( ... )的参数。

为了检查请求中是否有csrf令牌,我将通过调试器运行这个令牌,并放置一个断点在CsrfFilter的第120-123行周围

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65418290

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档