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

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

我的环境

  • CentOS 7
  • 关闭防火墙(开放指定的端口也是可以的,这里也很容易出问题)
  • yum
  • ldapAdmin 免安装管理工具

服务安装

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//公钥(自签名)

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 env = new Hashtable();
        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());

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

你可能感兴趣的:(经验)