LDAP部署、java连接、SSL协议,以及遇到的证书问题

写在前面的话:
部署openLDAP 2.4.44 (centOS 7.X 直接yum 安装的版本),之前在网上查找过教程,大多数openLDAP 2.3.X 初始配置已经有了很大变化。说直接改/etc/openldap/slapd.conf 没有就新建,或者修改/etc/openldap/slapd.d/下的文件。最后导致slapd服务总是起不来。所以写下这个教程,避坑。

我的环境

服务安装

yum install -y openldap openldap-servers openldap-clients openldap-devel

生成OpenLDAP管理密码

[root@localhost ~]# slappasswd
New password: //此处输入密码
Re-enter new password: //再次密码
{SSHA}CrdqT5EAh8H2y2SorEUbuxP3R5eOggjb

{SSHA}CrdqT5EAh8H2y2SorEUbuxP3R5eOggjb复制出来,后面用得到

配置OpenLDAP

OpenLDAP 2.3之后的版本取消了/etc/openldap/slapd.conf的配置方式,使用ldif文件动态配置

vi /usr/share/openldap-servers/slapd.ldif

可以参考我的修改

[root@localhost ~]# cat /usr/share/openldap-servers/slapd.ldif
#
# See slapd-config(5) for details on configuration options.
# This file should NOT be world readable.
#

dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/openldap/slapd.args
olcPidFile: /var/run/openldap/slapd.pid
#
# TLS settings
#  这是关于ssl协议的证书配置,我是用是openSSL生成的自签证书

olcTLSCACertificatePath: /etc/openldap/certs
olcTLSCertificateFile: /etc/openldap/certs/ldap.crt
olcTLSCertificateKeyFile: /etc/openldap/certs/ldap.key
#
# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#
#olcReferral: ldap://root.openldap.org
#
# Sample security restrictions
#       Require integrity protection (prevent hijacking)
#       Require 112-bit (3DES or better) encryption for updates
#       Require 64-bit encryption for simple bind
#
#olcSecurity: ssf=1 update_ssf=112 simple_bind=64


#
# Load dynamic backend modules:
# - modulepath is architecture dependent value (32/64-bit system)
# - back_sql.la backend requires openldap-servers-sql package
# - dyngroup.la and dynlist.la cannot be used at the same time
#

dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
#olcModulepath: /usr/lib/openldap
olcModulepath:  /usr/lib64/openldap
olcModuleload: accesslog.la
olcModuleload: auditlog.la
olcModuleload: back_dnssrv.la
olcModuleload: back_ldap.la
olcModuleload: back_mdb.la
olcModuleload: back_meta.la
olcModuleload: back_null.la
olcModuleload: back_passwd.la
olcModuleload: back_relay.la
olcModuleload: back_shell.la
olcModuleload: back_sock.la
olcModuleload: collect.la
olcModuleload: constraint.la
olcModuleload: dds.la
olcModuleload: deref.la
#olcModuleload: dyngroup.la
olcModuleload: dynlist.la
olcModuleload: memberof.la
olcModuleload: pcache.la
olcModuleload: ppolicy.la
olcModuleload: refint.la
olcModuleload: retcode.la
olcModuleload: rwm.la
olcModuleload: seqmod.la
olcModuleload: smbk5pwd.la
olcModuleload: sssvlv.la
olcModuleload: syncprov.la
olcModuleload: translucent.la
olcModuleload: unique.la
olcModuleload: valsort.la


#
# Schema settings
#

dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema

include: file:///etc/openldap/schema/core.ldif

#
# Frontend settings
#

dn: olcDatabase=frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: frontend
#
# Sample global access control policy:
#       Root DSE: allow anyone to read it
#       Subschema (sub)entry DSE: allow anyone to read it
#       Other DSEs:
#               Allow self write access
#               Allow authenticated users read access
#               Allow anonymous users to authenticate
#
#olcAccess: to dn.base="" by * read
#olcAccess: to dn.base="cn=Subschema" by * read
#olcAccess: to *
#       by self write
#       by users read
#       by anonymous auth
#
# if no access controls are present, the default policy
# allows anyone and everyone to read anything but restricts
# updates to rootdn.  (e.g., "access to * by * read")
#
# rootdn can always read and write EVERYTHING!
#

#
# Configuration database
#

dn: olcDatabase=config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: config
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,c
 n=auth" manage by * none

#
# Server status monitoring
#

dn: olcDatabase=monitor,cn=config
objectClass: olcDatabaseConfig
olcDatabase: monitor
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,c
 n=auth" read by dn.base="cn=root,dc=这里改成自己的,dc=com" read by * none

#
# Backend database definitions
#

dn: olcDatabase=hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: hdb
olcSuffix: dc=这里改成自己的,dc=com
olcRootDN: cn=root,dc=这里改成自己的,dc=com
olcRootPW: {SSHA}PU4CNCews363SCGpb4hUYmrkHyMnUCrX  密码是前面生成的 
olcDbDirectory: /var/lib/ldap
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
[root@localhost ~]# 

导入DB_CONFIG、重新生成配置、修改目录权限并启动服务

删除配置

[root@localhost ~]# rm -rf /etc/openldap/slapd.d/*

导入配置

[root@localhost ~]# cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
[root@localhost ~]# slapadd -n 0 -F /etc/openldap/slapd.d -l /usr/share/openldap-servers/slapd.ldif

修改目录权限

[root@localhost ~]# chown -R ldap.ldap /etc/openldap/slapd.d/*
[root@localhost ~]# chown -R ldap.ldap /var/lib/ldap/*

启动

[root@localhost ~]# systemctl start slapd

导入schema

[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif

解决 报错 No Object

[root@localhost ~]# vim base.ldif
dn: dc=这里改成自己的,dc=com
o: 这里改成自己的
objectclass: dcObject
objectclass: organization


[root@localhost ~]# ldapadd -f base.ldif -x -D cn=root,dc=这里改成自己的,dc=com -W
输入密码

解决 systemctl start slapd 启动失败

  • 重新生成配置。
  • 重新生成配置仍然失败,完全卸载后重新安装。

启动ldap:// ldaps://

 slapd -h "ldap:/// ldaps:///"

修改启动端口

slapd -h "ldap://:123"

netstat -tunlp  查看

补充ldap.配置的签名

一.Server端自签名证书(ldap.key(私钥)、ldap.crt(证书、公钥))
1、首先安装openssl,已安装请忽略

yum -y install openssl

2、生成server端的私钥

cd /etc/openldap/certs/
openssl genrsa -out ldap.key 2048  //私钥

3、生成签名请求

openssl req -new -key ldap.key -out ldap.csr //生成签名请求

只有Common Name项一定要填写Sever的IP或域名,其余项可不填写。
4、生成自签名CA证书

openssl x509 -req -days 1095 -in ldap.csr -signkey ldap.key -out ldap.crt//公钥(自签名)

查看证书

openssl x509 -in ldap.crt -text -noout

JDK 版本升级到14 证书连接失败的问题

1、jdk14需要检查证书扩展属性,验证IP
2、使用openssl 生成v3证书增加服务器IP的扩展属性
2.1、增加v3证书扩展属性 需求修改openssl.cnf vi /etc/pki/tls/openssl.cnf

#部分配置  
#先搜搜看是否有  没有在文件底部新增,

[ alternate_names ]
IP.1 = 172.17.1.2
IP.2 = 172.17.1.3
DNS.1  = example1.com
DNS.2  = example2.com

#找到 v3_req
# 添加 subjectAltName = @alternate_names

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names

生成V3版本的证书

 openssl x509 -req   -extfile /etc/pki/tls/openssl.cnf -extensions v3_req  -in ldap.csr -out ldap.cer -signkey ldap.key  -days 3650   
 
\\ -extfile /etc/pki/tls/openssl.cnf -extensions v3_req  参数是生成 X509 V3 版本的证书的必要条件。

最后记得重启ldap 让证书生效

ps -ef | grep ldap #查询PID
kill-9  PID
slapd -h "ldap:/// ldaps:///"

JDK自带API连接LDAP

  /**
     * 连接LDAP
     * @param userName uid
     * @param passwd  
     * @param SearchName 所在的目录  例如ou=test,dc=maxcrc,dc=com
     * @return
     */
    public static DirContext connectLDAP(String userName, String passwd) {
    	
        Hashtable<String, String> env = new Hashtable<String, String>();
        logger.debug("===" + userName + "==="+passwd);

        env.put(Context.SECURITY_PRINCIPAL, userName );//用户名 全路径
        env.put(Context.SECURITY_CREDENTIALS, passwd);//密码
        env.put(Context.PROVIDER_URL, "ldap://127.0.0.1:389");//连接LDAP的URL和端口
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");//JNDI Context工厂类
        env.put(Context.SECURITY_AUTHENTICATION, "simple");//认证类型
      
        DirContext ctx=null;
        try {
        	ctx = new InitialLdapContext(env, null);//开始连接
        	logger.debug("===auth OK===");
        } catch (NamingException e) {
        	e.printStackTrace();
        	logger.error("===auth ERR==="+e.getMessage());
        }
        return ctx;
    }

Java连接ldaps

根据网上教程,导入后

keytool -import  -alias ldapserver -file D:\test\server.cert -keystore cacerts -storepass changeit
//具体可百度

env.put(Context.PROVIDER_URL, "ldaps://127.0.0.1:636");//导入的是jre目录下的cacerts 就可以连接

动态导入证书报证书签名错误

因为JVM启动只加载一次证书,如果不重启加载,这需要重写SSL SocketFactory

public class LdapSocketFactory extends SocketFactory {
	private static final Logger logger = RootLogger.getLog(LdapSocketFactory.class.getName());
	
	private static LdapSocketFactory instance = null;
	private SSLContext sslContext = null;
	private static String certFileName = "C:\\ldap.crt";

	public static SocketFactory getDefault() {

		try {
			instance = new LdapSocketFactory();
			instance.initFactory();
		} catch (Exception e) {
			e.printStackTrace();
			logger.debug("Returning null socket factory");
		}

		return instance;
	}

	private void initFactory() throws Exception {
		logger.debug("Initializing socket factory...");
		InputStream certStream = new FileInputStream(certFileName);
		CertificateFactory certificateFactory = CertificateFactory
				.getInstance("X.509");
		Certificate certificate = certificateFactory
				.generateCertificate(certStream);
		logger.debug("The certificate was generated. It is issued to "
				+ ((X509Certificate) certificate).getSubjectDN());
				
		KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
		keyStore.load(null, "myPassword".toCharArray()); //自定义密码
		
		new KeyStore.TrustedCertificateEntry(certificate);
		
		keyStore.setCertificateEntry("myCert", certificate);//自定义名称
		
		logger.debug("The Keystore was initialized.");
		
		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance("SunX509", "SunJSSE");
		trustManagerFactory.init(keyStore);
		logger.debug("The TrustManagerFactory was initialized.");
		
		sslContext = SSLContext.getInstance("TLS");
		sslContext.init(null, trustManagerFactory.getTrustManagers(),
				new SecureRandom());
		logger.debug("The SSLContext was initialized.");
	}

	@Override
	public Socket createSocket(String host, int port) throws IOException,
			UnknownHostException {
		// TODO Auto-generated method stub
		return sslContext.getSocketFactory().createSocket(host, port);
	}

	@Override
	public Socket createSocket(InetAddress host, int port) throws IOException {
		// TODO Auto-generated method stub
		return sslContext.getSocketFactory().createSocket(host, port);
	}

	@Override
	public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
			throws IOException, UnknownHostException {
		// TODO Auto-generated method stub
		return sslContext.getSocketFactory().createSocket(host, port, localHost, localPort);
	}

	@Override
	public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
			int localPort) throws IOException {
		// TODO Auto-generated method stub
		return sslContext.getSocketFactory().createSocket(address, port, localAddress, localPort);
	}

}

在connectLDAP方法中 添加

env.put("java.naming.ldap.factory.socket", LdapSocketFactory.class.getName());

如此,每次连接都会加载证书

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
根据提供的引用内容,建立LDAP连接池的步骤如下: 1. 配置LDAP连接池的上下文环境: ```java Hashtable<String, String> env = new Hashtable<>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://ldap.example.com:389"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "cn=admin,dc=example,dc=com"); env.put(Context.SECURITY_CREDENTIALS, "password"); ``` 2. 创建LDAP连接池对象: ```java DirContext ctx = new InitialDirContext(env); ``` 3. 配置连接池属性: ```java ctx.addToEnvironment(javax.naming.Context.PROVIDER_URL, "ldap://ldap.example.com:389"); ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "simple"); ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, "cn=admin,dc=example,dc=com"); ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, "password"); ctx.addToEnvironment(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); ctx.addToEnvironment(javax.naming.Context.SECURITY_PROTOCOL, "ssl"); ctx.addToEnvironment(javax.naming.Context.SECURITY_PROTOCOL, "tls"); ctx.addToEnvironment(javax.naming.Context.SECURITY_PROTOCOL, "ssl"); ctx.addToEnvironment(javax.naming.Context.SECURITY_PROTOCOL, "ssl"); ``` 4. 创建连接池对象: ```java DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/dbpooling"); ``` 请注意,以上代码仅为示例,实际配置和使用LDAP连接池可能会因环境和需求而有所不同。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值