Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.keycloak.models.*;
import org.keycloak.protocol.AuthorizationEndpointBase;
import org.keycloak.services.Urls;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.validation.Validation;

import org.keycloak.sessions.AuthenticationSessionCompoundId;
Expand All @@ -48,7 +49,7 @@ public class VerifyEmail implements RequiredActionProvider, RequiredActionFactor
private static final Logger logger = Logger.getLogger(VerifyEmail.class);
@Override
public void evaluateTriggers(RequiredActionContext context) {
if (context.getRealm().isVerifyEmail() && !context.getUser().isEmailVerified()) {
if (context.getRealm().isVerifyEmail() && !context.getUser().isEmailVerified() && !Validation.isBlank(context.getUser().getEmail())) {
context.getUser().addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);
logger.debug("User is required to verify email");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1279,12 +1279,19 @@ else if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) {
authSession.setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, model.getProviderId());
return context.getChallenge();
}
else if (context.getStatus() == RequiredActionContext.Status.IGNORE) {
authSession.getAuthenticatedUser().removeRequiredAction(factory.getId());
authSession.removeRequiredAction(factory.getId());
setKcActionStatus(factory.getId(), RequiredActionContext.KcActionStatus.SUCCESS, authSession);
return nextActionAfterAuthentication(session, authSession, session.getContext().getConnection(), request, session.getContext().getUri(), event);
}
else if (context.getStatus() == RequiredActionContext.Status.SUCCESS) {
event.clone().event(EventType.CUSTOM_REQUIRED_ACTION).detail(Details.CUSTOM_REQUIRED_ACTION, factory.getId()).success();
// don't have to perform the same action twice, so remove it from both the user and session required actions
authSession.getAuthenticatedUser().removeRequiredAction(factory.getId());
authSession.removeRequiredAction(factory.getId());
setKcActionStatus(factory.getId(), RequiredActionContext.KcActionStatus.SUCCESS, authSession);
return AuthenticationManager.nextActionAfterAuthentication(session, authSession, session.getContext().getConnection(), request, session.getContext().getUri(), event);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.messages.Messages;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.admin.ApiUtil;
Expand All @@ -46,6 +47,7 @@
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
import org.keycloak.testsuite.pages.TermsAndConditionsPage;
import org.keycloak.testsuite.pages.VerifyEmailPage;
import org.keycloak.testsuite.pages.VerifyProfilePage;
import org.keycloak.testsuite.util.GreenMailRule;
import org.keycloak.testsuite.util.OAuthClient;
Expand Down Expand Up @@ -88,6 +90,9 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
@Page
protected VerifyProfilePage verifyProfilePage;

@Page
protected VerifyEmailPage verifyEmailPage;

@Page
protected TermsAndConditionsPage termsPage;

Expand Down Expand Up @@ -416,6 +421,85 @@ public void setupTotpAfterUpdatePassword() {

}

@Test
public void skipRequiredActionsWithCustomPriority() {
enableRequiredActionForUser(RequiredAction.VERIFY_EMAIL);
enableRequiredActionForUser(RequiredAction.UPDATE_PASSWORD);

RealmRepresentation realmRep = testRealm().toRepresentation();
realmRep.setVerifyEmail(true);
testRealm().update(realmRep);

final var requiredActionsCustomOrdered = List.of(
RequiredAction.VERIFY_EMAIL,
RequiredAction.UPDATE_PASSWORD
);
ApiUtil.updateRequiredActionsOrder(testRealm(), requiredActionsCustomOrdered);

final var userResource = testRealm().users().get(testUserId);
final var user = userResource.toRepresentation();
user.setEmail("");
userResource.update(user);

// Login
loginPage.open();
loginPage.login(USERNAME, PASSWORD);

// change password
changePasswordPage.assertCurrent();
changePasswordPage.changePassword(NEW_PASSWORD, NEW_PASSWORD);
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();

// Second, complete the profile
verifyProfilePage.assertCurrent();
events.expectRequiredAction(EventType.VERIFY_PROFILE)
.user(testUserId)
.detail(Details.FIELDS_TO_UPDATE, UserModel.EMAIL)
.assertEvent();

verifyProfilePage.updateEmail(EMAIL, NEW_FIRST_NAME, NEW_LAST_NAME);
events.expectRequiredAction(EventType.UPDATE_PROFILE)
.user(testUserId)
.assertEvent();

verifyEmailPage.assertCurrent();
}

@Test
public void skipToNextRequiredActionWithCustomPriority() {
enableRequiredActionForUser(RequiredAction.VERIFY_EMAIL);
enableRequiredActionForUser(RequiredAction.UPDATE_PASSWORD);

RealmRepresentation realmRep = testRealm().toRepresentation();
realmRep.setVerifyEmail(true);
testRealm().update(realmRep);

final var userResource = testRealm().users().get(testUserId);
final var user = userResource.toRepresentation();
user.setEmailVerified(true);
userResource.update(user);

final var requiredActionsCustomOrdered = List.of(
RequiredAction.VERIFY_EMAIL,
RequiredAction.UPDATE_PASSWORD
);
ApiUtil.updateRequiredActionsOrder(testRealm(), requiredActionsCustomOrdered);

// Login
loginPage.open();
loginPage.login(USERNAME, PASSWORD);
events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION).assertEvent();

// change password
changePasswordPage.assertCurrent();
changePasswordPage.changePassword(NEW_PASSWORD, NEW_PASSWORD);
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();

appPage.assertCurrent();
assertThat(appPage.getRequestType(), is(RequestType.AUTH_RESPONSE));
events.expectLogin().assertEvent();
}

private void enableRequiredActionForUser(final RequiredAction requiredAction) {
setRequiredActionEnabled(TEST_REALM_NAME, testUserId, requiredAction.name(), true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
@Drone
@SecondBrowser
protected WebDriver driver2;

@Rule
public AssertEvents events = new AssertEvents(this);

Expand Down Expand Up @@ -1146,7 +1146,7 @@ public void testVerifyEmailInNewBrowserWithPreserveClient() {
//test if the user has verified email
assertTrue(consumerRealm.users().get(linkedUserId).toRepresentation().isEmailVerified());
}

@Test
public void testEventsOnUpdateProfileNoEmailChange() {
updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin);
Expand All @@ -1165,7 +1165,7 @@ public void testEventsOnUpdateProfileNoEmailChange() {
loginPage.login("no-first-name", "password");

waitForPage(driver, "update account information", false);

updateAccountInformationPage.assertCurrent();
updateAccountInformationPage.updateAccountInformation("FirstName", "LastName");

Expand Down Expand Up @@ -1219,7 +1219,7 @@ public void testEventsOnUpdateProfileWithEmailChange() {
loginPage.login("no-first-name", "password");

waitForPage(driver, "update account information", false);

updateAccountInformationPage.assertCurrent();
updateAccountInformationPage.updateAccountInformation("[email protected]","FirstName", "LastName");

Expand Down Expand Up @@ -1294,7 +1294,7 @@ public void testUpdateProfileIfMissingInformation() {
loginPage.login("no-first-name", "password");

waitForPage(driver, "update account information", false);

updateAccountInformationPage.assertCurrent();
updateAccountInformationPage.updateAccountInformation("FirstName", "LastName");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT

private static String userId2;

private static String defaultUserId;

private static String userIdMultipleOTPs;

private final TimeBasedOTP totp = new TimeBasedOTP();
Expand Down Expand Up @@ -164,6 +166,7 @@ public void importTestRealms() {
userIdMultipleOTPs = adminClient.realm("test").users().search("direct-login-multiple-otps", true).get(0).getId();
userId = adminClient.realm("test").users().search("direct-login", true).get(0).getId();
userId2 = adminClient.realm("test").users().search("direct-login-otp", true).get(0).getId();
defaultUserId = adminClient.realm("test").users().search("test-user@localhost", true).get(0).getId();
}

@Test
Expand Down Expand Up @@ -310,6 +313,10 @@ private void grantAccessToken(String login, String clientId) throws Exception {
grantAccessToken(userId, login, clientId, null);
}

private void grantAccessToken(String userId, String login, String clientId) throws Exception {
grantAccessToken(userId, login, clientId, null);
}

private void grantAccessToken(String userId, String login, String clientId, String otp) throws Exception {
oauth.clientId(clientId);

Expand Down Expand Up @@ -532,28 +539,15 @@ public void grantAccessTokenVerifyEmail() throws Exception {

oauth.clientId("resource-owner");

OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password");

assertEquals(400, response.getStatusCode());

assertEquals("invalid_grant", response.getError());
assertEquals("Account is not fully set up", response.getErrorDescription());

events.expectLogin()
.client("resource-owner")
.session((String) null)
.clearDetails()
.error(Errors.RESOLVE_REQUIRED_ACTIONS)
.user((String) null)
.assertEvent();
grantAccessToken(defaultUserId, "test-user@localhost", "resource-owner");

RealmManager.realm(realmResource).verifyEmail(false);
UserManager.realm(realmResource).username("test-user@localhost").removeRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL.toString());

// Check that count of authSessions is same as before authentication (as authentication session was removed)
Assert.assertEquals(authSessionsBefore, getAuthenticationSessionsCount());
}

@Test
public void grantAccessTokenVerifyEmailInvalidPassword() throws Exception {

Expand Down Expand Up @@ -617,7 +611,7 @@ public void grantAccessTokenExpiredPassword() throws Exception {
.removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString());
}
}

@Test
public void grantAccessTokenExpiredPasswordInvalidPassword() throws Exception {

Expand Down