AD域-入门

1. 简介

​ AD域(Active Directory),在企业网络信息化建设中,经常会使用AD域(Active Directory Domain)来统一管理网络中的PC终端。在AD域中,DC(域控制器)包含了由这个域的账户、密码、属于这个域的计算机等信息构成的数据库。通过AD域可以增删改查所有的域用户信息。

​ AD域中的用户信息以对象的形式存储,对象中包含了名称,邮件,电话号码,密码等等属性。

​ AD域命名空间使用的DNS架构,通过DNS来解析主机的ip,AD域的命名使用DNS格式,例如aacopy.cn。

​ DC(域控制器)使用windows服务器搭建

2. 安装AD域控服务器

windows镜像版本:cn_windows_server_2012_r2_vl_with_update_x64_dvd_4051059.iso

2.1 安装虚拟机

参考文章vm安装windows_server

2.2 安装DNS(非必要)

  • 网络设置DNS指向自己127.0.0.1

  • 添加角色和功能

  • 点击下一步

  • 安装类型和服务器选择都直接点击下一步
  • 服务器角色勾选DNS服务器

  • 连续点下一步
  • 到确认步骤,点击安装

  • 安装完成后关闭

2.3 安装AD域服务

  • 添加角色和功能

  • 一直下一步到服务器角色
  • 添加AD服务

  • 一直下一步到确认,点击安装

  • 安装完成,升级为域控制器

  • 添加新林

image-20230129143306040

  • 设置密码,对密码强度有要求

  • 下一步

  • 一直到先决条件检查,都直接点下一步,administrator账号要有密码,不然通不过,所以创建虚拟机的时候直接用administrator账号

  • 点击安装,安装完成后会自动重启

3. 管理AD域中的账号

  • 点击工具,选择AD 用户和计算机

  • 创建组织OU

  • 组织单位(OU)可以建多级目录

  • 添加用户

  • 配置用户属性

  • 创建多个用户

4. java操作AD域

4.1 LDAP

LDAP协议可以操作AD域中的数据

4.2 java操作AD域

先把AD域服务器的防火墙关掉

编写测试用例demo对AD域中的用户做增删改查操作

初始化ldap连接,执行结束关闭连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AdTest {

private static InitialLdapContext initialLdapContext = null;

@BeforeAll
static void init() throws Exception {
Hashtable<String, String> environment = new Hashtable<>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, "administrator@aacopy.cn");
environment.put(Context.SECURITY_CREDENTIALS, "123456");
environment.put(Context.PROVIDER_URL, "ldap://192.168.80.130:389/");
initialLdapContext = new InitialLdapContext(environment, null);
}

@AfterAll
static void destroy() throws Exception {
initialLdapContext.close();
}
}

4.2.1 查询用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    /**
* 查询
*/
@Test
void search() throws Exception {
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// 设置返回的属性,不设置返回所有属性
// searchControls.setReturningAttributes(new String[]{"cn", "name", "sAMAccountName", "mail", "displayName", "userPrincipalName", "distinguishedName"});

NamingEnumeration<SearchResult> searchResult = initialLdapContext.search("OU=Hefei,DC=AACOPY,DC=CN", "objectClass=user", searchControls);

while (searchResult.hasMore()) {
System.out.println("=====================================");
SearchResult result = searchResult.next();
Attributes attributes = result.getAttributes();
NamingEnumeration<? extends Attribute> attributesAll = attributes.getAll();
while (attributesAll.hasMore()) {
Attribute attribute = attributesAll.next();
System.out.println("ID = " + attribute.getID() + ", VALUE = " + attribute.get());
}
}
}

执行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
=====================================
ID = objectCategory, VALUE = CN=Person,CN=Schema,CN=Configuration,DC=aacopy,DC=cn
ID = whenCreated, VALUE = 20230129075917.0Z
ID = badPwdCount, VALUE = 0
ID = codePage, VALUE = 0
ID = pager, VALUE = 222
ID = mail, VALUE = swk@aacopy.cn
ID = objectGUID, VALUE = ڵ��ER�B�*��n��H
ID = instanceType, VALUE = 4
ID = objectSid, VALUE = ��%�ix�z�Q
ID = st, VALUE = 222
ID = badPasswordTime, VALUE = 0
ID = dSCorePropagationData, VALUE = 16010101000000.0Z
ID = ipPhone, VALUE = 555
ID = objectClass, VALUE = top
ID = company, VALUE = 12
ID = name, VALUE = 孙悟空
ID = description, VALUE = 斗战胜佛
ID = sn, VALUE = 孙
ID = initials, VALUE = mk
ID = telephoneNumber, VALUE = 123456789
ID = userAccountControl, VALUE = 512
ID = primaryGroupID, VALUE = 513
ID = postalCode, VALUE = 2132342
ID = accountExpires, VALUE = 9223372036854775807
ID = lastLogon, VALUE = 0
ID = lastLogoff, VALUE = 0
ID = wWWHomePage, VALUE = swk.cn
ID = uSNChanged, VALUE = 12811
ID = physicalDeliveryOfficeName, VALUE = 御马监
ID = co, VALUE = 中国
ID = cn, VALUE = 孙悟空
ID = homePhone, VALUE = 111
ID = title, VALUE = 3
ID = logonCount, VALUE = 0
ID = mobile, VALUE = 333
ID = sAMAccountType, VALUE = 805306368
ID = givenName, VALUE = 悟空
ID = uSNCreated, VALUE = 12772
ID = displayName, VALUE = 孙悟空
ID = userPrincipalName, VALUE = wk.sun@aacopy.cn
ID = pwdLastSet, VALUE = 133194527579076933
ID = whenChanged, VALUE = 20230129085253.0Z
ID = department, VALUE = 2
ID = streetAddress, VALUE = 2333444
ID = facsimileTelephoneNumber, VALUE = 444
ID = countryCode, VALUE = 156
ID = l, VALUE = 333
ID = distinguishedName, VALUE = CN=孙悟空,OU=信息技术开发部,OU=Hefei,DC=aacopy,DC=cn
ID = postOfficeBox, VALUE = 2312333
ID = info, VALUE = 666
ID = c, VALUE = CN
ID = sAMAccountName, VALUE = wk.sun
=====================================
ID = objectCategory, VALUE = CN=Person,CN=Schema,CN=Configuration,DC=aacopy,DC=cn
ID = whenCreated, VALUE = 20230129080727.0Z
ID = badPwdCount, VALUE = 0
ID = codePage, VALUE = 0
ID = pager, VALUE = 222
ID = mail, VALUE = 1212312
ID = objectGUID, VALUE = ��o�N�G�]c�s3�b
ID = instanceType, VALUE = 4
ID = objectSid, VALUE = ��%�ix�z�R
ID = st, VALUE = 32412
ID = badPasswordTime, VALUE = 0
ID = dSCorePropagationData, VALUE = 16010101000000.0Z
ID = ipPhone, VALUE = 555
ID = objectClass, VALUE = top
ID = name, VALUE = 猪八戒
ID = description, VALUE = 天蓬元帅
ID = sn, VALUE = 猪
ID = initials, VALUE = pig
ID = telephoneNumber, VALUE = 1232
ID = userAccountControl, VALUE = 512
ID = primaryGroupID, VALUE = 513
ID = postalCode, VALUE = 2312312
ID = accountExpires, VALUE = 9223372036854775807
ID = lastLogon, VALUE = 0
ID = lastLogoff, VALUE = 0
ID = wWWHomePage, VALUE = 313222
ID = uSNChanged, VALUE = 12792
ID = physicalDeliveryOfficeName, VALUE = 办公室
ID = co, VALUE = 中国
ID = cn, VALUE = 猪八戒
ID = homePhone, VALUE = 111
ID = logonCount, VALUE = 0
ID = mobile, VALUE = 333
ID = sAMAccountType, VALUE = 805306368
ID = givenName, VALUE = 八戒
ID = uSNCreated, VALUE = 12783
ID = displayName, VALUE = 猪八戒
ID = userPrincipalName, VALUE = bj.zhu@aacopy.cn
ID = pwdLastSet, VALUE = 133194532470495533
ID = whenChanged, VALUE = 20230129080825.0Z
ID = streetAddress, VALUE = 123123
ID = facsimileTelephoneNumber, VALUE = 444
ID = countryCode, VALUE = 156
ID = l, VALUE = 12312313
ID = distinguishedName, VALUE = CN=猪八戒,OU=信息技术开发部,OU=Hefei,DC=aacopy,DC=cn
ID = postOfficeBox, VALUE = 12312
ID = info, VALUE = 666
ID = c, VALUE = CN
ID = sAMAccountName, VALUE = bj.zhu

进程已结束,退出代码为 0

4.2.2 新增用户

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 新增用户
*/
@Test
void add() throws Exception {
Attributes attributes = new BasicAttributes(true);
attributes.put("objectClass", "user");
attributes.put("samAccountName", "zhangsan");
attributes.put("displayName", "zhangsan");
attributes.put("userPrincipalName", "zhangsan@aacopy.cn");
initialLdapContext.createSubcontext("CN=zhangsan,OU=信息技术开发部,OU=Hefei,DC=AACOPY,DC=CN", attributes);
System.out.println("新增成功");
}

4.2.3 删除用户

1
2
3
4
5
6
7
8
9
/**
* 删除用户
*/
@Test
void delete() throws Exception {
String dn = "CN=zhangsan,OU=信息技术开发部,OU=Hefei,DC=AACOPY,DC=CN";
initialLdapContext.destroySubcontext(dn);
System.out.println("删除成功");
}

4.2.4 修改用户信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    /**
* 修改用户属性
*/
@Test
void edit() throws Exception {
String dn = "CN=孙悟空,OU=信息技术开发部,OU=Hefei,DC=aacopy,DC=cn";
ModificationItem[] modificationItems = new ModificationItem[1];
Attribute attribute = new BasicAttribute("description", "斗战胜佛");
// 添加属性
// modificationItems[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attribute);
// 删除属性
// modificationItems[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attribute);
// 修改属性
modificationItems[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attribute);

initialLdapContext.modifyAttributes(dn, modificationItems);
System.out.println("修改成功");
}

4.3 AD域中的时间

在windows中的ad域中的时间和java的时间标准不一样,不能直接转换,比如:用户最后修改密码的时间:ID = pwdLastSet, VALUE = 133194527579076933

这个long型的数字133194527579076933,表示当前时间与1601-01-01 00:00:00的时间差,java的时间是从1970-01-01 00:00:00开始计算的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 测试时间
*/
@Test
void testTime() {
/**
* Unix 时间 1970-01-01 00:00:00 与 Win32 FileTime 时间 1601-01-01 00:00:00
* 毫秒数差
*/
long UNIX_FILETIME_DIFF = 11644473600000L;

/**
* Win32 FileTime 采用 100ns 为单位的,定义 100ns 与 1ms 的倍率
*/
int MILLISECOND_MULTIPLE = 10000;

// long转为java的date
Date date3 = new Date(133194527579076933L / MILLISECOND_MULTIPLE - UNIX_FILETIME_DIFF);
System.out.println(DateUtil.formatDateTime(date3));

// date 转long
long time = (UNIX_FILETIME_DIFF + date3.getTime()) * MILLISECOND_MULTIPLE;
System.out.println(time);

}

测试结果

2023-01-29 15:59:17
133194527579070000

4.4 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package cn.aacopy.test.simpleboot;

import cn.hutool.core.date.DateUtil;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
import java.util.Date;
import java.util.Hashtable;

/**
* @author iseven.yang
* @date 2023/1/28 15:11
*/
public class AdTest {

private static InitialLdapContext initialLdapContext = null;

@BeforeAll
static void init() throws Exception {
Hashtable<String, String> environment = new Hashtable<>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, "administrator@aacopy.cn");
environment.put(Context.SECURITY_CREDENTIALS, "123456");
environment.put(Context.PROVIDER_URL, "ldap://192.168.80.130:389/");
initialLdapContext = new InitialLdapContext(environment, null);
}

@AfterAll
static void destroy() throws Exception {
initialLdapContext.close();
}

/**
* 查询
*/
@Test
void search() throws Exception {
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// 设置返回的属性,不设置返回所有属性
// searchControls.setReturningAttributes(new String[]{"cn", "name", "sAMAccountName", "mail", "displayName", "userPrincipalName", "distinguishedName"});

NamingEnumeration<SearchResult> searchResult = initialLdapContext.search("OU=Hefei,DC=AACOPY,DC=CN", "objectClass=user", searchControls);

while (searchResult.hasMore()) {
System.out.println("=====================================");
SearchResult result = searchResult.next();
Attributes attributes = result.getAttributes();
NamingEnumeration<? extends Attribute> attributesAll = attributes.getAll();
while (attributesAll.hasMore()) {
Attribute attribute = attributesAll.next();
System.out.println("ID = " + attribute.getID() + ", VALUE = " + attribute.get());
}
}
}

/**
* 新增用户
*/
@Test
void add() throws Exception {
Attributes attributes = new BasicAttributes(true);
attributes.put("objectClass", "user");
attributes.put("samAccountName", "zhangsan");
attributes.put("displayName", "zhangsan");
attributes.put("userPrincipalName", "zhangsan@aacopy.cn");
initialLdapContext.createSubcontext("CN=zhangsan,OU=信息技术开发部,OU=Hefei,DC=AACOPY,DC=CN", attributes);
System.out.println("新增成功");
}

/**
* 删除用户
*/
@Test
void delete() throws Exception {
String dn = "CN=zhangsan,OU=信息技术开发部,OU=Hefei,DC=AACOPY,DC=CN";
initialLdapContext.destroySubcontext(dn);
System.out.println("删除成功");
}

/**
* 修改用户属性
*/
@Test
void edit() throws Exception {
String dn = "CN=孙悟空,OU=信息技术开发部,OU=Hefei,DC=aacopy,DC=cn";
ModificationItem[] modificationItems = new ModificationItem[1];
Attribute attribute = new BasicAttribute("description", "斗战胜佛");
// 添加属性
// modificationItems[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attribute);
// 删除属性
// modificationItems[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attribute);
// 修改属性
modificationItems[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attribute);

initialLdapContext.modifyAttributes(dn, modificationItems);
System.out.println("修改成功");
}

/**
* 测试时间
*/
@Test
void testTime() {
/**
* Unix 时间 1970-01-01 00:00:00 与 Win32 FileTime 时间 1601-01-01 00:00:00
* 毫秒数差
*/
long UNIX_FILETIME_DIFF = 11644473600000L;

/**
* Win32 FileTime 采用 100ns 为单位的,定义 100ns 与 1ms 的倍率
*/
int MILLISECOND_MULTIPLE = 10000;

// long转为java的date
Date date3 = new Date(133194527579076933L / MILLISECOND_MULTIPLE - UNIX_FILETIME_DIFF);
System.out.println(DateUtil.formatDateTime(date3));

// date 转long
long time = (UNIX_FILETIME_DIFF + date3.getTime()) * MILLISECOND_MULTIPLE;
System.out.println(time);

}
}