rework the user ldap logic to match the account table#125
Conversation
1b62dad to
fe52c0d
Compare
0d6ff75 to
8d2057e
Compare
|
|
To me, it is cleaner version of the code + adjustment to accounts thing. Looks good in general, just difficult to review 👍 |
|
Tested with master:
|
| * @return string|false with with the name to use in ownCloud or false if unsuccessful | ||
| */ | ||
| private function createAltInternalOwnCloudName($name, $isUser) { | ||
| public function createAltInternalOwnCloudName($name, $isUser) { |
There was a problem hiding this comment.
I'll also need context here.
If this needs to be public I wonder if this function should be here. It would make more sense to move this function to a specialized object.
Although we should move this function to another place, I think it's fine if we can make it private for now.
There was a problem hiding this comment.
separate PR, see lib\User\Manager.php:292:
// FIXME move to a better place, naming related. eg DistinguishedNameUtils
jvillafanez
left a comment
There was a problem hiding this comment.
Still need to review the big diffs
| $this->isAllowed($input->getOption('force')); | ||
| $this->confirmUserIsMapped($uid); | ||
| $exists = $this->backend->userExistsOnLDAP($uid); | ||
| $exists = $this->backend->userExists($uid); |
There was a problem hiding this comment.
Reason for this change? I think originally this was intended to bypass the cache and check directly against the LDAP server.
There was a problem hiding this comment.
The implementation now always talks to LDAP but caches the result per request.
There was a problem hiding this comment.
Actually userExistsOnLdap has been moved to User_LDAP. userExists tries to determine the answer based on the cache in the LDAP UserManager. It will fall back to LDAP just as before.
There was a problem hiding this comment.
Ok, so the redis cache has been removed and we cache the information per request... fair enough 👍
| $username = $this->getAttributeValue($attr, null); | ||
| } | ||
| if ($username === null) { | ||
| $json = @json_encode($this->ldapEntry, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK | JSON_PARTIAL_OUTPUT_ON_ERROR ); |
There was a problem hiding this comment.
I'd rather have a comment here for the @ since error supression isn't common.
| /** | ||
| * @param string $ownCloudUID | ||
| */ | ||
| public function setOwnCloudUID($ownCloudUID) { |
There was a problem hiding this comment.
I'm worried this is the only "set" method here. Is it expected to be changed? Could it be set during the object creation?
There was a problem hiding this comment.
We need to store an already mapped uid somewhere.
There was a problem hiding this comment.
My point is if we can set the value only in the constructor in order to prevent modifications, or we need to modify the value once the object is already constructor.
| } | ||
| } | ||
| if ($quota === null) { | ||
| $quota = 'default'; |
There was a problem hiding this comment.
I think this changed recently to not set the "default" quota in order to avoid being overwritten
| } | ||
|
|
||
| /** | ||
| * @return string |
There was a problem hiding this comment.
I'd comment here what is the expected behavior. I don't expect this method to return the username unless explicitly told.
My expectation is that this method returns null if the displayname can't be fetched, so anyone can fetch the username later if they want. Better to add a comment if this isn't the case
| /** | ||
| * returns the home directory of the user if specified by LDAP settings | ||
| * @return string|null | ||
| * @throws \Exception |
There was a problem hiding this comment.
Comment here when this exception is expected to be thrown.
In addition, we should narrow the exception.
| if (isset($this->ldapEntry['memberof'])) { | ||
| return $this->ldapEntry['memberof']; | ||
| } | ||
| return []; |
There was a problem hiding this comment.
I'd rather return something different because empty result is also a valid result, it would be difficult to distinguish this case and an error case (or if there isn't such entry)
| */ | ||
| private function getAttributeValue($attributeName, $default = null, $trim = true) { | ||
| $attributeName = strtolower($attributeName); // all ldap keys are lowercase | ||
| if (isset($this->ldapEntry[$attributeName][0])) { |
There was a problem hiding this comment.
Should we check for multivalued attributes? We should have a comment just in case.
There was a problem hiding this comment.
no. only search attributes may be multi value. updating phpdoc as well
| * @param $attributeName string | ||
| * @param $default string | ||
| * @param $trim bool don't trim value, eg for binary data | ||
| * @return string|null|mixed |
There was a problem hiding this comment.
Specify when we should expect each data type.
| use OCP\UserInterface; | ||
|
|
||
| class User_Proxy extends Proxy implements IUserBackend, UserInterface, IProvidesExtendedSearchBackend { | ||
| class User_Proxy extends Proxy implements IUserBackend, UserInterface, IProvidesQuotaBackend, IProvidesExtendedSearchBackend, IProvidesEMailBackend { |
There was a problem hiding this comment.
I'm forced to complain about the massive interface implementation here, but no change needed for now because it will require quite huge changes, and not just here.
There was a problem hiding this comment.
The app used to update core itself, which is not the way it shoud be. This PR just corrects that by removing the related code and implementing the interfaces to get the correct behavior.
| @@ -25,6 +26,9 @@ | |||
| namespace OCA\User_LDAP; | |||
|
|
|||
| abstract class LDAPUtility { | |||
There was a problem hiding this comment.
We should review the usage if this class because right now I think it's quite pointless. Probably we can remove it.
| /** | ||
| * returns the Connection instance | ||
| * @return \OCA\User_LDAP\ILDAPWrapper | ||
| */ |
There was a problem hiding this comment.
Is this function used outside of the class? I'm fine to use this function as a shortcut but also private. Making it public would open new dependencies between components which doesn't seem a good idea.
| $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20); | ||
|
|
||
| return strtoupper($hex_guid_to_guid_str); | ||
| public static function binGUID2str($binGuid) { |
There was a problem hiding this comment.
Any reason to use static methods here? I'd rather move this function to a helper object and inject it in the constructor. This way we have this function outside if this class (I don't think this is needed to be here), and also make the function testeable.
| * @return string | ||
| */ | ||
| public function convertSID2Str($sid) { | ||
| public static function sid2str($sid) { |
| * The nsuniqueid values are generated based on the entryuuid value by moving the "-" to comply with the format of the ODSEE Nsuniqueid Virtual Attribute attribute. | ||
| * | ||
| * ## RedHat FreeIPA is defined as utf string | ||
| * {@link https://github.com/freeipa/freeipa/blob/master/install/share/uuid.ldif ipaUniqueID schema} |
There was a problem hiding this comment.
👏
Really greatful for this references. Just this one should be an official redhat link. No need to do this now anyway.
| * | ||
| * @package OCA\User_LDAP | ||
| */ | ||
| class User_LDAP implements IUserBackend, UserInterface { |
There was a problem hiding this comment.
I wonder if this class should implement these interfaces. It should be oriented to implement them so the User_Proxy class is easier to implement but other than that, the interfaces will be implemented by the User_Proxy.
| $user = $this->access->userManager->get($uid); | ||
| if(!$user instanceof User) { | ||
| $user = $this->userManager->getByOwnCloudUID($uid); | ||
| if(!$user instanceof UserEntry) { |
There was a problem hiding this comment.
According to the PHPDocs, the method returns a UserEntry or null. I'd change this to check against null because otherwise it seems that other type of objects can be returned by that function.
There was a problem hiding this comment.
getByOwnCloudUID now always returns a UserEntry
There was a problem hiding this comment.
or throws an exception
There was a problem hiding this comment.
so we can remove that check (or use a try-catch for the exception instead)
| * Get a users email address | ||
| * | ||
| * @param string $uid The username | ||
| * @return string|null|false false if user was not found, null if no email is set |
| * FIXME This is an expensive operation and takes roughly half a second to parse the data and create the image. This might be too slow for sync jobs. | ||
| * | ||
| * @param string $uid The username | ||
| * @return IImage|null|false |
There was a problem hiding this comment.
Need to specify each possible cases
| /** | ||
| * Get avatar for a users account for core powered user search | ||
| * | ||
| * FIXME This is an expensive operation and takes roughly half a second to parse the data and create the image. This might be too slow for sync jobs. |
There was a problem hiding this comment.
Side question for the future: is it possible to store the raw image data (I think it's base64 encoded) and compare the data we have and the data we receive, and then create the image if the data is different? I'm not sure if it will improve the performance, but it might be worthy to have a try.
|
Review finished from my part. I think most of them are easy to solve, and the rest might be moved to tech debt if they're too complex to manage in this PR. |
|
bug here with user sync, suggested arribute is not found when it is present: https://github.com/owncloud/enterprise/issues/2275 |
76dccbe to
602c16e
Compare
|
Rebased to include some other fixes and the tests should now run |
|
"0" quota is recorded in the accounts table as NULL => correct or not? |
| if($userEntry === null) { | ||
| try { | ||
| $this->userManager->getCachedEntry($uid); | ||
| } catch (\Exception $e) { |
|
This mornings commit fixes the sync issue I found. |
…to getCachedEntry
…ption to trigger the fetching from ldap
…etrieve a results which was not cached and return null.
…w takes array of attributes
3ddbc28 to
c9ed34f
Compare
|
Rebased + pushed a test. Will wait for CI. Then build test tarball which we can share round as a beta release 🎉 |
|
Ideas for performance comparisons for release:
|
|
Merging, next up testing with large installations before release |


I am sick of our ldap problems. The app is heavily used, yet undertested and quirky at best. It grew over time but its purpose changes with the introduction of the Account table in OC10.
requires owncloud/core#28729 to make the user sync correctly update quota and email
yes, I am ripping this apart and putting it together anew. I don't care about the ui. I need the underlying sync logic to work reliably AND the code to be readable. That means not trying to be smart and use less reflection ...