diff --git a/server-spi/src/main/java/org/keycloak/services/managers/ClientSessionCode.java b/server-spi/src/main/java/org/keycloak/services/managers/ClientSessionCode.java index 5e2468155c..91c388f704 100755 --- a/server-spi/src/main/java/org/keycloak/services/managers/ClientSessionCode.java +++ b/server-spi/src/main/java/org/keycloak/services/managers/ClientSessionCode.java @@ -65,6 +65,7 @@ public class ClientSessionCode { ClientSessionCode code; boolean clientSessionNotFound; boolean illegalHash; + ClientSessionModel clientSession; public ClientSessionCode getCode() { return code; @@ -77,6 +78,10 @@ public class ClientSessionCode { public boolean isIllegalHash() { return illegalHash; } + + public ClientSessionModel getClientSession() { + return clientSession; + } } public static ParseResult parseResult(String code, KeycloakSession session, RealmModel realm) { @@ -89,19 +94,19 @@ public class ClientSessionCode { String[] parts = code.split("\\."); String id = parts[1]; - ClientSessionModel clientSession = session.sessions().getClientSession(realm, id); - if (clientSession == null) { + result.clientSession = session.sessions().getClientSession(realm, id); + if (result.clientSession == null) { result.clientSessionNotFound = true; return result; } - String hash = createHash(realm, clientSession); + String hash = createHash(realm, result.clientSession); if (!hash.equals(parts[0])) { result.illegalHash = true; return result; } - result.code = new ClientSessionCode(realm, clientSession); + result.code = new ClientSessionCode(realm, result.clientSession); return result; } catch (RuntimeException e) { result.illegalHash = true; diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java index ca1db96590..71238b772d 100755 --- a/services/src/main/java/org/keycloak/services/messages/Messages.java +++ b/services/src/main/java/org/keycloak/services/messages/Messages.java @@ -151,6 +151,8 @@ public class Messages { public static final String INVALID_CODE = "invalidCodeMessage"; + public static final String STALE_VERIFY_EMAIL_LINK = "staleEmailVerificationLink"; + public static final String IDENTITY_PROVIDER_UNEXPECTED_ERROR = "identityProviderUnexpectedErrorMessage"; public static final String IDENTITY_PROVIDER_NOT_FOUND = "identityProviderNotFoundMessage"; diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index e46cbcad5e..e23f9df216 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -169,6 +169,7 @@ public class LoginActionsService { private class Checks { ClientSessionCode clientCode; Response response; + ClientSessionCode.ParseResult result; boolean verifyCode(String code, String requiredAction, ClientSessionCode.ActionType actionType) { if (!verifyCode(code)) { @@ -213,7 +214,7 @@ public class LoginActionsService { response = ErrorPage.error(session, Messages.REALM_NOT_ENABLED); return false; } - ClientSessionCode.ParseResult result = ClientSessionCode.parseResult(code, session, realm); + result = ClientSessionCode.parseResult(code, session, realm); clientCode = result.getCode(); if (clientCode == null) { if (result.isClientSessionNotFound()) { // timeout @@ -654,6 +655,9 @@ public class LoginActionsService { if (key != null) { Checks checks = new Checks(); if (!checks.verifyCode(code, ClientSessionModel.Action.REQUIRED_ACTIONS.name(), ClientSessionCode.ActionType.USER)) { + if (checks.clientCode == null && checks.result.isClientSessionNotFound() || checks.result.isIllegalHash()) { + return ErrorPage.error(session, Messages.STALE_VERIFY_EMAIL_LINK); + } return checks.response; } ClientSessionCode accessCode = checks.clientCode; @@ -661,7 +665,7 @@ public class LoginActionsService { if (!ClientSessionModel.Action.VERIFY_EMAIL.name().equals(clientSession.getNote(AuthenticationManager.CURRENT_REQUIRED_ACTION))) { logger.reqdActionDoesNotMatch(); event.error(Errors.INVALID_CODE); - throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE)); + throw new WebApplicationException(ErrorPage.error(session, Messages.STALE_VERIFY_EMAIL_LINK)); } UserSessionModel userSession = clientSession.getUserSession(); diff --git a/themes/src/main/resources/theme/base/login/messages/messages_en.properties b/themes/src/main/resources/theme/base/login/messages/messages_en.properties old mode 100644 new mode 100755 index 0641230e0e..cc3f410e95 --- a/themes/src/main/resources/theme/base/login/messages/messages_en.properties +++ b/themes/src/main/resources/theme/base/login/messages/messages_en.properties @@ -205,6 +205,7 @@ identityProviderLinkSuccess=Your account was successfully linked with {0} accoun realmSupportsNoCredentialsMessage=Realm does not support any credential type. identityProviderNotUniqueMessage=Realm supports multiple identity providers. Could not determine which identity provider should be used to authenticate with. emailVerifiedMessage=Your email address has been verified. +staleEmailVerificationLink=The link you clicked is a old stale link and is no longer valid. Maybe you have already verified your email? locale_ca=Catal\u00E0 locale_de=Deutsch