KEYCLOAK-787 Clicking back to login after sending password reset email fails

This commit is contained in:
Stian Thorgersen 2014-10-31 13:48:34 +01:00
parent 9b0d5acb50
commit bb2de4dc59
7 changed files with 58 additions and 11 deletions

View file

@ -40,6 +40,8 @@ public enum EventType {
SEND_VERIFY_EMAIL_ERROR, SEND_VERIFY_EMAIL_ERROR,
SEND_RESET_PASSWORD, SEND_RESET_PASSWORD,
SEND_RESET_PASSWORD_ERROR, SEND_RESET_PASSWORD_ERROR,
RESET_PASSWORD,
RESET_PASSWORD_ERROR,
INVALID_SIGNATURE_ERROR, INVALID_SIGNATURE_ERROR,
REGISTER_NODE, REGISTER_NODE,

View file

@ -47,6 +47,7 @@ public interface ClientSessionModel {
UPDATE_PROFILE, UPDATE_PROFILE,
CONFIGURE_TOTP, CONFIGURE_TOTP,
UPDATE_PASSWORD, UPDATE_PASSWORD,
RECOVER_PASSWORD,
AUTHENTICATE, AUTHENTICATE,
SOCIAL_CALLBACK SOCIAL_CALLBACK
} }

View file

@ -78,10 +78,6 @@ public class ClientSessionCode {
return clientSession; return clientSession;
} }
public boolean isValid(RequiredAction requiredAction) {
return isValid(convertToAction(requiredAction));
}
public boolean isValid(ClientSessionModel.Action requestedAction) { public boolean isValid(ClientSessionModel.Action requestedAction) {
ClientSessionModel.Action action = clientSession.getAction(); ClientSessionModel.Action action = clientSession.getAction();
if (action == null) { if (action == null) {

View file

@ -271,9 +271,9 @@ public class LoginActionsService {
return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application."); return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application.");
} }
ClientSessionModel clientSession = clientCode.getClientSession(); ClientSessionModel clientSession = clientCode.getClientSession();
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE)) { if (!(clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientCode.isValid(ClientSessionModel.Action.RECOVER_PASSWORD))) {
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE); clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
event.client(clientSession.getClient()).error(Errors.INVALID_USER_CREDENTIALS); event.client(clientSession.getClient()).error(Errors.INVALID_CODE);
return Flows.forms(this.session, realm, clientSession.getClient(), uriInfo).setError(Messages.INVALID_USER) return Flows.forms(this.session, realm, clientSession.getClient(), uriInfo).setError(Messages.INVALID_USER)
.setClientSessionCode(clientCode.getCode()) .setClientSessionCode(clientCode.getCode())
.createLogin(); .createLogin();
@ -753,13 +753,14 @@ public class LoginActionsService {
@Path("password-reset") @Path("password-reset")
@GET @GET
public Response passwordReset(@QueryParam("code") String code, @QueryParam("key") String key) { public Response passwordReset(@QueryParam("code") String code, @QueryParam("key") String key) {
event.event(EventType.SEND_RESET_PASSWORD); event.event(EventType.RESET_PASSWORD);
if (key != null) { if (key != null) {
Checks checks = new Checks(); Checks checks = new Checks();
if (!checks.check(key, ClientSessionModel.Action.UPDATE_PASSWORD)) { if (!checks.check(key, ClientSessionModel.Action.RECOVER_PASSWORD)) {
return checks.response; return checks.response;
} }
ClientSessionCode accessCode = checks.clientCode; ClientSessionCode accessCode = checks.clientCode;
accessCode.setRequiredAction(RequiredAction.UPDATE_PASSWORD);
return Flows.forms(session, realm, null, uriInfo) return Flows.forms(session, realm, null, uriInfo)
.setClientSessionCode(accessCode.getCode()) .setClientSessionCode(accessCode.getCode())
.createResponse(RequiredAction.UPDATE_PASSWORD); .createResponse(RequiredAction.UPDATE_PASSWORD);
@ -820,7 +821,7 @@ public class LoginActionsService {
event.session(userSession); event.session(userSession);
TokenManager.attachClientSession(userSession, clientSession); TokenManager.attachClientSession(userSession, clientSession);
accessCode.setRequiredAction(RequiredAction.UPDATE_PASSWORD); accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD);
try { try {
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri()); UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
@ -840,7 +841,7 @@ public class LoginActionsService {
} }
} }
return Flows.forms(session, realm, client, uriInfo).setSuccess("emailSent").createPasswordReset(); return Flows.forms(session, realm, client, uriInfo).setSuccess("emailSent").setClientSessionCode(accessCode.getCode()).createPasswordReset();
} }
private Response redirectOauth(UserModel user, ClientSessionCode accessCode, ClientSessionModel clientSession, UserSessionModel userSession) { private Response redirectOauth(UserModel user, ClientSessionCode accessCode, ClientSessionModel clientSession, UserSessionModel userSession) {

View file

@ -166,7 +166,7 @@ public class LoginTotpTest {
loginPage.assertCurrent(); loginPage.assertCurrent();
Assert.assertEquals("Invalid username or password.", loginPage.getError()); Assert.assertEquals("Invalid username or password.", loginPage.getError());
AssertEvents.ExpectedEvent expectedEvent = events.expectLogin().error("invalid_user_credentials") AssertEvents.ExpectedEvent expectedEvent = events.expectLogin().error("invalid_code")
.user((String)null) .user((String)null)
.clearDetails() .clearDetails()
.session((String) null); .session((String) null);

View file

@ -38,6 +38,7 @@ import org.keycloak.testsuite.MailUtil;
import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType; import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.LoginPasswordResetPage; import org.keycloak.testsuite.pages.LoginPasswordResetPage;
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
@ -96,6 +97,9 @@ public class ResetPasswordTest {
@WebResource @WebResource
protected LoginPage loginPage; protected LoginPage loginPage;
@WebResource
protected ErrorPage errorPage;
@WebResource @WebResource
protected LoginPasswordResetPage resetPasswordPage; protected LoginPasswordResetPage resetPasswordPage;
@ -110,6 +114,42 @@ public class ResetPasswordTest {
resetPassword("login-test"); resetPassword("login-test");
} }
@Test
public void resetPasswordCancel() throws IOException, MessagingException {
loginPage.open();
loginPage.resetPassword();
resetPasswordPage.assertCurrent();
resetPasswordPage.changePassword("login-test");
resetPasswordPage.assertCurrent();
events.expectRequiredAction(EventType.SEND_RESET_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").detail(Details.EMAIL, "login@test.com").assertEvent().getSessionId();
resetPasswordPage.backToLogin();
Assert.assertTrue(loginPage.isCurrent());
loginPage.login("login-test", "password");
events.expectLogin().user(userId).detail(Details.USERNAME, "login-test").assertEvent();
Assert.assertEquals(1, greenMail.getReceivedMessages().length);
MimeMessage message = greenMail.getReceivedMessages()[0];
String body = (String) message.getContent();
String changePasswordUrl = MailUtil.getLink(body);
driver.navigate().to(changePasswordUrl.trim());
events.expect(EventType.RESET_PASSWORD_ERROR).client((String) null).user((String) null).error("invalid_code").clearDetails().assertEvent();
Assert.assertTrue(errorPage.isCurrent());
Assert.assertEquals("Unknown code, please login again through your application.", errorPage.getError());
}
@Test @Test
public void resetPasswordByEmail() throws IOException, MessagingException { public void resetPasswordByEmail() throws IOException, MessagingException {
resetPassword("login@test.com"); resetPassword("login@test.com");

View file

@ -41,6 +41,9 @@ public class LoginPasswordResetPage extends AbstractPage {
@FindBy(className = "feedback-error") @FindBy(className = "feedback-error")
private WebElement emailErrorMessage; private WebElement emailErrorMessage;
@FindBy(partialLinkText = "Back to Login")
private WebElement backToLogin;
public void changePassword(String username) { public void changePassword(String username) {
usernameInput.sendKeys(username); usernameInput.sendKeys(username);
@ -63,4 +66,8 @@ public class LoginPasswordResetPage extends AbstractPage {
return emailErrorMessage != null ? emailErrorMessage.getText() : null; return emailErrorMessage != null ? emailErrorMessage.getText() : null;
} }
public void backToLogin() {
backToLogin.click();
}
} }