LDAP总结
- 简介
- 服务端
- 问题
- 配置LDAP
- 导入数据
- 删除数据
- 安装ldapbrowser
- 使用
- 登陆信息
- Java对Ldap的使用
- 问题
简介
Ldap是一个轻量级访问目录。
具有很强大的查询(读)的功能,适合进行大量数据的检索。
写方面就慢的多,适合读不适合写。
常用字段
含义 | |
o | organization(组织-公司) |
ou | organization unit(组织单元/部门) |
c | countryName(国家) |
dc | domainComponent(域名组件) |
sn | suer name(真实名称) |
cn | common name(常用名称) |
dn | distinguished name(专有名称) |
服务端
问题
如果数据库选BDB一直启动不了的话,卸载重新安装,选MDB
slapd -d 1 -f
run文件夹下的run.cmd
Win+R->services.msc->OpenLDAP Service设为手动
配置LDAP
找到安装路径,找到slapd.conf文件
将dc修改为任意值
suffix "dc=micmiu,dc=com"
rootdn "cn=test,dc=micmiu,dc=com"
C:\Windows\System32\drivers\etc\hosts:在最后添加localhost micmiu.com
导入数据
- 在安装路径新建文件,后缀名为ldif
- slapd -d 1 -f ./slapd.conf
出现slapd starting则表示启动成功 - slapadd -v -l ./mydemo.ldif
- slapadd -v -l ./info.ldif
出现100%…Closing…表示导入成功 - 查看导入信息
在ClientTools目录下打开cmd
ldapsearch -x -b “dc=micmiu,dc=com” “(objectclass=*)”
删除数据
- 先关闭服务,删除安装路径下data文件夹(默认路径)下的东西即可。
- 具体目录在slapd.conf文件的directory标签后面的参数。
安装ldapbrowser
安装的类型,建议选择第一个安装(Typical)
使用
- New->New Profile并填写Profile:自定义
- 填写Host,Port和Base DN
Base DN可以按"Fetch Base DNs",然后自己选择 - 填写Principal和Password
登陆信息
- Host:localhost
- Port:389
- Base DN:dc=micmiu,dc=com
上面这一项对应slapd.conf文件的suffix后面的参数 - User DN(Principal):cn=Manager,dc=micmiu,dc=com
上面这一项对应slapd.conf文件的rootdn后面的参数 - Password:secret
上面这一项对应slapd.conf文件的rootpw后面的参数
默认值secret,默认基于{SSHA}加密
{SSHA}n5e8W0KjKOkhPhpQ4gTdfeuaIG1E2NEI - 可以根据:
C:\Users\Administrator>slappasswd
New password: 123
Re-enter new password: 123
{SSHA}2e49d0L/XomzoVsO+VuWQbC5qixCdKK/
Java对Ldap的使用
package com.demo.database.other.ldap;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
public class LdapUtil {
public static void main(String[] args) {
// new LdapUtil().getOrgDN();
// new LdapUtil().getUserDN();
}
// 声明静态变量只是例子,通常需要把这些参数写到配置文件中去
private static String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
// 链接的Host ldap://localhost/
private static String URL = "ldap://localhost:389/";
// 根据自己情况修改Base DN
private static String BASEDN = "dc=micmiu,dc=com";
// 管理员账号
private static String PRINCIPAL = "cn=test,dc=micmiu,dc=com";
// 管理员密码
private static String PASSWORD = "123456789";
private static String AUTHENTICATION = "simple";
private LdapContext ctx = null;
private final Control[] conControl = null;
/**
* 进行LDAP连接
*/
private void openConnect() {
Hashtable<String, String> hashTable = new Hashtable<String, String>();
hashTable.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
hashTable.put(Context.PROVIDER_URL, URL + BASEDN);
hashTable.put(Context.SECURITY_AUTHENTICATION, AUTHENTICATION);
hashTable.put(Context.SECURITY_PRINCIPAL, PRINCIPAL);
hashTable.put(Context.SECURITY_CREDENTIALS, PASSWORD);
try {
ctx = new InitialLdapContext(hashTable, conControl);
System.out.println("连接成功");
} catch (javax.naming.AuthenticationException e) {
System.out.println("连接失败");
e.printStackTrace();
} catch (Exception e) {
System.out.println("连接失败");
e.printStackTrace();
}
}
/**
* 关闭LDAP连接
*/
private void closeConnect() {
if (ctx != null) {
try {
ctx.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
}
/**
* 遍历所有部门
*
* @return
*/
public boolean getOrgDN() {
boolean result = true;
try {
this.openConnect();
String filter = "(&(|(objectClass=organizationalUnit)))";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> en = ctx.search("", filter, constraints);
while (en != null && en.hasMoreElements()) {
Object obj = en.nextElement();
if (obj instanceof SearchResult) {
SearchResult sr = (SearchResult) obj;
Attributes attrs = sr.getAttributes();
// ou=Developer
System.out.println(sr.getName());
// 打印全部属性
System.out.println("全部属性:\n" + attrs);
// 打印单个属性
System.out.println("单个属性:\n" + sr.getAttributes().get("description"));
// 进行截取值
if (sr.getAttributes().get("description") != null) {
// description=description: xxx
String des = sr.getAttributes().get("description").toString();
System.out.println(des.substring(des.lastIndexOf(":") + 2, des.length()));
}
if (sr.getName() != null) {// 部门名称
String orgname = sr.getName().toString();
System.out.println(orgname.substring(orgname.lastIndexOf("=") + 1, orgname.length()));
}
} else {
System.out.println(obj);
}
}
} catch (Exception e) {
result = false;
e.printStackTrace();
} finally {
this.closeConnect();
}
return result;
}
/**
* 遍历所有用户
*
* @return
*/
public boolean getUserDN() {
boolean result = true;
try {
this.openConnect();
String filter = "(&(|(objectClass=person)))";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> en = ctx.search("", filter, constraints);
while (en != null && en.hasMoreElements()) {
Object obj = en.nextElement();
if (obj instanceof SearchResult) {
SearchResult sr = (SearchResult) obj;
Attributes attrs = sr.getAttributes();
// uid=565,ou=Developer
System.out.println(sr.getName());
// 全部属性
System.out.println("全部属性:\n" + attrs);
// 单个属性
System.out.println("单个属性:\n" + sr.getAttributes().get("mail"));
// 可在此处新建对象进行赋值
if (sr.getAttributes().get("uid") != null) {// uid
String uid = sr.getAttributes().get("uid").toString();
System.out.println(uid.substring(uid.lastIndexOf(":") + 2, uid.length()));
}
if (sr.getAttributes().get("cn") != null) { // cn
String cn = sr.getAttributes().get("cn").toString();
System.out.println(cn.substring(cn.lastIndexOf(":") + 2, cn.length()));
}
} else {
System.out.println(obj);
}
}
} catch (Exception e) {
result = false;
e.printStackTrace();
} finally {
this.closeConnect();
}
return result;
}
/**
* 根据ldap中用户的mail字段与明文密码验证是否正确
*
* @param mail
* ldap中用户的mail字段
* @param password
* 输入的明文密码
* @return String 1:认证成功,0:认证失败,-1:此用户不存在
*/
public String authenticate(String mail, String password) {
String result = "1";
System.out.println("开始认证:" + mail);
// 获取SSHA密文
String sshapwd = getSSHAPwdByMail(mail);
if ("".equals(sshapwd)) {
result = "-1";
}
try {
if (this.verifySSHA(sshapwd, password)) {
result = "1";
System.out.println(mail + ":认证通过");
} else {
result = "0";
System.out.println(mail + ":认证失败");
}
} catch (IOException e) {
result = "0";
e.printStackTrace();
}
return result;
}
/**
* 根据ldap中用户的mail字段获取用户的LDAP{SSHA}密码
*
* @param mail
* ldap中用户的mail字段
* @return
*/
public String getSSHAPwdByMail(String mail) {
String result = "";
try {
this.openConnect();
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
// 可以修改此处ldap中的属性
NamingEnumeration<SearchResult> en = ctx.search("", "mail=" + mail, constraints);
if (en == null || !en.hasMoreElements()) {
result = "";
}
while (en != null && en.hasMoreElements()) {
Object obj = en.nextElement();
if (obj instanceof SearchResult) {
SearchResult sr = (SearchResult) obj;
Attributes attrs = sr.getAttributes();
Attribute attr = attrs.get("userPassword");
byte[] bytes = (byte[]) attr.get(0);
result = new String(bytes);
} else {
System.out.println(obj);
}
}
} catch (Exception e) {
result = "";
e.printStackTrace();
}
return result;
}
/**
* 根据ldap中用户的uid字段获取用户的userDN
*
* @param uid
* ldap中用户的uid字段
* @return
*/
public String getuserDNByUid(String uid) {
String userDN = "";
try {
this.openConnect();
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> en = ctx.search("", "uid=" + uid, constraints);
if (en == null || !en.hasMoreElements()) {
System.out.println("未找到该用户");
}
while (en != null && en.hasMoreElements()) {
Object obj = en.nextElement();
if (obj instanceof SearchResult) {
SearchResult sr = (SearchResult) obj;
userDN += sr.getName();
userDN += "," + BASEDN;
} else {
System.out.println(obj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return userDN;
}
/**
* 将明文与密文进行比较
*
* @param ldappw
* LDAP{SSHA}密文
* @param inputpw
* 明文
* @return
* @throws IOException
*/
public boolean verifySSHA(String ldappw, String inputpw) throws IOException {
// MessageDigest提供了消息摘要算法,这里LDAP使用的是SHA-1
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 取出加密字符
if (ldappw.startsWith("{SSHA}")) {
ldappw = ldappw.substring(6);
} else if (ldappw.startsWith("{SHA}")) {
ldappw = ldappw.substring(5);
}
// 解码BASE64
byte[] ldappwbyte = Base64.decode(ldappw);
byte[] shacode;
byte[] salt;
// 前20位是SHA-1加密段,20位后是最初加密时的随机明文
if (ldappwbyte.length <= 20) {
shacode = ldappwbyte;
salt = new byte[0];
} else {
shacode = new byte[20];
salt = new byte[ldappwbyte.length - 20];
System.arraycopy(ldappwbyte, 0, shacode, 0, 20);
System.arraycopy(ldappwbyte, 20, salt, 0, salt.length);
}
// System.out.println(new String(shacode));
// 把用户输入的密码添加到摘要计算信息
md.update(inputpw.getBytes());
// 把随机明文添加到摘要计算信息
md.update(salt);
// 按SSHA把当前用户密码进行计算
byte[] inputpwbyte = md.digest();
// 返回校验结果
return MessageDigest.isEqual(shacode, inputpwbyte);
}
}
问题
javax.naming.InvalidNameException: [LDAP: error code 34 - invalid DN]
SECURITY_PRINCIPAL
格式错误
javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
①:slapd.conf文件不正确。sldap.conf文件中rootpw 配置,rootpw就写在行首,前面不能有空格,然后和密码之间使用tab键
②:修改slapd.conf文件rootpw后面的值(密码),然后重启slapd服务,发现密码并没有修改过来,还是只能用原来的密码登录,执行sudo slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d 时,密码才真正修改成功
③:确保用户名和密码正确