了解LDAP协议、数据层次结构和条目组件
介绍
LDAP 或轻量级目录访问协议是一种开放协议,用于存储和检索分层目录结构中的数据。 LDAP 通常用于存储有关组织及其资产和用户的信息,是一种灵活的解决方案,用于定义任何类型的实体及其质量。
对于许多用户来说,LDAP 似乎很难理解,因为它依赖于特殊的术语,使用了一些不常见的缩写,并且通常作为一个更大的交互部件系统的一个组件来实现。 在本指南中,我们将向您介绍一些 LDAP 基础知识,以便您为使用该技术打下良好的基础。
什么是目录服务?
目录服务用于以键值类型格式存储、组织和呈现数据。 通常,目录针对查找、搜索和读取操作进行了优化,而不是写入操作,因此它们对于经常引用但不经常更改的数据非常有效。
存储在目录服务中的数据通常具有描述性,用于定义实体的质量。 可以在目录服务中很好地表示的物理对象的一个示例是地址簿。 每个人都可以用目录中的一个条目来表示,键值对描述他们的联系信息、营业地点等。 目录服务在您希望使定性、描述性信息可访问的许多情况下都很有用。
什么是 LDAP?
LDAP 或轻量级目录访问协议是一种通信协议,它定义了可以访问目录服务的方法。 更广泛地说,LDAP 塑造了目录服务中的数据应向用户表示的方式,定义了用于在目录服务中创建数据条目的组件的要求,并概述了使用不同的原始元素组成条目的方式。
由于 LDAP 是一个开放协议,因此有许多不同的实现可用。 OpenLDAP 项目是最受支持的开源变体之一。
基本 LDAP 数据组件
我们在上面讨论了 LDAP 是如何用于与目录数据库通信以查询、添加或修改信息的协议。 然而,这个简单的定义歪曲了支持该协议的系统的复杂性。 LDAP 向用户显示数据的方式非常依赖于一些已定义的结构组件之间的交互和关系。
属性
LDAP 系统中的数据本身主要存储在称为 attributes 的元素中。 属性基本上是键值对。 与其他一些系统不同,键具有预定义的名称,这些名称由选择用于条目的对象类指定(我们将稍后讨论)。 此外,属性中的数据必须与属性初始定义中定义的类型相匹配。
设置属性值是通过属性名称和由冒号和空格分隔的属性值来完成的。 一个名为 mail
的属性示例,它定义了一个电子邮件地址,如下所示:
mail: admin@example.com
当引用属性及其数据时(未设置时),两侧用等号连接:
mail=example.com
属性值包含您要在 LDAP 系统中存储和访问的大部分实际数据。 LDAP 中的其他元素用于结构、组织等。
参赛作品
属性本身不是很有用。 为了有意义,它们必须与某物关联。 在 LDAP 中,您使用 条目 中的属性。 条目基本上是用于描述某事的名称下的属性集合。
例如,您可以为系统中的用户或库存中的每个项目创建一个条目。 这大致类似于关系数据库系统中的一行或地址簿中的单个页面(此处的属性将代表每个模型中的各个字段)。 虽然属性定义了某物的质量或特征,但条目通过简单地在名称下收集这些属性来描述项目本身。
LDIF(LDAP 数据交换格式)中显示的示例条目如下所示:
dn: sn=Ellingwood,ou=people,dc=digitalocean,dc=com objectclass: person sn: Ellingwood cn: Justin Ellingwood
上面的示例可能是 LDAP 系统中的有效条目。
数码管
当您开始熟悉 LDAP 时,很容易认识到由属性定义的数据仅代表有关对象的部分可用信息。 剩下的就是条目在 LDAP 系统中的位置以及这暗示的关系。
例如,如果可以同时拥有用户和库存项目的条目,那么有人如何能够区分它们? 区分不同类型条目的一种方法是建立关系和组。 这在很大程度上取决于创建条目时放置的位置。 条目都作为树上的分支添加到 LDAP 系统,称为 Data Information Trees 或 DITs。
DIT 表示类似于文件系统的组织结构,其中每个条目(顶级条目除外)只有一个父条目,并且在其下可能有任意数量的子条目。 由于 LDAP 树中的条目几乎可以表示任何内容,因此某些条目将主要用于组织目的,类似于文件系统中的目录。
这样,您可能会有一个“people”条目和一个“inventoryItems”条目。 您的实际数据条目可以创建为这些的子项,以更好地区分它们的类型。 您的组织条目可以任意定义以最好地代表您的数据。
在上一节的示例条目中,我们在 dn
行中看到一个 DIT 指示:
dn: sn=Ellingwood,ou=people,dc=digitalocean,dc=com
此行称为条目的专有名称(稍后将详细介绍)并用于标识条目。 它的功能类似于返回 DIT 根目录的完整路径。 在本例中,我们创建了一个名为 sn=Ellingwood
的条目。 直接父项是一个名为 ou=people
的条目,它可能被用作描述人的条目的容器。 此条目的父项源自 digitalocean.com
域名,它充当我们 DIT 的根。
定义 LDAP 数据组件
在上一节中,我们讨论了如何在 LDAP 系统中表示数据。 但是,我们还必须谈谈存储数据的组件是如何定义的。 例如,我们提到数据必须匹配为每个属性定义的类型。 这些定义从何而来? 让我们再次从复杂性的底部开始,然后逐步上升。
属性定义
属性是使用相当复杂的语法定义的。 它们必须指明属性的名称、可用于引用该属性的任何其他名称、可输入的数据类型以及各种其他元数据。 此元数据可以描述属性,告诉 LDAP 如何排序或比较属性的值,并告诉它与其他属性的关系。
例如,这是 name
属性的定义:
attributetype ( 2.5.4.41 NAME 'name' DESC 'RFC4519: common supertype of name attributes' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
'name'
是属性的名称。 第一行中的数字是分配给属性的全局唯一 OID(对象 ID),以将其与其他所有属性区分开来。 条目的其余部分定义了在搜索期间如何比较条目,并有一个指针告诉在哪里可以找到属性的数据类型要求的信息。
属性定义的一个重要部分是该属性是否可以在一个条目中多次定义。 例如,定义可以定义一个姓氏只能在每个条目中定义一次,但“侄女”的属性可能允许在单个条目中多次定义该属性。 属性默认是多值的,如果每个条目只能设置一次,则必须包含 SINGLE-VALUE
标志。
属性定义比使用和设置属性要复杂得多。 幸运的是,在大多数情况下,您不必定义自己的属性,因为大多数 LDAP 实现都包含最常见的属性,而其他属性可以轻松导入。
对象类定义
属性收集在称为 objectClasses 的实体中。 对象类只是对描述特定事物有用的相关属性的分组。 例如,“人”是一个对象类。
通过设置一个名为 objectClass
的特殊属性,条目可以使用 objectClass 的属性,命名您希望使用的 objectClass。 事实上,objectClass
是您可以在条目中设置的唯一属性,而无需指定进一步的 objectClass。
因此,如果您正在创建一个条目来描述一个人,包括 objectClass person
(或任何从 person 派生的更具体的 person objectClasses - 我们将在稍后介绍)允许您使用该 objectClass 中的所有属性:
dn: . . . objectClass: person
然后,您将能够在条目中设置这些属性:
- cn:通用名
- description:条目的人类可读描述
- seeAlso:参考相关条目
- sn:姓氏
- telephoneNumber:电话号码
- userPassword:用户密码
如果您需要来自不同对象类的属性,则可以多次使用 objectClass
属性,但有一些规则规定什么是可接受的。 ObjectClasses 被定义为几种“类型”之一。
ObjectClass 的两种主要类型是 structural 或 auxiliary。 一个条目 必须 有一个结构类,但可能有零个或多个辅助类,用于增加类可用的属性。 结构 objectClass 用于创建和定义条目,而辅助 objectClasses 通过额外属性添加附加功能。
ObjectClass 定义确定它们提供的属性是必需的(由 MUST
规范指示)还是可选的(由 MAY
规范指示)。 多个 objectClasses 可以提供相同的属性,并且属性的 MAY
或 MUST
分类可能因 objectClass 而异。
例如,person
objectClass 定义如下:
objectclass ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
这被定义为一个结构对象类,这意味着它可以用来创建一个条目。 创建的条目必须设置surname
和commonname
属性,可选择设置userPassword
、telephoneNumber
、seeAlso
或 description
属性。
模式
ObjectClass 定义和属性定义依次组合在一个称为 schema 的结构中。 与传统的关系数据库不同,LDAP 中的模式只是相关对象类和属性的集合。 单个 DIT 可以有许多不同的模式,以便它可以创建所需的条目和属性。
模式通常会包含额外的属性定义,并且可能需要在其他模式中定义的属性。 例如,我们上面讨论的 person
objectClass 要求为使用 person
objectClass 的任何条目设置 surname
或 sn
属性。 如果这些没有在 LDAP 服务器本身中定义,则可以使用包含这些定义的模式将这些定义添加到服务器的词汇表中。
模式的格式基本上只是上述条目的组合,如下所示:
. . . objectclass ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) ) attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' ) DESC 'RFC2256: last (family) name(s) for which the entity is known by' SUP name ) attributetype ( 2.5.4.4 NAME ( 'cn' 'commonName' ) DESC 'RFC4519: common name(s) for which the entity is known by' SUP name ) . . .
数据组织
我们已经介绍了用于在 LDAP 系统中构建条目的常见元素,并讨论了这些构建块是如何在系统中定义的。 但是,我们还没有过多地讨论信息本身是如何在 LDAP DIT 中组织和结构化的。
在 DIT 中放置条目
DIT 只是描述现有条目关系的层次结构。 在创建时,每个新条目都必须通过将其自身作为现有条目的子项来“连接”到现有 DIT。 这将创建一个树状结构,用于定义关系和分配意义。
DIT 的顶部是最广泛的分类,在该分类下,每个后续节点都是以某种方式派生的。 通常,最顶部的条目仅用作指示使用 DIT 的组织的标签。 这些条目可以是所需的任何 objectClasses,但通常使用域组件(dc=example,dc=com
用于与 example.com
关联的 LDAP 管理信息)、位置(组织的 l=new_york,c=us
或纽约的部门)或组织部门(ou=marketing,o=Example_Co
)。
用于组织的条目(像文件夹一样使用)通常使用organizationalUnit objectClass,它允许使用称为ou=
的简单描述性属性标签。 这些通常用于顶级 DIT 条目下的一般类别(例如 ou=people
、ou=groups
和 ou=inventory
很常见)。 LDAP 针对沿树横向而不是在树内上下查找信息进行了优化,因此通常最好保持 DIT 层次结构相当浅,通过分配特定属性来指示一般组织分支和进一步细分。
命名和引用 DIT 中的条目
我们通过它们的属性来引用条目。 这意味着每个条目必须具有在 DIT 层次结构中其级别明确的属性或属性组。 此属性或属性组称为条目的 相对专有名称 或 RDN,它的功能类似于文件名。
要明确引用条目,您可以使用条目的 RDN 及其所有父条目的 RDN。 这条 RDN 链返回到 DIT 层次结构的顶部,并为所讨论的条目提供了明确的路径。 我们将此 RDN 链称为条目的 可分辨名称 或 DN。 您必须在创建期间指定条目的 DN,以便 LDAP 系统知道将新条目放置在何处,并可以确保该条目的 RDN 尚未被另一个条目使用。
作为一个类比,您可以将 RDN 视为相对文件或目录名称,就像您在文件系统中看到的那样。 另一方面,DN 更类似于绝对路径。 一个重要的区别是 LDAP DN 在 left-hand 端包含最具体的值,而文件路径在 right-hand 端包含最具体的信息。 DN 用逗号分隔 RDN 值。
例如,一个名为 John Smith 的人的条目可能会放置在 example.com
下组织的“人员”条目下方。 由于组织中可能有多个 John Smith,因此对于条目的 RDN,用户 ID 可能是更好的选择。 条目可以这样指定:
dn: uid=jsmith1,ou=People,dc=example,dc=com objectClass: inetOrgPerson cn: John Smith sn: Smith uid: jsmith1
在此实例中,我们必须使用 inetOrgPerson
对象类来访问 uid
属性(我们仍然可以访问 person
对象类中定义的所有属性,因为我们将见下一节)。
LDAP 继承
归根结底,LDAP 系统中的数据相互关联的大部分方式都是层次结构、继承和嵌套的问题。 LDAP 最初对很多人来说似乎是不寻常的,因为它在设计中实现了一些面向对象的概念。 这主要来自它对类的使用,正如我们之前讨论过的,以及我们现在将要讨论的继承的可用性。
对象类继承
每个 objectClass 都是一个描述该类型对象特征的类。
但是,与简单继承不同,LDAP 中的对象可以并且通常是多个类的实例(一些编程语言通过多重继承提供类似的功能)。 这是可能的,因为 LDAP 的类概念只是它必须或可能拥有的属性的集合。 这允许为一个条目指定多个类(尽管只有一个 STRUCTURAL
objectClass 可以并且必须存在),从而导致对象只需访问具有最严格的 MUST 或 MAY 声明优先的合并属性集合.
在其定义中,objectClass 可以标识一个父 objectClass,从该父 objectClass 继承其属性。 这是使用 SUP
后跟要继承的 objectClass 来完成的。 例如,organizationalPerson
objectClass 的开头是这样的:
objectclass ( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL . . .
SUP
标识符后面的 objectClass 是父 objectClass。 父级必须共享正在定义的 objectClass 的 objectClass 类型(例如 STRUCTURAL
或 AUXILIARY
)。 子对象类自动继承父对象的属性和属性要求。
在条目中分配 objectClass 时,您只需要指定继承链的最具体的后代即可一直访问属性。 在上一节中,我们使用它来指定 inetOrgPerson
作为 John Smith 条目的唯一对象类,同时仍然可以访问 person
和 organizationalPerson
对象类中定义的属性。 inetOrgPerson
继承层次结构如下所示:
inetOrgPerson -> organizationalPerson -> person -> top
几乎所有 objectClass 继承树都以一个名为“top”的特殊 objectClass 结尾。 这是一个抽象 objectClass,其唯一目的是要求设置 objectClass 本身。 它用于指示继承链的顶部。
属性继承
以类似的方式,属性本身可以在其定义期间列出父属性。 然后该属性将继承在父属性中设置的属性。
这通常用于制作通用属性的更具体版本。 例如,姓氏是一种名称,可以使用所有相同的方法来比较和检查是否相等。 它可以继承这些特性以获得“名称”属性的一般形式。 事实上,实际的姓氏定义可能只包含一个指向父属性的指针。
这很有用,因为它允许创建对人们解释元素有用的特定属性,即使它的一般形式保持不变。 我们在这里讨论的 surname
属性的继承有助于人们区分姓氏和更一般的名称,但除了值的含义之外,LDAP 系统中的姓氏和名称之间几乎没有区别。
LDAP 协议变体
我们在开头提到 LDAP 实际上只是定义用于目录服务的通信接口的协议。 这通常被称为 LDAP 或 ldap 协议。
值得一提的是,您可能会看到一些常规格式的变体:
- ldap://:这是允许结构化访问目录服务的基本 LDAP 协议。
- ldaps://:此变体用于指示 LDAP over SSL/TLS。 正常的 LDAP 流量没有加密,尽管大多数 LDAP 实现都支持这一点。 这种加密 LDAP 连接的方法实际上已被弃用,而是建议使用 STARTTLS 加密。 如果您在不安全的网络上运行 LDAP,强烈建议使用加密。
- ldapi://:这用于指示 IPC 上的 LDAP。 这通常用于与本地 LDAP 系统安全连接以进行管理。 它通过内部套接字进行通信,而不是使用暴露的网络端口。
所有三种格式都使用 LDAP 协议,但最后两种表示有关如何使用它的附加信息。
结论
您应该对 LDAP 协议以及 LDAP 实现向用户表示数据的方式有相当好的了解。 了解系统的元素是如何相互关联的,以及它们从何处获取属性,可以使管理和使用 LDAP 系统变得更简单、更可预测。