Use note to detect the IDP verify email action is already done
Closes #31563 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
90dc7c168c
commit
1d23c3c720
3 changed files with 74 additions and 13 deletions
|
@ -30,7 +30,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserModel.RequiredAction;
|
import org.keycloak.models.UserModel.RequiredAction;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
|
||||||
import org.keycloak.services.managers.AuthenticationSessionManager;
|
import org.keycloak.services.managers.AuthenticationSessionManager;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.sessions.AuthenticationSessionCompoundId;
|
import org.keycloak.sessions.AuthenticationSessionCompoundId;
|
||||||
|
@ -81,17 +80,21 @@ public class IdpVerifyAccountLinkActionTokenHandler extends AbstractActionTokenH
|
||||||
|
|
||||||
AuthenticationSessionModel authSession = tokenContext.getAuthenticationSession();
|
AuthenticationSessionModel authSession = tokenContext.getAuthenticationSession();
|
||||||
|
|
||||||
if (user.isEmailVerified() && !isVerifyEmailActionSet(user, authSession)) {
|
if (authSession.getAuthNote(IdpEmailVerificationAuthenticator.VERIFY_ACCOUNT_IDP_USERNAME) != null) {
|
||||||
event.user(user).error(Errors.EMAIL_ALREADY_VERIFIED);
|
return sendEmailAlreadyVerified(session, event, user);
|
||||||
return session.getProvider(LoginFormsProvider.class)
|
|
||||||
.setAuthenticationSession(session.getContext().getAuthenticationSession())
|
|
||||||
.setInfo(Messages.EMAIL_VERIFIED_ALREADY, user.getEmail())
|
|
||||||
.createInfoPage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event.success();
|
AuthenticationSessionManager asm = new AuthenticationSessionManager(session);
|
||||||
|
|
||||||
if (tokenContext.isAuthenticationSessionFresh()) {
|
if (tokenContext.isAuthenticationSessionFresh()) {
|
||||||
|
AuthenticationSessionCompoundId compoundId = AuthenticationSessionCompoundId.encoded(token.getCompoundAuthenticationSessionId());
|
||||||
|
ClientModel originalClient = realm.getClientById(compoundId.getClientUUID());
|
||||||
|
AuthenticationSessionModel origAuthSession = asm.getAuthenticationSessionByIdAndClient(realm,
|
||||||
|
compoundId.getRootSessionId(), originalClient, compoundId.getTabId());
|
||||||
|
if (origAuthSession == null || origAuthSession.getAuthNote(IdpEmailVerificationAuthenticator.VERIFY_ACCOUNT_IDP_USERNAME) != null) {
|
||||||
|
return sendEmailAlreadyVerified(session, event, user);
|
||||||
|
}
|
||||||
|
|
||||||
token.setOriginalCompoundAuthenticationSessionId(token.getCompoundAuthenticationSessionId());
|
token.setOriginalCompoundAuthenticationSessionId(token.getCompoundAuthenticationSessionId());
|
||||||
|
|
||||||
String authSessionEncodedId = AuthenticationSessionCompoundId.fromAuthSession(authSession).getEncodedId();
|
String authSessionEncodedId = AuthenticationSessionCompoundId.fromAuthSession(authSession).getEncodedId();
|
||||||
|
@ -109,9 +112,9 @@ public class IdpVerifyAccountLinkActionTokenHandler extends AbstractActionTokenH
|
||||||
|
|
||||||
// verify user email as we know it is valid as this entry point would never have gotten here.
|
// verify user email as we know it is valid as this entry point would never have gotten here.
|
||||||
user.setEmailVerified(true);
|
user.setEmailVerified(true);
|
||||||
|
event.success();
|
||||||
|
|
||||||
if (token.getOriginalCompoundAuthenticationSessionId() != null) {
|
if (token.getOriginalCompoundAuthenticationSessionId() != null) {
|
||||||
AuthenticationSessionManager asm = new AuthenticationSessionManager(session);
|
|
||||||
asm.removeAuthenticationSession(realm, authSession, true);
|
asm.removeAuthenticationSession(realm, authSession, true);
|
||||||
|
|
||||||
AuthenticationSessionCompoundId compoundId = AuthenticationSessionCompoundId.encoded(token.getOriginalCompoundAuthenticationSessionId());
|
AuthenticationSessionCompoundId compoundId = AuthenticationSessionCompoundId.encoded(token.getOriginalCompoundAuthenticationSessionId());
|
||||||
|
@ -140,8 +143,11 @@ public class IdpVerifyAccountLinkActionTokenHandler extends AbstractActionTokenH
|
||||||
return tokenContext.brokerFlow(null, null, authSession.getAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH));
|
return tokenContext.brokerFlow(null, null, authSession.getAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isVerifyEmailActionSet(UserModel user, AuthenticationSessionModel authSession) {
|
private Response sendEmailAlreadyVerified(KeycloakSession session, EventBuilder event, UserModel user) {
|
||||||
return Stream.concat(user.getRequiredActionsStream(), authSession.getRequiredActions().stream())
|
event.user(user).error(Errors.EMAIL_ALREADY_VERIFIED);
|
||||||
.anyMatch(RequiredAction.VERIFY_EMAIL.name()::equals);
|
return session.getProvider(LoginFormsProvider.class)
|
||||||
|
.setAuthenticationSession(session.getContext().getAuthenticationSession())
|
||||||
|
.setInfo(Messages.EMAIL_VERIFIED_ALREADY, user.getEmail())
|
||||||
|
.createInfoPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,12 @@ public class IdpLinkEmailPage extends AbstractPage {
|
||||||
@FindBy(id = "instruction1")
|
@FindBy(id = "instruction1")
|
||||||
private WebElement message;
|
private WebElement message;
|
||||||
|
|
||||||
@FindBy(linkText = "Click here")
|
@FindBy(xpath = "//p[@id='instruction2']/a[text() = 'Click here']")
|
||||||
private WebElement resendEmailLink;
|
private WebElement resendEmailLink;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//p[@id='instruction3']/a[text() = 'Click here']")
|
||||||
|
private WebElement continueLink;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCurrent() {
|
public boolean isCurrent() {
|
||||||
return PageUtils.getPageTitle(driver).startsWith("Link ");
|
return PageUtils.getPageTitle(driver).startsWith("Link ");
|
||||||
|
@ -48,4 +51,8 @@ public class IdpLinkEmailPage extends AbstractPage {
|
||||||
public void resendEmail() {
|
public void resendEmail() {
|
||||||
resendEmailLink.click();
|
resendEmailLink.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void continueLink() {
|
||||||
|
continueLink.click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.openqa.selenium.support.PageFactory;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED;
|
import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED;
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.removeUserByUsername;
|
import static org.keycloak.testsuite.admin.ApiUtil.removeUserByUsername;
|
||||||
|
@ -1018,6 +1019,53 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
||||||
waitForPage(driver, "your email address has been verified already.", false);
|
waitForPage(driver, "your email address has been verified already.", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLinkAccountByEmailVerificationInAnotherBrowser() {
|
||||||
|
RealmResource realm = adminClient.realm(bc.consumerRealmName());
|
||||||
|
|
||||||
|
UserResource userResource = realm.users().get(createUser("consumer"));
|
||||||
|
UserRepresentation consumerUser = userResource.toRepresentation();
|
||||||
|
|
||||||
|
consumerUser.setEmail(bc.getUserEmail());
|
||||||
|
consumerUser.setEmailVerified(true);
|
||||||
|
userResource.update(consumerUser);
|
||||||
|
configureSMTPServer();
|
||||||
|
|
||||||
|
oauth.clientId("broker-app");
|
||||||
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
|
||||||
|
logInWithBroker(bc);
|
||||||
|
|
||||||
|
//link account by email
|
||||||
|
waitForPage(driver, "update account information", false);
|
||||||
|
Assert.assertTrue(updateAccountInformationPage.isCurrent());
|
||||||
|
updateAccountInformationPage.updateAccountInformation("FirstName", "LastName");
|
||||||
|
waitForPage(driver, "account already exists", false);
|
||||||
|
assertTrue(idpConfirmLinkPage.isCurrent());
|
||||||
|
assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage());
|
||||||
|
idpConfirmLinkPage.clickLinkAccount();
|
||||||
|
idpLinkEmailPage.assertCurrent();
|
||||||
|
|
||||||
|
String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL,
|
||||||
|
"Someone wants to link your ", false);
|
||||||
|
|
||||||
|
// in the second browser confirm the mail
|
||||||
|
driver2.navigate().to(url);
|
||||||
|
assertThat(driver2.findElement(By.className("instruction")).getText(), startsWith("Confirm linking the account"));
|
||||||
|
driver2.findElement(By.linkText("» Click here to proceed")).click();
|
||||||
|
assertThat(driver2.findElement(By.className("instruction")).getText(), startsWith("You successfully verified your email."));
|
||||||
|
|
||||||
|
idpLinkEmailPage.continueLink();
|
||||||
|
|
||||||
|
//test if user is logged in
|
||||||
|
assertTrue(driver.getCurrentUrl().startsWith(getConsumerRoot() + "/auth/realms/master/app/"));
|
||||||
|
// check user is linked
|
||||||
|
List<FederatedIdentityRepresentation> identities = userResource.getFederatedIdentity();
|
||||||
|
assertEquals(1, identities.size());
|
||||||
|
assertEquals(bc.getIDPAlias(), identities.iterator().next().getIdentityProvider());
|
||||||
|
assertEquals(bc.getUserLogin(), identities.iterator().next().getUserName());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLinkAccountByEmailVerificationToEmailVerifiedUser() {
|
public void testLinkAccountByEmailVerificationToEmailVerifiedUser() {
|
||||||
// set up a user with verified email
|
// set up a user with verified email
|
||||||
|
|
Loading…
Reference in a new issue