Kerberos User Impersonation on Tomcat With Apache HttpComponents

Datetime:2016-08-23 03:54:14          Topic: Tomcat           Share

If you are using Kerberos for single sign-on SSO and want to be able to make HTTP requests impersonating the end user to third party systems you can do this using the HttpClient that is part of the Apache HttpComponents project.

This was made possible using HttpComponents as of version 4.4. You will require the following libraries:

  • httpclient-4.4.jar
  • httpcore-4.4.jar
  • httpmime-4.4.jar
  • fluent-hc-4.4.jar

As well as their dependencies:

  • Commons Codec 1.9
  • Commons Logging 1.2
  • SLF4J 1.7.5

Firstly, you need to create an HttpClientBuilder. This is because the properties of the HttpClient are all final, so you must use a builder to configure everything before building the HttpClient object.

HttpClientBuilder clientBuilder = HttpClientBuilder.create();

Let's assume that this code is running within a servlet and that the request object was passed in as a parameter.

HttpServletRequest request

In the HttpServletRequest, we have the user principal of the current user, in the case of Tomcat this is a GenericPrincipal however the implementation of this is platform specific for each Application Server. For this reason, I have used reflection here so as not to have dependencies on platform-specific libraries. This class has a method getGssCredential which allows us to retrieve the credentials of the end user.

GSSCredential gssCredential = null; 
if (request != null) {
    final Principal princ = request.getUserPrincipal();
  try {  
  if (princ != null && Class.forName("org.apache.catalina.realm.GenericPrincipal").isAssignableFrom(princ.getClass())) {
        Method m = princ.getClass().getMethod("getGssCredential", null);
        if (m != null)
            gssCredential = (GSSCredential)m.invoke(princ, null);
    }
    } catch (ClassNotFoundException e) {
// Ignore, presumably the current Application Server implementation is different.
}
    CredentialsProvider cp = new BasicCredentialsProvider();
    cp.setCredentials(new AuthScope(host, -1, null), new KerberosCredentials(gssCredential));
    clientBuilder.setDefaultCredentialsProvider(cp);
}
HttpClient client = clientBuilder.build();

If the user allows delegation then the service principal of the server can ask for a Ticket Granting Service TGS ticket which allows it to send a ticket on behalf of the user encapsulating the users credentials within its own ticket.

Now if we create a credentials provider and set the credentials for the credentials provider to be those we have just retrieved, we can then specify this credentials provider to be the default to be used for the httpClient we are about to create.

We can then use this client quite simply in the following way for a simple HTTP GET.

String url = "http://www.mydomain.com/test";
method = new HttpGet();
method.setHeader("Accept", accept);
method.setURI(new URIBuilder(url).setCustomQuery(queryString).build());
response = client.execute(method);




About List