Keycloak自定义身份验证器存在问题

时间:2020-11-02 15:10:10

标签: keycloak

我正在尝试构建自定义DirectGrantAuthenticator,将来应该进行网络调用以针对外部服务对用户/密码进行身份验证。

目前,我有一个虚拟的身份验证器,应该为每个用户名/密码验证用户身份并使用默认声明进行响应。

我在身份验证呼叫期间正在与Keycloak异常作斗争,并且不知道如何解决它。.看来Keycloak在会话中仍然看不到身份验证用户

keycloak_1  | 13:32:10,638 INFO  [stdout] (default task-1) query params - io.undertow.servlet.util.IteratorEnumeration@278071bb
keycloak_1  | 13:32:10,639 INFO  [stdout] (default task-1) formData - {password=[test], grant_type=[password], username=[test]}
keycloak_1  | 13:32:10,644 INFO  [stdout] (default task-1) URI path params - {protocol=[openid-connect], realm=[retail-kasa]}
keycloak_1  | 13:32:10,645 INFO  [stdout] (default task-1) Authentication - UserName + test
keycloak_1  | 13:32:10,647 INFO  [stdout] (default task-1) Authentication - Pwd + test
keycloak_1  | 13:32:10,656 INFO  [stdout] (default task-1) User session - org.keycloak.models.sessions.infinispan.AuthenticationSessionAdapter@437f0e65
keycloak_1  | 13:32:10,660 INFO  [stdout] (default task-1) User in session - null
keycloak_1  | 13:32:10,660 INFO  [stdout] (default task-1) Authentication OK
keycloak_1  | 13:32:10,672 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) Uncaught server error: org.keycloak.authentication.AuthenticationFlowException
keycloak_1  |   at org.keycloak.keycloak-services@11.0.2//org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:981)

这是我的虚拟身份验证器代码

    package cz.ifortuna.keycloak;

import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.AuthenticationFlowError;
import org.keycloak.authentication.authenticators.directgrant.AbstractDirectGrantAuthenticator;
import org.keycloak.events.Errors;
import org.keycloak.models.*;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.idm.CredentialRepresentation;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;

public class KomDirectGrantAuthenticator extends AbstractDirectGrantAuthenticator {

    public static final String PROVIDER_ID = "kom-direct-grant-validate-password";


    @Override
    public void authenticate(AuthenticationFlowContext context) {


        MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
        System.out.println("query params - " + context.getHttpRequest().getAttributeNames());
        System.out.println("formData - " + formData);
        System.out.println("URI path params - " + context.getUriInfo().getPathParameters());

        final String userName = formData.getFirst("username");
        final String pwd = formData.getFirst("password");

        System.out.println("Authentication - UserName + " + userName);
        System.out.println("Authentication - Pwd + " + pwd);

        // Creating dummy user model from the scratch
        KomUserModel userModel = new KomUserModel(context.getSession(), context.getRealm(), new KomComponentModel(), 0L, userName);
        context.setUser(userModel);

        // TODO - call external service (now always valid)
        boolean valid = true;
        if (!valid) {
            context.getEvent().user(context.getUser());
            context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
            Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials");
            context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
            return;
        }

        System.out.println("User session - " + context.getAuthenticationSession());
        //context.attachUserSession(new KomSessionModel());
        System.out.println("User in session - " + context.getAuthenticationSession().getAuthenticatedUser());

        // User is authenticated
        context.getAuthenticationSession().setAuthenticatedUser(userModel);
        context.success();
        System.out.println("Authentication OK");
    }

    @Override
    public boolean requiresUser() {
        return false;
    }

    @Override
    public boolean configuredFor(KeycloakSession keycloakSession, RealmModel realmModel, UserModel userModel) {
        return true;
    }

    @Override
    public void setRequiredActions(KeycloakSession keycloakSession, RealmModel realmModel, UserModel userModel) {

    }

    @Override
    public String getDisplayType() {
        return "kom-direct-grant";
    }

    @Override
    public String getReferenceCategory() {
        return null;
    }

    @Override
    public boolean isConfigurable() {
        return true;
    }

    @Override
    public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
        return REQUIREMENT_CHOICES;
    }

    @Override
    public boolean isUserSetupAllowed() {
        return false;
    }

    @Override
    public String getHelpText() {
        return "Validates the password supplied as a 'password' form parameter in direct grant request against KOM";

    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        List<ProviderConfigProperty> configProperties = new ArrayList<>();
        ProviderConfigProperty property = new ProviderConfigProperty();
        property.setName("KOM_URL");
        property.setLabel("Komunikator URL");
        property.setType(ProviderConfigProperty.STRING_TYPE);
        property.setHelpText("KOM URL for authentication requests");
        configProperties.add(property);
        return configProperties;
    }

    @Override
    public String getId() {
        return PROVIDER_ID;
    }

    protected String retrievePassword(AuthenticationFlowContext context) {
        MultivaluedMap<String, String> inputData = context.getHttpRequest().getDecodedFormParameters();
        return inputData.getFirst(CredentialRepresentation.PASSWORD);
    }
}

您能指出我的解决方案吗?我需要为用户存储库实现自定义SPI吗?在我的用例中,我只想将用户pwd身份验证委派给外部服务...

谢谢

0 个答案:

没有答案