Question

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.

Was it helpful?

Solution 5

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.

OTHER TIPS

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:

  1. Spring 3.0, the CommonsClientHttpRequestFactory integrated with the now end of lifed HttpClient 3.x
  2. Spring 3.1 introduced support for the current HttpClient 4.x via HttpComponentsClientHttpRequestFactory (support added in the JIRA SPR-6180)
  3. Spring 4.0 introduced async support via the 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.

I have another solution to set basic authentication for customized rest template.

RestTemplate restTemplate = new RestTemplate();
    HttpHost proxy =null;
    RequestConfig config=null;
    String credentials = this.env.getProperty("uname") + ":" + this.env.getProperty("pwd");
    String encodedAuthorization = Base64.getEncoder().encodeToString(credentials.getBytes());

    Header header = new BasicHeader(HttpHeaders.AUTHORIZATION, "Basic " + encodedAuthorization);
    List<Header> headers = new ArrayList<>();
    headers.add(header);
    // if we need proxy
    if(Boolean.valueOf(env.getProperty("proxyFlag"))){
        proxy = new HttpHost(this.env.getProperty("proxyHost"), Integer.parseInt(env.getProperty("proxyPort")), "http");
        config= RequestConfig.custom().setProxy(proxy).build();
    }else{
        config= RequestConfig.custom().build();
    }


    CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config)
            .setDefaultHeaders(headers).build();

    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
    restTemplate.setRequestFactory(factory);

    return restTemplate;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top