Question

I'm trying to perform an basic auth to the login-module which runs on my jboss using REST. I already found an StackOverflow topic which explains how to authenticate with credentials.

RESTEasy client framework authentication credentials

This does not work. Analysing the established connection with Wireshark I was not able to see an HTTP package with Authorization: Basic. After more research I found this article, http://docs.jboss.org/resteasy/docs/2.3.3.Final/userguide/html/RESTEasy_Client_Framework.html which describes how to append basic auth to ApacheHttpClient4Executor from resteasy.

// Configure HttpClient to authenticate preemptively
// by prepopulating the authentication data cache.

// 1. Create AuthCache instance
AuthCache authCache = new BasicAuthCache();

// 2. Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put("com.bluemonkeydiamond.sippycups", basicAuth);

// 3. Add AuthCache to the execution context
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

// 4. Create client executor and proxy
httpClient = new DefaultHttpClient();
ApacheHttpClient4Executor executor = new ApacheHttpClient4Executor(httpClient, localContext);
client = ProxyFactory.create(BookStoreService.class, url, executor);

But this does not work either. There is no description how to append username and passwort for basic auth to the construct. Why is that information not associated with any class from httpcomponent?

Was it helpful?

Solution 3

You can add a raw authorization header to your REST client by invoking .header(HttpHeaders.AUTHORIZATION, authHeader) in your client configuration. The credentials must be packed in authorization header in the format of "user:pass", encoded as base64 byte array and then appended to the string "Basic " which identifies basic auth.

This is the whole snippet (inspired by this post on baeldung)

    String auth = userName + ":" + password;
    byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("ISO-8859-1")));
    String authHeader = "Basic " + new String(encodedAuth);

    authToken = restClient.target(restApiUrl + loginPath)
            .request()
            .accept(MediaType.TEXT_PLAIN)
            .header(HttpHeaders.AUTHORIZATION, authHeader)
            .get(String.class);

This worked for me in a Resteasy client. For information, when testing this with wget I had to use the --auth-no-challenge flag.

OTHER TIPS

One can use org.jboss.resteasy.client.jaxrs.BasicAuthentication which is packaged with resteasy-client 3.x and is meant specifically for basic authentication.

Client client = ClientBuilder.newClient();    
ResteasyWebTarget resteasyWebTarget = (ResteasyWebTarget)client.target("http://mywebservice/rest/api");
resteasyWebTarget.register(new BasicAuthentication("username", "passwd"));

Consider the solution from Adam Bien:

You can attach an ClientRequestFilter to the RESTEasy Client, which adds the Authorization header to the request:

public class Authenticator implements ClientRequestFilter {

    private final String user;
    private final String password;

    public Authenticator(String user, String password) {
        this.user = user;
        this.password = password;
    }

    public void filter(ClientRequestContext requestContext) throws IOException {
        MultivaluedMap<String, Object> headers = requestContext.getHeaders();
        final String basicAuthentication = getBasicAuthentication();
        headers.add("Authorization", basicAuthentication);

    }

    private String getBasicAuthentication() {
        String token = this.user + ":" + this.password;
        try {
            return "Basic " +
                 DatatypeConverter.printBase64Binary(token.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException ex) {
            throw new IllegalStateException("Cannot encode with UTF-8", ex);
        }
    }
}

Client client = ClientBuilder.newClient()
                     .register(new Authenticator(user, password));

I recently upgraded to resteasy-client:4.0.0.Final to deal with some Jackson upgrade issues, and I noticed that setting headers seem to work differently (I was getting 401: Authorization Errors for every authenticated request that previously worked). I also couldn't find much documentation, (the 4.0.0.Final release is only a month old and has some dependency issues, if my experience is representative of the broader case).

The code previously injected headers into the ClientRequestContext:

public AddAuthHeadersRequestFilter(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        String token = username + ":" + password;
        String base64Token = Base64.encodeString(token);
        requestContext.getHeaders().add("Authorization", "Basic " + base64Token);
    }
}

then we set the filter on the ResteasyClient like so:

ResteasyClient client = new ResteasyClientBuilder()
            .sslContext(buildSSLContext())
            .hostnameVerifier(buildHostVerifier())
            .build();

client.register(new AddAuthHeadersRequestFilter(user, pass));

However, this appears not to set the HeaderDelegate, which is where headers are retrieved in 4.x(?) and possibly earlier versions.

The trick was to register that filter on the ResteasyWebTarget instead of the client in the 4.0.0.Final version (you may notice the clientBuilder works a little differently now too).

    ResteasyClient client = (ResteasyClient)ResteasyClientBuilder.newBuilder()
            .sslContext(buildSSLContext())
            .hostnameVerifier(buildHostVerifier())
            .build();

    ResteasyWebTarget target = client.target(url);

    target.register(new AddAuthHeadersRequestFilter(user, pass));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top