2016-06-27 15 views
0

Ich habe eine Feder-Controller, der auf einem authentifizierten GET aus „/ user“ die folgende JSON zurückgibt:Wie kann man auf ein CSRF-Token in einem Spring-Controller-Unit-Test zugreifen?

{"name":<name>,"token":<csrf-token>} 

Ich habe versucht, einen Komponententest für den Controller zu konstruieren, dass das zurückgegebene JSON enthält eine dynamically- überprüfen wird erzeugt CSRF-Token:

@Autowired 
private FilterChainProxy springSecurityFilterChain; 

private MockMvc mvc; 

@Before 
public void setUp() 
    throws Exception 
{ 
    ... 
    mvc = standaloneSetup(controller) 
     .apply(springSecurity(springSecurityFilterChain)) 
     .build(); 
} 

@Test 
public void getUser() 
    throws Exception 
{ 
    CsrfRequestPostProcessor csrfPostProcessor = null; 
    mvc.perform(get("/user").with(user(Const.USER)).with(csrfPostProcessor = csrf())) 
     .andExpect(status().isOk()) 
     .andExpect(content().json("{\"name\":\"" + Const.NAME + "\",\"token\":\"" + csrfPostProcessor.toString() + "\"}")); 
} 

Der Test schlägt fehl in dieser Richtung:

Failed tests: 
    ControllerTest.getUser:74 token 
Expected: org.springframework.security.test.web.servlet.reques[email protected]203c20cf 
    got: 565a95b0-d0bb-4376-a8a0-725a3b16a787 

gibt es eine Möglichkeit, dies und ich zu beheben Ist es nicht möglich, einen alternativen Test zu erstellen, der ein dynamisch generiertes CSRF-Token verwendet?

+0

das Generieren eines Tokens ist hier nutzlos, das Token ändert sich jedes Mal mit der neuen Anfrage an den Server. –

+0

Es ist nicht nutzlos. Der Controller gibt das dynamisch generierte Token für andere (nicht Spring-) Dienste während einer Sitzung zurück. Der Komponententest simuliert eine solche Sitzung. – user1408140

Antwort

0

Hier ist eine mögliche Lösung - einen benutzerdefinierten Matcher konstruieren, der die CSRF-Token in UUID4 Format ab:

private static Pattern CSRF_PATTERN = Pattern.compile("[\\da-f]{8}-[\\da-f]{4}-4[\\da-f]{3}-[\\da-f]{4}-[\\da-f]{12}"); 

public static Matcher<String> isCsrf(StringBuilder intercept) { 
    return new ArgumentMatcher<String>() { 
     @Override 
     public boolean matches(Object obj) { 
      // intercept may be null 
      Assert.isTrue(obj instanceof DefaultCsrfToken, "obj"); 

      String token = ((DefaultCsrfToken)obj).getToken(); 
      if (intercept != null) { 
       intercept.setLength(0); 
       intercept.append(token); 
      } 

      java.util.regex.Matcher matcher = CSRF_PATTERN.matcher(token); 
      return matcher.matches(); 
     }   
    }; 
} 

es dann wie folgt verwenden:

@Test 
public void getUser() 
    throws Exception 
{ 
    StringBuilder token = new StringBuilder(); 
    mvc.perform(get("/user").with(user(Const.USER)).with(csrf())) 
     .andExpect(status().isOk()) 
     .andExpect(request().attribute("_csrf", isCsrf(csrf))) 
     .andExpect(content().json("{\"name\":\"" + Const.NAME + "\",\"token\":\"" + token.toString() + "\"}")); 
} 

Als Bonus erhalten Sie ein CSRF-Token-Validator.