[OID4VCI] User-editable did attribute used as credential subject with realm-local uniqueness only - #51221
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Removes DID-specific handling from OID4VCI issuance by eliminating DID utilities/validators and switching subject identifier mapping away from a DID-focused user attribute.
Changes:
- Deleted DID-related utility/validator code and corresponding test coverage.
- Removed automatic “did” user-profile attribute injection and validator SPI registration.
- Changed OID4VC subject-id mapping defaults in factories/tests (now mapped to username in the reviewed hunks).
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCUserDidAttributeTest.java | Removes DID-specific integration tests. |
| tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java | Stops seeding users with did and remaps subject-id mapper input to username. |
| tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerEndpointTest.java | Removes test-time injection of a DID attribute + validators into user profile config. |
| tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCINaturalPersonTest.java | Updates expected subject identifier value from DID to username. |
| services/src/main/resources/META-INF/services/org.keycloak.validate.ValidatorFactory | Removes DuplicateDidValidator service registration. |
| services/src/main/java/org/keycloak/userprofile/DeclarativeUserProfileProviderFactory.java | Removes VC-enabled DID attribute injection and associated validation logic. |
| services/src/main/java/org/keycloak/protocol/oid4vc/userprofile/DuplicateDidValidator.java | Deletes the DID-uniqueness validator implementation. |
| services/src/main/java/org/keycloak/protocol/oid4vc/issuance/mappers/OID4VCSubjectIdMapper.java | Removes DID from selectable options and changes default to username. |
| services/src/main/java/org/keycloak/protocol/oid4vc/OID4VCLoginProtocolFactory.java | Changes built-in subject-id mapper default from DID to username. |
| server-spi/src/main/java/org/keycloak/models/UserModel.java | Removes the DID attribute constant from the public SPI. |
| core/src/main/java/org/keycloak/util/DIDUtils.java | Deletes DID encoding/decoding utilities. |
| core/src/main/java/org/keycloak/OID4VCConstants.java | Removes DID-specific wording from subject-id constant documentation. |
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.broker.KcOidcBrokerTest#loginWithExistingUserWithBruteForceEnabledKeycloak CI - Java Distribution IT (windows-latest - temurin - 21) |
ebca0f6 to
264b0f2
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
services/src/main/java/org/keycloak/protocol/oid4vc/issuance/mappers/OID4VCSubjectIdMapper.java:102
- The class-level Javadoc still describes a default user-editable
didattribute and DID-based authorization flow, but this configuration now defaults tousernameand no longer creates that profile attribute. Please update the mapper documentation so it no longer advertises the removed DID-specific behavior.
userAttributeConfig.setOptions(List.of(UserModel.USERNAME, UserModel.EMAIL, UserModel.ID));
userAttributeConfig.setDefaultValue(UserModel.USERNAME);
tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java:734
- Removing these
didvalues leaves the JWT credential scope without a subject identifier:test-credential-mappers.jsonstill configures itsoid4vc-subject-id-mapperwithuserAttribute: "did". Consequently the JWT issuance tests now exercise credentials with no mappedid/sub; update that mapper fixture tousernametogether with this data change.
realm.users(createUser("John Doe", Map.of(), List.of(), Collections.emptyMap()));
realm.users(createUser("Alice Wonderland", Map.of(), List.of(), Map.of()));
It must be some funky side-effect from removing the did attribute. It is this code in the test case that works in main, but fails in the PR So it seems that the user update does no longer work. |
264b0f2 to
9bc5fc2
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 36 out of 36 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
services/src/main/java/org/keycloak/services/resources/admin/UserResource.java:224
- This also excludes
locale, but unlike the other root attributes, locale has no top-level field inUserRepresentation. When an update omitsattributes, the profile normalizes the missing editable locale to an empty value andprofile.update(false)removes the user's existing locale; preserve locale in this merge while filtering the top-level root fields.
if (!UserProfileUtil.isRootAttribute(entry.getKey())) {
attributes.putIfAbsent(entry.getKey(), entry.getValue());
}
9bc5fc2 to
5498528
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 37 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
services/src/main/java/org/keycloak/services/resources/admin/UserResource.java:223
- When
attributesand top-level profile fields are omitted in a partial update,getRawAttributes()does not supply those fields. Skipping the user's current root attributes therefore normalizes editable email/name/locale fields to empty, so credential-only updates can clear unrelated profile data or fail required-field validation; the changed hashed-credential test now fetches the full representation and masks this established partial-update path.
// account the existing attributes associated with the user. Root attributes (username, email,
// firstName, lastName, locale) are already handled by getRawAttributes() via top-level fields.
for (Map.Entry<String, List<String>> entry : user.getAttributes().entrySet()) {
if (!UserProfileUtil.isRootAttribute(entry.getKey())) {
attributes.putIfAbsent(entry.getKey(), entry.getValue());
5498528 to
5fe6cd0
Compare
mposolda
left a comment
There was a problem hiding this comment.
@tdiesler I think it should be possible to fix the OID4VCI test failures without a need to change core user-profile logic in classes like AbstractUserRepresentation or UserResource . As you can see, there are other test failures now and changes in those classes might be backwards incompatible... I suppose the root cause of OID4VCI test failures after removal of did is somewhere else (scoped within OID4VCI)...?
5fe6cd0 to
928ebcf
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 37 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
server-spi-private/src/main/java/org/keycloak/userprofile/DefaultUserProfile.java:298
- This changes the established user-representation contract from
nullto{}when no attributes remain. Existing tests explicitly requirenullafter attributes are removed (for exampletests/base/src/test/java/org/keycloak/tests/admin/user/UserAttributesTest.java:132andDeclarativeUserTest.java:127-137), so this causes unrelated test failures and an Admin REST response compatibility change.
rep.setAttributes(attributesRep);
928ebcf to
72d84eb
Compare
It seems to be related to null vs. empty map of user attributes. This workaround in OID4VCAuthorizationCodeFlowTestBase fixes it (for that test case) |
72d84eb to
373cd7c
Compare
… realm-local uniqueness only Closes keycloak#50524 Signed-off-by: Thomas Diesler <tdiesler@proton.me> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Remove DID-specific support from OID4VCI, treating the subject identifier as a plain user attribute with realm-local uniqueness only. Deleted (bulk of the change — 497 lines removed): - DIDUtils.java — Entire utility class for DID encoding/decoding (did:key for P-256/ES256, multibase/multicodec/base58btc). Gone. - DuplicateDidValidator.java — Custom validator that enforced DID-format uniqueness on user attributes. Gone. - OID4VCUserDidAttributeTest.java — Tests for the DID user attribute behavior. Gone. - ValidatorFactory SPI entry — Removed the DuplicateDidValidator service registration. Modified: - OID4VCConstants.java — Removed the comment "Would in most cases be the subject's DID" from the CLAIM_NAME_SUBJECT_ID constant. - DeclarativeUserProfileProviderFactory.java — Removed the automatic registration of a did user attribute with the DuplicateDidValidator. The factory no longer injects DID-specific profile configuration. - OID4VCLoginProtocolFactory.java — Changed the subject ID mapper from did to subjectId as the mapped user attribute. - OID4VCSubjectIdMapper.java — Same rename: reads subjectId attribute instead of did. - UserModel.java — Removed the ATTR_DID constant. - Test files — Updated tests to use subjectId instead of did, removed DID-specific test scenarios. In essence: The credential subject identifier is no longer assumed to be a DID. It's now a generic subjectId user attribute with no special format validation — just realm-local uniqueness via standard mechanisms.
373cd7c to
9532c13
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.webauthn.WebAuthnPropertyTest#timeout |
Closes #50524
Signed-off-by: Thomas Diesler tdiesler@proton.me
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com
Remove DID-specific support from OID4VCI, treating the subject identifier as a plain user attribute with realm-local uniqueness only.
Deleted (bulk of the change — 497 lines removed):
Modified:
In essence:
The credential subject identifier is no longer assumed to be a DID. It's now a generic subjectId user attribute with no special format validation — just realm-local
uniqueness via standard mechanisms.