【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.html

LdapContext 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); 
            // 初始化搜索结果数为0
            int 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/588960.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器数据恢复—多块磁盘离线导致阵列瘫痪,上层lun不可用的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌MSA2000存储&#xff0c;该存储中有一组由8块SAS硬盘&#xff08;其中有一块热备盘&#xff09;组建的RAID5阵列&#xff0c;raid5阵列上层划分了6个lun&#xff0c;均分配给HP-Unix小型机使用&#xff0c;主要数据为oracle数据库和O…

Mac 上安装多版本的 JDK 且实现 自由切换

背景 当前电脑上已经安装了 jdk8; 现在再安装 jdk17。 期望 完成 jdk17 的安装&#xff0c;并且完成 环境变量 的配置&#xff0c;实现自由切换。 前置补充知识 jdk 的安装路径 可以通过查看以下目录中的内容&#xff0c;确认当前已经安装的 jdk 版本。 cd /Library/Java/Java…

解决WordPress无法强制转换https问题

原因&#xff1a;我在用cs的时候&#xff0c;突然老鸟校园网突然断了&#xff0c;客户端cs连不上了&#xff0c;进程也杀不死&#xff0c;cpu占用100%&#xff0c;只能重启&#xff0c;但是重启后我的blog网站打不开了 开始以为是Nginx的问题&#xff0c;重启它说配置出了问题…

基于Springboot的在线博客网站

基于SpringbootVue的在线博客网站的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 博客标签 博客分类 博客列表 图库相册 后台登录 后台首页 用户管理 博客标…

Word文件导出为PDF

Word文件导出为PDF 方法一、使用Word自带另存为PDF功能 打开需要转换为PDF格式的Word文件&#xff0c;依次点击【文件】➡【另存为】➡选择文件保存类型为.PDF 使用这种方法导出的PDF可能存在Word中书签丢失的情况&#xff0c;在导出界面点击&#xff0c;选项进入详细设置 勾…

算法系列--BFS解决拓扑排序

&#x1f495;"请努力活下去"&#x1f495; 作者&#xff1a;Lvzi 文章主要内容&#xff1a;算法系列–算法系列–BFS解决拓扑排序 大家好,今天为大家带来的是算法系列--BFS解决拓扑排序 前言:什么是拓扑排序 拓扑排序–解决有顺序的排序问题(要做事情的先后顺序) …

Vulntarget-a 打靶练习

关于环境配置&#xff0c;这里就不在附上图片和说明了&#xff0c;网上一大堆&#xff0c;这里只针对自己练习&#xff0c;做一个记录。 外网信息收集 利用arpscan工具&#xff0c;扫描了当前局域网中都存在哪些主机&#xff1a; 正常来说我们不应该使用arpscan&#xff0c;而是…

各个硬件的工作原理

目录 前言 主存储器的基本组成 运算器的基本组成 控制器的基本组成 计算机的工作过程 前言 上个小节我们学习了现代计算机的基本构成都是基于冯诺依曼的思想来设计的,那么本章节要来看看主机内部三个组件的细节以及它们之间相互协调工作的. 主存储器的基本组成 这张图非常…

WPF基础应用

WPF参考原文 MVVM介绍 1.常用布局控件 1.1 布局控件 WPF&#xff08;Windows Presentation Foundation&#xff09;提供了多种布局容器来帮助开发者设计用户界面&#xff0c;以下是一些常用的布局&#xff1a; Grid: Grid是最常用的布局容器之一&#xff0c;它允许你通过定…

暗区突围端游海外版|暗区突围怎么玩 新手游玩攻略分享

游戏中健康系统与其它射击游戏有很大区别&#xff0c;根据受伤部位、伤势的不同&#xff0c;会有不同的表现。除了头部之外&#xff0c;其它部位如果损坏后继续受到伤害&#xff0c;那么伤害将会分摊到身体其它部位。在暗区内或者暗区外都可以对角色进行治疗&#xff0c;角色不…

Mybatis进阶(映射关系一对一 )

文章目录 1.基本介绍1.基本说明2.映射方式 2.配置xml方式&#xff08;多表联查&#xff09;1.数据库表设计2.新建子模块1.创建子模块2.创建基本结构 3.MyBatisUtils.java和jdbc.properties和mybatis-config.xml与原来的一致4.IdenCard.java5.Person.java6.IdenCardMapper.java7…

使用 uni-app 开发 iOS 应用的操作步骤

哈喽呀&#xff0c;大家好呀&#xff0c;淼淼又来和大家见面啦&#xff0c;上一期和大家一起探讨了使用uniapp开发iOS应用的优势及劣势之后有许多小伙伴想要尝试使用uniapp开发iOS应用&#xff0c;但是却不懂如何使用uniapp开发iOS应用&#xff0c;所以这一期淼淼就来给你们分享…

TCP三次握手,四次挥手

TCP三次握手 TCP协议 &#xff1a; 1。源端口 &#xff1a;当前的进程端口&#xff0c;2字节 2。目的端口&#xff1a;对方的端口 &#xff0c;2字节 3。序号&#xff1a;客户端或者服务器端生成的随机数 4.确认序号&#xff1a;确认上一次发送给数据对方有没有收到 5.标志…

三数之和细节

这道题看着简单&#xff0c;但是有细节要注意&#xff0c;不能有重复的三元组&#xff0c;我们也不能一开始的时候把重复的元素去除&#xff0c;如果全都是0的话&#xff0c;那么就删除的只剩下一个0了&#xff0c;显然答案是[0,0,0] class Solution { public:vector<vecto…

Jetpack Compose简介

文章目录 Jetpack Compose简介概述声明式UI和命令式UIJetpack Compose和Android View对比Compose API设计原则一切皆为函数组合优于继承单一数据源 Jetpack Compose和Android View关系使用ComposesetContent()源码ComposablePreview Jetpack Compose简介 概述 Jetpack Compos…

用龙梦迷你电脑福珑2.0做web服务器

用龙梦迷你电脑福珑2.0上做web服务器是可行的。已将一个网站源码放到该电脑&#xff0c;在局域网里可以访问网站网页。另外通过在同一局域网内的一台windows10电脑上安装花生壳软件&#xff0c;也可以在外网访问该内网服务器网站网页。该电脑的操作系统属于LAMP。在该电脑上安装…

【python】python标准化考试系统[单项选择题 简易版](源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

docker挂载数据卷-以nginx为例

目录 一、什么是数据卷 二、数据卷的作用 三、如何挂载数据卷 1、创建nginx容器挂载数据卷 2、查看数据卷 3、查看数据卷详情 4、尝试在宿主机修改数据卷 5、查看容器内对应的数据卷目录 6、 访问nginx查看效果 ​​​​​​​一、什么是数据卷 挂载数据卷本质上就是实…

基于springboot实现公司日常考勤系统项目【项目源码+论文说明】

基于springboot实现公司日常考勤系统演示 摘要 目前社会当中主要特征就是对于信息的传播比较快和信息内容的安全问题&#xff0c;原本进行办公的类型都耗费了很多的资源、传播的速度也是相对较慢、准确性不高等许多的不足。这个系统就是运用计算机软件来完成对于企业当中出勤率…

Unity3D初级实战项目之方块跑酷

目录 初始化项目开发环境初始化项目屏幕自适应 游戏UI界面元素布局开始界面UI角色选择&#xff08;商城&#xff09;界面UI游戏界面UI 地图生成算法之菱形布局Resources资源加载代码生成地图菱形布局 地图生成算法之墙壁边界菱形地图双排布局地图瓷砖颜色美化墙壁边界生成 地图…
最新文章