Basic Authentication using HTTP Commons Client

The_Lost_Avatar picture The_Lost_Avatar · Oct 30, 2013 · Viewed 13.8k times · Source

I am looking at this link an am trying to send requests to the server

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html

public class Test {
    public static void main(String[] args) throws ClientProtocolException, IOException {

        DefaultHttpClient httpClient;
        URL url = new URL("https://9.5.127.34:443");
        httpClient = getSSLHttpClient(url);
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope("https://9.5.127.34", AuthScope.ANY_PORT),
                new UsernamePasswordCredentials("root", "passw0rd"));


         httpClient.setCredentialsProvider(credsProvider);


        HttpGet httpget = new HttpGet("https://9.5.127.34/powervc/openstack/volume/v1/115e4ad38aef463e8f99991baad1f809//volumes/3627400b-cd98-46c7-a7e2-ebce587a0b05/restricted_metadata");
        HttpResponse response = httpClient.execute(httpget);
        BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String line = "";
        while ((line = rd.readLine()) != null) {

            System.out.println(line);

            }   
        }

But it is giving me error as

Authentication required

Please tell me what I am doing wrongly. Thanx in Advance

Answer

Roman Vottner picture Roman Vottner · Oct 30, 2013

Maybe you should try to send the authentication parameters preemptively like explained here: http://hc.apache.org/httpclient-legacy/authentication.html - but I'm not sure if this relates to your version.

Mat Mannion (@MatMannion) described probably a more common method, which should work with the current version: Preemptive Basic authentication with Apache HttpClient 4

Basically you just need to add a HTTP-header field containing the key: "authorization" and a base64 encoded string of the username and the password (combined together and then base64 encoded) or the way @Jonathan or @AdamBatkin presented it in the same thread (linked above)


@edit:

After having had a bit of spare-time I took your example code and throw it into Netbeans (yeah, I want to get a bit more familiar with NB) and built a simple jetty server demo which uses SSL and basic auth and an Apache HttpClient to invoke a simple hello world servlet to showcase how the client needs to define SSL and basic auth. Note further that some of the code was taken from the official docs and the keystore as well as the truststore are setup like explained here.

Below please find the complete code (except the keystores which are binary) of the project (maybe someone other might find it useful too).

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>at.rovo.test</groupId>
  <artifactId>HttpClientExample</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>HttpClientExample</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <!-- Client -->
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.3</version>
      <type>jar</type>
    </dependency>
    <!-- Server -->
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-server</artifactId>
      <version>9.1.0.M0</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-security</artifactId>
      <version>9.1.0.M0</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlet</artifactId>
      <version>9.1.0.M0</version>
      <type>jar</type>
    </dependency>
  </dependencies>
</project>

JettyServer.java

package at.rovo.test.httpclient;

import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.security.Constraint;

public class JettyServer 
{
    private String REALM;

    public static void main( String[] args ) throws Exception
    {
        new JettyServer();
    }

    public JettyServer() throws Exception
    {
        Server server = new Server(8080);
        server.addConnector(this.getSslChannelConnector(server));
        server.setStopAtShutdown(true);

        // create the context handler for the server        
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        context.setClassLoader(Thread.currentThread().getContextClassLoader());
        // attach the security handler to it that has basic authentication
        context.setSecurityHandler(this.getSecurityHandler());

        server.setHandler(context);
        // define the processing servlet
        context.addServlet(new ServletHolder(new ProcessingServlet()), "/process");

        server.start();
        server.join();
    }

    private Connector getSslChannelConnector(Server server)
    {
        try
        {           
            String keyStore = this.getClass().getResource("/serverKey.jks").toURI().getPath();

            SslConnectionFactory sslConnFactory = new SslConnectionFactory();
            sslConnFactory.getSslContextFactory().setKeyStorePath(keyStore);
            sslConnFactory.getSslContextFactory().setKeyStorePassword("keystorePW");
            sslConnFactory.getSslContextFactory().setKeyManagerPassword("jettyPW");

            HttpConfiguration config = new HttpConfiguration();
            ConnectionFactory connFactory = new HttpConnectionFactory(config);

            ServerConnector connector = new ServerConnector(server, sslConnFactory, connFactory);
            connector.setPort(8443);
            connector.setHost("localhost");
            connector.setIdleTimeout(30000);
            return connector;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    private SecurityHandler getSecurityHandler() throws Exception 
    {
        // add authentication
        Constraint constraint = new Constraint(Constraint.__BASIC_AUTH,"user");
        constraint.setAuthenticate(true);
        constraint.setRoles(new String[]{"user","admin"});

        // map the security constraint to the root path.
        ConstraintMapping cm = new ConstraintMapping();
        cm.setConstraint(constraint);
        cm.setPathSpec("/*");

        // create the security handler, set the authentication to Basic
        // and assign the realm.
        ConstraintSecurityHandler csh = new ConstraintSecurityHandler();
        csh.setAuthenticator(new BasicAuthenticator());
        csh.setRealmName(REALM);
        csh.addConstraintMapping(cm);

        // set the login service
        csh.setLoginService(getHashLoginService());

        return csh;
    }

    private HashLoginService getHashLoginService() throws Exception 
    {
        // load the authentication data from a simple property file
        HashLoginService hls = new HashLoginService();
        hls.setName(REALM);
        hls.setConfig(this.getClass().getResource("/realm.properties").toURI().toString());
        hls.setRefreshInterval(0);
        return hls;
    }
}

ProcessingServlet.java

package at.rovo.test.httpclient;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ProcessingServlet extends HttpServlet
{
    public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException 
    {
        response.setContentType("text/html");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().println("<h1>Hello World</h1>");
        response.getWriter().println("session=" + request.getSession(true).getId());
  }
}

realm.properties

admin: admin123, admin
root: passw0rd, user

Client.java

package at.rovo.test.httpclient;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class Client 
{
    public static void main(String[] args) throws Exception 
    {
        CloseableHttpClient httpClient;

        // SSL setup
        KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream instream = new FileInputStream(new File(Client.class.getResource("/clientTrust.jks").toURI()));
        try 
        {
            trustStore.load(instream, "truststorePW".toCharArray());
        } 
        finally 
        {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom()
                .loadTrustMaterial(trustStore)
                .build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);


        HttpHost targetHost = new HttpHost("localhost", 8443, "https");

        // Basic Auth setup
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                new UsernamePasswordCredentials("root", "passw0rd"));
        httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .setDefaultCredentialsProvider(credsProvider)
                .build();

        try
        {
            HttpGet httpget = new HttpGet("https://localhost:8443/process");

            System.out.println("executing request: " + httpget.getRequestLine());
            System.out.println("to target: " + targetHost);

            CloseableHttpResponse response = httpClient.execute(httpget);
            try
            {
                HttpEntity entity = response.getEntity();

                System.out.println("--------------------------------------------------");
                System.out.println(response.getStatusLine());
                if (entity != null)
                {
                    System.out.println("Response content length: "+entity.getContentLength());
                }
                BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                String line;
                while ((line = rd.readLine()) != null) 
                {
                    System.out.println(line);
                }
                EntityUtils.consume(entity);
            }
            finally
            {
                response.close();
            }
        }
        finally
        {
            httpClient.close();
        }
    }
}

Bear with me as I'm hardly checking for errors, but this is a quick&dirty example to demonstrate just the functionality of an SSL-secured Apache HttpClient that uses basic authentication.