Don't fail reset credentials action upon first broker login without EXISTING_USER_INFO
(#26324)
The ResetCredentialsActionTokenHandler depends upon the `EXISTING_USER_INFO` through `AbstractIdpAuthenticator.getExistingUser` solely to log the username. However, if the first broker login flow does not include a `IdpCreateUserIfUniqueAuthenticator` or `IdpDetectExistingBrokerUserAuthenticator`, the `EXISTING_USER_INFO` is never set. This commit does not attempt to fetch the existing user if we don't have this info set. Closes #26323 Signed-off-by: Chris Tanaskoski <chris@devristo.com>
This commit is contained in:
parent
02d86d1d8f
commit
5373f3c97a
2 changed files with 71 additions and 2 deletions
|
@ -85,12 +85,19 @@ public class ResetCredentialsActionTokenHandler extends AbstractActionTokenHandl
|
|||
boolean firstBrokerLoginInProgress = (authenticationSession.getAuthNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE) != null);
|
||||
if (firstBrokerLoginInProgress) {
|
||||
|
||||
UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realm, authenticationSession);
|
||||
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
|
||||
authenticationSession.setAuthNote(AbstractIdpAuthenticator.FIRST_BROKER_LOGIN_SUCCESS, serializedCtx.getIdentityProviderId());
|
||||
|
||||
boolean hasExistingUserInfo = (authenticationSession.getAuthNote(AbstractIdpAuthenticator.EXISTING_USER_INFO) != null);
|
||||
String username = "";
|
||||
|
||||
if (hasExistingUserInfo) {
|
||||
UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realm, authenticationSession);
|
||||
username = linkingUser.getUsername();
|
||||
}
|
||||
|
||||
logger.debugf("Forget-password flow finished when authenticated user '%s' after first broker login with identity provider '%s'.",
|
||||
linkingUser.getUsername(), serializedCtx.getIdentityProviderId());
|
||||
username, serializedCtx.getIdentityProviderId());
|
||||
|
||||
return LoginActionsService.redirectToAfterBrokerLoginEndpoint(session, realm, uriInfo, authenticationSession, true);
|
||||
} else {
|
||||
|
|
|
@ -453,6 +453,68 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
assertNumFederatedIdentities(existingUser, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset password during first broker login should work without `AbstractIdpAuthenticator.EXISTING_USER_INFO` set.
|
||||
*
|
||||
* This session note is only set by {@link org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticator}
|
||||
* or {@link org.keycloak.authentication.authenticators.broker.IdpDetectExistingBrokerUserAuthenticator}. However,
|
||||
* the reset password feature should work without them.
|
||||
*
|
||||
* For more info see https://github.com/keycloak/keycloak/issues/26323 .
|
||||
*/
|
||||
@Test
|
||||
public void testResetPasswordDuringFirstBrokerFlowWithoutExistingUserAuthenticator() throws InterruptedException {
|
||||
RealmResource realm = adminClient.realm(bc.consumerRealmName());
|
||||
RealmRepresentation realmRep = realm.toRepresentation();
|
||||
|
||||
realmRep.setResetPasswordAllowed(true);
|
||||
|
||||
realm.update(realmRep);
|
||||
|
||||
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
||||
updateExecutions(AbstractBrokerTest::disableExistingUser);
|
||||
String existingUser = createUser("consumer");
|
||||
|
||||
oauth.clientId("broker-app");
|
||||
loginPage.open(bc.consumerRealmName());
|
||||
|
||||
logInWithBroker(bc);
|
||||
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
Assert.fail("Not expected to see social button with " + bc.getIDPAlias());
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
this.loginPage.clickRegister();
|
||||
Assert.fail("Not expected to see register link");
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
configureSMTPServer();
|
||||
|
||||
this.loginPage.resetPassword();
|
||||
this.loginPasswordResetPage.assertCurrent();
|
||||
this.loginPasswordResetPage.changePassword("consumer");
|
||||
assertEquals("You should receive an email shortly with further instructions.", this.loginPage.getSuccessMessage());
|
||||
assertEquals(1, MailServer.getReceivedMessages().length);
|
||||
MimeMessage message = MailServer.getLastReceivedMessage();
|
||||
String linkFromMail = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL,
|
||||
"credentials", false);
|
||||
|
||||
driver.navigate().to(linkFromMail.trim());
|
||||
|
||||
// Need to update password now
|
||||
this.passwordUpdatePage.assertCurrent();
|
||||
this.passwordUpdatePage.changePassword("password", "password");
|
||||
|
||||
Assert.assertTrue(appPage.isCurrent());
|
||||
assertNumFederatedIdentities(existingUser, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByReauthentication_forgetPassword_differentBrowser
|
||||
|
|
Loading…
Reference in a new issue