# LdapForge **Repository Path**: rRR0VrFP/ldap-forge ## Basic Information - **Project Name**: LdapForge - **Description**: Forge a standard LDAP v3 directory from any backend — one auth entry for all your services. - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-11 - **Last Updated**: 2026-10-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 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/management | | 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=<用户名>,` - 组条目:`cn=<组名>,`,组内可再建子组 - 应用条目:`uid=<应用ID>,` - 用户与组/应用的成员关系通过 `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 ` | | 新建组织/组 | `python3 -m ldapforge addorg --dn "cn=研发部,"` | | 用户加入组/应用 | `python3 -m ldapforge binduser --uid alice --member-dn "cn=研发部,"` | | 带有效期加入应用 | `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=研发部,"` | | 查看成员/归属 | `python3 -m ldapforge listbindings --member-dn "cn=研发部,"` | | 查看认证日志 | `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/management/bindings/create` 与 MCP `bindings_create` 同样接受 `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 | `` | | 用户登录属性 | `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:" 只存摘要 [[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:","read_only":true}]' # 或 ldapforge serve --api-key ops=change-me --api-key audit=sha256: ``` 每次请求需携带 `Authorization: Bearer ` 或 `X-API-Key: `; 只读密钥可加 `read_only = true`。`/health` 无需鉴权。 ```sh curl -H 'Authorization: Bearer change-me' http://127.0.0.1:4711/api/v1/management/whoami curl -H 'Authorization: Bearer change-me' http://127.0.0.1:4711/api/v1/management/count ``` 覆盖条目、用户、应用与密钥、成员关系、组织、认证日志、导入导出与清理等; **完整的方法、路径与参数清单见 [附录 C. HTTP 管理 API](#c-http-管理-api)**。 ### MCP 服务(面向应用开发者 / 管理员 / 集成商,非终端用户) 提供两个 Streamable HTTP(JSON-RPC 2.0)服务,客户端向 `/mcp` 发送 `initialize`、`tools/list`、`tools/call`: - **管理服务**(`mcp_management_port`,默认 4712):面向**管理员 / 运维 / 集成商**, 提供完整的管理能力,工具与 `/api/v1/management` 路由一一对应,鉴权与 HTTP 管理 API 相同(`[[ldapforge.api_keys]]`,`Authorization: Bearer ` / `X-API-Key: `,`read_only` 密钥只读)。 - **应用认证服务**(`mcp_app_auth_port`,默认 4713):**面向应用开发者 / 业务系统, 不得面向终端用户**。它由业务系统用自身 LDAP 应用密钥 (`X-App-Id` + `Authorization: Bearer ` 或 `X-API-Key`)调用,代表应用去校验 用户、查询成员关系;终端用户不直接接触该服务。提供 `authenticate_user`、 `check_user_membership`、`user_exists`、`get_user`、`list_application_members`、 `application_info` 等只读工具。同一套面向应用的**认证/查询接口**也以 REST 形式 发布在 **`/api/v1/app-auth`**(见 [附录 C′. HTTP 应用认证 API](#c-http-应用认证-api)), 与 MCP 应用认证服务共用应用密钥与语义。 > **定位说明**:两个 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/management/authlogs/search` 查询;可设置保留时长自动清理。 - **升级**:执行 `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://:/api/v1/management`(默认端口 `4711`)。 - 鉴权:`Authorization: Bearer ` 或 `X-API-Key: `;`read_only` 密钥禁止写操作。 - `GET /health`(位于 `/api/v1` 之外)无需鉴权。 - 请求/响应均为 JSON;错误格式 `{"error": "...", "code": "..."}`。 - 只使用 `GET`/`POST` 两种方法,不使用 `PUT`/`PATCH`/`DELETE`。 - 每个操作使用**语义化的固定路径**区分,不在同一路径上用 GET/POST 表达不同语义。 - 输入参数不放入 URL 路径:**读(GET)参数放 query string,写(POST)参数放 JSON body**。 | 方法 | 路径(`/api/v1/management` 之后) | 说明 / 主要参数 | | --- | --- | --- | | GET | `/` | 服务与目录信息 | | GET | `/whoami` | 当前密钥名称与是否只读 | | GET | `/count` | 条目总数 | | GET | `/entries/search` | 查询条目(GET,query):`base`、`scope`、`filter`、`attributes`、`size_limit` | | POST | `/entries/create` | 新增条目(body):`dn`、`attributes` | | GET | `/entries/fetch` | 按 DN 获取条目(query):`dn` | | POST | `/entries/replace` | 替换/新增条目(body):`dn`、`attributes`、`display_dn` | | POST | `/entries/modify` | 修改条目(body):`dn`、`changes` 或属性映射 | | POST | `/entries/delete` | 删除条目(body):`dn` | | GET | `/entries/children` | 是否含直接子条目(query):`dn` | | GET | `/entries/compare` | 比较属性(query):`dn`、`attribute`、`value` | | POST | `/entries/rename` | 重命名/移动(body):`dn`、`new_rdn`、`delete_old_rdn`、`new_superior` | | GET | `/users/search` | 列出用户(query):`filter`、`attributes`、`size_limit` | | POST | `/users/create` | 创建用户(body):`uid`、`dn`、`cn`、`sn`、`mail`、`password`、`object_class`、`valid_from`、`valid_until`、`attributes` | | GET | `/users/fetch` | 按 uid 获取用户(query):`uid` | | POST | `/users/modify` | 修改用户(body):`uid`、其余改动用 `changes` 或属性映射 | | POST | `/users/delete` | 删除用户(body):`uid` | | POST | `/users/password` | 设置密码(body):`uid`、`password`(或 `userPassword`) | | GET | `/applications/search` | 列出应用 | | POST | `/applications/create` | 创建应用(body):`app_id`、`display_name`、`description`、`enabled`、`password`、`extra` | | GET | `/applications/fetch` | 获取应用(query):`app` | | POST | `/applications/modify` | 更新应用(body):`app`、`display_name`、`description`、`enabled` | | POST | `/applications/delete` | 删除应用及其密钥(body):`app` | | POST | `/applications/enable` | 启用应用(body):`app` | | POST | `/applications/disable` | 停用应用(body):`app` | | GET | `/applications/keys/search` | 列出应用密钥(query):`app` | | POST | `/applications/keys/create` | 新增密钥(body):`app`、`password`(或 `key`)、`label`、`expires_at` | | POST | `/applications/keys/remove` | 删除密钥(body):`app`、`key_id` | | POST | `/applications/keys/enable` | 启用密钥(body):`app`、`key_id` | | POST | `/applications/keys/disable` | 停用密钥(body):`app`、`key_id` | | GET | `/members/search` | 列出成员(query):`member_dn`(或 `app_dn`) | | GET | `/memberships/search` | 列出归属(query):`user_dn`(或 `uid`) | | POST | `/bindings/create` | 建立绑定(body):`user_dn`、`member_dn`、`enabled`、`valid_from`、`valid_until`(后两者仅应用绑定) | | POST | `/bindings/remove` | 解除绑定(body):`user_dn`、`member_dn` | | GET | `/orgs/search` | 列出组织/组(query):`base`、`scope`、`filter` | | POST | `/orgs/create` | 创建组织/组(body):`dn`、`kind`(`group`/`ou`)、`name`、`description` | | POST | `/orgs/delete` | 删除组织/组(body):`dn` | | GET | `/orgs/members/search` | 列出组织/组成员(query):`dn` | | POST | `/orgs/members/add` | 添加组织成员(body):`org_dn`、`user_dn`(或 `user_dns`/`users`) | | POST | `/orgs/members/remove` | 移除组织成员(body):`org_dn`、`user_dn`(或 `user_dns`/`users`) | | GET | `/authlogs/search` | 认证日志(query):`limit`、`offset`、`dn`、`application`、`success`、`type`、`since` | | GET | `/authlogs/count` | 认证日志计数(query):`dn`、`success`、`since` | | POST | `/authlogs/clear` | 清理认证日志(body):`older_than` | | GET | `/export` | 导出 LDIF(query):`base_dn`、`scope`、`users_only`、`include_passwords` | | POST | `/import` | 导入 LDIF(body):`ldif`、`skip_existing` | | POST | `/purge/expired` | 清理过期账号并软删除超期绑定 | | POST | `/purge/authlogs` | 按保留策略清理认证日志 | ### C′. HTTP 应用认证 API > 这是**真正面向应用系统**的接口:应用用**自己的应用密钥**(库存于应用,同 LDAPv3 > 应用绑定用的那把)鉴权,去**校验用户密码 / 查询本应用的成员关系**等。这里**不放** > 任何应用/密钥的增删改查(那些属于管理的 `/api/v1/management/applications/...`, > 见上文 C 节)。 - 基址:`http://:/api/v1/app-auth`(与管理 API 同端口)。 - 鉴权:应用用自身 LDAP 应用密钥,携带 `X-App-Id: ` 并加 `Authorization: Bearer ` 或 `X-API-Key: `(密钥即应用创建时的 password/追加的 API key,明文或用 `sha256:` 摘要均只存后端);密钥无效、停用 或应用被停用时返回 `401`。 - 请求/响应均为 JSON;只读,全部为 `GET`(`authenticate`/`login` 类操作用 `POST` 以承载密码,避免写入 URL/日志)。 - 参数不放入 URL 路径:**读(GET)参数放 query string,写(POST)参数放 JSON body**。 | 方法 | 路径(`/api/v1/app-auth` 之后) | 说明 / 主要参数 | | --- | --- | --- | | GET | `/info` | 当前已认证应用的信息 | | POST | `/authenticate` | 以本应用身份校验用户密码(body):`uid`、`password` | | GET | `/membership` | 用户是否属于本应用(query):`uid` 或 `user_dn` | | GET | `/users/exists` | 用户是否存在(query):`uid` 或 `user_dn` | | GET | `/users/fetch` | 获取用户属性(query):`uid` 或 `user_dn`;隐藏密码,可 `attributes` 过滤 | | GET | `/members` | 列出绑定到本应用的用户 | 下表为对应关系(也即应用认证 MCP 服务[D 节](#d-mcp-工具)的工具): | REST 路径 | 说明 | | --- | --- | | `GET /info` | `application_info` | | `POST /authenticate` | `authenticate_user` | | `GET /membership` | `check_user_membership` | | `GET /users/exists` | `user_exists` | | `GET /users/fetch` | `get_user` | | `GET /members` | `list_application_members` | ### D. MCP 工具 > 两者均为**给程序调用的服务接口**,不面向终端用户:管理服务面向管理员/运维/ > 集成商,应用认证服务面向应用开发者/业务系统。 **管理服务**(默认 `4712`,**面向管理员 / 运维 / 集成商等管理侧程序,不得面向 终端用户**;鉴权与 HTTP 管理 API 相同,即 `[[ldapforge.api_keys]]` `Authorization: Bearer ` / `X-API-Key: `):工具与上方 `/api/v1/management` 路由一一对应: | 工具 | 说明 | | --- | --- | | `info` | 服务与目录信息 | | `whoami` | 当前管理密钥名称与是否只读 | | `count` | 条目总数 | | `entries_search` | 按 RFC 4515 过滤器查询条目 | | `entries_fetch` | 按 DN 获取条目 | | `entries_create` | 新增条目(LDAP add) | | `entries_replace` | 替换条目指定属性 | | `entries_modify` | 应用 LDAP 修改 | | `entries_delete` | 按 DN 删除条目 | | `entries_rename` | 重命名/移动条目(ModifyDN) | | `entries_children` | 条目是否有直接子条目 | | `entries_compare` | 比较属性值(LDAP compare) | | `users_search` | 列出用户 | | `users_create` | 创建用户 | | `users_fetch` | 按 uid/DN 获取用户 | | `users_modify` | 修改用户 | | `users_delete` | 删除用户 | | `users_password` | 设置用户密码 | | `applications_search` | 列出应用 | | `applications_create` | 创建应用 | | `applications_fetch` | 获取应用 | | `applications_modify` | 更新应用名称/描述/启用状态 | | `applications_enable` | 启用应用 | | `applications_disable` | 停用应用 | | `applications_delete` | 删除应用及其密钥 | | `applications_keys_search` | 列出应用密钥 | | `applications_keys_create` | 新增应用密钥 | | `applications_keys_remove` | 删除应用密钥 | | `applications_keys_enable` | 启用应用密钥 | | `applications_keys_disable` | 停用应用密钥 | | `members_search` | 列出应用/组成员 | | `memberships_search` | 列出用户的归属 | | `bindings_create` | 绑定用户到应用/组(`valid_from`/`valid_until` 设置应用绑定有效期) | | `bindings_remove` | 解除绑定 | | `orgs_search` | 列出组织/组 | | `orgs_create` | 创建组织/组 | | `orgs_delete` | 删除组织/组 | | `orgs_members_search` | 列出组织/组成员 | | `orgs_members_add` | 添加组织成员 | | `orgs_members_remove` | 移除组织成员 | | `authlogs_search` | 列出认证日志 | | `authlogs_count` | 认证日志计数 | | `authlogs_clear` | 清理认证日志 | | `export` | 导出 LDIF | | `import` | 导入 LDIF | | `purge_expired` | 清理过期账号并软删除超期应用绑定 | | `purge_authlogs` | 按保留策略清理认证日志 | **应用认证服务**(默认 `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)