On this page:
This page describes how to get web applications like JIRA and Confluence connecting to external servers over SSL, via the various SSL-wrapped protocols. For instance, you may want to:
- Refer to an
https://...URL in a Confluence macro. - Use an IMAPS server to retrieve mail in JIRA.
- Use SMTP over SSL (SMTPS) to send mail in JIRA.
- Connect to a LDAP directory over SSL.
- Set up Trusted Applications over SSL.
If you want to run JIRA itself over SSL, see Running JIRA over SSL or HTTPS.
Problem symptoms
Simply entering the 'https' URL, or specifying IMAPS in JIRA will result in odd java.net.ssl.* exceptions in the logs, for example:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:441)
at javax.mail.Service.connect(Service.java:233)
at javax.mail.Service.connect(Service.java:134)
....
The cause
The problem is that our webapp is now acting as a SSL client, and as a client, it needs to obtain and 'trust' the server's public key.
This is identical to what happens when you visit a https://... URL in a browser - the browser fetches the public key and (if not signed by a trusted agent) presents it to you for inspection. If you trust the key, the browser saves it, and uses it to encrypt all subsequent communication with the site. We need to emulate this process before our webapp can access https resources. |
The fix
Obtain the server's public key.
To quote Microsoft; "consult your system administrator". The public/private key pair will live somewhere on the server. The public key should be located and copied to the server hosting JIRA/Confluence. For example:
scp root@mail.yourcompany.com:/etc/ssl/certs/imapd.pem .
If you have openssl installed locally, the key can be retrieved with a command like:
jturner@teacup:~$ openssl s_client -connect imap.atlassian.com:imaps CONNECTED(00000003) depth=0 /C=AU/ST=NSW/L=Sydney/O=Atlassian/CN=imap.atlassian.com/emailAddress=info@atlassian.com ..... ..... Server certificate -----BEGIN CERTIFICATE----- MIICiTCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQQFADB/MQswCQYDVQQGEwJBVTEM MAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxEjAQBgNVBAoTCUF0bGFzc2lh bjEaMBgGA1UEAxMRY3ZzLmF0bGFzc2lhbi5jb20xITAfBgkqhkiG9w0BCQEWEmlu Zm9AYXRsYXNzaWFuLmNvbTAeFw0wNTA5MjMwNjUyNTNaFw0wNjA5MjMwNjUyNTNa MH8xCzAJBgNVBAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTES MBAGA1UEChMJQXRsYXNzaWFuMRowGAYDVQQDExFjdnMuYXRsYXNzaWFuLmNvbTEh MB8GCSqGSIb3DQEJARYSaW5mb0BhdGxhc3NpYW4uY29tMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDhwAgx/gDgKe9tBjUCj7JtVkwQSzj2Dq0PHiJu1AWUYWFW ivbBWaWSYbt/w9vIRSL8OlGVOLnlFOH5o7QIpIBZvd3xBMv6DxMijM86/hu8QTPt KcMuqBTGpu1T846SzNncj883wSE1hXxezCgEFCsqyC7dVX4l0Ay6zgzkt2wc3QID AQABoxUwEzARBglghkgBhvhCAQEEBAMCBkAwDQYJKoZIhvcNAQEEBQADgYEAJOgg O4brCcQa3IgONo8UmLcHo6Rq+Py6ZA3ueUegy/uyQ358JUeL4kktXuYL9gAPCuMc hsC1iyaOrWY/S9S67w2ZWqc+uYX9ophFHkxK1r3YiaiMpEzMyB12VWSrOITcR0LV 7NTWfxfPLUpkDbj+Mw/66QJkI0lqBvcKn3KXI74= -----END CERTIFICATE-----
Cut and paste the certificate (including BEGIN and END lines) into a local file (eg. imapd.pem).
Import the public key.
To do this, you need to use the keytool program that comes with the Java platform used to run JIRA.
The instructions in the remainder of this section assume you are using a JIRA installation installed from an 'archive' or the JIRA WAR distribution. If you installed JIRA using the automated 'Windows' or 'Linux' installers, please enter the jre\bin (or jre/bin) subdirectory of your JIRA Installation Directory when running the keytool command.
Assuming you are using a JIRA installation installed from an 'archive' or the JIRA WAR distribution, change directory to $JAVA_HOME/bin and then run the following:
jturner@teacup:~$ sudo keytool -import -alias mail.yourcompany.com -keystore $JAVA_HOME/jre/lib/security/cacerts -file imapd.pem Enter keystore password: changeit Owner: EMAILADDRESS=info@atlassian.com, CN=atlassian.com, O=Atlassian, L=Sydney, ST=NSW, C=AU Issuer: EMAILADDRESS=info@atlassian.com, CN=atlassian.com, O=Atlassian, L=Sydney, ST=NSW, C=AU Serial number: 0 Valid from: Fri Feb 11 14:09:05 EST 2005 until: Sat Feb 11 14:09:05 EST 2006 Certificate fingerprints: MD5: CB:AE:7D:5D:1A:08:06:77:93:3B:0F:53:BB:40:C0:D4 SHA1: 7C:02:44:0D:A9:8F:F9:FB:BB:7B:C6:F1:52:DE:CA:00:17:D9:3A:A0 Trust this certificate? [no]: yes Certificate was added to keystore
This will import the public key (imapd.pem) into Java's default keystore, and marks it as trusted.
On Windows the command is similar, eg.:
C:\Program Files\Java\jre1.6.0_05>bin\keytool -import -file c:\certs\imapd.pem -alias mail.yourcompany.com -keystore lib\security\cacerts
Enter keystore password:
Owner: CN=*.atlassian.com, OU=IT, O=ATLASSIAN SOFTWARE SYSTEMS PROPRIETARY LIMITED, L=Sydney, ST=NSW, C=au
Issuer: CN=DigiCert Global CA, OU=www.digicert.com, O=DigiCert Inc, C=US
Serial number: a2d7047dc5d47ba988c9685e1efb860
Valid from: Thu Jan 10 11:00:00 EST 2008 until: Fri Jan 14 10:59:59 EST 2011
Certificate fingerprints:
MD5: 9D:B4:9F:3D:0A:DE:6A:BD:BC:3D:95:BE:60:BD:70:02
SHA1: 67:C6:E9:C8:3F:F1:7A:3C:66:E2:CE:62:78:A1:66:84:35:5E:62:1E
Signature algorithm name: SHA1withRSA
Version: 3
.....
Trust this certificate? [no]: yes
Certificate was added to keystore
C:\Program Files\Java\jre1.6.0_05>
Restart the app server
Restart, and if everything is correct, your webapp should now connect to the SSL resource without problems.
Note: alternative keystore locations
Java will normally use a system-wide keystore in $JAVA_HOME/jre/lib/security/cacerts, but it is possible to use a different keystore by specifying a parameter, -Djavax.net.ssl.trustStore=/path/to/keystore, where '/path/to/keystore' is the absolute file path of the alternative keystore.
Setting this is not recommended, however, because if Java is told to use a custom keystore (eg. containing a self-signed certificate), then Java will not have access to the root certificates of signing authorities found in $JAVA_HOME/jre/lib/security/cacerts, and accessing most CA-signed SSL sites will fail. It is better to add new certificates (eg. self-signed) to the system-wide keystore (as above).
There is also a per-user truststore (~/.keystore -- at least on Linux), but its contents do not appear to be logically appended to those in the system-wide keystore; ie. it is entirely separate, and only used if one specifies -Djavax.net.ssl.trustStore=/home/<user>/.keystore. This has the same disadvantage described above with custom keystores, so the per-user truststore is best avoided.
Debugging
Problems are one of two forms:
- Java is not referring to the correct keystore.
- The keystore does not contain the certificate of the SSL service you're connecting to.
Using Java
The attached SSLPoke.class Java program (source) is useful for debugging. It simply connects to a SSL service, sends a byte of input, and watches the output. For instance, connecting to a local HTTPS server on port 443 (the HTTPS default) with a untrusted (self-signed) certificate:
jturner@psyche:~$ java SSLPoke localhost 443
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:285)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:191)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:954)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:123)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:511)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:449)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:817)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1029)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:621)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:73)
at SSLPoke.main(SSLPoke.java:28)
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:280)
... 15 more
and connecting to a CA-verified certificate:
jturner@psyche:~$ java SSLPoke mail.atlassian.com 443 Successfully connected jturner@psyche:~$
Similarly you would test port 636 to test LDAPS connections.
Make sure that the version of Java you are using is the same as that used in your production Java application. On Unix systems, 'ps -ef | grep java' will show the full command for Java processes. Check for the presence of a -Djavax.net.ssl.trustStore parameter. If -Djavax.net.ssl.trustStore is present in the command, this may well be the cause of your problems (see discussion above). You can verify whether the -Djavax.net.ssl.trustStore parameter is causing problems by running the SSLPoke test utility above with it, eg:
java -Djavax.net.ssl.trustStore=/my/custom/keystore SSLPoke localhost 443
If this fails (confirming the problem), the solution is to remove the -Djavax.net.ssl.trustStore parameter, import your custom keystore certificates into the main keystore with keytool -importkeystore -srckeystore /my/custom/keystore -destkeystore $JAVA_HOME/jre/lib/security/cacerts, and restart the application.
If you are sure the certificate is trusted and found by Java, and you are having low-level SSL problems, you can get debug information in the stdout logs by setting the -Djavax.net.debug=all property.
Using openssl
The openssl commands are very useful for debugging SSL problems. For instance, to print the server's certificate:
jturner@psyche:~$ openssl s_client -connect localhost:443 2>/dev/null CONNECTED(00000003) --- Certificate chain 0 s:/C=AU/ST=NSW/L=Sydney/O=Atlassian/OU=Support/CN=localhost/emailAddress=jeff@atlassian.com i:/C=AU/ST=NSW/L=Sydney/O=Atlassian/OU=Support/CN=localhost/emailAddress=jeff@atlassian.com --- Server certificate -----BEGIN CERTIFICATE----- MIICizCCAfQCCQCt7NSYJaxDETANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMC QVUxDDAKBgNVBAgTA05TVzEPMA0GA1UEBxMGU3lkbmV5MRIwEAYDVQQKEwlBdGxh c3NpYW4xEDAOBgNVBAsTB1N1cHBvcnQxEjAQBgNVBAMTCWxvY2FsaG9zdDEhMB8G CSqGSIb3DQEJARYSamVmZkBhdGxhc3NpYW4uY29tMB4XDTA4MDEwMzAwMTEzMVoX DTA4MDIwMjAwMTEzMVowgYkxCzAJBgNVBAYTAkFVMQwwCgYDVQQIEwNOU1cxDzAN BgNVBAcTBlN5ZG5leTESMBAGA1UEChMJQXRsYXNzaWFuMRAwDgYDVQQLEwdTdXBw b3J0MRIwEAYDVQQDEwlsb2NhbGhvc3QxITAfBgkqhkiG9w0BCQEWEmplZmZAYXRs YXNzaWFuLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApOEOBbKKj189 15w078TUsR68gOahr6KiXg3s2zOyVaFbAepTnvhgtzej/qOJ8ESU5quCNIeBALov PRyxUyySBLOV14i3vrhqugQLKeYUiCIehri2iRaU+/6FsX8kIgfSBIMu75uV0bnM 9A6t1zZizSdcP+1k2DzaIc8sXzkpJ2sCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCA jm1xW5DvCYvHCa76QIwmsEIxCvya2zEqiwhAYC9gLbuQ1kjFgpn17U9x2ltJ1jWE /5BQOeRk+cBaVVZJpfrKAUZoRczsNIQcaDs3JEUrZ6qBUxXheT8MijXhhhnKN0Fl CvOuhw5DsgtEa1MT3CWetf9XFD3K4NI5+X7ihehs9g== -----END CERTIFICATE----- subject=/C=AU/ST=NSW/L=Sydney/O=Atlassian/OU=Support/CN=localhost/emailAddress=jeff@atlassian.com issuer=/C=AU/ST=NSW/L=Sydney/O=Atlassian/OU=Support/CN=localhost/emailAddress=jeff@atlassian.com ---
(add -showcerts to print all the certificates in the chain)
save it to a local file:
jturner@psyche:~$ cat > localhost.pem -----BEGIN CERTIFICATE----- MIICizCCAfQCCQCt7NSYJaxDETANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMC QVUxDDAKBgNVBAgTA05TVzEPMA0GA1UEBxMGU3lkbmV5MRIwEAYDVQQKEwlBdGxh c3NpYW4xEDAOBgNVBAsTB1N1cHBvcnQxEjAQBgNVBAMTCWxvY2FsaG9zdDEhMB8G CSqGSIb3DQEJARYSamVmZkBhdGxhc3NpYW4uY29tMB4XDTA4MDEwMzAwMTEzMVoX DTA4MDIwMjAwMTEzMVowgYkxCzAJBgNVBAYTAkFVMQwwCgYDVQQIEwNOU1cxDzAN BgNVBAcTBlN5ZG5leTESMBAGA1UEChMJQXRsYXNzaWFuMRAwDgYDVQQLEwdTdXBw b3J0MRIwEAYDVQQDEwlsb2NhbGhvc3QxITAfBgkqhkiG9w0BCQEWEmplZmZAYXRs YXNzaWFuLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApOEOBbKKj189 15w078TUsR68gOahr6KiXg3s2zOyVaFbAepTnvhgtzej/qOJ8ESU5quCNIeBALov PRyxUyySBLOV14i3vrhqugQLKeYUiCIehri2iRaU+/6FsX8kIgfSBIMu75uV0bnM 9A6t1zZizSdcP+1k2DzaIc8sXzkpJ2sCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCA jm1xW5DvCYvHCa76QIwmsEIxCvya2zEqiwhAYC9gLbuQ1kjFgpn17U9x2ltJ1jWE /5BQOeRk+cBaVVZJpfrKAUZoRczsNIQcaDs3JEUrZ6qBUxXheT8MijXhhhnKN0Fl CvOuhw5DsgtEa1MT3CWetf9XFD3K4NI5+X7ihehs9g== -----END CERTIFICATE----- jturner@psyche:~$
We can now calculate the fingerprint of the certificate with openssl x509:
jturner@psyche:~$ openssl x509 -fingerprint -md5 -noout -in localhost.pem MD5 Fingerprint=29:37:D6:C3:03:B6:0B:29:76:55:B5:35:E0:BE:21:5C jturner@psyche:~$
and verify that this fingerprint matches what is in Java's keystore:
jturner@psyche:~$ keytool -keystore /usr/lib/jvm/java-6-sun/jre/lib/security/cacerts -list | grep -A2 localhost Enter keystore password: changeit localhost, 27/06/2008, trustedCertEntry, Certificate fingerprint (MD5): 29:37:D6:C3:03:B6:0B:29:76:55:B5:35:E0:BE:21:5C verisignclass3ca, 28/10/2003, trustedCertEntry, jturner@psyche:~$







10 Comments
Hide/Show CommentsJan 29, 2007
Immo Huneke
Another way to achieve the same result was posted by Andreas Sterbenz at http://blogs.sun.com/andreas/entry/no_more_unable_to_find
Oct 05, 2011
Anonymous
The information of the previous post has been removed. Any other place where I can find the information?
Sep 28, 2007
Brian Sanders
The issue I was attempting to resolve was using the {jiraissues} macro to link to the SSL port in Jira.
I had to set a few other parameters to get this working. Oh, and the property names are case-sensitive too! Here's an example:
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=/path/to/truststore.p12"
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStorePassword=truststore\$password"
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStoreType=pkcs12"
I decided to throw in something a little extra in the password because the password for our trust store contains a $ and setenv.sh will try to interpret it unless you escape it. I spent nearly an entire work day trying to figure this stuff out because I was also exploring the option of putting this info into server.xml but this is the ONLY way I could get it to work.
Feb 01, 2008
Igor Muratov
It works great with https if server does not require client's certificate. We use Subversion plugin and SVN with certificate-based authentification. JIRA has it's own certificate. I can't find any way to configure JIRA and/or Tomcat to use this certificate for client's purposes.
As I understand, the keystorage file does not hold private keys, but certificates only. That means Tomcat can't work as a SSL client when two-way authentification required. Is it correct?
Aug 20, 2008
Yves Martin
If you want to use client certificat authentication, you have to create a "CA" certificate and sign your client X.509 certificates with the CA - as described in the following IBM documentation: http://publib.boulder.ibm.com/infocenter/rpthelp/v7r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc/topics/tcreatecertopenssl.html\\
Then, you have to insert the CA in a "trust store" you configure on your SSL connector in Tomcat server.xml (in addition to the https SSL certificate keystore) with
Then you have to register your users (and roles) in Tomcat Realm so that it is able to grant access based on the "CN" from the user's X.509 certificate.
To do basic tests, you can use "tomcat-users.xml" with a line like
Hope this helps
Sep 05, 2008
Martin Cooper
New to Client certification - but looking at using for login method to do away with login/password so all 'login' controlled via client certs and no activity required of end user.
How does the solution above work / manifest - do users still have to login to JIRA via the login prompt or does this client authentication do this for them?
Or is this just to secure the connection?
cheers
Nov 10, 2011
Luther Hargrove
Try this article that I found: How to Configure SSL for JAVA and Tomcat
Feb 08, 2012
Del
In importing the key, the question "Enter keystore password:" is asked.
How do you discover the keystore password? This is the first time I've accessed the keystore and I don't recall setting a password for it.
Feb 08, 2012
Alex Holtz
Try a blank password.
Feb 08, 2012
Del
Thanks for the reply. No, that doesn't work, I get an error message saying the password must be at least 6 characters.
Add Comment