解决Jenkins邮箱配置中,使用SSL连接的问题
背景:最近在配置Jenkins的邮件发送功能时,正确设置好各参数后,在进行通过发送测试邮件测试配置时,总是出现unable to find valid certification path to requested target的错误,自己在网上也查找了很多资料,但网上涉及Jenkins邮箱的配置资料基本上是qq、163邮箱等,总之该问题困扰了自己很久,现将解决方案给出,希望对后续的其他人有较好的
背景:最近在配置Jenkins的邮件发送功能时,正确设置好各参数后,在进行通过发送测试邮件测试配置时,总是出现unable to find valid certification path to requested target的错误,自己在网上也查找了很多资料,但网上涉及Jenkins邮箱的配置资料基本上是qq、163邮箱等,总之该问题困扰了自己很久,现将解决方案给出,希望对后续的其他人有较好的帮助。
在刚开始的时候,自己走了很多弯路,在网上查了很多资料,也在QQ群里问了很多人,但他们的答案都没有解决这个问题,后面实在没办法,就只能依靠自己,继续研究。
在最开始的时候,以为是自己的配置问题,那好,自己就将各种组合都尝试了一遍,结果问题还是没有解决,此时,自己也有点心烦了,就把这个问题放了几天。
几天后,再将这个问题拿出来,发现自己解决问题的思路有点问题,那么就改变自己的解决思路,先还是按照网上已公开的资料,重新设置了邮箱,然后看出错的提示信息,从提示信息中,发现问题可能出现在访问时的SSH证书,想到这,自己通过浏览器访问公司邮箱的服务器,发现公司邮箱的请求是由https协议实现的,因此自己就朝这个方向去寻找解决方案,总算有点头绪了,给自己一点鼓励。
有了头绪后,自己很快在网上找到了解决该问题的方案,原来该问题的主要原因是因为服务器端的证书在客户端没有被认证,因此解决该问题,只需要将服务器端的证书导入到java keystore中,具体的操作步骤如下:
1、得到InstallCert.java程序,该程序主要是获取SSH的安全证书,也可以将以下代码直接复制,保存为InstallCert.java:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class InstallCert {
public static void main(String[] args) throws Exception {
String host;
int port;
char[] passphrase;
if ((args.length == 1) || (args.length == 2)) {
String[] c = args[0].split(":");
host = c[0];
port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
String p = (args.length == 1) ? "changeit" : args[1];
passphrase = p.toCharArray();
} else {
System.out
.println("Usage: java InstallCert <host>[:port] [passphrase]");
return;
}
File file = new File("jssecacerts");
if (file.isFile() == false) {
char SEP = File.separatorChar;
File dir = new File(System.getProperty("java.home") + SEP + "lib"
+ SEP + "security");
file = new File(dir, "jssecacerts");
if (file.isFile() == false) {
file = new File(dir, "cacerts");
}
}
System.out.println("Loading KeyStore " + file + "...");
InputStream in = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, passphrase);
in.close();
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf
.getTrustManagers()[0];
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
context.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory factory = context.getSocketFactory();
System.out
.println("Opening connection to " + host + ":" + port + "...");
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.setSoTimeout(10000);
try {
System.out.println("Starting SSL handshake...");
socket.startHandshake();
socket.close();
System.out.println();
System.out.println("No errors, certificate is already trusted");
} catch (SSLException e) {
System.out.println();
e.printStackTrace(System.out);
}
X509Certificate[] chain = tm.chain;
if (chain == null) {
System.out.println("Could not obtain server certificate chain");
return;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
System.out.println();
System.out.println("Server sent " + chain.length + " certificate(s):");
System.out.println();
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
MessageDigest md5 = MessageDigest.getInstance("MD5");
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = chain[i];
System.out.println(" " + (i + 1) + " Subject "
+ cert.getSubjectDN());
System.out.println(" Issuer " + cert.getIssuerDN());
sha1.update(cert.getEncoded());
System.out.println(" sha1 " + toHexString(sha1.digest()));
md5.update(cert.getEncoded());
System.out.println(" md5 " + toHexString(md5.digest()));
System.out.println();
}
System.out
.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
String line = reader.readLine().trim();
int k;
try {
k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
} catch (NumberFormatException e) {
System.out.println("KeyStore not changed");
return;
}
X509Certificate cert = chain[k];
String alias = host + "-" + (k + 1);
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts");
ks.store(out, passphrase);
out.close();
System.out.println();
System.out.println(cert);
System.out.println();
System.out
.println("Added certificate to keystore 'jssecacerts' using alias '"
+ alias + "'");
}
private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 3);
for (int b : bytes) {
b &= 0xff;
sb.append(HEXDIGITS[b >> 4]);
sb.append(HEXDIGITS[b & 15]);
sb.append(' ');
}
return sb.toString();
}
private static class SavingTrustManager implements X509TrustManager {
private final X509TrustManager tm;
private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm) {
this.tm = tm;
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
//throw new UnsupportedOperationException();
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
this.chain = chain;
tm.checkServerTrusted(chain, authType);
}
}
}
2、编译:javac InstallCert.java
3、运行:java InstallCert email.ssscc.com.cn:465,当提示Enter certificate to add to trusted keystore or ‘q’ to quit: [1]时,输入1,回车
E:\>java InstallCert email.ssscc.com.cn:465
Loading KeyStore D:\Program Files\Java\jre7\lib\security\cacerts...
Opening connection to email.ssscc.com.cn:465...
Starting SSL handshake...
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.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at InstallCert.main(InstallCert.java:87)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertP
athBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:182)
... 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to reques
ted target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 15 more
Server sent 1 certificate(s):
1 Subject CN=yong mook kim, OU=mkyong, O=mkyong, L=puchong, ST=PJ, C=my
Issuer CN=yong mook kim, OU=mkyong, O=mkyong, L=puchong, ST=PJ, C=my
sha1 32 3e 15 42 96 ba e9 4d 9c 5d e7 5e 6b 0f 30 23 b4 e3 f4 98
md5 c8 dd a1 af 9f 55 a0 7f 6e 98 10 de 8c 63 1b a5
Enter certificate to add to trusted keystore or 'q' to quit: [1]
1
[
[
Version: V3
Subject: CN=yong mook kim, OU=mkyong, O=mkyong, L=puchong, ST=PJ, C=my
Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
Key: Sun RSA public key, 1024 bits
modulus: 1129473579651954554552730664834664064459539051598864058082387115962631728819634110255367718769683451438528187
923246533854744470790959477657386037636238098777089479256059697784394926741427654735994678054030193662669088404706890444
59364523220747231216704221781747262219695262340353839314222273672957748320603247
public exponent: 65537
Validity: [From: Tue Dec 14 15:13:51 SGT 2010,
To: Mon Mar 14 15:13:51 SGT 2011]
Issuer: CN=yong mook kim, OU=mkyong, O=mkyong, L=puchong, ST=PJ, C=my
SerialNumber: [ 4d07192f]
]
Algorithm: [SHA1withRSA]
Signature:
0000: 38 E4 F4 D9 51 B1 5F C1 01 13 32 79 DE 97 26 58 8...Q._...2y..&X
0010: 13 08 F1 A0 33 DB B9 90 AF EE 9E AE B9 9B 68 7D ....3.........h.
0020: DF E8 7D 79 9D 92 24 4A 76 C9 4C 28 DA 68 B0 62 ...y..$Jv.L(.h.b
0030: FF AB 27 03 5C DD 1F C8 77 A2 25 18 DF 0C DC FD ..'.\...w.%.....
0040: D3 39 5D 18 B4 BA 4B 36 8C FD C5 80 FF F2 E3 4D .9]...K6.......M
0050: 0A 28 57 B9 04 D8 25 F6 FB CA DA 13 0C 36 FB 02 .(W...%......6..
0060: 9A B3 B1 28 46 D1 8E C7 D9 1A 5B CE BB A6 6F FD ...(F.....[...o.
0070: 6D F2 35 D9 95 43 6E 38 2A 56 E7 31 21 D9 F0 90 m.5..Cn8*V.1!...
]
Added certificate to keystore 'jssecacerts' using alias 'email.ssscc.com.cn-1'
4、再次运行java InstallCert email.ssscc.com.cn:465,提示如下即无误
5、复制InstallCert.java目录下的jssecacerts文件至jenkins安装目录下的/jre/lib/security目录下
6、重启jenkins服务,测试邮件发送功能
注意:如果你安装的是jdk7,则可能会出现下面这样的错误
javax.net.ssl.SSLException: java.lang.UnsupportedOperationException
如果出现这样的错误,直接修改InstallCert.java
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
// throw new UnsupportedOperationException();注释该行,用上面这行替代即可
}
当然,你可以直接在上面下载使用。,至此,该问题得到解决。
更多推荐
所有评论(0)