KEYCLOAK-19486 Verify the WebAuthn registration functionality
This commit is contained in:
parent
3a2bf0c04b
commit
8e8fab857e
29 changed files with 1349 additions and 38 deletions
|
@ -513,6 +513,8 @@ mvn -f testsuite/integration-arquillian/tests/other/pom.xml clean test \
|
|||
-Dbrowser=chrome -Pwebauthn
|
||||
```
|
||||
|
||||
**Note:** You can also execute those tests with `chromeHeadless` browser in order to not open a new window.
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
If you try to run WebAuthn tests with Chrome browser and you see error like:
|
||||
|
|
|
@ -24,7 +24,9 @@ public class TestClassProvider {
|
|||
"/org/jboss/arquillian",
|
||||
"/org/jboss/shrinkwrap",
|
||||
"/org/jboss/jandex",
|
||||
"/org/openqa/selenium"
|
||||
"/org/openqa/selenium",
|
||||
"/com/webauthn4j",
|
||||
"/com/fasterxml/jackson/dataformat/cbor"
|
||||
};
|
||||
|
||||
private Undertow server;
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
<properties>
|
||||
<keycloak.theme.dir>${auth.server.home}/themes</keycloak.theme.dir>
|
||||
<supportedBrowsers>firefox|chrome|internetExplorer|safari</supportedBrowsers>
|
||||
<supportedBrowsers>firefox|chrome|internetExplorer|safari|chromeHeadless</supportedBrowsers>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -42,7 +42,13 @@ public enum DefaultVirtualAuthOptions {
|
|||
|
||||
YUBIKEY_4(DefaultVirtualAuthOptions::getYubiKeyGeneralOptions),
|
||||
YUBIKEY_5_USB(DefaultVirtualAuthOptions::getYubiKeyGeneralOptions),
|
||||
YUBIKEY_5_NFC(() -> getYubiKeyGeneralOptions().setTransport(NFC));
|
||||
YUBIKEY_5_NFC(() -> getYubiKeyGeneralOptions().setTransport(NFC)),
|
||||
|
||||
TOUCH_ID(() -> DEFAULT.getOptions()
|
||||
.setTransport(INTERNAL)
|
||||
.setHasUserVerification(true)
|
||||
.setIsUserVerified(true)
|
||||
);
|
||||
|
||||
private final Supplier<VirtualAuthenticatorOptions> options;
|
||||
|
||||
|
@ -50,7 +56,7 @@ public enum DefaultVirtualAuthOptions {
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
public VirtualAuthenticatorOptions getOptions() {
|
||||
public final VirtualAuthenticatorOptions getOptions() {
|
||||
return options.get();
|
||||
}
|
||||
|
||||
|
|
|
@ -55,11 +55,12 @@ public class KcVirtualAuthenticator {
|
|||
private final boolean hasUserVerification;
|
||||
private final boolean isUserConsenting;
|
||||
private final boolean isUserVerified;
|
||||
private final Map<String, Object> map;
|
||||
|
||||
private Options(VirtualAuthenticatorOptions options) {
|
||||
this.options = options;
|
||||
|
||||
final Map<String, Object> map = options.toMap();
|
||||
this.map = options.toMap();
|
||||
this.protocol = protocolFromMap(map);
|
||||
this.transport = transportFromMap(map);
|
||||
this.hasResidentKey = (Boolean) map.get("hasResidentKey");
|
||||
|
@ -96,6 +97,10 @@ public class KcVirtualAuthenticator {
|
|||
return options;
|
||||
}
|
||||
|
||||
public Map<String, Object> asMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
private static VirtualAuthenticatorOptions.Protocol protocolFromMap(Map<String, Object> map) {
|
||||
return Arrays.stream(VirtualAuthenticatorOptions.Protocol.values())
|
||||
.filter(f -> f.id.equals(map.get("protocol")))
|
||||
|
|
|
@ -17,11 +17,15 @@
|
|||
|
||||
package org.keycloak.testsuite.webauthn.authenticators;
|
||||
|
||||
import org.apache.http.util.Args;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.virtualauthenticator.HasVirtualAuthenticator;
|
||||
import org.openqa.selenium.virtualauthenticator.VirtualAuthenticatorOptions;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +35,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
*/
|
||||
public class VirtualAuthenticatorManager {
|
||||
private final HasVirtualAuthenticator driver;
|
||||
private KcVirtualAuthenticator actualAuthenticator;
|
||||
private KcVirtualAuthenticator currentAuthenticator;
|
||||
|
||||
public VirtualAuthenticatorManager(WebDriver driver) {
|
||||
assertThat("Driver must support Virtual Authenticators", driver, CoreMatchers.instanceOf(HasVirtualAuthenticator.class));
|
||||
|
@ -39,18 +43,20 @@ public class VirtualAuthenticatorManager {
|
|||
}
|
||||
|
||||
public KcVirtualAuthenticator useAuthenticator(VirtualAuthenticatorOptions options) {
|
||||
this.actualAuthenticator = new KcVirtualAuthenticator(driver.addVirtualAuthenticator(options), options);
|
||||
return actualAuthenticator;
|
||||
if (options == null) return null;
|
||||
|
||||
this.currentAuthenticator = new KcVirtualAuthenticator(driver.addVirtualAuthenticator(options), options);
|
||||
return currentAuthenticator;
|
||||
}
|
||||
|
||||
public KcVirtualAuthenticator getActualAuthenticator() {
|
||||
return actualAuthenticator;
|
||||
public KcVirtualAuthenticator getCurrent() {
|
||||
return currentAuthenticator;
|
||||
}
|
||||
|
||||
public void removeAuthenticator() {
|
||||
if (actualAuthenticator != null) {
|
||||
driver.removeVirtualAuthenticator(actualAuthenticator.getAuthenticator());
|
||||
this.actualAuthenticator = null;
|
||||
if (currentAuthenticator != null) {
|
||||
driver.removeVirtualAuthenticator(currentAuthenticator.getAuthenticator());
|
||||
this.currentAuthenticator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public abstract class AbstractWebAuthnRealmUpdater<T extends AbstractWebAuthnRealmUpdater> extends RealmAttributeUpdater {
|
||||
|
||||
public AbstractWebAuthnRealmUpdater(RealmResource resource) {
|
||||
|
@ -47,4 +50,10 @@ public abstract class AbstractWebAuthnRealmUpdater<T extends AbstractWebAuthnRea
|
|||
public abstract T setWebAuthnPolicyUserVerificationRequirement(String webAuthnPolicyUserVerificationRequirement);
|
||||
|
||||
public abstract T setWebAuthnPolicyAcceptableAaguids(List<String> webAuthnPolicyAcceptableAaguids);
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public AbstractWebAuthnRealmUpdater<T> update() {
|
||||
return (AbstractWebAuthnRealmUpdater<T>) super.update();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ import org.keycloak.admin.client.resource.RealmResource;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PasswordLessRealmAttributeUpdater extends AbstractWebAuthnRealmUpdater<PasswordLessRealmAttributeUpdater> {
|
||||
public PasswordLessRealmAttributeUpdater(RealmResource resource) {
|
||||
super(resource);
|
||||
|
|
|
@ -21,6 +21,9 @@ import org.keycloak.admin.client.resource.RealmResource;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class WebAuthnRealmAttributeUpdater extends AbstractWebAuthnRealmUpdater<WebAuthnRealmAttributeUpdater> {
|
||||
public WebAuthnRealmAttributeUpdater(RealmResource resource) {
|
||||
super(resource);
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.utils;
|
||||
|
||||
import com.webauthn4j.converter.util.CborConverter;
|
||||
import com.webauthn4j.converter.util.ObjectConverter;
|
||||
import com.webauthn4j.data.attestation.authenticator.COSEKey;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.UserCredentialManager;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.dto.WebAuthnCredentialData;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static org.keycloak.models.credential.WebAuthnCredentialModel.createFromCredentialModel;
|
||||
|
||||
/**
|
||||
* Helper class for WebAuthn data wrapping
|
||||
*
|
||||
* @author Martin Bartos <mabartos@redhat.com>
|
||||
*/
|
||||
public class WebAuthnDataWrapper implements Serializable {
|
||||
private static final ObjectConverter converter = new ObjectConverter();
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final String username;
|
||||
private final String credentialType;
|
||||
private WebAuthnCredentialData webAuthnData = null;
|
||||
|
||||
public WebAuthnDataWrapper(KeycloakSession session, String username, String credentialType) {
|
||||
this.session = session;
|
||||
this.username = username;
|
||||
this.credentialType = credentialType;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
final UserModel user = session.users().getUserByUsername(session.getContext().getRealm(), username);
|
||||
if (user == null) return;
|
||||
|
||||
final UserCredentialManager userCredentialManager = session.userCredentialManager();
|
||||
if (userCredentialManager == null) return;
|
||||
|
||||
final CredentialModel credential = userCredentialManager
|
||||
.getStoredCredentialsByTypeStream(session.getContext().getRealm(), user, credentialType)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (credential == null) return;
|
||||
|
||||
this.webAuthnData = createFromCredentialModel(credential).getWebAuthnCredentialData();
|
||||
}
|
||||
|
||||
public COSEKey getKey() {
|
||||
if (webAuthnData != null) {
|
||||
CborConverter cborConverter = converter.getCborConverter();
|
||||
return cborConverter.readValue(Base64Url.decode(webAuthnData.getCredentialPublicKey()), COSEKey.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public WebAuthnCredentialData getWebAuthnData() {
|
||||
return webAuthnData;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.utils;
|
||||
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Helper class for retrieving WebAuthn data
|
||||
*
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class WebAuthnRealmData {
|
||||
|
||||
private final RealmRepresentation realm;
|
||||
private final boolean isPasswordless;
|
||||
|
||||
public WebAuthnRealmData(RealmRepresentation realm, boolean isPasswordless) {
|
||||
assertThat("RealmRepresentation must not be NULL", realm, notNullValue());
|
||||
this.realm = realm;
|
||||
this.isPasswordless = isPasswordless;
|
||||
}
|
||||
|
||||
public String getRpEntityName() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessRpEntityName() : realm.getWebAuthnPolicyRpEntityName();
|
||||
}
|
||||
|
||||
public List<String> getSignatureAlgorithms() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessSignatureAlgorithms() : realm.getWebAuthnPolicySignatureAlgorithms();
|
||||
}
|
||||
|
||||
public String getRpId() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessRpId() : realm.getWebAuthnPolicyRpId();
|
||||
}
|
||||
|
||||
public String getAttestationConveyancePreference() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessAttestationConveyancePreference() : realm.getWebAuthnPolicyAttestationConveyancePreference();
|
||||
}
|
||||
|
||||
public String getAuthenticatorAttachment() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessAuthenticatorAttachment() : realm.getWebAuthnPolicyAuthenticatorAttachment();
|
||||
}
|
||||
|
||||
public String getRequireResidentKey() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessRequireResidentKey() : realm.getWebAuthnPolicyRequireResidentKey();
|
||||
}
|
||||
|
||||
public String getUserVerificationRequirement() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessUserVerificationRequirement() : realm.getWebAuthnPolicyUserVerificationRequirement();
|
||||
}
|
||||
|
||||
public Integer getCreateTimeout() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessCreateTimeout() : realm.getWebAuthnPolicyCreateTimeout();
|
||||
}
|
||||
|
||||
public Boolean isAvoidSameAuthenticatorRegister() {
|
||||
return isPasswordless ? realm.isWebAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister() : realm.isWebAuthnPolicyAvoidSameAuthenticatorRegister();
|
||||
}
|
||||
|
||||
public List<String> getAcceptableAaguids() {
|
||||
return isPasswordless ? realm.getWebAuthnPolicyPasswordlessAcceptableAaguids() : realm.getWebAuthnPolicyAcceptableAaguids();
|
||||
}
|
||||
}
|
|
@ -20,11 +20,15 @@ package org.keycloak.testsuite.webauthn;
|
|||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.UseVirtualAuthenticators;
|
||||
import org.keycloak.testsuite.webauthn.authenticators.VirtualAuthenticatorManager;
|
||||
import org.keycloak.testsuite.webauthn.updaters.AbstractWebAuthnRealmUpdater;
|
||||
import org.keycloak.testsuite.webauthn.updaters.PasswordLessRealmAttributeUpdater;
|
||||
import org.keycloak.testsuite.webauthn.updaters.WebAuthnRealmAttributeUpdater;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.virtualauthenticator.VirtualAuthenticatorOptions;
|
||||
|
||||
|
@ -36,18 +40,22 @@ import org.openqa.selenium.virtualauthenticator.VirtualAuthenticatorOptions;
|
|||
@EnableFeature(value = Profile.Feature.WEB_AUTHN, skipRestart = true, onlyForProduct = true)
|
||||
public abstract class AbstractWebAuthnVirtualTest extends AbstractTestRealmKeycloakTest implements UseVirtualAuthenticators {
|
||||
|
||||
private VirtualAuthenticatorManager virtualAuthenticatorsManager;
|
||||
protected static final String ALL_ZERO_AAGUID = "00000000-0000-0000-0000-000000000000";
|
||||
protected static final String ALL_ONE_AAGUID = "11111111-1111-1111-1111-111111111111";
|
||||
|
||||
private VirtualAuthenticatorManager virtualAuthenticatorManager;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUpVirtualAuthenticator() {
|
||||
this.virtualAuthenticatorsManager = createDefaultVirtualManager(driver, getDefaultAuthenticatorOptions());
|
||||
this.virtualAuthenticatorManager = createDefaultVirtualManager(driver, getDefaultAuthenticatorOptions());
|
||||
clearEventQueue();
|
||||
}
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void removeVirtualAuthenticator() {
|
||||
virtualAuthenticatorsManager.removeAuthenticator();
|
||||
virtualAuthenticatorManager.removeAuthenticator();
|
||||
clearEventQueue();
|
||||
}
|
||||
|
||||
|
@ -55,12 +63,24 @@ public abstract class AbstractWebAuthnVirtualTest extends AbstractTestRealmKeycl
|
|||
return DefaultVirtualAuthOptions.DEFAULT.getOptions();
|
||||
}
|
||||
|
||||
public VirtualAuthenticatorManager getDefaultVirtualAuthManager() {
|
||||
return virtualAuthenticatorsManager;
|
||||
public VirtualAuthenticatorManager getVirtualAuthManager() {
|
||||
return virtualAuthenticatorManager;
|
||||
}
|
||||
|
||||
public void setDefaultVirtualAuthManager(VirtualAuthenticatorManager manager) {
|
||||
this.virtualAuthenticatorsManager = manager;
|
||||
public void setVirtualAuthManager(VirtualAuthenticatorManager manager) {
|
||||
this.virtualAuthenticatorManager = manager;
|
||||
}
|
||||
|
||||
public AbstractWebAuthnRealmUpdater getWebAuthnRealmUpdater() {
|
||||
return isPasswordless() ? new PasswordLessRealmAttributeUpdater(testRealm()) : new WebAuthnRealmAttributeUpdater(testRealm());
|
||||
}
|
||||
|
||||
public String getCredentialType() {
|
||||
return isPasswordless() ? WebAuthnCredentialModel.TYPE_PASSWORDLESS : WebAuthnCredentialModel.TYPE_TWOFACTOR;
|
||||
}
|
||||
|
||||
public boolean isPasswordless() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void clearEventQueue() {
|
||||
|
|
|
@ -27,10 +27,15 @@ import org.keycloak.testsuite.webauthn.authenticators.VirtualAuthenticatorManage
|
|||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.virtualauthenticator.VirtualAuthenticatorOptions;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
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.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT_NFC;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT_USB;
|
||||
|
||||
/**
|
||||
* Test class for VirtualAuthenticatorManager
|
||||
|
@ -44,7 +49,7 @@ public class VirtualAuthenticatorsManagerTest extends AbstractWebAuthnVirtualTes
|
|||
WebDriver driver2;
|
||||
|
||||
@Test
|
||||
public void testAddVirtualAuthenticator() {
|
||||
public void addVirtualAuthenticator() {
|
||||
final VirtualAuthenticatorManager manager = new VirtualAuthenticatorManager(driver);
|
||||
assertThat(manager, notNullValue());
|
||||
|
||||
|
@ -52,23 +57,23 @@ public class VirtualAuthenticatorsManagerTest extends AbstractWebAuthnVirtualTes
|
|||
assertAuthenticatorOptions(authenticator);
|
||||
|
||||
manager.removeAuthenticator();
|
||||
assertThat(manager.getActualAuthenticator(), Matchers.nullValue());
|
||||
assertThat(manager.getCurrent(), Matchers.nullValue());
|
||||
|
||||
authenticator = useDefaultTestingAuthenticator(manager);
|
||||
assertAuthenticatorOptions(authenticator);
|
||||
|
||||
manager.removeAuthenticator();
|
||||
assertThat(manager.getActualAuthenticator(), Matchers.nullValue());
|
||||
assertThat(manager.getCurrent(), Matchers.nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideUsedAuthenticator() {
|
||||
public void overrideUsedAuthenticator() {
|
||||
final VirtualAuthenticatorManager manager = new VirtualAuthenticatorManager(driver);
|
||||
assertThat(manager, notNullValue());
|
||||
|
||||
KcVirtualAuthenticator defaultTesting = useDefaultTestingAuthenticator(manager);
|
||||
assertAuthenticatorOptions(defaultTesting);
|
||||
assertThat(manager.getActualAuthenticator(), is(defaultTesting));
|
||||
assertThat(manager.getCurrent(), is(defaultTesting));
|
||||
|
||||
VirtualAuthenticatorOptions defaultBleOptions = DefaultVirtualAuthOptions.DEFAULT_BLE.getOptions();
|
||||
assertThat(defaultBleOptions, notNullValue());
|
||||
|
@ -77,22 +82,40 @@ public class VirtualAuthenticatorsManagerTest extends AbstractWebAuthnVirtualTes
|
|||
assertThat(defaultBLE, notNullValue());
|
||||
assertAuthenticatorOptions(defaultTesting);
|
||||
|
||||
assertThat(manager.getActualAuthenticator(), is(defaultBLE));
|
||||
assertThat(manager.getActualAuthenticator().getOptions().clone(), is(defaultBleOptions));
|
||||
assertThat(manager.getCurrent(), is(defaultBLE));
|
||||
assertThat(manager.getCurrent().getOptions().clone(), is(defaultBleOptions));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentDriver() {
|
||||
public void differentDriver() {
|
||||
final VirtualAuthenticatorManager manager = new VirtualAuthenticatorManager(driver);
|
||||
assertThat(manager, notNullValue());
|
||||
|
||||
KcVirtualAuthenticator authenticator = useDefaultTestingAuthenticator(manager);
|
||||
assertThat(authenticator, notNullValue());
|
||||
assertThat(manager.getActualAuthenticator(), notNullValue());
|
||||
assertThat(manager.getCurrent(), notNullValue());
|
||||
|
||||
final VirtualAuthenticatorManager manager2 = new VirtualAuthenticatorManager(driver2);
|
||||
assertThat(manager2, notNullValue());
|
||||
assertThat(manager2.getActualAuthenticator(), nullValue());
|
||||
assertThat(manager2.getCurrent(), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleResponsibleAuthOptions() {
|
||||
VirtualAuthenticatorOptions options = DefaultVirtualAuthOptions.DEFAULT_BLE.getOptions();
|
||||
options.setTransport(VirtualAuthenticatorOptions.Transport.NFC);
|
||||
|
||||
final VirtualAuthenticatorManager manager = new VirtualAuthenticatorManager(driver);
|
||||
assertThat(manager, notNullValue());
|
||||
|
||||
manager.useAuthenticator(options);
|
||||
|
||||
assertThat(manager.getCurrent().getOptions().getTransport(), is(VirtualAuthenticatorOptions.Transport.NFC));
|
||||
|
||||
options = DefaultVirtualAuthOptions.DEFAULT_BLE.getOptions();
|
||||
manager.useAuthenticator(options);
|
||||
|
||||
assertThat(manager.getCurrent().getOptions().getTransport(), is(VirtualAuthenticatorOptions.Transport.BLE));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,7 +127,7 @@ public class VirtualAuthenticatorsManagerTest extends AbstractWebAuthnVirtualTes
|
|||
KcVirtualAuthenticator authenticator = manager.useAuthenticator(defaultTestingAuthenticatorOptions());
|
||||
assertThat(authenticator, notNullValue());
|
||||
|
||||
assertThat(manager.getActualAuthenticator(), is(authenticator));
|
||||
assertThat(manager.getCurrent(), is(authenticator));
|
||||
|
||||
return authenticator;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ import org.keycloak.testsuite.webauthn.updaters.WebAuthnRealmAttributeUpdater;
|
|||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -99,15 +100,21 @@ public class WebAuthnRegisterAndLoginTest extends AbstractWebAuthnVirtualTest {
|
|||
@Page
|
||||
protected SelectAuthenticatorPage selectAuthenticatorPage;
|
||||
|
||||
private static final String ALL_ZERO_AAGUID = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation realmRepresentation = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/webauthn/testrealm-webauthn.json"), RealmRepresentation.class);
|
||||
|
||||
List<String> acceptableAaguids = new ArrayList<>();
|
||||
acceptableAaguids.add("00000000-0000-0000-0000-000000000000");
|
||||
acceptableAaguids.add("6d44ba9b-f6ec-2e49-b930-0c8fe920cb73");
|
||||
|
||||
realmRepresentation.setWebAuthnPolicyAcceptableAaguids(acceptableAaguids);
|
||||
|
||||
testRealms.add(realmRepresentation);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ public class WebAuthnErrorTest extends AbstractWebAuthnAccountTest {
|
|||
final int webAuthnCount = webAuthnCredentialType.getUserCredentialsCount();
|
||||
assertThat(webAuthnCount, is(2));
|
||||
|
||||
getWebAuthnManager().getActualAuthenticator().getAuthenticator().removeAllCredentials();
|
||||
getWebAuthnManager().getCurrent().getAuthenticator().removeAllCredentials();
|
||||
|
||||
setUpWebAuthnFlow("webAuthnFlow");
|
||||
logout();
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* 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.registration;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Rule;
|
||||
import org.keycloak.authentication.requiredactions.WebAuthnPasswordlessRegisterFactory;
|
||||
import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory;
|
||||
import org.keycloak.common.util.SecretGenerator;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.AbstractAdminTest;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.RegisterPage;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
import org.keycloak.testsuite.webauthn.pages.WebAuthnErrorPage;
|
||||
import org.keycloak.testsuite.webauthn.pages.WebAuthnRegisterPage;
|
||||
import org.openqa.selenium.virtualauthenticator.Credential;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
@AuthServerContainerExclude(REMOTE)
|
||||
public abstract class AbstractWebAuthnRegisterTest extends AbstractWebAuthnVirtualTest {
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
@Page
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@Page
|
||||
protected RegisterPage registerPage;
|
||||
|
||||
@Page
|
||||
protected WebAuthnRegisterPage webAuthnRegisterPage;
|
||||
|
||||
@Page
|
||||
protected WebAuthnErrorPage webAuthnErrorPage;
|
||||
|
||||
@Page
|
||||
protected AppPage appPage;
|
||||
|
||||
protected static final String USERNAME = "registerUserWebAuthnSuccess";
|
||||
protected static final String PASSWORD = "password";
|
||||
protected static final String EMAIL = "registerUserWebAuthnSuccess@email";
|
||||
|
||||
protected final static String base64EncodedPK =
|
||||
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q"
|
||||
+ "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU"
|
||||
+ "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB";
|
||||
|
||||
protected final static PKCS8EncodedKeySpec privateKey = new PKCS8EncodedKeySpec(Base64.getUrlDecoder().decode(base64EncodedPK));
|
||||
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation realmRepresentation = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/webauthn/testrealm-webauthn.json"), RealmRepresentation.class);
|
||||
|
||||
if (isPasswordless()) {
|
||||
makePasswordlessRequiredActionDefault(realmRepresentation);
|
||||
}
|
||||
|
||||
testRealms.add(realmRepresentation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAfterAbstractKeycloak() {
|
||||
List<UserRepresentation> defaultUser = testRealm().users().search(USERNAME, true);
|
||||
if (defaultUser != null && !defaultUser.isEmpty()) {
|
||||
Response response = testRealm().users().delete(defaultUser.get(0).getId());
|
||||
assertThat(response, notNullValue());
|
||||
assertThat(response.getStatus(), is(204));
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerDefaultWebAuthnUser(boolean promptLabel) {
|
||||
if (promptLabel) {
|
||||
registerDefaultWebAuthnUser();
|
||||
} else {
|
||||
registerDefaultWebAuthnUser(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerDefaultWebAuthnUser(String authenticatorLabel) {
|
||||
registerWebAuthnUser(USERNAME, PASSWORD, EMAIL, authenticatorLabel);
|
||||
}
|
||||
|
||||
protected void registerDefaultWebAuthnUser() {
|
||||
registerDefaultWebAuthnUser(SecretGenerator.getInstance().randomString(24));
|
||||
}
|
||||
|
||||
protected void registerWebAuthnUser(String username, String password, String email, String authenticatorLabel) {
|
||||
loginPage.open();
|
||||
loginPage.clickRegister();
|
||||
|
||||
waitForPageToLoad();
|
||||
registerPage.assertCurrent();
|
||||
registerPage.register("firstName", "lastName", email, username, password, password);
|
||||
|
||||
// User was registered. Now he needs to register WebAuthn credential
|
||||
waitForPageToLoad();
|
||||
webAuthnRegisterPage.assertCurrent();
|
||||
webAuthnRegisterPage.clickRegister();
|
||||
|
||||
if (authenticatorLabel != null) {
|
||||
webAuthnRegisterPage.registerWebAuthnCredential(authenticatorLabel);
|
||||
}
|
||||
}
|
||||
|
||||
protected String displayErrorMessageIfPresent() {
|
||||
if (webAuthnErrorPage.isCurrent()) {
|
||||
final String msg = webAuthnErrorPage.getError();
|
||||
log.info("Error message from Error Page: " + msg);
|
||||
return msg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Credential getDefaultResidentKeyCredential() {
|
||||
byte[] credentialId = {1, 2, 3, 4};
|
||||
byte[] userHandle = {1};
|
||||
return Credential.createResidentCredential(credentialId, "localhost", privateKey, userHandle, 0);
|
||||
}
|
||||
|
||||
protected Credential getDefaultNonResidentKeyCredential() {
|
||||
byte[] credentialId = {1, 2, 3, 4};
|
||||
return Credential.createNonResidentCredential(credentialId, "localhost", privateKey, 0);
|
||||
}
|
||||
|
||||
protected static void makePasswordlessRequiredActionDefault(RealmRepresentation realm) {
|
||||
RequiredActionProviderRepresentation webAuthnProvider = realm.getRequiredActions()
|
||||
.stream()
|
||||
.filter(f -> f.getProviderId().equals(WebAuthnRegisterFactory.PROVIDER_ID))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertThat(webAuthnProvider, notNullValue());
|
||||
|
||||
webAuthnProvider.setEnabled(false);
|
||||
|
||||
RequiredActionProviderRepresentation webAuthnPasswordlessProvider = realm.getRequiredActions()
|
||||
.stream()
|
||||
.filter(f -> f.getProviderId().equals(WebAuthnPasswordlessRegisterFactory.PROVIDER_ID))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertThat(webAuthnPasswordlessProvider, notNullValue());
|
||||
|
||||
webAuthnPasswordlessProvider.setEnabled(true);
|
||||
webAuthnPasswordlessProvider.setDefaultAction(true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.registration;
|
||||
|
||||
import com.webauthn4j.data.AttestationConveyancePreference;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.credential.dto.WebAuthnCredentialData;
|
||||
import org.keycloak.testsuite.webauthn.updaters.AbstractWebAuthnRealmUpdater;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnDataWrapper;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnRealmData;
|
||||
import org.openqa.selenium.virtualauthenticator.Credential;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.models.Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class AttestationConveyanceRegisterTest extends AbstractWebAuthnRegisterTest {
|
||||
|
||||
@Test
|
||||
public void attestationDefaultValue() {
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getAttestationConveyancePreference(), is(DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED));
|
||||
|
||||
registerDefaultWebAuthnUser();
|
||||
displayErrorMessageIfPresent();
|
||||
|
||||
final String credentialType = getCredentialType();
|
||||
|
||||
getTestingClient().server(TEST_REALM_NAME).run(session -> {
|
||||
final WebAuthnDataWrapper dataWrapper = new WebAuthnDataWrapper(session, USERNAME, credentialType);
|
||||
assertThat(dataWrapper, notNullValue());
|
||||
|
||||
final WebAuthnCredentialData data = dataWrapper.getWebAuthnData();
|
||||
assertThat(data, notNullValue());
|
||||
assertThat(data.getAttestationStatementFormat(), is(AttestationConveyancePreference.NONE.getValue()));
|
||||
});
|
||||
}
|
||||
|
||||
@Ignore("invalid cert path")
|
||||
@Test
|
||||
public void attestationConveyancePreferenceNone() {
|
||||
assertAttestationConveyance(true, AttestationConveyancePreference.NONE);
|
||||
}
|
||||
|
||||
@Ignore("invalid cert path")
|
||||
@Test
|
||||
public void attestationConveyancePreferenceIndirect() {
|
||||
assertAttestationConveyance(true, AttestationConveyancePreference.INDIRECT);
|
||||
}
|
||||
|
||||
@Ignore("invalid cert path")
|
||||
@Test
|
||||
public void attestationConveyancePreferenceDirect() {
|
||||
getVirtualAuthManager().useAuthenticator(DEFAULT.getOptions().setHasResidentKey(true).setIsUserConsenting(true).setHasUserVerification(true));
|
||||
assertAttestationConveyance(true, AttestationConveyancePreference.DIRECT);
|
||||
}
|
||||
|
||||
protected void assertAttestationConveyance(boolean shouldSuccess, AttestationConveyancePreference attestation) {
|
||||
Credential credential = getDefaultResidentKeyCredential();
|
||||
|
||||
getVirtualAuthManager().useAuthenticator(getDefaultAuthenticatorOptions().setHasResidentKey(true));
|
||||
getVirtualAuthManager().getCurrent().getAuthenticator().addCredential(credential);
|
||||
|
||||
try (AbstractWebAuthnRealmUpdater updater = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyAttestationConveyancePreference(attestation.getValue())
|
||||
.update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getAttestationConveyancePreference(), is(attestation.getValue()));
|
||||
|
||||
registerDefaultWebAuthnUser(shouldSuccess);
|
||||
displayErrorMessageIfPresent();
|
||||
|
||||
final boolean isErrorCurrent = webAuthnErrorPage.isCurrent();
|
||||
assertThat(isErrorCurrent, is(!shouldSuccess));
|
||||
|
||||
final String credentialType = getCredentialType();
|
||||
|
||||
getTestingClient().server(TEST_REALM_NAME).run(session -> {
|
||||
final WebAuthnDataWrapper dataWrapper = new WebAuthnDataWrapper(session, USERNAME, credentialType);
|
||||
assertThat(dataWrapper, notNullValue());
|
||||
|
||||
final WebAuthnCredentialData data = dataWrapper.getWebAuthnData();
|
||||
assertThat(data, notNullValue());
|
||||
assertThat(data.getAttestationStatementFormat(), is(attestation.getValue()));
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.registration;
|
||||
|
||||
import com.webauthn4j.data.AuthenticatorAttachment;
|
||||
import com.webauthn4j.data.UserVerificationRequirement;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnRealmData;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT_BLE;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT_INTERNAL;
|
||||
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT_USB;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class AuthAttachmentRegisterTest extends AbstractWebAuthnRegisterTest {
|
||||
|
||||
@Test
|
||||
public void authenticatorAttachmentCrossPlatform() {
|
||||
getVirtualAuthManager().useAuthenticator(DEFAULT_USB.getOptions());
|
||||
assertAuthenticatorAttachment(true, AuthenticatorAttachment.CROSS_PLATFORM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatorAttachmentCrossPlatformInternal() {
|
||||
getVirtualAuthManager().useAuthenticator(DEFAULT_INTERNAL.getOptions());
|
||||
assertAuthenticatorAttachment(true, AuthenticatorAttachment.CROSS_PLATFORM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatorAttachmentPlatform() throws IOException {
|
||||
try (Closeable u = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyAuthenticatorAttachment(AuthenticatorAttachment.PLATFORM.getValue())
|
||||
.setWebAuthnPolicyUserVerificationRequirement(UserVerificationRequirement.DISCOURAGED.getValue())
|
||||
.update()) {
|
||||
|
||||
// It shouldn't be possible to register the authenticator
|
||||
getVirtualAuthManager().useAuthenticator(DEFAULT_BLE.getOptions());
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getAuthenticatorAttachment(), is(AuthenticatorAttachment.PLATFORM.getValue()));
|
||||
assertThat(realmData.getUserVerificationRequirement(), is(UserVerificationRequirement.DISCOURAGED.getValue()));
|
||||
|
||||
registerDefaultWebAuthnUser(false);
|
||||
|
||||
webAuthnRegisterPage.assertCurrent();
|
||||
|
||||
webAuthnRegisterPage.clickRegister();
|
||||
|
||||
webAuthnErrorPage.assertCurrent();
|
||||
assertThat(webAuthnErrorPage.getError(), containsString("A request is already pending."));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatorAttachmentPlatformInternal() {
|
||||
getVirtualAuthManager().useAuthenticator(DEFAULT_INTERNAL.getOptions());
|
||||
assertAuthenticatorAttachment(true, AuthenticatorAttachment.PLATFORM);
|
||||
}
|
||||
|
||||
private void assertAuthenticatorAttachment(boolean shouldSuccess, AuthenticatorAttachment attachment) {
|
||||
try (Closeable u = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyAuthenticatorAttachment(attachment.getValue())
|
||||
.update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getAuthenticatorAttachment(), is(attachment.getValue()));
|
||||
|
||||
registerDefaultWebAuthnUser(shouldSuccess);
|
||||
|
||||
displayErrorMessageIfPresent();
|
||||
|
||||
assertThat(webAuthnErrorPage.isCurrent(), is(!shouldSuccess));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.registration;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import com.webauthn4j.data.attestation.authenticator.COSEKey;
|
||||
import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.credential.dto.WebAuthnCredentialData;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnDataWrapper;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnRealmData;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.crypto.Algorithm.ES256;
|
||||
import static org.keycloak.crypto.Algorithm.ES512;
|
||||
import static org.keycloak.crypto.Algorithm.RS256;
|
||||
import static org.keycloak.crypto.Algorithm.RS512;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PubKeySignRegisterTest extends AbstractWebAuthnRegisterTest {
|
||||
|
||||
@Test
|
||||
public void publicKeySignaturesWrong() {
|
||||
assertPublicKeyAlgorithms(false, null, Lists.newArrayList(RS512, ES512));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicKeySignaturesAlternatives() {
|
||||
assertPublicKeyAlgorithms(true, COSEAlgorithmIdentifier.ES256, Lists.newArrayList(ES256, ES512));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicKeySignaturesCorrect() {
|
||||
assertPublicKeyAlgorithms(true, COSEAlgorithmIdentifier.ES256, Collections.singletonList(ES256));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicKeySignaturesRSA() {
|
||||
assertPublicKeyAlgorithms(false, null, Lists.newArrayList(RS256, ES512));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicKeySignaturesEmpty() {
|
||||
assertPublicKeyAlgorithms(true, COSEAlgorithmIdentifier.ES256, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicKeySignaturesNonExisting() {
|
||||
assertPublicKeyAlgorithms(true, COSEAlgorithmIdentifier.ES256, Collections.singletonList("RSSSS2048"));
|
||||
}
|
||||
|
||||
private void assertPublicKeyAlgorithms(boolean shouldSuccess, COSEAlgorithmIdentifier selectedAlgorithm, List<String> algorithms) {
|
||||
assertThat(algorithms, notNullValue());
|
||||
|
||||
try (Closeable u = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicySignatureAlgorithms(algorithms)
|
||||
.update()) {
|
||||
|
||||
if (!algorithms.isEmpty()) {
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getSignatureAlgorithms(), is(algorithms));
|
||||
}
|
||||
|
||||
registerDefaultWebAuthnUser(shouldSuccess);
|
||||
|
||||
assertThat(webAuthnErrorPage.isCurrent(), is(!shouldSuccess));
|
||||
if (!shouldSuccess) {
|
||||
assertThat(webAuthnErrorPage.getError(), containsString("The operation either timed out or was not allowed"));
|
||||
return;
|
||||
}
|
||||
|
||||
final String credentialType = getCredentialType();
|
||||
|
||||
getTestingClient().server(TEST_REALM_NAME).run(session -> {
|
||||
final WebAuthnDataWrapper dataWrapper = new WebAuthnDataWrapper(session, USERNAME, credentialType);
|
||||
assertThat(dataWrapper, notNullValue());
|
||||
|
||||
final WebAuthnCredentialData data = dataWrapper.getWebAuthnData();
|
||||
assertThat(data, notNullValue());
|
||||
|
||||
final COSEKey pubKey = dataWrapper.getKey();
|
||||
assertThat(pubKey, notNullValue());
|
||||
assertThat(pubKey.getAlgorithm(), notNullValue());
|
||||
assertThat(pubKey.getAlgorithm().getValue(), is(selectedAlgorithm.getValue()));
|
||||
assertThat(pubKey.hasPublicKey(), is(true));
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.registration;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.testsuite.webauthn.utils.PropertyRequirement;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnRealmData;
|
||||
import org.openqa.selenium.virtualauthenticator.Credential;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class ResidentKeyRegisterTest extends AbstractWebAuthnRegisterTest{
|
||||
|
||||
@Test
|
||||
public void residentKeyNotRequiredNoRK() {
|
||||
assertResidentKey(true, PropertyRequirement.NO, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void residentKeyNotRequiredPresent() {
|
||||
assertResidentKey(true, PropertyRequirement.NO, true);
|
||||
}
|
||||
|
||||
@Ignore("Not working")
|
||||
@Test
|
||||
public void residentKeyRequiredCorrect() {
|
||||
assertResidentKey(true, PropertyRequirement.YES, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void residentKeyRequiredWrong() {
|
||||
assertResidentKey(false, PropertyRequirement.YES, false);
|
||||
}
|
||||
|
||||
private void assertResidentKey(boolean shouldSuccess, PropertyRequirement requirement, boolean hasResidentKey) {
|
||||
Credential credential;
|
||||
getVirtualAuthManager().useAuthenticator(getDefaultAuthenticatorOptions().setHasResidentKey(hasResidentKey));
|
||||
|
||||
if (hasResidentKey) {
|
||||
credential = getDefaultResidentKeyCredential();
|
||||
} else {
|
||||
credential = getDefaultNonResidentKeyCredential();
|
||||
}
|
||||
|
||||
getVirtualAuthManager().getCurrent().getAuthenticator().addCredential(credential);
|
||||
|
||||
try (Closeable u = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyRequireResidentKey(requirement.getValue())
|
||||
.update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getRequireResidentKey(), containsString(requirement.getValue()));
|
||||
|
||||
registerDefaultWebAuthnUser(shouldSuccess);
|
||||
|
||||
displayErrorMessageIfPresent();
|
||||
|
||||
assertThat(webAuthnErrorPage.isCurrent(), is(!shouldSuccess));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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.registration;
|
||||
|
||||
import com.webauthn4j.data.UserVerificationRequirement;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnRealmData;
|
||||
import org.openqa.selenium.virtualauthenticator.VirtualAuthenticatorOptions;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class UserVerificationRegisterTest extends AbstractWebAuthnRegisterTest {
|
||||
|
||||
@Test
|
||||
public void discouragedAny() {
|
||||
assertUserVerification(true, UserVerificationRequirement.DISCOURAGED,
|
||||
auth -> auth.setHasUserVerification(true).setIsUserVerified(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discouraged() {
|
||||
assertUserVerification(true, UserVerificationRequirement.DISCOURAGED,
|
||||
auth -> auth.setHasUserVerification(true).setIsUserVerified(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discouragedNoVerification() {
|
||||
assertUserVerification(true, UserVerificationRequirement.DISCOURAGED,
|
||||
auth -> auth.setHasUserVerification(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferredNoVerification() {
|
||||
assertUserVerification(true, UserVerificationRequirement.PREFERRED,
|
||||
auth -> auth.setHasUserVerification(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferredVerificationWrong() {
|
||||
assertUserVerification(true, UserVerificationRequirement.PREFERRED,
|
||||
auth -> auth.setHasUserVerification(true).setIsUserVerified(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferredVerificationCorrect() {
|
||||
assertUserVerification(true, UserVerificationRequirement.PREFERRED,
|
||||
auth -> auth.setHasUserVerification(true).setIsUserVerified(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiredWrong() {
|
||||
assertUserVerification(false, UserVerificationRequirement.REQUIRED,
|
||||
auth -> auth.setHasUserVerification(true).setIsUserVerified(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiredWrongNoVerification() {
|
||||
assertUserVerification(false, UserVerificationRequirement.REQUIRED,
|
||||
auth -> auth.setHasUserVerification(false));
|
||||
}
|
||||
|
||||
@Ignore("Not working")
|
||||
@Test
|
||||
public void required() {
|
||||
assertUserVerification(true, UserVerificationRequirement.REQUIRED,
|
||||
auth -> auth.setHasUserVerification(true).setIsUserVerified(true));
|
||||
}
|
||||
|
||||
private void assertUserVerification(boolean shouldSuccess,
|
||||
UserVerificationRequirement requirement,
|
||||
Consumer<VirtualAuthenticatorOptions> authenticator) {
|
||||
VirtualAuthenticatorOptions options = getDefaultAuthenticatorOptions();
|
||||
authenticator.accept(options);
|
||||
getVirtualAuthManager().useAuthenticator(options);
|
||||
WaitUtils.pause(200);
|
||||
|
||||
try (Closeable u = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyUserVerificationRequirement(requirement.getValue())
|
||||
.update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getUserVerificationRequirement(), containsString(requirement.getValue()));
|
||||
|
||||
registerDefaultWebAuthnUser(shouldSuccess);
|
||||
|
||||
displayErrorMessageIfPresent();
|
||||
|
||||
assertThat(webAuthnErrorPage.isCurrent(), is(!shouldSuccess));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.registration;
|
||||
|
||||
import com.webauthn4j.data.AttestationConveyancePreference;
|
||||
import com.webauthn4j.data.attestation.authenticator.COSEKey;
|
||||
import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier;
|
||||
import com.webauthn4j.data.attestation.statement.COSEKeyType;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.WebAuthnConstants;
|
||||
import org.keycloak.authentication.requiredactions.WebAuthnPasswordlessRegisterFactory;
|
||||
import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.credential.dto.WebAuthnCredentialData;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnDataWrapper;
|
||||
import org.keycloak.testsuite.webauthn.utils.WebAuthnRealmData;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.anyOf;
|
||||
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.keycloak.testsuite.util.WaitUtils.pause;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class WebAuthnOtherSettingsTest extends AbstractWebAuthnRegisterTest {
|
||||
|
||||
@Test
|
||||
public void defaultValues() {
|
||||
registerDefaultWebAuthnUser("webauthn");
|
||||
|
||||
WaitUtils.waitForPageToLoad();
|
||||
appPage.assertCurrent();
|
||||
|
||||
String userId = events.expectRegister(USERNAME, EMAIL).assertEvent().getUserId();
|
||||
|
||||
events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, isPasswordless()
|
||||
? WebAuthnPasswordlessRegisterFactory.PROVIDER_ID
|
||||
: WebAuthnRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, "webauthn")
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, ALL_ZERO_AAGUID)
|
||||
.assertEvent();
|
||||
|
||||
final String credentialType = getCredentialType();
|
||||
|
||||
getTestingClient().server(TEST_REALM_NAME).run(session -> {
|
||||
final WebAuthnDataWrapper dataWrapper = new WebAuthnDataWrapper(session, USERNAME, credentialType);
|
||||
assertThat(dataWrapper, notNullValue());
|
||||
|
||||
final WebAuthnCredentialData data = dataWrapper.getWebAuthnData();
|
||||
assertThat(data, notNullValue());
|
||||
assertThat(data.getCredentialId(), notNullValue());
|
||||
assertThat(data.getAaguid(), is(ALL_ZERO_AAGUID));
|
||||
assertThat(data.getAttestationStatement(), nullValue());
|
||||
assertThat(data.getCredentialPublicKey(), notNullValue());
|
||||
assertThat(data.getCounter(), is(1L));
|
||||
assertThat(data.getAttestationStatementFormat(), is(AttestationConveyancePreference.NONE.getValue()));
|
||||
|
||||
final COSEKey pubKey = dataWrapper.getKey();
|
||||
assertThat(pubKey, notNullValue());
|
||||
assertThat(pubKey.getAlgorithm(), notNullValue());
|
||||
assertThat(pubKey.getAlgorithm().getValue(), is(COSEAlgorithmIdentifier.ES256.getValue()));
|
||||
assertThat(pubKey.getKeyType(), is(COSEKeyType.EC2));
|
||||
assertThat(pubKey.hasPublicKey(), is(true));
|
||||
});
|
||||
}
|
||||
|
||||
@Ignore("Individually it works, otherwise not")
|
||||
@Test
|
||||
public void timeout() throws IOException {
|
||||
final Integer TIMEOUT = 3; //seconds
|
||||
|
||||
getVirtualAuthManager().removeAuthenticator();
|
||||
|
||||
try (Closeable u = getWebAuthnRealmUpdater().setWebAuthnPolicyCreateTimeout(TIMEOUT).update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getCreateTimeout(), is(TIMEOUT));
|
||||
|
||||
loginPage.open();
|
||||
loginPage.clickRegister();
|
||||
registerPage.assertCurrent();
|
||||
|
||||
registerPage.register("firstName", "lastName", EMAIL, USERNAME, PASSWORD, PASSWORD);
|
||||
|
||||
// User was registered. Now he needs to register WebAuthn credential
|
||||
webAuthnRegisterPage.assertCurrent();
|
||||
webAuthnRegisterPage.clickRegister();
|
||||
|
||||
pause((TIMEOUT + 2) * 1000);
|
||||
|
||||
webAuthnErrorPage.assertCurrent();
|
||||
assertThat(webAuthnErrorPage.getError(), containsString("The operation either timed out or was not allowed"));
|
||||
|
||||
webAuthnErrorPage.clickTryAgain();
|
||||
waitForPageToLoad();
|
||||
|
||||
webAuthnRegisterPage.assertCurrent();
|
||||
webAuthnRegisterPage.clickRegister();
|
||||
|
||||
assertThat(webAuthnErrorPage.isCurrent(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptableAaguidsShouldBeEmptyOrNullByDefault() {
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getAcceptableAaguids(), anyOf(nullValue(), Matchers.empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excludeCredentials() throws IOException {
|
||||
List<String> acceptableAaguids = Collections.singletonList(ALL_ONE_AAGUID);
|
||||
|
||||
try (Closeable u = getWebAuthnRealmUpdater()
|
||||
.setWebAuthnPolicyAcceptableAaguids(acceptableAaguids)
|
||||
.update()) {
|
||||
|
||||
WebAuthnRealmData realmData = new WebAuthnRealmData(testRealm().toRepresentation(), isPasswordless());
|
||||
assertThat(realmData.getAcceptableAaguids(), Matchers.contains(ALL_ONE_AAGUID));
|
||||
|
||||
registerDefaultWebAuthnUser();
|
||||
|
||||
webAuthnErrorPage.assertCurrent();
|
||||
assertThat(webAuthnErrorPage.getError(), allOf(containsString("not acceptable aaguid"), containsString(ALL_ZERO_AAGUID)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.registration.passwordless;
|
||||
|
||||
import org.keycloak.testsuite.webauthn.registration.AttestationConveyanceRegisterTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PwdLessAttestationRegTest extends AttestationConveyanceRegisterTest {
|
||||
|
||||
@Override
|
||||
public boolean isPasswordless() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.registration.passwordless;
|
||||
|
||||
import org.keycloak.testsuite.webauthn.registration.AuthAttachmentRegisterTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PwdLessAuthAttachmentRegTest extends AuthAttachmentRegisterTest {
|
||||
|
||||
@Override
|
||||
public boolean isPasswordless() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.registration.passwordless;
|
||||
|
||||
import org.keycloak.testsuite.webauthn.registration.WebAuthnOtherSettingsTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PwdLessOtherSettingsTest extends WebAuthnOtherSettingsTest {
|
||||
|
||||
@Override
|
||||
public boolean isPasswordless() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.registration.passwordless;
|
||||
|
||||
import org.keycloak.testsuite.webauthn.registration.PubKeySignRegisterTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PwdLessPubKeySignRegTest extends PubKeySignRegisterTest {
|
||||
|
||||
@Override
|
||||
public boolean isPasswordless() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.registration.passwordless;
|
||||
|
||||
import org.keycloak.testsuite.webauthn.registration.ResidentKeyRegisterTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PwdLessResidentKeyRegTest extends ResidentKeyRegisterTest {
|
||||
|
||||
@Override
|
||||
public boolean isPasswordless() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.registration.passwordless;
|
||||
|
||||
import org.keycloak.testsuite.webauthn.registration.UserVerificationRegisterTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
|
||||
*/
|
||||
public class PwdLessUserVerRegTest extends UserVerificationRegisterTest {
|
||||
|
||||
@Override
|
||||
public boolean isPasswordless() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -22,10 +22,6 @@
|
|||
"webAuthnPolicyRpEntityName": "keycloak-webauthn-2FA",
|
||||
"webAuthnPolicyCreateTimeout": 60,
|
||||
"webAuthnPolicyAvoidSameAuthenticatorRegister": true,
|
||||
"webAuthnPolicyAcceptableAaguids": [
|
||||
"00000000-0000-0000-0000-000000000000",
|
||||
"6d44ba9b-f6ec-2e49-b930-0c8fe920cb73"
|
||||
],
|
||||
"smtpServer": {
|
||||
"from": "auto@keycloak.org",
|
||||
"host": "localhost",
|
||||
|
|
Loading…
Reference in a new issue