我正在管理Keycloak领域,仅添加了一个完全信任的外部IdP,该Id被用作用户的默认身份验证机制。
我不不想允许用户注册,即我想手动创建本地Keycloak用户,然后应允许该用户将其外部IdP帐户链接到预先存在的Keycloak帐户,以电子邮件地址作为通用标识符。不能访问具有外部IdP但没有现有Keycloak帐户的用户。
我尝试了以下 First Broker Login 设置,但是每当用户尝试登录时,他都会收到一条错误消息(代码:invalid_user_credentials
)。
您知道我的错误可能是什么吗?
答案 0 :(得分:3)
答案 1 :(得分:1)
根据此讨论:
https://keycloak.discourse.group/t/link-idp-to-existing-user/1094/5
这是密钥斗篷中的一个错误,他们似乎不愿意为此进行修复 不管什么原因。我的用户很少,所以我手动解决了 查询idp以获取信息密钥斗篷使用的信息,然后将其复制 进入用户界面中的相关字段。因此,没有注册流程 我的用户我只是让他们自己做。显然,这是一个糟糕的解决方案 但是,我们真正需要的是接管该PR的人, 说服维护者将其合并。
答案 2 :(得分:1)
正如 this GitHub issue response 中所述,解决方案是使用处理此问题的 JavaScript authenticator。
为此,您需要执行以下操作:
通过 https://stackoverflow.com/a/63274532/550222creating 启用[在您的服务器中使用 JavaScript 的自定义身份验证器[(https://www.keycloak.org/docs/latest/server_installation/#profiles)配置目录中包含以下内容的文件 profile.properties
:
feature.scripts=enabled
创建自定义身份验证器。您必须创建一个具有以下结构的 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)
}
然后,您可以定义如下: