【发布时间】:2022-02-06 18:15:56
【问题描述】:
我已经实现了一个自定义用户存储提供程序,用于联合我们数据库中的用户。
我想通过 keycloak 为这些用户管理 OTP,当我在流程中将 OTP 设置为必需并将 OTP 配置为所需操作时,在联合用户登录后会显示 otp 表单,但是当我尝试设置 OTP 时,我收到了错误用户对此更新是只读的。
如何允许只读联合用户通过 keycloak 进行 OTP 配置?
2022-01-31 17:00:12,704 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-669) Uncaught server error: org.keycloak.storage.ReadOnlyException: user is read only for this update
at org.keycloak.keycloak-server-spi@15.1.1//org.keycloak.storage.adapter.AbstractUserAdapter.removeRequiredAction(AbstractUserAdapter.java:77)
at org.keycloak.keycloak-services@15.1.1//org.keycloak.services.resources.LoginActionsService.processRequireAction(LoginActionsService.java:1044)
at org.keycloak.keycloak-services@15.1.1//org.keycloak.services.resources.LoginActionsService.requiredActionPOST(LoginActionsService.java:967)
用户适配器是
public class UserAdminAdapter extends AbstractUserAdapter {
private final CustomUser user;
public UserAdminAdapter(
KeycloakSession session,
RealmModel realm,
ComponentModel storageProviderModel,
CustomUser user) {
super(session, realm, storageProviderModel);
this.user = user;
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public Stream<String> getAttributeStream(String name) {
Map<String, List<String>> attributes = getAttributes();
return (attributes.containsKey(name)) ? attributes.get(name).stream() : Stream.empty();
}
@Override
protected Set<GroupModel> getGroupsInternal() {
if (user.getGroups() != null) {
return user.getGroups().stream().map(UserGroupModel::new).collect(Collectors.toSet());
}
return new HashSet<>();
}
@Override
protected Set<RoleModel> getRoleMappingsInternal() {
if (user.getRoles() != null) {
return user.getRoles().stream().map(roleName -> new UserRoleModel(roleName, realm)).collect(Collectors.toSet());
}
return new HashSet<>();
}
@Override
public boolean isEnabled() {
return user.isEnabled();
}
@Override
public String getId() {
return StorageId.keycloakId(storageProviderModel, user.getUserId() + "");
}
@Override
public String getFirstAttribute(String name) {
List<String> list = getAttributes().getOrDefault(name, Collections.emptyList());
return list.isEmpty() ? null : list.get(0);
}
@Override
public Map<String, List<String>> getAttributes() {
MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
attributes.add(UserModel.USERNAME, getUsername());
attributes.add(UserModel.EMAIL, getEmail());
attributes.add(UserModel.FIRST_NAME, getFirstName());
attributes.add(UserModel.LAST_NAME, getLastName());
attributes.addAll(user.getAttributes());
return attributes;
}
@Override
public String getFirstName() {
return user.getFirstName();
}
@Override
public String getLastName() {
return user.getLastName();
}
@Override
public String getEmail() {
return user.getEmail();
}
}
【问题讨论】:
-
如果您可以在从数据库中获取用户返回 Keycloak 时发布您正在使用的用户模型/适配器实现,这将有助于我们了解情况。
-
@zaerymoghaddam 我已经添加了适配器实现
-
@zaerymoghaddam 你知道如何解决这个问题吗?
-
在下面查看我的答案
标签: keycloak federation totp