For a hackaton I wanted to read some files from our BitBucket server. I knew the URLs of the files, but there were some complications. First, you need to be authenticated. According to the documentation, the preferred way of authentication is HTTP Basic Authentication when authenticating over SSL. We are using an SSL connection, but with self-signed certificates.
When working with SSL, Java uses keystores and truststores. The difference between the two is that keystores store private keys, which are used by the server side, and truststores contain public keys, which are used by the client side. We have our own custom truststore, and we can tell the JVM to use that one by passing the following parameters:
This works when you only want to access sites using your custom truststore. As soon as you want to make a connection to public sites, this fails. By default you can only use one truststore at a time. If you want more, you have create some custom code.
Or you can use the Apache HttpClient.
HTTP Basic Authentication
There are a couple of ways to use Basic Authentication. For BitBucket we need to use Preemptive Basic Authentication, which means we need to configure a HttpClientContext.
The first thing we need to do is to setup the CredentialsProvider. This doesn’t need much explanation.
// Configure CredentialsProvider final CredentialsProvider provider = new BasicCredentialsProvider(); final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("username", "password"); provider.setCredentials(AuthScope.ANY, credentials);
Next we need to configure an AuthCache. We’re going to cache the authentication for a specific host.
// configure AuthCache final HttpHost targetHost = new HttpHost("host", PORT, "https"); final AuthCache authCache = new BasicAuthCache(); authCache.put(targetHost, new BasicScheme());
Last, we use the previous steps to configure our HttpClientContext
// configure HttpClientContext final HttpClientContext context = HttpClientContext.create(); context.setCredentialsProvider(provider); context.setAuthCache(authCache);
HttpClient with custom SSL context
Now it’s time to configure our HttpClient. We’re going to load our truststore specifically for this client. This means that other clients and connections will still use the default Java truststore.
SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial( new File(configuration.getTruststoreLocation()), configuration.getTruststorePassword().toCharArray() ).build(); SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext); return HttpClientBuilder.create() .setSSLSocketFactory(sslSocketFactory) .build();
Using the HttpClient to execute the request
Now that we have configured both the HttpClient and its context, executing a request also becomes easy. Note that we need to pass the context to the execute method.
final HttpGet request = new HttpGet(link); HttpResponse response = httpClient.execute(request, context); InputStream connectionDataStream = response.getEntity().getContent();