Friday, May 31, 2013

Configuring Tomcat and SOAP client for one-way and two-way ssl



I will soon be testing the connectivity between two servers. Both involve self-signed certificates that are shared in one another's trust store. There are many details that factor in to a successful connection between two servers. If you're not using a CA certificate chain, you need to make sure that you have exported valid public certificates and then installed peer certificates in the server's trust chain. If signing is used, what ciphers are your servers configured to use? Are your certificates expired? Does the DN value match the domain of the server's involved (host-name verification). Again, there are many factors.

A pragmatic approach to testing the ssl connection between two servers is to execute a series of tests in building block fashion. First, just make sure that you and your peer servers have adjusted one another's firewalls to allow access. Do this first without mixing in certificates or ssl. If there are proxies involved (load balancing?), resolve any issues there too. I'm not sure if there are proxies that can simply pass the https request along to the next destination; it feels like there might be some security issues there. I have seen examples where the proxies handle the SSL and then package up the attributes (as environment variables?) and pass them along to secondary servers. Once the two peer servers can issue commands to one another (e.g., web service), you're ready for the next step.

One-way ssl can be thought of as a client verifying the server, but the server doesn't care didley-squat about who the client is.


  1. Client knocks on the server's door
  2. Server opens the door without asking who's there and hands them a copy of a key to their garage (their public key), waves goodbye, and closes the door
  3. Client opens the garage, drops off some boxes of clothes and grabs a soda from the outside fridge
  4. Client keeps Server's key on keychain for the next visit; no big deal if he loses it. He can always knock on the door again and get another copy from the Server
In order to carry out a 'one-way ssl' test, the server must extract their public key from their keystore and send it to the client. The client then imports the server's public key into his trust store (usually it is added to the keystore, as with Java Key Store files (JKS)). The server should not enforce client authentication (that comes later with '2-way ssl'); the client, however, should authenticate the server's certificate by verifying that his copy of the server's public key matches the one the server sends in response to the client's initial request. If that verification succeeds, the client has good reason to trust the server. Again, the server doesn't care who the client is; one may describe it as blind trust.The server  should care enough to match its certificate CN value with the domain name it is using. Most clients do a host-name verification as part of authenticating the server it wishes to connect to. If the client is not rejected (given that previous non-ssl tests were successful), and verifies the protocol used is https, then the 'one-way ssl' test should be deemed successful.

Two-way ssl involves two people who are more reserved. This server has a more cynical view on life and won't hand out keys to just any guy on the street.


  1. Client knocks on the server's door
  2. Server asks the Client for his name, driver's license and another form of photo id.
  3. He calls up the DMV to verify that there is such a person and that their license was issued from the DMV.
  4. He may check to see if the Client is on the list of people he is expecting to stop by if an appointment was made in the past
  5. If the Server doesn't trust the Client, he throws the Client's references out the mail slot in the front door; the door is certainly not opened.
  6. If the Server does trust the Client, he opens the door and gives him a key.
  7. Like with the other case, the Client then has access to designated rooms in the Server's house as the Server sees fit.
In order to carry out a 'two-way ssl' test, in addition to the steps taken in the 'one-way ssl' test, the client will also need to send his public certificate to the server. The server will then install the client's certificate in the server's trust store. The server should ensure that the client authentication option is turned on. In two steps, 1) the server authenticates the client first and then 2) the client authenticates the server. If the client doesn't trust the server, he can always walk away. Ever seen one of those browser warnings suggesting that the server you're connecting to may not be trustworthy? At that point, you may choose to make an exception and trust them anyway or you slam the door in the server's face.

In preparation for running these tests, I wanted to make sure what configuration changes need to be made for each test phase. I ran tests and pulled together the following matrix:


Green == "can access" and Red == "rejected". Some rejection takes place before the client is even out of the starting block. This could be due to the fact that you don't have any certificates and the server is asking for one. This often times shows itself as an ugly and cryptic error message displayed in your browser or an exception that is thrown by your client code. If the client has a public certificate to hand to the server, if upon evalation of the client's certificate the server finds it untrustworthy, the client can be rejected that way too. These tend to represent themselves as return codes 401 or 403.

Many of the colored boxes have reference numbers in them. I have collected some screen captures to provide some context for the test results in the matrix.

Server Configuration

Our server is using Apache CXF to manage our web service behavior, including authentication. Important components in this configuration are:

Apache Tomcat

  • server trust store includes client's public key (required for two-way ssl only)
  • tomcat/conf/server.xml
  • tomcat/libexec/conf/tomcat-users.xml
A server cannot establish an ssl-encrypted connection or handle https requests without a valid certificate in its keystore. If a CA authority chain is not used, a 'direct trust' must be established by including the client's public key in the server's trust store.

The Tomcat server must be listening on an ssl-enabled port. Whether to set clientAuth to 'true' or 'false' is determined by whether the server will use one-way ssl or two-way ssl.

If two-way ssl is configured, users will be authorized once they have been authenticated. A 'user' entry is made, associating the full DN value from a client certificate with a role. The role will then be used later on to determine if a user is authorized to access a resource.

Web Service Application

  • webapp/src/main/webapp/WEB-INF/web.xml (example)
The web.xml is used to configure a web application's behavior once it has been deployed to Tomcat. In our case, a security-constraint is defined to check the user's role (associated by Tomcat when the client is authenticated) with the resource being requested (in this case, all web service endpoints).

One-Way SSL (Server)

Our server can establish one-way ssl by:
  • web.xml: remove the security-constraint, login-config and security-role
  • server.xml: ensure that clientAuth="false"

Two-Way SSL (Server)

Our server can establish two-way ssl by:
  • web.xml: include the security-constraint, login-config and security-role
  • server.xml: ensure that clientAuth="false" (yes, still false; CXF is handling the authentication and authorization)
  • tomcat-users.xml: ensure the client's DN has been included in the list of authorized users and the correct role(s) has been applied. The DN must be identical to how it appears in the client's public certificate.

Client Configuration

Our test client also uses Apache CXF to interface with an Apache CXF-driven server, including authentication. Important components in this configuration are:

SOAP Client Application

  • client trust store includes servers's public key (for both one-way and two-way ssl)
  • ws-ucidm/src/main/java/xxx/xxx/idm/UCIDMServicesClient.java (snippet)
  • ws-ucidm/src/main/resources/ClientConfig.xml (example)
A client cannot communicate with a server that demands an ssl-encrypted connection or send https requests without obtaining a valid certificate from it's peer and including it in its keystore.  If a CA authority chain is not used, a 'direct trust' must be established by including the server's public key in the client's trust store.  Whether one-way or two-way ssl, a client must always have it's peer's certificate.

Apache CXF uses Spring xml configuration files to authenticate the server.  The client code pulls in this configuration file and automatically handles the ssl handshaking required to establish a secure connection.  I believe it also verifies the signature and handles the encryption/decryption of the SOAP body.  With the Spring xml configuration in place, the Java client need only include 4 lines of code to automatically handle encryption and signing for you.

One-Way SSL (Client)

The burden of determining one-way or two-way ssl lies primarily with the server.  In either case, the client code will need to include the server's public certificate in it's own trust store.  This means the client must have an unexpired certificate to go along with his trust store, although in the case of one-way ssl, the server won't even ask for the client's public certificate.

Two-Way SSL (Client)

The client must provide a public certificate to the server that is trusted by the server.  Now a particular certificate must be used, not just any one.

Surely there are lots of things that could go wrong in this test, factors that weren't even mentioned here. But I hope this overview provides enough to understand what's going on so that troubleshooting can be more easily accomplished.

Friday, May 3, 2013

Using DropZone with Cloudinary

My application requires an image manager. I wanted to find something with a small footprint and that is easy to understand and use. Here is what I have so far, using DropZone (js) and Cloudinary with my Ruby on Rails app:

See my Design Document for details.