From f4cec9ae357396a3407e240888ac91243ce46013 Mon Sep 17 00:00:00 2001 From: Anna Larch Date: Wed, 3 Jun 2026 09:01:39 +0200 Subject: [PATCH] fix(user_ldap): allow editing profile fields not managed by LDAP canEditProperty() was returning true (editable) when an LDAP attribute was configured for a field, and false when no attribute was configured. This is inverted: a field with an LDAP attribute mapping is owned by LDAP and should not be user-editable, while a field with no mapping is not sourced from LDAP and the user should be free to set it themselves. Fixes profile fields being uneditable for all LDAP users whose admin has not configured attribute mappings for those fields. Assisted-by: ClaudeCode:claude-sonnet-4-6 Signed-off-by: Anna Larch --- apps/user_ldap/lib/User_LDAP.php | 22 ++++++++--------- apps/user_ldap/tests/User_LDAPTest.php | 33 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/apps/user_ldap/lib/User_LDAP.php b/apps/user_ldap/lib/User_LDAP.php index 6a4ba3bf642..e973cbaa503 100644 --- a/apps/user_ldap/lib/User_LDAP.php +++ b/apps/user_ldap/lib/User_LDAP.php @@ -689,17 +689,17 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I return match($property) { // Display name is always set by LDAP IAccountManager::PROPERTY_DISPLAYNAME => false, - IAccountManager::PROPERTY_EMAIL => ((string)$this->access->connection->ldapEmailAttribute !== ''), - IAccountManager::PROPERTY_PHONE => ((string)$this->access->connection->ldapAttributePhone !== ''), - IAccountManager::PROPERTY_WEBSITE => ((string)$this->access->connection->ldapAttributeWebsite !== ''), - IAccountManager::PROPERTY_ADDRESS => ((string)$this->access->connection->ldapAttributeAddress !== ''), - IAccountManager::PROPERTY_FEDIVERSE => ((string)$this->access->connection->ldapAttributeFediverse !== ''), - IAccountManager::PROPERTY_ORGANISATION => ((string)$this->access->connection->ldapAttributeOrganisation !== ''), - IAccountManager::PROPERTY_ROLE => ((string)$this->access->connection->ldapAttributeRole !== ''), - IAccountManager::PROPERTY_HEADLINE => ((string)$this->access->connection->ldapAttributeHeadline !== ''), - IAccountManager::PROPERTY_BIOGRAPHY => ((string)$this->access->connection->ldapAttributeBiography !== ''), - IAccountManager::PROPERTY_BIRTHDATE => ((string)$this->access->connection->ldapAttributeBirthDate !== ''), - IAccountManager::PROPERTY_PRONOUNS => ((string)$this->access->connection->ldapAttributePronouns !== ''), + IAccountManager::PROPERTY_EMAIL => ((string)$this->access->connection->ldapEmailAttribute === ''), + IAccountManager::PROPERTY_PHONE => ((string)$this->access->connection->ldapAttributePhone === ''), + IAccountManager::PROPERTY_WEBSITE => ((string)$this->access->connection->ldapAttributeWebsite === ''), + IAccountManager::PROPERTY_ADDRESS => ((string)$this->access->connection->ldapAttributeAddress === ''), + IAccountManager::PROPERTY_FEDIVERSE => ((string)$this->access->connection->ldapAttributeFediverse === ''), + IAccountManager::PROPERTY_ORGANISATION => ((string)$this->access->connection->ldapAttributeOrganisation === ''), + IAccountManager::PROPERTY_ROLE => ((string)$this->access->connection->ldapAttributeRole === ''), + IAccountManager::PROPERTY_HEADLINE => ((string)$this->access->connection->ldapAttributeHeadline === ''), + IAccountManager::PROPERTY_BIOGRAPHY => ((string)$this->access->connection->ldapAttributeBiography === ''), + IAccountManager::PROPERTY_BIRTHDATE => ((string)$this->access->connection->ldapAttributeBirthDate === ''), + IAccountManager::PROPERTY_PRONOUNS => ((string)$this->access->connection->ldapAttributePronouns === ''), default => true, }; } diff --git a/apps/user_ldap/tests/User_LDAPTest.php b/apps/user_ldap/tests/User_LDAPTest.php index 4720b0a5709..7dd3822e774 100644 --- a/apps/user_ldap/tests/User_LDAPTest.php +++ b/apps/user_ldap/tests/User_LDAPTest.php @@ -1463,4 +1463,37 @@ class User_LDAPTest extends TestCase { $this->assertSame($expected, $this->backend->implementsActions($actionCode)); } + + public static function canEditPropertyProvider(): array { + return [ + // Display name is always managed by LDAP + [\OCP\Accounts\IAccountManager::PROPERTY_DISPLAYNAME, '', false], + [\OCP\Accounts\IAccountManager::PROPERTY_DISPLAYNAME, 'cn', false], + // Fields with no LDAP attribute configured are user-editable + [\OCP\Accounts\IAccountManager::PROPERTY_EMAIL, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_PHONE, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_ROLE, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_HEADLINE, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_BIRTHDATE, '', true], + [\OCP\Accounts\IAccountManager::PROPERTY_PRONOUNS, '', true], + // Fields with an LDAP attribute configured are managed by LDAP, not user-editable + [\OCP\Accounts\IAccountManager::PROPERTY_EMAIL, 'mail', false], + [\OCP\Accounts\IAccountManager::PROPERTY_PHONE, 'telephoneNumber', false], + [\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE, 'labeledURI', false], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider(methodName: 'canEditPropertyProvider')] + public function testCanEditProperty(string $property, string $ldapAttributeValue, bool $expected): void { + $this->connection->expects($this->any()) + ->method('__get') + ->willReturn($ldapAttributeValue); + + $this->assertSame($expected, $this->backend->canEditProperty('uid', $property)); + } }