keycloak-aplcache
Changes
services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java 18(+15 -3)
Details
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
index 79a2b67..12cb4fd 100755
--- a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
@@ -1,10 +1,20 @@
package org.keycloak.models;
+import java.util.Comparator;
+
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AuthenticationExecutionModel {
+ public static class ExecutionComparator implements Comparator<AuthenticationExecutionModel> {
+ public static final ExecutionComparator SINGLETON = new ExecutionComparator();
+
+ @Override
+ public int compare(AuthenticationExecutionModel o1, AuthenticationExecutionModel o2) {
+ return o1.priority - o2.priority;
+ }
+ }
private String id;
private String authenticator;
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index bf97994..2bc6e61 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -20,6 +20,7 @@ import org.keycloak.services.managers.BruteForceProtector;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
import java.util.List;
/**
@@ -332,6 +333,7 @@ public class AuthenticationProcessor {
}
public Response authenticate() throws AuthException {
+ logger.info("AUTHENTICATE");
event.event(EventType.LOGIN);
event.client(clientSession.getClient().getClientId())
.detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
@@ -381,7 +383,7 @@ public class AuthenticationProcessor {
public Response finishAuthentication() {
event.success();
RealmModel realm = clientSession.getRealm();
- return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm , userSession, clientSession, request, uriInfo, connection);
+ return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, connection);
}
@@ -393,11 +395,13 @@ public class AuthenticationProcessor {
}
List<AuthenticationExecutionModel> executions = realm.getAuthenticationExecutions(flowId);
if (executions == null) return null;
+ Collections.sort(executions, AuthenticationExecutionModel.ExecutionComparator.SINGLETON);
Response alternativeChallenge = null;
AuthenticationExecutionModel challengedAlternativeExecution = null;
boolean alternativeSuccessful = false;
for (AuthenticationExecutionModel model : executions) {
if (isProcessed(model)) {
+ logger.info("execution is processed");
if (!alternativeSuccessful && model.isAlternative() && isSuccessful(model)) alternativeSuccessful = true;
continue;
}
@@ -421,6 +425,7 @@ public class AuthenticationProcessor {
AuthenticatorModel authenticatorModel = realm.getAuthenticatorById(model.getAuthenticator());
AuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, authenticatorModel.getProviderId());
Authenticator authenticator = factory.create(authenticatorModel);
+ logger.info("authenticator: " + authenticatorModel.getProviderId());
UserModel authUser = clientSession.getAuthenticatedUser();
if (authenticator.requiresUser() && authUser == null){
@@ -428,7 +433,7 @@ public class AuthenticationProcessor {
clientSession.setAuthenticatorStatus(challengedAlternativeExecution.getId(), UserSessionModel.AuthenticatorStatus.CHALLENGED);
return alternativeChallenge;
}
- throw new AuthException(Error.UNKNOWN_USER);
+ throw new AuthException("authenticator: " + authenticatorModel.getProviderId(), Error.UNKNOWN_USER);
}
boolean configuredFor = false;
if (authenticator.requiresUser() && authUser != null) {
@@ -436,6 +441,7 @@ public class AuthenticationProcessor {
if (!configuredFor) {
if (model.isRequired()) {
if (model.isUserSetupAllowed()) {
+ logger.info("authenticator SETUP_REQUIRED: " + authenticatorModel.getProviderId());
clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.SETUP_REQUIRED);
String requiredAction = authenticator.getRequiredAction();
if (!authUser.getRequiredActions().contains(requiredAction)) {
@@ -455,15 +461,18 @@ public class AuthenticationProcessor {
authenticator.authenticate(context);
Status result = context.getStatus();
if (result == Status.SUCCESS){
+ logger.info("authenticator SUCCESS: " + authenticatorModel.getProviderId());
clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.SUCCESS);
if (model.isAlternative()) alternativeSuccessful = true;
continue;
} else if (result == Status.FAILED) {
+ logger.info("authenticator FAILED: " + authenticatorModel.getProviderId());
logUserFailure();
clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.FAILED);
if (context.challenge != null) return context.challenge;
throw new AuthException(context.error);
} else if (result == Status.CHALLENGE) {
+ logger.info("authenticator CHALLENGE: " + authenticatorModel.getProviderId());
if (model.isRequired() || (model.isOptional() && configuredFor)) {
clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.CHALLENGED);
return context.challenge;
@@ -476,16 +485,19 @@ public class AuthenticationProcessor {
}
continue;
} else if (result == Status.FAILURE_CHALLENGE) {
+ logger.info("authenticator FAILURE_CHALLENGE: " + authenticatorModel.getProviderId());
logUserFailure();
clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.CHALLENGED);
return context.challenge;
} else if (result == Status.ATTEMPTED) {
+ logger.info("authenticator ATTEMPTED: " + authenticatorModel.getProviderId());
if (model.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) {
throw new AuthException(Error.INVALID_CREDENTIALS);
}
clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.ATTEMPTED);
continue;
} else {
+ logger.info("authenticator INTERNAL_ERROR: " + authenticatorModel.getProviderId());
logger.error("Unknown result status");
throw new AuthException(Error.INTERNAL_ERROR);
}
@@ -508,10 +520,15 @@ public class AuthenticationProcessor {
protected Response authenticationComplete() {
String username = clientSession.getAuthenticatedUser().getUsername();
+ String rememberMe = clientSession.getNote(Details.REMEMBER_ME);
+ boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("true");
if (userSession == null) { // if no authenticator attached a usersession
- userSession = session.sessions().createUserSession(realm, clientSession.getAuthenticatedUser(), username, connection.getRemoteAddr(), "form", false, null, null);
+ userSession = session.sessions().createUserSession(realm, clientSession.getAuthenticatedUser(), username, connection.getRemoteAddr(), clientSession.getAuthMethod(), remember, null, null);
userSession.setState(UserSessionModel.State.LOGGING_IN);
}
+ if (remember) {
+ event.detail(Details.REMEMBER_ME, "true");
+ }
TokenManager.attachClientSession(userSession, clientSession);
event.user(userSession.getUser())
.detail(Details.USERNAME, username)
diff --git a/services/src/main/java/org/keycloak/authentication/Authenticator.java b/services/src/main/java/org/keycloak/authentication/Authenticator.java
index ee9d435..63abd76 100755
--- a/services/src/main/java/org/keycloak/authentication/Authenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/Authenticator.java
@@ -15,5 +15,4 @@ public interface Authenticator extends Provider {
boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user);
String getRequiredAction();
-
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java
index 14ae6a1..6550d13 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java
@@ -24,6 +24,7 @@ import javax.ws.rs.core.Response;
* @version $Revision: 1 $
*/
public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator implements Authenticator {
+ public static final String FORM_USERNAME = "FORM_USERNAME";
protected AuthenticatorModel model;
public LoginFormUsernameAuthenticator(AuthenticatorModel model) {
@@ -35,9 +36,14 @@ public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator im
if (!isActionUrl(context)) {
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
String loginHint = context.getClientSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);
- if (loginHint == null) {
- loginHint = AuthenticationManager.getRememberMeUsername(context.getRealm(), context.getHttpRequest().getHttpHeaders());
+
+ String rememberMeUsername = AuthenticationManager.getRememberMeUsername(context.getRealm(), context.getHttpRequest().getHttpHeaders());
+
+ if (loginHint != null || rememberMeUsername != null) {
if (loginHint != null) {
+ formData.add(AuthenticationManager.FORM_USERNAME, loginHint);
+ } else {
+ formData.add(AuthenticationManager.FORM_USERNAME, rememberMeUsername);
formData.add("rememberMe", "on");
}
}
@@ -83,9 +89,15 @@ public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator im
return;
}
context.getEvent().detail(Details.USERNAME, username);
- context.getClientSession().setNote("FORM_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();
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 5bfabae..6585f2d 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -216,8 +216,9 @@ public class AccountTest {
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
- String sessionId = events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent().getSessionId();
-
+ Event event = events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
+ String sessionId = event.getSessionId();
+ String userId = event.getUserId();
changePasswordPage.changePassword("", "new-password", "new-password");
Assert.assertEquals("Please specify password.", profilePage.getError());
@@ -241,7 +242,7 @@ public class AccountTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().session((String) null).user((String)null).error("invalid_user_credentials").assertEvent();
+ events.expectLogin().session((String) null).user(userId).error("invalid_user_credentials").assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "new-password");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
index 0d6b4cf..b814f62 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
@@ -26,11 +26,15 @@ import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
+import org.keycloak.authentication.authenticators.OTPFormAuthenticator;
+import org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory;
import org.keycloak.events.Details;
import org.keycloak.events.Event;
import org.keycloak.events.EventType;
+import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.MailUtil;
@@ -46,6 +50,7 @@ import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
+import org.keycloak.testsuite.utils.CredentialHelper;
import org.openqa.selenium.WebDriver;
import javax.mail.MessagingException;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index e13fa0e..4a86f78 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -144,28 +144,4 @@ public class LoginTotpTest {
events.expectLogin().error("invalid_user_credentials").session((String) null).assertEvent();
}
-
- @Test
- public void loginWithTotpExpiredPasswordToken() throws Exception {
- try {
- loginPage.open();
- loginPage.login("test-user@localhost", "password");
-
- loginTotpPage.assertCurrent();
-
- Time.setOffset(350);
-
- loginTotpPage.login(totp.generate("totpSecret"));
-
- loginPage.assertCurrent();
- Assert.assertEquals("Invalid username or password.", loginPage.getError());
-
- AssertEvents.ExpectedEvent expectedEvent = events.expectLogin().error("invalid_user_credentials")
- .session((String) null);
- expectedEvent.assertEvent();
- } finally {
- Time.setOffset(0);
- }
- }
-
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LogoutTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LogoutTest.java
index 561fcd6..e026c69 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LogoutTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LogoutTest.java
@@ -123,7 +123,7 @@ public class LogoutTest {
// Check session 1 logged-in
oauth.openLoginForm();
- events.expectLogin().session(sessionId).detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).assertEvent();
+ events.expectLogin().session(sessionId).removeDetail(Details.USERNAME).assertEvent();
// Logout session 1 by redirect
driver.navigate().to(oauth.getLogoutUrl(AppPage.baseUrl, null));
@@ -140,7 +140,7 @@ public class LogoutTest {
// Check session 3 logged-in
oauth.openLoginForm();
- events.expectLogin().session(sessionId3).detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).assertEvent();
+ events.expectLogin().session(sessionId3).removeDetail(Details.USERNAME).assertEvent();
}
}
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 3018fac..a88d8b1 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
@@ -34,6 +34,14 @@ public class CredentialHelper {
}
}
+ public static AuthenticationExecutionModel.Requirement getRequirement(RealmModel realm, String authenticatorProviderId, String flowAlias) {
+ AuthenticatorModel authenticator = findAuthenticatorByProviderId(realm, authenticatorProviderId);
+ AuthenticationFlowModel flow = findAuthenticatorFlowByAlias(realm, flowAlias);
+ AuthenticationExecutionModel execution = findExecutionByAuthenticator(realm, flow.getId(), authenticator.getId());
+ return execution.getRequirement();
+
+ }
+
public static void requireAuthentication(RealmModel realm, String authenticatorProviderId, String flowAlias) {
AuthenticationExecutionModel.Requirement requirement = AuthenticationExecutionModel.Requirement.REQUIRED;
authenticationRequirement(realm, authenticatorProviderId, flowAlias, requirement);