I am currently working on integration of a third party application with our local reporting system. I would like to implement REST calls with basic authentication but facing issues in Spring 4.0.0. I have a simple solution what works nicely:
final RestTemplate restTemplate = new RestTemplate();
final String plainCreds = "username:password";
final byte[] plainCredsBytes = plainCreds.getBytes();
final byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
final String base64Creds = new String(base64CredsBytes);
final HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
final HttpEntity<String> request = new HttpEntity<String>(headers);
final ResponseEntity<MyDto> response = restTemplate.exchange("myUrl", HttpMethod.GET, request, MyDto.class);
final MyDto dot = response.getBody();
but wanted to rewrite this to use ClientHttpRequestFactory in the following way:
final RestTemplate restTemplate = new RestTemplate(createSecureTransport("username", "password"));
private ClientHttpRequestFactory createSecureTransport(final String username, final String password) {
final HttpClient client = new HttpClient();
final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
client.getState().setCredentials(new AuthScope(null, 9090, AuthScope.ANY_REALM), credentials);
return new CommonsClientHttpRequestFactory(client);
}
This code is not compiling as the CommonsClientHttpRequestFactory class not exists anymore in Spring 4.0.0. Do somebody know any alternative solution to this? I am quite new in this REST world therefore any help will be appreciated.
Now that everything is in place, the RestTemplate will be able to support the Basic Authentication scheme just by adding a BasicAuthorizationInterceptor: restTemplate. getInterceptors(). add( new BasicAuthorizationInterceptor("username", "password"));
To enable basic authentication in RestTemplate for outgoing rest requests, we shall configure CredentialsProvider into HttpClient API. This HttpClient will be used by RestTemplate to send HTTP requests to backend rest apis. In this example, we are creating a Junit test which invokes a basic auth secured rest api.
I know that this is an old question, but I was looking for the answer to this myself. You need to add a RestTemplate interceptor when configuring the RestTemplate. An example below in annotation configuration:
@Bean
public RestTemplate restTemplate() {
final RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(
new FormHttpMessageConverter(),
new StringHttpMessageConverter()
));
restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("client", "secret"));
return restTemplate;
}
Javadoc for BasicAuthorizationInterceptor.
I was stuck on this for a good few hours. Maybe it will help somebody out in the near future.
From http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/ with HttpClient 4.3 edits:
Both Spring 3.0 and 3.1 and now 4.x have very good support for the Apache HTTP libraries:
CommonsClientHttpRequestFactory
integrated with the now end of lifed HttpClient 3.x
HttpComponentsClientHttpRequestFactory
(support added in the JIRA SPR-6180)HttpComponentsAsyncClientHttpRequestFactory
Let’s start setting things up with HttpClient 4 and Spring 4.
The RestTemplate
will require an HTTP request factory – a factory that supports Basic Authentication – so far, so good. However, using the existing HttpComponentsClientHttpRequestFactory
directly will prove to be difficult, as the architecture of RestTemplate
was designed without good support for HttpContext
– an instrumental piece of the puzzle. And so we’ll need to subclass HttpComponentsClientHttpRequestFactory
and override the createHttpContext
method: (taken from soluvas-framework on GitHub)
package org.soluvas.commons.util;
import java.net.URI;
import javax.annotation.Nullable;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.protocol.HttpContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* From http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/
*
* <p>And with that, everything is in place – the {@link RestTemplate} will now be able to support the Basic Authentication scheme; a simple usage pattern would be:
*
* <pre>
* final AuthHttpComponentsClientHttpRequestFactory requestFactory = new AuthHttpComponentsClientHttpRequestFactory(
* httpClient, host, userName, password);
* final RestTemplate restTemplate = new RestTemplate(requestFactory);
* </pre>
*
* And the request:
*
* <pre>
* restTemplate.get("http://localhost:8080/spring-security-rest-template/api/foos/1", Foo.class);
* </pre>
*
* @author anton
*/
public class AuthHttpComponentsClientHttpRequestFactory extends
HttpComponentsClientHttpRequestFactory {
protected HttpHost host;
@Nullable
protected String userName;
@Nullable
protected String password;
public AuthHttpComponentsClientHttpRequestFactory(HttpHost host) {
this(host, null, null);
}
public AuthHttpComponentsClientHttpRequestFactory(HttpHost host, @Nullable String userName, @Nullable String password) {
super();
this.host = host;
this.userName = userName;
this.password = password;
}
public AuthHttpComponentsClientHttpRequestFactory(HttpClient httpClient, HttpHost host) {
this(httpClient, host, null, null);
}
public AuthHttpComponentsClientHttpRequestFactory(HttpClient httpClient, HttpHost host,
@Nullable String userName, @Nullable String password) {
super(httpClient);
this.host = host;
this.userName = userName;
this.password = password;
}
@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(host, basicAuth);
// Add AuthCache to the execution context
HttpClientContext localcontext = HttpClientContext.create();
localcontext.setAuthCache(authCache);
if (userName != null) {
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(host), new UsernamePasswordCredentials(userName, password));
localcontext.setCredentialsProvider(credsProvider);
}
return localcontext;
}
}
It is here – in the creation of the HttpContext
– that the basic authentication support is built in. As you can see, doing preemptive Basic Authentication with HttpClient 4.x is a bit of a burden: the authentication info is cached and the process of setting up this authentication cache is very manual and unintuitive.
And with that, everything is in place – the RestTemplate
will now be able to support the Basic Authentication scheme; a simple usage pattern would be:
final AuthHttpComponentsClientHttpRequestFactory requestFactory =
new AuthHttpComponentsClientHttpRequestFactory(
httpClient, host, userName, password);
final RestTemplate restTemplate = new RestTemplate(requestFactory);
And the request:
restTemplate.get(
"http://localhost:8080/spring-security-rest-template/api/foos/1",
Foo.class);
For an in depth discussion on how to secure the REST Service itself, check out this article.
Since Spring 4.3.1 there is a simplier way using BasicAuthorizationInterceptor
, which is also independent of underlying http client used in RestTemplate
.
The example that uses RestTemplateBuilder
from spring-boot to add BasicAuthorizationInterceptor
to RestTemplate
:
@Configuration
public class AppConfig {
@Bean
public RestTemplate myRestTemplate(RestTemplateBuilder builder) {
return builder
.rootUri("http://my.cool.domain/api/")
.basicAuthorization("login", "password")
.build();
}
}
This way any request sent using myRestTemplate
bean instance will include given basic authorization header. So be careful to not use the same RestTemplate
bean instance to send requests to foreign domains. The rootUri
is partially protects from this, but you can always pass the absolute URL when making the request using RestTemplate
instance, so be careful!
If you are not using spring-boot
, you can also manually add this interceptor to your RestTemplate
following this answer.
If you prefer simple over complex, then just set the header
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString("myuser:mypass".getBytes(Charset.forName("UTF-8"))));
HttpEntity<SomeBody> myRequest = new HttpEntity<>(mybody, headers);
restTemplate.postForEntity(someUrl, myRequest, null);
I'm sure there's some other Base64-library out there if the encoding that ships with the JDK is too verbose for you.
Why not check the Spring 4 APIs to see which classes implement the required interface, namely ClientHttpRequestFactory
?
As you'll see from the Javadoc, most likely you want HttpComponentsClientHttpRequestFactory
, which uses the client from Apache's HttpComponents, the successor to the old commons HttpClient
.
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