Keycloak - 在不创建新帐户的情况下从身份提供者登录获取电子邮件地址

Keycloak - Get email address from Identity Provider Login without creating a new account

我正在尝试使用 Google 作为 Keycloak 的身份提供者作为 OpenShift 的 OAuth 提供者。

first-broker-login 的默认身份验证流程允许任何 Google 帐户访问 Keycloak,因此我想在身份验证流程中尽早插入脚本以验证电子邮件用户正在使用的属于特定托管域。

我当前的脚本如下所示:

AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");

function authenticate(context) {

    var username = user ? user.username : "anonymous";
    LOG.info(script.name + " trace auth for: " + username);

    var authShouldPass = typeof user.email !== 'undefined' && user.email.endsWith("domain.com");
    if (!authShouldPass) {

        context.failure(AuthenticationFlowError.INVALID_USER);
        return;
    }

    context.success();
}

在 "Create User If Unique" 身份验证步骤之前使用此脚本会出错,因为 UserModel 不存在,因为在此上下文中流程的此时点不存在任何用户。

将此移动到流程的后期(Create User If Unique 之后)允许在流程上下文中创建用户并且脚本成功检测恶意电子邮件,但是,恶意用户现在可以访问到 Keycloak(除非我在 if 语句中添加 user.setEnabled(false);)。

我已经为此苦恼好几天了,我不知所措。

Screenshot of Authentication Flow

编辑: 我尝试修改脚本以绕过不存在的 UserModel,方法是使用 var email = context.getHttpRequest().getDecodedFormParameters().getFirst("email"); 之类的语句 - 这只是 returnsnull

编辑 2: 登录时,我尝试使用的电子邮件地址在错误日志中:

07:11:34,374 WARN  [org.keycloak.events] (default task-5) \
type=IDENTITY_PROVIDER_FIRST_LOGIN_ERROR, \
realmId=openshift, clientId=account, \
userId=null, ipAddress=10.131.0.1, \
error=user_not_found, identity_provider=google, \
auth_method=openid-connect, redirect_uri=https://keycloak.domain.com/auth/realms/openshift/account/login-redirect, \
identity_provider_identity=user@domain.com, code_id=code

在与同事一起挖掘后,我们找到了解决方案。

错误日志的最后一行打印出一大堆变量,其中一个是identity_provider_identity=user@domain.com,在挖掘之后我们追踪到EventBuilder class 然后进入 Event class.
Event class 中是一个调用名为 details 的 hashmap 的方法。

public Event clone() {
    Event clone = new Event();
    clone.time = time;
    clone.type = type;
    clone.realmId = realmId;
    clone.clientId = clientId;
    clone.userId = userId;
    clone.sessionId = sessionId;
    clone.ipAddress = ipAddress;
    clone.error = error;
    clone.details = details != null ? new HashMap<>(details) : null;
    return clone;
}

context.getEvent().event.details.get("identity_provider_identity") 将 return 客户使用的电子邮件地址。