LDAP介绍

介绍

LDAP是域的一种管理系统。
LDAP的存储结构为树状结构,由父节点、子节点、叶子节点组成。

概念

Entry

条目,LDAP系统中最基本的颗粒,类似于数据库的记录。通常对LDAP的增删查改是以条目为基本对象。

dn

相当于条目的id,通常由包含ou、cn、dc等组成,例如:cn=test_test_1_6_210,ou=test3,ou=test2,ou=test_group,ou=Users。LDAP能通过dn清晰表示出该条目在LDAP系统中的位置。

Attribute

条目的属性

用户属性

userAccountControl

属性标志

十六进制值

十进制值

说明

SCRIPT

0x0001

1

将运行登录脚本

ACCOUNTDISABLE

0x0002

2

禁用用户帐户

HOMEDIR_REQUIRED

0x0008

8

需要主文件夹

LOCKOUT

0x0010

16

不需要密码

PASSWD_NOTREQD

0x0020

32

用户不能更改密码。可以读取此标志,但不能直接设置它

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

运行 Microsoft Windows NT 4.0 Workstation、Microsoft Windows NT 4.0 Server、Microsoft Windows 2000 Professional 或 Windows 2000 Server 并且属于该域的计算机的计算机帐户

SERVER_TRUST_ACCOUNT

0x2000

8192

属于该域的域控制器的计算机帐户

DONT_EXPIRE_PASSWORD

0x10000

65536

在该帐户上永远不会过期的密码

MNS_LOGON_ACCOUNT

0x20000

131072

MNS 登录帐户

SMARTCARD_REQUIRED

0x40000

262144

设置此标志后,将强制用户使用智能卡登录

TRUSTED_FOR_DELEGATION

0x80000

524288

设置此标志后,将信任运行服务的服务帐户(用户或计算机帐户)进行 Kerberos 委派。任何此类服务都可模拟请求该服务的客户端。若要允许服务进行 Kerberos 委派,必须在服务帐户的userAccountControl 属性上设置此标志

NOT_DELEGATED

0x100000

1048576

设置此标志后,即使将服务帐户设置为信任其进行 Kerberos 委派,也不会将用户的安全上下文委派给该服务

USE_DES_KEY_ONLY

0x200000

2097152

(Windows 2000/Windows Server 2003) 将此用户限制为仅使用数据加密标准 (DES) 加密类型的密钥。

DONT_REQ_PREAUTH

0x400000

4194304

(Windows 2000/Windows Server 2003) 此帐户在登录时不需要进行 Kerberos 预先验证

PASSWORD_EXPIRED

0x800000

8388608

(Windows 2000/Windows Server 2003) 用户的密码已过期

TRUSTED_TO_AUTH_FOR_DELEGATION

0x1000000

16777216

(Windows 2000/Windows Server 2003) 允许该帐户进行委派。这是一个与安全相关的设置。应严格控制启用此选项的帐户。此设置允许该帐户运行的服务冒充客户端的身份,并作为该用户接受网络上其他远程服务器的身份验证

ObjectClass

条目的属性的集合

Schema

ObjectClass的集合。确保从外部导入数据到LDAP时的数据结构与现有数据结构一致性。

backend

读写数据的操作的单元模块

database

存储数据

缩写

缩写

全称

内容

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”

springboot整合

依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-ldap</artifactId>
        </dependency>

ladp版本跟随springboot版本即可

配置项

spring:
  ldap:
    urls: ldap://123:389
    base: dc=123-123,dc=cn
    username: cn=123,dc=123,dc=cn
    password: asdf

  jackson:
    serialization:
      # 不关闭jackson序列化,输出Name类型的dn会报错
      FAIL_ON_EMPTY_BEANS: false

实体类

base只填写至ou部分即可

objectClass从这里找,此界面为php-ldap-admin

Springboot ldap单点登录 springboot ldap认证_java

成员

package com.me.ldap.domain;

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

import javax.naming.Name;
import javax.naming.ldap.LdapName;
import java.io.Serializable;
import java.util.List;

/**
 * @author Wuzhiming
 */
@Entry(objectClasses = {"inetOrgPerson"}, base = "ou=Users")
public class Person implements Serializable {


    private static final long serialVersionUID = 2537331577057988415L;
    @Id
    private Name dn;

    /**
     * 用户唯一标识
     */
    @Attribute(name = "cn")
    private String cn;

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

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

    @Attribute(name = "ou")
    private String groupName;

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

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public String getUserAccountControl() {
        return userAccountControl;
    }

    public void setUserAccountControl(String userAccountControl) {
        this.userAccountControl = userAccountControl;
    }

    public Person(String cn) {
        LdapName dn = LdapNameBuilder.newInstance()
                .add("o", "Users")
                .add("cn", cn)
                .add("dc", "yuang-group")
                .build();
        this.dn = dn;
    }

    public Person(String cn, String groupName) {
        LdapName dn = LdapNameBuilder.newInstance()
                .add("o", groupName)
                .add("cn", cn)
                .add("dn", "Users")
                .add("dc", "yuang-group")
                .build();
        this.dn = dn;
    }

    public Person() {
    }

    /**
     * getter
     */
    public Name getDn() {
        return dn;
    }

    public String getCn() {
        return cn;
    }

    public String getSn() {
        return sn;
    }

    public String getUserPassword() {
        return userPassword;
    }

    /** setter */
    public void setDn(Name dn) {
        this.dn = dn;
    }

    public void setCn(String cn) {
        this.cn = cn;
    }

    public void setGroup(String groupName) {
        if (this.dn == null) {
            LdapName dn = LdapNameBuilder.newInstance()
                    .add("ou","Users")
                    .add("ou", groupName)
                    .add("cn",cn)
                    .build();
            this.dn = dn;
        }
    }
    public void setGroup(List<String> groupNameList) {

        if (this.dn == null) {
            LdapNameBuilder builder = LdapNameBuilder.newInstance()
                    .add("ou", "Users");
            for (String groupName : groupNameList) {
                builder=builder.add("ou",groupName);
            }
            LdapName dn = builder.add("cn", cn).build();
            this.dn = dn;
        }
    }

    public void setSn(String sn) {
        this.sn = sn;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    @Override
    public String toString() {
        return "Person{" +
                "dn=" + dn +
                ", cn='" + cn + '\'' +
                ", sn='" + sn + '\'' +
                ", userPassword='" + userPassword + '\'' +
                ", groupName='" + groupName + '\'' +
                '}';
    }
}

成员组

package com.me.ldap.domain;

import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import org.springframework.ldap.support.LdapNameBuilder;

import javax.naming.Name;
import java.util.List;

@Entry(objectClasses = {"organizationalUnit","top"},base = "ou=Users")
public class Group {
    @Id
    private Name dn;

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

    public Name getDn() {
        return dn;
    }

    public void setGroupName(List<String> groupNameList) {
        if(this.dn==null){
            LdapNameBuilder builder = LdapNameBuilder.newInstance();
            builder.add("ou","Users");
            for (String groupName : groupNameList) {
                builder=builder.add("ou",groupName);
            }
            dn=builder.build();
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Group{" +
                "dn=" + dn +
                ", name='" + name + '\'' +
                '}';
    }
}

前端传参接收类

用户
package com.me.ldap.domain.param;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import org.springframework.ldap.support.LdapNameBuilder;

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

/**
 * @author Wuzhiming
 */
@Data
public class AddPersonParam implements Serializable {


    private static final long serialVersionUID = -3761043026736955966L;

    private List<String> groupName;

    private String cn;

    private String sn;

    private String userPassword;

}

用户组

package com.me.ldap.domain.param;

import lombok.Data;

import java.util.List;

/**
 * @author Wuzhiming
 */
@Data
public class AddGroupParam {

    private List<String> groupNameList;
    
}

增删查改

查询
查询单个用户
public Person getPersonByCn(String cn) {
        Person cn1 = ldapTemplate.findOne(query().where("cn").is(cn), Person.class);
        return cn1;
    }
查询所有用户(只包含在base下的)
public List<Person> getAll() {
        return ldapTemplate.findAll(Person.class);
    }
新增
/**
     * 创建用户
     *
     * @param personParam
     */
    public void create(AddPersonParam personParam) {
        Person person = new Person();
        BeanCopier beanCopier = BeanCopier.create(AddPersonParam.class, Person.class, false);
        beanCopier.copy(personParam, person, null);
        person.setGroup(personParam.getGroupName());
        System.out.println(person);
        ldapTemplate.create(person);
    }
{
  "groupName": ["test_group","test2","test3"],
  "cn": "test_test_1_6_20",
  "sn": "114851418",
  "userPassword": "123456abcABC."
}
注意事项
  1. 只能在${base}组和以下级别的节点上创建用户。
  2. 添加用户前必须先创建用户组,create()不能级联创建用户组。
  3. Springboot ldap单点登录 springboot ldap认证_java_02{base}级别以下的成员组中加入用户,则需要写上此成员组及所有成员组名(${base}除外)
  4. cn必须保证全局唯一
删除
删除本节点
public void deletePerson(String personCn) {
        Person person = this.getPersonByCn(personCn);
        System.out.println(person);
        ldapTemplate.delete(person);
    }
注意事项
  1. 删除本节点时,本节点不能有任何子节点,否则会报错
级联删除
Group group = new Group();
        BeanCopier beanCopier = BeanCopier.create(AddGroupParam.class, Group.class, false);
        beanCopier.copy(param, group, null);
        group.setGroupName(param.getGroupNameList());
        System.out.println(group);
        ldapTemplate.unbind(group.getDn(),true);