Files
Yongjie XuandClaude Opus 4.6 7f171b6bf7 add bidirectional sync for user enabled status
Keycloak → LDAP sync via UserModelDelegate proxy in setEnabled()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 15:13:01 +08:00
..

Keycloak OpenLDAP PPolicy Status Mapper

将 OpenLDAP 的 pwdAccountLockedTime 属性映射为 Keycloak 的用户启用/禁用状态。

背景

OpenLDAP 使用 ppolicy overlay 管理密码策略,当账号被锁定时会设置 pwdAccountLockedTime 属性。Keycloak 默认无法识别该属性,导致 LDAP 中已锁定的用户在 Keycloak 中仍然显示为启用状态。

本 provider 通过自定义 LDAP Storage Mapper 解决这一问题。

工作原理

  1. LDAP 查询阶段beforeLDAPQuery 中将 pwdAccountLockedTime 加入返回属性,确保 LDAP 查询结果包含该字段
  2. 用户导入阶段onImportUserFromLDAP 中读取 pwdAccountLockedTime 的值:
    • 属性存在且非空 → 用户设置为 enabled = false
    • 属性不存在或为空 → 用户设置为 enabled = true

注意:OpenLDAP 管理员主动禁用账号时,pwdAccountLockedTime 通常被设为 000001010000Z,该场景同样会被识别为锁定。

构建

mvn clean package

构建产物位于 providers/PwdLockToEnabledMapper/target/

部署

  1. 将构建生成的 JAR 文件复制到 Keycloak 的 providers 目录:
cp providers/PwdLockToEnabledMapper/target/pwd-lock-to-enabled-mapper.jar \
   <KEYCLOAK_HOME>/providers/
  1. 重启 Keycloak 或执行一次构建:
<KEYCLOAK_HOME>/bin/kc.sh build

配置

  1. 登录 Keycloak Admin Console
  2. 进入目标 Realm → User Federation → 选择已配置的 LDAP provider
  3. Mappers 标签页点击 Add mapper
  4. 填写配置:
    • Mapper Type:选择 OpenLDAP PPolicy Status Mapper
    • Name:自定义名称,如 pwdLockStatus
  5. 保存

配置完成后,下次 LDAP 同步时将自动根据 pwdAccountLockedTime 更新用户启用状态。

项目结构

providers/PwdLockToEnabledMapper/
└── src/main/
    ├── java/com/example/keycloak/
    │   ├── PwdLockToEnabledMapper.java         # Mapper 实现
    │   └── PwdLockToEnabledMapperFactory.java  # Factoryprovider ID: openldap-ppolicy-mapper
    └── resources/META-INF/services/
        └── org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory  # SPI 注册

前提条件

  • Keycloak 版本需支持 AbstractLDAPStorageMapper / AbstractLDAPStorageMapperFactory API
  • OpenLDAP 需启用 ppolicy overlay
  • LDAP 用户条目需包含 pwdAccountLockedTime 属性(ppolicy overlay 自动管理)

限制

  • 仅支持 LDAP → Keycloak 单向同步,Keycloak 中的禁用操作不会同步回 LDAP
  • pwdAccountLockedTime 属性必须可被 Keycloak 的 LDAP 服务账号读取