I have a method that returns a session. My goal is that it always should return a new session when the method is called. I have a web application and when I click on "Start" or "Send" then it always connects and sends a mail.
I have following cases:
- I connect() to a server, which needs my own custom truststore.
- If I connect to this server, I should select truststorename.jks from the dropdown box. And it should work. If I do not select my truststore, then an exception should be thrown.
- If I connect to another server, which doesnt need my own custom truststore, then I can select "None". So java takes the default configuration.
The exception that should be thrown is at the Transport.connect() method of javamail:
java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
The problem:
Now when I start or restart the webapplication - it works only for the first time.
So if I select my own truststore, it works with no exception. But then I select "Nothing" or "None" from the dropdown box but it still sends successfully instead of throwing an exception. So I think that the old session is still there and a new one will only be created when I redeploy the web-app. Maybe there is a conflict with the System-Properties? Or jetty?
private Session connect(SMTPTask task) {
log.debug("Connecting to SMTP");
Properties props = new Properties();
Properties systemProps = System.getProperties();
if (task.getKeyStorePath().contains("None")) {
systemProps.remove("javax.net.ssl.trustStore");
systemProps.remove("javax.net.ssl.trustStorePassword");
System.setProperties(systemProps);
props.remove("mail.smtp.ssl.socketFactory");
} else {
systemProps.put("javax.net.ssl.trustStore", "src/main/resources/stores/" + task.getKeyStorePath());
systemProps.put("javax.net.ssl.trustStorePassword", "changeit");
System.setProperties(systemProps);
SSLSocketFactory factory = null;
try {
SSLContext ctx;
KeyManagerFactory kmf;
KeyStore ks;
char[] passphrase = "changeit".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
URL resource = this.getClass().getResource("/stores/" + task.getKeyStorePath());
File file = new File(resource.toURI());
FileInputStream fis = new FileInputStream(file);
ks.load(fis, passphrase);
fis.close();
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, null);
factory = ctx.getSocketFactory();
props.put("mail.smtp.ssl.socketFactory", factory);
} catch (Exception e) {
log.error("Error with SSLFactory", e);
}
}
String host = task.getHost();
String port = String.valueOf(task.getPort());
props.put("mail.smtps.host", host);
props.put("mail.smtps.port", port);
props.put("mail.smtps.auth", "true");
props.put("mail.imaps.fetchsize", "22020096");
return Session.geInstance(props);
}
Somewhere else I do:
public void send() {
...
Session s = connect(task);
...
}
EDIT:
I am not trying to do it with MailSSLFactory:
private Session connect(SMTPTask task) {
...
try {
MailSSLSocketFactory factory = new MailSSLSocketFactory();
KeyManagerFactory kmf= KeyManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
char[] passphrase = "changeit".toCharArray();
URL resource = this.getClass().getResource("/stores/" + task.getKeyStorePath());
File file = new File(resource.toURI());
FileInputStream fis = new FileInputStream(file);
ks.load(fis, passphrase);
fis.close();
kmf.init(ks,passphrase);
factory.setKeyManagers(kmf.getKeyManagers());
factory.setTrustAllHosts(true);
props.put("mail.smtp.ssl.socketFactory", factory);
} catch (Exception e) {
log.error("Error with SSLFactory", e);
}
}
props.put("mail.smtps.host", host);
props.put("mail.smtps.port", port);
props.put("mail.smtps.auth", "true");
props.put("mail.imaps.fetchsize", "22020096");
return Session.getInstance(props);
}