Search code examples
javaproxyjira

Jira REST API with proxy (Java)


I would like to use the Jira REST Client API for Java in an application that needs to go through a proxy to access the desired Jira instance. Unfortunately I didn't find a way to set it when using the given factory from that library:

JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
String authentication = Base64.getEncoder().encodeToString("username:password".toBytes());
return factory.createWithAuthenticationHandler(URI.create(JIRA_URL), new BasicAuthenticationHandler(authentication));

How can we use the Jira API and set a proxy ?


Solution

  • The only solution I found on the internet was to set it with system parameters (see solution 1 below). Unfortunately that did not fit my requirements as in the company I work for, there are multiple proxies and depending on the service to call, it has to use another proxy configuration. In that case, I cannot set the system properties without destroying all calls to other services that would need another proxy.

    Nevertheless, I was able to find a way to set it by re-implementing some classes (see solution 2).

    Important limitation: the proxy server must not ask for credentials.

    1. Context

    Maybe as context before, I created a class containing proxy configuration:

    @Data
    @AllArgsConstructor
    public class ProxyConfiguration {
    
        public static final Pattern PROXY_PATTERN = Pattern.compile("(https?):\\/\\/(.*):(\\d+)");
    
        private String scheme;
        private String host;
        private Integer port;
    
        public static ProxyConfiguration fromPath(String path) {
            Matcher matcher = PROXY_PATTERN.matcher(path);
            if (matcher.find()) {
                return new ProxyConfiguration(matcher.group(1), matcher.group(2), toInt(matcher.group(3)));
            }
            return null;
        }
    
        public String getPath() {
            return scheme + "://" + host + ":" + port;
        }
    
    }
    
    1. Set system properties for proxy

    Call the following method with your proxy configuration at the start of the application or before using the Jira REST API:

    public static void configureProxy(ProxyConfiguration proxy) {
        if (proxy != null) {
            System.getProperties().setProperty("http.proxyHost", proxy.getHost());
            System.getProperties().setProperty("http.proxyPort", proxy.getPort().toString());
            System.getProperties().setProperty("https.proxyHost", proxy.getHost());
            System.getProperties().setProperty("https.proxyPort", proxy.getPort().toString());
        }
    }
    
    1. Re-implement AsynchronousHttpClientFactory

    Unfortunately, as this class has many private inner classes and methods, you will have to do an ugly copy paste and change the following code to give the wanted proxy configuration:

    public DisposableHttpClient createClient(URI serverUri, ProxyConfiguration proxy, AuthenticationHandler authenticationHandler) {
        HttpClientOptions options = new HttpClientOptions();
    
        if (proxy != null) {
            options.setProxyOptions(new ProxyOptions.ProxyOptionsBuilder()
                .withProxy(HTTP, new Host(proxy.getHost(), proxy.getPort()))
                .withProxy(HTTPS, new Host(proxy.getHost(), proxy.getPort()))
                .build());
        }
    
        DefaultHttpClientFactory<?> defaultHttpClientFactory = ...
    }
    

    You can then use it (in the following example, my re-implementation of AsynchronousHttpClientFactory is called AtlassianHttpClientFactory):

    URI url = URI.create(JIRA_URL);
    String authentication = Base64.getEncoder().encodeToString("username:password".toBytes());
    DisposableHttpClient client = new AtlassianHttpClientFactory().createClient(url, proxy, new BasicAuthenticationHandler(authentication));
    return new AsynchronousJiraRestClient(url, client);
    

    Note that after all those problems, I also decided to write a Jira client library supporting authentication, proxy, multiple HTTP clients and working asynchronously with CompletableFuture.