KEYCLOAK-787 Clicking back to login after sending password reset email fails
This commit is contained in:
parent
9b0d5acb50
commit
bb2de4dc59
7 changed files with 58 additions and 11 deletions
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue