I've created a test for the creation of a new user:
private static String USERS_ENDPOINT = "http://localhost:8080/users/";
private static String GROUPS_ENDPOINT = "http://localhost:8080/groups/";
@Test
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
public void whenCreateAppUser() {
AppUser appUser = new AppUser();
appUser.setUsername("[email protected]");
appUser.setPassword("password");
// Throws java.net.HttpRetryException
template.postForEntity(USERS_ENDPOINT, appUser, AppUser.class);
ResponseEntity<AppUser> appUserResponse = template.getForEntity(USERS_ENDPOINT + "1/", AppUser.class);
assertEquals("Username is incorrect. AppUser not created?",
appUser.getUsername(), appUserResponse.getBody().getUsername());
}
However, for some reason I am getting:
Caused by: java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1692)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:55)
at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:49)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:735)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:700)
... 34 more
For the call
template.postForEntity(USERS_ENDPOINT, appUser, AppUser.class);
I actually don't know what I changed because this used to work for me. Any idea what causes this issue?
My WebSecurity
settings are:
@Override
public void configure(WebSecurity web) throws Exception {
final String[] SWAGGER_UI = {
"/swagger-resources/**",
"/swagger-ui.html",
"/v2/api-docs",
"/webjars/**"
};
web.ignoring().antMatchers("/pub/**", "/users")
.antMatchers(SWAGGER_UI);
}
Spring's RestTemplate
and Spring Boot's TestRestTemplate
will on JDK's internal HttpURLConnection
implementation by default, which fails to access the body of an HTTP-response with status 401 "Unauthorized".
A magical solution is to include Apache's HTTP Client into the classpath — e.g. with Maven:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
<scope>test</scope>
</dependency>
In this case, Spring (or Spring Boot) will use Apache's HTTP Client which doesn't face the problem.
See also: https://github.com/spring-projects/spring-security-oauth/issues/441#issuecomment-92033542
P.S. I've just fought the same problem :)
Using the HttpClient from the Apache HttpComponents Client library solved the issue for me.
To use the Apache HttpClient you have to configure your RestTemplate the following way:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestClientConfig {
@Bean
public RestTemplate restTemplate() {
var template = new RestTemplate();
template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
return template;
}
}
As answered in java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
an alternative is:
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
return requestFactory;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With