RestTemplate and Proactive Basic Authentication

The Problem

Not that long ago we looked into how to use RestTemplate with http basic auth.

However, we might have some trouble with that code using the RestTemplate on some services. In particular, with services that anticipate proactive vs reactive authentication. The rest template does not send the Authentication header on the initial request, so if the service does not respond with a WWW-Authenticate header (as it should according to the HTTP spec) and the RestTemplate does not attempt to send the credentials after the initial response, then the call will simply fail on the intial 401 response.

The Solution

Fortunately, there is a solution: Tell the rest template to send the credentials on the initial request rather than waiting for a 401 with a WWW-Authenticate header.

The trick here is to override the request factory’s createHttpContext() method to take control over the HTTP context, and use this factory in constructing the RestTemplate. This code works, and uses the self-signed certificate that we set it up for in the previous post. You may of course restructure it to your taste…

public class BasicRequestFactory extends HttpComponentsClientHttpRequestFactory {

    public BasicRequestFactory(HttpClient httpClient) {
        super(httpClient);
    }

    @Override
    protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
        HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
        AuthCache authCache = new BasicAuthCache();
        BasicScheme basicAuth = new BasicScheme();
        authCache.put(targetHost, basicAuth);
        BasicHttpContext localContext = new BasicHttpContext();
        localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);
        return localContext;
    }

    private static HttpClient createSecureClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build();
        SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier());
        return HttpClientBuilder.create().setSSLSocketFactory(connectionFactory).build();
    }

    private static HttpClient createSecureClient(String username, String password) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build();
        SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier());
        return HttpClientBuilder.create().setSSLSocketFactory(connectionFactory).setDefaultCredentialsProvider(credentialsProvider).build();
    }

    public static RestTemplate createTemplate(String username, String password) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        RestTemplate template = new RestTemplate(new BasicRequestFactory(createSecureClient(username, password)));
        template.setErrorHandler(new NopResponseErrorHandler());
        return template;
    }

    public static RestTemplate createTemplate() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        RestTemplate template = new RestTemplate(new BasicRequestFactory(createSecureClient()));
        template.setErrorHandler(new NopResponseErrorHandler());
        return template;
    }

    private static class NopResponseErrorHandler implements ResponseErrorHandler {

        @Override
        public boolean hasError(ClientHttpResponse chr) throws IOException {
            return false;
        }

        @Override
        public void handleError(ClientHttpResponse chr) throws IOException {
        }
    }

}

Happy Authenticating!

Advertisements

Leave a comment

Filed under Software Engineering

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s