7

I am trying to reproduce the following curl command using Java:

curl -v -u user:pass http://myapp.com/api

This command returns some JSON data.

My buggy Java implementation is as follows:

@Test
public void callTest() {
    RestTemplate restTemplate = createRestTemplate("user", "pass");
    URI uri = new URI("http://myapp.com/api");
    String res = restTemplate.getForObject(uri, String.class);
}

private static RestTemplate createRestTemplate(String username, String password) {

    UsernamePasswordCredentials cred = new UsernamePasswordCredentials(username, password);
    BasicCredentialsProvider cp = new BasicCredentialsProvider();
    cp.setCredentials(AuthScope.ANY, cred);
    DefaultHttpClient client = new DefaultHttpClient();
    client.setCredentialsProvider(cp);
    ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client);

    RestTemplate restTemplate = new RestTemplate(factory);
    // set the media types properly
    return restTemplate;
}

Yet, when I execute the test, it returns a org.springframework.web.client.HttpClientErrorException: 401 Unauthorized exception.

When logging in DEBUG, I see no information about the authentication...

What am I doing wrong while setting the authentication credentials?

Jean Logeart
  • 52,687
  • 11
  • 83
  • 118

4 Answers4

13

Instantiating using

HttpClient client = new HttpClient();

doesn't exist anymore and class DefaultHttpClient is deprecated from HttpComponents HttpClient from version 4.3. So other answer are either invalid or deprecated. Here is my version, I wrote this class for rest requests which require basic authentication:

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public class RestClient extends RestTemplate {
    public RestClient(String username, String password) {
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope(null, -1),
                new UsernamePasswordCredentials(username, password));
        HttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
        setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
    }
}

Then use it like, for example:

RestClient restClient = new RestClient("username", "password");

String result = restClient.postForObject(...
Utku Özdemir
  • 7,390
  • 2
  • 52
  • 49
  • Thanks! The only one working (without using depreciated methods) on this page for me. – Nereis Dec 20 '13 at 15:47
  • 6
    Extending RestTemplate to do this is the wrong approach. Configure it to do what you need (in Spring XML or Java config), rather than subclassing it. – Ted Pennings Feb 17 '14 at 22:06
  • Nice example there, Good point made by @TedPennings.. thank you both. – Maximus Mar 27 '14 at 16:16
  • I was already creating a RestTemplate as needed, so I didn't need to subclass like this - I simply used the provided code to set my credentials. Good work. – Blamkin86 Jan 06 '15 at 21:01
  • I tried this implementation to POST to the Jenkins buildWithParameters URL for a particular job and it keeps failing with a 403 indicating that the operation did not work. Using the same URL, user, and password with curl and this works without a problem. Any clues as to why this is not working? – Hazok Jun 11 '15 at 01:55
1

I do something like this - and it has worked for me:

private RestTemplate createRestTemplate(String username, String password) {
    return new RestTemplate(this.createSecureTransport(username, password));
}

protected ClientHttpRequestFactory createSecureTransport(String username, String password){
    HttpClient client = new HttpClient();
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username,password);
    client.getState().setCredentials(AuthScope.ANY, credentials);
    CommonsClientHttpRequestFactory commons = new CommonsClientHttpRequestFactory(client);

    return commons;
}

It is used here: Reference Code

kevinpeterson
  • 1,150
  • 9
  • 15
  • That's with the old HTTPClient api. I use the 4.x, in which the CommonsClientHttpRequestFactory does not exist any more. – Jean Logeart Jan 18 '13 at 13:45
1

httpclient v4.0 not Support Preemptive authentication

Look this : http://forum.springsource.org/showthread.php?123385-Preemptive-Basic-Authentication-with-RestTemplate

In spring Source found this solution.

It works for me.

Look this : RestTemplate with Basic Auth in Spring 3.1

Community
  • 1
  • 1
Makoton
  • 443
  • 3
  • 14
  • None of the other answers worked for me. The only way I got it to work was using preemptive authentication. http://forum.spring.io/forum/spring-projects/web/114029-preemptive-basic-authentication-with-resttemplate – Jason Apr 23 '14 at 09:54
1

This answer is based on the one by @kevinpeterson, but with a rewrite to use the updated Apache HTTP Client.

RestTemplate createRestTemplate(String username, String password, String host, int port ) {
    return new RestTemplate(this.createSecureTransport( username, password, host, port ));
}

ClientHttpRequestFactory createSecureTransport( String username, String password, String host, int port ){
    DefaultHttpClient client = new DefaultHttpClient();
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( username, password );
    client.getCredentialsProvider().setCredentials( new AuthScope( host, port ), credentials );
    return new HttpComponentsClientHttpRequestFactory(client);
Alex
  • 855
  • 7
  • 21
  • At least with Spring Framework 3.2.3 and httpclient 4.2.3, I couldn't get this code above to work. I tried it with both specified AuthScope and AuthScope.ANY, but i think it won't work. The link from Makoton explains why and has a better solution. – java1337 Sep 12 '13 at 02:45
  • Don't know what issue you're experiencing, but I'm using this code successfully with Spring Framework 3.2.4 and httpclient 4.2.1. I doubt that the minor version differences are the problem, but who knows. – Alex Sep 12 '13 at 11:15