Course – LS (cat=HTTP Client-Side)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

This article will show how to configure the Spring RestTemplate to consume a service secured with Digest Authentication.

Similar to Basic Authentication, once Digest auth is set in the template, the client will be able to go through the necessary security steps and get the information needed for the Authorization header:

Authorization: Digest 
    username="user1",
    realm="Custom Realm Name",
    nonce="MTM3NTYwOTA5NjU3OTo5YmIyMjgwNTFlMjdhMTA1MWM3OTMyMWYyNDY2MGFlZA==",
    uri="/spring-security-rest-basic-auth/api/bars/1", 
    ....

With this data, the server can correctly authenticate the request and return the 200 OK response.

2. Setup the RestTemplate

The RestTemplate needs to be declared as a bean in the Spring context – this is simple enough either in XML or plain Java, using the @Bean annotation:

import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.core5.http.HttpHost;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import com.baeldung.client.HttpComponentsClientHttpRequestFactoryDigestAuth;

@Configuration
public class ClientConfig {
    private static final String DEFAULT_USER = "user1";
    private static final String DEFAULT_PASS = "user1Pass";

    public ClientConfig() {
        super();
    }

    @Bean
    public RestTemplate restTemplate() {
        HttpHost host = new HttpHost("http", "localhost", 8080);
        CloseableHttpClient client = HttpClientBuilder.create().
          setDefaultCredentialsProvider(provider()).useSystemProperties().build();
        HttpComponentsClientHttpRequestFactory requestFactory =
          new HttpComponentsClientHttpRequestFactoryDigestAuth(host, client);

        return new RestTemplate(requestFactory);
    }

    private CredentialsProvider provider() {
        BasicCredentialsProvider provider = new BasicCredentialsProvider();
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS.toCharArray());
        //defining null and -1 it applies to any host and any port
        final AuthScope authScope = new AuthScope(null, -1);
        provider.setCredentials(authScope, credentials);
        return provider;
    }

}

Most of the configuration of the digest access mechanism is done in the custom implementation of the client http request factory injected into the template – HttpComponentsClientHttpRequestFactoryDigestAuth.

Note that we are now pre-configuring the template with the credentials that have access to the secured API.

3. Configure Digest Authentication

We are going to leverage the support introduced in Spring 3.1 for the current HttpClient 4.x – namely the HttpComponentsClientHttpRequestFactory – by extending and configuring it.

We’re mainly going to configure the HttpContext and hook up our custom logic for Digest Authentication:

import org.apache.hc.client5.http.auth.AuthCache;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
import org.apache.hc.client5.http.impl.auth.DigestScheme;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.BasicHttpContext;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

import java.net.URI;

public class HttpComponentsClientHttpRequestFactoryDigestAuth extends HttpComponentsClientHttpRequestFactory {
    HttpHost host;

    public HttpComponentsClientHttpRequestFactoryDigestAuth(final HttpHost host, final HttpClient httpClient) {
        super(httpClient);
        this.host = host;
    }

    //
    @Override
    protected HttpContext createHttpContext(final HttpMethod httpMethod, final URI uri) {
        return createHttpContext();
    }

    private HttpContext createHttpContext() {
        // Create AuthCache instance
        final AuthCache authCache = new BasicAuthCache();
        // Generate DIGEST scheme object, initialize it and add it to the local auth cache
        final DigestScheme digestAuth = new DigestScheme();
        // If we already know the realm name
        digestAuth.initPreemptive(new UsernamePasswordCredentials("user1", "user1Pass".toCharArray()),
                "", "Custom Realm Name");

        // digestAuth.overrideParamter("nonce", "MTM3NTU2OTU4MDAwNzoyYWI5YTQ5MTlhNzc5N2UxMGM5M2Y5M2ViOTc4ZmVhNg==");
        authCache.put(host, digestAuth);

        // Add AuthCache to the execution context
        final BasicHttpContext localcontext = new BasicHttpContext();
        localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
        return localcontext;
    }

}

Now, the RestTemplate can simply be injected and used in a test:

@Test
public void whenSecuredRestApiIsConsumed_then200OK() throws IOException {
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();
    HttpGet getMethod = new HttpGet("http://localhost:8082/spring-security-rest-basic-auth/api/bars/1");
    HttpResponse response = httpClient.execute(getMethod);
    System.out.println("HTTP Status of response: " + response.getCode());
}

To illustrate the full configuration process, this test also sets up the user credentials – user1 and user1Pass. This part should, of course, be done only once and outside the test itself.

4. Maven Dependencies

The required Maven Dependencies for the RestTemplate and the HttpClient library are:

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>6.1.2</version>
</dependency>

<dependency>
   <groupId>org.apache.httpcomponents.client5</groupId>
   <artifactId>httpclient5</artifactId>
   <version>5.3</version>
</dependency>

5. Conclusion

This tutorial showed how to set up and configure the Rest Template so that it can consume an application secured with Digest authentication. The REST API itself needs to be configured with the digest security mechanism.

The implementation can be found in the example GitHub project – this is a Maven-based project, so it should be easy to import and run as it is.

Course – LSS (cat=Security/Spring Security)

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security:

>> CHECK OUT THE COURSE
Course – LS (cat=HTTP Client-Side)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – Security (video) (cat=Security/Spring Security)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.