KEYCLOAK-3641 Clicking an invalid verification link due to re-send removes the email verification key from the session

This commit is contained in:
Stian Thorgersen 2016-10-27 14:01:09 +02:00
parent 317749a7fd
commit c6ac3266f0
2 changed files with 53 additions and 17 deletions

View file

@ -693,6 +693,20 @@ public class LoginActionsService {
public Response emailVerification(@QueryParam("code") String code, @QueryParam("key") String key) { public Response emailVerification(@QueryParam("code") String code, @QueryParam("key") String key) {
event.event(EventType.VERIFY_EMAIL); event.event(EventType.VERIFY_EMAIL);
if (key != null) { if (key != null) {
ClientSessionModel clientSession = null;
String keyFromSession = null;
if (code != null) {
clientSession = ClientSessionCode.getClientSession(code, session, realm);
keyFromSession = clientSession.getNote(Constants.VERIFY_EMAIL_KEY);
}
if (clientSession == null || !key.equals(keyFromSession)) {
ServicesLogger.LOGGER.invalidKeyForEmailVerification();
event.error(Errors.INVALID_CODE);
throw new WebApplicationException(ErrorPage.error(session, Messages.STALE_VERIFY_EMAIL_LINK));
}
clientSession.removeNote(Constants.VERIFY_EMAIL_KEY);
Checks checks = new Checks(); Checks checks = new Checks();
if (!checks.verifyCode(code, ClientSessionModel.Action.REQUIRED_ACTIONS.name(), ClientSessionCode.ActionType.USER)) { if (!checks.verifyCode(code, ClientSessionModel.Action.REQUIRED_ACTIONS.name(), ClientSessionCode.ActionType.USER)) {
if (checks.clientCode == null && checks.result.isClientSessionNotFound() || checks.result.isIllegalHash()) { if (checks.clientCode == null && checks.result.isClientSessionNotFound() || checks.result.isIllegalHash()) {
@ -700,8 +714,9 @@ public class LoginActionsService {
} }
return checks.response; return checks.response;
} }
ClientSessionCode accessCode = checks.clientCode; ClientSessionCode accessCode = checks.clientCode;
ClientSessionModel clientSession = accessCode.getClientSession(); clientSession = accessCode.getClientSession();
if (!ClientSessionModel.Action.VERIFY_EMAIL.name().equals(clientSession.getNote(AuthenticationManager.CURRENT_REQUIRED_ACTION))) { if (!ClientSessionModel.Action.VERIFY_EMAIL.name().equals(clientSession.getNote(AuthenticationManager.CURRENT_REQUIRED_ACTION))) {
ServicesLogger.LOGGER.reqdActionDoesNotMatch(); ServicesLogger.LOGGER.reqdActionDoesNotMatch();
event.error(Errors.INVALID_CODE); event.error(Errors.INVALID_CODE);
@ -713,14 +728,6 @@ public class LoginActionsService {
initEvent(clientSession); initEvent(clientSession);
event.event(EventType.VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()); event.event(EventType.VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail());
String keyFromSession = clientSession.getNote(Constants.VERIFY_EMAIL_KEY);
clientSession.removeNote(Constants.VERIFY_EMAIL_KEY);
if (!key.equals(keyFromSession)) {
ServicesLogger.LOGGER.invalidKeyForEmailVerification();
event.error(Errors.INVALID_USER_CREDENTIALS);
throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE));
}
user.setEmailVerified(true); user.setEmailVerified(true);
user.removeRequiredAction(RequiredAction.VERIFY_EMAIL); user.removeRequiredAction(RequiredAction.VERIFY_EMAIL);

View file

@ -31,6 +31,7 @@ import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.TestRealmKeycloakTest; import org.keycloak.testsuite.TestRealmKeycloakTest;
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.InfoPage; import org.keycloak.testsuite.pages.InfoPage;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.RegisterPage; import org.keycloak.testsuite.pages.RegisterPage;
@ -72,6 +73,9 @@ public class RequiredActionEmailVerificationTest extends TestRealmKeycloakTest {
@Page @Page
protected InfoPage infoPage; protected InfoPage infoPage;
@Page
protected ErrorPage errorPage;
@Override @Override
public void configureTestRealm(RealmRepresentation testRealm) { public void configureTestRealm(RealmRepresentation testRealm) {
testRealm.setVerifyEmail(Boolean.TRUE); testRealm.setVerifyEmail(Boolean.TRUE);
@ -176,6 +180,33 @@ public class RequiredActionEmailVerificationTest extends TestRealmKeycloakTest {
events.expectLogin().session(sessionId).assertEvent(); events.expectLogin().session(sessionId).assertEvent();
} }
@Test
public void verifyEmailResendFirstInvalidSecondStillValid() throws IOException, MessagingException {
loginPage.open();
loginPage.login("test-user@localhost", "password");
verifyEmailPage.clickResendEmail();
Assert.assertEquals(2, greenMail.getReceivedMessages().length);
MimeMessage message1 = greenMail.getReceivedMessages()[0];
String verificationUrl1 = getPasswordResetEmailLink(message1);
driver.navigate().to(verificationUrl1.trim());
assertTrue(errorPage.isCurrent());
assertEquals("The link you clicked is a old stale link and is no longer valid. Maybe you have already verified your email?", errorPage.getError());
MimeMessage message2 = greenMail.getReceivedMessages()[1];
String verificationUrl2 = getPasswordResetEmailLink(message2);
driver.navigate().to(verificationUrl2.trim());
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
}
@Test @Test
public void verifyEmailNewBrowserSession() throws IOException, MessagingException { public void verifyEmailNewBrowserSession() throws IOException, MessagingException {
loginPage.open(); loginPage.open();
@ -221,10 +252,7 @@ public class RequiredActionEmailVerificationTest extends TestRealmKeycloakTest {
String resendEmailLink = verifyEmailPage.getResendEmailLink(); String resendEmailLink = verifyEmailPage.getResendEmailLink();
String keyInsteadCodeURL = resendEmailLink.replace("code=", "key="); String keyInsteadCodeURL = resendEmailLink.replace("code=", "key=");
AssertEvents.ExpectedEvent emailEvent = events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).detail("email", "test-user@localhost"); events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).detail("email", "test-user@localhost").assertEvent();
EventRepresentation sendEvent = emailEvent.assertEvent();
String sessionId = sendEvent.getSessionId();
String mailCodeId = sendEvent.getDetails().get(Details.CODE_ID);
driver.navigate().to(keyInsteadCodeURL); driver.navigate().to(keyInsteadCodeURL);
@ -240,10 +268,11 @@ public class RequiredActionEmailVerificationTest extends TestRealmKeycloakTest {
driver.navigate().to(badKeyURL); driver.navigate().to(badKeyURL);
events.expectRequiredAction(EventType.VERIFY_EMAIL_ERROR) events.expectRequiredAction(EventType.VERIFY_EMAIL_ERROR)
.error(Errors.INVALID_USER_CREDENTIALS) .error(Errors.INVALID_CODE)
.session(sessionId) .client((String)null)
.detail("email", "test-user@localhost") .user((String)null)
.detail(Details.CODE_ID, mailCodeId) .session((String)null)
.clearDetails()
.assertEvent(); .assertEvent();
} }