cleanup authenticators
This commit is contained in:
parent
f5b4a0788e
commit
70fd7bea99
19 changed files with 109 additions and 472 deletions
|
@ -3,15 +3,10 @@ package org.keycloak.login.freemarker;
|
|||
import freemarker.template.TemplateMethodModelEx;
|
||||
import freemarker.template.TemplateModelException;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.AuthenticatorUtil;
|
||||
import org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.Urls;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,7 +48,7 @@ public class UrlBean {
|
|||
if (this.actionuri != null) {
|
||||
return this.actionuri.toString();
|
||||
}
|
||||
return Urls.realmLoginAction(baseURI, realm).toString();
|
||||
throw new RuntimeException("action URI not set");
|
||||
}
|
||||
|
||||
public String getLoginUrl() {
|
||||
|
|
|
@ -19,22 +19,17 @@ public class DefaultAuthenticationFlows {
|
|||
model.setProviderId("auth-cookie");
|
||||
model.setAlias("Cookie");
|
||||
AuthenticatorModel cookieAuth = realm.addAuthenticator(model);
|
||||
|
||||
model = new AuthenticatorModel();
|
||||
model.setProviderId("auth-login-form-otp");
|
||||
model.setAlias("Login Form OTP");
|
||||
AuthenticatorModel loginFormOtp = realm.addAuthenticator(model);
|
||||
model = new AuthenticatorModel();
|
||||
model.setProviderId("auth-login-form-password");
|
||||
model.setAlias("Login Form Password");
|
||||
AuthenticatorModel password = realm.addAuthenticator(model);
|
||||
model = new AuthenticatorModel();
|
||||
model.setProviderId("auth-login-form-username");
|
||||
model.setAlias("Login Form Username");
|
||||
AuthenticatorModel username = realm.addAuthenticator(model);
|
||||
model.setProviderId("auth-username-password-form");
|
||||
model.setAlias("Username Password Form");
|
||||
AuthenticatorModel usernamePasswordForm = realm.addAuthenticator(model);
|
||||
|
||||
model = new AuthenticatorModel();
|
||||
model.setProviderId("auth-otp-form");
|
||||
model.setAlias("Single OTP Form");
|
||||
AuthenticatorModel otp = realm.addAuthenticator(model);
|
||||
AuthenticatorModel otpForm = realm.addAuthenticator(model);
|
||||
|
||||
model = new AuthenticatorModel();
|
||||
model.setProviderId("auth-spnego");
|
||||
model.setAlias("Kerberos");
|
||||
|
@ -48,7 +43,7 @@ public class DefaultAuthenticationFlows {
|
|||
execution.setParentFlow(browser.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
|
||||
execution.setAuthenticator(cookieAuth.getId());
|
||||
execution.setPriority(0);
|
||||
execution.setPriority(10);
|
||||
execution.setUserSetupAllowed(false);
|
||||
execution.setAutheticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
@ -56,10 +51,12 @@ public class DefaultAuthenticationFlows {
|
|||
execution.setParentFlow(browser.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED);
|
||||
execution.setAuthenticator(kerberos.getId());
|
||||
execution.setPriority(1);
|
||||
execution.setPriority(20);
|
||||
execution.setUserSetupAllowed(false);
|
||||
execution.setAutheticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
|
||||
AuthenticationFlowModel forms = new AuthenticationFlowModel();
|
||||
forms.setAlias(FORMS_FLOW);
|
||||
forms.setDescription("Username, password, otp and other auth forms.");
|
||||
|
@ -68,38 +65,28 @@ public class DefaultAuthenticationFlows {
|
|||
execution.setParentFlow(browser.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
|
||||
execution.setAuthenticator(forms.getId());
|
||||
execution.setPriority(2);
|
||||
execution.setPriority(30);
|
||||
execution.setUserSetupAllowed(false);
|
||||
execution.setAutheticatorFlow(true);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
// forms
|
||||
// Username processing
|
||||
// Username Password processing
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(forms.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator(username.getId());
|
||||
execution.setAuthenticator(usernamePasswordForm.getId());
|
||||
execution.setPriority(10);
|
||||
execution.setUserSetupAllowed(false);
|
||||
execution.setAutheticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
// password processing
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(forms.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
execution.setAuthenticator(password.getId());
|
||||
execution.setPriority(11);
|
||||
execution.setUserSetupAllowed(true);
|
||||
execution.setAutheticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
||||
// otp processing
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(forms.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.OPTIONAL);
|
||||
execution.setAuthenticator(otp.getId());
|
||||
execution.setPriority(12);
|
||||
execution.setAuthenticator(otpForm.getId());
|
||||
execution.setPriority(20);
|
||||
execution.setUserSetupAllowed(true);
|
||||
execution.setAutheticatorFlow(false);
|
||||
realm.addAuthenticatorExecution(execution);
|
||||
|
|
|
@ -13,7 +13,6 @@ import java.util.List;
|
|||
*/
|
||||
public interface AuthenticatorFactory extends ProviderFactory<Authenticator>, ConfiguredProvider {
|
||||
Authenticator create(AuthenticatorModel model);
|
||||
String getDisplayCategory();
|
||||
String getDisplayType();
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
|
|
@ -3,14 +3,22 @@ package org.keycloak.authentication.authenticators;
|
|||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.authentication.AuthenticationProcessor;
|
||||
import org.keycloak.authentication.AuthenticatorContext;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.login.LoginFormsProvider;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.LoginActionsService;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.net.URI;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -21,6 +29,7 @@ public class AbstractFormAuthenticator {
|
|||
public static final String LOGIN_FORM_ACTION = "login_form";
|
||||
public static final String REGISTRATION_FORM_ACTION = "registration_form";
|
||||
public static final String ACTION = "action";
|
||||
public static final String FORM_USERNAME = "FORM_USERNAME";
|
||||
|
||||
protected boolean isAction(AuthenticatorContext context, String action) {
|
||||
return action.equals(context.getAction());
|
||||
|
@ -92,4 +101,50 @@ public class AbstractFormAuthenticator {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean validateUser(AuthenticatorContext context, MultivaluedMap<String, String> inputData) {
|
||||
String username = inputData.getFirst(AuthenticationManager.FORM_USERNAME);
|
||||
if (username == null) {
|
||||
context.getEvent().error(Errors.USER_NOT_FOUND);
|
||||
Response challengeResponse = invalidUser(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_USER, challengeResponse);
|
||||
return false;
|
||||
}
|
||||
context.getEvent().detail(Details.USERNAME, username);
|
||||
context.getClientSession().setNote(AbstractFormAuthenticator.FORM_USERNAME, username);
|
||||
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(context.getSession(), context.getRealm(), username);
|
||||
if (invalidUser(context, user)) return false;
|
||||
String rememberMe = inputData.getFirst("rememberMe");
|
||||
boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("on");
|
||||
if (remember) {
|
||||
context.getClientSession().setNote(Details.REMEMBER_ME, "true");
|
||||
context.getEvent().detail(Details.REMEMBER_ME, "true");
|
||||
}
|
||||
context.setUser(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean validatePassword(AuthenticatorContext context, MultivaluedMap<String, String> inputData) {
|
||||
List<UserCredentialModel> credentials = new LinkedList<>();
|
||||
String password = inputData.getFirst(CredentialRepresentation.PASSWORD);
|
||||
if (password == null) {
|
||||
if (context.getUser() != null) {
|
||||
context.getEvent().user(context.getUser());
|
||||
}
|
||||
context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
|
||||
Response challengeResponse = invalidCredentials(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
|
||||
return false;
|
||||
}
|
||||
credentials.add(UserCredentialModel.password(password));
|
||||
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
|
||||
if (!valid) {
|
||||
context.getEvent().user(context.getUser());
|
||||
context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
|
||||
Response challengeResponse = invalidCredentials(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,14 +66,9 @@ public class CookieAuthenticatorFactory implements AuthenticatorFactory {
|
|||
return REQUIREMENT_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "Complete Authenticator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Cookie Authenticator";
|
||||
return "Cookie";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
package org.keycloak.authentication.authenticators;
|
||||
|
||||
import org.keycloak.authentication.AuthenticationProcessor;
|
||||
import org.keycloak.authentication.AuthenticatorContext;
|
||||
import org.keycloak.models.AuthenticatorModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LoginFormOTPAuthenticator extends LoginFormUsernameAuthenticator {
|
||||
|
||||
public LoginFormOTPAuthenticator(AuthenticatorModel model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticate(AuthenticatorContext context) {
|
||||
if (!isAction(context, LOGIN_FORM_ACTION)) {
|
||||
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
validateOTP(context);
|
||||
}
|
||||
|
||||
protected Response badPassword(AuthenticatorContext context) {
|
||||
return loginForm(context).setError(Messages.INVALID_USER).createLogin();
|
||||
}
|
||||
|
||||
public void validateOTP(AuthenticatorContext context) {
|
||||
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
|
||||
List<UserCredentialModel> credentials = new LinkedList<>();
|
||||
String password = inputData.getFirst(CredentialRepresentation.TOTP);
|
||||
if (password == null) {
|
||||
Response challengeResponse = badPassword(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
|
||||
return;
|
||||
}
|
||||
credentials.add(UserCredentialModel.totp(password));
|
||||
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
|
||||
if (!valid) {
|
||||
Response challengeResponse = badPassword(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
|
||||
return;
|
||||
}
|
||||
context.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresUser() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
return session.users().configuredForCredentialType(UserCredentialModel.TOTP, realm, user) && user.isTotp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
if (!user.getRequiredActions().contains(UserModel.RequiredAction.CONFIGURE_TOTP.name())) {
|
||||
user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP.name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
package org.keycloak.authentication.authenticators;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.AuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticatorModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LoginFormOTPAuthenticatorFactory implements AuthenticatorFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "auth-login-form-otp";
|
||||
|
||||
@Override
|
||||
public Authenticator create(AuthenticatorModel model) {
|
||||
return new LoginFormOTPAuthenticator(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator create(KeycloakSession session) {
|
||||
throw new IllegalStateException("illegal call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReferenceType() {
|
||||
return UserCredentialModel.TOTP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED,
|
||||
AuthenticationExecutionModel.Requirement.OPTIONAL,
|
||||
AuthenticationExecutionModel.Requirement.DISABLED};
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
|
||||
return REQUIREMENT_CHOICES;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "Credential Validation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Login Form OTP";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Validates an OTP that is specified on the login page.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package org.keycloak.authentication.authenticators;
|
||||
|
||||
import org.keycloak.authentication.AuthenticationProcessor;
|
||||
import org.keycloak.authentication.AuthenticatorContext;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.models.AuthenticatorModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LoginFormPasswordAuthenticator extends LoginFormUsernameAuthenticator {
|
||||
|
||||
public LoginFormPasswordAuthenticator(AuthenticatorModel model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticate(AuthenticatorContext context) {
|
||||
if (!isAction(context, LOGIN_FORM_ACTION) && !isAction(context, REGISTRATION_FORM_ACTION)) {
|
||||
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
validatePassword(context);
|
||||
}
|
||||
|
||||
public void validatePassword(AuthenticatorContext context) {
|
||||
MultivaluedMap<String, String> inputData = context.getHttpRequest().getDecodedFormParameters();
|
||||
List<UserCredentialModel> credentials = new LinkedList<>();
|
||||
String password = inputData.getFirst(CredentialRepresentation.PASSWORD);
|
||||
if (password == null) {
|
||||
if (context.getUser() != null) {
|
||||
context.getEvent().user(context.getUser());
|
||||
}
|
||||
context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
|
||||
Response challengeResponse = invalidCredentials(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
|
||||
return;
|
||||
}
|
||||
credentials.add(UserCredentialModel.password(password));
|
||||
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
|
||||
if (!valid) {
|
||||
context.getEvent().user(context.getUser());
|
||||
context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
|
||||
Response challengeResponse = invalidCredentials(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
|
||||
return;
|
||||
}
|
||||
context.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresUser() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
return session.users().configuredForCredentialType(UserCredentialModel.PASSWORD, realm, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
if (!user.getRequiredActions().contains(UserModel.RequiredAction.UPDATE_PASSWORD.name())) {
|
||||
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package org.keycloak.authentication.authenticators;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.AuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticatorModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LoginFormUsernameAuthenticatorFactory implements AuthenticatorFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "auth-login-form-username";
|
||||
|
||||
@Override
|
||||
public Authenticator create(AuthenticatorModel model) {
|
||||
return new LoginFormUsernameAuthenticator(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator create(KeycloakSession session) {
|
||||
throw new IllegalStateException("illegal call");
|
||||
}
|
||||
|
||||
@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 getReferenceType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
|
||||
AuthenticationExecutionModel.Requirement.ALTERNATIVE,
|
||||
AuthenticationExecutionModel.Requirement.DISABLED};
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
|
||||
return REQUIREMENT_CHOICES;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "User Validation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Login Form Username";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Validates a username that is specified on the login page.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -69,10 +69,6 @@ public class OTPFormAuthenticatorFactory implements AuthenticatorFactory {
|
|||
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
|
||||
return REQUIREMENT_CHOICES;
|
||||
}
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "Credential Validation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
|
|
|
@ -71,11 +71,6 @@ public class SpnegoAuthenticatorFactory implements AuthenticatorFactory {
|
|||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "Complete Authenticator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "SPNEGO";
|
||||
|
|
|
@ -10,24 +10,27 @@ import org.keycloak.login.LoginFormsProvider;
|
|||
import org.keycloak.models.AuthenticatorModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.LoginProtocol;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator implements Authenticator {
|
||||
public static final String FORM_USERNAME = "FORM_USERNAME";
|
||||
public class UsernamePasswordForm extends AbstractFormAuthenticator implements Authenticator {
|
||||
protected AuthenticatorModel model;
|
||||
|
||||
public LoginFormUsernameAuthenticator(AuthenticatorModel model) {
|
||||
public UsernamePasswordForm(AuthenticatorModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
|
@ -67,7 +70,14 @@ public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator im
|
|||
return;
|
||||
}
|
||||
|
||||
validateUser(context, formData);
|
||||
if (!validateUser(context, formData)) {
|
||||
return;
|
||||
}
|
||||
if (!validatePassword(context, formData)) {
|
||||
return;
|
||||
}
|
||||
context.success();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,35 +93,16 @@ public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator im
|
|||
return forms.createLogin();
|
||||
}
|
||||
|
||||
public void validateUser(AuthenticatorContext context, MultivaluedMap<String, String> inputData) {
|
||||
String username = inputData.getFirst(AuthenticationManager.FORM_USERNAME);
|
||||
if (username == null) {
|
||||
context.getEvent().error(Errors.USER_NOT_FOUND);
|
||||
Response challengeResponse = invalidUser(context);
|
||||
context.failureChallenge(AuthenticationProcessor.Error.INVALID_USER, challengeResponse);
|
||||
return;
|
||||
}
|
||||
context.getEvent().detail(Details.USERNAME, username);
|
||||
context.getClientSession().setNote(FORM_USERNAME, username);
|
||||
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(context.getSession(), context.getRealm(), username);
|
||||
if (invalidUser(context, user)) return;
|
||||
String rememberMe = inputData.getFirst("rememberMe");
|
||||
boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("on");
|
||||
if (remember) {
|
||||
context.getClientSession().setNote(Details.REMEMBER_ME, "true");
|
||||
context.getEvent().detail(Details.REMEMBER_ME, "true");
|
||||
}
|
||||
context.setUser(user);
|
||||
context.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
// never called
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
// never called
|
||||
}
|
||||
|
||||
@Override
|
|
@ -16,13 +16,13 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LoginFormPasswordAuthenticatorFactory implements AuthenticatorFactory {
|
||||
public class UsernamePasswordFormFactory implements AuthenticatorFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "auth-login-form-password";
|
||||
public static final String PROVIDER_ID = "auth-username-password-form";
|
||||
|
||||
@Override
|
||||
public Authenticator create(AuthenticatorModel model) {
|
||||
return new LoginFormPasswordAuthenticator(model);
|
||||
return new UsernamePasswordForm(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,27 +60,22 @@ public class LoginFormPasswordAuthenticatorFactory implements AuthenticatorFacto
|
|||
return true;
|
||||
}
|
||||
public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED,
|
||||
AuthenticationExecutionModel.Requirement.DISABLED};
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED
|
||||
};
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
|
||||
return REQUIREMENT_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "Credential Validation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Login Form Password";
|
||||
return "Username Password Form";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Validates a user password that is specified on the login page.";
|
||||
return "Validates a username and password from login form.";
|
||||
}
|
||||
|
||||
@Override
|
|
@ -176,12 +176,8 @@ public class Urls {
|
|||
return UriBuilder.fromUri(baseUri).path(RealmsResource.class);
|
||||
}
|
||||
|
||||
public static URI realmLoginAction(URI baseUri, String realmId) {
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "processLogin").build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmLoginPage(URI baseUri, String realmId) {
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "loginPage").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "authenticate").build(realmId);
|
||||
}
|
||||
|
||||
private static UriBuilder realmLogout(URI baseUri) {
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.keycloak.authentication.AuthenticatorUtil;
|
|||
import org.keycloak.authentication.RequiredActionContext;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.authentication.authenticators.AbstractFormAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.UsernamePasswordFormFactory;
|
||||
import org.keycloak.email.EmailException;
|
||||
import org.keycloak.email.EmailProvider;
|
||||
import org.keycloak.events.Details;
|
||||
|
@ -125,23 +125,13 @@ public class LoginActionsService {
|
|||
}
|
||||
|
||||
public static UriBuilder authenticationFormProcessor(UriInfo uriInfo) {
|
||||
return loginActionsBaseUrl(uriInfo).path(LoginActionsService.class, "authForm");
|
||||
return loginActionsBaseUrl(uriInfo).path(LoginActionsService.class, "authenticateForm");
|
||||
}
|
||||
|
||||
public static UriBuilder loginActionsBaseUrl(UriBuilder baseUriBuilder) {
|
||||
return baseUriBuilder.path(RealmsResource.class).path(RealmsResource.class, "getLoginActionsService");
|
||||
}
|
||||
|
||||
public static UriBuilder processOAuthUrl(UriInfo uriInfo) {
|
||||
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
|
||||
return processOAuthUrl(baseUriBuilder);
|
||||
}
|
||||
|
||||
public static UriBuilder processOAuthUrl(UriBuilder baseUriBuilder) {
|
||||
UriBuilder uriBuilder = loginActionsBaseUrl(baseUriBuilder);
|
||||
return uriBuilder.path(OIDCLoginProtocolService.class, "processOAuth");
|
||||
}
|
||||
|
||||
public LoginActionsService(RealmModel realm, AuthenticationManager authManager, EventBuilder event) {
|
||||
this.realm = realm;
|
||||
this.authManager = authManager;
|
||||
|
@ -241,9 +231,10 @@ public class LoginActionsService {
|
|||
* @param code
|
||||
* @return
|
||||
*/
|
||||
@Path("login")
|
||||
@Path("authenticate")
|
||||
@GET
|
||||
public Response loginPage(@QueryParam("code") String code) {
|
||||
public Response authenticate(@QueryParam("code") String code,
|
||||
@QueryParam("action") String action) {
|
||||
event.event(EventType.LOGIN);
|
||||
Checks checks = new Checks();
|
||||
if (!checks.check(code)) {
|
||||
|
@ -266,6 +257,7 @@ public class LoginActionsService {
|
|||
.setConnection(clientConnection)
|
||||
.setEventBuilder(event)
|
||||
.setProtector(authManager.getProtector())
|
||||
.setAction(action)
|
||||
.setRealm(realm)
|
||||
.setSession(session)
|
||||
.setUriInfo(uriInfo)
|
||||
|
@ -316,10 +308,10 @@ public class LoginActionsService {
|
|||
* @param code
|
||||
* @return
|
||||
*/
|
||||
@Path("auth-form")
|
||||
@Path("authenticate")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response authForm(@QueryParam("code") String code,
|
||||
public Response authenticateForm(@QueryParam("code") String code,
|
||||
@QueryParam("action") String action) {
|
||||
event.event(EventType.LOGIN);
|
||||
Checks checks = new Checks();
|
||||
|
@ -523,7 +515,7 @@ public class LoginActionsService {
|
|||
|
||||
public boolean isPasswordRequired() {
|
||||
AuthenticationFlowModel browserFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW);
|
||||
return AuthenticatorUtil.isRequired(realm, browserFlow.getId(), LoginFormPasswordAuthenticatorFactory.PROVIDER_ID);
|
||||
return AuthenticatorUtil.isRequired(realm, browserFlow.getId(), UsernamePasswordFormFactory.PROVIDER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
org.keycloak.authentication.authenticators.CookieAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.LoginFormOTPAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.LoginFormUsernameAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.UsernamePasswordFormFactory
|
||||
org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.keycloak.testsuite.utils;
|
||||
|
||||
import org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.UsernamePasswordFormFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorModel;
|
||||
|
@ -36,7 +36,7 @@ public class CredentialHelper {
|
|||
String flowAlias = DefaultAuthenticationFlows.BROWSER_FLOW;
|
||||
authenticationRequirement(realm, providerId, flowAlias, requirement);
|
||||
} else if (type.equals(CredentialRepresentation.PASSWORD)) {
|
||||
String providerId = LoginFormPasswordAuthenticatorFactory.PROVIDER_ID;
|
||||
String providerId = UsernamePasswordFormFactory.PROVIDER_ID;
|
||||
String flowAlias = DefaultAuthenticationFlows.FORMS_FLOW;
|
||||
authenticationRequirement(realm, providerId, flowAlias, requirement);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue