Handle reset password flow with logged in user
Closes #8887 Signed-off-by: Giuseppe Graziano <g.graziano94@gmail.com>
This commit is contained in:
parent
00bd6224fa
commit
c6d3e56cda
4 changed files with 52 additions and 7 deletions
|
@ -71,6 +71,10 @@ public class AuthenticatorUtil {
|
|||
return "true".equals(authSession.getAuthNote(PASSWORD_VALIDATED));
|
||||
}
|
||||
|
||||
public static boolean isForkedFlow(AuthenticationSessionModel authSession) {
|
||||
return authSession.getAuthNote(AuthenticationProcessor.FORKED_FROM) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authentication session note for callbacks defined for {@link AuthenticationFlowCallbackFactory) factories
|
||||
*
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.authentication.authenticators.browser;
|
|||
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.AuthenticatorUtil;
|
||||
import org.keycloak.authentication.authenticators.util.AcrStore;
|
||||
import org.keycloak.authentication.authenticators.util.AuthenticatorUtils;
|
||||
import org.keycloak.models.Constants;
|
||||
|
@ -61,6 +62,8 @@ public class CookieAuthenticator implements Authenticator {
|
|||
authSession.setAuthNote(AuthenticationManager.FORCED_REAUTHENTICATION, "true");
|
||||
context.setForwardedInfoMessage(Messages.REAUTHENTICATE);
|
||||
context.attempted();
|
||||
} else if(AuthenticatorUtil.isForkedFlow(authSession)){
|
||||
context.attempted();
|
||||
} else {
|
||||
int previouslyAuthenticatedLevel = acrStore.getHighestAuthenticatedLevelFromPreviousAuthentication();
|
||||
AuthenticatorUtils.updateCompletedExecutions(context.getAuthenticationSession(), authResult.getSession(), context.getExecution().getId());
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.FormMessage;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.validation.Validation;
|
||||
|
||||
|
@ -75,6 +76,15 @@ public class ResetCredentialChooseUser implements Authenticator, AuthenticatorFa
|
|||
return;
|
||||
}
|
||||
|
||||
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(context.getSession(), context.getRealm(), true);
|
||||
//skip user choice if sso session exists
|
||||
if (authResult != null) {
|
||||
context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, authResult.getUser().getUsername());
|
||||
context.setUser(authResult.getUser());
|
||||
context.success();
|
||||
return;
|
||||
}
|
||||
|
||||
Response challenge = context.form().createPasswordReset();
|
||||
context.challenge(challenge);
|
||||
}
|
||||
|
|
|
@ -160,7 +160,30 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
String username = "login-test";
|
||||
String resetUri = oauth.AUTH_SERVER_ROOT + "/realms/test/login-actions/reset-credentials";
|
||||
|
||||
openResetPasswordUrlAndDoFlow(resetUri, "account", oauth.AUTH_SERVER_ROOT + "/realms/test/account/");
|
||||
openResetPasswordUrlAndDoFlow(resetUri, "account", oauth.AUTH_SERVER_ROOT + "/realms/test/account/", false);
|
||||
|
||||
AccountHelper.logout(testRealm(), username);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
|
||||
TestAppHelper testAppHelper = new TestAppHelper(oauth, loginPage, appPage);
|
||||
testAppHelper.login(username, "resetPassword");
|
||||
|
||||
appPage.assertCurrent();
|
||||
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetPasswordLoggedUser() throws IOException {
|
||||
String username = "login-test";
|
||||
loginPage.open();
|
||||
loginPage.login(username, "password");
|
||||
|
||||
events.expectLogin().user(userId).detail(Details.USERNAME, username).assertEvent();
|
||||
|
||||
String resetUri = oauth.AUTH_SERVER_ROOT + "/realms/test/login-actions/reset-credentials";
|
||||
|
||||
openResetPasswordUrlAndDoFlow(resetUri, "account", oauth.AUTH_SERVER_ROOT + "/realms/test/account/", true);
|
||||
|
||||
AccountHelper.logout(testRealm(), username);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
|
@ -174,13 +197,14 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
|
||||
// Starts by opening "reset-password-url". Then go through the successful reset-password flow for the particular user. After user confirms new password, this method ends.
|
||||
private void openResetPasswordUrlAndDoFlow(String resetUri, String expectedClientId, String expectedRedirectUri) throws IOException {
|
||||
private void openResetPasswordUrlAndDoFlow(String resetUri, String expectedClientId, String expectedRedirectUri, boolean userAuthenticated) throws IOException {
|
||||
String username = "login-test";
|
||||
driver.navigate().to(resetUri);
|
||||
|
||||
if (!userAuthenticated) {
|
||||
resetPasswordPage.assertCurrent();
|
||||
|
||||
resetPasswordPage.changePassword(username);
|
||||
}
|
||||
|
||||
loginPage.assertCurrent();
|
||||
assertEquals("You should receive an email shortly with further instructions.", loginPage.getSuccessMessage());
|
||||
|
@ -208,6 +232,10 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
updatePasswordPage.assertCurrent();
|
||||
|
||||
if(userAuthenticated) {
|
||||
updatePasswordPage.uncheckLogoutSessions();
|
||||
}
|
||||
|
||||
updatePasswordPage.changePassword("resetPassword", "resetPassword");
|
||||
|
||||
event = events.expectRequiredAction(EventType.UPDATE_PASSWORD)
|
||||
|
@ -225,7 +253,7 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
public void resetPasswordLinkTestAppWithoutRedirectUriParam() throws IOException {
|
||||
String resetUri = oauth.AUTH_SERVER_ROOT + "/realms/test/login-actions/reset-credentials?client_id=test-app";
|
||||
|
||||
openResetPasswordUrlAndDoFlow(resetUri, "test-app", null);
|
||||
openResetPasswordUrlAndDoFlow(resetUri, "test-app", null, false);
|
||||
|
||||
// Link "Back to application" with the baseUrl of client "test-app"
|
||||
infoPage.assertCurrent();
|
||||
|
@ -240,7 +268,7 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
public void resetPasswordLinkTestAppWithRedirectUriParam() throws IOException {
|
||||
String resetUri = oauth.AUTH_SERVER_ROOT + "/realms/test/login-actions/reset-credentials?client_id=test-app&redirect_uri=" + oauth.getRedirectUri();
|
||||
|
||||
openResetPasswordUrlAndDoFlow(resetUri, "test-app", oauth.getRedirectUri());
|
||||
openResetPasswordUrlAndDoFlow(resetUri, "test-app", oauth.getRedirectUri(), false);
|
||||
|
||||
// Should be directly redirected to "application because of "redirect_uri" parameter
|
||||
appPage.assertCurrent();
|
||||
|
|
Loading…
Reference in a new issue