Thursday, 23 May 2024

How to Configure a Credential Provider in Apache HttpClient?

In this post, I am going to explain how to set a credential provider to http client.

Step 1: Define Authentication Scope instance.

HttpHost targetHost = new HttpHost("http", "localhost", 8080);
AuthScope authScope = new AuthScope(targetHost);

AuthScope in Apache HttpClient represents the scope of authentication, including the host, port, realm, and authentication scheme. It's used to determine which credentials to use for a particular request based on the target host and the authentication credentials available. In the provided code, it's initialized with just the target host, but you can customize it further based on your specific authentication requirements.

 

Step 2: Define CredentialsProvider instance.

private static CredentialsProvider provider() {
	final BasicCredentialsProvider provider = new BasicCredentialsProvider();
	provider.setCredentials(authScope, new UsernamePasswordCredentials(USERNAME, PASSWORD.toCharArray()));
	return provider;
}

The provided snippet defines a method named provider() that returns a CredentialsProvider object. Within the method, it initializes a BasicCredentialsProvider named provider. This BasicCredentialsProvider is responsible for managing credentials for authentication. It sets the credentials for a specific authentication scope (authScope) using a UsernamePasswordCredentials object, which takes a username and password as arguments.

 

Step 3: Define CredsInterceptor that set the request Authorizaiton header based on the configured credential providers.

class CredsInterceptor implements HttpRequestInterceptor {

    @Override
    public void process(HttpRequest request, EntityDetails entity, HttpContext context)
            throws HttpException, IOException {
        CredentialsProvider provider = HttpClientContext.adapt(context).getCredentialsProvider();

        if (provider == null) {
            return;
        }

        Credentials credentials = provider.getCredentials(authScope, context);

        if (credentials instanceof UsernamePasswordCredentials) {
            UsernamePasswordCredentials creds = (UsernamePasswordCredentials) credentials;
            String encodedCredentials = Base64.getEncoder()
                    .encodeToString((creds.getUserName() + ":" + new String(creds.getUserPassword()))
                            .getBytes(StandardCharsets.UTF_8));
            request.addHeader("Authorization", "Basic " + encodedCredentials);
        }
    }

}

The provided code defines a Java class named CredsInterceptor, which implements the HttpRequestInterceptor interface. This class is intended to intercept HTTP requests and add authentication credentials to the request headers. Within the process method, it first obtains the CredentialsProvider from the HttpContext. If no credentials provider is found, it returns early. If a credentials provider is available, it retrieves the credentials for the specified authentication scope from the provider. It then checks if the credentials are of type UsernamePasswordCredentials, and if so, it encodes the username and password using Base64 encoding and adds them to the request headers with the key "Authorization". This interceptor essentially injects basic authentication credentials into outgoing HTTP requests based on the provided credentials provider and authentication scope.

 

Step 4: Build the http client with the CredentialsProvider configured in step 2. 

CloseableHttpClient httpClient = HttpClients
.custom()
.addRequestInterceptorFirst(new CredsInterceptor())
.setDefaultCredentialsProvider(provider())
.build();

Find the below working application.

 

CredentialsProviderDemo.java

package com.sample.app.httpclient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.stream.Collectors;

import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpGet;
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.HttpClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpRequestInterceptor;
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
import org.apache.hc.core5.http.protocol.HttpContext;

public class CredentialsProviderDemo {

    private static HttpHost targetHost = new HttpHost("http", "localhost", 8080);
    private static AuthScope authScope = new AuthScope(targetHost);
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "password123";

    public static String inputStreamToString(InputStream inputStream, Charset charSet) throws IOException {

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charSet))) {
            return reader.lines().collect(Collectors.joining("\n"));
        }

    }

    private static class CredsInterceptor implements HttpRequestInterceptor {

        @Override
        public void process(HttpRequest request, EntityDetails entity, HttpContext context)
                throws HttpException, IOException {
            CredentialsProvider provider = HttpClientContext.adapt(context).getCredentialsProvider();

            if (provider == null) {
                return;
            }

            Credentials credentials = provider.getCredentials(authScope, context);

            if (credentials instanceof UsernamePasswordCredentials) {
                UsernamePasswordCredentials creds = (UsernamePasswordCredentials) credentials;
                String encodedCredentials = Base64.getEncoder()
                        .encodeToString((creds.getUserName() + ":" + new String(creds.getUserPassword()))
                                .getBytes(StandardCharsets.UTF_8));
                request.addHeader("Authorization", "Basic " + encodedCredentials);
            }
        }

    }

    private static CredentialsProvider provider() {
        final BasicCredentialsProvider provider = new BasicCredentialsProvider();
        provider.setCredentials(authScope, new UsernamePasswordCredentials(USERNAME, PASSWORD.toCharArray()));
        return provider;
    }

    public static void main(String[] args) throws Exception {

        HttpClientResponseHandler<Void> responseHandler = new HttpClientResponseHandler<Void>() {
            @Override
            public Void handleResponse(final ClassicHttpResponse response) throws IOException {

                System.out.println("Response code : " + response.getCode());

                HttpEntity httpEntity = response.getEntity();

                try (InputStream is = httpEntity.getContent()) {
                    String result = inputStreamToString(is, StandardCharsets.UTF_8);
                    System.out.println(result);
                }

                return null;

            }
        };

        String url = "http://localhost:8080/api/v1/basic-auth";

        try (CloseableHttpClient httpClient = HttpClients.custom().addRequestInterceptorFirst(new CredsInterceptor())
                .setDefaultCredentialsProvider(provider()).build();) {

            HttpGet httpGet = new HttpGet(url);
            httpClient.execute(httpGet, responseHandler);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}




 



 

Previous                                                    Next                                                    Home

No comments:

Post a Comment