[OpenID4VCI] Add support for mDoc (#48095) - #48582
Conversation
5def263 to
ebd25d0
Compare
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.forms.ResetPasswordTest#resetPasswordWrongSmtpKeycloak CI - Forms IT (firefox) org.keycloak.testsuite.forms.ResetPasswordTest#resetPasswordKeycloak CI - Forms IT (firefox) |
c3894f2 to
675869c
Compare
IngridPuppet
left a comment
There was a problem hiding this comment.
Hello @dominikschlosser - I've gone through just a tiny part of the PR so far. I hope to send my complete review by Thursday. Thank you for implementing this support for mDoc credentials.
f23ab1b to
eff6546
Compare
IngridPuppet
left a comment
There was a problem hiding this comment.
Hello @dominikschlosser - I went through the entire PR and left a few additional comments. Please could you check them?
f45bc18 to
ccf3a20
Compare
|
@IngridPuppet Thank you very much for your review. I addressed your changes in a second commit so you can follow easier. I will squash them into one commit after successful re-review. Could you please look at it again? |
|
Try ...
for me the format does not show. Neither on additional realms that are created with oid4vci enabled |
|
@tdiesler Thanks i will look into it. |
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.adapter.servlet.SAMLClockSkewAdapterTest#testTokenTimeIsValidKeycloak CI - Adapter IT Strict Cookies org.keycloak.testsuite.adapter.servlet.SAMLClockSkewAdapterTest#testTokenHasExpiredKeycloak CI - Adapter IT Strict Cookies |
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.federation.ldap.LDAPGroupMapperTest#test01_ldapOnlyGroupMappings |
edewit
left a comment
There was a problem hiding this comment.
it's fine from a UI point of view
| if (StringUtil.isNotBlank(credentialModel.getSigningKeyId())) { | ||
| return resolveKeyAlgorithm(keycloakSession, credentialModel.getSigningKeyId()) | ||
| .orElse(fallbackSigningAlgorithm); |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 86 out of 86 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
services/src/main/java/org/keycloak/protocol/oid4vc/model/Claim.java:84
- A client scope can be switched to
mso_mdocwithout revalidating its existing mappers (the issuance path explicitly accounts for this), but metadata generation does not validate the required namespace. A mapper missingmdoc.namespacetherefore gets an unprefixed path fromgetMetadataAttributePath()and is advertised as an invalid mDoc claim, while issuance later rejects the same configuration. Validate the mDoc namespace here and omit or reject invalid mapper metadata consistently.
| List<String> allowedBindingMethods = VCFormat.MSO_MDOC.equals(format) | ||
| ? List.of(CRYPTOGRAPHIC_BINDING_METHOD_COSE_KEY) | ||
| : List.of(CRYPTOGRAPHIC_BINDING_METHOD_JWK); |
| private static Optional<String> resolveKeyAlgorithm(KeycloakSession keycloakSession, String signingKeyId) { | ||
| return keycloakSession.keys() | ||
| .getKeysStream(keycloakSession.getContext().getRealm()) | ||
| .filter(key -> signingKeyId.equals(key.getKid())) | ||
| .findAny() | ||
| .map(KeyWrapper::getAlgorithm); |
IngridPuppet
left a comment
There was a problem hiding this comment.
New updates look good to me. I struggled to identify what changed since last time I reviewed, but could get a superset from adorsys@d889b40. I think it'd help that you keep some history between feedback submissions 😅 Thanks.
|
@rmartinc @mposolda The mDoc community contribution has already gone through community review and received approval. It has also been validated against the OpenID Conformance Test Suite. |
|
To better understand mdoc vs sd-jwt, i created a blog post: https://dominikschlosser.github.io/blog/2026/08/05/credential-formats-eudi-ecosystem.html |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 86 out of 86 changed files in this pull request and generated no new comments.
Suppressed comments (3)
services/src/main/java/org/keycloak/protocol/oid4vc/model/CredentialSigningAlgorithmResolver.java:134
- This validates only that some active key with the same algorithm has a certificate, not that a configured
signingKeyIdidentifies that key. If the selected key lacks a certificate while another ES256 key has one, metadata advertises ES256 but signing still uses the selected key and every issuance fails; validate the exact configured key's status/use/certificate before accepting it.
js/apps/admin-ui/src/utils/useIsFeatureEnabled.ts:18 - The server reports this feature as
OID4VC_MDOC(theProfile.Featureenum name), while this hook compares feature names exactly. WithOID4VC_VCI_MDOC,isMdocEnabledis always false and the Admin UI never exposes the mDoc format even when the feature is enabled.
OpenId4VCIMdoc = "OID4VC_VCI_MDOC",
core/src/main/java/org/keycloak/mdoc/MdocCose.java:54
- RFC 9360 §2 requires
x5chainto be a byte string for one certificate and an array only for two or more certificates. Generated mDoc keys commonly have a single certificate, so always serializing a list produces a non-conformant IssuerAuth that strict wallets may reject.
Map<Integer, List<byte[]>> unprotectedHeader = Collections.singletonMap(
HEADER_X5CHAIN, certificateChain.stream().map(MdocCose::encodeCertificate).collect(Collectors.toList())
);
Signed-off-by: Dominik Schlosser <dominik.schlosser@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 86 out of 86 changed files in this pull request and generated no new comments.
Suppressed comments (2)
services/src/main/java/org/keycloak/protocol/oid4vc/model/CredentialSigningAlgorithmResolver.java:144
- A configured
signingKeyIdis reduced to only its algorithm here, then accepted whenever any active certified key has that algorithm. The signer remains pinned to the original ID (AbstractCredentialSigner.java:53-56), so a missing, disabled, or certificate-less pinned key can still be advertised as usable and every issuance then fails; validate the exact pinned key (including status, signing use, and certificate chain) and do not fall back while retaining an unusable ID.
js/apps/admin-ui/src/utils/useIsFeatureEnabled.ts:18 - The server exposes this feature as
OID4VC_MDOC(Profile.Feature.OID4VC_MDOC, andServerInfoAdminResourceserializesfeature.name()), so this value never matches the enabled feature list. As a result, the admin console hides the mDoc format even when the feature is enabled.
OpenId4VCIMdoc = "OID4VC_VCI_MDOC",
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.federation.ldap.LDAPSearchForUsersPaginationTest#testPaginationorg.keycloak.testsuite.federation.ldap.LDAPUserLoginTest#loginLDAPUserAuthenticationNoneEncryptionStartTLSKeycloak CI - Java Distribution IT (windows-latest - temurin - 21) |
|
This PR has already been reviewed and approved by the SIG member and has been open for over four months. @vaceksimon , @rmartinc : could you please help review and merge the PR when you get a chance? Your help would be greatly appreciated. |
Closes #48095
Adds support for issuance of mDoc credentials.
OID4VCI Conformance Tests passed using mdoc credential_format: