diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f88b6ab4eb..a8f602ba06 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -502,6 +502,43 @@ jobs: with: job-name: Account Console IT + webauthn-integration-tests: + name: WebAuthn IT + runs-on: ubuntu-latest + needs: build + timeout-minutes: 30 + strategy: + matrix: + browser: [firefox] # Chrome not working for now + fail-fast: false + steps: + - uses: actions/checkout@v3 + + - name: Setup firefox + uses: browser-actions/setup-firefox@latest + with: + firefox-version: latest + - run: firefox --version + + - id: integration-test-setup + name: Integration test setup + uses: ./.github/actions/integration-test-setup + + - name: Run WebAuthn IT + run: ./mvnw test -Dsurefire.rerunFailingTestsCount=${{ env.SUREFIRE_RERUN_FAILING_COUNT }} -nsu -B -Pauth-server-quarkus -Dtest=org.keycloak.testsuite.webauthn.**.*Test -Dbrowser=${{ matrix.browser }} -Pwebauthn -f testsuite/integration-arquillian/tests/other/pom.xml | misc/log/trimmer.sh + + - name: Upload JVM Heapdumps + if: always() + uses: ./.github/actions/upload-heapdumps + + - uses: ./.github/actions/upload-flaky-tests + name: Upload flaky tests + env: + GH_TOKEN: ${{ github.token }} + with: + job-name: WebAuthn IT + + check-set-status: name: Set check conclusion needs: @@ -516,6 +553,7 @@ jobs: - fips-unit-tests - fips-integration-tests - account-console-integration-tests + - webauthn-integration-tests runs-on: ubuntu-latest outputs: conclusion: ${{ steps.check.outputs.conclusion }} diff --git a/testsuite/integration-arquillian/tests/other/webauthn/src/main/java/org/keycloak/testsuite/webauthn/pages/WebAuthnPolicyPage.java b/testsuite/integration-arquillian/tests/other/webauthn/src/main/java/org/keycloak/testsuite/webauthn/pages/WebAuthnPolicyPage.java index a43ac49d76..a4832be2fe 100644 --- a/testsuite/integration-arquillian/tests/other/webauthn/src/main/java/org/keycloak/testsuite/webauthn/pages/WebAuthnPolicyPage.java +++ b/testsuite/integration-arquillian/tests/other/webauthn/src/main/java/org/keycloak/testsuite/webauthn/pages/WebAuthnPolicyPage.java @@ -21,9 +21,7 @@ import com.webauthn4j.data.AttestationConveyancePreference; import com.webauthn4j.data.AuthenticatorAttachment; import com.webauthn4j.data.UserVerificationRequirement; import org.jboss.arquillian.graphene.page.Page; -import org.keycloak.testsuite.console.page.authentication.Authentication; import org.keycloak.testsuite.console.page.fragment.OnOffSwitch; -import org.keycloak.testsuite.console.page.idp.mappers.MultivaluedStringProperty; import org.keycloak.testsuite.webauthn.utils.PropertyRequirement; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; @@ -44,7 +42,7 @@ import static org.keycloak.utils.StringUtil.isNotBlank; * * @author Martin Bartos */ -public class WebAuthnPolicyPage extends Authentication { +public class WebAuthnPolicyPage { @FindBy(id = "name") private WebElement rpEntityName; @@ -73,24 +71,12 @@ public class WebAuthnPolicyPage extends Authentication { @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='avoidsame']]") private OnOffSwitch avoidSameAuthenticatorRegister; - @Page - private MultivaluedAcceptableAaguid acceptableAaguid; - @FindBy(xpath = "//button[text()='Save']") private WebElement saveButton; @FindBy(xpath = "//button[text()='Cancel']") private WebElement cancelButton; - @Override - public String getUriFragment() { - return getAuthenticationUriFragment() + "/webauthn-policy"; - } - - public String getAuthenticationUriFragment() { - return super.getUriFragment(); - } - /* Relaying Party Entity Name */ public String getRpEntityName() { @@ -212,10 +198,6 @@ public class WebAuthnPolicyPage extends Authentication { } } - public MultivaluedAcceptableAaguid getAcceptableAaguid() { - return acceptableAaguid; - } - /* Buttons */ public void clickSaveButton() { waitUntilElement(checkElement(() -> saveButton)).is().clickable(); @@ -256,40 +238,4 @@ public class WebAuthnPolicyPage extends Authentication { return null; } } - - public class MultivaluedAcceptableAaguid extends MultivaluedStringProperty { - - @FindBy(className = "webauthn-acceptable-aaguid") - private List aaguids; - - @FindBy(id = "newAcceptableAaguid") - private WebElement newAaguid; - - @FindBy(xpath = "//button[@data-ng-click='deleteAcceptableAaguid($index)']") - private List minusButtons; - - @FindBy(xpath = "//button[@data-ng-click='newAcceptableAaguid.length > 0 && addAcceptableAaguid()']") - private WebElement plusButton; - - @Override - public List getItems() { - return checkElement(() -> aaguids); - } - - @Override - public void addItem(String item) { - setTextInputValue(checkElement(() -> newAaguid), item); - clickAddItem(); - } - - @Override - protected List getMinusButtons() { - return minusButtons; - } - - @Override - protected WebElement getPlusButton() { - return plusButton; - } - } } diff --git a/testsuite/integration-arquillian/tests/other/webauthn/src/main/java/org/keycloak/testsuite/webauthn/pages/WebAuthnPolicyPasswordlessPage.java b/testsuite/integration-arquillian/tests/other/webauthn/src/main/java/org/keycloak/testsuite/webauthn/pages/WebAuthnPolicyPasswordlessPage.java deleted file mode 100644 index 2cc54f487f..0000000000 --- a/testsuite/integration-arquillian/tests/other/webauthn/src/main/java/org/keycloak/testsuite/webauthn/pages/WebAuthnPolicyPasswordlessPage.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2021 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.webauthn.pages; - -/** - * Helper class for WebAuthnPolicy Passwordless Page - * - * @author Martin Bartos - */ -public class WebAuthnPolicyPasswordlessPage extends WebAuthnPolicyPage { - - @Override - public String getUriFragment() { - return super.getAuthenticationUriFragment() + "/webauthn-policy-passwordless"; - } -} diff --git a/testsuite/integration-arquillian/tests/other/webauthn/src/test/java/org/keycloak/testsuite/webauthn/admin/PwdLessPolicySettingsTest.java b/testsuite/integration-arquillian/tests/other/webauthn/src/test/java/org/keycloak/testsuite/webauthn/admin/PwdLessPolicySettingsTest.java deleted file mode 100644 index b3dc2a5340..0000000000 --- a/testsuite/integration-arquillian/tests/other/webauthn/src/test/java/org/keycloak/testsuite/webauthn/admin/PwdLessPolicySettingsTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.webauthn.admin; - -/** - * @author Martin Bartos - */ -public class PwdLessPolicySettingsTest extends WebAuthnPolicySettingsTest { - - @Override - protected boolean isPasswordless() { - return true; - } -} diff --git a/testsuite/integration-arquillian/tests/other/webauthn/src/test/java/org/keycloak/testsuite/webauthn/admin/WebAuthnPolicySettingsTest.java b/testsuite/integration-arquillian/tests/other/webauthn/src/test/java/org/keycloak/testsuite/webauthn/admin/WebAuthnPolicySettingsTest.java deleted file mode 100644 index 70616f13cb..0000000000 --- a/testsuite/integration-arquillian/tests/other/webauthn/src/test/java/org/keycloak/testsuite/webauthn/admin/WebAuthnPolicySettingsTest.java +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright 2021 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.webauthn.admin; - -import com.webauthn4j.data.AttestationConveyancePreference; -import com.webauthn4j.data.AuthenticatorAttachment; -import com.webauthn4j.data.UserVerificationRequirement; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.models.Constants; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.testsuite.AssertEvents; -import org.keycloak.testsuite.console.AbstractConsoleTest; -import org.keycloak.testsuite.page.AbstractPatternFlyAlert; -import org.keycloak.testsuite.updaters.RealmAttributeUpdater; -import org.keycloak.testsuite.util.UIUtils; -import org.keycloak.testsuite.webauthn.pages.WebAuthnPolicyPage; -import org.keycloak.testsuite.webauthn.pages.WebAuthnPolicyPasswordlessPage; -import org.keycloak.testsuite.webauthn.updaters.AbstractWebAuthnRealmUpdater; -import org.keycloak.testsuite.webauthn.updaters.PasswordLessRealmAttributeUpdater; -import org.keycloak.testsuite.webauthn.updaters.WebAuthnRealmAttributeUpdater; -import org.keycloak.testsuite.webauthn.utils.PropertyRequirement; -import org.keycloak.testsuite.webauthn.utils.WebAuthnRealmData; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.Select; - -import java.io.Closeable; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static com.webauthn4j.data.AttestationConveyancePreference.INDIRECT; -import static com.webauthn4j.data.AuthenticatorAttachment.CROSS_PLATFORM; -import static com.webauthn4j.data.UserVerificationRequirement.PREFERRED; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.hasItems; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasSize; -import static org.keycloak.models.Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED; -import static org.keycloak.testsuite.util.WaitUtils.pause; -import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad; -import static org.keycloak.testsuite.webauthn.utils.PropertyRequirement.NO; -import static org.keycloak.testsuite.webauthn.utils.PropertyRequirement.YES; - -/** - * @author Martin Bartos - */ -public class WebAuthnPolicySettingsTest extends AbstractConsoleTest { - - protected static final String ALL_ZERO_AAGUID = "00000000-0000-0000-0000-000000000000"; - protected static final String ALL_ONE_AAGUID = "11111111-1111-1111-1111-111111111111"; - - @Rule - public AssertEvents events = new AssertEvents(this); - - @Page - WebAuthnPolicyPage webAuthnPolicyPage; - - @Page - WebAuthnPolicyPasswordlessPage webAuthnPolicyPasswordlessPage; - - @Before - public void navigateToPolicy() { - driver.manage().window().maximize(); - getPolicyPage().navigateTo(); - waitForPageToLoad(); - getPolicyPage().assertCurrent(); - } - - protected boolean isPasswordless() { - return false; - } - - protected WebAuthnPolicyPage getPolicyPage() { - return isPasswordless() ? webAuthnPolicyPasswordlessPage : webAuthnPolicyPage; - } - - protected AbstractWebAuthnRealmUpdater getWebAuthnRealmUpdater() { - return isPasswordless() ? new PasswordLessRealmAttributeUpdater(testRealmResource()) : new WebAuthnRealmAttributeUpdater(testRealmResource()); - } - - protected AbstractWebAuthnRealmUpdater updateWebAuthnPolicy( - String rpName, - List algorithms, - String attestationPreference, - String authenticatorAttachment, - String requireResidentKey, - String rpId, - String userVerification, - List acceptableAaguids) { - - AbstractWebAuthnRealmUpdater updater = getWebAuthnRealmUpdater().setWebAuthnPolicyRpEntityName(rpName); - - checkAndSet(algorithms, updater::setWebAuthnPolicySignatureAlgorithms); - checkAndSet(attestationPreference, updater::setWebAuthnPolicyAttestationConveyancePreference); - checkAndSet(authenticatorAttachment, updater::setWebAuthnPolicyAuthenticatorAttachment); - checkAndSet(requireResidentKey, updater::setWebAuthnPolicyRequireResidentKey); - checkAndSet(rpId, updater::setWebAuthnPolicyRpId); - checkAndSet(userVerification, updater::setWebAuthnPolicyUserVerificationRequirement); - checkAndSet(acceptableAaguids, updater::setWebAuthnPolicyAcceptableAaguids); - - return updater.update(); - } - - private void checkAndSet(T value, Consumer consumer) { - if (value != null) { - consumer.accept(value); - } - } - - @Test - public void policySettingsWithExternalProperties() throws IOException { - try (RealmAttributeUpdater rau = updateWebAuthnPolicy( - "rpName", - Collections.singletonList("ES256"), - INDIRECT.getValue(), - CROSS_PLATFORM.getValue(), - "No", - null, - PREFERRED.getValue(), - Collections.singletonList(ALL_ZERO_AAGUID)) - ) { - - WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - - assertThat(realm.getSignatureAlgorithms(), hasItems("ES256")); - assertThat(realm.getAttestationConveyancePreference(), is(INDIRECT.getValue())); - assertThat(realm.getAuthenticatorAttachment(), is(CROSS_PLATFORM.getValue())); - assertThat(realm.getRequireResidentKey(), is("No")); - assertThat(realm.getRpId(), is("")); - assertThat(realm.getUserVerificationRequirement(), is(PREFERRED.getValue())); - assertThat(realm.getAcceptableAaguids(), hasItems(ALL_ZERO_AAGUID)); - } - } - - @Test - public void rpEntityValues() { - String rpEntityName = getPolicyPage().getRpEntityName(); - assertThat(rpEntityName, notNullValue()); - assertThat(rpEntityName, is(Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME)); - - getPolicyPage().setRpEntityName("newEntityName"); - getPolicyPage().clickSaveButton(); - AbstractPatternFlyAlert.waitUntilHidden(); - - rpEntityName = getPolicyPage().getRpEntityName(); - assertThat(rpEntityName, notNullValue()); - assertThat(rpEntityName, is("newEntityName")); - - getPolicyPage().setRpEntityName(""); - getPolicyPage().clickSaveButton(); - AbstractPatternFlyAlert.waitUntilHidden(); - - rpEntityName = getPolicyPage().getRpEntityName(); - assertThat(rpEntityName, notNullValue()); - assertThat(rpEntityName, is(Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME)); - - String rpEntityId = getPolicyPage().getRpEntityId(); - assertThat(rpEntityId, notNullValue()); - assertThat(rpEntityId, is("")); - - getPolicyPage().setRpEntityId("rpId123"); - getPolicyPage().clickSaveButton(); - AbstractPatternFlyAlert.waitUntilHidden(); - - rpEntityId = getPolicyPage().getRpEntityId(); - assertThat(rpEntityId, notNullValue()); - assertThat(rpEntityId, is("rpId123")); - - final WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - - assertThat(realm.getRpEntityName(), is(Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME)); - assertThat(realm.getRpId(), is("rpId123")); - } - - @Test - public void wrongSignatureAlgorithm() throws IOException { - try (Closeable c = getWebAuthnRealmUpdater() - .setWebAuthnPolicySignatureAlgorithms(Collections.singletonList("something-bad")) - .update()) { - - RealmRepresentation realm = testRealmResource().toRepresentation(); - assertThat(realm, notNullValue()); - - final List signatureAlgorithms = realm.getWebAuthnPolicySignatureAlgorithms(); - assertThat(signatureAlgorithms, notNullValue()); - assertThat(signatureAlgorithms.size(), is(1)); - - getPolicyPage().navigateTo(); - waitForPageToLoad(); - - Select selectedAlg = getPolicyPage().getSignatureAlgorithms(); - assertThat(selectedAlg, notNullValue()); - - try { - // should throw an exception - selectedAlg.getFirstSelectedOption(); - } catch (NoSuchElementException e) { - assertThat(e.getMessage(), containsString("No options are selected")); - } - } - } - - @Test - public void signatureAlgorithms() { - getPolicyPage().assertCurrent(); - - final Select algorithms = getPolicyPage().getSignatureAlgorithms(); - assertThat(algorithms, notNullValue()); - - algorithms.selectByValue("ES256"); - algorithms.selectByValue("ES384"); - algorithms.selectByValue("RS1"); - - final List selectedAlgs = algorithms.getAllSelectedOptions() - .stream() - .map(WebElement::getText) - .collect(Collectors.toList()); - - assertThat(selectedAlgs, notNullValue()); - assertThat(selectedAlgs, hasSize(3)); - - try { - algorithms.selectByValue("something-bad"); - } catch (NoSuchElementException e) { - assertThat(e.getMessage(), containsString("Cannot locate option with value: something-bad")); - } - - assertThat(getPolicyPage().isSaveButtonEnabled(), is(true)); - assertThat(getPolicyPage().isCancelButtonEnabled(), is(true)); - - getPolicyPage().clickSaveButton(); - - assertThat(getPolicyPage().isSaveButtonEnabled(), is(false)); - assertThat(getPolicyPage().isCancelButtonEnabled(), is(false)); - - final WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - - final List realmSignatureAlgs = realm.getSignatureAlgorithms(); - assertThat(realmSignatureAlgs, notNullValue()); - assertThat(realmSignatureAlgs, hasSize(3)); - assertThat(realmSignatureAlgs, contains("ES256", "ES384", "RS1")); - } - - @Test - public void attestationConveyancePreference() { - // default not specified - AttestationConveyancePreference attestation = getPolicyPage().getAttestationConveyancePreference(); - assertThat(attestation, nullValue()); - - // Direct - getPolicyPage().setAttestationConveyancePreference(AttestationConveyancePreference.DIRECT); - getPolicyPage().clickSaveButton(); - - attestation = getPolicyPage().getAttestationConveyancePreference(); - assertThat(attestation, notNullValue()); - assertThat(attestation, is(AttestationConveyancePreference.DIRECT)); - - // Indirect - getPolicyPage().setAttestationConveyancePreference(AttestationConveyancePreference.INDIRECT); - getPolicyPage().clickSaveButton(); - - attestation = getPolicyPage().getAttestationConveyancePreference(); - assertThat(attestation, notNullValue()); - assertThat(attestation, is(AttestationConveyancePreference.INDIRECT)); - - // None - getPolicyPage().setAttestationConveyancePreference(AttestationConveyancePreference.NONE); - getPolicyPage().clickSaveButton(); - - attestation = getPolicyPage().getAttestationConveyancePreference(); - assertThat(attestation, notNullValue()); - assertThat(attestation, is(AttestationConveyancePreference.NONE)); - - try { - getPolicyPage().setAttestationConveyancePreference(AttestationConveyancePreference.ENTERPRISE); - Assert.fail("We don't support 'Enterprise' mode at this moment"); - } catch (NoSuchElementException e) { - // Expected - NOP - } - - assertDataAfterModification(AttestationConveyancePreference.NONE.getValue(), - DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED, - WebAuthnRealmData::getAttestationConveyancePreference, - (builder) -> builder.attestationConveyancePreference(null) - ); - } - - @Test - public void authenticatorAttachment() { - AuthenticatorAttachment attachment = getPolicyPage().getAuthenticatorAttachment(); - assertThat(attachment, nullValue()); - - // Cross-platform - getPolicyPage().setAuthenticatorAttachment(AuthenticatorAttachment.CROSS_PLATFORM); - getPolicyPage().clickSaveButton(); - - attachment = getPolicyPage().getAuthenticatorAttachment(); - assertThat(attachment, notNullValue()); - assertThat(attachment, is(AuthenticatorAttachment.CROSS_PLATFORM)); - - // Platform - getPolicyPage().setAuthenticatorAttachment(AuthenticatorAttachment.PLATFORM); - getPolicyPage().clickSaveButton(); - - attachment = getPolicyPage().getAuthenticatorAttachment(); - assertThat(attachment, notNullValue()); - assertThat(attachment, is(AuthenticatorAttachment.PLATFORM)); - - assertDataAfterModification(AuthenticatorAttachment.PLATFORM.getValue(), - DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED, - WebAuthnRealmData::getAuthenticatorAttachment, - (builder) -> builder.authenticatorAttachment(null) - ); - } - - @Test - public void residentKey() { - PropertyRequirement requireResidentKey = getPolicyPage().requireResidentKey(); - assertThat(requireResidentKey, notNullValue()); - assertThat(requireResidentKey, is(PropertyRequirement.NOT_SPECIFIED)); - - getPolicyPage().requireResidentKey(YES); - getPolicyPage().clickSaveButton(); - - // Yes - requireResidentKey = getPolicyPage().requireResidentKey(); - assertThat(requireResidentKey, notNullValue()); - assertThat(requireResidentKey, is(YES)); - - getPolicyPage().requireResidentKey(NO); - getPolicyPage().clickSaveButton(); - - // Null - getPolicyPage().requireResidentKey(null); - assertThat(getPolicyPage().isSaveButtonEnabled(), is(false)); - - // Not specified - getPolicyPage().requireResidentKey(PropertyRequirement.NOT_SPECIFIED); - assertThat(getPolicyPage().isSaveButtonEnabled(), is(true)); - getPolicyPage().clickSaveButton(); - - // No - getPolicyPage().requireResidentKey(NO); - getPolicyPage().clickSaveButton(); - - requireResidentKey = getPolicyPage().requireResidentKey(); - assertThat(requireResidentKey, notNullValue()); - assertThat(requireResidentKey, is(NO)); - - assertDataAfterModification(NO.getValue(), - DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED, - WebAuthnRealmData::getRequireResidentKey, - (builder) -> builder.requireResidentKey(null) - ); - } - - @Test - public void userVerification() { - UserVerificationRequirement userVerification = getPolicyPage().getUserVerification(); - assertThat(userVerification, nullValue()); - - // Preferred - getPolicyPage().setUserVerification(UserVerificationRequirement.PREFERRED); - getPolicyPage().clickSaveButton(); - - userVerification = getPolicyPage().getUserVerification(); - assertThat(userVerification, notNullValue()); - assertThat(userVerification, is(UserVerificationRequirement.PREFERRED)); - - // Required - getPolicyPage().setUserVerification(UserVerificationRequirement.REQUIRED); - getPolicyPage().clickSaveButton(); - - userVerification = getPolicyPage().getUserVerification(); - assertThat(userVerification, notNullValue()); - assertThat(userVerification, is(UserVerificationRequirement.REQUIRED)); - - // Discouraged - getPolicyPage().setUserVerification(UserVerificationRequirement.DISCOURAGED); - getPolicyPage().clickSaveButton(); - - userVerification = getPolicyPage().getUserVerification(); - assertThat(userVerification, notNullValue()); - assertThat(userVerification, is(UserVerificationRequirement.DISCOURAGED)); - - assertDataAfterModification(UserVerificationRequirement.DISCOURAGED.getValue(), - DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED, - WebAuthnRealmData::getUserVerificationRequirement, - (builder) -> builder.userVerificationRequirement(null) - ); - } - - @Test - public void timeout() { - int timeout = getPolicyPage().getTimeout(); - assertThat(timeout, is(0)); - - getPolicyPage().setTimeout(10); - getPolicyPage().clickSaveButton(); - - timeout = getPolicyPage().getTimeout(); - assertThat(timeout, is(10)); - - getPolicyPage().setTimeout(-10); - getPolicyPage().clickSaveButton(); - assertAlertDanger(); - - timeout = getPolicyPage().getTimeout(); - assertThat(timeout, is(-10)); - - getPolicyPage().navigateTo(); - waitForPageToLoad(); - - timeout = getPolicyPage().getTimeout(); - assertThat(timeout, is(10)); - - getPolicyPage().setTimeout(1000000); - getPolicyPage().clickSaveButton(); - assertAlertDanger(); - - getPolicyPage().setTimeout(500); - getPolicyPage().clickSaveButton(); - - timeout = getPolicyPage().getTimeout(); - assertThat(timeout, is(500)); - - final WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - assertThat(realm.getCreateTimeout(), is(500)); - } - - @Test - public void avoidSameAuthenticatorRegistration() { - boolean avoidSameAuthenticatorRegistration = getPolicyPage().avoidSameAuthenticatorRegistration(); - assertThat(avoidSameAuthenticatorRegistration, is(false)); - - getPolicyPage().avoidSameAuthenticatorRegister(true); - assertThat(getPolicyPage().isSaveButtonEnabled(), is(true)); - getPolicyPage().clickSaveButton(); - - avoidSameAuthenticatorRegistration = getPolicyPage().avoidSameAuthenticatorRegistration(); - assertThat(avoidSameAuthenticatorRegistration, is(true)); - - getPolicyPage().avoidSameAuthenticatorRegister(false); - getPolicyPage().clickSaveButton(); - - avoidSameAuthenticatorRegistration = getPolicyPage().avoidSameAuthenticatorRegistration(); - assertThat(avoidSameAuthenticatorRegistration, is(false)); - - final WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - assertThat(realm.isAvoidSameAuthenticatorRegister(), is(false)); - } - - @Test - public void acceptableAaguid() { - WebAuthnPolicyPage.MultivaluedAcceptableAaguid acceptableAaguid = getPolicyPage().getAcceptableAaguid(); - assertThat(acceptableAaguid, notNullValue()); - - List items = getAcceptableAaguid(getPolicyPage().getAcceptableAaguid()); - assertThat(items, notNullValue()); - - acceptableAaguid.addItem(ALL_ONE_AAGUID); - getPolicyPage().clickSaveButton(); - - items = getAcceptableAaguid(getPolicyPage().getAcceptableAaguid()); - - assertThat(items, notNullValue()); - assertThat(items.isEmpty(), is(false)); - assertThat(items.contains(ALL_ONE_AAGUID), is(true)); - - final String YUBIKEY_5_AAGUID = "cb69481e-8ff7-4039-93ec-0a2729a154a8"; - final String YUBICO_AAGUID = "f8a011f3-8c0a-4d15-8006-17111f9edc7d"; - - acceptableAaguid.addItem(YUBIKEY_5_AAGUID); - acceptableAaguid.addItem(YUBICO_AAGUID); - items = getAcceptableAaguid(getPolicyPage().getAcceptableAaguid()); - - assertThat(items, notNullValue()); - assertThat(items, hasSize(3)); - - getPolicyPage().clickSaveButton(); - acceptableAaguid.removeItem(0); - items = getAcceptableAaguid(getPolicyPage().getAcceptableAaguid()); - - assertThat(items, notNullValue()); - assertThat(items, hasSize(2)); - assertThat(items.contains(YUBICO_AAGUID), is(true)); - assertThat(items.contains(YUBIKEY_5_AAGUID), is(true)); - assertThat(items.contains(ALL_ONE_AAGUID), is(false)); - - assertThat(getPolicyPage().isSaveButtonEnabled(), is(true)); - getPolicyPage().clickSaveButton(); - pause(100); - - WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - assertThat(realm.getAcceptableAaguids(), is(getAcceptableAaguid(getPolicyPage().getAcceptableAaguid()))); - } - - protected List getAcceptableAaguid(WebAuthnPolicyPage.MultivaluedAcceptableAaguid acceptableAaguid) { - return acceptableAaguid.getItems() - .stream() - .map(UIUtils::getTextInputValue) - .collect(Collectors.toList()); - } - - /** - * Assert WebAuthn Realm data before and after modification - * - * @param actualValue actual value before modification - * @param expectedValue expected value after modification - * @param getCurrentValue get updated value - * @param setData exact approach, how to change the realm data - */ - private void assertDataAfterModification(T actualValue, T expectedValue, - Function getCurrentValue, - Consumer setData) { - - WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - - assertThat(getCurrentValue.apply(realm), is(actualValue)); - - WebAuthnRealmData.Builder builder = realm.builder(); - assertThat(builder, notNullValue()); - setData.accept(builder); - - final RealmRepresentation newRealm = builder.build(); - assertThat(newRealm, notNullValue()); - - testRealmResource().update(newRealm); - - realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless()); - assertThat(realm, notNullValue()); - - assertThat(getCurrentValue.apply(realm), is(expectedValue)); - } -}