2023年6月21日发(作者:)

SpringBoot实战(六)之使⽤LDAP验证⽤户本⽂主要讲LDAP相关的概念,普及相关知识和相关例⼦实战。⼀、LDAP服务器概念和原理1. ⽬录服务⽬录是⼀个为查询、浏览和搜索⽽优化的专业分布式数据库,它呈树状结构组织数据,就好象Linux/Unix系统中的⽂件⽬录⼀样。⽬录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以⽬录天⽣是⽤来查询的,就好象它的名字⼀样。⽬录服务是由⽬录数据库和⼀套访问协议组成的系统。类似以下的信息适合储存在⽬录中:企业员⼯信息,如姓名、电话、邮箱等;公⽤证书和安全密钥;公司的物理设备信息,如服务器,它的IP地址、存放位置、⼚商、购买时间等;是轻量⽬录访问协议(Lightweight Directory Access Protocol)的缩写,LDAP是从X.500⽬录访问协议的基础上发展过来的,⽬前的版本是v3.0。与LDAP⼀样提供类似的⽬录服务软件还有、、 。

2. LDAP特点LDAP的结构⽤树来表⽰,⽽不是⽤表格。正因为这样,就不能⽤SQL语句了LDAP可以很快地得到查询结果,不过在写⽅⾯,就慢得多LDAP提供了静态数据的快速查询⽅式Client/server模型,Server ⽤于存储数据,Client提供操作⽬录信息树的⼯具这些⼯具可以将数据库的内容以⽂本格式(LDAP 数据交换格式,LDIF)呈现在您的⾯前LDAP是⼀种开放Internet标准,LDAP协议是跨平台的Interent协议

3. LDAP组织数据的⽅式

4. 基本概念在浏览LDAP相关⽂档时经常会遇见⼀些概念,下⾯是常见概念的简单解释。

4.1 Entry条⽬,也叫记录项,是LDAP中最基本的颗粒,就像字典中的词条,或者是数据库中的记录。通常对LDAP的添加、删除、更改、检索都是以条⽬为基本对象的。dn:每⼀个条⽬都有⼀个唯⼀的标识名(distinguished Name ,DN),如上图中⼀个dn:"cn=baby,ou=marketing,ou=people,dc=mydomain,dc=org" 。通过DN的层次型语法结构,可以⽅便地表⽰出条⽬在LDAP树中的位置,通常⽤于检索。rdn:⼀般指dn逗号最左边的部分,如cn=baby。它与RootDN不同,RootDN通常与RootPW同时出现,特指管理LDAP中信息的最⾼权限⽤户。Base DN:LDAP⽬录树的最顶部就是根,也就是所谓的“Base DN",如"dc=mydomain,dc=org"。

4.2 Attribute每个条⽬都可以有很多属性(Attribute),⽐如常见的⼈都有姓名、地址、电话等属性。每个属性都有名称及对应的值,属性值可以有单个、多个,⽐如你有多个邮箱。属性不是随便定义的,需要符合⼀定的规则,⽽这个规则可以通过schema制定。⽐如,如果⼀个entry没有包含在 inetorgperson 这个schema 中的objectClass: inetOrgPerson,那么就不能为它指定employeeNumber属性,因为employeeNumber是在inetOrgPerson中定义的。LDAP为⼈员组织机构中常见的对象都设计了属性(⽐如commonName,surname)。下⾯有⼀些常⽤的别名:属性commonNamesurnameorganizationalUnitNameorganizationtelephoneNumberobjectClass别名cnsnou o  语法Directory StringDirectory StringDirectory StringDirectory StringTelephone Number 描述姓名姓单位(部门)名称组织(公司)名称电话号码内置属性值(举例)seanChowIT_SECTIONexample110organizationalPerson

4.3 ObjectClass对象类是属性的集合,LDAP预想了很多⼈员组织机构中常见的对象,并将其封装成对象类。⽐如⼈员(person)含有姓(sn)、名(cn)、电话(telephoneNumber)、密码(userPassword)等属性,单位职⼯(organizationalPerson)是⼈员(person)的继承类,除了上述属性之外还含有职务(title)、邮政编码(postalCode)、通信地址(postalAddress)等属性。通过对象类可以⽅便的定义条⽬类型。每个条⽬可以直接继承多个对象类,这样就继承了各种属性。如果2个对象类中有相同的属性,则条⽬继承后只会保留1个属性。对象类同时也规定了哪些属性是基本信息,必须含有(Must 活Required,必要属性):哪些属性是扩展信息,可以含有(May或Optional,可选属性)。对象类有三种类型:结构类型(Structural)、抽象类型(Abstract)和辅助类型(Auxiliary)。结构类型是最基本的类型,它规定了对象实体的基本属性,每个条⽬属于且仅属于⼀个结构型对象类。抽象类型可以是结构类型或其他抽象类型⽗类,它将对象属性中共性的部分组织在⼀起,称为其他类的模板,条⽬不能直接集成抽象型对象类。辅助类型规定了对象实体的扩展属性。每个条⽬⾄少有⼀个结构性对象类。对象类本⾝是可以相互继承的,所以对象类的根类是top抽象型对象类。以常⽤的⼈员类型为例,他们的继承关系:下⾯是inetOrgPerson对象类的在schema中的定义,可以清楚的看到它的⽗类SUB和可选属性MAY、必要属性MUST(继承⾃organizationalPerson),关于各属性的语法则在schema中的attributetype定义。# inetOrgPerson# The inetOrgPerson represents people who are associated with an# organization in some way. It is a structural class and is derived# from the organizationalPerson which is defined in X.521 [X521].objectclass ( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RFC2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL MAY

4.4 Schema对象类(ObjectClass)、属性类型(AttributeType)、语法(Syntax)分别约定了条⽬、属性、值,他们之间的关系如下图所⽰。所以这些构成了模式(Schema)——对象类的集合。条⽬数据在导⼊时通常需要接受模式检查,它确保了⽬录中所有的条⽬数据结构都是⼀致的。schema(⼀般在/etc/ldap/schema/⽬录)在导⼊时要注意前后顺序。

4.5 backend & databaseldap的后台进程slapd接收、响应请求,但实际存储数据、获取数据的操作是由Backends做的,⽽数据是存放在database中,所以你可以看到往往你可以看到backend和database指令是⼀样的值如 bdb 。⼀个 backend 可以有多个 database instance,但每个 database 的suffix 和 rootdn 不⼀样。openldap 2.4版本的模块是动态加载的,所以在使⽤backend时需要moduleload back_bdb指令。bdb是⼀个⾼性能的⽀持事务和故障恢复的数据库后端,可以满⾜绝⼤部分需求。许多旧⽂档⾥(包括官⽅)说建议将bdb作为⾸选后端服务(primary backend),但明确说hdb才是被⾸先推荐使⽤的,这从 2.4.40 版默认安装后的配置⽂件⾥也可以看出。hdb是基于bdb的,但是它通过扩展的索引和缓存技术可以加快数据访问,修改entries会更有效率,有兴趣可以访问上的链接或。另外config是特殊的backend,⽤来在运⾏时管理slapd的配置,它只能有⼀个实例,甚⾄⽆需显式在中配置。

4.6 TLS & SASL分布式LDAP 是以明⽂的格式通过⽹络来发送信息的,包括client访问ldap的密码(当然⼀般密码已然是⼆进制的),SSL/TLS 的加密协议就是来保证数据传送的保密性和完整性。SASL (Simple Authenticaion and Security Layer)简单⾝份验证安全框架,它能够实现openldap客户端到服务端的⽤户验证,也是ldapsearch、ldapmodify这些标准客户端⼯具默认尝试与LDAP服务端认证⽤户的⽅式(前提是已经安装好 )。SASL有⼏⼤⼯业实现标准:Kerveros V5、DIGEST-MD5、EXTERNAL、PLAIN、LOGIN。Kerveros V5是⾥⾯最复杂的⼀种,使⽤GSSAPI机制,必须配置完整的Kerberos V5安全系统,密码不再存放在⽬录服务器中,每⼀个dn与Kerberos数据库的主体对应。DIGEST-MD5稍微简单⼀点,密码通过saslpasswd2⽣成放在sasldb数据库中,或者将明⽂hash存到LDAP dn的userPassword中,每⼀个authid映射成⽬录服务器的dn,常和SSL配合使⽤。参考EXTERNAL⼀般⽤于初始化添加schema时使⽤,如ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/。

4.7 LDIFLDIF(LDAP Data Interchange Format,数据交换格式)是LDAP数据库信息的⼀种⽂本格式,⽤于数据的导⼊导出,每⾏都是“属性:值”对,见

OpenLDAP(2.4.3x)服务器安装配置⽅法见。

⼆、实例讲解依赖 4.0.0 framework gs-authenticating-ldap 0.1.0 spring-boot-starter-parent E 1.8

spring-boot-starter-web spring-boot-starter-security spring-ldap-core ty spring-security-ldap did unboundid-ldapsdk spring-boot-starter-test test ty spring-security-test test spring-boot-maven-plugin

2.编写WEB安全配置ckage hello;import uration;import aPasswordEncoder;import ticationManagerBuilder;import curity;import urityConfigurerAdapter;@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().fullyAuthenticated() .and() .formLogin(); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth .ldapAuthentication() .userDnPatterns("uid={0},ou=people") .groupSearchBase("ou=groups") .contextSource() .url("ldap://localhost:8389/dc=springframework,dc=org") .and() .passwordCompare() .passwordEncoder(new LdapShaPasswordEncoder()) .passwordAttribute("userPassword"); }}

3.编写启动类package hello;import Application;import BootApplication;@SpringBootApplicationpublic class Application { public static void main(String[] args) { (, args); }}

4.对应的配置⽂件: dc=springframework,dc=orgobjectclass: topobjectclass: domainobjectclass: extensibleObjectobjectclass: extensibleObjectdc: springframeworkdn: ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: groupsdn: ou=subgroups,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: subgroupsdn: ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: peopledn: ou=space cadets,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: space cadetsdn: ou="quoted people",dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: "quoted people"dn: ou=otherpeople,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: otherpeopledn: uid=ben,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Ben Alexsn: Alexuid: benuserPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=dn: uid=bob,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Bob Hamiltonsn: Hamiltonuid: bobuserPassword: bobspassworddn: uid=joe,ou=otherpeople,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Joe Smethsn: Smethuid: joeuserPassword: joespassworddn: cn=mouse, jerry,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Mouse, Jerrysn: Mouseuid: jerryuserPassword: jerryspassworddn: cn=slash/guy,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: slash/guysn: Slashuid: slashguyuserPassword: slashguyspassworddn: cn=quote"guy,ou="quoted people",dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: quote"guysn: Quoteuid: quoteguyuserPassword: quoteguyspassworddn: uid=space cadet,ou=space cadets,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Space Cadetsn: Cadetuid: space cadetuserPassword: spacecadetspassworddn: cn=developers,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: groupOfUniqueNamescn: developersou: developeruniqueMember: uid=ben,ou=people,dc=springframework,dc=orguniqueMember: uid=bob,ou=people,dc=springframework,dc=orgdn: cn=managers,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: groupOfUniqueNamescn: managersou: manageruniqueMember: uid=ben,ou=people,dc=springframework,dc=orguniqueMember: cn=mouse, jerry,ou=people,dc=springframework,dc=orgdn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: groupOfUniqueNamescn: submanagersou: submanageruniqueMember: uid=ben,ou=people,dc=springframework,dc=org

2023年6月21日发(作者:)

SpringBoot实战(六)之使⽤LDAP验证⽤户本⽂主要讲LDAP相关的概念,普及相关知识和相关例⼦实战。⼀、LDAP服务器概念和原理1. ⽬录服务⽬录是⼀个为查询、浏览和搜索⽽优化的专业分布式数据库,它呈树状结构组织数据,就好象Linux/Unix系统中的⽂件⽬录⼀样。⽬录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以⽬录天⽣是⽤来查询的,就好象它的名字⼀样。⽬录服务是由⽬录数据库和⼀套访问协议组成的系统。类似以下的信息适合储存在⽬录中:企业员⼯信息,如姓名、电话、邮箱等;公⽤证书和安全密钥;公司的物理设备信息,如服务器,它的IP地址、存放位置、⼚商、购买时间等;是轻量⽬录访问协议(Lightweight Directory Access Protocol)的缩写,LDAP是从X.500⽬录访问协议的基础上发展过来的,⽬前的版本是v3.0。与LDAP⼀样提供类似的⽬录服务软件还有、、 。

2. LDAP特点LDAP的结构⽤树来表⽰,⽽不是⽤表格。正因为这样,就不能⽤SQL语句了LDAP可以很快地得到查询结果,不过在写⽅⾯,就慢得多LDAP提供了静态数据的快速查询⽅式Client/server模型,Server ⽤于存储数据,Client提供操作⽬录信息树的⼯具这些⼯具可以将数据库的内容以⽂本格式(LDAP 数据交换格式,LDIF)呈现在您的⾯前LDAP是⼀种开放Internet标准,LDAP协议是跨平台的Interent协议

3. LDAP组织数据的⽅式

4. 基本概念在浏览LDAP相关⽂档时经常会遇见⼀些概念,下⾯是常见概念的简单解释。

4.1 Entry条⽬,也叫记录项,是LDAP中最基本的颗粒,就像字典中的词条,或者是数据库中的记录。通常对LDAP的添加、删除、更改、检索都是以条⽬为基本对象的。dn:每⼀个条⽬都有⼀个唯⼀的标识名(distinguished Name ,DN),如上图中⼀个dn:"cn=baby,ou=marketing,ou=people,dc=mydomain,dc=org" 。通过DN的层次型语法结构,可以⽅便地表⽰出条⽬在LDAP树中的位置,通常⽤于检索。rdn:⼀般指dn逗号最左边的部分,如cn=baby。它与RootDN不同,RootDN通常与RootPW同时出现,特指管理LDAP中信息的最⾼权限⽤户。Base DN:LDAP⽬录树的最顶部就是根,也就是所谓的“Base DN",如"dc=mydomain,dc=org"。

4.2 Attribute每个条⽬都可以有很多属性(Attribute),⽐如常见的⼈都有姓名、地址、电话等属性。每个属性都有名称及对应的值,属性值可以有单个、多个,⽐如你有多个邮箱。属性不是随便定义的,需要符合⼀定的规则,⽽这个规则可以通过schema制定。⽐如,如果⼀个entry没有包含在 inetorgperson 这个schema 中的objectClass: inetOrgPerson,那么就不能为它指定employeeNumber属性,因为employeeNumber是在inetOrgPerson中定义的。LDAP为⼈员组织机构中常见的对象都设计了属性(⽐如commonName,surname)。下⾯有⼀些常⽤的别名:属性commonNamesurnameorganizationalUnitNameorganizationtelephoneNumberobjectClass别名cnsnou o  语法Directory StringDirectory StringDirectory StringDirectory StringTelephone Number 描述姓名姓单位(部门)名称组织(公司)名称电话号码内置属性值(举例)seanChowIT_SECTIONexample110organizationalPerson

4.3 ObjectClass对象类是属性的集合,LDAP预想了很多⼈员组织机构中常见的对象,并将其封装成对象类。⽐如⼈员(person)含有姓(sn)、名(cn)、电话(telephoneNumber)、密码(userPassword)等属性,单位职⼯(organizationalPerson)是⼈员(person)的继承类,除了上述属性之外还含有职务(title)、邮政编码(postalCode)、通信地址(postalAddress)等属性。通过对象类可以⽅便的定义条⽬类型。每个条⽬可以直接继承多个对象类,这样就继承了各种属性。如果2个对象类中有相同的属性,则条⽬继承后只会保留1个属性。对象类同时也规定了哪些属性是基本信息,必须含有(Must 活Required,必要属性):哪些属性是扩展信息,可以含有(May或Optional,可选属性)。对象类有三种类型:结构类型(Structural)、抽象类型(Abstract)和辅助类型(Auxiliary)。结构类型是最基本的类型,它规定了对象实体的基本属性,每个条⽬属于且仅属于⼀个结构型对象类。抽象类型可以是结构类型或其他抽象类型⽗类,它将对象属性中共性的部分组织在⼀起,称为其他类的模板,条⽬不能直接集成抽象型对象类。辅助类型规定了对象实体的扩展属性。每个条⽬⾄少有⼀个结构性对象类。对象类本⾝是可以相互继承的,所以对象类的根类是top抽象型对象类。以常⽤的⼈员类型为例,他们的继承关系:下⾯是inetOrgPerson对象类的在schema中的定义,可以清楚的看到它的⽗类SUB和可选属性MAY、必要属性MUST(继承⾃organizationalPerson),关于各属性的语法则在schema中的attributetype定义。# inetOrgPerson# The inetOrgPerson represents people who are associated with an# organization in some way. It is a structural class and is derived# from the organizationalPerson which is defined in X.521 [X521].objectclass ( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RFC2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL MAY

4.4 Schema对象类(ObjectClass)、属性类型(AttributeType)、语法(Syntax)分别约定了条⽬、属性、值,他们之间的关系如下图所⽰。所以这些构成了模式(Schema)——对象类的集合。条⽬数据在导⼊时通常需要接受模式检查,它确保了⽬录中所有的条⽬数据结构都是⼀致的。schema(⼀般在/etc/ldap/schema/⽬录)在导⼊时要注意前后顺序。

4.5 backend & databaseldap的后台进程slapd接收、响应请求,但实际存储数据、获取数据的操作是由Backends做的,⽽数据是存放在database中,所以你可以看到往往你可以看到backend和database指令是⼀样的值如 bdb 。⼀个 backend 可以有多个 database instance,但每个 database 的suffix 和 rootdn 不⼀样。openldap 2.4版本的模块是动态加载的,所以在使⽤backend时需要moduleload back_bdb指令。bdb是⼀个⾼性能的⽀持事务和故障恢复的数据库后端,可以满⾜绝⼤部分需求。许多旧⽂档⾥(包括官⽅)说建议将bdb作为⾸选后端服务(primary backend),但明确说hdb才是被⾸先推荐使⽤的,这从 2.4.40 版默认安装后的配置⽂件⾥也可以看出。hdb是基于bdb的,但是它通过扩展的索引和缓存技术可以加快数据访问,修改entries会更有效率,有兴趣可以访问上的链接或。另外config是特殊的backend,⽤来在运⾏时管理slapd的配置,它只能有⼀个实例,甚⾄⽆需显式在中配置。

4.6 TLS & SASL分布式LDAP 是以明⽂的格式通过⽹络来发送信息的,包括client访问ldap的密码(当然⼀般密码已然是⼆进制的),SSL/TLS 的加密协议就是来保证数据传送的保密性和完整性。SASL (Simple Authenticaion and Security Layer)简单⾝份验证安全框架,它能够实现openldap客户端到服务端的⽤户验证,也是ldapsearch、ldapmodify这些标准客户端⼯具默认尝试与LDAP服务端认证⽤户的⽅式(前提是已经安装好 )。SASL有⼏⼤⼯业实现标准:Kerveros V5、DIGEST-MD5、EXTERNAL、PLAIN、LOGIN。Kerveros V5是⾥⾯最复杂的⼀种,使⽤GSSAPI机制,必须配置完整的Kerberos V5安全系统,密码不再存放在⽬录服务器中,每⼀个dn与Kerberos数据库的主体对应。DIGEST-MD5稍微简单⼀点,密码通过saslpasswd2⽣成放在sasldb数据库中,或者将明⽂hash存到LDAP dn的userPassword中,每⼀个authid映射成⽬录服务器的dn,常和SSL配合使⽤。参考EXTERNAL⼀般⽤于初始化添加schema时使⽤,如ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/。

4.7 LDIFLDIF(LDAP Data Interchange Format,数据交换格式)是LDAP数据库信息的⼀种⽂本格式,⽤于数据的导⼊导出,每⾏都是“属性:值”对,见

OpenLDAP(2.4.3x)服务器安装配置⽅法见。

⼆、实例讲解依赖 4.0.0 framework gs-authenticating-ldap 0.1.0 spring-boot-starter-parent E 1.8

spring-boot-starter-web spring-boot-starter-security spring-ldap-core ty spring-security-ldap did unboundid-ldapsdk spring-boot-starter-test test ty spring-security-test test spring-boot-maven-plugin

2.编写WEB安全配置ckage hello;import uration;import aPasswordEncoder;import ticationManagerBuilder;import curity;import urityConfigurerAdapter;@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().fullyAuthenticated() .and() .formLogin(); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth .ldapAuthentication() .userDnPatterns("uid={0},ou=people") .groupSearchBase("ou=groups") .contextSource() .url("ldap://localhost:8389/dc=springframework,dc=org") .and() .passwordCompare() .passwordEncoder(new LdapShaPasswordEncoder()) .passwordAttribute("userPassword"); }}

3.编写启动类package hello;import Application;import BootApplication;@SpringBootApplicationpublic class Application { public static void main(String[] args) { (, args); }}

4.对应的配置⽂件: dc=springframework,dc=orgobjectclass: topobjectclass: domainobjectclass: extensibleObjectobjectclass: extensibleObjectdc: springframeworkdn: ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: groupsdn: ou=subgroups,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: subgroupsdn: ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: peopledn: ou=space cadets,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: space cadetsdn: ou="quoted people",dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: "quoted people"dn: ou=otherpeople,dc=springframework,dc=orgobjectclass: topobjectclass: organizationalUnitou: otherpeopledn: uid=ben,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Ben Alexsn: Alexuid: benuserPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=dn: uid=bob,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Bob Hamiltonsn: Hamiltonuid: bobuserPassword: bobspassworddn: uid=joe,ou=otherpeople,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Joe Smethsn: Smethuid: joeuserPassword: joespassworddn: cn=mouse, jerry,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Mouse, Jerrysn: Mouseuid: jerryuserPassword: jerryspassworddn: cn=slash/guy,ou=people,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: slash/guysn: Slashuid: slashguyuserPassword: slashguyspassworddn: cn=quote"guy,ou="quoted people",dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: quote"guysn: Quoteuid: quoteguyuserPassword: quoteguyspassworddn: uid=space cadet,ou=space cadets,dc=springframework,dc=orgobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersoncn: Space Cadetsn: Cadetuid: space cadetuserPassword: spacecadetspassworddn: cn=developers,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: groupOfUniqueNamescn: developersou: developeruniqueMember: uid=ben,ou=people,dc=springframework,dc=orguniqueMember: uid=bob,ou=people,dc=springframework,dc=orgdn: cn=managers,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: groupOfUniqueNamescn: managersou: manageruniqueMember: uid=ben,ou=people,dc=springframework,dc=orguniqueMember: cn=mouse, jerry,ou=people,dc=springframework,dc=orgdn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=orgobjectclass: topobjectclass: groupOfUniqueNamescn: submanagersou: submanageruniqueMember: uid=ben,ou=people,dc=springframework,dc=org