前两天工作遇到一个基于C/S结构的LDAP+SSL访问的问题,由于LDAP的服务器都是内网服务器,所以不需要去进行certificate。在网上搜了一下,找到了个solution分享给大家。
由于默认的Java over SSL是需要certificate,对于一些不需要证书的case,如果只是简简单单的在初始化Context的时候加上如下的语句
props.put(Context.SECURITY_PROTOCOL, "ssl");
你就会收到如下的异常:
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 at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868) at sun.security.ssl.Handshaker.process_record(Handshaker.java:804) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312) at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:882) at sun.security.ssl.AppInputStream.read(AppInputStream.java:102) at java.io.BufferedInputStream.fill(BufferedInputStream.java:235) at java.io.BufferedInputStream.read1(BufferedInputStream.java:275) at java.io.BufferedInputStream.read(BufferedInputStream.java:334) at com.sun.jndi.ldap.Connection.run(Connection.java:853) at java.lang.Thread.run(Thread.java:744) Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323) ... 12 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) ... 18 more
这一大串的异常信息用一句简单的话来概括就是你的Java client通过SSL来访问LADP server的时候,需要证书来做certificate,但是在我们本地并没有这样的东西,所以创建连接失败。
如何在建立连接的时候忽略certificate这一步呢?在我们的Java代码里需要做如下的事情,首先我们需要创建一个我们自己的TrustManagerh和SSLSocketFactory来替代默认的SSLSocketFactory
import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; public class LTSTrustmanager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[0]; } }
import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.SecureRandom; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; public class LTSSSLSocketFactory extends SSLSocketFactory { private SSLSocketFactory socketFactory; public LTSSSLSocketFactory() { try { SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, new TrustManager[]{ new LTSTrustmanager()}, new SecureRandom()); socketFactory = ctx.getSocketFactory(); } catch ( Exception ex ) { ex.printStackTrace(System.err); } } public static SocketFactory getDefault(){ return new LTSSSLSocketFactory(); } @Override public Socket createSocket(Socket arg0, String arg1, int arg2, boolean arg3) throws IOException { return null; } @Override public String[] getDefaultCipherSuites() { return socketFactory.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return socketFactory.getSupportedCipherSuites(); } @Override public Socket createSocket(String arg0, int arg1) throws IOException, UnknownHostException { return socketFactory.createSocket(arg0, arg1); } @Override public Socket createSocket(InetAddress arg0, int arg1) throws IOException { return socketFactory.createSocket(arg0, arg1); } @Override public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) throws IOException, UnknownHostException { return socketFactory.createSocket(arg0, arg1, arg2, arg3); } @Override public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, int arg3) throws IOException { return socketFactory.createSocket(arg0, arg1, arg2, arg3); } }
这两个类里有几句代码要解释一下。
SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, new TrustManager[]{ new LTSTrustmanager()}, new SecureRandom()); socketFactory = ctx.getSocketFactory();
这里的TLS其实是一个protocol。TLS的全称是Transport Layer Security Protocol,至于这个协议具体是干嘛用的,自己google啦。 接下来的两句就是通过自己dummy的TrustManager来初始化我们的SSLSocketFactory。值得多提的一句就是getDefault方法一定要有,因为在SSL建立连接的时候他需要通过这个方法来获取SSLSocketFactory的实例。
至于我们自己dummy的TrustManager我们只需要实现getAcceptedIssuers这个方法,让他返回一个X509Certificate的数组即可。
public X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[0]; }
上述的一切都做好之后,我们需要把我们dummy的class配置到LdapContextt当中。
Properties props = new Properties(); props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); props.setProperty(Context.PROVIDER_URL, "ldap.provider.url=ldap://XXXXXX:636"); props.put("java.naming.ldap.factory.socket", "LTSSSLSocketFactory"); props.put(Context.SECURITY_PROTOCOL, "ssl"); props.setProperty(Context.URL_PKG_PREFIXES, "com.sun.jndi.url"); props.setProperty(Context.REFERRAL, "ignore"); props.setProperty(Context.SECURITY_AUTHENTICATION, "simple"); props.setProperty(Context.SECURITY_PRINCIPAL, "xxxxx"); props.setProperty(Context.SECURITY_CREDENTIALS, "xxxxxxx"); LdapContext ctx = new InitialLdapContext(props, null);
这里注意我们新配置的java.naming.ldap.factory.socket是需要包名+类名的,比如
props.put("java.naming.ldap.factory.socket", "com.xxx.LTSSSLSocketFactory");
就此我们完成了全部的工作,Java over SSL再也不需要certificate。
相关推荐
本文将深入探讨如何使用Java通过LDAP(轻量级目录访问协议)和SSL(安全套接层)来实现用户和组织(部门)的增删改查操作,并结合证书确保通信的安全性。这些功能通常用于大型企业的用户管理,例如Active Directory...
在使用自定义的Socket Factory访问LDAP目录时,客户端需要实现一个自定义的TrustManager来验证服务器端的SSL证书。例如,在Java中,可以使用以下代码来实现自定义的TrustManager: public class DummyTrustManager ...
Java 连接和验证 LDAP 文档 Java 连接和验证 LDAP 文档是一份关于 Java 语言连接和验证 LDAP 服务器的学习...通过使用 Java 6.0 API for LDAP,可以轻松地连接和访问 LDAP 服务器,实现目录服务中的数据访问和管理。
Java 语言可以通过 JNI(Java Native Interface,Java 本地接口)或纯 Java 实现来访问和操作 LDAP 服务器。 二、Java 访问 LDAP 服务器 在 Java 中,访问 LDAP 服务器需要使用 javax.naming 和 javax.naming.ldap...
通过 JNDI,开发者可以使用 Java 语言来访问和操作 LDAP 服务器。 在本文中,我们将讨论 Java 语言如何使用 JNDI 对 LDAP 服务器进行增删改查等操作。我们将使用一个简单的示例程序来演示如何使用 JNDI 连接到 LDAP...
完成上述步骤后,你将拥有一个配置了SSL安全和LDAP认证的Ubuntu SVN服务器,允许团队成员通过HTTP/HTTPS安全地访问和操作版本库。这个过程确保了数据的保密性和用户的身份验证,提高了协作的效率和安全性。在实际...
这个主题涉及几个关键知识点,包括Java LDAP API、SSL安全连接以及如何通过代码操作LDAP目录。 首先,LDAP是一个开放标准的协议,用于存储和检索用户、组、计算机等对象的数据。这些数据通常分布在多台服务器上,...
Java连接LDAP服务器是一种常见的任务,尤其在企业级应用中,用于身份验证、用户管理或访问控制。LDAP(轻量级目录访问协议)是一种基于X.500标准的目录服务协议,它允许快速查找和管理分布式数据库中的信息。在Java...
### 将 LDIF 文件导入 LDAP 服务器:详细指南与步骤 ...通过上述步骤,你可以有效地将LDIF文件导入到LDAP服务器中,从而更新或扩展你的目录服务。这不仅有助于优化网络管理,还能增强组织的数据安全性与灵活性。
LDAP协议遵循客户端/服务器模型,客户端通过API和TCP/IP向服务器发送符合LDAP协议的请求,服务器直接处理目录操作并返回结果。这一过程包含请求/回复的交互,确保了目录服务的正常运行。 【LDAP的信息模型】 LDAP...
JAVA中使用LDAP进行用户认证是指在JAVA应用程序中使用轻量级目录访问协议(LDAP)来进行用户身份验证。LDAP是一种基于X.500标准的目录访问协议,但它更简单、更灵活,可以根据需要进行定制。LDAP支持TCP/IP协议,使...
### 使用Java实现LDAP访问 #### 一、简介 在企业级应用开发中,LDAP(Lightweight Directory Access Protocol,轻量目录访问协议)是一种常见的用于管理组织机构中的用户账户信息的标准协议。通过LDAP,开发者可以...
**LDAP简介** Lightweight Directory Access Protocol(轻量级目录访问协议)是互联网上广泛使用的协议,用于...通过深入理解Java LDAP API和SUN LDAP服务器的配置与管理,开发者可以构建出高效、安全的分布式系统。
在IT领域,LDAP(Lightweight Directory Access Protocol)是一种用于存储和检索目录信息的标准协议,常用于企业级的...通过以上步骤,你可以在CentOS系统上搭建一个基本的LDAP服务器,并用Java进行数据的访问和管理。
3. **设置安全性和权限**:配置LDAP服务器的安全策略,包括密码策略、SSL/TLS加密、访问控制列表(ACLs)等,确保数据传输和存储的安全。 4. **配置客户端访问**:在需要使用LDAP进行身份验证和授权的系统上配置...
**LDAP服务器搭建详解** 在Linux环境中, Lightweight Directory Access Protocol (LDAP) 服务器是一种用于存储和检索用户、组、网络资源等信息的目录...通过排查和调试,应该能够成功建立一个运行正常的LDAP服务器。
LDAP(Lightweight Directory Access Protocol)是一种轻量级目录访问协议,用于存储和管理目录信息。AD 域(Active Directory Domain)是 Microsoft 提供的一种目录服务,用于存储和管理用户、组、计算机和其他对象...
LDAP(Lightweight Directory Access Protocol)是一种目录访问协议,允许客户端访问和操作目录服务。 LDAP 广泛应用于企业目录服务中,如 Active Directory、OpenLDAP 等。 Java 使用 LDAP 修改 AD 域用户密码 在...
通过JNDI,Java开发者可以方便地与LDAP服务器进行交互,实现诸如连接、添加、删除、修改和搜索等操作。 1. **JNDI基础** JNDI是一个接口,提供了一种统一的方式来查找和管理各种命名和目录服务,包括 LDAP、DNS、...