Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User backend extendable account searching #27906

Merged
merged 30 commits into from
May 18, 2017
Merged

User backend extendable account searching #27906

merged 30 commits into from
May 18, 2017

Conversation

tomneedham
Copy link
Contributor

Description

Continued from: #27832

Problem

  • In OC9 we allow LDAP users to specify custom search attributes which can be used for finding users to share
  • In OC10 we have the accounts table which is used for searching to reduce the hits to LDAP servers
  • Organisations use these search attributes to help users find other users based on terms they may know (like usernames, emails, staff codes, etc)

Proposed / Implemented Solution

  • Added a new oc_account_terms table with account_id (foreign key to accounts.id) and term columns
  • Altered user manager code to find users using these terms
  • Allow user backends to manipulate these search terms as needed (e.g: LDAP can add these from custom attributes the user configures)

User_LDAP App:

Related Issue

owncloud/user_ldap#96

How Has This Been Tested?

  • Manual testing - needs more 💪
  • Updated unit tests -> still WIP 🚧

Screenshots (if appropriate):

because they make your PR look more cool:
screen shot 2017-05-16 at 15 44 52

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@tomneedham tomneedham added this to the 10.0.1 milestone May 16, 2017
@tomneedham tomneedham changed the title [:construction] User backend extendable account searching :construction User backend extendable account searching May 16, 2017
@tomneedham tomneedham changed the title :construction User backend extendable account searching [WIP] User backend extendable account searching May 16, 2017
@PVince81
Copy link
Contributor

I wonder if this extra table is really necessary. Hitting the LDAP server when someone types in a share search string might be ok especially as it benefits from LDAP specific searching capabilities (and patterns?). If it doesn't work at all with the current core then maybe the sharing code somehow needs a way for apps to provide their user search functions there. I think previously it was one of the user manager's functions, maybe not suitable any more.

The part we want to prevent is doing a search on LDAP for already existing users we already know, by user id or email, which usually happens when setting up FS for received shares.

But since you guys have worked on this already you might have more insights about the reasons this is needed.

@PVince81 PVince81 requested a review from jvillafanez May 16, 2017 15:32
use OCP\AppFramework\Db\Entity;

/**
* Class Account
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AccountTerm

Copy link
Contributor

@PVince81 PVince81 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first look the code looks fine

@butonic
Copy link
Member

butonic commented May 16, 2017

The idea of the account table was to only rely on eg ldap for the login to be able to iterate over all users etc. The code that used to lead to a lot of ldap queries because it would execute pages etc was the search method used when sharing users. But also fetching any other use metadata was triggering ldap queries. Unfortunately, the ldap user bachend allos specifying additional fields that should be taken into account when doing a user search. that might eg be the city or multi value attributes like mailAccounts. That is actually a nice feature. The initial approach does not fit as @tomneedham and I today by chance stumbled over an LDIF entry with 7 email addresses. We were told there were accounts with many more. We came up with the idea of an additional table to hold arbitrary search terms. Another approach would be to add an elasticsearch based framework for this kind of cacheable metadata ... but that is nothing we can add on short notice.

For now I think this is a good approach. We could add a foreign key but did not want to be the first ones to actually use the relevant code. We would have liked to have an ORMapper, but got around it with adding an interface and making the ldap app actively update the search attributes on first login.

@DeepDiver1975
Copy link
Member

Hitting the LDAP server when someone types in a share search string might be ok especially as it benefits from LDAP specific searching capabilities (and patterns?).

this is one major complaint I'm hearing from big installations: searching the ldap takes ages. From an UX pov this is not acceptable.

}
}

public static function fromRow(array $row) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needed?

@@ -65,6 +64,9 @@ class Account extends Entity {
protected $state;
protected $home;

protected $terms = [];
private $_termsChanged = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_ ?? needed ???

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_ to indicate it is used like _updatedFields: tracking if the attribute was changed so the mapper can act accordingly

* @param $account_id
* @param string[] $terms
*/
public function setTermsForAccount($account_id, array $terms) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use Mapper:insert ???

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* Removes all search terms for a given account id
* @param $account_id
*/
public function deleteTermsForAccount($account_id) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use Mapper:delete ???

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want to delete by account_id, not id

@@ -170,7 +176,7 @@ protected function getUserObject(Account $account, $cacheUser = true) {
return $this->cachedUsers[$account->getUserId()];
}

$user = new User($account, $this->accountMapper, $this, $this->config, null, \OC::$server->getEventDispatcher() );
$user = new User($account, $this->accountMapper, $this->accountTermMapper, $this, $this->config, null, \OC::$server->getEventDispatcher() );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the terms mapper necessary inside class User? I'd hide the terms mapper within the account mapper

* @param string $search
* @param int $limit
* @param int $offset
* @return array an array of display names (value) and user ids (key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not the User objects?

/**
* @var \OC\User\Manager $userManager
*/
$userManager = $this->createMock('\OC\User\Manager');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manager:class

* @var \OC\User\Manager $userManager
*/
$userManager = $this->createMock('\OC\User\Manager');
$userBackend = $this->createMock('\OC_User_Backend');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OC_User_Backend::class

@butonic butonic added 3 - To Review app:user_ldap p1-urgent Critical issue, need to consider hotfix with just that issue and removed 2 - Developing labels May 17, 2017
@tomneedham tomneedham changed the title [WIP] User backend extendable account searching User backend extendable account searching May 17, 2017
@butonic butonic requested a review from cdamken May 17, 2017 13:39
@PVince81
Copy link
Contributor

This doesn't work with guest emails (haven't tried generic emails), steps:

  1. Login as admin
  2. Enable guest app
  3. Create folder "test1"
  4. Type "Vince" in share field for "test1", select "Share to guest"
  5. Type in local email address, "vincent@host.tld"
  6. Log out
  7. Open mail, open link and set password
  8. Login as admin again
  9. Create another folder "test2"
  10. Share "test2" with "vincent@host.tld"

Expected: autocomplete finds the guest user "Vince"
Actual: autocomplete doesn't find the user and only offers a "remote" user (due to the format).

This worked on the previous PR.

@tomneedham did you properly include searching by email ? I can see that the oc_accounts column "email" for that guest user contains the correct email address. (and it's unique)

Because searching by email do not require terms to exist.
@PVince81
Copy link
Contributor

Fixed by replacing "inner join" with "left join": 06d7c36

@tomneedham
Copy link
Contributor Author

🤞 for jenkins ;)

@butonic
Copy link
Member

butonic commented May 18, 2017

investigating the index question in #27832 (comment) made me look up how ldap handles it. turns out we have another config option hidden in the code: https://github.com/owncloud/user_ldap/blob/5e2a75bb78f57b8a406467ad48ea68faa856a85d/lib/Access.php#L1368-L1368

It is disabled by default, so we get the same search behavior as with ldap.

we use individual indexes because every db can combine them and they help with getByEmail and getByUid as well.

@tomneedham @DeepDiver1975 @PVince81 please review.

@PVince81
Copy link
Contributor

that option was supposed to be an unsupported experimental feature, do we need it enabled now ?

@PVince81
Copy link
Contributor

@jvillafanez

@@ -205,7 +220,7 @@ public function callForAllUsers($callback, $search, $onlySeen) {
$qb->select(['*'])
->from($this->getTableName());

if ($search) {
if ($search) { // TODO use medial search config option here as well
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something for much later ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well if the medial search was only experimental we can get rid of all the TODOs as well as the config option stuff.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, yeah... if the search is running entirely within OC tables then the option is not useful any more.

It was added for people with special requirements but not default due to perf impact.

@butonic
Copy link
Member

butonic commented May 18, 2017

no we dont need it enabled, but since it was there i assumed someone was using it.

@PVince81 PVince81 merged commit 5330019 into master May 18, 2017
@PVince81 PVince81 deleted the account-terms-table branch May 18, 2017 19:20
@PVince81
Copy link
Contributor

please test extensively in the RC2, thanks

@mrow4a
Copy link
Contributor

mrow4a commented Oct 27, 2017

Hey guys, what was the motivation to add setter and getter of search terms to account https://github.com/owncloud/core/blob/master/lib/private/User/Account.php#L104-L104 ? Is that really needed? I cannot find nowhere in the code sth using it @tomneedham

If you need to search, there is a heavy query joining with terms table, so I wonder why we need in explicitely in the Account class.

@tomneedham
Copy link
Contributor Author

Since our entity ORM stuff doesnt deal with parent/child relationships we had to half bake this in ourselves. When an account is first created it is used to store search terms: https://github.com/owncloud/core/blob/master/lib/private/User/Manager.php#L452 and also when a user is synchronised: https://github.com/owncloud/core/blob/master/lib/private/User/SyncService.php#L174

(but this logic is under a TODO to combine it since it is duplicated)

@tomneedham
Copy link
Contributor Author

group search terms is another idea.....

@lock
Copy link

lock bot commented Aug 2, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Aug 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
3 - To Review p1-urgent Critical issue, need to consider hotfix with just that issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants