Update per feedback review

Signed-off-by: mposolda <mposolda@gmail.com>
This commit is contained in:
mposolda
2025-07-18 13:36:51 +02:00
committed by Bruno Oliveira da Silva
parent bba869b3d5
commit 57972d85d3
10 changed files with 106 additions and 33 deletions

View File

@@ -307,6 +307,10 @@ public class PasskeysOrganizationAuthenticationTest extends AbstractWebAuthnVirt
.open();
WaitUtils.waitForPageToLoad();
loginPage.assertCurrent();
MatcherAssert.assertThat(loginPage.isPasswordInputPresent(), Matchers.is(true));
MatcherAssert.assertThat(driver.findElement(By.xpath("//form[@id='webauth']")), Matchers.notNullValue());
webAuthnLoginPage.clickAuthenticate();
appPage.assertCurrent();
events.expectLogin()

View File

@@ -42,6 +42,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.AbstractAdminTest;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.arquillian.annotation.IgnoreBrowserDriver;
import org.keycloak.testsuite.util.WaitUtils;
@@ -51,6 +52,9 @@ import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.firefox.FirefoxDriver;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
/**
*
* @author rmartinc
@@ -66,6 +70,7 @@ public class PasskeysUsernameFormTest extends AbstractWebAuthnVirtualTest {
makePasswordlessRequiredActionDefault(realmRepresentation);
switchExecutionInBrowser(realmRepresentation);
configureTestRealm(realmRepresentation);
testRealms.add(realmRepresentation);
}
@@ -198,8 +203,10 @@ public class PasskeysUsernameFormTest extends AbstractWebAuthnVirtualTest {
// login OK now
loginPage.loginUsername(USERNAME);
loginPage.assertCurrent();
// Passkeys available on password-form as well. Allows to login only with the passkey of current user
MatcherAssert.assertThat(loginPage.getAttemptedUsername(), Matchers.is(USERNAME));
Assert.assertThrows(NoSuchElementException.class, () -> driver.findElement(By.xpath("//form[@id='webauth']")));
MatcherAssert.assertThat(loginPage.isPasswordInputPresent(), Matchers.is(true));
MatcherAssert.assertThat(driver.findElement(By.xpath("//form[@id='webauth']")), Matchers.notNullValue());
loginPage.login(getPassword(USERNAME));
appPage.assertCurrent();
events.expectLogin()
@@ -307,6 +314,11 @@ public class PasskeysUsernameFormTest extends AbstractWebAuthnVirtualTest {
.open();
WaitUtils.waitForPageToLoad();
loginPage.assertCurrent();
MatcherAssert.assertThat(loginPage.isPasswordInputPresent(), Matchers.is(true));
MatcherAssert.assertThat(driver.findElement(By.xpath("//form[@id='webauth']")), Matchers.notNullValue());
webAuthnLoginPage.clickAuthenticate();
appPage.assertCurrent();
events.expectLogin()
@@ -319,4 +331,67 @@ public class PasskeysUsernameFormTest extends AbstractWebAuthnVirtualTest {
logout();
}
}
@Test
public void passwordLogin_reauthenticationOfUserWithoutPasskey() throws Exception {
// use a default resident key which is not shown in conditional UI
getVirtualAuthManager().useAuthenticator(DefaultVirtualAuthOptions.DEFAULT_RESIDENT_KEY.getOptions());
// set passwordless policy for discoverable keys
try (Closeable c = getWebAuthnRealmUpdater()
.setWebAuthnPolicyRpEntityName("localhost")
.setWebAuthnPolicyRequireResidentKey(Constants.WEBAUTHN_POLICY_OPTION_YES)
.setWebAuthnPolicyUserVerificationRequirement(Constants.WEBAUTHN_POLICY_OPTION_REQUIRED)
.setWebAuthnPolicyPasskeysEnabled(Boolean.TRUE)
.update()) {
// Login with password
oauth.openLoginForm();
WaitUtils.waitForPageToLoad();
// WebAuthn elements available, user is not yet known. Password not available as on username-form
loginPage.assertCurrent();
MatcherAssert.assertThat(loginPage.isPasswordInputPresent(), Matchers.is(false));
MatcherAssert.assertThat(driver.findElement(By.xpath("//form[@id='webauth']")), Matchers.notNullValue());
// Login with password. WebAuthn elements not available on password screen as user does not have passkeys
loginPage.loginUsername("test-user@localhost");
Assert.assertThrows(NoSuchElementException.class, () -> driver.findElement(By.xpath("//form[@id='webauth']")));
loginPage.login(getPassword("test-user@localhost"));
appPage.assertCurrent();
events.clear();
// Re-authentication now with prompt=login. Passkeys login should not be available on the page as this user does not have passkey
oauth.loginForm()
.prompt(OIDCLoginProtocol.PROMPT_VALUE_LOGIN)
.open();
WaitUtils.waitForPageToLoad();
loginPage.assertCurrent();
assertEquals("Please re-authenticate to continue", loginPage.getInfoMessage());
Assert.assertThrows(NoSuchElementException.class, () -> driver.findElement(By.xpath("//form[@id='webauth']")));
// Incorrect password (password of different user)
loginPage.login(getPassword("john-doh@localhost"));
MatcherAssert.assertThat(loginPage.getPasswordInputError(), Matchers.is("Invalid password."));
events.clear();
// Login with password
loginPage.login(getPassword("test-user@localhost"));
appPage.assertCurrent();
UserRepresentation testUser = ApiUtil.findUserByUsernameId(testRealm(), "test-user@localhost").toRepresentation();
events.expectLogin()
.user(testUser.getId())
.detail(Details.USERNAME, testUser.getUsername())
.detail(WebAuthnConstants.USER_VERIFICATION_CHECKED, nullValue())
.assertEvent();
logout();
}
}
}

View File

@@ -46,6 +46,7 @@ import org.keycloak.testsuite.util.WaitUtils;
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.firefox.FirefoxDriver;
import static org.hamcrest.Matchers.nullValue;
@@ -288,12 +289,7 @@ public class PasskeysUsernamePasswordFormTest extends AbstractWebAuthnVirtualTes
// WebAuthn elements not available
loginPage.assertCurrent();
try {
MatcherAssert.assertThat(driver.findElement(By.xpath("//form[@id='webauth']")), nullValue());
fail("Not expected to have webauthn button");
} catch (Exception nsee) {
// expected
}
Assert.assertThrows(NoSuchElementException.class, () -> driver.findElement(By.xpath("//form[@id='webauth']")));
// Login with password
loginPage.login("test-user@localhost", getPassword("test-user@localhost"));
@@ -309,12 +305,7 @@ public class PasskeysUsernamePasswordFormTest extends AbstractWebAuthnVirtualTes
loginPage.assertCurrent();
assertEquals("Please re-authenticate to continue", loginPage.getInfoMessage());
try {
MatcherAssert.assertThat(driver.findElement(By.xpath("//form[@id='webauth']")), nullValue());
fail("Not expected to have webauthn button");
} catch (Exception nsee) {
// expected
}
Assert.assertThrows(NoSuchElementException.class, () -> driver.findElement(By.xpath("//form[@id='webauth']")));
// Login with password
loginPage.login(getPassword("test-user@localhost"));