KEYCLOAK-5061 Process correct initial flow when action expired

This commit is contained in:
mposolda 2017-07-10 22:52:44 +02:00
parent 2b427dfcd2
commit 936efe872a
5 changed files with 77 additions and 10 deletions

View file

@ -433,7 +433,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
String flowId = flow.getId();
AuthenticationProcessor processor = createProcessor(authenticationSession, flowId, LoginActionsService.RESET_CREDENTIALS_PATH);
authenticationSession.setClientNote(APP_INITIATED_FLOW, LoginActionsService.REGISTRATION_PATH);
authenticationSession.setClientNote(APP_INITIATED_FLOW, LoginActionsService.RESET_CREDENTIALS_PATH);
return processor.authenticate();
}

View file

@ -342,7 +342,7 @@ public class LoginActionsService {
}
authSession = createAuthenticationSessionForClient();
return processResetCredentials(false, null, authSession);
return processResetCredentials(false, null, authSession, null);
}
event.event(EventType.RESET_PASSWORD);
@ -386,7 +386,7 @@ public class LoginActionsService {
}
return processResetCredentials(checks.isActionRequest(), execution, authSession);
return processResetCredentials(checks.isActionRequest(), execution, authSession, null);
}
/**
@ -469,7 +469,9 @@ public class LoginActionsService {
flowPath = AUTHENTICATE_PATH;
}
AuthenticationProcessor.resetFlow(authSession, flowPath);
return processAuthentication(false, null, authSession, Messages.EXPIRED_ACTION_TOKEN_SESSION_EXISTS);
// Process correct flow
return processFlowFromPath(flowPath, authSession, Messages.EXPIRED_ACTION_TOKEN_SESSION_EXISTS);
}
return handleActionTokenVerificationException(null, ex, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION_TOKEN_NO_SESSION);
@ -539,6 +541,20 @@ public class LoginActionsService {
}
}
private Response processFlowFromPath(String flowPath, AuthenticationSessionModel authSession, String errorMessage) {
if (AUTHENTICATE_PATH.equals(flowPath)) {
return processAuthentication(false, null, authSession, errorMessage);
} else if (REGISTRATION_PATH.equals(flowPath)) {
return processRegistration(false, null, authSession, errorMessage);
} else if (RESET_CREDENTIALS_PATH.equals(flowPath)) {
return processResetCredentials(false, null, authSession, errorMessage);
} else {
return ErrorPage.error(session, errorMessage == null ? Messages.INVALID_REQUEST : errorMessage);
}
}
private <T extends DefaultActionToken> ActionTokenHandler<T> resolveActionTokenHandler(String actionId) throws VerificationException {
if (actionId == null) {
throw new VerificationException("Action token operation not set");
@ -562,10 +578,10 @@ public class LoginActionsService {
return ErrorPage.error(session, errorMessage == null ? Messages.INVALID_CODE : errorMessage);
}
protected Response processResetCredentials(boolean actionRequest, String execution, AuthenticationSessionModel authSession) {
protected Response processResetCredentials(boolean actionRequest, String execution, AuthenticationSessionModel authSession, String errorMessage) {
AuthenticationProcessor authProcessor = new ResetCredentialsActionTokenHandler.ResetCredsAuthenticationProcessor();
return processFlow(actionRequest, execution, authSession, RESET_CREDENTIALS_PATH, realm.getResetCredentialsFlow(), null, authProcessor);
return processFlow(actionRequest, execution, authSession, RESET_CREDENTIALS_PATH, realm.getResetCredentialsFlow(), errorMessage, authProcessor);
}

View file

@ -424,7 +424,7 @@ public class RequiredActionEmailVerificationTest extends AbstractTestRealmKeyclo
driver.navigate().to(verificationUrl.trim());
loginPage.assertCurrent();
assertEquals("Action expired. Please login again.", loginPage.getError());
assertEquals("Action expired. Please start again.", loginPage.getError());
events.expectRequiredAction(EventType.EXECUTE_ACTION_TOKEN_ERROR)
.error(Errors.EXPIRED_CODE)

View file

@ -371,7 +371,7 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
loginPage.assertCurrent();
assertEquals("Action expired. Please login again.", loginPage.getError());
assertEquals("Action expired. Please start again.", loginPage.getError());
events.expectRequiredAction(EventType.EXECUTE_ACTION_TOKEN_ERROR).error("expired_code").client((String) null).user(userId).session((String) null).clearDetails().detail(Details.ACTION, ResetCredentialsActionToken.TOKEN_TYPE).assertEvent();
} finally {
@ -407,7 +407,7 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
loginPage.assertCurrent();
assertEquals("Action expired. Please login again.", loginPage.getError());
assertEquals("Action expired. Please start again.", loginPage.getError());
events.expectRequiredAction(EventType.EXECUTE_ACTION_TOKEN_ERROR).error("expired_code").client((String) null).user(userId).session((String) null).clearDetails().detail(Details.ACTION, ResetCredentialsActionToken.TOKEN_TYPE).assertEvent();
} finally {
@ -463,6 +463,57 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
}
}
// KEYCLOAK-5061
@Test
public void resetPasswordExpiredCodeForgotPasswordFlow() throws IOException, MessagingException, InterruptedException {
final AtomicInteger originalValue = new AtomicInteger();
RealmRepresentation realmRep = testRealm().toRepresentation();
originalValue.set(realmRep.getActionTokenGeneratedByUserLifespan());
realmRep.setActionTokenGeneratedByUserLifespan(60);
testRealm().update(realmRep);
try {
// Redirect directly to KC "forgot password" endpoint instead of "authenticate" endpoint
String loginUrl = oauth.getLoginFormUrl();
String forgotPasswordUrl = loginUrl.replace("/auth?", "/forgot-credentials?"); // Workaround, but works
driver.navigate().to(forgotPasswordUrl);
resetPasswordPage.assertCurrent();
resetPasswordPage.changePassword("login-test");
loginPage.assertCurrent();
assertEquals("You should receive an email shortly with further instructions.", loginPage.getSuccessMessage());
expectedMessagesCount++;
events.expectRequiredAction(EventType.SEND_RESET_PASSWORD)
.session((String)null)
.user(userId).detail(Details.USERNAME, "login-test").detail(Details.EMAIL, "login@test.com").assertEvent();
assertEquals(1, greenMail.getReceivedMessages().length);
MimeMessage message = greenMail.getReceivedMessages()[0];
String changePasswordUrl = getPasswordResetEmailLink(message);
setTimeOffset(70);
driver.navigate().to(changePasswordUrl.trim());
resetPasswordPage.assertCurrent();
assertEquals("Action expired. Please start again.", loginPage.getError());
events.expectRequiredAction(EventType.EXECUTE_ACTION_TOKEN_ERROR).error("expired_code").client((String) null).user(userId).session((String) null).clearDetails().detail(Details.ACTION, ResetCredentialsActionToken.TOKEN_TYPE).assertEvent();
} finally {
setTimeOffset(0);
realmRep.setActionTokenGeneratedByUserLifespan(originalValue.get());
testRealm().update(realmRep);
}
}
@Test
public void resetPasswordDisabledUser() throws IOException, MessagingException, InterruptedException {
UserRepresentation user = findUser("login-test");

View file

@ -131,7 +131,7 @@ accountTemporarilyDisabledMessage=Account is temporarily disabled, contact admin
expiredCodeMessage=Login timeout. Please login again.
expiredActionMessage=Action expired. Please continue with login now.
expiredActionTokenNoSessionMessage=Action expired.
expiredActionTokenSessionExistsMessage=Action expired. Please login again.
expiredActionTokenSessionExistsMessage=Action expired. Please start again.
missingFirstNameMessage=Please specify first name.
missingLastNameMessage=Please specify last name.