Keycloak-如何允许无需注册即可链接帐户

时间:2018-09-18 08:47:19

标签: authentication keycloak

我正在管理Keycloak领域,仅添加了一个完全信任的外部IdP,该Id被用作用户的默认身份验证机制。

不想允许用户注册,即我想手动创建本地Keycloak用户,然后应允许该用户将其外部IdP帐户链接到预先存在的Keycloak帐户,以电子邮件地址作为通用标识符。不能访问具有外部IdP但没有现有Keycloak帐户的用户。

我尝试了以下 First Broker Login 设置,但是每当用户尝试登录时,他都会收到一条错误消息(代码:invalid_user_credentials)。

enter image description here

您知道我的错误可能是什么吗?

3 个答案:

答案 0 :(得分:3)

好像他们在4.5.0版中集成了此功能。

请参见automatic account link docs

基本上,您需要创建一个新流程并添加2个替代执行:

  1. 创建用户(如果唯一)

  2. 自动链接经纪帐户

答案 1 :(得分:1)

根据此讨论:

https://keycloak.discourse.group/t/link-idp-to-existing-user/1094/5

这是密钥斗篷中的一个错误,他们似乎不愿意为此进行修复 不管什么原因。我的用户很少,所以我手动解决了 查询idp以获取信息密钥斗篷使用的信息,然后将其复制 进入用户界面中的相关字段。因此,没有注册流程 我的用户我只是让他们自己做。显然,这是一个糟糕的解决方案 但是,我们真正需要的是接管该PR的人, 说服维护者将其合并。

这是PR:https://github.com/keycloak/keycloak/pull/6282

答案 2 :(得分:1)

正如 this GitHub issue response 中所述,解决方案是使用处理此问题的 JavaScript authenticator

为此,您需要执行以下操作:

  1. 通过 https://stackoverflow.com/a/63274532/550222creating 启用[在您的服务器中使用 JavaScript 的自定义身份验证器[(https://www.keycloak.org/docs/latest/server_installation/#profiles)配置目录中包含以下内容的文件 profile.properties

     feature.scripts=enabled
    
  2. 创建自定义身份验证器。您必须创建一个具有以下结构的 JAR 文件(本质上是一个 ZIP 文件):

     META-INF/keycloak-scripts.json
     auth-user-must-exist.js
    

    文件的内容在 this Gist 中,但我也将它们包括在这里:

    • META-INF/keycloak-scripts.json

      {
          "authenticators": [
              {
                  "name": "User must exists",
                  "fileName": "auth-user-must-exists.js",
                  "description": "User must exists"
              }
          ]
      }
      
    • auth-user-must-exist.js

      AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError")
      ServicesLogger = Java.type("org.keycloak.services.ServicesLogger")       
      AbstractIdpAuthenticator = Java.type("org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator")
      IdpCreateUserIfUniqueAuthenticator = Java.type("org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticator")
      
      
      var IdpUserMustExists = Java.extend(IdpCreateUserIfUniqueAuthenticator)
      
      
      function authenticate(context) {                                         
          var auth = new IdpUserMustExists() {                                 
              authenticateImpl: function(context, serializedCtx, brokerContext) {
                  var parent = Java.super(auth)                                
      
                  var session = context.getSession()                           
                  var realm = context.getRealm()                               
      
                  var authSession = context.getAuthenticationSession()         
      
                  if (authSession.getAuthNote(AbstractIdpAuthenticator.EXISTING_USER_INFO) != null) {
                      context.attempted()                                      
                      return                                                   
                  }                                                            
      
                  var username = parent.getUsername(context, serializedCtx, brokerContext)
                  if (username == null) {                                      
                      ServicesLogger.LOGGER.resetFlow(realm.isRegistrationEmailAsUsername() ? "Email" : "Username")
                      authSession.setAuthNote(AbstractIdpAuthenticator.ENFORCE_UPDATE_PROFILE, "true")
                      context.resetFlow()                                      
                      return                                                   
                  }                                                            
      
                  var duplication = parent.checkExistingUser(context, username, serializedCtx, brokerContext)
                  if (duplication == null) {                                   
                      LOG.info("user not found " + username)                   
                      context.failure(AuthenticationFlowError.INVALID_USER) 
                      return                                                   
                  } else {                                                     
                      authSession.setAuthNote(AbstractIdpAuthenticator.EXISTING_USER_INFO, duplication.serialize())
                      context.attempted()                                      
                  }                                                            
              }                                                                
          }                                                                    
      
          auth.authenticate(context)                                           
      }
      
  3. 然后,您可以定义如下:

    • 用户必须存在 -> 替代
    • 自动设置现有用户 -> 替代