Configure Tomcat 8.0's SSL using XCA - java

I have recently discovered XCA tool to manage certificates, keys and so on related to cryptography or security (check it out here ).
So far, I've created a self-signed CA certificate, with which I've signed my server and client certificates:
Now, what I want to do is configure Tomcat with the exported files of XCA so as to make use of SSL:
<Connector
port="8443"
protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="true"
sslProtocol="TLSv1.2"
SSLVerifyClient="require"
SSLCipherSuite="ALL"
SSLCertificateFile="??"
SSLCertificateKeyFile="??"
SSLCertificateChainFile="??"
SSLCACertificateFile="??" />
So my question comes here: which files must I export and where to place them in the Tomcat Connector? (PEM, pem with certificate chain file, pem with all trusted certificates, pem with all certificates...).
Thanks for your help!
EDIT:
I've followed this tutorial to set all up (this guide is in spanish). I've tested it on Firefox, Chrome, Internet Explorer and Safari. The unique browser in which it's working is Firefox... I'm getting the following error: ERR_CERT_INVALID
I've realised what might be causing this issue... I've used sometimes SHA-1 alg to make these certificates. I'll repeat the process using another algorithm.
EDIT 2
After changing the hashing algorithm from SHA-1 to SHA-512, nothing has changed...
EDIT 3
It seems that Chrome, Internet Explorer or Safari are more strict than Firefox on terms of security. I've tried a client in Java which connects to my web service using HTTPS and works fine :).

Since you are using the APR connector, you are correct that you should be using PEM files (the other connectors use Java keystores). Just be aware that a "PEM file" just describes the file type and not its contents.
You will need two artifacts to get TLS configured:
The server's private key
The server's certificate
There are ways to configure these artifacts in a single file, but it's a bit easier to understand if you have each one in a separate file. It's somewhat traditional to have a file called [servername].key for the key and another file called [servername].crt for the certificate.
It will be easier to verify that TLS is configured properly first without using client certificates, so try that first and then add the client-cert configuration on top of that.
Now that you have these files, the SSL-related attribute values are somewhat obvious:
SSLCertificateFile="[servername].crt"
SSLCertificateKeyFile="[servername].key"
You will not need either of these attributes to be set to anything:
SSLCertificateChainFile
SSLCACertificateFile
Don't set the cipher suite to "ALL"... that will enable ciphers with essentially zero security. Try something like SSLCipherSuite="HIGH". You'll want to read online a bit about how to configure a decent set of cipher suites for a modern deployment.

Related

Why does my Java servlet filter not work over HTTPS?

Spring (Boot) here, although that shouldn't matter at all. I am trying to learn more about how HTTP/S proxies work and am building one to run locally on my machine. I wrote (and registered) a servlet filter that replaces the body of the HTTP response with a silly HTML message:
public class DummyFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
String html = "<html><head><title>Awesome!</title></head><body>Proxy is working!</body></html>";
httpServletResponse.writer.write(html);
httpServletResponse.writer.flush();
return;
}
#Override
public void destroy() {
}
}
I then run my Spring app, and change my browser's proxy settings to point to my app (localhost:8080).
I am now able to go to HTTP websites and see my dummy message ("Proxy is working!") as the HTML output. Success!!! However, I then went to Google's homepage, which apparently uses HTTPS, and the Google homepage rendered just fine.
So I changed my browser to also use my Spring app for proxying SSL (again, localhost:8080) and tried again. This time when I went to Google, my browser gave me an error stating that there was a problem with the connection. I assume this is because my stupid-simple proxy is causing problems with the SSL 'handshake' between the browser and the site requiring SSL (in this case, Google).
I know that using proxies over SSL is certainly possible, because (at the very least) the Charles Proxy can be configured to do this. Apparently, Charles operates by dynamically generating a cert for the site you are trying to access, based off its own root CA cert. Charles and the SSL site use the site's cert, and the communication between the browser and Charles uses Charles' cert.
But knowing that doesn't help me understand why my simple proxy is causing problems in SSL-land in the first place. What would I need to change in my code so that it could behave the same with HTTPS as it does with HTTP?
Update
I'm wondering if the following would work for me:
Create a self-signed wildcard cert for, say *.example.com (anything dot com)
Configure my Sring app to use this wildcart cert and to serve HTTPS from port 443 (HTTPS default)
Configure the browser's SSL proxy settings to point to localhost:443
Add my self-signed wildcard cert to my browser's trust store
Now when I go to any URL under https://example.com, the browser reaches out to my proxy, which serves it back the self-signed cert (which it now trusts), and the proxy can talk with the example.com site's actual cert just fine.
Would this, or something similar, fix my problem?
The problems indicated really are HTTP/S basic ones.
When directing your browser to use a proxy at the given address (localhost:8080), the browser is causing any subsequent HTTP call to the configured "proxy server" indicating to this "proxy" that it should execute a call on behalf of the calling browser to the original URL.
In your case the "proxy" really is returning a canned message and does not really try connecting to the original URL. (At least you did not tell anything about what your "Proxy Server" is going to do in order to contacting the originally targeted site.)
That would be the more material aspect of a proxy basic functionality.
In the case of connecting to a server using HTTPS, it is then important, how you did configured that proxy connection with your browser.
It would be possible to use a plain HTTP connection to the proxy and still request the proxy to using a HTTPS connection for the "external" call. (Such configuration, however, is not so much widespread, as the proxy need to e.g. carefully treat redirects. Also it would invalidate some gains of using HTTPS in the first place (at least on the communication segment from browser to proxy.)
Most likely your browser configuration used an HTTPS connection to the "proxy" (localhost:8080). Then the browser tried an HTTPS request and hit an error as the target "responded" with regular HTTP.
Configuring your proxy servlet to accepting HTTPS calls would "repair" that problem. (Form this, your steps from the "Update" edit will "solve" the errors.) However, you do not need to use port 443 at localhost. Any port will do. Just if you want to provide an HTTP and an HTTPS proxy at the same time do you need to allocate two ports (e.g. you could use 8080 for HTTP and 8081 for HTTPS).
Just to empachase: Seeing the "Proxy is working" message does not prove having a working proxy. It just proves that your browser does talk to your servlet. (As you do not read any header information, it is not different from just calling URL localhost:8080 directly.)
Beyond getting "contacted" a working proxy would need to take the request, analyze the headers passed in and react according to the standards (especially executing the requested "external" call and returning the results).
(Of course, you have read RFCs related to HTTP protocol (e.g. RFC7230)?)
You must create a HTTPS connector.
In order to create an HTTPS connector, you will need a few things; but most importantly, you will need to generate Certificate keystore that is used to encrypt and decrypt the SSL communication with the browser.
If you are using Unix or Mac, you can do it by running the following command:
$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA
On Windows, this could be achieved via the following code:
"%JAVA_HOME%\bin\keytool" -genkey -alias tomcat -keyalg RSA
During the creation of the keystore, you should enter the information that is appropriate to you, including passwords, name, and so on. For the purpose of Once the execution is complete, a newly generated keystore file will appear in your home directory under the name: .keystore.
Note
You can find more information about preparing the certificate keystore at tomcat.
With the keystore creation complete, you will need to create a separate properties file in order to store your configuration for the HTTPS connector, such as port and others. After that, you will create a configuration property binding object and use it to configure our new connector.
See this example of a prop file. you can cll it whatever name you want : tomcat.https.properties
custom.tomcat.https.port=8443
custom.tomcat.https.secure=true
custom.tomcat.https.scheme=https
custom.tomcat.https.ssl=true
custom.tomcat.https.keystore=${user.home}/.keystore
custom.tomcat.https.keystore-password=changeit
Don't need to change your code.You might be missing configuration.Check whether you configured ssl correctly .
Follow the steps to enable ssl in your spring app:
create Keystore file
keytool -genkey -alias tomcat -keyalg RSA
2.Configuring Tomcat for using the keystore file – SSL config
in your server.xml
Find the following declaration:
<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
-->
Uncomment it and modify it to look like the following:
Connector SSLEnabled="true" acceptCount="100" clientAuth="false"
disableUploadTimeout="true" enableLookups="false" maxThreads="25"
port="8443" keystoreFile="/Users/prashant/.keystore" keystorePass="password"
protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
secure="true" sslProtocol="TLS" />
3.Configuring your app to work with SSL (access through https://localhost:8443/yourApp)
add in your web.xml file of your application.
<security-constraint>
<web-resource-collection>
<web-resource-name>securedapp</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
It works for me with my custom filter.
Hope so it will help you..

Java Security Warning SSL Connection after server change

After a server change, I get nasty SSL warning in browsers (tested FF & Chrome), when loading an applet, used in an JavaEE Application (Serlvet API 3)
The warning says: "Certificate is not valid, and cannot used to identify the website"
The more detailed warning says: "The certificate authority, who provided the certificate, is not trusted." The messages are translated into english, so please excuse slight differences there. After this message, I get the message of Java, which shows that the Applet is ordinary signed (the dialog with the blue sign). So the Applet is working, only the warning message annoys.
Before I moved to another server, everything was fine and worked. No security warnings or anything else. The Applet is signed, by a certificate, which I requested from an CA. (rapidssl)
The old server environment was just a common web space, offered by 3rd party hoster. Now I moved to my own server, which utilizes XEN for hosting VMs. On one of that internal vm's, our webserver is deployed. According to that, I defined firewall rules to route traffic http/https to the vms.
Also the domain was ported, was purchased at old hoster, and the ip of new server is bound to domain.
I use Tomcat 7 as Application Server on an debian based OS.
In old environment, I could use the specified url in CN of my wildcard cert.(e.g. *.domain.com)
In new environment the basic message says: *.domain.com:port is not a trusted site.
I thought actually, that SSL Certs are independent of the used port. I've read that, on some research too. I also searched here in many threads, but the supposed answers didnt work for me.
The certificate and root cert. are imported to Java's own keystore cacerts. In Tomcat 7, I use the JSSE Implementation for SSL, with properly setup keystore files.
I've tried already this, but as im not that experienced with SSL/TLS Technology, the tried solutions maybe even wont solve my problem:
Disabling SNI in Tomcat 7 (dont work)
Adding Host aliases in server.xml (dont work)
Can anyone clarify, what the actual problem is, or has experienced the same issue ?
#edit: The are no error stacktraces in any logs, which I could provide here, also no exceptions gets thrown.
It came clear, thanks to Khanna111 Gaurav Khanna and jwv, that the certificate chain wasnt setup properly. I thought, if there were any problems with the certificate chain, that the browser will notify me about it. It isn't like that.
As we migrated from old hoster to new server, they provided only the certificates, but without the private key.
As im not that much experinced with SSL, I thought that importing the intermediary certs and the acquired cert is enough.. It is not :)
After stumbling on
intermediate-ca-certificate-in-java (link in comment), I've read this, which solved my problem: why doesn't java send the client certificate during SSL handshake? & external website:Import private key and certificate into Java Key Store (JKS)
I had certkey.key,publiccert.crt, intermediate_primary.cer and secondary_primary.cer Files.
The first step was, to convert the .key and .crt file to DER format, as mentioned in last link
via OpenSSL due to keytool's inability to import a key in an existing keystore
After converting to DER Format, I used the Tool ImportKey and created a new keystore with key/cert contained.
The second step was following the instructions of second link (Bruno's Answer), so it was copy&paste the certificate contents, into a single file. After importing the bundle of certificates into keystore, everything was fine.
I hope this can help anyone else, which is also not that familiar with SSL.
p.s. due to my lack of rep, i cannot mention all sites, I've used.. I'll provide them in comments

Do I Really Need to Import a SSL Cert into Java Keystore Manually?

I have a Java web app that has been running fine for several months. It integrates with the Box API (https://upload.box.com/api/2.0) to save files to the cloud service. Out of the blue, we started receiving the dreaded javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated exception while trying to make a REST API call to the Box web service.
There are tons of posts out there that tell you how to manually import the cert into your key store using the keytool utility. I understand that I can do this to fix the problem. But is this really the correct fix?
The fact that my application has been running fine for months leads me to believe something in the certificate at https://upload.box.com changed. Looking at the cert in my web browser, the certificate seems valid and was only renewed a few weeks ago. What is missing from my keystore?
Is it the Root CA certificate that is missing from my keystore? If that is the case, could I just copy the cacerts file from newer version of Java? My app is currently running JDK 1.6.0_33.
I am just trying to understand why this would suddenly stop working and what the "real" fix should be. It doesn't seem like modifying the JDK keystore is the correct thing to do.
I'll just assume you're using Apache HTTP Client 4.x, before 4.2.6, 4.3 Beta2, in which case javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated is most likely to come from a certificate that isn't trusted (otherwise it means the server didn't send a cert, which is a different problem, more details in this answer).
The current cert for server you're trying to access seems to have been issued on 07/04/2014, so this indicates that the certificate, and perhaps its chain has changed recently indeed.
I don't have a JDK 1.6.0_33 at hand, but it's possible that some of these CA certs were not part of the default bundle. In any case, it's worth updating cacerts, even on older JREs (if only to remove CA certs that should no longer be trusted, for example). The JSSE Reference Guide clearly states (admittedly in the middle of a fairly long document, but it's worth searching for "important note"...):
IMPORTANT NOTE: The JDK ships with a limited number of trusted root certificates in the <java-home>/lib/security/cacerts file. As documented in keytool, it is your responsibility to maintain (that is, add/remove) the certificates contained in this file if you use this file as a truststore.
Depending on the certificate configuration of the servers you contact, you may need to add additional root certificate(s). Obtain the needed specific root certificate(s) from the appropriate vendor.
If you can't upgrade your JRE (Java 6 is in general out of support), updating the cacerts file from a more recent version is certainly a sensible compromise.
Besides the various fixes in Java 7, Java 7+ would also allow you to connect to hosts that require SNI (although this doesn't seem to be the case for this particular host).

How do I create self signed certificates that two tomcats will be happy with when using https between the tomcats?

I am trying to use https between two tomcat servers. Unfortunately, the self-signed certificates are causing this error:
Caused by: 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
Specifically, I have a master tomcat and a number of slave tomcat servers. The master communicates from a servlet using a simple HttpURLConnection.
What is the simplest way for me to create self signed certificates using my own self generated Certificate Authority, such that every time I add a new server, I do not need to change the master tomcat server.
I have access to openssl and java 7 keytool
For reference my previous configuration:
The server.xml connector:
<Connector port="443" maxHttpHeaderSize="8192" maxThreads="150"
minSpareThreads="25" maxSpareThreads="75" enableLookups="false"
disableUploadTimeout="true" acceptCount="100" debug="0" scheme="https"
secure="true" clientAuth="false" sslProtocol="TLS" keystoreType="PKCS12"
keystoreFile="/usr/java/apache-tomee-plus/conf/keystore.ks"
keystorePass="XXX_SSL" truststoreType="JKS"
truststoreFile="/usr/java/apache-tomee-plus/conf/truststore.ks"
SSLEnabled="true" maxPostSize="0"/>
The startup script /etc/init.d/tomee
$DAEMON_HOME/jsvc \
-user $TOMCAT_USER \
-home $JAVA_HOME \
-pidfile $JSVC_PID_FILE \
-Dcatalina.home=$CATALINA_HOME \
-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.conf \
-Djavax.net.ssl.keystore=$CATALINA_HOME/conf/keystore.ks \
-Djavax.net.ssl.keyStorePassword=XXX_SSL \
-Djavax.net.ssl.trustStore=$CATALINA_HOME/conf/truststore.ks \
-Djavax.net.ssl.trustStorePassword=changeit \
-Djava.awt.headless=true \
-Djava.io.tmpdir=$TMP_DIR \
-Dopenam.agents.bootstrap.dir=/home/tomcat/tomcat_v6_agent/Agent_001/config \
-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses \
-outfile $CATALINA_HOME/logs/catalina.out \
-errfile $CATALINA_HOME/logs/catalina.err \
$CATALINA_OPTS \
-cp $CLASSPATH \
org.apache.catalina.startup.Bootstrap
conf/jaas.conf
josso {
org.josso.tc55.agent.jaas.SSOGatewayLoginModule required debug=true;
};
Which is there for legacy support only and will be phased out. I'm not sure it even loads since it is built for tomcat 5.5...
Within the code I am avoiding the problems of using IP addresses within the CN= by using the following HostnameVerifier().
HostnameVerifier hv = new HostnameVerifier()
{
public boolean verify(String urlHostName, SSLSession session)
{
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
connection = (HttpURLConnection) servlet.openConnection();
------------ Update ---------------
This has been solved by a lengthy discussion with #Bruno, please use his original post and the long chat discussion that we had.
In the end I used the tools Keytool Explorer and XCA to make it easier for me to learn and execute.
Firstly, you're not actually making server-to-server connections: these are still client-to-server connections. It just happens that your client is a webapp running within a servlet container.
It matters because it's the client trust settings that are going to be used to establish the connections. Those are different from the trust settings on the Tomcat connector.
How your client webapp uses its trust settings depends on how it's implemented and on which library it uses. It seems fair to say that most clients would use the default JRE settings, unless there is specific code to do otherwise. Without any settings, the JRE's cacerts file would normally be used (see details in JSSE Reference guide, customisation section). You can also specify the usual javax.net.ssl.* properties (using -Djavax.net.ssl....=....); this would need to be done in the catalina launch script file (.bat or .sh depending on the platform) in JAVA_OPTS. This will affect the default values running within this JRE instance, so it might not be your preferred choice (you might want something more specific that affects only a given webapp, but you'd need to know how that webapp is implemented or which possible options it can use). The settings in your <Connector .../> will override this, though (and the truststore settings there don't matter unless you want to use client-certificate authentication too).
If you have a number of systems, it's probably not worth using self-signed certificates: each client would need to import all these self-signed certificates into its trust store. Instead you can create your own CA and import only that CA certificate. (In a local deployment, a single top-level/root CA should be sufficient, without the need for intermediate CAs.) OpenSSL's CA.pl is a good script to build a small CA, but you may find other tools such as XCA or TinyCA more convenient. (Note that you can generally use .p12 files directly in Java, using the PKCS12 keystore type, instead of the default JKS. For PKCS#12 stores, the keystore password and the key/keymanager password are the same.)
Since you're using IP addresses instead of names, you should also be aware that Java follows RFC 2818 on IP address quite stricly (unlike many browsers). In particular, an IP address in the CN of your Subject DN will not work: it needs to be in a Subject Alternative Name extension (of type IPAddress, not DNSname).
EDIT:
First, get rid of that hostname verifier: it introduces a vulnerability to MITM attacks for all the HttpsURLConnection that will use that default verifier, including possible connections to external servers. You can fix this by using an IP address the SAN.
Here are the steps you need to follow:
Create your CA (e.g. with XCA). Export its certificate (not its private key) to mycacert.pem.
If your application is likely to make HTTPS connections to other services, copy the default cacerts file into a new file mytruststore.jks (if your application isn't making any other connection, don't copy the file, keytool will create it).
Import mycacert.pem into mytruststore.jks with keytool:
keytool -import -keystore mytruststore.jks -alias my_alias_name -cert mycacert.pem
You now have a truststore that you can install in all your clients that will need to talk to these servers. (You might need to perform these steps again if the cacerts file gets updated with the JRE.)
Configure that truststore in your clients. Here, this is done in your Catalina scripts in JAVA_OPTS: -Djavax.net.ssl.trustStore=... (and password). Besides the fact these JVM options are in the Catalina launch strict, they're the same as for other types of client.
Get rid of the -Djavax.net.ssl.keyStore=... there, this would only be used for client-certificate authentication, and it's not always a good idea to let the webapps use the certificate of the server within which they're running for client authentication.
Create a certificate with that CA for each server you want to use. Make sure you're using an IP-Address SAN if you want to use IP addresses. (Since you're in control of everything, XCA should allow you to generate the private key and certificate in one step, no need for CSR here, but you could if you wanted to. It also has prepared profiles for web server extensions, as well as the option to add Subject Alternative Names of type IP address or other.)
Export the combination of certificate and private key into a PKCS#12 (e.g. server1.p12) for each server. Each server should have its own, don't share them. You'll be able to use this as the "keystore keystore" in each server configuration.
Configure these keystores in each server in the connector configuration (keystoreType="PKCS12", and keyPass and keystorePass should be identical when using PKCS#12 stores).
You don't really need any truststore settings in your connector configuration unless you're using client-certificate authentication.
(It might be worth using client-certificate authentication to make sure the connections to your server at least only come from one other entity coming from that same CA, short of anything more precise, but the truststore you configure on the connector would need to contain only your CA certificate, not the others, so create a brand new truststore for that.)
To answer your question, I don't think that you need a chain of certificates. I already used tomcat with a self signed server certificate and connected to it with another self signed client certificate. I don't know about tomEE but I guess it would be the same.
To help you figure out what is goining on, I think about these possible debugging actions:
before going into automation, try to make things work without scripting. Generating the right configuration will than be easier.
make sure the script is running correctly: check if tje contents of the stores are as expected and make sure the server.xml files point to the right ones.
Try to test the servers separately using a browser client authentication if you can.
Above all, make sure you really need https between your servers. If you are in a protected realm, you are probably over using security and just slowing your application.
How do I create self signed certificates that two tomcats will be happy with when using https between the tomcats?
Tomcat must allow you to do one of two things. First is run a private PKI, or second is utilize a pinset.
The easier answer first: a pinset is a set of trusted certificates or public keys to identify a host or set of hosts. It's certificate or public key pinning with a multiplier. In this case, you want to take the 3 or 4 certificates and apply them to each server. Then, when peer's communicate, they will implicitly trust the peer's certificate.
It does not appear Tomcat (or IIS, or Apache) allow you to specify a pinset. That is, you cannot specify a collection of self-signed certificates to trust. So you'll have to use a private PKI.
The harder answer is to run a private PKI. There's nothing difficult about running a private PKI. The difficulty is in implementing it because there's a lot to it. There's no silver bullet to make it work because you need the private PKI and you need to configure your servers to use it.
For the question, "How do I use my own CA to sign each cert", see for example, How To Setup a CA or even Signing a certificate with my CA and Create my CA how to make a trusted self certified....
I can't help you with the configuration of Tomcat. But here are the steps to do it programmatically in OpenSSL if you were building a client and server. Here, "client" and "server" means the role the Tomcat server is taking (each takes both roles):
Client
call SSL_CTX_load_verify_locations with your CA
call SSL_CTX_set_default_verify_paths on the context
call SSL_CTX_set_verify with SSL_VERIFY_PEER
Server
call SSL_CTX_use_certificate_chain_file
call SSL_CTX_use_PrivateKey_file
call SSL_CTX_set_verify with SSL_VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT
When acting as a client, the Tomcat server needs to know the organization's trusted root. That's what SSL_CTX_load_verify_locations and SSL_CTX_set_default_verify_paths accomplish.
When acting as a client, SSL_CTX_set_verify ensures the Tomcat server verifies the peer's identify (modulo the lack of hostname checking in OpenSSL).
When acting as a server, the Tomcat server needs to know the certificate to send and the private key to sign with. That's what SSL_CTX_use_certificate_chain_file and SSL_CTX_use_PrivateKey_file do.
When acting as a server, the the Tomcat server wants mutual authentication. That's what SSL_CTX_set_verify with SSL_VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT does.
I don't know how to pound these into an Tomcat configuration, though.

HttpClient+SSL from Glassfish

I'm trying to download a simple page from an SSL secured webpage. I'm using HtmlUnit for that task (which wraps around HttpClient).
The webpage I'm trying to download has a proper certificate signed by Verisign and Verisign certificate is present in cacerts file (it was there in first place but I even reimported whole certiciate chain there).
My application runs perfectly as stand-alone application using the same JVM that is used by Glassfish. However if I deploy it to glassfish I'm getting a classic certificate problem exception:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated,
com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:339)
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:123)
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147)
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:597)
com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:133)
com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1405)
com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1324)
com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:303)
com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:385)
I've already tried disabling security manager in glassfish and that did not help.
What can be the cause of this weird behavior?
Thanks in advance.
I thought GlassFish used it's own magical keystore:
http://metro.java.net/guide/Configuring_Keystores_and_Truststores.html
Good luck!
If this is test or temporary code and you don't care to validate the certificate, try accepting all certs and host names. Using that SSLUtilities class:
SSLUtilities.trustAllHostnames();
SSLUtilities.trustAllHttpsCertificates();
You can import certificate chain into a truststore and set the following VM arguments:
-Djavax.net.ssl.trustStore="<path to truststore file>"
-Djavax.net.ssl.trustStorePassword="<passphrase for truststore>"
or override the truststore at runtime like:
System.setproperty("javax.net.ssl.trustStore","<path to truststore file>")
System.setproperty("javax.net.ssl.trustStorePassword","<passphrase for truststore>")
Keep in mind that both options will override default JVM truststore. So if you are hitting different sites with different certs, you may want to import all of them into one truststore.

Categories

Resources