【LDAP】LDAP 和 AD 介绍及使用 LDAP 操作 AD 域

2024-05-02 14:04
文章标签 使用 介绍 操作 ad ldap

本文主要是介绍【LDAP】LDAP 和 AD 介绍及使用 LDAP 操作 AD 域,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LDAP 和 AD 介绍及使用 LDAP 操作 AD 域

  • 1.LDAP入门
    • 1.1 定义
    • 1.2 目录结构
    • 1.3 命名格式
  • 2.AD 入门
    • 2.1 AD 定义
    • 2.2 作用
    • 2.3 AD 域结构常用对象
      • 2.3.1 域(Domain)
      • 2.3.2 组织单位(Organization Unit)
      • 2.3.3 群组(Group)
      • 2.3.4 用户(User)
  • 3.使用 LDAP 操作 AD 域
    • 3.1 389 登录
    • 3.2 636 登录验证(需要导入证书)
    • 3.3 查询域用户信息
    • 3.4 重置用户密码
    • 3.5 域账号解锁

1.LDAP入门

1.1 定义

LDAP 是 轻量目录访问协议Lightweight Directory Access Protocol)的缩写,LDAP 标准实际上是在 X.500 标准基础上产生的一个简化版本。

1.2 目录结构

LDAP 也可以说成是一种数据库,也有 Client 端和 Server 端。Server 端是用来存放数据,Client 端用于操作增删改查等操作,通常说的 LDAP 是指运行这个数据库的服务器。只不过,LDAP 数据库结构为树结构,数据存储在叶子节点上。

假设你要树上的一个苹果(一条记录),你怎么告诉园丁它的位置呢?

当然首先要说明是哪一棵树(dc,相当于 MySQL 的 DB),然后是从树根到那个苹果所经过的所有 “分叉”(ou),最后就是这个苹果的名字(uid,相当于 MySQL 表主键 id)。好了!这时我们可以清晰的指明这个苹果的位置了,就是那棵 “歪脖树” 的东边那个分叉上的靠西边那个分叉的再靠北边的分叉上的半红半绿的 … …

因此,在 LDAP 中,位置可以描述如下

  • 树(dc=ljheee)
  • 分叉(ou=bei, ou=xi, ou=dong
  • 苹果(cn=redApple

因此,苹果 redApple 的位置为 dn:cn=honglv,ou=bei,ou=xi,ou=dong,dc=ljheee

dn 标识一条记录,描述了数据的详细路径。因此,LDAP 树形数据库如下

  • dnDistinguished Name):一条记录的详细位置
  • dc:一条记录所属区域 (哪一颗树)
  • ouOrganization Unit):一条记录所属组织 (哪一个分支)
  • cn/uid:一条记录的名字 / ID(哪一个苹果名字)LDAP目录树的最顶部就是根,也就是所谓的 “基准 DN"

因此,LDAP 树形结构在存储大量数据时,查询效率更高,实现迅速查找,可以应用于域验证等。

1.3 命名格式

LDAP 协议中采用的命名格式常用的有如下两种:LDAP URL 和 X.500。

任何一个支持 LDAP 的客户都可以利用 LDAP 名通过 LDAP 协议访问活动目录,LDAP 名不像普通的 Internet URL 名字那么直观,但是 LDAP 名往往隐藏在应用系统的内部,最终用户很少直接使用 LDAP 名。LDAP 名使用 X.500 命名规 范,也称为属性化命名法,包括活动目录服务所在的服务器以及对象的属性信息。

2.AD 入门

2.1 AD 定义

AD 是 Active Directory 的缩写,AD 是 LDAP 的一个应用实例,而不应该是 LDAP 本身。比如:Windows 域控的用户、权限管理应该是微软公司使用 LDAP 存储了一些数据来解决域控这个具体问题,只是 AD 顺便还提供了用户接口,也可以利用 Active Directory 当做 LDAP 服务器存放一些自己的东西而已。比如 LDAP 是关系型数据库,微软自己在库中建立了几个表,每个表都定义好了字段。显然这些表和字段都是根据微软自己的需求定制的,而不是 LDAP 协议的规定。然后微软将 LDAP 做了一些封装接口,用户可以利用这些接口写程序操作 LDAP,使得 Active Directory 也成了一个 LDAP 服务器。

在这里插入图片描述

2.2 作用

  • 用户服务:管理用户的域账号、用户信息、企业通信录(与电子邮箱系统集成)、用户组管理、用户身份认证、用户授权管理、按需实施组管理策略等。这里不单单指某些线上的应用更多的是指真实的计算机,服务器等。
  • 计算机管理:管理服务器及客户端计算机账户、所有服务器及客户端计算机加入域管理并按需实施组策略。
  • 资源管理:管理打印机、文件共享服务、网络资源等实施组策略。
  • 应用系统的支持:对于电子邮件(Exchange)、在线及时通讯(Lync)、企业信息管理(SharePoint)、微软 CRM & ERP 等业务系统提供数据认证(身份认证、数据集成、组织规则等)。这里不单是微软产品的集成,其它的业务系统根据公用接口的方式一样可以嵌入进来。
  • 客户端桌面管理:系统管理员可以集中的配置各种桌面配置策略,如:用户适用域中资源权限限制、界面功能的限制、应用程序执行特征的限制、网络连接限制、安全配置限制等。

2.3 AD 域结构常用对象

2.3.1 域(Domain)

是 AD 的根,是 AD 的管理单位。域中包含着大量的域对象,如:组织单位Organizational Unit),Group),用户User),计算机Computer),联系人Contact),打印机安全策略 等。

可简单理解为:公司总部。

2.3.2 组织单位(Organization Unit)

组织单位 简称为 OU,是一个容器对象,可以把域中的对象组织成逻辑组,帮助网络管理员简化管理组。组织单位可以包含下列类型的对象:用户,计算机,工作组,打印机,安全策略,其他组织单位等。可以在组织单位基础上部署组策略,统一管理组织单位中的域对象。

可以简单理解为:分公司。

2.3.3 群组(Group)

群组 是一批具有相同管理任务的用户账户,计算机账户或者其他域对象的一个集合。例如公司的开发组,产品组,运维组等等。可以简单理解为分公司的某事业部。

群组类型分为两类:

  • 安全组:用来设置有安全权限相关任务的用户或者计算机账户的集合。比如:Tiger 组都可以登录并访问某 ftp 地址,并拿到某个文件。
  • 通信组:用于用户之间通信的组,适用通信组可以向一组用户发送电子邮件。比如:我要向团队内 10 位成员都发送同一封邮件这里就要抄送 9 次,而使用组的话我直接可以发送给 @Tiger,所有 Tiger 组内的成员都会收到邮件。

2.3.4 用户(User)

AD 中 域用户 是最小的管理单位,域用户最容易管理又最难管理,如果赋予域用户的权限过大,将带来安全隐患,如果权限过小域用户无法正常工作。可简单理解成为某个工作人员。

域用户的类型,域中常见用户类型分为:

  • 普通域用户:创建的域用户默认就添加到 Domain Users 中。
  • 域管理员:普通域用户添加进 Domain Admins 中,其权限升为域管理员。
  • 企业管理员:普通域管理员添加进 Enterprise Admins 后,其权限提升为企业管理员,企业管理员具有最高权限。

一个大致的 AD 如下所示:

在这里插入图片描述
总之:Active Directory = LDAP 服务器LDAP 应用(Windows 域控)。Active Directory 先实现一个 LDAP 服务器,然后自己先用这个 LDAP 服务器实现了自己的一个具体应用(域控)。

3.使用 LDAP 操作 AD 域

特别注意:Java 操作查询域用户信息获取到的数据和域管理员在电脑上操作查询的数据可能会存在差异(同一个意思的表示字段,两者可能不同)。

连接 AD 域有两个地址:ldap://XXXXX.com:389ldap://XXXXX.com:636(SSL)。

端口 389 用于一般的连接,例如登录,查询等非密码操作,端口 636 安全性较高,用户密码相关操作,例如修改密码等。

域控可能有多台服务器,之间数据同步不及时,可能会导致已经修改的数据被覆盖掉,这个要么域控缩短同步的时间差,要么同时修改每一台服务器的数据。

3.1 389 登录

// 只要不抛出异常就是验证通过
public LdapContext adLogin(JSONObject json) {String username = json.getString("username");String password = json.getString("password");String server = "ldap://XXXXXXX.com:389";try {Hashtable<String, String> env = new Hashtable<String, String>();//用户名称,cn,ou,dc 分别:用户,组,域env.put(Context.SECURITY_PRINCIPAL, username);//用户密码 cn 的密码env.put(Context.SECURITY_CREDENTIALS, password);//url 格式:协议://ip:端口/组,域   ,直接连接到域或者组上面env.put(Context.PROVIDER_URL, server);//LDAP 工厂env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");//验证的类型     "none", "simple", "strong"env.put(Context.SECURITY_AUTHENTICATION, "simple");LdapContext ldapContext = new InitialLdapContext(env, null);log.info("ldapContext:" + ldapContext);log.info("用户" + username + "登录验证成功");return ldapContext;} catch (NamingException e) {log.info("用户" + username + "登录验证失败");log.info("错误信息:"+e.getExplanation());return null;}
}

3.2 636 登录验证(需要导入证书)

//证书提前倒入的Java库中
// 参考:https://www.cnblogs.com/moonson/p/4454159.htmlLdapContext adLoginSSL(JSONObject json) {String username = json.getString("username");String password = json.getString("password");Hashtable env = new Hashtable();String javaHome = System.getProperty("java.home");String keystore = javaHome+"/lib/security/cacerts";log.info("java.home,{}",keystore);// 加载导入jdk的域证书System.setProperty("javax.net.ssl.trustStore", keystore);System.setProperty("javax.net.ssl.trustStorePassword", "changeit");String LDAP_URL = "ldap://XXXXXX.com:636"; // LDAP访问地址env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");env.put(Context.SECURITY_PROTOCOL, "ssl");//链接认证服务器env.put(Context.PROVIDER_URL, LDAP_URL);env.put(Context.SECURITY_AUTHENTICATION, "simple");env.put(Context.SECURITY_PRINCIPAL, username);env.put(Context.SECURITY_CREDENTIALS, password);try {LdapContext ldapContext = new InitialLdapContext(env, null);log.info("认证成功");// 这里可以改成异常抛出。return ldapContext;} catch (javax.naming.AuthenticationException e) {log.info("认证失败:{}",e.getMessage());} catch (Exception e) {log.info("认证出错:{}",e.getMessage());}return null;
}

3.3 查询域用户信息

public List getUserKey(JSONObject json){JSONObject admin = new JSONObject();admin.put("username", "Aaaaa");admin.put("password", "bbbbbbbb");String name = json.getString("name");log.info("需要查询的ad信息:{}",name);List<JSONObject> resultList = new JSONArray();LdapContext ldapContext = adLogin(admin); //连接到域控if (ldapContext!=null){String company = "";String result = "";try {// 域节点String searchBase = "DC=XXXXXXX,DC=com";// LDAP搜索过滤器类// cn=*name*模糊查询 // cn=name 精确查询// String searchFilter = "(objectClass="+type+")";String searchFilter = "(sAMAccountName="+name+")";    //查询域帐号// 创建搜索控制器SearchControls searchCtls = new SearchControls();String  returnedAtts[]={"description","sAMAccountName","userAccountControl"};        searchCtls.setReturningAttributes(returnedAtts); //设置指定返回的字段,不设置则返回全部//  设置搜索范围 深度searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);// 根据设置的域节点、过滤器类和搜索控制器搜索LDAP得到结果NamingEnumeration answer = ldapContext.search(searchBase, searchFilter,searchCtls); // 初始化搜索结果数为0int totalResults = 0; int rows = 0;while (answer.hasMoreElements()) {// 遍历结果集SearchResult sr = (SearchResult) answer.next();// 得到符合搜索条件的DN++rows;String dn = sr.getName();log.info(dn);Attributes Attrs = sr.getAttributes();// 得到符合条件的属性集if (Attrs != null) {try {for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {Attribute Attr = (Attribute) ne.next();// 得到下一个属性// 读取属性值for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) {company = e.next().toString();JSONObject tempJson = new JSONObject();tempJson.put(Attr.getID(), company.toString());resultList.add(tempJson);}}} catch (NamingException e) {log.info("Throw Exception : " + e.getMessage());}} } log.info("总共用户数:" + rows);} catch (NamingException e) {log.info("Throw Exception : " + e.getMessage());}finally {try{ldapContext.close();}catch (Exception e){e.printStackTrace();}}}return resultList;
}

3.4 重置用户密码

// 管理员重置用户密码,后强制用户首次登录修改密码
public Map<String, String> updateAdPwd(JSONObject json) {String dn = json.getString("dn");//要修改的帐号(这个dn是查询的用户信息里的dn的值,而不是域账号)String password = json.getString("password");//新密码JSONObject admin = new JSONObject();admin.put("username", "aaaaaaa");admin.put("password", "bbbbbbb");Map<String,String> map = new HashMap<String,String>();LdapContext ldapContext = adLoginSSL(admin); //连接636端口域ModificationItem[] mods = new ModificationItem[2];if (ldapContext!=null){try {String newQuotedPassword = "\"" + password + "\"";byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");// unicodePwd:修改的字段,newUnicodePassword:修改的值mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,new BasicAttribute("unicodePwd", newUnicodePassword));mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,new BasicAttribute("pwdLastSet", "0"));  // 首次登录必须修改密码// 修改密码ldapContext.modifyAttributes(dn, mods); map.put("result", "S");map.put("message","成功");}catch (Exception e){ map.put("result","E");map.put("message", "无法重置密码");} finally {try{ldapContext.close();}catch (Exception e){e.printStackTrace();}}} else {log.info("");map.put("result","E");map.put("message", "验证失败");}return map;
}

3.5 域账号解锁

// 表示锁定的字段需要测试,不一定是这个lockoutTime
public Map<String, String> deblocking(JSONObject json) {JSONObject admin = new JSONObject();String dn = json.getString("dn"); //被解锁的帐号(这个dn指的是查询用户信息里的dn的值,不是域账号)admin.put("username","aaaaaa");admin.put("password","bbbbbb");Map<String,String> map = new HashMap<String,String>();LdapContext ldapContext = adLogin(admin);ModificationItem[] mods = new ModificationItem[1];if (ldapContext!=null){try {// 0 表示未锁定,不为 0 表示锁定mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,new BasicAttribute("lockoutTime","0"));// 解锁域帐号ldapContext.modifyAttributes(dn, mods); map.put("result", "S");map.put("message","成功");}catch (Exception e){ map.put("result","E");map.put("message", "解锁失败");}finally {try{ldapContext.close();}catch (Exception e){e.printStackTrace();}}}else {map.put("result","E");map.put("message", "验证失败");}return map;
}

这篇关于【LDAP】LDAP 和 AD 介绍及使用 LDAP 操作 AD 域的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/954415

相关文章

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

C#中lock关键字的使用小结

《C#中lock关键字的使用小结》在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时,其他线程无法访问同一实例的该代码块,下面就来介绍一下lock关键字的使用... 目录使用方式工作原理注意事项示例代码为什么不能lock值类型在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

C# $字符串插值的使用

《C#$字符串插值的使用》本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录$ 字符使用方式创建内插字符串包含不同的数据类型控制内插表达式的格式控制内插表达式的对齐方式内插表达式中使用转义序列内插表达式中使用

flask库中sessions.py的使用小结

《flask库中sessions.py的使用小结》在Flask中Session是一种用于在不同请求之间存储用户数据的机制,Session默认是基于客户端Cookie的,但数据会经过加密签名,防止篡改,... 目录1. Flask Session 的基本使用(1) 启用 Session(2) 存储和读取 Se

Java Thread中join方法使用举例详解

《JavaThread中join方法使用举例详解》JavaThread中join()方法主要是让调用改方法的thread完成run方法里面的东西后,在执行join()方法后面的代码,这篇文章主要介绍... 目录前言1.join()方法的定义和作用2.join()方法的三个重载版本3.join()方法的工作原

Spring AI使用tool Calling和MCP的示例详解

《SpringAI使用toolCalling和MCP的示例详解》SpringAI1.0.0.M6引入ToolCalling与MCP协议,提升AI与工具交互的扩展性与标准化,支持信息检索、行动执行等... 目录深入探索 Spring AI聊天接口示例Function CallingMCPSTDIOSSE结束语

Linux系统之lvcreate命令使用解读

《Linux系统之lvcreate命令使用解读》lvcreate是LVM中创建逻辑卷的核心命令,支持线性、条带化、RAID、镜像、快照、瘦池和缓存池等多种类型,实现灵活存储资源管理,需注意空间分配、R... 目录lvcreate命令详解一、命令概述二、语法格式三、核心功能四、选项详解五、使用示例1. 创建逻

在Java中使用OpenCV实践

《在Java中使用OpenCV实践》用户分享了在Java项目中集成OpenCV4.10.0的实践经验,涵盖库简介、Windows安装、依赖配置及灰度图测试,强调其在图像处理领域的多功能性,并计划后续探... 目录前言一 、OpenCV1.简介2.下载与安装3.目录说明二、在Java项目中使用三 、测试1.测