Only add the none verifier when attestation conveyance preference is none

Closes #43723


(cherry picked from commit 1bd9a3f4733f80f30111a5e2bad973b85530dc16)

Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
Ricardo Martin 2025-10-28 15:09:09 +01:00 committed by GitHub
parent 334f403653
commit 29eacdd9d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 56 additions and 11 deletions

View File

@ -61,6 +61,7 @@ import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.utils.StringUtil;
import com.webauthn4j.converter.util.ObjectConverter;
import com.webauthn4j.data.AttestationConveyancePreference;
import com.webauthn4j.data.attestation.authenticator.AttestedCredentialData;
import com.webauthn4j.data.attestation.statement.AttestationStatement;
import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier;
@ -72,6 +73,7 @@ import com.webauthn4j.data.RegistrationData;
import com.webauthn4j.data.RegistrationParameters;
import com.webauthn4j.server.ServerProperty;
import com.webauthn4j.util.exception.WebAuthnException;
import com.webauthn4j.verifier.attestation.statement.AttestationStatementVerifier;
import com.webauthn4j.verifier.attestation.statement.androidkey.AndroidKeyAttestationStatementVerifier;
import com.webauthn4j.verifier.attestation.statement.androidsafetynet.AndroidSafetyNetAttestationStatementVerifier;
import com.webauthn4j.verifier.attestation.statement.none.NoneAttestationStatementVerifier;
@ -264,7 +266,7 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
AuthenticatorUtil.logoutOtherSessions(context);
}
WebAuthnRegistrationManager webAuthnRegistrationManager = createWebAuthnRegistrationManager();
WebAuthnRegistrationManager webAuthnRegistrationManager = createWebAuthnRegistrationManager(policy.getAttestationConveyancePreference());
try {
// parse
RegistrationData registrationData = webAuthnRegistrationManager.parse(registrationRequest);
@ -314,22 +316,29 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
* Create WebAuthnRegistrationManager instance
* Can be overridden in subclasses to customize the used attestation validators
*
* @param attestationPreference The attestation selected in the policy
* @return webauthn4j WebAuthnRegistrationManager instance
*/
protected WebAuthnRegistrationManager createWebAuthnRegistrationManager() {
protected WebAuthnRegistrationManager createWebAuthnRegistrationManager(String attestationPreference) {
List<AttestationStatementVerifier> verifiers = new ArrayList<>(6);
if (attestationPreference == null
|| Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED.equals(attestationPreference)
|| AttestationConveyancePreference.NONE.getValue().equals(attestationPreference)) {
verifiers.add(new NoneAttestationStatementVerifier());
}
verifiers.add(new PackedAttestationStatementVerifier());
verifiers.add(new TPMAttestationStatementVerifier());
verifiers.add(new AndroidKeyAttestationStatementVerifier());
verifiers.add(new AndroidSafetyNetAttestationStatementVerifier());
verifiers.add(new FIDOU2FAttestationStatementVerifier());
return new WebAuthnRegistrationManager(
Arrays.asList(
new NoneAttestationStatementVerifier(),
new PackedAttestationStatementVerifier(),
new TPMAttestationStatementVerifier(),
new AndroidKeyAttestationStatementVerifier(),
new AndroidSafetyNetAttestationStatementVerifier(),
new FIDOU2FAttestationStatementVerifier()
), this.certPathtrustVerifier,
verifiers,
this.certPathtrustVerifier,
new DefaultSelfAttestationTrustworthinessVerifier(),
Collections.emptyList(), // Custom Registration Verifier is not supported
new ObjectConverter()
);
);
}
/**

View File

@ -35,7 +35,10 @@ 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.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertTrue;
import static org.keycloak.models.Constants.DEFAULT_WEBAUTHN_POLICY_NOT_SPECIFIED;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
import static org.keycloak.testsuite.webauthn.authenticators.DefaultVirtualAuthOptions.DEFAULT;
/**
@ -92,6 +95,39 @@ public class AttestationConveyanceRegisterTest extends AbstractWebAuthnVirtualTe
}
}
@Test
public void attestationConveyancePreferenceNoneToDirect() throws IOException {
oauth.openLoginForm();
waitForPageToLoad();
loginPage.assertCurrent();
loginPage.clickRegister();
waitForPageToLoad();
registerPage.assertCurrent();
registerPage.register("firstName", "lastName", EMAIL, USERNAME, generatePassword(USERNAME));
// User was registered. Now he needs to register WebAuthn credential
waitForPageToLoad();
webAuthnRegisterPage.assertCurrent();
webAuthnRegisterPage.clickRegister();
try (AbstractWebAuthnRealmUpdater updater = getWebAuthnRealmUpdater()
.setWebAuthnPolicyAttestationConveyancePreference(AttestationConveyancePreference.DIRECT.getValue())
.update()) {
testingClient.testing().disableTruststoreSpi();
assertTrue(webAuthnRegisterPage.isRegisterAlertPresent());
webAuthnRegisterPage.registerWebAuthnCredential("new webauth credential");
// should fail because none is not allowed
webAuthnErrorPage.isCurrent();
assertThat(webAuthnErrorPage.getError(), containsString("AttestationVerifier is not configured to handle the supplied AttestationStatement format 'none'."));
} finally {
testingClient.testing().reenableTruststoreSpi();
}
}
protected void assertAttestationConveyance(boolean shouldSuccess, AttestationConveyancePreference attestation) {
Credential credential = getDefaultResidentKeyCredential();