:::danger
TBD
1. 補充 wiki 裡 server 的 chaining
3. 閱讀 [OpenLDAP 2.5 doc](https://www.openldap.org/doc/admin25/intro.html)
4. 閱讀 RFC4512 三種 object class
5. 補充常見的 attribute types, object classes
7. `groupsOfUniqueName` 或 `uniqueMember`
8. 常見的 layout: root 是 `dc`
:::
# LDAP
顧名思義,**Lightweight Directory Access Protocol (LDAP)** 是用來存取 (access) directory 的協議。因此,我們需要先理解何謂 directory。
## Directory, Directory Service
根據 [wiki](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol)
> The **Lightweight Directory Access Protocol** (**LDAP** /ˈɛldæp/) is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed *directory information services* over an Internet Protocol (IP) network.
其中的 directory information service 一般稱為 directory service。其概念遠在電腦網路出現之前就存在於電信 (telecommunication) 領域中。將 directory 翻譯為[目錄](https://dict.revised.moe.edu.tw/dictView.jsp?ID=33004&q=1&word=%E7%9B%AE%E9%8C%84)便可以很好地理解 directory service 的概念:**用以查詢某些資訊的服務**。比如 telephone directories 就是用以查詢電話號碼。
從「查詢資訊」的角度,也就很容易理解許多技術文件在定義 directory 時,會與 database 放在一起說明。OpenLDAP 的[文件](https://www.openldap.org/doc/admin25/intro.html#What%20is%20a%20directory%20service)這樣定義 directory:
> **A directory is a specialized database specifically designed for searching and browsing, in additional to supporting basic lookup and update functions.**
注意,其中的 searching 與 browsing 皆為 read 操作(而非 write)。部份過度簡化的文件會將 directory 定義為 database optimized for read access。
:::warning
建議剛接觸 LDAP 相關知識時不要讀 wiki 中的 [directory service](https://en.wikipedia.org/wiki/Directory_service) 。
:::
### Directory Service 與使用者驗證的關聯
既然 directory 易於快速瀏覽 (brwosing) 及快速搜尋 (search),也就很適合「時常需要瀏覽、搜尋、查詢 (look-up)」,相對較少寫入」的應用。如:儲存使用者帳號、密碼、對於電腦檔案系統的存取權限。
> wiki: A common use of LDAP is to provide a central place to store usernames and passwords. This allows many different applications and services to connect to the LDAP server to validate users.
另外,LDAP 也常在企業中用於[管理資源分配](https://youtu.be/a2NYJmgQfX4),如一個員工/部門可以使用的會議室、可存取的檔案、可登入的系統等。
## Protocol Overview, Client-Server Model
理解了 directory 的概念後,就可以定義如何在 IP 網路中存取 directory,這個協議即是 LDAP。以下直接複製 wiki 內容:
> A client starts an LDAP session by connecting to an LDAP server, called a Directory System Agent (DSA), by default on TCP and UDP port 389, or on port 636 for LDAPS (LDAP over TLS/SSL, see below). The client then sends an operation request to the server, and a server sends responses in return. With some exceptions, the client does not need to wait for a response before sending the next request, and the server may send the responses in any order. All information is transmitted using Basic Encoding Rules (BER).
>
> The client may request the following operations:
> - StartTLS – use the LDAPv3 Transport Layer Security (TLS) extension for a secure connection
> - Bind – authenticate and specify LDAP protocol version
> - Search – search for and/or retrieve directory entries
> - Compare – test if a named entry contains a given attribute value
> - Add a new entry
> - Delete an entry
> - Modify an entry
> - Modify Distinguished Name (DN) – move or rename an entry
> - Abandon – abort a previous request
> - Extended Operation – generic operation used to define other operations
> - Unbind – close the connection (not the inverse of Bind)
>
> In addition the server may send "Unsolicited Notifications" that are not responses to any request, e.g. before the connection is timed out.
可以看出,LDAP 使用的是 Client-Server 架構。Directory 儲存於 servers,並且可以由 clients 來執行 search, add, delete, modify 等操作 (operations)。
由於整個 directory 可能儲存在不同機器之間 (distributed),client 對一個 server 執行特定的 search 或 compare 等操作,可能需要由其他 server 來完成。
在 OpenLDAP 的[舊版文件](https://tldp.org/HOWTO/LDAP-HOWTO/howitworks.html)中這樣描述:
> - LDAP directory service is based on a client-server model.
> - One or more LDAP servers contain the data making up the LDAP directory tree or LDAP backend database.
> - An LDAP client connects to an LDAP server and asks it a question. The server responds with the answer, or with a pointer to where the client can get more information (typically, another LDAP server).
> - No matter what LDAP server a client connects to, it sees the same view of the directory; a name presented to one LDAP server references the same entry it would at another LDAP server. This is an important feature of a global directory service, like LDAP.
## Data Model
LDAP 中也規範了 directory 應由什麼組成(在 RFC 4512 ):
整個 directory 是一個稱為 **DIT (Directory Information Tree)** 的**樹**,儲存在 LDAP server 端,可能由一至多個機器儲存。樹中的每個 node 稱為 entry。
務必閱讀 wiki 當中 [directory structure](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol#Directory_structure) 的段落,以下引用自該段落
> The protocol provides an interface with directories that follow the 1993 edition of the X.500 model:
> - An entry consists of a set of attributes.
> - An attribute has a name (an *attribute type* or *attribute description*) and one or more values. The attributes are defined in a *schema* (see below).
> - Each entry has a unique identifier: its *Distinguished Name* (DN). This consists of its *Relative Distinguished Name* (RDN), constructed from some attribute(s) in the entry, followed by the parent entry's DN. Think of the DN as the full file path and the RDN as its relative filename in its parent folder (e.g. if /foo/bar/myfile.txt were the DN, then myfile.txt would be the RDN).
>
> A DN may change over the lifetime of the entry, for instance, when entries are moved within a tree. To reliably and unambiguously identify entries, a UUID might be provided in the set of the entry's operational attributes.
既然一個 entry 由多個「描述性」(隱含可用字串表示)的 attribute 組成,就可用 plain text format 來表示。常見的檔案格式是 LDAP Data Interchange Format (LDIF)。例如,這是一個以 LDIF 表示的 entry:
```ldif
dn: cn=John Doe,dc=example,dc=com
cn: John Doe
givenName: John
sn: Doe
telephoneNumber: +1 888 555 6789
telephoneNumber: +1 888 555 1232
mail: john@example.com
manager: cn=Barbara Doe,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
```
每個 attribute 都由 name (*attribute type*) 及一至多個 value 組成。例如,此 entry 中,`cn` 這個 attribute type 的值為 `John Doe`,而 `telephoneNumber` 這個 attribute type 則有 `+1 888 555 6789` 和 `+1 888 555 1232` 兩個值。
:::info
一般習慣用 an attribute 來稱呼 an attribute type + its value(s) 的組合。如,我們會說 `cn: John Doe` 是 an attribute,但是在規格書中,也會看到用 Attribute Value Assertion (AVA) 這個正式名稱來稱呼我們俗稱的 attribute。(參考 [RFC-4511 Section-4.1.6](https://www.rfc-editor.org/rfc/rfc4511.html#section-4.1.6))
:::
那麼,很容易想到兩個問題
1. 一個 entry 有這麼多個 attributes,應該選擇哪一個作為 relative distinguished name?
2. 一個 entry 可以用哪些 attribute types?
### To Decide the Relative Distinguished Name (RDN)
先回答第一個問題:一個 entry 有這麼多個 attributes,應該選擇哪一個作為 relative distinguished name?
在 RFC 4512, Section 2.3.1 當中,並未直接規定如何選擇應選擇哪個 attribute 作為 RDN。其描述如下:
> Each entry is named relative to its immediate superior. This relative name, known as its Relative Distinguished Name (RDN) [X.501], is composed of an unordered set of **one or more attribute value assertions (AVA)** consisting of an attribute description with zero options and an attribute value. These AVAs are chosen to match attribute values (each a distinguished value) of the entry.
>
> An entry's relative distinguished name must be unique among all immediate subordinates of the entry's immediate superior (i.e., all siblings).
可以看出有兩項規定:
1. RDN 必須在該 entry 的 sibling entries' RDN 之間是唯一
2. RDN 可以是單值的(如 `UID=12345`)或多值的(如`CN=Kurt Zeilenga+L=Redwood Shores`)
至於選擇 entry 的哪個屬性作為 RDN 是由 LDAP 系統管理者決定,而非規格強制要求。不過,組織(學校、公司)內部或者業界可能有特定的慣例。且一些 schema 也會引導特定應用情境下的 RDN 應該如何選擇。例如:
- 對人員條目使用 `uid` 或 `cn`
- 對組織單位使用 `ou`
- 對域組件使用 `dc`
:::danger
TBD: what is schema? example? schema 文件如何引導 RDN 選擇?
:::
### Ojbect Class
接著是第二個問題:那麼我們怎麼知道一個 entry 可以使用哪些 attribute types 呢?可以看到範例 entry 的最下面有四個 `objectClass`。 這四個 object classes 其實也就規定了這個 entry 可以/必須使用的 attribute type。
根據 [RFC4512 Section 2.4](https://www.rfc-editor.org/rfc/rfc4512#section-2.4):
1. Each object class identifies the set of attributes required to be present in entries belonging to the class and the set of attributes allowed to be present in entries belonging to the class. ...
2. Each object class is defined to be one of three kinds of object classes: Abstract, Structural, or Auxiliary.
3. Each object class is identified by an object identifier (OID) and, optionally, one or more short names (descriptors).
簡單來說,**每個 entry 至少屬於 (belong to) 一個 object class,而每個 object class 都規定了這個 entry 必須 (MUST) 用哪些 attributes,以及可以 (MAY) 用哪些 attributes 來描述。**
透過實例很容易就可以理解 object class 的概念:[RFC4519 Section 3.9](https://www.rfc-editor.org/rfc/rfc4519.html#section-3.9) 中定義了 `organizationalRole` 這個 object class 必須 (MUST) 有 `cn` 這個 attribute,並且可以有 `ou`, `telephoneNumber` 等 attributes。
```
3.10. 'organizationalRole'
The 'organizationalRole' object class is the basis of an entry that
represents a job, function, or position in an organization.
(Source: X.521 [X.521])
( 2.5.6.8 NAME 'organizationalRole'
SUP top
STRUCTURAL
MUST cn
MAY ( x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $
teletexTerminalIdentifier $ telephoneNumber $
internationalISDNNumber $ facsimileTelephoneNumber $
seeAlso $ roleOccupant $ preferredDeliveryMethod $
street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ ou $ st $ l $
description ) )
```
:::info
LDAP object classes 的設計使用物件導向中多重繼承 (multiple inheritance) 的概念,細節參考 [RFC4512 Section 2.4](https://www.rfc-editor.org/rfc/rfc4512#section-2.4)。
:::
### 常見的 attribute types, object classes
目前我看到的範例當中使用到的 object class 皆可在 RFC 文件當中找到定義,可能為 LDAP 規格、 X.500 系列規格 。如
| RFC doc. | Name | object class listed | attribute type listed |
| ------- | ---- | --- | --- |
| RFC 4519 |LDAP: Schema for User Applications|`groupOfNames`, `organizationalPerson`, `country`, `device`, etc. |`dc`,`cn`,`o`,`ou`,`sn`,`uid`, etc.|
| RFC 4523 | LDAP Schema Definitions for X.509 Certificates| `pkiUser`, `userSecurityInformation`, etc.| `userCertificate`, `cACertificate`, `crossCertificatePair`, etc.|
| RFC 2079 | Definition of an X.500 Attribute Type and an Object Class to Hold Uniform Resource Identifiers (URIs) | `labeledURIObject` |`labeledURI`|
| RFC 2247 | Using Domains in LDAP/X.500 Distinguished Names |`dcObject`, `domain` |`dc`(domainComponent) |
| RFC 3112 | LDAP Authentication Password Schema |`authPasswordObject`|`authPassword`, `supportedAuthPasswordSchemes`|
其它像 `inetOrgPerson` object class 被單獨定義在 [RFC2798](https://www.rfc-editor.org/rfc/rfc2798.html),允許 (MAY) 的 attribute types 包括 `displayName`, `mail` 等。
在這些規格書中:
- 部份 object classes 必須被任何 LDAP server implementation 實作
- 部份 object classes 在規格書中提供參考,是否實作取決於各個 LDAP server implementation。
不過,只要符合規格 (主要為 RFC 4512),LDAP server implementation 仍然可以自行擴展 object classes。
## LDAP Operations
接下來看我們可以對一個 LDAP directory 做哪些 operations。記得 searching 和 browsing 的效能應該要是最被注重的。這邊只簡短紀錄,較完整的可參考 [wiki](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol#Operations) 或[規格書](https://www.rfc-editor.org/rfc/rfc4511.html)。
下列為簡化 LDAP 規格書的內容,而一般操作時會用工具來操作。如,server 為 OpenLDAP 時,可以用 command line tools: `ldapadd`, `ldapcompare`, `ldapsearch`, `ldapdelete` 等。
須注意:client 發起 request 之後,server 會回應 response。client 需要透過確認回應來確保應用邏輯完整。
> CRUD
1. `Add` 插入未存在於 directory 中的 entry,參數為 DN 及 attributes。 所插入的 DN 必須不存在,而其 parent 的 DN 必須存在。
2. `Delete` 移除特定 entry,傳入 DN 作為參數。只能刪除 leaf entry。
3. `Compare` 用來比較某個 entry 的特定 attribute 是否為特定值
- 參數為 entry DN 及 AVA (attribute type + value)
- server 會回應 `compareTrue`, `compareFalse` 或錯誤碼
- 可以用來驗證某個 password 值是否正確
4. `Search` 用來請求 server 返回符合特定搜索條件的 entry set,可以用於:
- 從單個條目讀取屬性
- 從特定條目的直接下級條目讀取屬性
- 從整個子樹的條目讀取屬性
- 使用上最複雜的 operation,另外紀錄在 [LDAP Search Operation](/dfe-HKncTfKIgW51I8lm5w) (TBD)
- OpenLDAP example: `ldapsearch -h ldap.example.com -b "ou=People,dc=example,dc=com" "(uid=jdoe)"`
5. `Modify`
6. `Modify DN`
## LDAP Technical Specification
自 2003 LDAPv2 完全退休後,目前的 LDAP 為 LDAPv3,相關規格定義在數個 [RFC](https://www.ietf.org/process/rfcs/) document 中,包括
| RFC doc.| Name |
| ------- | ---- |
| RFC4510 | LDAP: Technical Specification Road Map |
| RFC4511 | LDAP: The Protocol |
| RFC4512 | LDAP: Directory Information Models |
| RFC4513 | LDAP: Authentication Methods and Security Mechanisms |
| RFC4514 | LDAP: String Representation of Distinguished Names |
| RFC4515 | LDAP: String Representation of Search Filters |
| RFC4516 | LDAP: Uniform Resource Locator |
| RFC4517 | LDAP: Syntaxes and Matching Rules |
| RFC4518 | LDAP: Internationalized String Preparation |
| RFC4519 | LDAP: Schema for User Applications|
以下是我認為較重要的
1. [RFC4511: The Protocol](https://www.rfc-editor.org/rfc/rfc4511.html) 定義 LDAP client 與server 之間的通訊協定。它規範了LDAP的運作方式、訊息格式、以及各種操作(search, add, modify, etc.)的執行方式。
2. [RFC4512 Directory Information Models](https://www.rfc-editor.org/rfc/rfc4512.html) 定義了 LDAP 的資料模型,包含 object class, attribute type 的定義。
3. [RFC4513:Authentication Methods and Security Machanisms](https://www.rfc-editor.org/rfc/rfc4513.html) 定義 LDAP 的驗證和安全層,含 SASL 及 TLS。
4. [RFC4519: Schema for User Applications](https://www.rfc-editor.org/rfc/rfc4519.html) 許多常見的 attribute types 如 `o`, `ou`, `cn`, `dc`, `userPassword`,以及常見的 object classes 如 `person`, `organization`, `organizationalPerson`, `groupOfNames`, `device` 皆定義在此。
:::danger
注意:RFC2251, RFC3377 等較舊的文件也定義 LDAPv3,而上列 RFC4511 等文件為其修訂版,但並非完全捨棄先前版本。詳細請見 RFC4511, RFC4519 等文件當中的 "Relationship with Other Specifications" 段落。
:::
## LDAP Server Implementations
前述為 LDAP 規格相關,而市面上常見的 LDAP server implementation 有以下: (由 LLM 生成, 待驗證)
| LDAP 軟體 | 優勢 | 劣勢 | 適用場景 |
|-----------|------|------|--------|
| OpenLDAP | 免費開源、高可擴展性 | 設定較複雜、缺乏 GUI | 企業內部身份管理、Linux/Unix 環境 |
| Microsoft AD | 與 Windows 整合、易用 GUI | 需付費、依賴 Windows | Windows 企業環境、Microsoft 產品整合 |
| 389 Directory Server | 與 Red Hat 整合、支援多主同步 | 主要適用於 Red Hat、較少社群支援 | Red Hat/CentOS 企業、需要高可用性 |
| Apache Directory | 跨平台、內建 GUI | 社群較小、效能較低 | 需要 GUI 管理、LDAP + Kerberos 整合 |
## Reference
- RFC 4510 系列規格書
- [X.500 Wiki](https://en.wikipedia.org/wiki/X.500)
- [LDAP Wiki](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) 寫得不錯,[directory structure](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol#Directory_structure) 一看就懂
- [LDAP Linux HOWTO](https://tldp.org/HOWTO/LDAP-HOWTO/) 是 OpenLDAP 社群在 1.x 版本時撰寫的文件。
- [1.2 How does LDAP work?](https://tldp.org/HOWTO/LDAP-HOWTO/howitworks.html) 簡述 LDAP 的 C/S 架構
- [1.3. LDAP backends, objects and attributes](https://tldp.org/HOWTO/LDAP-HOWTO/ldapbackends.html) 含 LDIF 簡述,backend 的部份過時了。object class, attirbutes 可參考。
- [OpenLDAP Software 2.5 Administrator's Guide](https://www.openldap.org/doc/admin25/) 更改 url 可以看到其它版本
- [LDAPWiki](https://ldapwiki.com/wiki/Wiki.jsp?page=DIT) 我沒看但有人提到
# 未整理
## Example: Directory Layout for Enterprises
Admin 在規劃 direcotry layout 時,通常會採用哪些慣例?有哪些考量?
1. 如果整個企業可以很簡單的用部門、子部門劃分,可以使用以下 layout。每個員工都只屬於一個部門,不同 subtrees 之間沒有業務邏輯上的關聯。

2. 另一種劃分方式是:`ou=Users` 和 `ou=Groups` 在樹中是 siblings,前者包含該企業中所有員工,後者則包含該企業中所有群組(職稱、部門等)。但是,業務邏輯上,我們希望表達:`Ram` 這個 user 屬於 `Admin` 這個 group。應該怎麼做?此時就可以使用特定的 attribute types 來表達不同 entries 之間的關係
- `groupsOfUniqueName` 或 `uniqueMember` 可以用來表示不同 entries 之間的從屬關係。詳細需要再查。
