我正在尝试编写一个定制的KeyClope验证器,该验证器可以从某个请求中检索用户凭据,并动态提交这些凭据进行身份验证,而最终用户不必手动将它们输入某个登录表单。
以这个问题为起点,我在KeyCloak中创建了自己的自定义身份验证SPI。我还根据需要配置了KeyCloak身份验证流。
自定义验证器
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.authenticators.browser.UsernamePasswordForm;
public class CustomUPForm extends UsernamePasswordForm implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
System.out.println("Authenticating....");
Response challenge = context.form().createForm("custom-up-form.ftl");
context.challenge(challenge);
MultivaluedMap<String, String> formData = new MultivaluedHashMap<>();
//Changed here - but otherwise valid credentials
formData.putSingle("username", "xxxxx");
formData.putSingle("password", "xxxxx");
context.form().setFormData(formData);
}
@Override
public void action(AuthenticationFlowContext context) {
System.out.println("Action....");
context.success();
}
}
自定义验证器工厂
import java.util.ArrayList;
import java.util.List;
import org.keycloak.Config;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.authentication.ConfigurableAuthenticatorFactory;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;
public class CustomUPFormFactory implements AuthenticatorFactory,
ConfigurableAuthenticatorFactory {
public static final String PROVIDER_ID = "custom-up-form";
public static final CustomUPForm SINGLETON = new CustomUPForm();
@Override
public Authenticator create(KeycloakSession session) {
return SINGLETON;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public String getDisplayType() {
return "Custom Authenticator";
}
@Override
public String getReferenceCategory() {
return "Reference Category";
}
@Override
public boolean isConfigurable() {
return true;
}
public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
AuthenticationExecutionModel.Requirement.REQUIRED
};
@Override
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
return REQUIREMENT_CHOICES;
}
@Override
public String getHelpText() {
return "POC Custom Authenticator";
}
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<>();
static {
/*
Add properties here
*/
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return CONFIG_PROPERTIES;
}
@Override
public boolean isUserSetupAllowed() {
return false;
}
}
下面是我的自定义登录表单,它基于这里的KeyClope“secret question”SPI示例中提供的表单
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "title">
${msg("loginTitle",realm.name)}
<#elseif section = "header">
${msg("loginTitleHtml",realm.name)}
<#elseif section = "form">
<form id="kc-totp-login-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="totp" class="${properties.kcLabelClass!}">Login</label>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input id="totp" name="username" type="text" class="${properties.kcInputClass!}" />
<input id="totp" name="password" type="password" class="${properties.kcInputClass!}" />
</div>
</div>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
<div class="${properties.kcFormButtonsWrapperClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
</div>
</div>
</div>
</form>
</#if>
</@layout.registrationLayout>
所有组件都呈现良好,但是当我动态尝试通过将凭据添加到表单数据来传递凭据时,我总是得到“无效的用户名/密码”响应。
如何在不需要用户手动输入的情况下传递用户名和密码组合?
问题是我试图在authenticate()
的范围内执行此操作,而它应该包含在action()
的逻辑中。
此外,包含表单数据的多值map
应该从当前上下文中包含的HTTP请求派生而来
下面的解决方案就是从这个问题中推导出来的
public class CustomUPForm extends UsernamePasswordForm implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
Response challenge = context.form()
.createForm("custom-up-form.ftl");
context.challenge(challenge);
}
@Override
public void action(AuthenticationFlowContext context) {
System.out.println("Processing form...");
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
formData.putSingle("username", "xxxxx");
formData.putSingle("password", "xxxxx");
if (!validateForm(context, formData)) {
return;
}
context.success();
}
}
请注意,在这个示例中
validateForm()
包含一些自定义验证逻辑,这些逻辑对于本问题的范围来说并不是必需的。但是用户名和密码的值可以通过调用getFirst()
来提取
formData.getFirst("username");
我是这方面的新手,读了很多之后,我觉得我不太明白如何在Keycloak中实现授权代码流。我的疑惑: > < li> 在创建了支持此流程的客户端后,如何执行凭据验证?默认情况下,如果我不做任何配置,我会得到一个登录表单。如果我在浏览器中打开这个html,并填写用户和密码字段,当我按下按钮时,它会将我发送到一个类型为.../realm/{ REAL _ NAME }/log in-actions/au
我试图使用Keycloak的openId-connectendpoint来获取关于用户角色的信息。我使用/auth/realms/moje/protocol/OpenID-connect/userinfoendpoint来获取关于已验证用户的信息。我可以获得姓名、用户名、电子邮件等信息。但是我不能强迫Keyclak给我关于用户角色的信息。 我已经阅读了openID文档,我没有找到任何关于必须获取角
我有一个需要联合到IDP的需求。我过去从未遇到过问题,在这种情况下,我遇到了问题,因为第三方/外部IDP启用并实施了PKCE。 有没有办法联合到启用了PKCE的IDP。基本上换句话说,我应该能够转发/发送code_challenge和code_challenge_method给外部 IDP。我可以在我的 IDP 上启用 PKCE,而不会出现任何问题,并在需要时将相同的标头转发给外部 IDP,但我看
部署在AWS上,我不想隧道到盒子并打开浏览器禁用它。 似乎存在一个配置:,可以放置在文件,但我不确定在哪个对象下。我在“王国”下试过,但一点运气都没有。 我不想在适配器级别禁用它,它需要全局禁用,那么在哪里,或者如何全局禁用ssh/https? 另外,我知道这在生产中是不推荐的。)
我正在使用SAML和外部IdP实现SSO选项。如果我在单击浏览器中的SSO按钮后检查收到的SAML响应,我可以看到所需的身份验证数据(如用户名和电子邮件),因此与IdP的通信工作正常。 然而,Keycloak并不执行登录,并显示给我一个页面,上面写着:“我们很抱歉...登录超时,请重新登录。”,并且没有新用户注册。我的领域中令牌的登录超时设置为30分钟。 查看日志时,我发现了以下错误: 我发现这可
我正在尝试在API网关(Apache APISIX)后面使用KeyClope。 我使用minikube来运行KeyClope和API网关。 网关正常工作,KeyClope也正常工作: 使用KeyClope,我可以使用不同的endpoint(使用发现endpoint(http://127.0.0.1:7070/auth/realms/myrealm/.well-已知/uma2配置),询问访问令牌并进