【问题标题】:Keycloak OTP for read only federated users只读联合用户的 Keycloak OTP
【发布时间】: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


【解决方案1】:

原因是在您的UserAdminAdapter 类中,您还没有实现removeRequiredActionaddRequiredAction 方法。您收到的消息来自基类提供的默认实现。您应该自己实现这些方法并将所需的操作存储在底层存储中,或者考虑从 AbstractUserAdapterFederatedStorage 扩展您的类,而不是将所有此类功能委托给内部 Keycloak 实现。

【讨论】:

    猜你喜欢
    • 2021-10-30
    • 2021-06-20
    • 2021-11-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2023-01-09
    • 2019-04-02
    • 1970-01-01
    相关资源
    最近更新 更多