2014-12-07 38 views
9

Ho una normale applicazione SpringBoot con filtro di autenticazione personalizzato che funziona normalmente.Eccezione quando si utilizza TestRestTemplate

Ma ho problemi con TestRestTemplate nel test di integrazione.

Vorrei controllare qui se l'utente con credenziali errate non può accedere. ma invece di ResponseEntity con 401 lo status ho avuto Eccezione:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: cannot retry due to server authentication, in streaming mode; nested exception is java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode 
    at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:228) 
    at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.read(MappingJackson2HttpMessageConverter.java:220) 
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:95) 
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:795) 
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:779) 
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:559) 
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:512) 
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:454) 
    at cz.angular.security.basic.rest.AuthorizeControllerTest.userWithWrongCreditials(AuthorizeControllerTest.java:64) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176) 
    at org.junit.runners.Suite.runChild(Suite.java:127) 
    at org.junit.runners.Suite.runChild(Suite.java:26) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 
Caused by: java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode 
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1280) 
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379) 
    at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:48) 
    at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33) 
    at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56) 
    at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50) 
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:552) 
    ... 42 more 

Internamente primavera getta org.springframework.security.authentication.BadCredentialsException ma nell'uso reale applicazione la sua tradotto in JSON risposta.

Quando si utilizza il ricciolo, ho ottenuto una risposta normale.

curl -H "Content-Type: application/json" -d '{"name":"user","password":"password-wrong"}' http://localhost:8080/login 
{"timestamp":"2014-12-07T10:07:27.166+0000","status":401,"error":"Unauthorized","exception":"org.springframework.security.authentication.BadCredentialsException","message":"Bad credentials","path":"/login"} 

Codice di prova è qui:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = Application.class) 
@WebAppConfiguration 
@IntegrationTest("server.port:9999") 
public class AuthorizeControllerTest { 

    public static final String LOCALHOST = "http://localhost:9999"; 

... 

    @Test 
    public void userWithWrongCreditials() throws Exception { 
    RestTemplate rest = new TestRestTemplate(); 

    Credentials credentials = new Credentials(); 
    credentials.setName("user"); 
    credentials.setPassword("password-wrong"); 

    ResponseEntity<Map> response = 
     rest.exchange(
     LOCALHOST + "/login", 
     HttpMethod.POST, 
     new HttpEntity<Credentials>(credentials), 
     Map.class); 

    assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); 
    } 
} 

intero progetto può essere visto nel repository

https://bitbucket.org/winsik/security-token-stackoverflow/

dove è possibile vedere entrambi i test di passaggio e la mancanza di uno in AuthorizeControllerTest.

Ho provato un sacco di cose come impostare il tipo di contenuto e così via, ma senza fortuna. Gradirei qualsiasi idea.

+0

funziona per me. Sei sicuro che sia il 'TestRestTemplate' di Spring Boot? –

+0

Sì, il suo TestRestTemplate da avvio a molla. Proverò a fornire il codice completo al più presto, forse c'è qualche problema nell'implementazione del filtro ma sono curioso del perché l'applicazione funzioni come previsto (restituisce 401 quando viene fornita una password errata) –

+0

@DaveSyer Ho modificato la domanda e ho aggiunto il repository con l'intero codice . https://bitbucket.org/winsik/security-token-stackoverflow/ Dove è possibile visualizzare sia i test di passaggio che quelli non funzionanti in AuthorizeControllerTest. –

risposta

17

È necessario che il client Apache HTTP sia in grado di gestire gli errori autonomamente con TestRestTemplate. Questo ha funzionato per me con il vostro progetto

<dependency> 
     <groupId>org.apache.httpcomponents</groupId> 
     <artifactId>httpclient</artifactId> 
     <scope>test</scope> 
    </dependency> 

(ho anche tolto i JUnit, Mockito e la primavera-test dipendenze duplicati.)

+0

Sì, funziona. Grazie mille, mi hai aiutato molto. Quindi, se ottengo correttamente httpclient avrà luogo di default httpClient in TestRestTemplate? –

+1

Ok, mi hai salvato il tempo. Molte grazie. Ma perché diavolo questo trucco risolve il problema ?! –

0

Non credo che Jackson saprà come convertire JSON in Object. Prova Map o qualcosa del genere?

+0

Nel test di login riuscito utilizzo l'oggetto UserInfo, che ovviamente funziona. Qui nel test di accesso sbagliato ho provato anche Map/LinkedHashMap/String, Object era il mio ultimo tentativo, ma il risultato è sempre lo stesso. –

+0

Forse dovresti aggiornare la domanda per essere più vicina a qualcosa che potrebbe funzionare (cioè usare 'Mappa' per tipo di risposta)? –

Problemi correlati