0

我要解决的问题是通过 Exchange 2007 SMTP 中继从我的 tomcat Web 应用程序发送电子邮件。

交换服务器没有安装有效的 SSL 证书,所以我试图推送我自己的 ssl 套接字工厂,它也接受无效的证书。

在堆栈溢出的帮助下,我找到了一个可以在简单测试程序中运行的解决方案,但在从正在运行的 Web 应用程序中执行时却不行(类加载问题)。

我目前的解释是 SocketFetcher 类的类加载器无法看到我的 webapp 的类,对吗?

我该如何解决这个限制?

只是为了好玩,我把我的工厂放在一个单独的 jar 中,并将它放在 tomcat lib 文件夹中,但仍然找不到。

我得到这个例外:

Caused by: java.lang.ClassNotFoundException: com.mypackage.MyTrustAllSslSocketFactory
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:104)
    at com.sun.mail.util.SocketFetcher.startTLS(SocketFetcher.java:247)
    ... 25 more

我这样推工厂:

Security.setProperty("ssl.SocketFactory.provider", MyTrustAllSslSocketFactory.class.getName());

我的自定义套接字工厂:

public class MyTrustAllSslSocketFactory extends SSLSocketFactory
{  
  private SSLSocketFactory    m_sslSocketFactory;

  public MyTrustAllSslSocketFactory() throws Exception
  {
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, new TrustManager[] { new TrustAllX509Manager() }, new SecureRandom());
    m_sslSocketFactory = sslContext.getSocketFactory();
  }

  @Override
  public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException
  {
    return m_sslSocketFactory.createSocket(s, host, port, autoClose);
  }

  @Override
  public String[] getDefaultCipherSuites()
  {
    return m_sslSocketFactory.getDefaultCipherSuites();
  }

  @Override
  public String[] getSupportedCipherSuites()
  {
    return m_sslSocketFactory.getSupportedCipherSuites();
  }

  @Override
  public Socket createSocket(String host, int port) throws IOException, UnknownHostException
  {
    return m_sslSocketFactory.createSocket(host, port);
  }

  @Override
  public Socket createSocket(InetAddress host, int port) throws IOException
  {
    return m_sslSocketFactory.createSocket(host, port);
  }

  @Override
  public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException
  {
    return m_sslSocketFactory.createSocket(host, port, localHost, localPort);
  }

  @Override
  public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException
  {
    return m_sslSocketFactory.createSocket(address, port, localAddress, localPort);
  }
}

和“信任所有人”经理:

public class TrustAllX509Manager implements X509TrustManager
{
  @Override
  public X509Certificate[] getAcceptedIssuers()
  {
    return null;
  }

  @Override
  public void checkClientTrusted(X509Certificate[] certs, String authType)
  {
    // nothing
  }

  @Override
  public void checkServerTrusted(X509Certificate[] certs, String authType)
  {
    // nothing
  }
}
4

2 回答 2

1

好的,一整天后,这是我当前的工作解决方案。它不安全,也不是特别便携,但对我来说已经足够了。

请注意,我正在控制 tomcat 和 java 版本,并且我的 webapp 是唯一在此 tomcat 实例中运行的应用程序。

SocketFactory originalSslSocketFactory = SSLSocketFactory.getDefault();

Field theFactoryField = SSLSocketFactory.class.getDeclaredField("theFactory");
theFactoryField.setAccessible(true);

try
{
  // doesn't work when running in webapp (class not found)
  //      Security.setProperty("ssl.SocketFactory.provider", TrustAllSslSocketFactory.class.getName());

  // temporarily replace the SSL socket factory. using reflection because there is no method SSLSocketFactory.setDefault
  theFactoryField.set(null, new TrustAllSslSocketFactory());

  [...] // send email (just in case you're interested, i use org.apache.tools.ant.taskdefs.email.EmailTask)
}
finally
{
  // restore original value
  theFactoryField.set(null, originalSslSocketFactory);
}
于 2013-02-28T15:22:44.630 回答
1

你让这变得不必要地复杂了。

一种更简单的方法是使用JavaMail 附带的com.sun.mail.util.MailSSLSocketFactory类。创建该类的一个实例,对其进行配置,并将其设置为 mail.smtps.ssl.socketFactory Session 属性(或 mail.smtp.ssl.socketFactory 属性,如果您只是使用“smtp”协议并启用STARTTLS 支持)。

于 2013-02-28T23:04:19.143 回答