diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/AuthenticatorConfiguredMethod.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/AuthenticatorConfiguredMethod.java index 7327e793e9..222252e791 100755 --- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/AuthenticatorConfiguredMethod.java +++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/AuthenticatorConfiguredMethod.java @@ -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; /** diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java index c652002ce6..25a28c9969 100755 --- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java +++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java @@ -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() { diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java index f4bb81c2ff..48c5d610c4 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java +++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java @@ -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); diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java index a6ac452030..32414ab491 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java @@ -13,7 +13,6 @@ import java.util.List; */ public interface AuthenticatorFactory extends ProviderFactory, ConfiguredProvider { Authenticator create(AuthenticatorModel model); - String getDisplayCategory(); String getDisplayType(); /** diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java index fcf34ba49c..30c123e287 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java @@ -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; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java index 9184034e20..6c611b1542 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java @@ -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 Bill Burke @@ -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 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 inputData) { + List 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; + } } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java index 525fb0b0ea..fc670d4a93 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java @@ -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 diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java deleted file mode 100755 index 56ef93a96b..0000000000 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java +++ /dev/null @@ -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 Bill Burke - * @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 inputData = context.getHttpRequest().getFormParameters(); - List 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() { - - } -} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticatorFactory.java deleted file mode 100755 index ff5043a4c1..0000000000 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticatorFactory.java +++ /dev/null @@ -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 Bill Burke - * @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 getConfigProperties() { - return null; - } -} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java deleted file mode 100755 index cdd49b95fd..0000000000 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java +++ /dev/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 Bill Burke - * @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 inputData = context.getHttpRequest().getDecodedFormParameters(); - List 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() { - - } -} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticatorFactory.java deleted file mode 100755 index 0db3a77579..0000000000 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticatorFactory.java +++ /dev/null @@ -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 Bill Burke - * @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 getConfigProperties() { - return null; - } -} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java index f197217835..6c8850d127 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java @@ -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() { diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticatorFactory.java index 21c56fc8d0..392ad4a5a1 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticatorFactory.java @@ -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"; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java similarity index 70% rename from services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java rename to services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java index 6c3759a6c7..3dd81d75fb 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java @@ -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 Bill Burke * @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 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 diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java similarity index 72% rename from services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticatorFactory.java rename to services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java index e136c442d4..24c5c5a30b 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java @@ -16,13 +16,13 @@ import java.util.List; * @author Bill Burke * @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 diff --git a/services/src/main/java/org/keycloak/services/Urls.java b/services/src/main/java/org/keycloak/services/Urls.java index 2adbd1e9dc..293437581c 100755 --- a/services/src/main/java/org/keycloak/services/Urls.java +++ b/services/src/main/java/org/keycloak/services/Urls.java @@ -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) { diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index 1a3bba4318..3bec193492 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -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); } /** diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory index eb41e5e7fd..d4d03d0745 100755 --- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory @@ -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 diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/utils/CredentialHelper.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/utils/CredentialHelper.java index 8ac3a158a7..fb38f17c8a 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/utils/CredentialHelper.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/utils/CredentialHelper.java @@ -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); }