diff options
author | Arthur Schiwon <blizzz@owncloud.com> | 2014-03-27 18:01:14 +0100 |
---|---|---|
committer | Arthur Schiwon <blizzz@owncloud.com> | 2014-06-03 12:59:09 +0200 |
commit | 6d64d7ec3fb64d6b2f196d4008f59b64e5a50446 (patch) | |
tree | 830c0d7dc3c9b4feb10f261d2e41df8061296062 /apps/user_ldap/lib | |
parent | d3e830e938fe85da2fd6d9912c26677034d952f7 (diff) | |
download | nextcloud-server-6d64d7ec3fb64d6b2f196d4008f59b64e5a50446.tar.gz nextcloud-server-6d64d7ec3fb64d6b2f196d4008f59b64e5a50446.zip |
LDAP: put out fetching of user meta data into a fully tested class of its own and update them (mail, quota, etc.) directly after mapping. Fixes #7785 properly on master
Diffstat (limited to 'apps/user_ldap/lib')
-rw-r--r-- | apps/user_ldap/lib/access.php | 33 | ||||
-rw-r--r-- | apps/user_ldap/lib/filesystemhelper.php | 46 | ||||
-rw-r--r-- | apps/user_ldap/lib/logwrapper.php | 39 | ||||
-rw-r--r-- | apps/user_ldap/lib/proxy.php | 15 | ||||
-rw-r--r-- | apps/user_ldap/lib/user/iusertools.php | 35 | ||||
-rw-r--r-- | apps/user_ldap/lib/user/manager.php | 161 | ||||
-rw-r--r-- | apps/user_ldap/lib/user/user.php | 320 |
7 files changed, 639 insertions, 10 deletions
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index 78de14f4ee9..b952910a8c5 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -27,20 +27,21 @@ namespace OCA\user_ldap\lib; * Class Access * @package OCA\user_ldap\lib */ -class Access extends LDAPUtility { +class Access extends LDAPUtility implements user\IUserTools { public $connection; + public $userManager; //never ever check this var directly, always use getPagedSearchResultState protected $pagedSearchedSuccessful; protected $cookies = array(); - /** - * @param Connection $connection - * @param ILDAPWrapper $ldap - */ - public function __construct(Connection $connection, ILDAPWrapper $ldap) { + + public function __construct(Connection $connection, ILDAPWrapper $ldap, + user\Manager $userManager) { parent::__construct($ldap); $this->connection = $connection; + $this->userManager = $userManager; + $this->userManager->setLdapAccess($this); } /** @@ -51,9 +52,17 @@ class Access extends LDAPUtility { } /** - * reads a given attribute for an LDAP record identified by a DN - * @param string $dn the record in question - * @param string $attr the attribute that shall be retrieved + * @brief returns the Connection instance + * @return \OCA\user_ldap\lib\Connection + */ + public function getConnection() { + return $this->connection; + } + + /** + * @brief reads a given attribute for an LDAP record identified by a DN + * @param $dn the record in question + * @param $attr the attribute that shall be retrieved * if empty, just check the record's existence * @param string $filter * @return array|false an array of values on success or an empty @@ -626,6 +635,12 @@ class Access extends LDAPUtility { return false; } + if($isUser) { + //make sure that email address is retrieved prior to login, so user + //will be notified when something is shared with him + $this->userManager->get($ocname)->update(); + } + return true; } diff --git a/apps/user_ldap/lib/filesystemhelper.php b/apps/user_ldap/lib/filesystemhelper.php new file mode 100644 index 00000000000..d85173c1f96 --- /dev/null +++ b/apps/user_ldap/lib/filesystemhelper.php @@ -0,0 +1,46 @@ +<?php + +/** + * ownCloud – LDAP FilesystemHelper + * + * @author Arthur Schiwon + * @copyright 2014 Arthur Schiwon blizzz@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\user_ldap\lib; + +/** + * @brief wraps around static ownCloud core methods + */ +class FilesystemHelper { + + /** + * @brief states whether the filesystem was loaded + * @return bool + */ + public function isLoaded() { + return \OC\Files\Filesystem::$loaded; + } + + /** + * @brief initializes the filesystem for the given user + * @param string the ownCloud username of the user + */ + public function setup($uid) { + \OC_Util::setupFS($uid); + } +}
\ No newline at end of file diff --git a/apps/user_ldap/lib/logwrapper.php b/apps/user_ldap/lib/logwrapper.php new file mode 100644 index 00000000000..2d30e0586cc --- /dev/null +++ b/apps/user_ldap/lib/logwrapper.php @@ -0,0 +1,39 @@ +<?php + +/** + * ownCloud – LDAP LogWrapper + * + * @author Arthur Schiwon + * @copyright 2014 Arthur Schiwon blizzz@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\user_ldap\lib; + +/** + * @brief wraps around static ownCloud core methods + */ +class LogWrapper { + protected $app = 'user_ldap'; + + /** + * @brief states whether the filesystem was loaded + * @return bool + */ + public function log($msg, $level) { + \OCP\Util::writeLog($this->app, $msg, $level); + } +}
\ No newline at end of file diff --git a/apps/user_ldap/lib/proxy.php b/apps/user_ldap/lib/proxy.php index d15d1ae8616..73a52a7ddd9 100644 --- a/apps/user_ldap/lib/proxy.php +++ b/apps/user_ldap/lib/proxy.php @@ -41,8 +41,21 @@ abstract class Proxy { * @param string $configPrefix */ private function addAccess($configPrefix) { + static $ocConfig; + static $fs; + static $log; + static $avatarM; + if(is_null($fs)) { + $ocConfig = \OC::$server->getConfig(); + $fs = new FilesystemHelper(); + $log = new LogWrapper(); + $avatarM = \OC::$server->getAvatarManager(); + } + $userManager = + new user\Manager($ocConfig, $fs, $log, $avatarM, new \OCP\Image()); $connector = new Connection($this->ldap, $configPrefix); - self::$accesses[$configPrefix] = new Access($connector, $this->ldap); + self::$accesses[$configPrefix] = + new Access($connector, $this->ldap, $userManager); } /** diff --git a/apps/user_ldap/lib/user/iusertools.php b/apps/user_ldap/lib/user/iusertools.php new file mode 100644 index 00000000000..248c975c976 --- /dev/null +++ b/apps/user_ldap/lib/user/iusertools.php @@ -0,0 +1,35 @@ +<?php + +/** + * ownCloud – LDAP User + * + * @author Arthur Schiwon + * @copyright 2014 Arthur Schiwon blizzz@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\user_ldap\lib\user; + +interface IUserTools { + public function getConnection(); + + public function readAttribute($dn, $attr, $filter = 'objectClass=*'); + + public function dn2username($dn, $ldapname = null); + + public function username2dn($name); + +} diff --git a/apps/user_ldap/lib/user/manager.php b/apps/user_ldap/lib/user/manager.php new file mode 100644 index 00000000000..1849e86e8c8 --- /dev/null +++ b/apps/user_ldap/lib/user/manager.php @@ -0,0 +1,161 @@ +<?php + +/** + * ownCloud – LDAP User + * + * @author Arthur Schiwon + * @copyright 2014 Arthur Schiwon blizzz@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\user_ldap\lib\user; + +use OCA\user_ldap\lib\user\IUserTools; +use OCA\user_ldap\lib\user\User; +use OCA\user_ldap\lib\LogWrapper; +use OCA\user_ldap\lib\FilesystemHelper; + +class Manager { + /** + * @var IUserTools + */ + protected $access; + /** + * @var \OCP\IConfig + */ + protected $ocConfig; + /** + * @var FilesystemHelper + */ + protected $ocFilesystem; + /** + * @var LogWrapper + */ + protected $ocLog; + /** + * @var \OCP\Image + */ + protected $image; + /** + * @param \OCP\IAvatarManager + */ + protected $avatarManager; + /** + * @var string[][] + */ + protected $users = array( + 'byDN' => array(), + 'byUid' => array(), + ); + + /** + * @brief Constructor + * @param \OCP\IConfig respectively an instance that provides the methods + * setUserValue and getUserValue as implemented in \OCP\Config + * @param \OCA\user_ldap\lib\FilesystemHelper object that gives access to + * necessary functions from the OC filesystem + * @param \OCA\user_ldap\lib\LogWrapper + * @param \OCP\IAvatarManager + * @param \OCP\Image an empty image instance + * @throws Exception when the methods mentioned above do not exist + */ + public function __construct(\OCP\IConfig $ocConfig, + FilesystemHelper $ocFilesystem, LogWrapper $ocLog, + \OCP\IAvatarManager $avatarManager, \OCP\Image $image) { + + if(!method_exists($ocConfig, 'setUserValue') + || !method_exists($ocConfig, 'getUserValue')) { + throw new \Exception('Invalid ownCloud User Config object'); + } + $this->ocConfig = $ocConfig; + $this->ocFilesystem = $ocFilesystem; + $this->ocLog = $ocLog; + $this->avatarManager = $avatarManager; + $this->image = $image; + } + + /** + * @brief binds manager to an instance of IUserTools (implemented by + * Access). It needs to be assigned first before the manager can be used. + * @param IUserTools + */ + public function setLdapAccess(IUserTools $access) { + $this->access = $access; + } + + /** + * @brief creates an instance of User and caches (just runtime) it in the + * property array + * @param string the DN of the user + * @param string the internal (owncloud) username + * @return \OCA\user_ldap\lib\User + */ + private function createAndCache($dn, $uid) { + $this->checkAccess(); + $user = new User($uid, $dn, $this->access, $this->ocConfig, + $this->ocFilesystem, clone $this->image, $this->ocLog, + $this->avatarManager); + $users['byDN'][$dn] = $user; + $users['byUid'][$uid] = $user; + return $user; + } + + /** + * @brief checks whether the Access instance has been set + * @throws Exception if Access has not been set + * @return null + */ + private function checkAccess() { + if(is_null($this->access)) { + throw new \Exception('LDAP Access instance must be set first'); + } + } + + /** + * @brief returns a User object by it's DN or ownCloud username + * @param string the DN or username of the user + * @return \OCA\user_ldap\lib\User | null + */ + public function get($id) { + $this->checkAccess(); + if(isset($this->users['byDN'][$id])) { + return $this->users['byDN'][$id]; + } else if(isset($this->users['byUid'][$id])) { + return $this->users['byUid'][$id]; + } + + if(strpos($id, 'dc=') === false) { + //most likely a uid + $dn = $this->access->username2dn($id); + if($dn !== false) { + return $this->createAndCache($dn, $id); + } + } else { + //so it's a DN + $uid = $this->access->dn2username($id); + if($uid !== false) { + return $this->createAndCache($id, $uid); + } + } + //either funny uid or invalid. Assume funny to be on the safe side. + $dn = $this->access->username2dn($id); + if($dn !== false) { + return $this->createAndCache($dn, $id); + } + return null; + } + +}
\ No newline at end of file diff --git a/apps/user_ldap/lib/user/user.php b/apps/user_ldap/lib/user/user.php new file mode 100644 index 00000000000..91417dbae6c --- /dev/null +++ b/apps/user_ldap/lib/user/user.php @@ -0,0 +1,320 @@ +<?php + +/** + * ownCloud – LDAP User + * + * @author Arthur Schiwon + * @copyright 2014 Arthur Schiwon blizzz@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\user_ldap\lib\user; + +use OCA\user_ldap\lib\user\IUserTools; +use OCA\user_ldap\lib\Connection; +use OCA\user_ldap\lib\FilesystemHelper; +use OCA\user_ldap\lib\LogWrapper; + +class User { + /** + * @var IUserTools + */ + protected $access; + /** + * @var Connection + */ + protected $connection; + /** + * @var \OCP\IConfig + */ + protected $config; + /** + * @var FilesystemHelper + */ + protected $fs; + /** + * @var \OCP\Image + */ + protected $image; + /** + * @var LogWrapper + */ + protected $log; + /** + * @var \OCP\IAvatarManager + */ + protected $avatarManager; + + /** + * @var string + */ + protected $dn; + /** + * @var string + */ + protected $uid; + /** + * @var string[] + */ + protected $refreshedFeatures = array(); + /** + * @var string + */ + protected $avatarImage; + + /** + * DB config keys for user preferences + */ + const USER_PREFKEY_FIRSTLOGIN = 'firstLoginAccomplished'; + const USER_PREFKEY_LASTREFRESH = 'lastFeatureRefresh'; + + /** + * @brief constructor, make sure the subclasses call this one! + * @param string the internal username + * @param string the LDAP DN + * @param IUserTools $access an instance that implements IUserTools for + * LDAP interaction + * @param \OCP\Config + * @param FilesystemHelper + * @param \OCP\Image any empty instance + * @param LogWrapper + * @param \OCP\IAvatarManager + */ + public function __construct($username, $dn, IUserTools $access, + \OCP\IConfig $config, FilesystemHelper $fs, \OCP\Image $image, + LogWrapper $log, \OCP\IAvatarManager $avatarManager) { + + $this->access = $access; + $this->connection = $access->getConnection(); + $this->config = $config; + $this->fs = $fs; + $this->dn = $dn; + $this->uid = $username; + $this->image = $image; + $this->log = $log; + $this->avatarManager = $avatarManager; + } + + /** + * @brief updates properties like email, quota or avatar provided by LDAP + * @return null + */ + public function update() { + if(is_null($this->dn)) { + return null; + } + + $hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap', + self::USER_PREFKEY_FIRSTLOGIN, 0); + + if($this->needsRefresh()) { + $this->updateEmail(); + $this->updateQuota(); + if($hasLoggedIn !== 0) { + //we do not need to try it, when the user has not been logged in + //before, because the file system will not be ready. + $this->updateAvatar(); + //in order to get an avatar as soon as possible, mark the user + //as refreshed only when updating the avatar did happen + $this->markRefreshTime(); + } + } + } + + /** + * @brief returns the LDAP DN of the user + * @return string + */ + public function getDN() { + return $this->dn; + } + + /** + * @brief returns the ownCloud internal username of the user + * @return string + */ + public function getUsername() { + return $this->uid; + } + + /** + * @brief reads the image from LDAP that shall be used as Avatar + * @return string data (provided by LDAP) | false + */ + public function getAvatarImage() { + if(!is_null($this->avatarImage)) { + return $this->avatarImage; + } + + $this->avatarImage = false; + $attributes = array('jpegPhoto', 'thumbnailPhoto'); + foreach($attributes as $attribute) { + $result = $this->access->readAttribute($this->dn, $attribute); + if($result !== false && is_array($result) && isset($result[0])) { + $this->avatarImage = $result[0]; + break; + } + } + + return $this->avatarImage; + } + + /** + * @brief marks the user as having logged in at least once + * @return null + */ + public function markLogin() { + $this->config->setUserValue( + $this->uid, 'user_ldap', self::USER_PREFKEY_FIRSTLOGIN, 1); + } + + /** + * @brief marks the time when user features like email have been updated + * @return null + */ + private function markRefreshTime() { + $this->config->setUserValue( + $this->uid, 'user_ldap', self::USER_PREFKEY_LASTREFRESH, time()); + } + + /** + * @brief checks whether user features needs to be updated again by + * comparing the difference of time of the last refresh to now with the + * desired interval + * @return bool + */ + private function needsRefresh() { + $lastChecked = $this->config->getUserValue($this->uid, 'user_ldap', + self::USER_PREFKEY_LASTREFRESH, 0); + + //TODO make interval configurable + if((time() - intval($lastChecked)) < 86400 ) { + return false; + } + return true; + } + + /** + * @brief checks whether an update method specified by feature was run + * already. If not, it will marked like this, because it is expected that + * the method will be run, when false is returned. + * @param string email | quota | avatar (can be extended) + * @return bool + */ + private function wasRefreshed($feature) { + if(isset($this->refreshedFeatures[$feature])) { + return true; + } + $this->refreshedFeatures[$feature] = 1; + return false; + } + + /** + * @brief fetches the email from LDAP and stores it as ownCloud user value + * @return null + */ + public function updateEmail() { + if($this->wasRefreshed('email')) { + return; + } + + $email = null; + $emailAttribute = $this->connection->ldapEmailAttribute; + if(!empty($emailAttribute)) { + $aEmail = $this->access->readAttribute($this->dn, $emailAttribute); + if($aEmail && (count($aEmail) > 0)) { + $email = $aEmail[0]; + } + if(!is_null($email)) { + $this->config->setUserValue( + $this->uid, 'settings', 'email', $email); + } + } + } + + /** + * @brief fetches the quota from LDAP and stores it as ownCloud user value + * @return null + */ + public function updateQuota() { + if($this->wasRefreshed('quota')) { + return; + } + + $quota = null; + $quotaDefault = $this->connection->ldapQuotaDefault; + $quotaAttribute = $this->connection->ldapQuotaAttribute; + if(!empty($quotaDefault)) { + $quota = $quotaDefault; + } + if(!empty($quotaAttribute)) { + $aQuota = $this->access->readAttribute($this->dn, $quotaAttribute); + + if($aQuota && (count($aQuota) > 0)) { + $quota = $aQuota[0]; + } + } + if(!is_null($quota)) { + $this->config->setUserValue($this->uid, 'files', 'quota', + \OCP\Util::computerFileSize($quota)); + } + } + + /** + * @brief attempts to get an image from LDAP and sets it as ownCloud avatar + * @return null + */ + public function updateAvatar() { + if($this->wasRefreshed('avatar')) { + return; + } + $avatarImage = $this->getAvatarImage(); + if($avatarImage === false) { + //not set, nothing left to do; + return; + } + $this->image->loadFromBase64(base64_encode($avatarImage)); + $this->setOwnCloudAvatar(); + } + + /** + * @brief sets an image as ownCloud avatar + * @return null + */ + private function setOwnCloudAvatar() { + if(!$this->image->valid()) { + $this->log->log('user_ldap', 'jpegPhoto data invalid for '.$this->dn, + \OCP\Util::ERROR); + return; + } + //make sure it is a square and not bigger than 128x128 + $size = min(array($this->image->width(), $this->image->height(), 128)); + if(!$this->image->centerCrop($size)) { + $this->log->log('user_ldap', + 'croping image for avatar failed for '.$this->dn, + \OCP\Util::ERROR); + return; + } + + if(!$this->fs->isLoaded()) { + $this->fs->setup($this->uid); + } + + $avatar = $this->avatarManager->getAvatar($this->uid); + $avatar->set($this->image); + } + +} |