diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/model/TotpBean.java b/services/src/main/java/org/keycloak/forms/login/freemarker/model/TotpBean.java index d712a134b7..6bf687386d 100755 --- a/services/src/main/java/org/keycloak/forms/login/freemarker/model/TotpBean.java +++ b/services/src/main/java/org/keycloak/forms/login/freemarker/model/TotpBean.java @@ -77,7 +77,8 @@ public class TotpBean { } public String getManualUrl() { - return uriBuilder.replaceQueryParam("session_code").replaceQueryParam("mode", "manual").build().toString(); + return uriBuilder.replaceQueryParam("session_code").replaceQueryParam("mode", "manual") + .replaceQueryParam("execution", UserModel.RequiredAction.CONFIGURE_TOTP.name()).build().toString(); } public String getQrUrl() { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionPriorityTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionPriorityTest.java index fe8935cfe3..53bb5e3d89 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionPriorityTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionPriorityTest.java @@ -26,6 +26,7 @@ import org.keycloak.events.Details; import org.keycloak.events.EventType; import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.RequiredAction; +import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; @@ -35,12 +36,18 @@ import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.pages.AppPage.RequestType; +import org.keycloak.testsuite.pages.LoginConfigTotpPage; import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; import org.keycloak.testsuite.pages.LoginUpdateProfileEditUsernameAllowedPage; import org.keycloak.testsuite.pages.TermsAndConditionsPage; import org.keycloak.testsuite.util.UserBuilder; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + /** * @author Hiroyuki Wada */ @@ -69,6 +76,9 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest { @Page protected TermsAndConditionsPage termsPage; + @Page + protected LoginConfigTotpPage totpPage; + @Before public void setupRequiredActions() { setRequiredActionEnabled("test", TermsAndConditions.PROVIDER_ID, true, false); @@ -158,4 +168,45 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest { Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); events.expectLogin().assertEvent(); } + + @Test + public void setupTotpAfterUpdatePassword() { + String testUserId = ApiUtil.findUserByUsername(testRealm(), "test-user@localhost").getId(); + + setRequiredActionEnabled("test", testUserId, RequiredAction.CONFIGURE_TOTP.name(), true); + setRequiredActionEnabled("test", testUserId, RequiredAction.UPDATE_PASSWORD.name(), true); + setRequiredActionEnabled("test", testUserId, TermsAndConditions.PROVIDER_ID, false); + setRequiredActionEnabled("test", testUserId, RequiredAction.UPDATE_PROFILE.name(), false); + + // make UPDATE_PASSWORD on top + testRealm().flows().raiseRequiredActionPriority(UserModel.RequiredAction.UPDATE_PASSWORD.name()); + testRealm().flows().raiseRequiredActionPriority(UserModel.RequiredAction.UPDATE_PASSWORD.name()); + + // Login + loginPage.open(); + loginPage.login("test-user@localhost", "password"); + + // change password + changePasswordPage.assertCurrent(); + changePasswordPage.changePassword("new-password", "new-password"); + events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent(); + + // CONFIGURE_TOTP + totpPage.assertCurrent(); + + totpPage.clickManual(); + String pageSource = driver.getPageSource(); + assertThat(pageSource, not(containsString("Unable to scan?"))); + assertThat(pageSource, containsString("Scan barcode?")); + + TimeBasedOTP totp = new TimeBasedOTP(); + totpPage.configure(totp.generateTOTP(totpPage.getTotpSecret()), "userLabel"); + events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent(); + + // Logined + appPage.assertCurrent(); + assertThat(appPage.getRequestType(), is(RequestType.AUTH_RESPONSE)); + events.expectLogin().assertEvent(); + + } }