fix(ldap): load full user fields on login so teams are not wiped#28121
fix(ldap): load full user fields on login so teams are not wiped#28121joaopamaral wants to merge 1 commit into
Conversation
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
5ae71ba to
2da8fef
Compare
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
2da8fef to
2451840
Compare
|
I've tested in openmetadata-service/src/test/java/org/openmetadata/service/security/auth/LdapAuthCompleteFlowTest.java in 1.12.7 but this test file was removed :( |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
There was a problem hiding this comment.
Pull request overview
Fixes an LDAP login data-loss/performance bug in LdapAuthenticator.checkAndCreateUser caused by fetching an existing user with a sparse field set and then persisting it via UserUtil.addOrUpdateUser, which triggers UserUpdater relationship updates (teams/personas/domains/etc.) and can wipe relationships when those fields are null.
Changes:
- Fetch the existing user using a full-field selector (
getFieldsWithUserAuth("*")) instead of onlyid,name,email,roles. - Add an explanatory comment documenting why the full fetch is required to prevent relationship clobbering during the subsequent update.
`LdapAuthenticator.checkAndCreateUser` fetched the existing OpenMetadata
user with only `"id,name,email,roles"`. The subsequent PUT through
`UserUtil.addOrUpdateUser -> userRepository.createOrUpdate` then ran
`UserUpdater.entitySpecificUpdate`, which unconditionally invokes
`updateTeams`, `updatePersonas`, etc. Because the in-memory user had
`teams = null`, `updateTeams` executed
`deleteTo(user, HAS, TEAM) + assignTeams(null)`, which wiped every
manually-assigned team on every LDAP login. The same path wiped
`personas`, `defaultPersona`, `profile`, `domains`, `personaPreferences`,
`authenticationMechanism`, and `isEmailVerified`. The `deleteTo` against
a user with many teams also made login visibly slow.
Switch the fetch to `userRepository.getFieldsWithUserAuth("*")`, matching
the `BasicAuthenticator` path, so the PUT sees the user's full state and
the updater preserves it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2451840 to
f64fbc7
Compare
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
Code Review ✅ Approved 4 resolved / 4 findingsLoads full user fields during LDAP authentication to ensure team and persona associations are preserved on login. No issues found. ✅ 4 resolved✅ Edge Case: Shell quoting in execLdapAdd breaks if LDIF contains quotes
✅ Quality: Method exceeds 15-line limit (testLoginPreservesManuallyAssignedTeams)
✅ Quality: Thread.sleep used for synchronization instead of polling
✅ Quality: Wildcard imports and inline fully-qualified names violate style rules
OptionsDisplay: compact → Showing less information. Comment with these commands to change:
Was this helpful? React with 👍 / 👎 | Gitar |
Summary
LdapAuthenticator.checkAndCreateUserfetched the existing OpenMetadata user with only"id,name,email,roles". The subsequent PUT throughUserUtil.addOrUpdateUser -> userRepository.createOrUpdatethen ranUserUpdater.entitySpecificUpdate, which unconditionally invokesupdateTeams,updatePersonas, etc.Because the in-memory user had
teams = null,updateTeamsexecuted:This wiped every manually-assigned team on every LDAP login. The same path wiped
personas,defaultPersona,profile,domains,personaPreferences,authenticationMechanism, andisEmailVerified. ThedeleteToagainst a user with many teams also made login visibly slow.This PR switches the fetch to
userRepository.getFieldsWithUserAuth("*")— the same callBasicAuthenticatoralready uses — so the PUT sees the user's full state and the updater preserves it.Reproducer
Organizationonly — every manually-assigned team was removed. Login latency scales with N (the number of pre-existing team relationships).After this fix, all manually-assigned teams persist across LDAP logins and login latency no longer scales with team count.
Why this is the right fix
BasicAuthenticatoralready loads the user withgetFieldsWithUserAuth("*"). The LDAP path silently diverged.UserRepository.USER_UPDATE_FIELDSandUserUpdater.entitySpecificUpdateare the source of truth for which fields need to be present on a PUT. Loading them all is the safe, no-special-case fix.Test plan
The original
LdapAuthCompleteFlowTestintegration test class was deleted frommainin #26204 ("Delete Old Integration tests and fix sonar workflow"), so this PR does not add or modify a test in tree.The fix was verified locally against a
1.12.7backport branch using a resurrected version ofLdapAuthCompleteFlowTestwith a newtestLoginPreservesManuallyAssignedTeamsregression case:osixia/openldap:1.5.0testcontainer and switch OM auth to LDAP.TeamRepository.create.UserRepository.createOrUpdate.Before the fix: the assertion fails — the user ends up in
Organizationonly.After the fix: the assertion passes — the three manually-assigned teams persist across the LDAP login. All other tests in the existing flow (
testSuccessfulLoginWithValidCredentials,testFailedLoginWithInvalidPassword,testFailedLoginWithNonExistentUser,testLogout,testAdminPrincipalsGrantsAdminPrivileges,testMultipleLoginAttempts) still pass.I'm happy to add an equivalent test in whatever style the maintainers prefer (unit test with mocks, integration test, etc.) — just let me know.
🤖 Generated with Claude Code