Unit testing with Spring Security

后端 未结 11 2173
暖寄归人
暖寄归人 2020-11-29 15:19

My company has been evaluating Spring MVC to determine if we should use it in one of our next projects. So far I love what I\'ve seen, and right now I\'m taking a look at th

相关标签:
11条回答
  • 2020-11-29 15:57

    I would take a look at Spring's abstract test classes and mock objects which are talked about here. They provide a powerful way of auto-wiring your Spring managed objects making unit and integration testing easier.

    0 讨论(0)
  • 2020-11-29 15:59

    I asked the same question myself over here, and just posted an answer that I recently found. Short answer is: inject a SecurityContext, and refer to SecurityContextHolder only in your Spring config to obtain the SecurityContext

    0 讨论(0)
  • 2020-11-29 16:07

    Using a static in this case is the best way to write secure code.

    Yes, statics are generally bad - generally, but in this case, the static is what you want. Since the security context associates a Principal with the currently running thread, the most secure code would access the static from the thread as directly as possible. Hiding the access behind a wrapper class that is injected provides an attacker with more points to attack. They wouldn't need access to the code (which they would have a hard time changing if the jar was signed), they just need a way to override the configuration, which can be done at runtime or slipping some XML onto the classpath. Even using annotation injection would be overridable with external XML. Such XML could inject the running system with a rogue principal.

    0 讨论(0)
  • 2020-11-29 16:07

    General

    In the meantime (since version 3.2, in the year 2013, thanks to SEC-2298) the authentication can be injected into MVC methods using the annotation @AuthenticationPrincipal:

    @Controller
    class Controller {
      @RequestMapping("/somewhere")
      public void doStuff(@AuthenticationPrincipal UserDetails myUser) {
      }
    }
    

    Tests

    In your unit test you can obviously call this Method directly. In integration tests using org.springframework.test.web.servlet.MockMvc you can use org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user() to inject the user like this:

    mockMvc.perform(get("/somewhere").with(user(myUserDetails)));
    

    This will however just directly fill the SecurityContext. If you want to make sure that the user is loaded from a session in your test, you can use this:

    mockMvc.perform(get("/somewhere").with(sessionUser(myUserDetails)));
    /* ... */
    private static RequestPostProcessor sessionUser(final UserDetails userDetails) {
        return new RequestPostProcessor() {
            @Override
            public MockHttpServletRequest postProcessRequest(final MockHttpServletRequest request) {
                final SecurityContext securityContext = new SecurityContextImpl();
                securityContext.setAuthentication(
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities())
                );
                request.getSession().setAttribute(
                    HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext
                );
                return request;
            }
        };
    }
    
    0 讨论(0)
  • 2020-11-29 16:10

    Authentication is a property of a thread in server environment in the same way as it is a property of a process in OS. Having a bean instance for accessing authentication information would be inconvenient configuration and wiring overhead without any benefit.

    Regarding test authentication there are several ways how you can make your life easier. My favourite is to make a custom annotation @Authenticated and test execution listener, which manages it. Check DirtiesContextTestExecutionListener for inspiration.

    0 讨论(0)
提交回复
热议问题