通过Java访问国内Azure服务

来源:互联网 发布:淘宝卖高仿耐克鞋 编辑:程序博客网 时间:2024/04/28 12:58

随着Azure服务在国内的开展,不少Java用户也开始在国内Azure部署应用。不过,目前有一个问题,是关于证书。国内Azure服务HTTPS端点的证书,是由CNNIC颁发的,而CNNIC作为一个根证书颁发机构,不被Oracle JDK信任。如果通过Oracle JDK开发一个应用,要去访问国内Azure的各种HTTPS地址,比如管理API、Service Bus、存储URL、SQL数据库等等,都会遇到类似下面的问题

Dec 13, 2013 8:35:57 PM com.microsoft.sqlserver.jdbc.TDSChannel enableSSLINFO: java.security path: C:\Program Files\Java\jre6\lib\securitySecurity providers: [SUN version 1.6, SunRsaSign version 1.5, SunJSSE version 1.6, SunJCE version 1.6, SunJGSS version 1.0, SunSASL version 1.5, XMLDSig version 1.0, SunPCSC version 1.6]SSLContext provider info: Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)SSLContext provider services:[SunJSSE: KeyFactory.RSA -> sun.security.rsa.RSAKeyFactory
.......
TrustManagerFactory provider info: Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)TrustManagerFactory default algorithm: PKIXjava.ext.dirs: C:\Program Files\Java\jre6\lib\ext;C:\WINDOWS\Sun\Java\lib\extcom.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". ClientConnectionId:4b1a3848-7aa5-4474-b7fc-25f79f52b4de

报错的原因,是JDK不信任服务端的HTTPS证书。


要解决这个问题,有几个办法:

1. 如果是Linux客户端,可以试试用OpenJDK http://openjdk.java.net/

2. 如果不要求数据加密,可以连接HTTP或普通端点,比如存储

3. 如果连接对象是SQL数据库,可以禁用加密(在连接字符串中将encrypt去掉)

4. 可以写一个小程序,下载服务端证书,然后导入本地JDK的信任证书列表 (对SQL数据库无效,因为不是HTTPS端点)

package example;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;}public X509Certificate[] getAcceptedIssuers() {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);}}}


0 0
原创粉丝点击