Complete support for Passwordless tests

Closes #9850
This commit is contained in:
Martin Bartoš 2022-01-31 11:26:53 +01:00 committed by Marek Posolda
parent 3528e7ba54
commit 191ef1874e
7 changed files with 588 additions and 731 deletions

View file

@ -20,6 +20,7 @@ package org.keycloak.testsuite.webauthn.utils;
import org.keycloak.representations.idm.RealmRepresentation;
import java.util.List;
import java.util.function.Consumer;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
@ -79,4 +80,84 @@ public class WebAuthnRealmData {
public List<String> getAcceptableAaguids() {
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessAcceptableAaguids() : realm.getWebAuthnPolicyAcceptableAaguids();
}
public RealmRepresentation getRealm() {
return realm;
}
public Builder builder() {
return new Builder(realm, isPasswordless);
}
public static class Builder {
private final RealmRepresentation realm;
private final boolean isPasswordless;
public Builder(RealmRepresentation realm, boolean isPasswordless) {
this.realm = realm;
this.isPasswordless = isPasswordless;
}
public Builder rpEntityName(String entityName) {
setProperty(entityName, realm::setWebAuthnPolicyRpEntityName, realm::setWebAuthnPolicyPasswordlessRpEntityName);
return this;
}
public Builder signatureAlgorithms(List<String> list) {
setProperty(list, realm::setWebAuthnPolicySignatureAlgorithms, realm::setWebAuthnPolicyPasswordlessSignatureAlgorithms);
return this;
}
public Builder rpId(String rpId) {
setProperty(rpId, realm::setWebAuthnPolicyRpId, realm::setWebAuthnPolicyPasswordlessRpId);
return this;
}
public Builder attestationConveyancePreference(String preference) {
setProperty(preference, realm::setWebAuthnPolicyAttestationConveyancePreference, realm::setWebAuthnPolicyPasswordlessAttestationConveyancePreference);
return this;
}
public Builder authenticatorAttachment(String attachment) {
setProperty(attachment, realm::setWebAuthnPolicyAuthenticatorAttachment, realm::setWebAuthnPolicyPasswordlessAuthenticatorAttachment);
return this;
}
public Builder requireResidentKey(String requirement) {
setProperty(requirement, realm::setWebAuthnPolicyRequireResidentKey, realm::setWebAuthnPolicyPasswordlessRequireResidentKey);
return this;
}
public Builder userVerificationRequirement(String requirement) {
setProperty(requirement, realm::setWebAuthnPolicyUserVerificationRequirement, realm::setWebAuthnPolicyPasswordlessUserVerificationRequirement);
return this;
}
public Builder timeout(Integer timeout) {
setProperty(timeout, realm::setWebAuthnPolicyCreateTimeout, realm::setWebAuthnPolicyPasswordlessCreateTimeout);
return this;
}
public Builder avoidSameAuthenticatorRegister(Boolean state) {
setProperty(state, realm::setWebAuthnPolicyAvoidSameAuthenticatorRegister, realm::setWebAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister);
return this;
}
public Builder acceptableAaguids(List<String> aaguids) {
setProperty(aaguids, realm::setWebAuthnPolicyAcceptableAaguids, realm::setWebAuthnPolicyPasswordlessAcceptableAaguids);
return this;
}
public RealmRepresentation build() {
return realm;
}
private <T> void setProperty(T value, Consumer<T> webauthnSetter, Consumer<T> passwordlessSetter) {
if (isPasswordless) {
passwordlessSetter.accept(value);
} else {
webauthnSetter.accept(value);
}
}
}
}

View file

@ -1,422 +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.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
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.util.UIUtils;
import org.keycloak.testsuite.webauthn.pages.WebAuthnPolicyPage;
import org.keycloak.testsuite.webauthn.updaters.AbstractWebAuthnRealmUpdater;
import org.keycloak.testsuite.webauthn.utils.PropertyRequirement;
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.stream.Collectors;
import static org.hamcrest.CoreMatchers.containsString;
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.hasSize;
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 <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
*/
public abstract class AbstractWebAuthnPolicySettingsTest 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);
@Before
public void navigateToPolicy() {
driver.manage().window().maximize();
getPolicyPage().navigateTo();
waitForPageToLoad();
getPolicyPage().assertCurrent();
}
protected abstract WebAuthnPolicyPage getPolicyPage();
protected abstract AbstractWebAuthnRealmUpdater<?> getWebAuthnRealmUpdater();
protected AbstractWebAuthnRealmUpdater<?> updateWebAuthnPolicy(
String rpName,
List<String> algorithms,
String attestationPreference,
String authenticatorAttachment,
String requireResidentKey,
String rpId,
String userVerification,
List<String> 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 <T> void checkAndSet(T value, Consumer<T> consumer) {
if (value != null) {
consumer.accept(value);
}
}
protected void checkRpEntityValues() {
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"));
}
protected void checkWrongSignatureAlgorithm() throws IOException {
try (Closeable c = getWebAuthnRealmUpdater()
.setWebAuthnPolicySignatureAlgorithms(Collections.singletonList("something-bad"))
.update()) {
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
final List<String> 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"));
}
}
}
protected void checkSignatureAlgorithms() {
getPolicyPage().assertCurrent();
final Select algorithms = getPolicyPage().getSignatureAlgorithms();
assertThat(algorithms, notNullValue());
algorithms.selectByValue("ES256");
algorithms.selectByValue("ES384");
algorithms.selectByValue("RS1");
final List<String> 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));
}
public void checkAttestationConveyancePreference() {
// 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) {
}
}
protected void checkAuthenticatorAttachment() {
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));
}
protected void checkResidentKey() {
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));
}
protected void checkUserVerification() {
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));
}
protected void checkTimeout() {
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));
}
protected void checkAvoidSameAuthenticatorRegistration() {
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));
}
protected void checkAcceptableAaguid() {
WebAuthnPolicyPage.MultivaluedAcceptableAaguid acceptableAaguid = getPolicyPage().getAcceptableAaguid();
assertThat(acceptableAaguid, notNullValue());
List<String> 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);
}
protected List<String> getAcceptableAaguid(WebAuthnPolicyPage.MultivaluedAcceptableAaguid acceptableAaguid) {
return acceptableAaguid.getItems()
.stream()
.map(UIUtils::getTextInputValue)
.collect(Collectors.toList());
}
}

View file

@ -0,0 +1,29 @@
/*
* 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 <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
*/
public class PwdLessPolicySettingsTest extends WebAuthnPolicySettingsTest {
@Override
protected boolean isPasswordless() {
return true;
}
}

View file

@ -1,219 +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.Test;
import org.keycloak.models.Constants;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
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 java.io.IOException;
import java.util.Collections;
import java.util.List;
import static com.webauthn4j.data.AttestationConveyancePreference.DIRECT;
import static com.webauthn4j.data.AuthenticatorAttachment.PLATFORM;
import static com.webauthn4j.data.UserVerificationRequirement.PREFERRED;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
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;
/**
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
*/
public class WebAuthnPolicyPasswordlessSettingsTest extends AbstractWebAuthnPolicySettingsTest {
@Page
WebAuthnPolicyPasswordlessPage webAuthnPolicyPasswordlessPage;
@Override
protected WebAuthnPolicyPage getPolicyPage() {
return webAuthnPolicyPasswordlessPage;
}
@Override
protected AbstractWebAuthnRealmUpdater<PasswordLessRealmAttributeUpdater> getWebAuthnRealmUpdater() {
return new PasswordLessRealmAttributeUpdater(testRealmResource());
}
@Test
public void policySettingsWithExternalProperties() throws IOException {
try (RealmAttributeUpdater rau = updateWebAuthnPolicy(
"rpNamePasswordless",
Collections.singletonList("RS256"),
DIRECT.getValue(),
PLATFORM.getValue(),
"Yes",
"1234",
PREFERRED.getValue(),
Collections.singletonList(ALL_ZERO_AAGUID))
) {
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessSignatureAlgorithms(), hasItems("RS256"));
assertThat(realm.getWebAuthnPolicyPasswordlessAttestationConveyancePreference(), is(DIRECT.getValue()));
assertThat(realm.getWebAuthnPolicyPasswordlessAuthenticatorAttachment(), is(PLATFORM.getValue()));
assertThat(realm.getWebAuthnPolicyPasswordlessRequireResidentKey(), is("Yes"));
assertThat(realm.getWebAuthnPolicyPasswordlessRpId(), is("1234"));
assertThat(realm.getWebAuthnPolicyPasswordlessUserVerificationRequirement(), is(PREFERRED.getValue()));
assertThat(realm.getWebAuthnPolicyPasswordlessAcceptableAaguids(), hasItems(ALL_ZERO_AAGUID));
}
}
@Test
public void wrongSignatureAlgorithm() throws IOException {
checkWrongSignatureAlgorithm();
}
@Test
public void algorithmsValuesSetUpInAdminConsole() {
checkSignatureAlgorithms();
final RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
final List<String> realmSignatureAlgs = realm.getWebAuthnPolicyPasswordlessSignatureAlgorithms();
assertThat(realmSignatureAlgs, notNullValue());
assertThat(realmSignatureAlgs, hasSize(3));
assertThat(realmSignatureAlgs, contains("ES256", "ES384", "RS1"));
}
@Test
public void rpValuesSetUpInAdminConsole() {
checkRpEntityValues();
final RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessRpEntityName(), is(Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME));
assertThat(realm.getWebAuthnPolicyPasswordlessRpId(), is("rpId123"));
}
@Test
public void attestationConveyancePreferenceSettings() {
checkAttestationConveyancePreference();
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessAttestationConveyancePreference(), is(AttestationConveyancePreference.NONE.getValue()));
realm.setWebAuthnPolicyPasswordlessAttestationConveyancePreference(null);
testRealmResource().update(realm);
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessAttestationConveyancePreference(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
}
@Test
public void authenticatorAttachmentSettings() {
checkAuthenticatorAttachment();
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessAuthenticatorAttachment(), is(AuthenticatorAttachment.PLATFORM.getValue()));
realm.setWebAuthnPolicyPasswordlessAuthenticatorAttachment(null);
testRealmResource().update(realm);
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessAuthenticatorAttachment(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
}
@Test
public void requireResidentKeySettings() {
checkResidentKey();
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessRequireResidentKey(), is("No"));
realm.setWebAuthnPolicyPasswordlessRequireResidentKey(null);
testRealmResource().update(realm);
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessRequireResidentKey(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
}
@Test
public void userVerificationRequirementSettings() {
checkUserVerification();
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessUserVerificationRequirement(), is(UserVerificationRequirement.DISCOURAGED.getValue()));
realm.setWebAuthnPolicyPasswordlessUserVerificationRequirement(null);
testRealmResource().update(realm);
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessUserVerificationRequirement(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
}
@Test
public void timeoutSettings() {
checkTimeout();
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessCreateTimeout(), is(500));
}
@Test
public void avoidSameAuthenticatorRegistrationSettings() {
checkAvoidSameAuthenticatorRegistration();
final RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.isWebAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister(), is(false));
}
@Test
public void acceptableAaguidSettings() {
checkAcceptableAaguid();
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyPasswordlessAcceptableAaguids(), is(getAcceptableAaguid(getPolicyPage().getAcceptableAaguid())));
}
}

View file

@ -21,45 +21,117 @@ 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 <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
*/
public class WebAuthnPolicySettingsTest extends AbstractWebAuthnPolicySettingsTest {
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;
@Override
protected WebAuthnPolicyPage getPolicyPage() {
return webAuthnPolicyPage;
@Page
WebAuthnPolicyPasswordlessPage webAuthnPolicyPasswordlessPage;
@Before
public void navigateToPolicy() {
driver.manage().window().maximize();
getPolicyPage().navigateTo();
waitForPageToLoad();
getPolicyPage().assertCurrent();
}
@Override
protected AbstractWebAuthnRealmUpdater<WebAuthnRealmAttributeUpdater> getWebAuthnRealmUpdater() {
return new WebAuthnRealmAttributeUpdater(testRealmResource());
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<String> algorithms,
String attestationPreference,
String authenticatorAttachment,
String requireResidentKey,
String rpId,
String userVerification,
List<String> 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 <T> void checkAndSet(T value, Consumer<T> consumer) {
if (value != null) {
consumer.accept(value);
}
}
@Test
@ -74,150 +146,424 @@ public class WebAuthnPolicySettingsTest extends AbstractWebAuthnPolicySettingsTe
PREFERRED.getValue(),
Collections.singletonList(ALL_ZERO_AAGUID))
) {
RealmRepresentation realm = testRealmResource().toRepresentation();
WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless());
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicySignatureAlgorithms(), hasItems("ES256"));
assertThat(realm.getWebAuthnPolicyAttestationConveyancePreference(), is(INDIRECT.getValue()));
assertThat(realm.getWebAuthnPolicyAuthenticatorAttachment(), is(CROSS_PLATFORM.getValue()));
assertThat(realm.getWebAuthnPolicyRequireResidentKey(), is("No"));
assertThat(realm.getWebAuthnPolicyRpId(), is(""));
assertThat(realm.getWebAuthnPolicyUserVerificationRequirement(), is(PREFERRED.getValue()));
assertThat(realm.getWebAuthnPolicyAcceptableAaguids(), hasItems(ALL_ZERO_AAGUID));
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 wrongSignatureAlgorithm() throws IOException {
checkWrongSignatureAlgorithm();
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 algorithmsValuesSetUpInAdminConsole() {
checkSignatureAlgorithms();
public void wrongSignatureAlgorithm() throws IOException {
try (Closeable c = getWebAuthnRealmUpdater()
.setWebAuthnPolicySignatureAlgorithms(Collections.singletonList("something-bad"))
.update()) {
final RealmRepresentation realm = testRealmResource().toRepresentation();
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
final List<String> 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<String> 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<String> realmSignatureAlgs = realm.getWebAuthnPolicySignatureAlgorithms();
final List<String> realmSignatureAlgs = realm.getSignatureAlgorithms();
assertThat(realmSignatureAlgs, notNullValue());
assertThat(realmSignatureAlgs, hasSize(3));
assertThat(realmSignatureAlgs, contains("ES256", "ES384", "RS1"));
}
@Test
public void rpValuesSetUpInAdminConsole() {
checkRpEntityValues();
public void attestationConveyancePreference() {
// default not specified
AttestationConveyancePreference attestation = getPolicyPage().getAttestationConveyancePreference();
assertThat(attestation, nullValue());
final RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
// Direct
getPolicyPage().setAttestationConveyancePreference(AttestationConveyancePreference.DIRECT);
getPolicyPage().clickSaveButton();
assertThat(realm.getWebAuthnPolicyRpEntityName(), is(Constants.DEFAULT_WEBAUTHN_POLICY_RP_ENTITY_NAME));
assertThat(realm.getWebAuthnPolicyRpId(), is("rpId123"));
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 attestationConveyancePreferenceSettings() {
checkAttestationConveyancePreference();
public void authenticatorAttachment() {
AuthenticatorAttachment attachment = getPolicyPage().getAuthenticatorAttachment();
assertThat(attachment, nullValue());
// Realm
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
// Cross-platform
getPolicyPage().setAuthenticatorAttachment(AuthenticatorAttachment.CROSS_PLATFORM);
getPolicyPage().clickSaveButton();
assertThat(realm.getWebAuthnPolicyAttestationConveyancePreference(), is(AttestationConveyancePreference.NONE.getValue()));
attachment = getPolicyPage().getAuthenticatorAttachment();
assertThat(attachment, notNullValue());
assertThat(attachment, is(AuthenticatorAttachment.CROSS_PLATFORM));
realm.setWebAuthnPolicyAttestationConveyancePreference(null);
testRealmResource().update(realm);
// Platform
getPolicyPage().setAuthenticatorAttachment(AuthenticatorAttachment.PLATFORM);
getPolicyPage().clickSaveButton();
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
attachment = getPolicyPage().getAuthenticatorAttachment();
assertThat(attachment, notNullValue());
assertThat(attachment, is(AuthenticatorAttachment.PLATFORM));
assertThat(realm.getWebAuthnPolicyAttestationConveyancePreference(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
assertDataAfterModification(AuthenticatorAttachment.PLATFORM.getValue(),
DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED,
WebAuthnRealmData::getAuthenticatorAttachment,
(builder) -> builder.authenticatorAttachment(null)
);
}
@Test
public void authenticatorAttachmentSettings() {
checkAuthenticatorAttachment();
public void residentKey() {
PropertyRequirement requireResidentKey = getPolicyPage().requireResidentKey();
assertThat(requireResidentKey, notNullValue());
assertThat(requireResidentKey, is(PropertyRequirement.NOT_SPECIFIED));
// Realm
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
getPolicyPage().requireResidentKey(YES);
getPolicyPage().clickSaveButton();
assertThat(realm.getWebAuthnPolicyAuthenticatorAttachment(), is(AuthenticatorAttachment.PLATFORM.getValue()));
// Yes
requireResidentKey = getPolicyPage().requireResidentKey();
assertThat(requireResidentKey, notNullValue());
assertThat(requireResidentKey, is(YES));
realm.setWebAuthnPolicyAuthenticatorAttachment(null);
testRealmResource().update(realm);
getPolicyPage().requireResidentKey(NO);
getPolicyPage().clickSaveButton();
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
// Null
getPolicyPage().requireResidentKey(null);
assertThat(getPolicyPage().isSaveButtonEnabled(), is(false));
assertThat(realm.getWebAuthnPolicyAuthenticatorAttachment(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
// 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 requireResidentKeySettings() {
checkResidentKey();
public void userVerification() {
UserVerificationRequirement userVerification = getPolicyPage().getUserVerification();
assertThat(userVerification, nullValue());
// Realm
RealmRepresentation realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
// Preferred
getPolicyPage().setUserVerification(UserVerificationRequirement.PREFERRED);
getPolicyPage().clickSaveButton();
assertThat(realm.getWebAuthnPolicyRequireResidentKey(), is("No"));
userVerification = getPolicyPage().getUserVerification();
assertThat(userVerification, notNullValue());
assertThat(userVerification, is(UserVerificationRequirement.PREFERRED));
realm.setWebAuthnPolicyRequireResidentKey(null);
testRealmResource().update(realm);
// Required
getPolicyPage().setUserVerification(UserVerificationRequirement.REQUIRED);
getPolicyPage().clickSaveButton();
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
userVerification = getPolicyPage().getUserVerification();
assertThat(userVerification, notNullValue());
assertThat(userVerification, is(UserVerificationRequirement.REQUIRED));
assertThat(realm.getWebAuthnPolicyRequireResidentKey(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
// 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 userVerificationRequirementSettings() {
checkUserVerification();
public void timeout() {
int timeout = getPolicyPage().getTimeout();
assertThat(timeout, is(0));
// Realm
RealmRepresentation realm = testRealmResource().toRepresentation();
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.getWebAuthnPolicyUserVerificationRequirement(), is(UserVerificationRequirement.DISCOURAGED.getValue()));
realm.setWebAuthnPolicyUserVerificationRequirement(null);
testRealmResource().update(realm);
realm = testRealmResource().toRepresentation();
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyUserVerificationRequirement(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
assertThat(realm.getCreateTimeout(), is(500));
}
@Test
public void timeoutSettings() {
checkTimeout();
public void avoidSameAuthenticatorRegistration() {
boolean avoidSameAuthenticatorRegistration = getPolicyPage().avoidSameAuthenticatorRegistration();
assertThat(avoidSameAuthenticatorRegistration, is(false));
// Realm
RealmRepresentation realm = testRealmResource().toRepresentation();
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.getWebAuthnPolicyCreateTimeout(), is(500));
assertThat(realm.isAvoidSameAuthenticatorRegister(), is(false));
}
@Test
public void avoidSameAuthenticatorRegistrationSettings() {
checkAvoidSameAuthenticatorRegistration();
public void acceptableAaguid() {
WebAuthnPolicyPage.MultivaluedAcceptableAaguid acceptableAaguid = getPolicyPage().getAcceptableAaguid();
assertThat(acceptableAaguid, notNullValue());
final RealmRepresentation realm = testRealmResource().toRepresentation();
List<String> 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.isWebAuthnPolicyAvoidSameAuthenticatorRegister(), is(false));
assertThat(realm.getAcceptableAaguids(), is(getAcceptableAaguid(getPolicyPage().getAcceptableAaguid())));
}
@Test
public void acceptableAaguidSettings() {
checkAcceptableAaguid();
protected List<String> getAcceptableAaguid(WebAuthnPolicyPage.MultivaluedAcceptableAaguid acceptableAaguid) {
return acceptableAaguid.getItems()
.stream()
.map(UIUtils::getTextInputValue)
.collect(Collectors.toList());
}
RealmRepresentation realm = testRealmResource().toRepresentation();
/**
* 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 <T> void assertDataAfterModification(T actualValue, T expectedValue,
Function<WebAuthnRealmData, T> getCurrentValue,
Consumer<WebAuthnRealmData.Builder> setData) {
WebAuthnRealmData realm = new WebAuthnRealmData(testRealmResource().toRepresentation(), isPasswordless());
assertThat(realm, notNullValue());
assertThat(realm.getWebAuthnPolicyAcceptableAaguids(), is(getAcceptableAaguid(getPolicyPage().getAcceptableAaguid())));
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));
}
}

View file

@ -15,13 +15,16 @@
* limitations under the License.
*/
package org.keycloak.testsuite.webauthn;
package org.keycloak.testsuite.webauthn.passwordless;
import org.keycloak.testsuite.webauthn.AppInitiatedActionWebAuthnTest;
/**
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
*/
public class AppInitiatedActionPwdLessTest extends AppInitiatedActionWebAuthnTest {
@Override
protected boolean isPasswordless() {
return true;
}

View file

@ -0,0 +1,39 @@
/*
* 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.passwordless;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.testsuite.webauthn.WebAuthnPropertyTest;
/**
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
*/
public class WebAuthnPwdLessPropertyTest extends WebAuthnPropertyTest {
@Override
public boolean isPasswordless() {
return true;
}
@Override
@Ignore("Not usable for Passwordless")
@Test
public void requiredActionRegistration() {
}
}