Package com.elastisys.scale.commons.net.http

Source Code of com.elastisys.scale.commons.net.http.AuthenticatedHttpRequester

package com.elastisys.scale.commons.net.http;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;

import org.apache.http.HttpStatus;
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.HttpUriRequest;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import com.elastisys.scale.commons.net.retryable.Requester;
import com.elastisys.scale.commons.net.ssl.BasicCredentials;
import com.elastisys.scale.commons.net.ssl.CertificateCredentials;

/**
* A {@link Requester} that, when executed, performs a HTTP request that is
* authenticated via Basic authentication and/or a client certificate.
*
*
*/
public class AuthenticatedHttpRequester implements
    Requester<HttpRequestResponse> {

  /** The type of key store used to store the client certificate key. */
  private static final String KEYSTORE_TYPE = "PKCS12";

  /** Username/password credentials for basic authentication. */
  private final BasicCredentials basicCredentials;
  /** Certificate credentials for certificate-based client authentication. */
  private final CertificateCredentials certificateCredentials;
  /** The HTTP request to send. */
  private final HttpUriRequest request;

  /**
   * Constructs a {@link AuthenticatedHttpRequester} with
   * {@link CertificateCredentials}.
   *
   * @param certificateCredentials
   *            Certificate credentials for certificate-based client
   *            authentication.
   * @param request
   *            The HTTP request to send.
   */
  public AuthenticatedHttpRequester(
      CertificateCredentials certificateCredentials,
      HttpUriRequest request) {
    this(null, certificateCredentials, request);
  }

  /**
   * Constructs a {@link AuthenticatedHttpRequester} with
   * {@link BasicCredentials}.
   *
   * @param basicCredentials
   *            Username/password credentials for basic authentication.
   * @param request
   *            The HTTP request to send.
   */
  public AuthenticatedHttpRequester(BasicCredentials basicCredentials,
      HttpUriRequest request) {
    this(basicCredentials, null, request);
  }

  /**
   * Constructs a {@link AuthenticatedHttpRequester} with
   * {@link BasicCredentials} and/or {@link CertificateCredentials}.
   *
   * @param basicCredentials
   *            Username/password credentials for basic authentication. May be
   *            <code>null</code> if {@link CertificateCredentials} are
   *            provided.
   * @param certificateCredentials
   *            Certificate credentials for certificate-based client
   *            authentication. May be <code>null</code> if
   *            {@link BasicCredentials} are provided.
   * @param request
   *            The HTTP request to send.
   */
  public AuthenticatedHttpRequester(BasicCredentials basicCredentials,
      CertificateCredentials certificateCredentials,
      HttpUriRequest request) {
    checkArgument((basicCredentials != null)
        || (certificateCredentials != null),
        "neither basic credentials nor certificate "
            + "credentials were provided");
    checkNotNull(request, "missing HTTP request");

    this.basicCredentials = basicCredentials;
    this.certificateCredentials = certificateCredentials;
    this.request = request;
  }

  /**
   * Prepares a http(s) client configured with {@link CertificateCredentials}
   * and/or {@link BasicCredentials}.
   *
   * @return
   * @throws CloudAdapterException
   */
  private CloseableHttpClient prepareAuthenticatingClient() throws Exception {
    // install host name verifier that always approves host names
    AllowAllHostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier();
    // for SSL requests we should accept self-signed host certificates
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    SSLContextBuilder sslContextBuilder = SSLContexts.custom()
        .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy());

    // first attempt to prepare a https client with certificate credentials
    if (this.certificateCredentials != null) {
      String keystorePath = this.certificateCredentials.getKeystorePath();
      String keystorePassword = this.certificateCredentials
          .getKeystorePassword();
      // fall back to keystore password if key password is missing
      String keyPassword = this.certificateCredentials.getKeyPassword()
          .or(keystorePassword);
      KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
      keyStore.load(new FileInputStream(keystorePath),
          keystorePassword.toCharArray());
      sslContextBuilder.loadKeyMaterial(keyStore,
          keyPassword.toCharArray());
    }

    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    if (this.basicCredentials != null) {
      String username = this.basicCredentials.getUsername();
      String password = this.basicCredentials.getPassword();
      credentialsProvider.setCredentials(AuthScope.ANY,
          new UsernamePasswordCredentials(username, password));
    }
    CloseableHttpClient httpclient = HttpClients.custom()
        .setDefaultCredentialsProvider(credentialsProvider)
        .setSslcontext(sslContextBuilder.build())
        .setHostnameVerifier(hostnameVerifier).build();
    return httpclient;
  }

  /**
   * Sends the HTTP request to the remote end-point and returns a
   * {@link HttpRequestResponse} object holding the response message status,
   * body, and headers.
   *
   * @return The received response.
   * @throws IOException
   *             If anything went wrong.
   */
  @Override
  public HttpRequestResponse call() throws IOException {
    CloseableHttpClient client;
    try {
      client = prepareAuthenticatingClient();
    } catch (Exception e) {
      throw new IOException(format(
          "failed to prepare http client for request (%s): %s",
          this.request, e.getMessage()), e);
    }

    try {
      CloseableHttpResponse httpResponse = null;
      try {
        httpResponse = client.execute(this.request);
      } catch (Exception e) {
        throw new IOException(format("failed to send request (%s): %s",
            this.request, e.getMessage()), e);
      }

      HttpRequestResponse response = new HttpRequestResponse(httpResponse);
      int responseCode = response.getStatusCode();
      String responseBody = response.getResponseBody();
      if (responseCode != HttpStatus.SC_OK) {
        throw new IOException(format(
            "error response received from remote endpoint "
                + "on request (%s): %s: %s", this.request,
            responseCode, responseBody));
      }
      return response;
    } finally {
      client.close();
    }
  }
}
TOP

Related Classes of com.elastisys.scale.commons.net.http.AuthenticatedHttpRequester

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.