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>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
870ebbf7d6
commit
7f171b6bf7
+33
-11
@@ -8,19 +8,33 @@ import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||
import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
|
||||
import org.keycloak.storage.ldap.mappers.AbstractLDAPStorageMapper;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class PwdLockToEnabledMapper extends AbstractLDAPStorageMapper {
|
||||
|
||||
private static final String PWD_ACCOUNT_LOCKED_TIME = "pwdAccountLockedTime";
|
||||
// OpenLDAP 常用的永久锁定时间戳
|
||||
private static final String LDAP_LOCK_TIME = "000001010000Z";
|
||||
|
||||
public PwdLockToEnabledMapper(ComponentModel mapperModel, LDAPStorageProvider ldapProvider) {
|
||||
super(mapperModel, ldapProvider);
|
||||
}
|
||||
|
||||
// 逻辑封装:根据 Keycloak 用户状态更新 LDAP 对象
|
||||
private void setLdapStatus(LDAPObject ldapObject, UserModel userModel) {
|
||||
if (!userModel.isEnabled()) {
|
||||
// 如果用户被禁用,设置锁定时间
|
||||
ldapObject.setAttribute(PWD_ACCOUNT_LOCKED_TIME, Collections.singleton(LDAP_LOCK_TIME));
|
||||
} else {
|
||||
// 如果用户被启用,移除锁定时间属性
|
||||
ldapObject.setAttribute(PWD_ACCOUNT_LOCKED_TIME, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImportUserFromLDAP(LDAPObject ldapUser, UserModel user, RealmModel realm, boolean isCreate) {
|
||||
// 1. 获取 pwdAccountLockedTime 属性
|
||||
String lockedTime = ldapUser.getAttributeAsString("pwdAccountLockedTime");
|
||||
|
||||
// 2. 逻辑判断:如果该属性存在,说明账号被锁定
|
||||
// 注意:OpenLDAP 中管理员禁用通常设置为 000001010000Z
|
||||
String lockedTime = ldapUser.getAttributeAsString(PWD_ACCOUNT_LOCKED_TIME);
|
||||
// 如果 LDAP 中有锁定时间,Keycloak 设置为禁用
|
||||
if (lockedTime != null && !lockedTime.isEmpty()) {
|
||||
user.setEnabled(false);
|
||||
} else {
|
||||
@@ -30,19 +44,27 @@ public class PwdLockToEnabledMapper extends AbstractLDAPStorageMapper {
|
||||
|
||||
@Override
|
||||
public void onRegisterUserToLDAP(LDAPObject ldapObject, UserModel userModel, RealmModel realmModel) {
|
||||
// 如果需要双向同步(Keycloak 禁用同步到 LDAP),则在此编写逻辑
|
||||
// 同步初始状态到新创建的 LDAP 用户
|
||||
setLdapStatus(ldapObject, userModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel proxy(LDAPObject ldapObject, UserModel userModel, RealmModel realmModel) {
|
||||
return userModel;
|
||||
// 关键:拦截 Keycloak 的更新操作
|
||||
return new org.keycloak.models.utils.UserModelDelegate(userModel) {
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
// 当在控制台切换"启用/禁用"开关时,同步到 LDAPObject
|
||||
setLdapStatus(ldapObject, userModel);
|
||||
// 提交更新到 LDAP
|
||||
ldapProvider.getLdapIdentityStore().update(ldapObject);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeLDAPQuery(LDAPQuery query) {
|
||||
// 关键修复:确保 LDAP 查询时请求了 pwdAccountLockedTime 属性
|
||||
// 否则 ldapUser.getAttributeAsString 将始终返回 null
|
||||
query.addReturningLdapAttribute("pwdAccountLockedTime");
|
||||
query.addReturningReadOnlyLdapAttribute("pwdAccountLockedTime");
|
||||
query.addReturningLdapAttribute(PWD_ACCOUNT_LOCKED_TIME);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user