From ee0f1490e1872cbe6071f5758e292ae1646ab1af Mon Sep 17 00:00:00 2001
From: Robin Appelman <icewind1991@gmail.com>
Date: Tue, 21 Jun 2011 19:28:46 +0200
Subject: [PATCH] Multiply changes to user system

keeping tracked of the logged in user is no longer done by the active backend but by oc_user directly instead

multiply backends can be active at the same time, allowing alternative authentication procedures like openid or tokens to be used next to the regular user system
---
 lib/User/backend.php  | 68 ++++++++++++-----------------
 lib/User/database.php | 97 +++++++++---------------------------------
 lib/base.php          |  2 +-
 lib/user.php          | 99 ++++++++++++++++++++++++++++++++++---------
 4 files changed, 127 insertions(+), 139 deletions(-)

diff --git a/lib/User/backend.php b/lib/User/backend.php
index e99016a521..8ea7f78190 100644
--- a/lib/User/backend.php
+++ b/lib/User/backend.php
@@ -21,7 +21,10 @@
  *
  */
 
-
+/**
+ * error code for functions not provided by the storage provider
+ */
+define('OC_USER_BACKEND_NOT_IMPLEMENTED',-501);
 
 /**
  * abstract base class for user management
@@ -37,7 +40,9 @@ abstract class OC_USER_BACKEND {
 	 * Creates a new user. Basic checking of username is done in OC_USER
 	 * itself, not in its subclasses.
 	 */
-	public static function createUser($uid, $password){}
+	public function createUser($uid, $password){
+		return OC_USER_BACKEND_NOT_IMPLEMENTED;
+	}
 
 	/**
 	 * @brief delete a user
@@ -46,41 +51,9 @@ abstract class OC_USER_BACKEND {
 	 *
 	 * Deletes a user
 	 */
-	public static function deleteUser( $uid ){}
-
-	/**
-	 * @brief Try to login a user
-	 * @param $uid The username of the user to log in
-	 * @param $password The password of the user
-	 * @returns true/false
-	 *
-	 * Log in a user - if the password is ok
-	 */
-	public static function login($uid, $password){}
-
-	/**
-	 * @brief Kick the user
-	 * @returns true
-	 *
-	 * Logout, destroys session
-	 */
-	public static function logout(){}
-
-	/**
-	 * @brief Check if the user is logged in
-	 * @returns true/false
-	 *
-	 * Checks if the user is logged in
-	 */
-	public static function isLoggedIn(){}
-
-	/**
-	 * @brief Autogenerate a password
-	 * @returns string
-	 *
-	 * generates a password
-	 */
-	public static function generatePassword(){}
+	public function deleteUser( $uid ){
+		return OC_USER_BACKEND_NOT_IMPLEMENTED;
+	}
 
 	/**
 	 * @brief Set password
@@ -90,7 +63,9 @@ abstract class OC_USER_BACKEND {
 	 *
 	 * Change the password of a user
 	 */
-	public static function setPassword($uid, $password){}
+	public function setPassword($uid, $password){
+		return OC_USER_BACKEND_NOT_IMPLEMENTED;
+	}
 
 	/**
 	 * @brief Check if the password is correct
@@ -100,7 +75,9 @@ abstract class OC_USER_BACKEND {
 	 *
 	 * Check if the password is correct without logging in the user
 	 */
-	public static function checkPassword($uid, $password){}
+	public function checkPassword($uid, $password){
+		return OC_USER_BACKEND_NOT_IMPLEMENTED;
+	}
 
 	/**
 	 * @brief Get a list of all users
@@ -108,5 +85,16 @@ abstract class OC_USER_BACKEND {
 	 *
 	 * Get a list of all users.
 	 */
-	public static function getUsers(){}
+	public function getUsers(){
+		return OC_USER_BACKEND_NOT_IMPLEMENTED;
+	}
+
+	/**
+	 * @brief check if a user exists
+	 * @param string $uid the username
+	 * @return boolean
+	 */
+	public function userExists($uid){
+		return OC_USER_BACKEND_NOT_IMPLEMENTED;
+	}
 }
diff --git a/lib/User/database.php b/lib/User/database.php
index eeabb592c2..0396ac3095 100644
--- a/lib/User/database.php
+++ b/lib/User/database.php
@@ -50,12 +50,8 @@ class OC_USER_DATABASE extends OC_USER_BACKEND {
 	 * Creates a new user. Basic checking of username is done in OC_USER
 	 * itself, not in its subclasses.
 	 */
-	public static function createUser( $uid, $password ){
-		// Check if the user already exists
-		$query = OC_DB::prepare( "SELECT * FROM `*PREFIX*users` WHERE uid = ?" );
-		$result = $query->execute( array( $uid ));
-
-		if ( $result->numRows() > 0 ){
+	public function createUser( $uid, $password ){
+		if( $this->userExists($uid) ){
 			return false;
 		}
 		else{
@@ -73,76 +69,13 @@ class OC_USER_DATABASE extends OC_USER_BACKEND {
 	 *
 	 * Deletes a user
 	 */
-	public static function deleteUser( $uid ){
+	public function deleteUser( $uid ){
 		// Delete user-group-relation
 		$query = OC_DB::prepare( "DELETE FROM `*PREFIX*users` WHERE uid = ?" );
 		$result = $query->execute( array( $uid ));
 		return true;
 	}
 
-	/**
-	 * @brief Try to login a user
-	 * @param $uid The username of the user to log in
-	 * @param $password The password of the user
-	 * @returns true/false
-	 *
-	 * Log in a user - if the password is ok
-	 */
-	public static function login( $uid, $password ){
-		// Query
-		$query = OC_DB::prepare( "SELECT uid FROM *PREFIX*users WHERE uid = ? AND password = ?" );
-		$result = $query->execute( array( $uid, sha1( $password )));
-
-		if( $result->numRows() > 0 ){
-			// Set username if name and password are known
-			$row = $result->fetchRow();
-			$_SESSION['user_id'] = $row["uid"];
-			OC_LOG::add( "core", $_SESSION['user_id'], "login" );
-			return true;
-		}
-		else{
-			return false;
-		}
-	}
-
-	/**
-	 * @brief Kick the user
-	 * @returns true
-	 *
-	 * Logout, destroys session
-	 */
-	public static function logout(){
-		OC_LOG::add( "core", $_SESSION['user_id'], "logout" );
-		$_SESSION['user_id'] = false;
-
-		return true;
-	}
-
-	/**
-	 * @brief Check if the user is logged in
-	 * @returns true/false
-	 *
-	 * Checks if the user is logged in
-	 */
-	public static function isLoggedIn() {
-		if( isset($_SESSION['user_id']) AND $_SESSION['user_id'] ){
-			return true;
-		}
-		else{
-			return false;
-		}
-	}
-
-	/**
-	 * @brief Autogenerate a password
-	 * @returns string
-	 *
-	 * generates a password
-	 */
-	public static function generatePassword(){
-		return uniqId();
-	}
-
 	/**
 	 * @brief Set password
 	 * @param $uid The username
@@ -151,12 +84,8 @@ class OC_USER_DATABASE extends OC_USER_BACKEND {
 	 *
 	 * Change the password of a user
 	 */
-	public static function setPassword( $uid, $password ){
-		// Check if the user already exists
-		$query = OC_DB::prepare( "SELECT * FROM `*PREFIX*users` WHERE uid = ?" );
-		$result = $query->execute( array( $uid ));
-
-		if( $result->numRows() > 0 ){
+	public function setPassword( $uid, $password ){
+		if( $this->userExists($uid) ){
 			$query = OC_DB::prepare( "UPDATE *PREFIX*users SET password = ? WHERE uid = ?" );
 			$result = $query->execute( array( sha1( $password ), $uid ));
 
@@ -175,7 +104,7 @@ class OC_USER_DATABASE extends OC_USER_BACKEND {
 	 *
 	 * Check if the password is correct without logging in the user
 	 */
-	public static function checkPassword( $uid, $password ){
+	public function checkPassword( $uid, $password ){
 		$query = OC_DB::prepare( "SELECT uid FROM *PREFIX*users WHERE uid = ? AND password = ?" );
 		$result = $query->execute( array( $uid, sha1( $password )));
 
@@ -193,7 +122,7 @@ class OC_USER_DATABASE extends OC_USER_BACKEND {
 	 *
 	 * Get a list of all users.
 	 */
-	public static function getUsers(){
+	public function getUsers(){
 		$query = OC_DB::prepare( "SELECT uid FROM *PREFIX*users" );
 		$result = $query->execute();
 
@@ -203,4 +132,16 @@ class OC_USER_DATABASE extends OC_USER_BACKEND {
 		}
 		return $users;
 	}
+
+	/**
+	 * @brief check if a user exists
+	 * @param string $uid the username
+	 * @return boolean
+	 */
+	public function userExists($uid){
+		$query = OC_DB::prepare( "SELECT * FROM `*PREFIX*users` WHERE uid = ?" );
+		$result = $query->execute( array( $uid ));
+		
+		return $result->numRows() > 0;
+	}
 }
diff --git a/lib/base.php b/lib/base.php
index 1baf5dc167..e93c471272 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -93,7 +93,7 @@ require_once('search.php');
 
 $error=(count(OC_UTIL::checkServer())>0);
 
-OC_USER::setBackend( OC_CONFIG::getValue( "userbackend", "database" ));
+OC_USER::useBackend( OC_CONFIG::getValue( "userbackend", "database" ));
 OC_GROUP::setBackend( OC_CONFIG::getValue( "groupbackend", "database" ));
 
 // Set up file system unless forbidden
diff --git a/lib/user.php b/lib/user.php
index 09501e59c5..2e11a30e85 100644
--- a/lib/user.php
+++ b/lib/user.php
@@ -40,7 +40,7 @@ if( !OC_CONFIG::getValue( "installed", false )){
  */
 class OC_USER {
 	// The backend used for user management
-	private static $_backend = null;
+	private static $_usedBackends = array();
 
 	// Backends available (except database)
 	private static $_backends = array();
@@ -66,15 +66,25 @@ class OC_USER {
 	public static function getBackends(){
 		return self::$_backends;
 	}
+	
+	/**
+	 * @brief gets used backends
+	 * @returns array of backends
+	 *
+	 * Returns the names of all used backends.
+	 */
+	public static function getUsedBackends(){
+		return array_keys(self::$_usedBackends);
+	}
 
 	/**
-	 * @brief Sets the backend
+	 * @brief Adds the backend to the list of used backends
 	 * @param $backend default: database The backend to use for user managment
 	 * @returns true/false
 	 *
 	 * Set the User Authentication Module
 	 */
-	public static function setBackend( $backend = 'database' ){
+	public static function useBackend( $backend = 'database' ){
 		// You'll never know what happens
 		if( null === $backend OR !is_string( $backend )){
 			$backend = 'database';
@@ -86,11 +96,11 @@ class OC_USER {
 			case 'mysql':
 			case 'sqlite':
 				require_once('User/database.php');
-				self::$_backend = new OC_USER_DATABASE();
+				self::$_usedBackends[$backend] = new OC_USER_DATABASE();
 				break;
 			default:
 				$className = 'OC_USER_' . strToUpper($backend);
-				self::$_backend = new $className();
+				self::$_usedBackends[$backend] = new $className();
 				break;
 		}
 
@@ -119,7 +129,7 @@ class OC_USER {
 			return false;
 		}
 		// Check if user already exists
-		if( in_array( $uid, self::getUsers())){
+		if( self::userExists($uid) ){
 			return false;
 		}
 
@@ -127,13 +137,17 @@ class OC_USER {
 		$run = true;
 		OC_HOOK::emit( "OC_USER", "pre_createUser", array( "run" => &$run, "uid" => $uid, "password" => $password ));
 
-		if( $run && self::$_backend->createUser( $uid, $password )){
-			OC_HOOK::emit( "OC_USER", "post_createUser", array( "uid" => $uid, "password" => $password ));
-			return true;
-		}
-		else{
-			return false;
+		if( $run ){
+			//create the user in the first backend that supports creating users
+			foreach(self::$_usedBackends as $backend){
+				$result=$backend->createUser($uid,$password);
+				if($result!==OC_USER_BACKEND_NOT_IMPLEMENTED){
+					OC_HOOK::emit( "OC_USER", "post_createUser", array( "uid" => $uid, "password" => $password ));
+					return true;
+				}
+			}
 		}
+		return false;
 	}
 
 	/**
@@ -147,7 +161,11 @@ class OC_USER {
 		$run = true;
 		OC_HOOK::emit( "OC_USER", "pre_deleteUser", array( "run" => &$run, "uid" => $uid ));
 
-		if( $run && self::$_backend->deleteUser( $uid )){
+		if( $run ){
+			//delete the user from all backends
+			foreach(self::$_usedBackends as $backend){
+				$backend->deleteUser($uid);
+			}
 			// We have to delete the user from all groups
 			foreach( OC_GROUP::getUserGroups( $uid ) as $i ){
 				OC_GROUP::removeFromGroup( $uid, $i );
@@ -174,7 +192,9 @@ class OC_USER {
 		$run = true;
 		OC_HOOK::emit( "OC_USER", "pre_login", array( "run" => &$run, "uid" => $uid ));
 
-		if( $run && self::$_backend->login( $uid, $password )){
+		if( $run && self::checkPassword( $uid, $password )){
+			$_SESSION['user_id'] = $uid;
+			OC_LOG::add( "core", $_SESSION['user_id'], "login" );
 			OC_HOOK::emit( "OC_USER", "post_login", array( "uid" => $uid ));
 			return true;
 		}
@@ -191,7 +211,9 @@ class OC_USER {
 	 */
 	public static function logout(){
 		OC_HOOK::emit( "OC_USER", "logout", array());
-		return self::$_backend->logout();
+		OC_LOG::add( "core", $_SESSION['user_id'], "logout" );
+		$_SESSION['user_id'] = false;
+		return true;
 	}
 
 	/**
@@ -201,7 +223,12 @@ class OC_USER {
 	 * Checks if the user is logged in
 	 */
 	public static function isLoggedIn(){
-		return self::$_backend->isLoggedIn();
+		if( isset($_SESSION['user_id']) AND $_SESSION['user_id'] ){
+			return true;
+		}
+		else{
+			return false;
+		}
 	}
 
 	/**
@@ -211,7 +238,7 @@ class OC_USER {
 	 * generates a password
 	 */
 	public static function generatePassword(){
-		return substr( md5( uniqId().time()), 0, 10 );
+		return uniqId();
 	}
 
 	/**
@@ -226,7 +253,12 @@ class OC_USER {
 		$run = true;
 		OC_HOOK::emit( "OC_USER", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password ));
 
-		if( $run && self::$_backend->setPassword( $uid, $password )){
+		if( $run ){
+			foreach(self::$_usedBackends as $backend){
+				if($backend->userExists($uid)){
+					$backend->setPassword($uid,$password);
+				}
+			}
 			OC_HOOK::emit( "OC_USER", "post_setPassword", array( "uid" => $uid, "password" => $password ));
 			return true;
 		}
@@ -244,7 +276,12 @@ class OC_USER {
 	 * Check if the password is correct without logging in the user
 	 */
 	public static function checkPassword( $uid, $password ){
-		return self::$_backend->checkPassword( $uid, $password );
+		foreach(self::$_usedBackends as $backend){
+			$result=$backend->checkPassword( $uid, $password );
+			if($result===true){
+				return true;
+			}
+		}
 	}
 
 	/**
@@ -254,6 +291,28 @@ class OC_USER {
 	 * Get a list of all users.
 	 */
 	public static function getUsers(){
-		return self::$_backend->getUsers();
+		$users=array();
+		foreach(self::$_usedBackends as $backend){
+			$result=$backend->getUsers();
+			if($result!=OC_USER_BACKEND_NOT_IMPLEMENTED){
+				$users=array_merge($users,$result);
+			}
+		}
+		return $users;
+	}
+
+	/**
+	 * @brief check if a user exists
+	 * @param string $uid the username
+	 * @return boolean
+	 */
+	public static function userExists($uid){
+		foreach(self::$_usedBackends as $backend){
+			$result=$backend->userExists($uid);
+			if($result===true){
+				return true;
+			}
+		}
+		return false;
 	}
 }
-- 
GitLab