Testing HTTPS Connections with Apache HttpClient 4.2

By | October 8, 2014

In this article I am going to show how to unit test a HTTPS endpoint using Apache HttpClient. In addition I will show how to set up a HTTPS endpoint using the Mule ESB as a mock HTTPS server.
The example in this article is limited to showing how the client will assert the identity of the server using a truststore. The server will not assert the identity of the client (mutual authentication).

Create the Example Project

I am going to develop the example project in Spring Tool Suite with the Anypoint Studio plug-in installed. The main reason for this is to be able to create a project with the appropriate Mule dependencies conveniently and quickly. If you are able to gather the necessary dependencies in some other way, feel free to use the IDE of your choice.
If you use the Anypoint Studio plug-in, you need at least one Mule runtime installed. I have used the 3.5.0 community edition runtime. Version 3.5.0 of Mule CE contains version 4.2 of the Apache HttpClient library, this is the version of HttpClient I chose.

Let’s get started by creating the example project:

  • In the File menu, select New and then Other.
    In the dialog that appears, select the Mule Project wizard.
  • In the Project Settings dialog, enter the name of the project and select the Mule runtime that the project will use. I will call my project “HTTPSUnitTestWithHTTPClient” and, as before, use the Mule 3.5.0 CE runtime.

We have now created the example project. Before we implement anything in this project, we are going to create the server keystore and the client truststore.

Create the Server Keystore

The server keystore is a file which contains the server’s private key. This key is used when clients negotiate a connection with the server to make it possible for clients to verify that the server it is connecting to is indeed the server that the client wants to connect to and not an imposter. In addition, HTTPS negotiation results in an encrypted connection enabling the exchange of information between client and server that is protected against eavesdropping.

To create the server keystore, I used the following commands from the terminal or command window:

After having issued the command, you will be asked a number of questions. Answer them as you desire. Below is how I answered the questions when creating my server keystore.

The result should be a file named “server_keystore.jks”.

Create the Client Truststore

The client truststore contain one or more entries for certificates that the client is expected to trust. When the client tries to connect to a server, the identity of the server is verified against the entries in the truststore.
To create the client truststore, I used the following two commands:

After having issued the second command, you will be asked whether to trust the certificate in the server.cert file. Answer yes to this question.
Now you should have a total of three files: “server_keystore.jks”, “client_truststore.jks” and “server.cert”. Copy the first two files to the “src/main/resources” of the example project we created earlier.

Create the Mock Server Configuration

In the example project there should be a file named “httpsunittestwithhttpclient.xml” in the “src/main/app” directory. Paste the following Mule configuration into this file:

If you are familiar with Mule configuration files, please feel free to skip the following explanation.
The above Mule configuration file contains:

  • A HTTPS connector named “HTTPSNoClientCert”.
    A Mule connector contains the configuration for a means of communication. In this case the communication use the basic protocol HTTPS with some timeout parameters and a keystore.
    In addition the connector has a null session handler configured on it which will prevent Mule from sending out Mule session information to clients.
  • A flow named “https-noclientcert-flow”.
    A Mule flow describes a potential path a message may travel.
  • The flow in turn contains an inbound endpoint.
    The inbound endpoint is a receiver for messages sent to the flow.
    As can be seen, the flow references the HTTPS connector mentioned earlier using the connector-ref attribute. The host and port attributes specifies the address and port at which the inbound endpoint will be listening for incoming messages.
  • After the inbound endpoint, the flow contains a test-component.
    Its purpose is to log received messages to the console.
  • Finally the flow contains a processor that sets the payload of the (outgoing) message.

We can test the mock HTTPS server by right-clicking on the Mule configuration file we just created and selecting Run As → Mule Application. Then open a browser, like Firefox, and enter the URL “https://localhost:8082/”.
There may be a warning about an untrusted certificate, but just confirm that you trust the certificate. Having done that, you should see a string like this in the browser window if everything works as expected:

Add a Log4J Configuration File

In order to be able to see what Mule logs, add the following file named “log4j.xml” in the “src/test/resources” directory in the example project:

Implement the Test

So far, we have only been preparing for the actual purpose of this article, namely the test showing how to connect to a server over HTTPS. The reason I prefer the Apache HttpClient to connect to the server over, for instance the Mule client API, is that it gives me more control over the request sent to the server and I also know that the response I receive in my test-code has not been altered in any way.
The test that connects to the mock server looks like this:

The code is fairly well commented, but I will despite this provide a brief analysis:

  • The test-class inherits from the class FunctionalTestCase.
    FunctionalTestCase is a base-class for tests that wants to start a Mule instance as part of the tests.
  • The method getConfigFiles returns the Mule configuration file(s) that are to be loaded into the Mule instance started as part of the tests.
    In this case it is the Mule configuration file containing the mock server.
  • The setUp method creates and configures an instance of the Apache HttpClient that uses a certain truststore to verify the identity of the server(s) it communicates with.
  • The test-method testSuccessfulConnection tests what is expected to be a successful connection attempt to the server.

Running the Test

If we now right-click the test-class in the IDE and selects Run As → JUnit Test, the test should pass and you should see, among other things, output similar to this in the console:

From the above, we can see that the request, with the HTTP header “test-header-name” having the value “test-header-value”, was received by the mock server. We can also see the response headers and the response payload, the latter which contains the same type of greeting string that we saw in the browser when testing the mock server.

Note that we can also see that the Apache HttpClient library was used to send the request to the server by looking for the “User-Agent” HTTP header which has the value “Apache-HttpClient/4.2 (java 1.5)”.

 

Leave a Reply

Your email address will not be published. Required fields are marked *