Metadata-Version: 2.4
Name: ldapforge
Version: 0.1.0
Summary: Twisted-based LDAPv3 compatible server with a pluggable SQLAlchemy backend
Author-email: rRR0VrFP <rrr0vrfp@qq.com>
License-Expression: MIT
Project-URL: Homepage, https://gitee.com/rRR0VrFP/ldap-forge
Project-URL: Repository, https://gitee.com/rRR0VrFP/ldap-forge
Project-URL: Issues, https://gitee.com/rRR0VrFP/ldap-forge/issues
Keywords: ldap,ldapv3,directory,authentication,twisted,sqlalchemy
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Framework :: Twisted
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Twisted>=22.10
Requires-Dist: SQLAlchemy>=2.0
Requires-Dist: alembic>=1.13
Requires-Dist: bcrypt>=4.0
Requires-Dist: cryptography>=42.0
Requires-Dist: pyOpenSSL>=23.0
Requires-Dist: service-identity>=21.0
Provides-Extra: postgres
Requires-Dist: psycopg2-binary>=2.9; extra == "postgres"
Provides-Extra: mysql
Requires-Dist: PyMySQL>=1.1; extra == "mysql"
Provides-Extra: client
Requires-Dist: ldap3>=2.9; extra == "client"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: ldap3>=2.9; extra == "dev"
Dynamic: license-file

# LdapForge 使用手册

LdapForge 是一套 **LDAPv3 目录服务**，用于集中管理用户账号、组织/组和应用（服务账号），
并提供标准的 LDAP 接口供各类业务系统、域管理系统和运维工具接入。

它面向两类使用者：

- **域管理员**：负责日常的账号、组织架构、应用与权限维护，可用命令行完成，
  也可选用部署栈集成的第三方图形界面 phpLDAPadmin。
- **域管理系统集成商**：负责把 LdapForge 接入自有平台，通过 LDAP、HTTP 管理 API
  或 MCP 服务完成账号同步、认证代理和目录查询。

> 本文档只介绍**怎么部署和使用**。生成一份带逐项注释的完整配置模板：
> `ldapforge initconfig`（仓库内为
> [`ldapforge/ldapforge.example.toml`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/ldapforge/ldapforge.example.toml)）。

## 核心能力

- 标准 LDAPv3 协议：绑定、查询、增删改、ModifyDN、比较、StartTLS、LDAPS。
- 用户、组织（可无限层级）、组、应用（服务账号）与成员关系的统一管理。
- **应用代理认证**：业务系统先以应用身份绑定，再代理用户认证，并校验用户是否属于该应用。
- 账号策略：登录失败锁定、账号有效期、用户↔应用绑定有效期、过期自动软删除清理。
- 密码策略：pbkdf2（默认）、bcrypt、SHA/SSHA、MD5/SMD5 等多种存储方案。
- 数据落库加密：所有数据列以 AES-SIV 透明加密，等值查询不受影响。
- 认证审计：每一次绑定（成功/失败）都写入认证日志，可查询、可清理。
- 三种管理入口：命令行、HTTP 管理 API、MCP 服务。

## 安装

从 PyPI 安装（推荐用于生产或集成到自有环境）：

```sh
pip3 install ldapforge
# 连接 MySQL / PostgreSQL 时附带对应驱动：
pip3 install 'ldapforge[mysql]'      # PostgreSQL 用 'ldapforge[postgres]'
```

安装后会提供 `ldapforge` 命令（等价于 `python3 -m ldapforge`）。
落库加密密钥为**必填项**，初始化前需先导出：

```sh
export LDAPFORGE_ENCRYPTION_KEY="请替换为32位随机字符串"
ldapforge initconfig                     # 生成 ldapforge.toml（按需修改）
ldapforge initdb --client-mode direct    # 初始化数据库与基础条目
ldapforge serve                          # 启动服务
```

> `initdb`、`migrate`、`purge` 等直连数据库的命令需加 `--client-mode direct`
> （或在 `[ldapforge-client]` 中设 `mode = "direct"`）。
> 管理员密码留空时，`initdb` 会生成一个强密码并只打印一次；如需自定义，设置
> `admin_password` 或 `LDAPFORGE_ADMIN_PASSWORD`。

## 快速部署（推荐）

整套演示/生产基础环境（MySQL + 双份 LdapForge + nginx 负载均衡，以及随栈启动的
第三方 phpLDAPadmin Web 界面，可自行停用或移除）可用一条命令启动，默认使用
**podman**。

### 前置条件

- podman（及 podman-compose 可选）
- 可访问容器镜像仓库（MySQL、nginx、phpLDAPadmin）
- 一个 **32 位随机字符串**作为落库加密密钥（必填）

### 启动

```sh
export LDAPFORGE_ENCRYPTION_KEY="请替换为32位随机字符串"
./deploy/run.sh
```

脚本会自动：创建网络、启动 MySQL、构建 LdapForge 镜像、生成共享 TLS 自签证书、
启动两个 LdapForge 副本、启动 nginx 负载均衡和 phpLDAPadmin。

### 启动后可用的地址与默认凭据

| 用途 | 地址 |
| --- | --- |
| LDAPv3（含 StartTLS） | `ldap://127.0.0.1:3890` |
| LDAPS（隐式 TLS） | `ldaps://127.0.0.1:6360` |
| phpLDAPadmin 管理界面（第三方） | http://127.0.0.1:8081 |
| HTTP 管理 API | http://127.0.0.1:4711/api/v1 |
| MCP 管理服务 | http://127.0.0.1:4712/mcp |
| MCP 应用认证服务 | http://127.0.0.1:4713/mcp |

| 项目 | 默认值 |
| --- | --- |
| 管理员绑定 DN | `cn=admin,dc=example,dc=com` |
| 管理员密码 | 未指定 `LDAP_ADMIN_PASSWORD` 时自动生成并打印 |
| 根后缀 Base DN | `dc=example,dc=com` |
| 用户容器 Users DN | `cn=users,cn=accounts,dc=example,dc=com` |
| 组容器 Groups DN | `cn=groups,cn=accounts,dc=example,dc=com` |
| 应用容器 Applications DN | `cn=applications,cn=accounts,dc=example,dc=com` |

> **上线前务必修改**管理员密码、Base DN 和加密密钥，并替换为受信任的 TLS 证书。
> 以上默认值可通过环境变量覆盖（见 [`deploy/run.sh`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/deploy/run.sh) 顶部的变量列表）。

### 停止

```sh
./deploy/stop.sh
```

### 不用容器？本机运行

适合集成商在自己的测试环境快速验证：

```sh
python3 -m venv .venv && . .venv/bin/activate
pip3 install -e '.[dev]'

export LDAPFORGE_ENCRYPTION_KEY="请替换为32位随机字符串"
python3 -m ldapforge initconfig                   # 生成 ldapforge.toml（按需修改）
python3 -m ldapforge initdb --client-mode direct  # 初始化数据库与基础条目
python3 -m ldapforge serve                        # 启动服务
```

默认监听 `127.0.0.1:3890`（明文 + StartTLS）与 `127.0.0.1:6366`（LDAPS），
数据存放在 `var/ldapforge.db`。管理员为 `uid=admin,ou=users,dc=example,dc=com`；
`admin_password` 留空时，`initdb` 会生成一个强密码并在终端打印一次，请及时保存。

## 初始化数据库

LdapForge 需要一张数据库来存放账号、组织、应用和审计记录。相关命令：

- `python3 -m ldapforge initconfig`：生成一份带注释的配置模板 `ldapforge.toml`
  （默认写到当前目录，已存在时不覆盖，加 `--force` 覆盖）。
- `python3 -m ldapforge migrate`：建表 / 应用结构变更（Alembic 迁移）。
- `python3 -m ldapforge initdb`：在表结构之上写入基础条目（Base DN、容器、管理员等）。

按部署方式不同，建库步骤也不同：

### 容器一键栈（无需手动）

`./deploy/run.sh` 会自动创建 MySQL 库，容器启动时由入口脚本依次执行
`migrate` 和 `initdb`，**无需任何手工操作**。默认库名为 `ldapdemo`，
可在启动前用 `MYSQL_DATABASE` 等变量覆盖。

### 本机 SQLite（推荐用于试用）

SQLite 无需预先建库，`initdb` 会自动创建数据库文件和所有表：

```sh
export LDAPFORGE_ENCRYPTION_KEY="请替换为32位随机字符串"
python3 -m ldapforge initdb --client-mode direct   # 自动建库 + 建表 + 基础条目
```

数据库位置由配置项 `backend_sqlite3`（默认 `var/ldapforge.db`）决定。

### 外部 MySQL / PostgreSQL（生产常用）

数据库实例需由 DBA / 集成商自行创建，LdapForge 不会替你创建库和账号：

```sql
-- MySQL 示例
CREATE DATABASE ldapdemo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'ldapforge'@'%' IDENTIFIED BY '强密码';
GRANT ALL PRIVILEGES ON ldapdemo.* TO 'ldapforge'@'%';
FLUSH PRIVILEGES;
```

然后在配置里指向该库，并执行迁移与初始化：

```toml
[ldapforge]
backend = "mysql"
backend_mysql = "mysql+pymysql://ldapforge:强密码@127.0.0.1:3306/ldapdemo?charset=utf8mb4"
# PostgreSQL 同理：backend = "postgresql"，
# backend_postgresql = "postgresql+psycopg2://user:pass@127.0.0.1/ldapdemo"
```

```sh
pip3 install -e '.[mysql]'       # PostgreSQL 用 '.[postgres]'
export LDAPFORGE_ENCRYPTION_KEY="请替换为32位随机字符串"
python3 -m ldapforge migrate --client-mode direct   # 建表
python3 -m ldapforge initdb --client-mode direct    # 写入基础条目
```

> 迁移与初始化命令只在 `direct` 模式（直连数据库）下可用，不能通过 LDAP 远程执行。
> 已有旧数据升级时，只需执行 `python3 -m ldapforge migrate --client-mode direct`。

## 用图形界面管理目录（集成的第三方 phpLDAPadmin）

> **phpLDAPadmin 不是 LdapForge 内置的服务**，而是我们**集成的第三方 Web 管理界面**。
> 它作为独立容器由部署栈（[`deploy/compose.yaml`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/deploy/compose.yaml) /
> [`deploy/run.sh`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/deploy/run.sh)）单独启动，通过标准 LDAP 协议连接 LdapForge，
> 不属于 LdapForge 程序本身，也不随 `ldapforge` 软件包分发。

**集成方式**：

- 部署栈单独启动 `phpldapadmin` 容器（宿主机 `8081` → 容器 `8080`）。
- 它通过内部 nginx TCP 负载均衡以标准 LDAP 访问 LdapForge
  （`ldapforge-lb:389`），无需 LdapForge 做任何特殊适配。
- 关键对接配置（见 `deploy/compose.yaml` / `deploy/run.sh`）：
  - `LDAP_HOST` / `LDAP_PORT`：指向负载均衡的 LDAP 地址与端口；
  - `LDAP_BASE_DN`：目录 Base DN；
  - `LDAP_LOGIN_ATTR=uid`、`LDAP_LOGIN_OBJECTCLASS`：登录属性与可选对象类；
  - `LDAP_USERNAME` / `LDAP_PASSWORD`：供登录前检索用的服务账号（默认管理员；
    因默认拒绝匿名绑定，必须有此账号）；
  - `LDAP_GUIDKEY=entryuuid`：用 LdapForge 的 `entryUUID` 作为条目唯一标识；
  - 挂载 `deploy/phpldapadmin/templates/user_account.json`，用匹配本数据模型的
    inetOrgPerson 表单替换官方镜像的 POSIX 模板。

登录后即可浏览组织树、新建/编辑用户、重置密码、维护组织与组成员、查看应用成员。
应用条目使用 `groupOfNames` + `uidObject` 标准对象类，组使用 `groupOfNames` 并在
有成员时暴露 `member` 属性，因此 phpLDAPadmin 会直接显示“成员”面板。

若不需要 Web 界面，可以完全跳过该容器，改用命令行、HTTP 管理 API 或 MCP。

## 目录结构与命名规范

```
dc=example,dc=com                        （Base DN）
├── cn=accounts,dc=example,dc=com
│   ├── cn=users,cn=accounts,...         用户容器    uid=<用户名>
│   ├── cn=groups,cn=accounts,...        组容器      cn=<组名>（可嵌套）
│   └── cn=applications,cn=accounts,...  应用容器    uid=<应用ID>
└── cn=admin,dc=example,dc=com           管理员
```

- 用户条目：`uid=<用户名>,<Users DN>`
- 组条目：`cn=<组名>,<Groups DN>`，组内可再建子组
- 应用条目：`uid=<应用ID>,<Applications DN>`
- 用户与组/应用的成员关系通过 `memberOf` / `member` 属性对外呈现

## 日常管理任务

除图形界面外，管理员也可在服务器或容器内使用命令行（`python3 -m ldapforge <命令>`）。

| 任务 | 命令示例 |
| --- | --- |
| 新建用户 | `python3 -m ldapforge createuser --uid alice --password s3cret` |
| 新建应用 | `python3 -m ldapforge addapp portal` |
| 列出应用 | `python3 -m ldapforge listapps` |
| 为应用签发访问密钥 | `python3 -m ldapforge addkey portal <key>` |
| 新建组织/组 | `python3 -m ldapforge addorg --dn "cn=研发部,<Groups DN>"` |
| 用户加入组/应用 | `python3 -m ldapforge binduser --uid alice --member-dn "cn=研发部,<Groups DN>"` |
| 带有效期加入应用 | `python3 -m ldapforge binduser --uid alice --app-id app01 --valid-until 2030-01-01T00:00:00Z` |
| 移出组/应用 | `python3 -m ldapforge unbinduser --uid alice --member-dn "cn=研发部,<Groups DN>"` |
| 查看成员/归属 | `python3 -m ldapforge listbindings --member-dn "cn=研发部,<Groups DN>"` |
| 查看认证日志 | `python3 -m ldapforge authlogs` |
| 导出 / 导入 LDIF | `python3 -m ldapforge export out.ldif` / `python3 -m ldapforge import out.ldif` |
| 清理过期账号/绑定 | `python3 -m ldapforge purge` |
| 常驻维护进程 | `python3 -m ldapforge maintain --client-mode direct` |

**完整命令清单见 [附录 A. 命令行命令](#a-命令行命令ldapforge-命令)。**

用户也可以通过标准 LDAP 客户端直接操作（需管理员绑定 DN 鉴权），例如：

```sh
ldapsearch -x -H ldap://127.0.0.1:3890 \
  -D 'cn=admin,dc=example,dc=com' -w '<管理员密码>' \
  -b 'dc=example,dc=com' '(uid=alice)'
```

> 管理员密码：容器栈由 `./deploy/run.sh` 启动时生成并打印（也可用
> `LDAP_ADMIN_PASSWORD` 预先指定）；本机运行则由 `initdb` 生成并打印。

## 认证与权限

### 两种认证模式

- **直连模式（direct）**：用户用自己的 DN 直接绑定，最直观，适合内部可信环境。
- **应用代理模式（application，容器部署默认）**：用户不能直接绑定；业务系统必须先以
  应用身份绑定，再代理绑定（rebind）用户，且该用户必须是此应用的成员。
  这样能精确控制“哪个系统可以认证哪些用户”。

### 访问控制默认策略

- 拒绝匿名绑定（`allow_anonymous=false`）。
- 只有管理员 DN 可以写入；已认证用户在默认情况下只能读取自己的条目。
- 密码属性默认不返回给查询者（仅用于认证）。

如需更细粒度授权（例如“运维组可改用户密码”），可在配置里编写 OpenLDAP 风格的
ACL 规则，详见 [`ldapforge initconfig`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/ldapforge/ldapforge.example.toml) 生成的配置模板
（access control 段落）。

### 账号与绑定有效期

有两种有效期，互不影响：

- **用户账号级**：`accountValidFrom` / `accountValidUntil`（`createuser
  --valid-from/--valid-until`）。不在窗口内，该用户**任何**绑定都被拒绝。
- **用户↔应用绑定级**：在把用户绑定到应用时指定，例如：

  ```sh
  python3 -m ldapforge binduser --uid alice --app-id app01 \
    --valid-from 2026-01-01T00:00:00Z --valid-until 2030-01-01T00:00:00Z
  ```

  不在窗口内时，禁止该用户通过该应用代理认证（直连用户绑定不受应用绑定窗口约束）。
  HTTP `POST /api/v1/bindings` 与 MCP `bind_member` 同样接受 `valid_from` /
  `valid_until`；有效期设置需要直连数据库（`--client-mode direct`），无法通过 LDAP 远程设置。

绑定过期后先进入宽限期（仍可见为 `memberOf`，但已不可认证），超过
`expired_binding_retention_days` 天后由维护进程**软删除**：从 `member` / `memberOf`
中消失，但数据库行保留（`deleted_at`）作为留痕；之后重新绑定会复用并复活该行。
`0`（默认）表示到期当日 24:00（UTC）即删除，负数表示永不自动删除。

### 维护进程

过期账号清理、绑定软删除、认证日志裁剪由维护进程执行：

- 独立进程：`python3 -m ldapforge maintain`（需 `--client-mode direct`）。
- 或由 `serve` 内置（`maintenance_enabled`，默认开启）。两者都会用数据库里的命名锁
  互斥，多副本同时运行时同一时刻只有一份扫描会真正执行，避免重复处理。

## SSL/TLS

容器部署默认生成一张自签证书供 StartTLS 和 LDAPS 共用（位于 `deploy/tls/`）。
生产环境请替换为受信任的 CA 证书：

```toml
tls_port = 636
tls_certificate = "certs/server.crt"
tls_private_key = "certs/server.key"
```

也可用内置工具生成证书对：`python3 -m ldapforge gencert --help`。

## 系统集成

### LDAP 接入参数

交给业务系统或域管理系统填写：

| 参数 | 值 |
| --- | --- |
| 服务器地址 | `127.0.0.1`（或负载均衡地址） |
| 端口 | `389`（明文/StartTLS）或 `636`（LDAPS） |
| Base DN | `dc=example,dc=com` |
| 用户搜索 Base | `<Users DN>` |
| 用户登录属性 | `uid` |
| 管理员绑定 DN | `cn=admin,dc=example,dc=com` |

### HTTP 管理 API（集成商）

用于在自己的平台里同步账号、组织、应用与审计信息。需在配置中启用并设置 API Key：

```toml
http_api_enabled = true
http_api_host = "127.0.0.1"
http_api_port = 4711

# 多个 API Key：重复书写 [[ldapforge.api_keys]] 块，每个块是一把密钥。
[[ldapforge.api_keys]]
name = "ops"
key = "change-me"        # 也可写 "sha256:<hex>" 只存摘要

[[ldapforge.api_keys]]
name = "audit"
key = "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
read_only = true         # 只读密钥，禁止 POST/PUT/PATCH/DELETE

[[ldapforge.api_keys]]
name = "ci"
key = "another-secret"
```

也可以改用环境变量（JSON 数组）或命令行（`--api-key` 可重复）：

```sh
export LDAPFORGE_API_KEYS='[{"name":"ops","key":"change-me"},{"name":"audit","key":"sha256:<hex>","read_only":true}]'
# 或
ldapforge serve --api-key ops=change-me --api-key audit=sha256:<hex>
```

每次请求需携带 `Authorization: Bearer <key>` 或 `X-API-Key: <key>`；
只读密钥可加 `read_only = true`。`/health` 无需鉴权。

```sh
curl -H 'Authorization: Bearer change-me' http://127.0.0.1:4711/api/v1/whoami
curl -H 'Authorization: Bearer change-me' http://127.0.0.1:4711/api/v1/users
```

覆盖条目、用户、应用与密钥、成员关系、组织、认证日志、导入导出与清理等；
**完整的方法、路径与参数清单见 [附录 C. HTTP 管理 API](#c-http-管理-api)**。

### MCP 服务（面向应用开发者 / 管理员 / 集成商，非终端用户）

提供两个 Streamable HTTP（JSON-RPC 2.0）服务，客户端向 `/mcp` 发送
`initialize`、`tools/list`、`tools/call`：

- **管理服务**（`mcp_management_port`，默认 4712）：面向**管理员 / 运维 / 集成商**，
  提供完整的管理能力，用 `[[ldapforge.mcp_api_keys]]` 中的密钥鉴权，如
  `create_user`、`list_users`、`set_user_password`、`create_application`、
  `bind_member`、`export_ldif` 等。与 `api_keys` 一样，**重复书写
  `[[ldapforge.mcp_api_keys]]` 块即可配置多把密钥**（每把可加 `read_only = true`）。
- **应用认证服务**（`mcp_app_auth_port`，默认 4713）：**面向应用开发者 / 业务系统，
  不得面向终端用户**。它由业务系统用自身 LDAP 应用密钥
  （`X-App-Id` + `Authorization: Bearer <key>` 或 `X-API-Key`）调用，代表应用去校验
  用户、查询成员关系；终端用户不直接接触该服务。提供 `authenticate_user`、
  `check_user_membership`、`user_exists`、`get_user`、`list_application_members`、
  `application_info` 等只读工具。

> **定位说明**：两个 MCP 服务都是**给程序调用的服务接口**，不是给终端用户使用的
> 界面。
> - **管理服务**面向管理员/运维/集成商的管理侧程序，拥有完整管理权限（可创建用户、
>   改密、绑定成员等），**必须仅限管理网段访问，不得面向终端用户或暴露到公网**。
> - **应用认证服务**面向应用开发者/业务系统，**不得面向终端用户**；须部署在受信任
>   网络内，**切勿把应用密钥下发给终端用户或暴露到公网**。

**完整工具清单见 [附录 D. MCP 工具](#d-mcp-工具)**。

### 常用环境变量

容器部署全部通过环境变量配置，常用项：

| 变量 | 说明 | 默认 |
| --- | --- | --- |
| `LDAPFORGE_ENCRYPTION_KEY` | 落库加密密钥（**必填**） | 无 |
| `LDAPFORGE_BASE_DN` | 根后缀 | `dc=example,dc=com` |
| `LDAPFORGE_ADMIN_DN` / `LDAPFORGE_ADMIN_PASSWORD` | 管理员凭据 | `cn=admin,...` / 未设置时自动生成并打印 |
| `LDAPFORGE_AUTH_MODE` | `direct` 或 `application` | `application` |
| `LDAPFORGE_ALLOW_ANONYMOUS` | 是否允许匿名绑定 | `false` |
| `LDAPFORGE_ALLOW_AUTHENTICATED_READS` | 已认证用户可读全目录 | `false` |
| `LDAPFORGE_ALLOW_AUTHENTICATED_WRITES` | 已认证用户可写 | `false` |
| `LDAPFORGE_MAX_FAILED_ATTEMPTS` / `LDAPFORGE_LOCKOUT_SECONDS` | 失败锁定次数/时长 | `5` / `900` |
| `LDAPFORGE_EXPIRED_BINDING_RETENTION_DAYS` | 绑定过期后软删除前的宽限天数 | `0`（当日 24:00 UTC） |
| `LDAPFORGE_MAINTENANCE_ENABLED` | 是否在 `serve` 内跑维护扫描 | `true` |
| `LDAPFORGE_API_KEYS` / `LDAPFORGE_MCP_API_KEYS` | 管理 API / MCP 密钥（JSON 数组） | `[]` |
| `LDAPFORGE_EVENT_SINK` | 审计事件去向 | `database` |

完整清单见 [`deploy/run.sh`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/deploy/run.sh)、[`deploy/compose.yaml`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/deploy/compose.yaml)
和 `ldapforge initconfig` 生成的配置模板。

## 运维

- **备份/恢复**：容器栈的数据在 MySQL 卷 `ldapforge-mysql-data` 中；也可用
  `python3 -m ldapforge export backup.ldif` 导出全部条目。恢复用 `import`。
- **审计日志**：每次绑定都记录在认证日志中，用 `authlogs` 命令或
  `GET /api/v1/authlogs` 查询；可设置保留时长自动清理。
- **升级**：执行 `python3 -m ldapforge migrate --client-mode direct` 应用数据库结构变更。
- **故障排查**：查看容器日志 `podman logs ldapforge`；确认 MySQL 健康、
  TLS 证书路径与加密密钥一致。

## 附录：服务接口一览

本节完整列出各类管理/接入接口。所有写操作默认仅管理员可用（详见
[认证与权限](#认证与权限)）。

### A. 命令行命令（`ldapforge <命令>`）

| 命令 | 说明 |
| --- | --- |
| `serve` | 启动 LDAP 服务（结合配置/参数） |
| `initconfig [PATH]` | 生成带注释的配置模板（`--force` 覆盖已存在文件） |
| `initdb` / `seed` | 创建表并写入基础条目（Base DN、容器、管理员） |
| `migrate` | 应用数据库结构迁移（Alembic） |
| `encryptdb` | 扩容加密列并回填、加密已有明文数据 |
| `export` | 导出条目到 LDIF 文件或标准输出 |
| `import` | 从 LDIF 文件或标准输入导入条目 |
| `purge` | 删除超出保留期的过期账号，并软删除超期绑定 |
| `maintain` | 以独立进程常驻执行 purge/软删除/日志裁剪（数据库锁互斥） |
| `createuser` | 创建用户条目 |
| `addapp` | 创建应用服务账号 |
| `listapps` | 列出应用服务账号 |
| `addkey` | 为应用添加 API key |
| `delkey` | 删除应用的某个 API key |
| `listkeys` | 列出应用的 API key |
| `binduser` | 将用户绑定到应用/组（`--valid-from`/`--valid-until` 设置绑定有效期） |
| `unbinduser` | 解除用户/应用的绑定 |
| `listbindings` | 列出应用/组/组织的成员，或用户的归属 |
| `addorg` | 创建组织单位或组 |
| `authlogs` | 查看认证日志 |
| `gencert`（别名 `cert`、`certificate`） | 生成 TLS 证书/私钥对 |

通用选项：`--config PATH`、`--client-mode {ldap,direct}`、`--database URL`、
`--base-dn`、`--users-dn`、`--applications-dn`、`--groups-dn`、`--admin-dn`、
`--admin-password` 等；`direct` 模式才可执行 `initdb`、`migrate`、`purge`、
`maintain`、`authlogs`、`addkey`、`delkey`、`listkeys` 等需要直连数据库的命令。

### B. LDAP 协议操作

| 操作 | 说明 |
| --- | --- |
| Bind | 简单绑定 / 匿名绑定（默认拒绝）/ 应用代理绑定 |
| Unbind | 断开连接 |
| Search | 查询条目（支持分页等控件） |
| Add | 新增条目 |
| Modify | 修改条目属性 |
| Delete | 删除条目 |
| ModifyDN | 重命名 / 移动条目 |
| Compare | 比较属性值 |
| Abandon | 放弃未完成请求 |
| StartTLS | 在明文连接上协商 TLS（OID `1.3.6.1.4.1.1466.20037`） |
| Extended: WhoAmI | 返回当前绑定身份（OID `1.3.6.1.4.1.4203.1.11.3`） |
| Extended: Password Modify | 修改密码（OID `1.3.6.1.4.1.4203.1.11.1`） |

### C. HTTP 管理 API

- 基址：`http://<host>:<http_api_port>/api/v1`（默认端口 `4711`）。
- 鉴权：`Authorization: Bearer <key>` 或 `X-API-Key: <key>`；`read_only` 密钥禁止写操作。
- `GET /health`（位于 `/api/v1` 之外）无需鉴权。
- 请求/响应均为 JSON；错误格式 `{"error": "...", "code": "..."}`。
- 路径中的 `{dn}` 含特殊字符时应做 URL 编码（服务端会解码）。

| 方法 | 路径（`/api/v1` 之后） | 说明 / 主要参数 |
| --- | --- | --- |
| GET | `/` | 服务与目录信息 |
| GET | `/whoami` | 当前密钥名称与是否只读 |
| GET | `/count` | 条目总数 |
| GET | `/entries` | 查询条目：`base`、`scope`、`filter`、`attributes`、`size_limit` |
| POST | `/entries` | 新增条目：`dn`、`attributes` |
| GET | `/entries/{dn}` | 按 DN 获取条目 |
| PUT | `/entries/{dn}` | 替换条目属性（body 为属性对象） |
| PATCH | `/entries/{dn}` | 修改条目（LDAP 修改语义） |
| DELETE | `/entries/{dn}` | 删除条目 |
| GET | `/entries/{dn}/children` | 是否含直接子条目 |
| POST | `/entries/{dn}/compare` | 比较属性：`attribute`、`value` |
| POST | `/entries/{dn}/rename` | 重命名/移动：`new_rdn`、`delete_old_rdn`、`new_superior` |
| GET | `/users` | 列出用户：`filter`、`attributes`、`size_limit` |
| POST | `/users` | 创建用户：`uid`、`dn`、`cn`、`sn`、`mail`、`password`、`object_class`、`valid_from`、`valid_until`、`attributes` |
| GET | `/users/{uid}` | 按 uid 获取用户 |
| PATCH | `/users/{uid}` | 修改用户 |
| DELETE | `/users/{uid}` | 删除用户 |
| POST | `/users/{uid}/password` | 设置密码：`password`（或 `userPassword`） |
| GET | `/applications` | 列出应用 |
| POST | `/applications` | 创建应用：`app_id`、`display_name`、`description`、`enabled`、`password`、`extra` |
| GET | `/applications/{app}` | 获取应用 |
| PATCH | `/applications/{app}` | 更新应用：`display_name`、`description`、`enabled` |
| DELETE | `/applications/{app}` | 删除应用及其密钥 |
| POST | `/applications/{app}/enable` 或 `/disable` | 启用/停用应用 |
| GET | `/applications/{app}/keys` | 列出应用密钥 |
| POST | `/applications/{app}/keys` | 新增密钥：`password`（或 `key`）、`label`、`expires_at` |
| DELETE | `/applications/{app}/keys/{key_id}` | 删除密钥 |
| POST | `/applications/{app}/keys/{key_id}/enable` 或 `/disable` | 启用/停用密钥 |
| GET | `/members` | 列出成员：`member_dn`（或 `app_dn`） |
| GET | `/memberships` | 列出归属：`user_dn`（或 `uid`） |
| POST | `/bindings` | 建立绑定：`user_dn`、`member_dn`、`enabled`、`valid_from`、`valid_until`（后两者仅应用绑定） |
| DELETE | `/bindings` | 解除绑定：`user_dn`、`member_dn`（可放 body 或查询串） |
| GET | `/orgs` | 列出组织/组：`base`、`scope`、`filter` |
| POST | `/orgs` | 创建组织/组：`dn`、`kind`（`group`/`ou`）、`name`、`description` |
| GET | `/orgs/{dn}/members` | 列出组织/组成员 |
| DELETE | `/orgs/{dn}` | 删除组织/组 |
| GET | `/authlogs` | 认证日志：`limit`、`offset`、`dn`、`application`、`success`、`type`、`since` |
| GET | `/authlogs/count` | 认证日志计数：`dn`、`success`、`since` |
| DELETE | `/authlogs` | 清理认证日志：`older_than` |
| GET | `/export` | 导出 LDIF：`base_dn`、`scope`、`users_only`、`include_passwords` |
| POST | `/import` | 导入 LDIF：`ldif`、`skip_existing` |
| POST | `/purge/expired` | 清理过期账号并软删除超期绑定 |
| POST | `/purge/authlogs` | 按保留策略清理认证日志 |

### D. MCP 工具

> 两者均为**给程序调用的服务接口**，不面向终端用户：管理服务面向管理员/运维/
> 集成商，应用认证服务面向应用开发者/业务系统。

**管理服务**（默认 `4712`，**面向管理员 / 运维 / 集成商等管理侧程序，不得面向
终端用户**；鉴权 `[[ldapforge.mcp_api_keys]]`）：

| 工具 | 说明 |
| --- | --- |
| `directory_info` | 服务与目录信息 |
| `directory_count` | 条目总数 |
| `search_entries` | 按 RFC 4515 过滤器查询条目 |
| `get_entry` | 按 DN 获取条目 |
| `create_entry` | 新增条目（LDAP add） |
| `replace_entry` | 替换条目指定属性 |
| `modify_entry` | 应用 LDAP 修改 |
| `delete_entry` | 按 DN 删除条目 |
| `rename_entry` | 重命名/移动条目（ModifyDN） |
| `entry_children` | 条目是否有直接子条目 |
| `compare_attribute` | 比较属性值（LDAP compare） |
| `list_users` | 列出用户 |
| `create_user` | 创建用户 |
| `get_user` | 按 uid/DN 获取用户 |
| `update_user` | 修改用户 |
| `delete_user` | 删除用户 |
| `set_user_password` | 设置用户密码 |
| `list_applications` | 列出应用 |
| `create_application` | 创建应用 |
| `get_application` | 获取应用 |
| `update_application` | 更新应用 |
| `delete_application` | 删除应用及其密钥 |
| `set_application_enabled` | 启用/停用应用 |
| `list_application_keys` | 列出应用密钥 |
| `add_application_key` | 新增应用密钥 |
| `remove_application_key` | 删除应用密钥 |
| `set_application_key_enabled` | 启用/停用应用密钥 |
| `list_members` | 列出应用/组成员 |
| `list_memberships` | 列出用户的归属 |
| `bind_member` | 绑定用户到应用/组（`valid_from`/`valid_until` 设置应用绑定有效期） |
| `unbind_member` | 解除绑定 |
| `list_organisations` | 列出组织/组 |
| `create_organisation` | 创建组织/组 |
| `delete_organisation` | 删除组织/组 |
| `list_authentication_logs` | 列出认证日志 |
| `count_authentication_logs` | 认证日志计数 |
| `clear_authentication_logs` | 清理认证日志 |
| `export_ldif` | 导出 LDIF |
| `import_ldif` | 导入 LDIF |
| `purge_expired_accounts` | 清理过期账号并软删除超期应用绑定 |
| `purge_authentication_logs` | 按保留策略清理认证日志 |

**应用认证服务**（默认 `4713`，面向应用开发者 / 业务系统，**不得面向终端用户**；
鉴权：`X-App-Id` + 应用密钥）：

| 工具 | 说明 |
| --- | --- |
| `application_info` | 当前已认证应用的信息 |
| `authenticate_user` | 以本应用身份校验用户密码 |
| `check_user_membership` | 用户是否属于本应用 |
| `user_exists` | 用户是否存在 |
| `get_user` | 获取用户属性（隐藏密码） |
| `list_application_members` | 列出绑定到本应用的用户 |

调用方式：向 `/mcp` POST JSON-RPC 2.0 请求（`initialize`、`tools/list`、`tools/call`）。

### E. phpLDAPadmin（第三方，非内置）

- **性质**：第三方开源 Web 管理界面，**不属于 LdapForge 内置服务**，不随
  `ldapforge` 包分发。
- **集成方式**：由部署栈作为独立容器启动，通过内部 nginx 负载均衡以标准 LDAP
  连接 LdapForge；不需要 LdapForge 侧的特殊插件。对接参数（`LDAP_HOST`、
  `LDAP_BASE_DN`、`LDAP_LOGIN_ATTR`、`LDAP_GUIDKEY` 等）见
  [用图形界面管理目录](#用图形界面管理目录集成的第三方-phpldapadmin) 与
  [`deploy/compose.yaml`](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/deploy/compose.yaml)。
- **能力范围**：完全取决于上面的 LDAP 协议操作，LdapForge 不为其提供专用接口。

## 版本记录

### 0.1.0（首个版本）

- LDAPv3 服务：绑定、查询、增删改、ModifyDN、比较、StartTLS、LDAPS。
- 用户 / 组织（任意层级）/ 组 / 应用（服务账号）与成员关系管理。
- 应用代理认证（先绑定应用，再代理用户，并校验成员关系）。
- OpenLDAP 风格 ACL；默认拒绝匿名、仅管理员可写。
- 账号策略：失败锁定、账号有效期、用户↔应用绑定有效期、过期账号/绑定自动清理。
- 多种密码存储方案（pbkdf2 / bcrypt / sha / ssha / md5 / smd5 等）。
- 数据落库 AES-SIV 加密。
- 认证日志与可插拔审计事件（logging / file / HTTP / database / null）。
- 管理命令行、HTTP 管理 API、管理与应用认证 MCP 服务；内置 `initconfig`
  生成配置模板（模板随包分发）。
- 数据库结构迁移（Alembic）与 `entryUUID` 操作属性。
- Podman 容器镜像与 compose 栈（nginx 负载均衡 + 第三方 phpLDAPadmin）、内置
  `gencert` 证书工具。
- Docker 镜像内置 MySQL 与 PostgreSQL 驱动。
- 附带面向域管理员与集成商的中文使用手册。

## 许可证

[MIT](https://gitee.com/rRR0VrFP/ldap-forge/blob/master/LICENSE)
