I will try to provide more details about the question that my colleague @janis.baiza asked.
This is needed for our eazyBI app when used in Jira Data Center. In our case, all our application is implemented as a servlet and we need need to initialize it when the app (plugin) is enabled. Currently, the only way how we can achieve it (that we have figured out) is to make a local HTTP request to our servlet URL. Our plugin lifecycle onStart event handler schedules a job which will make the request to our servlet URL.
In a Jira Data Center environment, we need to make the request to the servlet URL on each individual node. If we will use a Jira Base URL then the front-end load balancer will route a request to just one node. Therefore we construct a URL http://127.0.0.1:{port}/{context}
where port
is a local port on which Jira Tomcat is listening. During the Data Center AppWeek with a help from Atlassians we got a solution how to find a local port on which Tomcat is listening. Here is a shortened code without error handling:
MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("Catalina:type=Manager,*"), null);
ObjectName objectName = objectNames.iterator().next();
String context = objectName.getKeyProperty("context");
objectNames = beanServer.queryNames(
new ObjectName("*:type=Connector,*"),
Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"))
);
objectName = objectNames.iterator().next();
String port = objectName.getKeyProperty("port");
String baseUrl = "http://127.0.0.1:" + port + context;
if (baseUrl.charAt(baseUrl.length() - 1) == '/') {
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
}
We identified a customer who has set up HTTPS also for the Tomcat server (so it means that the front-end web server proxies the incoming connections using HTTPS to the back-end Jira Tomcat server). Therefore now we have added that if the servlet URL request fails with NoHttpResponseException
then we retry the request with HTTPS using the https://127.0.0.1:{port}/{context}
prefix. As we are making the request to 127.0.0.1
, but the SSL certificate uses a different hostname, then our HTTPS request was failing with a certificate validation error.
So the solution that we have found as referred in the original question is to disable SSL certificate validation for a short time when we make this request. Here is a shortened code without error handling:
SSLSocketFactory currentSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
HostnameVerifier currentHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
// Create all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting trust manager
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
URL url = new URL(pluginUrl);
URLConnection con = url.openConnection();
// We can restore default values as they used only for creating a connection
HttpsURLConnection.setDefaultSSLSocketFactory(currentSSLSocketFactory);
HttpsURLConnection.setDefaultHostnameVerifier(currentHostnameVerifier);
con.getContent();
This solution disables SSL certificate validation for a short time (should be less than a second) during the plugin initialization for all JVM instance while the connection to the localhost is established.
Therefore we are interested if there is another way how to make an HTTPS request to localhost without SSL certificate validation during the plugin initialization?
P.S. In general, it would be good if there would be a Jira Server API for making local REST API requests to localhost and avoiding network layer overhead. For example, sometimes we have identified problems that when we make a request from Jira Server to the canonical Jira Base URL (which is going to the front-end web server) then either DNS is providing wrong IP address (when servers have different public or private IP addresses) or a firewall is blocking requests from Jira Server to the fron-end web server / load balancer.
We need to use local REST API requests also for accessing either some Jira data (for which there is no Java public API and only a REST API) or for accessing REST APIs provided by other Jira apps.
Kind regards,
Raimonds