diff options
author | Thomas Müller <thomas.mueller@tmit.eu> | 2013-09-25 13:36:30 +0200 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2013-09-30 16:36:59 +0200 |
commit | 9c9dc276b7a1d2592c4fb0a887888632dc1f1e29 (patch) | |
tree | bbe3aed3e09c31c68806bdb8acffef70ba08f51c /lib/private/user | |
parent | a711399e62d5a9f14d4b748efe4354ee37e61f13 (diff) | |
download | nextcloud-server-9c9dc276b7a1d2592c4fb0a887888632dc1f1e29.tar.gz nextcloud-server-9c9dc276b7a1d2592c4fb0a887888632dc1f1e29.zip |
move the private namespace OC into lib/private - OCP will stay in lib/public
Conflicts:
lib/private/vcategories.php
Diffstat (limited to 'lib/private/user')
-rw-r--r-- | lib/private/user/backend.php | 159 | ||||
-rw-r--r-- | lib/private/user/database.php | 269 | ||||
-rw-r--r-- | lib/private/user/dummy.php | 126 | ||||
-rw-r--r-- | lib/private/user/example.php | 70 | ||||
-rw-r--r-- | lib/private/user/http.php | 110 | ||||
-rw-r--r-- | lib/private/user/interface.php | 80 | ||||
-rw-r--r-- | lib/private/user/manager.php | 250 | ||||
-rw-r--r-- | lib/private/user/session.php | 174 | ||||
-rw-r--r-- | lib/private/user/user.php | 179 |
9 files changed, 1417 insertions, 0 deletions
diff --git a/lib/private/user/backend.php b/lib/private/user/backend.php new file mode 100644 index 00000000000..e9be08e429c --- /dev/null +++ b/lib/private/user/backend.php @@ -0,0 +1,159 @@ +<?php + +/** + * ownCloud + * + * @author Frank Karlitschek + * @author Dominik Schmidt + * @copyright 2012 Frank Karlitschek frank@owncloud.org + * @copyright 2011 Dominik Schmidt dev@dominik-schmidt.de + * + * 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/>. + * + */ + +/** + * error code for functions not provided by the user backend + */ +define('OC_USER_BACKEND_NOT_IMPLEMENTED', -501); + +/** + * actions that user backends can define + */ +define('OC_USER_BACKEND_CREATE_USER', 0x000001); +define('OC_USER_BACKEND_SET_PASSWORD', 0x000010); +define('OC_USER_BACKEND_CHECK_PASSWORD', 0x000100); +define('OC_USER_BACKEND_GET_HOME', 0x001000); +define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x010000); +define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x100000); + + +/** + * Abstract base class for user management. Provides methods for querying backend + * capabilities. + * + * Subclass this for your own backends, and see OC_User_Example for descriptions + */ +abstract class OC_User_Backend implements OC_User_Interface { + + protected $possibleActions = array( + OC_USER_BACKEND_CREATE_USER => 'createUser', + OC_USER_BACKEND_SET_PASSWORD => 'setPassword', + OC_USER_BACKEND_CHECK_PASSWORD => 'checkPassword', + OC_USER_BACKEND_GET_HOME => 'getHome', + OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName', + OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName', + ); + + /** + * @brief Get all supported actions + * @return int bitwise-or'ed actions + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function getSupportedActions() { + $actions = 0; + foreach($this->possibleActions AS $action => $methodName) { + if(method_exists($this, $methodName)) { + $actions |= $action; + } + } + + return $actions; + } + + /** + * @brief Check if backend implements actions + * @param int $actions bitwise-or'ed actions + * @return boolean + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function implementsActions($actions) { + return (bool)($this->getSupportedActions() & $actions); + } + + /** + * @brief delete a user + * @param string $uid The username of the user to delete + * @return bool + * + * Deletes a user + */ + public function deleteUser( $uid ) { + return false; + } + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null) { + return array(); + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + return false; + } + + /** + * @brief get the user's home directory + * @param string $uid the username + * @return boolean + */ + public function getHome($uid) { + return false; + } + + /** + * @brief get display name of the user + * @param string $uid user ID of the user + * @return string display name + */ + public function getDisplayName($uid) { + return $uid; + } + + /** + * @brief Get a list of all display names + * @returns array with all displayNames (value) and the corresponding uids (key) + * + * Get a list of all display names and user ids. + */ + public function getDisplayNames($search = '', $limit = null, $offset = null) { + $displayNames = array(); + $users = $this->getUsers($search, $limit, $offset); + foreach ( $users as $user) { + $displayNames[$user] = $user; + } + return $displayNames; + } + + /** + * @brief Check if a user list is available or not + * @return boolean if users can be listed or not + */ + public function hasUserListings() { + return false; + } +} diff --git a/lib/private/user/database.php b/lib/private/user/database.php new file mode 100644 index 00000000000..9f00a022d9f --- /dev/null +++ b/lib/private/user/database.php @@ -0,0 +1,269 @@ +<?php + +/** + * ownCloud + * + * @author Frank Karlitschek + * @copyright 2012 Frank Karlitschek frank@owncloud.org + * + * 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/>. + * + */ +/* + * + * The following SQL statement is just a help for developers and will not be + * executed! + * + * CREATE TABLE `users` ( + * `uid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, + * `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + * PRIMARY KEY (`uid`) + * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + * + */ + +require_once 'phpass/PasswordHash.php'; + +/** + * Class for user management in a SQL Database (e.g. MySQL, SQLite) + */ +class OC_User_Database extends OC_User_Backend { + /** + * @var PasswordHash + */ + static private $hasher=null; + + private function getHasher() { + if(!self::$hasher) { + //we don't want to use DES based crypt(), since it doesn't return a hash with a recognisable prefix + $forcePortable=(CRYPT_BLOWFISH!=1); + self::$hasher=new PasswordHash(8, $forcePortable); + } + return self::$hasher; + + } + + /** + * @brief Create a new user + * @param $uid The username of the user to create + * @param $password The password of the new user + * @returns true/false + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ + public function createUser( $uid, $password ) { + if( $this->userExists($uid) ) { + return false; + }else{ + $hasher=$this->getHasher(); + $hash = $hasher->HashPassword($password.OC_Config::getValue('passwordsalt', '')); + $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )' ); + $result = $query->execute( array( $uid, $hash)); + + return $result ? true : false; + } + } + + /** + * @brief delete a user + * @param $uid The username of the user to delete + * @returns true/false + * + * Deletes a user + */ + public function deleteUser( $uid ) { + // Delete user-group-relation + $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*users` WHERE `uid` = ?' ); + $query->execute( array( $uid )); + return true; + } + + /** + * @brief Set password + * @param $uid The username + * @param $password The new password + * @returns true/false + * + * Change the password of a user + */ + public function setPassword( $uid, $password ) { + if( $this->userExists($uid) ) { + $hasher=$this->getHasher(); + $hash = $hasher->HashPassword($password.OC_Config::getValue('passwordsalt', '')); + $query = OC_DB::prepare( 'UPDATE `*PREFIX*users` SET `password` = ? WHERE `uid` = ?' ); + $query->execute( array( $hash, $uid )); + + return true; + }else{ + return false; + } + } + + /** + * @brief Set display name + * @param $uid The username + * @param $displayName The new display name + * @returns true/false + * + * Change the display name of a user + */ + public function setDisplayName( $uid, $displayName ) { + if( $this->userExists($uid) ) { + $query = OC_DB::prepare( 'UPDATE `*PREFIX*users` SET `displayname` = ? WHERE `uid` = ?' ); + $query->execute( array( $displayName, $uid )); + return true; + }else{ + return false; + } + } + + /** + * @brief get display name of the user + * @param $uid user ID of the user + * @return display name + */ + public function getDisplayName($uid) { + if( $this->userExists($uid) ) { + $query = OC_DB::prepare( 'SELECT `displayname` FROM `*PREFIX*users` WHERE `uid` = ?' ); + $result = $query->execute( array( $uid ))->fetchAll(); + $displayName = trim($result[0]['displayname'], ' '); + if ( !empty($displayName) ) { + return $displayName; + } else { + return $uid; + } + } + } + + /** + * @brief Get a list of all display names + * @returns array with all displayNames (value) and the correspondig uids (key) + * + * Get a list of all display names and user ids. + */ + public function getDisplayNames($search = '', $limit = null, $offset = null) { + $displayNames = array(); + $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`' + .' WHERE LOWER(`displayname`) LIKE LOWER(?)', $limit, $offset); + $result = $query->execute(array($search.'%')); + $users = array(); + while ($row = $result->fetchRow()) { + $displayNames[$row['uid']] = $row['displayname']; + } + + // let's see if we can also find some users who don't have a display name yet + $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`' + .' WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset); + $result = $query->execute(array($search.'%')); + while ($row = $result->fetchRow()) { + $displayName = trim($row['displayname'], ' '); + if ( empty($displayName) ) { + $displayNames[$row['uid']] = $row['uid']; + } + } + + + return $displayNames; + } + + /** + * @brief Check if the password is correct + * @param $uid The username + * @param $password The password + * @returns string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + public function checkPassword( $uid, $password ) { + $query = OC_DB::prepare( 'SELECT `uid`, `password` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' ); + $result = $query->execute( array( $uid)); + + $row=$result->fetchRow(); + if($row) { + $storedHash=$row['password']; + if ($storedHash[0]=='$') {//the new phpass based hashing + $hasher=$this->getHasher(); + if($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''), $storedHash)) { + return $row['uid']; + }else{ + return false; + } + }else{//old sha1 based hashing + if(sha1($password)==$storedHash) { + //upgrade to new hashing + $this->setPassword($row['uid'], $password); + return $row['uid']; + }else{ + return false; + } + } + }else{ + return false; + } + } + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null) { + $query = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*users` WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset); + $result = $query->execute(array($search.'%')); + $users = array(); + while ($row = $result->fetchRow()) { + $users[] = $row['uid']; + } + return $users; + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + $query = OC_DB::prepare( 'SELECT COUNT(*) FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' ); + $result = $query->execute( array( $uid )); + if (OC_DB::isError($result)) { + OC_Log::write('core', OC_DB::getErrorMessage($result), OC_Log::ERROR); + return false; + } + return $result->fetchOne() > 0; + } + + /** + * @brief get the user's home directory + * @param string $uid the username + * @return boolean + */ + public function getHome($uid) { + if($this->userExists($uid)) { + return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid; + }else{ + return false; + } + } + + /** + * @return bool + */ + public function hasUserListings() { + return true; + } + +} diff --git a/lib/private/user/dummy.php b/lib/private/user/dummy.php new file mode 100644 index 00000000000..b5b7a6c3c7a --- /dev/null +++ b/lib/private/user/dummy.php @@ -0,0 +1,126 @@ +<?php + +/** + * ownCloud + * + * @author Frank Karlitschek + * @copyright 2012 Frank Karlitschek frank@owncloud.org + * + * 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/>. + * + */ + +/** + * dummy user backend, does not keep state, only for testing use + */ +class OC_User_Dummy extends OC_User_Backend { + private $users = array(); + + /** + * @brief Create a new user + * @param string $uid The username of the user to create + * @param string $password The password of the new user + * @return bool + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ + public function createUser($uid, $password) { + if (isset($this->users[$uid])) { + return false; + } else { + $this->users[$uid] = $password; + return true; + } + } + + /** + * @brief delete a user + * @param string $uid The username of the user to delete + * @return bool + * + * Deletes a user + */ + public function deleteUser($uid) { + if (isset($this->users[$uid])) { + unset($this->users[$uid]); + return true; + } else { + return false; + } + } + + /** + * @brief Set password + * @param string $uid The username + * @param string $password The new password + * @return bool + * + * Change the password of a user + */ + public function setPassword($uid, $password) { + if (isset($this->users[$uid])) { + $this->users[$uid] = $password; + return true; + } else { + return false; + } + } + + /** + * @brief Check if the password is correct + * @param string $uid The username + * @param string $password The password + * @return string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + public function checkPassword($uid, $password) { + if (isset($this->users[$uid])) { + return ($this->users[$uid] == $password); + } else { + return false; + } + } + + /** + * @brief Get a list of all users + * @param string $search + * @param int $limit + * @param int $offset + * @return array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null) { + return array_keys($this->users); + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + return isset($this->users[$uid]); + } + + /** + * @return bool + */ + public function hasUserListings() { + return true; + } +} diff --git a/lib/private/user/example.php b/lib/private/user/example.php new file mode 100644 index 00000000000..b2d0dc25410 --- /dev/null +++ b/lib/private/user/example.php @@ -0,0 +1,70 @@ +<?php + +/** + * ownCloud + * + * @author Frank Karlitschek + * @copyright 2012 Frank Karlitschek frank@owncloud.org + * + * 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/>. + * + */ + +/** + * abstract reference class for user management + * this class should only be used as a reference for method signatures and their descriptions + */ +abstract class OC_User_Example extends OC_User_Backend { + /** + * @brief Create a new user + * @param $uid The username of the user to create + * @param $password The password of the new user + * @returns true/false + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ + abstract public function createUser($uid, $password); + + /** + * @brief Set password + * @param $uid The username + * @param $password The new password + * @returns true/false + * + * Change the password of a user + */ + abstract public function setPassword($uid, $password); + + /** + * @brief Check if the password is correct + * @param $uid The username + * @param $password The password + * @returns string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + abstract public function checkPassword($uid, $password); + + /** + * @brief get the user's home directory + * @param $uid The username + * @returns string + * + * get the user's home directory + * returns the path or false + */ + abstract public function getHome($uid); +} diff --git a/lib/private/user/http.php b/lib/private/user/http.php new file mode 100644 index 00000000000..e99afe59ba7 --- /dev/null +++ b/lib/private/user/http.php @@ -0,0 +1,110 @@ +<?php + +/** +* ownCloud +* +* @author Frank Karlitschek +* @copyright 2012 Robin Appelman icewind@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/>. +* +*/ + +/** + * user backend using http auth requests + */ +class OC_User_HTTP extends OC_User_Backend { + /** + * split http://user@host/path into a user and url part + * @param string path + * @return array + */ + private function parseUrl($url) { + $parts=parse_url($url); + $url=$parts['scheme'].'://'.$parts['host']; + if(isset($parts['port'])) { + $url.=':'.$parts['port']; + } + $url.=$parts['path']; + if(isset($parts['query'])) { + $url.='?'.$parts['query']; + } + return array($parts['user'], $url); + + } + + /** + * check if an url is a valid login + * @param string url + * @return boolean + */ + private function matchUrl($url) { + return ! is_null(parse_url($url, PHP_URL_USER)); + } + + /** + * @brief Check if the password is correct + * @param $uid The username + * @param $password The password + * @returns string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + public function checkPassword($uid, $password) { + if(!$this->matchUrl($uid)) { + return false; + } + list($user, $url)=$this->parseUrl($uid); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$password); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + curl_exec($ch); + + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + curl_close($ch); + + if($status === 200) { + return $uid; + } + + return false; + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + return $this->matchUrl($uid); + } + + /** + * @brief get the user's home directory + * @param string $uid the username + * @return boolean + */ + public function getHome($uid) { + if($this->userExists($uid)) { + return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid; + }else{ + return false; + } + } +} diff --git a/lib/private/user/interface.php b/lib/private/user/interface.php new file mode 100644 index 00000000000..c72bdfaf3fd --- /dev/null +++ b/lib/private/user/interface.php @@ -0,0 +1,80 @@ +<?php + +/** + * ownCloud - user interface + * + * @author Arthur Schiwon + * @copyright 2012 Arthur Schiwon blizzz@owncloud.org + * + * 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/>. + * + */ + +interface OC_User_Interface { + + /** + * @brief Check if backend implements actions + * @param $actions bitwise-or'ed actions + * @returns boolean + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function implementsActions($actions); + + /** + * @brief delete a user + * @param $uid The username of the user to delete + * @returns true/false + * + * Deletes a user + */ + public function deleteUser($uid); + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null); + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid); + + /** + * @brief get display name of the user + * @param $uid user ID of the user + * @return display name + */ + public function getDisplayName($uid); + + /** + * @brief Get a list of all display names + * @returns array with all displayNames (value) and the corresponding uids (key) + * + * Get a list of all display names and user ids. + */ + public function getDisplayNames($search = '', $limit = null, $offset = null); + + /** + * @brief Check if a user list is available or not + * @return boolean if users can be listed or not + */ + public function hasUserListings(); +} diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php new file mode 100644 index 00000000000..13286bc28a4 --- /dev/null +++ b/lib/private/user/manager.php @@ -0,0 +1,250 @@ +<?php + +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\PublicEmitter; + +/** + * Class Manager + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user, string $password) + * + * @package OC\User + */ +class Manager extends PublicEmitter { + /** + * @var \OC_User_Backend[] $backends + */ + private $backends = array(); + + /** + * @var \OC\User\User[] $cachedUsers + */ + private $cachedUsers = array(); + + public function __construct() { + $cachedUsers = $this->cachedUsers; + $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) { + $i = array_search($user, $cachedUsers); + if ($i !== false) { + unset($cachedUsers[$i]); + } + }); + } + + /** + * register a user backend + * + * @param \OC_User_Backend $backend + */ + public function registerBackend($backend) { + $this->backends[] = $backend; + } + + /** + * remove a user backend + * + * @param \OC_User_Backend $backend + */ + public function removeBackend($backend) { + $this->cachedUsers = array(); + if (($i = array_search($backend, $this->backends)) !== false) { + unset($this->backends[$i]); + } + } + + /** + * remove all user backends + */ + public function clearBackends() { + $this->cachedUsers = array(); + $this->backends = array(); + } + + /** + * get a user by user id + * + * @param string $uid + * @return \OC\User\User + */ + public function get($uid) { + if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends + return $this->cachedUsers[$uid]; + } + foreach ($this->backends as $backend) { + if ($backend->userExists($uid)) { + return $this->getUserObject($uid, $backend); + } + } + return null; + } + + /** + * get or construct the user object + * + * @param string $uid + * @param \OC_User_Backend $backend + * @return \OC\User\User + */ + protected function getUserObject($uid, $backend) { + if (isset($this->cachedUsers[$uid])) { + return $this->cachedUsers[$uid]; + } + $this->cachedUsers[$uid] = new User($uid, $backend, $this); + return $this->cachedUsers[$uid]; + } + + /** + * check if a user exists + * + * @param string $uid + * @return bool + */ + public function userExists($uid) { + $user = $this->get($uid); + return ($user !== null); + } + + /** + * Check if the password is valid for the user + * + * @param $loginname + * @param $password + * @return mixed the User object on success, false otherwise + */ + public function checkPassword($loginname, $password) { + foreach ($this->backends as $backend) { + if($backend->implementsActions(\OC_USER_BACKEND_CHECK_PASSWORD)) { + $uid = $backend->checkPassword($loginname, $password); + if ($uid !== false) { + return $this->getUserObject($uid, $backend); + } + } + } + return false; + } + + /** + * search by user id + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function search($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getUsers($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid) { + $users[] = $this->getUserObject($uid, $backend); + if (!is_null($limit)) { + $limit--; + } + if (!is_null($offset) and $offset > 0) { + $offset--; + } + + } + } + } + + usort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getUID(), $b->getUID()); + }); + return $users; + } + + /** + * search by displayName + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function searchDisplayName($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid => $displayName) { + $users[] = $this->getUserObject($uid, $backend); + if (!is_null($limit)) { + $limit--; + } + if (!is_null($offset) and $offset > 0) { + $offset--; + } + + } + } + } + + usort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getDisplayName(), $b->getDisplayName()); + }); + return $users; + } + + /** + * @param string $uid + * @param string $password + * @throws \Exception + * @return bool | \OC\User\User the created user of false + */ + public function createUser($uid, $password) { + // Check the name for bad characters + // Allowed are: "a-z", "A-Z", "0-9" and "_.@-" + if (preg_match('/[^a-zA-Z0-9 _\.@\-]/', $uid)) { + throw new \Exception('Only the following characters are allowed in a username:' + . ' "a-z", "A-Z", "0-9", and "_.@-"'); + } + // No empty username + if (trim($uid) == '') { + throw new \Exception('A valid username must be provided'); + } + // No empty password + if (trim($password) == '') { + throw new \Exception('A valid password must be provided'); + } + + // Check if user already exists + if ($this->userExists($uid)) { + throw new \Exception('The username is already being used'); + } + + $this->emit('\OC\User', 'preCreateUser', array($uid, $password)); + foreach ($this->backends as $backend) { + if ($backend->implementsActions(\OC_USER_BACKEND_CREATE_USER)) { + $backend->createUser($uid, $password); + $user = $this->getUserObject($uid, $backend); + $this->emit('\OC\User', 'postCreateUser', array($user, $password)); + return $user; + } + } + return false; + } +} diff --git a/lib/private/user/session.php b/lib/private/user/session.php new file mode 100644 index 00000000000..525c65ab8a1 --- /dev/null +++ b/lib/private/user/session.php @@ -0,0 +1,174 @@ +<?php + +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\Emitter; + +/** + * Class Session + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user) + * - preLogin(string $user, string $password) + * - postLogin(\OC\User\User $user) + * - logout() + * + * @package OC\User + */ +class Session implements Emitter, \OCP\IUserSession { + /** + * @var \OC\User\Manager $manager + */ + private $manager; + + /** + * @var \OC\Session\Session $session + */ + private $session; + + /** + * @var \OC\User\User $activeUser + */ + protected $activeUser; + + /** + * @param \OC\User\Manager $manager + * @param \OC\Session\Session $session + */ + public function __construct($manager, $session) { + $this->manager = $manager; + $this->session = $session; + } + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback) { + $this->manager->listen($scope, $method, $callback); + } + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, $callback = null) { + $this->manager->removeListener($scope, $method, $callback); + } + + /** + * get the manager object + * + * @return \OC\User\Manager + */ + public function getManager() { + return $this->manager; + } + + /** + * set the currently active user + * + * @param \OC\User\User $user + */ + public function setUser($user) { + if (is_null($user)) { + $this->session->remove('user_id'); + } else { + $this->session->set('user_id', $user->getUID()); + } + $this->activeUser = $user; + } + + /** + * get the current active user + * + * @return \OC\User\User + */ + public function getUser() { + if ($this->activeUser) { + return $this->activeUser; + } else { + $uid = $this->session->get('user_id'); + if ($uid) { + $this->activeUser = $this->manager->get($uid); + return $this->activeUser; + } else { + return null; + } + } + } + + /** + * try to login with the provided credentials + * + * @param string $uid + * @param string $password + * @return bool + */ + public function login($uid, $password) { + $this->manager->emit('\OC\User', 'preLogin', array($uid, $password)); + $user = $this->manager->checkPassword($uid, $password); + if($user !== false) { + if (!is_null($user)) { + if ($user->isEnabled()) { + $this->setUser($user); + $this->manager->emit('\OC\User', 'postLogin', array($user, $password)); + return true; + } else { + return false; + } + } + } else { + return false; + } + } + + /** + * logout the user from the session + */ + public function logout() { + $this->manager->emit('\OC\User', 'logout'); + $this->setUser(null); + $this->unsetMagicInCookie(); + } + + /** + * Set cookie value to use in next page load + * + * @param string $username username to be set + * @param string $token + */ + public function setMagicInCookie($username, $token) { + $secure_cookie = \OC_Config::getValue("forcessl", false); //TODO: DI for cookies and OC_Config + $expires = time() + \OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); + setcookie("oc_username", $username, $expires, \OC::$WEBROOT, '', $secure_cookie); + setcookie("oc_token", $token, $expires, \OC::$WEBROOT, '', $secure_cookie, true); + setcookie("oc_remember_login", true, $expires, \OC::$WEBROOT, '', $secure_cookie); + } + + /** + * Remove cookie for "remember username" + */ + public function unsetMagicInCookie() { + unset($_COOKIE["oc_username"]); //TODO: DI + unset($_COOKIE["oc_token"]); + unset($_COOKIE["oc_remember_login"]); + setcookie('oc_username', '', time()-3600, \OC::$WEBROOT); + setcookie('oc_token', '', time()-3600, \OC::$WEBROOT); + setcookie('oc_remember_login', '', time()-3600, \OC::$WEBROOT); + } +} diff --git a/lib/private/user/user.php b/lib/private/user/user.php new file mode 100644 index 00000000000..e5f842944f1 --- /dev/null +++ b/lib/private/user/user.php @@ -0,0 +1,179 @@ +<?php + +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\Emitter; + +class User { + /** + * @var string $uid + */ + private $uid; + + /** + * @var string $displayName + */ + private $displayName; + + /** + * @var \OC_User_Backend $backend + */ + private $backend; + + /** + * @var bool $enabled + */ + private $enabled; + + /** + * @var Emitter | Manager $emitter + */ + private $emitter; + + /** + * @param string $uid + * @param \OC_User_Backend $backend + * @param Emitter $emitter + */ + public function __construct($uid, $backend, $emitter = null) { + $this->uid = $uid; + if ($backend and $backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) { + $this->displayName = $backend->getDisplayName($uid); + } else { + $this->displayName = $uid; + } + $this->backend = $backend; + $this->emitter = $emitter; + $enabled = \OC_Preferences::getValue($uid, 'core', 'enabled', 'true'); //TODO: DI for OC_Preferences + $this->enabled = ($enabled === 'true'); + } + + /** + * get the user id + * + * @return string + */ + public function getUID() { + return $this->uid; + } + + /** + * get the displayname for the user, if no specific displayname is set it will fallback to the user id + * + * @return string + */ + public function getDisplayName() { + return $this->displayName; + } + + /** + * set the displayname for the user + * + * @param string $displayName + * @return bool + */ + public function setDisplayName($displayName) { + if ($this->canChangeDisplayName()) { + $this->displayName = $displayName; + $result = $this->backend->setDisplayName($this->uid, $displayName); + return $result !== false; + } else { + return false; + } + } + + /** + * Delete the user + * + * @return bool + */ + public function delete() { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preDelete', array($this)); + } + $result = $this->backend->deleteUser($this->uid); + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postDelete', array($this)); + } + return !($result === false); + } + + /** + * Set the password of the user + * + * @param string $password + * @param string $recoveryPassword for the encryption app to reset encryption keys + * @return bool + */ + public function setPassword($password, $recoveryPassword) { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword)); + } + if ($this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD)) { + $result = $this->backend->setPassword($this->uid, $password); + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postSetPassword', array($this, $password, $recoveryPassword)); + } + return !($result === false); + } else { + return false; + } + } + + /** + * get the users home folder to mount + * + * @return string + */ + public function getHome() { + if ($this->backend->implementsActions(\OC_USER_BACKEND_GET_HOME) and $home = $this->backend->getHome($this->uid)) { + return $home; + } + return \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $this->uid; //TODO switch to Config object once implemented + } + + /** + * check if the backend supports changing passwords + * + * @return bool + */ + public function canChangePassword() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD); + } + + /** + * check if the backend supports changing display names + * + * @return bool + */ + public function canChangeDisplayName() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME); + } + + /** + * check if the user is enabled + * + * @return bool + */ + public function isEnabled() { + return $this->enabled; + } + + /** + * set the enabled status for the user + * + * @param bool $enabled + */ + public function setEnabled($enabled) { + $this->enabled = $enabled; + $enabled = ($enabled) ? 'true' : 'false'; + \OC_Preferences::setValue($this->uid, 'core', 'enabled', $enabled); + } +} |