SpringMVC + Ldap 整合,LdapTemplate使用

一、什么是LDAP?

        LDAP(Light Directory Access Portocol),它是基于X.500标准的轻量级目录访问协议。

        目录是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。

        目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好象它的名字一样。

        LDAP目录服务是由目录数据库和一套访问协议组成的系统。

二、LDAP的基本模型

        每一个系统、协议都会有属于自己的模型,LDAP也不例外,在了解LDAP的基本模型之前我们需要先了解几个LDAP的目录树概念:

(一)目录树概念

1. 目录树:在一个目录服务系统中,整个目录信息集可以表示为一个目录信息树,树中的每个节点是一个条目。

2. 条目:每个条目就是一条记录,每个条目有自己的唯一可区别的名称(DN)。

3. 对象类:与某个实体类型对应的一组属性,对象类是可以继承的,这样父类的必须属性也会被继承下来。

4. 属性:描述条目的某个方面的信息,一个属性由一个属性类型和一个或多个属性值组成,属性有必须属性和非必须属性。

(二)DC、UID、OU、CN、SN、DN、RDN

关键字

英文全称

含义

dc

Domain Component

域名的部分,其格式是将完整的域名分成几部分,如域名为example.com变成dc=example,dc=com(一条记录的所属位置)

uid

User Id

用户ID songtao.xu(一条记录的ID)

ou

Organization Unit

组织单位,组织单位可以包含其他各种对象(包括其他组织单元),如“oa组”(一条记录的所属组织)

cn

Common Name

公共名称,如“Thomas Johansson”(一条记录的名称)

sn

Surname

姓,如“许”

dn

Distinguished Name

“uid=songtao.xu,ou=oa组,dc=example,dc=com”,一条记录的位置(唯一)

rdn

Relative dn

相对辨别名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,如“uid=tom”或“cn= Thomas Johansson”

三、了解 ldap objectclass 、Attribute

       LDAP中,一个条目必须包含一个objectClass属性,且需要赋予至少一个值。每一个值将用作一条LDAP条目进行数据存储的模板;模板中包含了一个条目必须被赋值的属性和可选的属性。
      objectClass有着严格的等级之分,最顶层是top和alias。例如,organizationalPerson这个objectClass就隶属于person,而person又隶属于top。

objectClass可分为以下3类:

  • 结构型(Structural) :如person和organizationUnit;
  • 辅助型(Auxiliary) :如extensibeObject;
  • 抽象型(Abstract) :如top,抽象型的objectClass不能直接使用。

在OpenLDAP的schema中定义了很多objectClass,下面列出部分常用的objectClass的名称。
  ● account
  ● alias
  ● dcobject
  ● domain
  ● ipHost
  ● organization
  ● organizationalRole
  ● organizationalUnit
  ● person
  ● organizationalPerson
  ● inetOrgPerson
  ● residentialPerson
  ● posixAccount
  ● posixGroup

属性(Attribute)类似于程序设计中的变量,可以被赋值。在OpenLDAP中声明了许多常用的Attribute(用户也可自己定义Attribute)。常见的Attribute含义如下:
  ● c:国家。
  ● cn:common name,指一个对象的名字。如果指人,需要使用其全名。
  ● dc:domain Component,常用来指一个域名的一部分。
  ● givenName:指一个人的名字,不能用来指姓。
  ● l:指一个地名,如一个城市或者其他地理区域的名字。
  ● mail:电子信箱地址。
  ● o:organizationName,指一个组织的名字。
  ● ou:organizationalUnitName,指一个组织单元的名字。
  ● sn:surname,指一个人的姓。
  ● telephoneNumber:电话号码,应该带有所在的国家的代码。
  ● uid:userid,通常指某个用户的登录名,与Linux系统中用户的uid不同。

        对于不同的objectClass,通常具有一些必设属性值和一些可选属性值。例如,可使用person这个objectClass来表示系统中一个用户的条目,对于系统中用户通常需要有这样一些信息:姓名、电话、密码、描述等。如下图所示,对于person,通过cn和sn设置用户的名和姓,这是必须设置的,而其他属性则是可选的。

下面列出部分常用objectClass要求必设的属性。
  ● account:userid。
  ● organization:o。
  ● person:cn和sn。
  ● organizationalPerson:与person相同。
  ● organizationalRole:cn。
  ● organizationUnit:ou。
  ● posixGroup:cn、gidNumber。
  ● posixAccount:cn、gidNumber、homeDirectory、uid、uidNumber。

四、用户属性userAccountControl的详细解释

        userAccountControl记录了用户的AD账号的很多属性信息,该属性标志是累积性的。若要禁用用户的帐户,请将 UserAccountControl 属性设置为 0x0202 (0x002 + 0x0200)。在十进制中,它是 514 (2 + 512)。

Microsoft官方网站有详尽的解释。

但有时汇出的资料并不完全都是下面的数值,经常会出现514、66048等不在下列列表中的数值。

哈哈。。。看到“该属性标志是累积性的”的意思大家应该明白了。514可以看成是512+2 ,66048可以看成是65536+512

对应最后的解释,所以:

514=512+2=账号存在且关闭

66045=65536+512=密码永不过期+账号正常

属性标志

十六进制值

十进制值

SCRIPT

0x0001

1

ACCOUNTDISABLE

0x0002

2

HOMEDIR_REQUIRED

0x0008

8

LOCKOUT

0x0010

16

PASSWD_NOTREQD

0x0020

32

PASSWD_CANT_CHANGE

0x0040

64

ENCRYPTED_TEXT_PWD_ALLOWED

0x0080

128

TEMP_DUPLICATE_ACCOUNT

0x0100

256

NORMAL_ACCOUNT

0x0200

512

INTERDOMAIN_TRUST_ACCOUNT

0x0800

2048

WORKSTATION_TRUST_ACCOUNT

0x1000

4096

SERVER_TRUST_ACCOUNT

0x2000

8192

DONT_EXPIRE_PASSWORD

0x10000

65536

MNS_LOGON_ACCOUNT

0x20000

131072

SMARTCARD_REQUIRED

0x40000

262144

TRUSTED_FOR_DELEGATION

0x80000

524288

NOT_DELEGATED

0x100000

1048576

USE_DES_KEY_ONLY

0x200000

2097152

DONT_REQ_PREAUTH

0x400000

4194304

PASSWORD_EXPIRED

0x800000

8388608

TRUSTED_TO_AUTH_FOR_DELEGATION

0x1000000

16777216

属性标志说明:

  • SCRIPT - 将运行登录脚本。
  • ACCOUNTDISABLE - 禁用用户帐户。
  • HOMEDIR_REQUIRED - 需要主文件夹。
  • PASSWD_NOTREQD - 不需要密码。
  • PASSWD_CANT_CHANGE - 用户不能更改密码。可以读取此标志,但不能直接设置它。
  • ENCRYPTED_TEXT_PASSWORD_ALLOWED - 用户可以发送加密的密码。
  • TEMP_DUPLICATE_ACCOUNT - 此帐户属于其主帐户位于另一个域中的用户。此帐户为用户提供访问该域的权限,但不提供访问信任该域的任何域的权限。有时将这种帐户称为“本地用户帐户”。
  • NORMAL_ACCOUNT - 这是表示典型用户的默认帐户类型。
  • INTERDOMAIN_TRUST_ACCOUNT - 对于信任其他域的系统域,此属性允许信任该系统域的帐户。
  • WORKSTATION_TRUST_ACCOUNT - 这是运行 Microsoft Windows NT 4.0 Workstation、Microsoft Windows NT 4.0 Server、Microsoft Windows 2000 Professional 或 Windows 2000 Server 并且属于该域的计算机的计算机帐户。
  • SERVER_TRUST_ACCOUNT - 这是属于该域的域控制器的计算机帐户。
  • DONT_EXPIRE_PASSWD - 表示在该帐户上永远不会过期的密码。
  • MNS_LOGON_ACCOUNT - 这是 MNS 登录帐户。
  • SMARTCARD_REQUIRED - 设置此标志后,将强制用户使用智能卡登录。
  • TRUSTED_FOR_DELEGATION - 设置此标志后,将信任运行服务的服务帐户(用户或计算机帐户)进行 Kerberos 委派。任何此类服务都可模拟请求该服务的客户端。若要允许服务进行 Kerberos 委派,必须在服务帐户的userAccountControl 属性上设置此标志。
  • NOT_DELEGATED - 设置此标志后,即使将服务帐户设置为信任其进行 Kerberos 委派,也不会将用户的安全上下文委派给该服务。
  • USE_DES_KEY_ONLY - (Windows 2000/Windows Server 2003) 将此用户限制为仅使用数据加密标准 (DES) 加密类型的密钥。
  • DONT_REQUIRE_PREAUTH - (Windows 2000/Windows Server 2003) 此帐户在登录时不需要进行 Kerberos 预先验证。
  • PASSWORD_EXPIRED - (Windows 2000/Windows Server 2003) 用户的密码已过期。
  • TRUSTED_TO_AUTH_FOR_DELEGATION - (Windows 2000/Windows Server 2003) 允许该帐户进行委派。这是一个与安全相关的设置。应严格控制启用此选项的帐户。此设置允许该帐户运行的服务冒充客户端的身份,并作为该用户接受网络上其他远程服务器的身份验证。

五、spring mvc 整合

spring-ldap github源码:GitHub - spring-projects/spring-ldap: Spring LDAP

spring-ldap 官方文档Spring LDAP Reference

1、添加依赖:

<dependency>
  <groupId>org.springframework.ldap</groupId>
  <artifactId>spring-ldap-core</artifactId>
  <version>2.3.2.RELEASE</version>
</dependency>

2、修改Spring配置文件

<!--配置Ldap数据源-->
<bean  id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
	<property name="url" value="ldap://${ldap.host}:${ldap.port}" />
	<property name="base" value="${ldap.baseDn}" />
	<property name="userDn" value="${ldap.userDn}" />
	<property name="password" value="${ldap.passwd}" />
</bean>
<!--配置Ldap pool连接池-->
<bean id="poolingContextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource">
	<property name="contextSource" ref="contextSource" />
	<property name="dirContextValidator" ref="dirContextValidator" />
	<property name="maxActive" value="20" />
	<property name="maxTotal" value="100" />
	<property name="maxIdle" value="10" />
	<property name="minIdle" value="5" />
	<property name="maxWait" value="5000" />
	<property name="testOnBorrow" value="true" />
	<property name="testWhileIdle" value="true" />
</bean>
<bean id="dirContextValidator" class="org.springframework.ldap.pool.validation.DefaultDirContextValidator" />
<!--配置LdapTemplate,类似于JDBCTemplete-->
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate" >
	<constructor-arg>
		<ref bean="contextSource" />
	</constructor-arg>
</bean>

新增一个properties,存储连接ldap基础信息:

ldap.host=192.168.1.153
ldap.port=389
ldap.userDn=cn=administrator,cn=Users,DC=inter-**,DC=net
ldap.passwd=******
ldap.baseDn=DC=inter-**,DC=net

3、编写代码

import com.alibaba.fastjson.JSON;
import com.lxhr.common.util.string.GetterUtil;
import com.lxhr.ldap.entity.LdapUser;
import com.lxhr.ldap.mapper.LdapGroupAttributeMapper;
import com.lxhr.ldap.mapper.LdapPersonAttributeMapper;
import com.lxhr.ldap.pojo.Group;
import com.lxhr.ldap.pojo.Person;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
import javax.naming.ldap.LdapName;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * ldap测试类  https://docs.spring.io/spring-ldap/docs/2.3.2.RELEASE/reference/
 * 514=512+2=账号存在且关闭
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:conf/spring.xml","classpath:conf/spring-mybatis.xml","classpath:conf/spring-mongodb.xml"})
public class LdapTest {

    public static final String BASE_DN = "DC=inter-**,DC=net";

    int UF_ACCOUNTDISABLE = 0x0002;

    int UF_PASSWD_NOTREQD = 0x0020;

    int UF_PASSWD_CANT_CHANGE = 0x0040;

    int UF_NORMAL_ACCOUNT = 0x0200;

    int UF_DONT_EXPIRE_PASSWD = 0x10000;

    int UF_PASSWORD_EXPIRED = 0x800000;

    @Autowired
    private LdapTemplate ldapTemplate;

    /**
     * 新增分组
     */
    @Test
    public void saveGroup() {
        Map<String, String> map = new HashMap<>();
        map.put("ou","测试test部门");
        String pou = "HR集团,青岛";
        this.insertOu(map, pou);
    }

    private void insertOu(Map<String, String> map, String pou) {
        Attributes ouAttributes=new BasicAttributes();
        BasicAttribute ouBasicAttribute=new BasicAttribute("objectclass");
        ouBasicAttribute.add("top");
        ouBasicAttribute.add("organizationalUnit");
        ouAttributes.put(ouBasicAttribute);
        for(String str:map.keySet()){
            if(StringUtils.isNotBlank(map.get(str))) {
                ouAttributes.put(str,map.get(str));
            }
        }

//        LdapName ldapName = LdapNameBuilder.newInstance().add("ou","HR集团").add("ou","事业部").add("ou", GetterUtil.getString(map.get("ou"))).build();
        LdapNameBuilder ldapNameBuilder = LdapNameBuilder.newInstance();
        if(StringUtils.isNotBlank(pou)) {
            String[] ouPNameStr = pou.split(",");
            for(String ouP:ouPNameStr) {
                ldapNameBuilder.add("ou", ouP);
            }
        }
        ldapNameBuilder.add("ou", GetterUtil.getString(map.get("ou")));
        LdapName ldapName =  ldapNameBuilder.build();
        ldapTemplate.bind(ldapName,null, ouAttributes);
    }

    /**
     * 新增用户
     */
    @SneakyThrows
    @Test
    public void bingPerson() {

        LdapName ldapName = LdapNameBuilder.newInstance().add("ou", "HR集团").add("cn", "LX011616").build();

        // 基类设置
        BasicAttribute ocattr = new BasicAttribute("objectClass");
        ocattr.add("top");
        ocattr.add("person");
        ocattr.add("organizationalPerson");
        ocattr.add("user");

        // 用户属性
        Attributes attrs = new BasicAttributes();
        attrs.put(ocattr);
        // 其他属性
        attrs.put("cn", "LX011616");
        attrs.put("displayName", "张宝宝");
        attrs.put("givenName", "宝宝");
        attrs.put("sn", "张");
        attrs.put("userPassword", "qwe123+++");

//        String newPassword = "qwe123+++";
//        String newQuotedPassword = "\"" + newPassword + "\"";
//        byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
//        attrs.put("unicodePwd", newUnicodePassword.toString());

//        attrs.put("userAccountControl", "544");
        attrs.put("sAMAccountName", "LX011616");
        attrs.put("userPrincipalName", "LX011616");
        attrs.put("userAccountControl", Integer.toString(UF_NORMAL_ACCOUNT+UF_PASSWD_NOTREQD));
        attrs.put("description", "HR集团");

        ldapTemplate.bind(ldapName, null, attrs);

//        LdapUser ldapUser = new LdapUser();
//        ldapUser.setId(ldapName);
//        ldapUser.setAccountName("LX011617");
//        ldapUser.setCommonName("LX011617");
//        ldapUser.setSurName("张");
//        ldapUser.setGivenName("宝宝");
//        ldapUser.setUserPassword("qwe123+++");
//        ldapUser.setDisplayName("张宝宝");
//        ldapUser.setUserAccountControl(Integer.toString(UF_NORMAL_ACCOUNT+UF_PASSWD_NOTREQD));
//        ldapUser.setDescription("HR集团");
//        ldapUser.setDepartment("HR集团");
//        ldapTemplate.create(ldapUser);
    }

    private byte[] unicodePwd(String password) {

        String newQuotedPassword = "\"" +  password + "\"";
        try {
            byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
            return newUnicodePassword;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 新增用户
     */
    @Test
    public void savePerson() {
        Map<String, String> map = new HashMap<>();
        map.put("cn","test");
        map.put("sn","est");
        map.put("displayName","test");
        map.put("name","test");
        map.put("userPassword","qwe123+++");
//        map.put("userAccountControl", "514");
        map.put("userAccountControl", "544");
        map.put("department","事业部");
        map.put("description","HR集团,事业部");
        this.insertCn(map);
    }

    public void insertCn(Map<String, String> map) {
        Attributes ouAttributes=new BasicAttributes();
        BasicAttribute ouBasicAttribute=new BasicAttribute("objectclass");
        ouBasicAttribute.add("top");
        ouBasicAttribute.add("person");
        ouBasicAttribute.add("organizationalPerson");
        ouBasicAttribute.add("user");
        ouAttributes.put(ouBasicAttribute);
        for(String str:map.keySet()){
            if(StringUtils.isNotBlank(map.get(str))) {
                ouAttributes.put(str,map.get(str));
            }
        }

//        LdapName ldapName = LdapNameBuilder.newInstance().add("cn", GetterUtil.getString(map.get("cn"))).build();
        LdapNameBuilder ldapNameBuilder = LdapNameBuilder.newInstance();
        ldapNameBuilder.add("ou", "HR集团");
        ldapNameBuilder.add("ou", "事业部");
        ldapNameBuilder.add("cn", GetterUtil.getString(map.get("cn")));
        LdapName ldapName = ldapNameBuilder.build();
        ldapTemplate.bind(ldapName,null,ouAttributes);
    }

    /**
     * 查找
     */
    @Test
    public void find() {
        //精确查找
        System.out.println(ldapTemplate.lookup("OU=HR集团"));
        System.out.println(ldapTemplate.lookup("OU=HR集团", new LdapGroupAttributeMapper()));
    }

    /**
     * 获取所有 internal人员
     * ou=Internal,ou=People
     */
    @Test
    public void listUsers(){
        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectClass", "person"));
        filter.and(new WhitespaceWildcardsFilter("cn","LX"));

        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);

        //查询所有内部人员
        List<Person> users = ldapTemplate.search("ou=HR集团", filter.encode(), controls, new LdapPersonAttributeMapper());
//        默认 SUBTREE_SCOPE
//        List<Person> users = ldapTemplate.search("ou=HR集团", filter.encode(), new LdapPersonAttributeMapper());
        for (Person user: users ) {
            System.out.println(JSON.toJSON(user));
        }
    }

    /**
     * 根据userid 查找单个人员
     */
    @Test
    public void findUser(){
        DirContextAdapter obj = (DirContextAdapter) ldapTemplate.lookup("cn=test,ou=测试,ou=集团");//BASE_DC 不用填
        System.out.println(obj);
    }

    /**
     * 模糊查找
     */
    @Test
    public void findByName() {
        LdapQuery query = LdapQueryBuilder.query()
                .where("objectclass").is("person")
                .and("cn").whitespaceWildcardsLike("测试");

        ldapTemplate.search(query, nameClassPair -> {
            // CN=测试api01,OU=用户,OU=总部
            System.out.println(nameClassPair.getName());
            // CN=测试api01,OU=用户,OU=总部,OU=集团,DC=inter-credit,DC=net
            System.out.println(nameClassPair.getNameInNamespace());
            // {samaccounttype=sAMAccountType: 805306368, primarygroupid=primaryGroupID: 513, objectclass=objectClass: top, person, organizationalPerson, user, badpasswordtime=badPasswordTime: 0, userpassword=userPassword: [B@71b1a49c, objectcategory=objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=inter-credit,DC=net, cn=cn: 测试api01, useraccountcontrol=userAccountControl: 546, dscorepropagationdata=dSCorePropagationData: 16010101000000.0Z, codepage=codePage: 0, distinguishedname=distinguishedName: CN=测试api01,OU=用户,OU=总部,OU=集团,DC=inter-credit,DC=net, whenchanged=whenChanged: 20210729070624.0Z, whencreated=whenCreated: 20210729070624.0Z, pwdlastset=pwdLastSet: 0, logoncount=logonCount: 0, accountexpires=accountExpires: 9223372036854775807, lastlogoff=lastLogoff: 0, objectguid=objectGUID: g��D��A��s���, sn=sn: 测, lastlogon=lastLogon: 0, usnchanged=uSNChanged: 548575, usncreated=uSNCreated: 548574, objectsid=objectSid:         �qL�,c�q.'�  , countrycode=countryCode: 0, samaccountname=sAMAccountName: $M71000-0PD84RTVIFL7, instancetype=instanceType: 4, badpwdcount=badPwdCount: 0, name=name: 测试api01}
            System.out.println(((SearchResult)nameClassPair).getAttributes());
        });
    }

    /**
     * 模糊查找
     */
    @Test
    public void findGroupByName() {
        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("ou","市场组"));
        LdapNameBuilder ldapNameBuilderQuery = LdapNameBuilder.newInstance();
        ldapNameBuilderQuery.add("ou","HR集团");
        LdapName ldapNameQuery = ldapNameBuilderQuery.build();
        //查询所有内部人员
        try {
            List<Group> list = ldapTemplate.search(ldapNameQuery, filter.encode(), new LdapGroupAttributeMapper());
            for (Group group: list ) {
                System.out.println(JSON.toJSON(group));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            SearchControls controls = new SearchControls();
            controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
            List<Group> groups = new ArrayList<>();
            NamingEnumeration<SearchResult> sr = ldapTemplate.getContextSource().getReadWriteContext().search(ldapNameQuery, filter.encode(), controls);
            while(sr.hasMoreElements()){
                Group group = new Group();
                SearchResult result = sr.next();
                NamingEnumeration<? extends Attribute> attrs = result.getAttributes().getAll();
                while(attrs.hasMore()){
                    Attribute attr= attrs.next();
                    System.out.println(attr.getID() + "~~~~~~" + attr.get());
                    if("name".equals(attr.getID())){
                        group.setName( attr.get().toString());
                    }
                    if("cn".equals(attr.getID())){
                        group.setDepartmentCd( attr.get().toString());
                    }
                    if("description".equals(attr.getID())){
                        group.setDepartmentPName( attr.get().toString());
                    }
                }
                groups.add(group);
            }
            System.out.println(JSON.toJSON(groups));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 根据部门编号o,查找部门
     */
    @Test
    public void findDept(){
        DirContextAdapter obj = (DirContextAdapter) ldapTemplate.lookup("ou=测试,ou=集团");//BASE_DC 不用填
        System.out.println(obj);
    }

    @Test
    public void rebingUser() {
        Attributes ouAttributes=new BasicAttributes();
        BasicAttribute ouBasicAttribute=new BasicAttribute("objectclass");
        ouBasicAttribute.add("top");
        ouBasicAttribute.add("person");
        ouBasicAttribute.add("organizationalPerson");
        ouBasicAttribute.add("user");
        ouAttributes.put(ouBasicAttribute);
        ouAttributes.put("cn", "LX011617");
        ldapTemplate.rebind("cn=LX011617,ou=HR集团", null, ouAttributes);
    }

    /**
     * 删除
     */
    @Test
    public void unbingUser() {
//        ldapTemplate.unbind("cn=测试api01,ou=测试,ou=集团");
        ldapTemplate.unbind("ou=市场组,ou=HR集团");
    }

    /**
     * 修改信息
     */
    @SneakyThrows
    @Test
    public void updateUser() {
        String newPassword = "qwe123+++";
        String newQuotedPassword = "\"" + newPassword + "\"";
        byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");

        ldapTemplate.modifyAttributes("cn=LX011616,ou=HR集团", new ModificationItem[] {
//                    new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("cn", "")),
//                    new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("displayName", "")),
//                    new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("sn","")),
//                    new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("mail", "LX011617@inter.com")),
//                    new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("telephoneNumber", "")),
                new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl", "512")),
//                new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword.toString())) //需要ssl连接 https://docs.microsoft.com/zh-CN/troubleshoot/windows/win32/change-windows-active-directory-user-password
        });
    }

    /**
     * 修改信息
     */
    @Test
    public void modifyAttributes() {
        DirContextOperations context = ldapTemplate
                .lookupContext("cn=测试api01,ou=测试,ou=集团");
        context.setAttributeValue("givenName", "测试");
        ldapTemplate.modifyAttributes(context);
    }

    /**
     * 重命名、移动
     */
    @Test
    public void rename() {
//        ldapTemplate.rename("cn=LX011617,ou=HR集团", "cn=LX011617,ou=青岛,ou=HR集团");
        ldapTemplate.rename("ou=测试test部门", "ou=测试test新部门");
    }

}

实体类 LdapUser:

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.DnAttribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;

import javax.naming.Name;

@Entry(objectClasses = {"user", "organizationalPerson", "person", "top"})
public class LdapUser {

    @Id
    @JsonIgnore
    private Name id;

    @DnAttribute(value = "CN", index = 0)
    @Attribute(name = "sAMAccountName")
    private String accountName;

    @Attribute(name = "cn")
    private String commonName;

    @Attribute(name = "sn")
    private String surName;

    @Attribute(name = "givenName")
    private String givenName;

    @Attribute(name = "distinguishedName")
    private String dn;

    @Attribute(name = "userPassword")
    private String userPassword;

    @Attribute(name = "displayName")
    private String displayName;

    @Attribute(name = "department")
    private String department;

    @Attribute(name = "userAccountControl")
    private String userAccountControl;

    @Attribute(name = "mobile")
    private String mobile;

    @Attribute(name = "mail")
    private String email;

    @Attribute(name = "description")
    private String description;

    //getter、settter .....
}

        实现AttributesMapper只是从中获得所需的属性值Attributes并返回它。在内部,LdapTemplate遍历找到的所有条目,AttributesMapper为每个条目调用给定的条目,并将结果收集到列表中。

LdapGroupAttributeMapper:

import com.lxhr.ldap.pojo.Group;
import org.springframework.ldap.core.AttributesMapper;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

/**
 * 将ldap返回的结果,转成指定对象
 */
public class LdapGroupAttributeMapper implements AttributesMapper {

    @Override
    public Group mapFromAttributes(Attributes attributes) throws NamingException {
        Group group = new Group();
        if(attributes.get("name") != null){
            group.setName( attributes.get("name").get().toString());
        }
        if(attributes.get("cn") != null){
            group.setDepartmentCd( attributes.get("cn").get().toString());
        }
        if(attributes.get("description") != null){
            group.setDepartmentPName( attributes.get("description").get().toString());
        }
        return group;
    }
}

LdapPersonAttributeMapper: 

import com.lxhr.ldap.pojo.Person;
import org.springframework.ldap.core.AttributesMapper;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

/**
 * 将ldap返回的结果,转成指定对象
 */
public class LdapPersonAttributeMapper implements AttributesMapper {

    /**
     * 将单个Attributes转成单个对象
     * @param attrs
     * @return
     * @throws NamingException
     */
    public Person mapFromAttributes(Attributes attrs) throws NamingException {
        Person user  = new Person();

        if(attrs.get("uid") != null){
            user.setUid( attrs.get("uid").get().toString());
        }
        if(attrs.get("cn") != null){
            user.setCn( attrs.get("cn").get().toString());
        }
        if(attrs.get("sn") != null){
            user.setSn( attrs.get("sn").get().toString());
        }
        if(attrs.get("name") != null){
            user.setName( attrs.get("name").get().toString());
        }
        if(attrs.get("givenName") != null){
            user.setGivenName( attrs.get("givenName").get().toString());
        }
        if(attrs.get("displayName") != null){
            user.setDisplayName( attrs.get("displayName").get().toString());
        }
        if(attrs.get("company") != null){
            user.setCompany( attrs.get("company").get().toString());
        }
        if(attrs.get("department") != null){
            user.setDepartment( attrs.get("department").get().toString());
        }
        if(attrs.get("mobile") != null){
            user.setMobile( attrs.get("mobile").get().toString());
        }
        if(attrs.get("mail") != null){
            user.setMail( attrs.get("mail").get().toString());
        }
        if(attrs.get("distinguishedName") != null){
            user.setDistinguishedName(attrs.get("distinguishedName").get().toString());
        }
        if(attrs.get("modifyTimestamp") != null){
            user.setModifyTimestamp(attrs.get("modifyTimestamp").get().toString());
        }
        if(attrs.get("description") != null){
            user.setDescription(attrs.get("description").get().toString());
        }
        return user;
    }
}

Group: 

import javax.naming.Name;
import java.io.Serializable;

public class Group implements Serializable {

    private Name dn;
    private String name;
    private String departmentCd;
    private String departmentName;
    private String departmentPName;

    //getter、setter ......
}

Person: 

import javax.naming.Name;
import java.io.Serializable;

public class Person implements Serializable {

    private Name dn;

    private String uid;
    private String cn;
    //first name
    private String givenName;
    //last name
    private String sn;
    private String name;
    private String displayName;
    private String distinguishedName;
    private String company;
    private String department;
    private String userPassword;
    private String sAMAccountName;
    private String userAccountControl;
    private String userPrincipalName;
    private String mail;
    private String mobile;
    private String description;
    private String modifyTimestamp;

    //getter、setter ......
}

如果想要通过 LDAP 更改 Windows Active Directory 和 LDS 用户密码,客户端必须具有到服务器的 128 位传输层安全性 (TLS) /Secure Socket Layer (SSL) 连接。

通过 LDAP Windows Active Directory 用户密码 - Application Developer | Microsoft Docs

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值