summaryrefslogtreecommitdiffstats
path: root/apps/user_ldap/lib/User
diff options
context:
space:
mode:
authorJoas Schilling <nickvergessen@owncloud.com>2016-05-12 11:25:50 +0200
committerJoas Schilling <nickvergessen@owncloud.com>2016-05-25 16:04:56 +0200
commit3f5e76162d74701c35a31b5a611466dba93d9a04 (patch)
tree5dc6b119f48333057dc45e2c04ba5873c889dc67 /apps/user_ldap/lib/User
parentb7fa5277915507622cc7043dc62998d849b8807d (diff)
downloadnextcloud-server-3f5e76162d74701c35a31b5a611466dba93d9a04.tar.gz
nextcloud-server-3f5e76162d74701c35a31b5a611466dba93d9a04.zip
Move lib\user to PSR-4
Diffstat (limited to 'apps/user_ldap/lib/User')
-rw-r--r--apps/user_ldap/lib/User/DeletedUsersIndex.php113
-rw-r--r--apps/user_ldap/lib/User/IUserTools.php40
-rw-r--r--apps/user_ldap/lib/User/Manager.php238
-rw-r--r--apps/user_ldap/lib/User/OfflineUser.php230
-rw-r--r--apps/user_ldap/lib/User/User.php532
5 files changed, 1153 insertions, 0 deletions
diff --git a/apps/user_ldap/lib/User/DeletedUsersIndex.php b/apps/user_ldap/lib/User/DeletedUsersIndex.php
new file mode 100644
index 00000000000..7a9823786dd
--- /dev/null
+++ b/apps/user_ldap/lib/User/DeletedUsersIndex.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\User;
+
+use OCA\User_LDAP\Mapping\UserMapping;
+
+/**
+ * Class DeletedUsersIndex
+ * @package OCA\User_LDAP
+ */
+class DeletedUsersIndex {
+ /**
+ * @var \OCP\IConfig $config
+ */
+ protected $config;
+
+ /**
+ * @var \OCP\IDBConnection $db
+ */
+ protected $db;
+
+ /**
+ * @var \OCA\User_LDAP\Mapping\UserMapping $mapping
+ */
+ protected $mapping;
+
+ /**
+ * @var array $deletedUsers
+ */
+ protected $deletedUsers;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OCP\IDBConnection $db
+ * @param \OCA\User_LDAP\Mapping\UserMapping $mapping
+ */
+ public function __construct(\OCP\IConfig $config, \OCP\IDBConnection $db, UserMapping $mapping) {
+ $this->config = $config;
+ $this->db = $db;
+ $this->mapping = $mapping;
+ }
+
+ /**
+ * reads LDAP users marked as deleted from the database
+ * @return \OCA\User_LDAP\User\OfflineUser[]
+ */
+ private function fetchDeletedUsers() {
+ $deletedUsers = $this->config->getUsersForUserValue(
+ 'user_ldap', 'isDeleted', '1');
+
+ $userObjects = array();
+ foreach($deletedUsers as $user) {
+ $userObjects[] = new OfflineUser($user, $this->config, $this->db, $this->mapping);
+ }
+ $this->deletedUsers = $userObjects;
+
+ return $this->deletedUsers;
+ }
+
+ /**
+ * returns all LDAP users that are marked as deleted
+ * @return \OCA\User_LDAP\User\OfflineUser[]
+ */
+ public function getUsers() {
+ if(is_array($this->deletedUsers)) {
+ return $this->deletedUsers;
+ }
+ return $this->fetchDeletedUsers();
+ }
+
+ /**
+ * whether at least one user was detected as deleted
+ * @return bool
+ */
+ public function hasUsers() {
+ if($this->deletedUsers === false) {
+ $this->fetchDeletedUsers();
+ }
+ if(is_array($this->deletedUsers) && count($this->deletedUsers) > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * marks a user as deleted
+ * @param string $ocName
+ */
+ public function markUser($ocName) {
+ $this->config->setUserValue($ocName, 'user_ldap', 'isDeleted', '1');
+ }
+}
diff --git a/apps/user_ldap/lib/User/IUserTools.php b/apps/user_ldap/lib/User/IUserTools.php
new file mode 100644
index 00000000000..747b46ec68a
--- /dev/null
+++ b/apps/user_ldap/lib/User/IUserTools.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\User;
+
+/**
+ * IUserTools
+ *
+ * defines methods that are required by User class for LDAP interaction
+ */
+interface IUserTools {
+ public function getConnection();
+
+ public function readAttribute($dn, $attr, $filter = 'objectClass=*');
+
+ public function stringResemblesDN($string);
+
+ 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..ca86970d477
--- /dev/null
+++ b/apps/user_ldap/lib/User/Manager.php
@@ -0,0 +1,238 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\User;
+
+use OCA\user_ldap\lib\LogWrapper;
+use OCA\user_ldap\lib\FilesystemHelper;
+use OCP\IAvatarManager;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\Image;
+use OCP\IUserManager;
+
+/**
+ * Manager
+ *
+ * upon request, returns an LDAP user object either by creating or from run-time
+ * cache
+ */
+class Manager {
+ /** @var IUserTools */
+ protected $access;
+
+ /** @var IConfig */
+ protected $ocConfig;
+
+ /** @var IDBConnection */
+ protected $db;
+
+ /** @var FilesystemHelper */
+ protected $ocFilesystem;
+
+ /** @var LogWrapper */
+ protected $ocLog;
+
+ /** @var Image */
+ protected $image;
+
+ /** @param \OCP\IAvatarManager */
+ protected $avatarManager;
+
+ /**
+ * array['byDN'] \OCA\User_LDAP\User\User[]
+ * ['byUid'] \OCA\User_LDAP\User\User[]
+ * @var array $users
+ */
+ protected $users = array(
+ 'byDN' => array(),
+ 'byUid' => array(),
+ );
+
+ /**
+ * @param IConfig $ocConfig
+ * @param \OCA\user_ldap\lib\FilesystemHelper $ocFilesystem object that
+ * gives access to necessary functions from the OC filesystem
+ * @param \OCA\user_ldap\lib\LogWrapper $ocLog
+ * @param IAvatarManager $avatarManager
+ * @param Image $image an empty image instance
+ * @param IDBConnection $db
+ * @throws \Exception when the methods mentioned above do not exist
+ */
+ public function __construct(IConfig $ocConfig,
+ FilesystemHelper $ocFilesystem, LogWrapper $ocLog,
+ IAvatarManager $avatarManager, Image $image,
+ IDBConnection $db, IUserManager $userManager) {
+
+ $this->ocConfig = $ocConfig;
+ $this->ocFilesystem = $ocFilesystem;
+ $this->ocLog = $ocLog;
+ $this->avatarManager = $avatarManager;
+ $this->image = $image;
+ $this->db = $db;
+ $this->userManager = $userManager;
+ }
+
+ /**
+ * @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 $dn the DN of the user
+ * @param string $uid the internal (owncloud) username
+ * @return \OCA\User_LDAP\User\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, $this->userManager);
+ $this->users['byDN'][$dn] = $user;
+ $this->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');
+ }
+ }
+
+ /**
+ * returns a list of attributes that will be processed further, e.g. quota,
+ * email, displayname, or others.
+ * @param bool $minimal - optional, set to true to skip attributes with big
+ * payload
+ * @return string[]
+ */
+ public function getAttributes($minimal = false) {
+ $attributes = array('dn', 'uid', 'samaccountname', 'memberof');
+ $possible = array(
+ $this->access->getConnection()->ldapQuotaAttribute,
+ $this->access->getConnection()->ldapEmailAttribute,
+ $this->access->getConnection()->ldapUserDisplayName,
+ $this->access->getConnection()->ldapUserDisplayName2,
+ );
+ foreach($possible as $attr) {
+ if(!is_null($attr)) {
+ $attributes[] = $attr;
+ }
+ }
+
+ $homeRule = $this->access->getConnection()->homeFolderNamingRule;
+ if(strpos($homeRule, 'attr:') === 0) {
+ $attributes[] = substr($homeRule, strlen('attr:'));
+ }
+
+ if(!$minimal) {
+ // attributes that are not really important but may come with big
+ // payload.
+ $attributes = array_merge($attributes, array(
+ 'jpegphoto',
+ 'thumbnailphoto'
+ ));
+ }
+
+ return $attributes;
+ }
+
+ /**
+ * Checks whether the specified user is marked as deleted
+ * @param string $id the ownCloud user name
+ * @return bool
+ */
+ public function isDeletedUser($id) {
+ $isDeleted = $this->ocConfig->getUserValue(
+ $id, 'user_ldap', 'isDeleted', 0);
+ return intval($isDeleted) === 1;
+ }
+
+ /**
+ * creates and returns an instance of OfflineUser for the specified user
+ * @param string $id
+ * @return \OCA\User_LDAP\User\OfflineUser
+ */
+ public function getDeletedUser($id) {
+ return new OfflineUser(
+ $id,
+ $this->ocConfig,
+ $this->db,
+ $this->access->getUserMapper());
+ }
+
+ /**
+ * @brief returns a User object by it's ownCloud username
+ * @param string $id the DN or username of the user
+ * @return \OCA\User_LDAP\User\User|\OCA\User_LDAP\User\OfflineUser|null
+ */
+ protected function createInstancyByUserName($id) {
+ //most likely a uid. Check whether it is a deleted user
+ if($this->isDeletedUser($id)) {
+ return $this->getDeletedUser($id);
+ }
+ $dn = $this->access->username2dn($id);
+ if($dn !== false) {
+ return $this->createAndCache($dn, $id);
+ }
+ return null;
+ }
+
+ /**
+ * @brief returns a User object by it's DN or ownCloud username
+ * @param string $id the DN or username of the user
+ * @return \OCA\User_LDAP\User\User|\OCA\User_LDAP\User\OfflineUser|null
+ * @throws \Exception when connection could not be established
+ */
+ 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($this->access->stringResemblesDN($id) ) {
+ $uid = $this->access->dn2username($id);
+ if($uid !== false) {
+ return $this->createAndCache($id, $uid);
+ }
+ }
+
+ return $this->createInstancyByUserName($id);
+ }
+
+}
diff --git a/apps/user_ldap/lib/User/OfflineUser.php b/apps/user_ldap/lib/User/OfflineUser.php
new file mode 100644
index 00000000000..a3a9995490d
--- /dev/null
+++ b/apps/user_ldap/lib/User/OfflineUser.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\User;
+
+use OCA\User_LDAP\Mapping\UserMapping;
+
+class OfflineUser {
+ /**
+ * @var string $ocName
+ */
+ protected $ocName;
+ /**
+ * @var string $dn
+ */
+ protected $dn;
+ /**
+ * @var string $uid the UID as provided by LDAP
+ */
+ protected $uid;
+ /**
+ * @var string $displayName
+ */
+ protected $displayName;
+ /**
+ * @var string $homePath
+ */
+ protected $homePath;
+ /**
+ * @var string $lastLogin the timestamp of the last login
+ */
+ protected $lastLogin;
+ /**
+ * @var string $email
+ */
+ protected $email;
+ /**
+ * @var bool $hasActiveShares
+ */
+ protected $hasActiveShares;
+ /**
+ * @var \OCP\IConfig $config
+ */
+ protected $config;
+ /**
+ * @var \OCP\IDBConnection $db
+ */
+ protected $db;
+ /**
+ * @var \OCA\User_LDAP\Mapping\UserMapping
+ */
+ protected $mapping;
+
+ /**
+ * @param string $ocName
+ * @param \OCP\IConfig $config
+ * @param \OCP\IDBConnection $db
+ * @param \OCA\User_LDAP\Mapping\UserMapping $mapping
+ */
+ public function __construct($ocName, \OCP\IConfig $config, \OCP\IDBConnection $db, UserMapping $mapping) {
+ $this->ocName = $ocName;
+ $this->config = $config;
+ $this->db = $db;
+ $this->mapping = $mapping;
+ $this->fetchDetails();
+ }
+
+ /**
+ * remove the Delete-flag from the user.
+ */
+ public function unmark() {
+ $this->config->setUserValue($this->ocName, 'user_ldap', 'isDeleted', '0');
+ }
+
+ /**
+ * exports the user details in an assoc array
+ * @return array
+ */
+ public function export() {
+ $data = array();
+ $data['ocName'] = $this->getOCName();
+ $data['dn'] = $this->getDN();
+ $data['uid'] = $this->getUID();
+ $data['displayName'] = $this->getDisplayName();
+ $data['homePath'] = $this->getHomePath();
+ $data['lastLogin'] = $this->getLastLogin();
+ $data['email'] = $this->getEmail();
+ $data['hasActiveShares'] = $this->getHasActiveShares();
+
+ return $data;
+ }
+
+ /**
+ * getter for ownCloud internal name
+ * @return string
+ */
+ public function getOCName() {
+ return $this->ocName;
+ }
+
+ /**
+ * getter for LDAP uid
+ * @return string
+ */
+ public function getUID() {
+ return $this->uid;
+ }
+
+ /**
+ * getter for LDAP DN
+ * @return string
+ */
+ public function getDN() {
+ return $this->dn;
+ }
+
+ /**
+ * getter for display name
+ * @return string
+ */
+ public function getDisplayName() {
+ return $this->displayName;
+ }
+
+ /**
+ * getter for email
+ * @return string
+ */
+ public function getEmail() {
+ return $this->email;
+ }
+
+ /**
+ * getter for home directory path
+ * @return string
+ */
+ public function getHomePath() {
+ return $this->homePath;
+ }
+
+ /**
+ * getter for the last login timestamp
+ * @return int
+ */
+ public function getLastLogin() {
+ return intval($this->lastLogin);
+ }
+
+ /**
+ * getter for having active shares
+ * @return bool
+ */
+ public function getHasActiveShares() {
+ return $this->hasActiveShares;
+ }
+
+ /**
+ * reads the user details
+ */
+ protected function fetchDetails() {
+ $properties = array (
+ 'displayName' => 'user_ldap',
+ 'uid' => 'user_ldap',
+ 'homePath' => 'user_ldap',
+ 'email' => 'settings',
+ 'lastLogin' => 'login'
+ );
+ foreach($properties as $property => $app) {
+ $this->$property = $this->config->getUserValue($this->ocName, $app, $property, '');
+ }
+
+ $dn = $this->mapping->getDNByName($this->ocName);
+ $this->dn = ($dn !== false) ? $dn : '';
+
+ $this->determineShares();
+ }
+
+
+ /**
+ * finds out whether the user has active shares. The result is stored in
+ * $this->hasActiveShares
+ */
+ protected function determineShares() {
+ $query = $this->db->prepare('
+ SELECT COUNT(`uid_owner`)
+ FROM `*PREFIX*share`
+ WHERE `uid_owner` = ?
+ ', 1);
+ $query->execute(array($this->ocName));
+ $sResult = $query->fetchColumn(0);
+ if(intval($sResult) === 1) {
+ $this->hasActiveShares = true;
+ return;
+ }
+
+ $query = $this->db->prepare('
+ SELECT COUNT(`owner`)
+ FROM `*PREFIX*share_external`
+ WHERE `owner` = ?
+ ', 1);
+ $query->execute(array($this->ocName));
+ $sResult = $query->fetchColumn(0);
+ if(intval($sResult) === 1) {
+ $this->hasActiveShares = true;
+ return;
+ }
+
+ $this->hasActiveShares = false;
+ }
+}
diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php
new file mode 100644
index 00000000000..4b9e3a3c9fc
--- /dev/null
+++ b/apps/user_ldap/lib/User/User.php
@@ -0,0 +1,532 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\User;
+
+use OCA\user_ldap\lib\Connection;
+use OCA\user_ldap\lib\FilesystemHelper;
+use OCA\user_ldap\lib\LogWrapper;
+use OCP\IAvatarManager;
+use OCP\IConfig;
+use OCP\Image;
+use OCP\IUserManager;
+
+/**
+ * User
+ *
+ * represents an LDAP user, gets and holds user-specific information from LDAP
+ */
+class User {
+ /**
+ * @var IUserTools
+ */
+ protected $access;
+ /**
+ * @var Connection
+ */
+ protected $connection;
+ /**
+ * @var IConfig
+ */
+ protected $config;
+ /**
+ * @var FilesystemHelper
+ */
+ protected $fs;
+ /**
+ * @var Image
+ */
+ protected $image;
+ /**
+ * @var LogWrapper
+ */
+ protected $log;
+ /**
+ * @var IAvatarManager
+ */
+ protected $avatarManager;
+ /**
+ * @var IUserManager
+ */
+ protected $userManager;
+ /**
+ * @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 $username the internal username
+ * @param string $dn the LDAP DN
+ * @param IUserTools $access an instance that implements IUserTools for
+ * LDAP interaction
+ * @param IConfig $config
+ * @param FilesystemHelper $fs
+ * @param Image $image any empty instance
+ * @param LogWrapper $log
+ * @param IAvatarManager $avatarManager
+ * @param IUserManager $userManager
+ */
+ public function __construct($username, $dn, IUserTools $access,
+ IConfig $config, FilesystemHelper $fs, Image $image,
+ LogWrapper $log, IAvatarManager $avatarManager, IUserManager $userManager) {
+
+ $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;
+ $this->userManager = $userManager;
+ }
+
+ /**
+ * @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();
+ }
+ }
+ }
+
+ /**
+ * processes results from LDAP for attributes as returned by getAttributesToRead()
+ * @param array $ldapEntry the user entry as retrieved from LDAP
+ */
+ public function processAttributes($ldapEntry) {
+ $this->markRefreshTime();
+ //Quota
+ $attr = strtolower($this->connection->ldapQuotaAttribute);
+ if(isset($ldapEntry[$attr])) {
+ $this->updateQuota($ldapEntry[$attr][0]);
+ }
+ unset($attr);
+
+ //Email
+ $attr = strtolower($this->connection->ldapEmailAttribute);
+ if(isset($ldapEntry[$attr])) {
+ $this->updateEmail($ldapEntry[$attr][0]);
+ }
+ unset($attr);
+
+ //displayName
+ $displayName = $displayName2 = '';
+ $attr = strtolower($this->connection->ldapUserDisplayName);
+ if(isset($ldapEntry[$attr])) {
+ $displayName = $ldapEntry[$attr][0];
+ }
+ $attr = strtolower($this->connection->ldapUserDisplayName2);
+ if(isset($ldapEntry[$attr])) {
+ $displayName2 = $ldapEntry[$attr][0];
+ }
+ if(!empty($displayName)) {
+ $this->composeAndStoreDisplayName($displayName);
+ $this->access->cacheUserDisplayName(
+ $this->getUsername(),
+ $displayName,
+ $displayName2
+ );
+ }
+ unset($attr);
+
+ // LDAP Username, needed for s2s sharing
+ if(isset($ldapEntry['uid'])) {
+ $this->storeLDAPUserName($ldapEntry['uid'][0]);
+ } else if(isset($ldapEntry['samaccountname'])) {
+ $this->storeLDAPUserName($ldapEntry['samaccountname'][0]);
+ }
+
+ //homePath
+ if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
+ $attr = strtolower(substr($this->connection->homeFolderNamingRule, strlen('attr:')));
+ if(isset($ldapEntry[$attr])) {
+ $this->access->cacheUserHome(
+ $this->getUsername(), $this->getHomePath($ldapEntry[$attr][0]));
+ }
+ }
+
+ //memberOf groups
+ $cacheKey = 'getMemberOf'.$this->getUsername();
+ $groups = false;
+ if(isset($ldapEntry['memberof'])) {
+ $groups = $ldapEntry['memberof'];
+ }
+ $this->connection->writeToCache($cacheKey, $groups);
+
+ //Avatar
+ $attrs = array('jpegphoto', 'thumbnailphoto');
+ foreach ($attrs as $attr) {
+ if(isset($ldapEntry[$attr])) {
+ $this->avatarImage = $ldapEntry[$attr][0];
+ // the call to the method that saves the avatar in the file
+ // system must be postponed after the login. It is to ensure
+ // external mounts are mounted properly (e.g. with login
+ // credentials from the session).
+ \OCP\Util::connectHook('OC_User', 'post_login', $this, 'updateAvatarPostLogin');
+ break;
+ }
+ }
+ }
+
+ /**
+ * @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;
+ }
+
+ /**
+ * returns the home directory of the user if specified by LDAP settings
+ * @param string $valueFromLDAP
+ * @return bool|string
+ * @throws \Exception
+ */
+ public function getHomePath($valueFromLDAP = null) {
+ $path = $valueFromLDAP;
+ $attr = null;
+
+ if( is_null($path)
+ && strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0
+ && $this->access->connection->homeFolderNamingRule !== 'attr:')
+ {
+ $attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
+ $homedir = $this->access->readAttribute(
+ $this->access->username2dn($this->getUsername()), $attr);
+ if ($homedir && isset($homedir[0])) {
+ $path = $homedir[0];
+ }
+ }
+
+ if(!empty($path)) {
+ //if attribute's value is an absolute path take this, otherwise append it to data dir
+ //check for / at the beginning or pattern c:\ resp. c:/
+ if( '/' !== $path[0]
+ && !(3 < strlen($path) && ctype_alpha($path[0])
+ && $path[1] === ':' && ('\\' === $path[2] || '/' === $path[2]))
+ ) {
+ $path = $this->config->getSystemValue('datadirectory',
+ \OC::$SERVERROOT.'/data' ) . '/' . $path;
+ }
+ //we need it to store it in the DB as well in case a user gets
+ //deleted so we can clean up afterwards
+ $this->config->setUserValue(
+ $this->getUsername(), 'user_ldap', 'homePath', $path
+ );
+ return $path;
+ }
+
+ if( !is_null($attr)
+ && $this->config->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)
+ ) {
+ // a naming rule attribute is defined, but it doesn't exist for that LDAP user
+ throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $this->getUsername());
+ }
+
+ //false will apply default behaviour as defined and done by OC_User
+ $this->config->setUserValue($this->getUsername(), 'user_ldap', 'homePath', '');
+ return false;
+ }
+
+ public function getMemberOfGroups() {
+ $cacheKey = 'getMemberOf'.$this->getUsername();
+ $memberOfGroups = $this->connection->getFromCache($cacheKey);
+ if(!is_null($memberOfGroups)) {
+ return $memberOfGroups;
+ }
+ $groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
+ $this->connection->writeToCache($cacheKey, $groupDNs);
+ return $groupDNs;
+ }
+
+ /**
+ * @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
+ */
+ public 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;
+ }
+
+ /**
+ * Stores a key-value pair in relation to this user
+ *
+ * @param string $key
+ * @param string $value
+ */
+ private function store($key, $value) {
+ $this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
+ }
+
+ /**
+ * Composes the display name and stores it in the database. The final
+ * display name is returned.
+ *
+ * @param string $displayName
+ * @param string $displayName2
+ * @returns string the effective display name
+ */
+ public function composeAndStoreDisplayName($displayName, $displayName2 = '') {
+ if(!empty($displayName2)) {
+ $displayName .= ' (' . $displayName2 . ')';
+ }
+ $this->store('displayName', $displayName);
+ return $displayName;
+ }
+
+ /**
+ * Stores the LDAP Username in the Database
+ * @param string $userName
+ */
+ public function storeLDAPUserName($userName) {
+ $this->store('uid', $userName);
+ }
+
+ /**
+ * @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 $feature 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;
+ }
+
+ /**
+ * fetches the email from LDAP and stores it as ownCloud user value
+ * @param string $valueFromLDAP if known, to save an LDAP read request
+ * @return null
+ */
+ public function updateEmail($valueFromLDAP = null) {
+ if($this->wasRefreshed('email')) {
+ return;
+ }
+ $email = $valueFromLDAP;
+ if(is_null($valueFromLDAP)) {
+ $emailAttribute = $this->connection->ldapEmailAttribute;
+ if(!empty($emailAttribute)) {
+ $aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
+ if(is_array($aEmail) && (count($aEmail) > 0)) {
+ $email = $aEmail[0];
+ }
+ }
+ }
+ if(!is_null($email)) {
+ $user = $this->userManager->get($this->uid);
+ if (!is_null($user)) {
+ $user->setEMailAddress($email);
+ }
+ }
+ }
+
+ /**
+ * fetches the quota from LDAP and stores it as ownCloud user value
+ * @param string $valueFromLDAP the quota attribute's value can be passed,
+ * to save the readAttribute request
+ * @return null
+ */
+ public function updateQuota($valueFromLDAP = null) {
+ if($this->wasRefreshed('quota')) {
+ return;
+ }
+ //can be null
+ $quotaDefault = $this->connection->ldapQuotaDefault;
+ $quota = $quotaDefault !== '' ? $quotaDefault : null;
+ $quota = !is_null($valueFromLDAP) ? $valueFromLDAP : $quota;
+
+ if(is_null($valueFromLDAP)) {
+ $quotaAttribute = $this->connection->ldapQuotaAttribute;
+ if(!empty($quotaAttribute)) {
+ $aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
+ if($aQuota && (count($aQuota) > 0)) {
+ $quota = $aQuota[0];
+ }
+ }
+ }
+ if(!is_null($quota)) {
+ $user = $this->userManager->get($this->uid)->setQuota($quota);
+ }
+ }
+
+ /**
+ * called by a post_login hook to save the avatar picture
+ *
+ * @param array $params
+ */
+ public function updateAvatarPostLogin($params) {
+ if(isset($params['uid']) && $params['uid'] === $this->getUsername()) {
+ $this->updateAvatar();
+ }
+ }
+
+ /**
+ * @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);
+ }
+
+ try {
+ $avatar = $this->avatarManager->getAvatar($this->uid);
+ $avatar->set($this->image);
+ } catch (\Exception $e) {
+ \OC::$server->getLogger()->notice(
+ 'Could not set avatar for ' . $this->dn . ', because: ' . $e->getMessage(),
+ ['app' => 'user_ldap']);
+ }
+ }
+
+}