260 lines
7.1 KiB
PHP
260 lines
7.1 KiB
PHP
<?php
|
|
/**
|
|
*
|
|
* MySQL authentication module. Uses MySQL capability to store or
|
|
* retrieve user credentials. Called from API when authentication
|
|
* functions are requested.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU 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 General Public License for more details.
|
|
*
|
|
* @author Filippo Callegari (callegari.filippo@gmail.com)
|
|
* @version $Id:1.0 MySQL.php 2015-03-10 23:49:11 Tio Igor
|
|
* @package phpVirtualBox
|
|
*
|
|
*/
|
|
|
|
|
|
/**
|
|
struct of db:
|
|
CREATE TABLE users(
|
|
username VARCHAR(20) PRIMARY KEY,
|
|
password VARCHAR(40),
|
|
admin ENUM('0','1') DEFAULT '0'
|
|
)ENGINE=InnoDB;
|
|
|
|
INSERT INTO users(username,password,admin)
|
|
VALUES("admin","$1$65CMtT1M$GSDBTEZ6o5Web.4cDL6rz1",'1'); /*user:admin, pass:admin*/
|
|
|
|
*/
|
|
class phpvbAuthMySQL implements phpvbAuth
|
|
{
|
|
|
|
var $capabilities = array(
|
|
'canChangePassword' => true,
|
|
'canModifyUsers' => true,
|
|
'canLogout' => true
|
|
);
|
|
|
|
/**
|
|
*
|
|
* Connect to MySQL DB.
|
|
* return PDOconnection.
|
|
*/
|
|
function newPDO()
|
|
{
|
|
$host="127.0.0.1";
|
|
$port=3306;
|
|
$user="MySQLuser";
|
|
$pass="MySQLpassword";
|
|
$db="vboxDB";
|
|
|
|
try{
|
|
return new PDO("mysql:host=$host;port=$port;dbname=$db;charset=utf8",$user,$pass);
|
|
}catch (PDOException $e){throw new Exception("Can't connect to MySQL db!",vboxconnector::PHPVB_ERRNO_CONNECT);}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Select row from username
|
|
* @param $username the user we search
|
|
* return row
|
|
*/
|
|
function PDO_selectUser($username)
|
|
{
|
|
try{
|
|
$statement=$this->newPDO()->prepare("SELECT username, password, admin FROM users WHERE username=:username");
|
|
$statement->bindValue(":username",$username, PDO::PARAM_STR);
|
|
$statement->execute();
|
|
}catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
|
|
return $statement->fetch(PDO::FETCH_ASSOC);
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Generate a random salt.
|
|
* @param $lenght the lenght of the salt, default is 8.
|
|
*
|
|
* On Linux (in particular Ubuntu), the password is generate with this command:
|
|
* "echo "${username}:${password}" | chpasswd -S -c $crypt_method | cut -d: -f2".
|
|
* in this particoular implementation I use MD5.
|
|
*
|
|
* Max length is 20 char!
|
|
*/
|
|
function generateRandomSalt($length = 8)
|
|
{
|
|
return substr(sha1(rand().time()), rand(0,20-$length), $length);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Revalidate login info and set authCheckHeartbeat session variable.
|
|
* @param vboxconnector $vbox vboxconnector object instance, THIS VARIABLE WILL NOT USED.
|
|
*/
|
|
function heartbeat($vbox)
|
|
{
|
|
global $_SESSION;
|
|
|
|
$q=$this->PDO_selectUser(@$_SESSION['user']);
|
|
$p=isset($q['password'])?$q['password']:0;
|
|
|
|
if($p && $p!=@$_SESSION[uHash])
|
|
{
|
|
$_SESSION['valid']=false;
|
|
session_destroy();
|
|
}
|
|
else
|
|
{
|
|
$_SESSION['admin']=intval(q['admin']);
|
|
$_SESSION['authCheckHeartbeat']=time();
|
|
}
|
|
|
|
if(!isset($_SESSION['valid']) || !$_SESSION['valid'])
|
|
throw new Exception(trans('Not logged in.','UIUsers'), vboxconnector::PHPVB_ERRNO_FATAL);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Log in function. Populates $_SESSION
|
|
* @param string $username user name
|
|
* @param string $password password
|
|
*/
|
|
function login($username, $password)
|
|
{
|
|
global $_SESSION;
|
|
|
|
$q=$this->PDO_selectUser($username);
|
|
$p=isset($q['password'])?$q['password']:0;
|
|
|
|
if($p && password_verify($password,$p))
|
|
{
|
|
$_SESSION['valid'] = true;
|
|
$_SESSION['user'] = $username;
|
|
$_SESSION['admin'] = intval($q['admin']);
|
|
$_SESSION['authCheckHeartbeat'] = time();
|
|
$_SESSION['uHash'] = $p;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Log out user present in $_SESSION
|
|
* @param array $response response passed byref by API and populated within function
|
|
*/
|
|
function logout(&$response)
|
|
{
|
|
global $_SESSION;
|
|
if(function_exists('session_destroy')) session_destroy();
|
|
else unset($_SESSION['valid']);
|
|
$response['data']['result'] = 1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Change password function.
|
|
* @param string $old old password
|
|
* @param string $new new password
|
|
* @return boolean true on success
|
|
*/
|
|
function changePassword($old, $new)
|
|
{
|
|
global $_SESSION;
|
|
|
|
$p=$this->PDO_selectUser($_SESSION['user']);
|
|
$p=isset($p['password'])?$p['password']:0; //along the time is changed?
|
|
|
|
if($p && password_verify($old, $p))
|
|
{
|
|
$np=crypt($new, '$1$'.$this->generateRandomSalt().'$'); //look the MD5 format!!
|
|
//look here for more info: http://php.net/manual/en/faq.passwords.php
|
|
try{
|
|
$sth=$this->newPDO()->prepare("UPDATE users SET password=:password WHERE username=:username");
|
|
$sth->bindValue(":password",$np,PDO::PARAM_STR);
|
|
$sth->bindValue(":username",$_SESSION['user'],PDO::PARAM_STR);
|
|
$sth->execute();
|
|
}catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Return a list of users
|
|
* @return array list of users
|
|
*/
|
|
function listUsers()
|
|
{
|
|
$response = array();
|
|
|
|
try{
|
|
$sth=$this->newPDO()->prepare("SELECT * FROM users");
|
|
$sth->execute();
|
|
}catch(PDOException $e){throw new Exception("Can't display users list!",vboxconnector::PHPVB_ERRNO_FATAL);}
|
|
|
|
while(($row=$sth->fetch(PDO::FETCH_ASSOC))!==FALSE)
|
|
{
|
|
$response[$row['username']]=array('username'=> $row['username'], 'admin'=> intval($row['admin']));
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Update user information such as password and admin status
|
|
* @param array $vboxRequest request passed from API representing the ajax request. Contains user, password and administration level.
|
|
* @param boolean $skipExistCheck Do not check that the user exists first. Essentially, if this is set and the user does not exist, it is added.
|
|
*/
|
|
function updateUser($vboxRequest, $skipExistCheck)
|
|
{
|
|
global $_SESSION;
|
|
|
|
|
|
if(!$_SESSION['admin']) return;
|
|
|
|
$q=$this->PDO_selectUser($vboxRequest['u']);
|
|
if(!$skipExistCheck && $q) return;
|
|
|
|
$np=($vboxRequest['p'])?crypt($vboxRequest['p'], '$1$'.$this->generateRandomSalt().'$'):0;
|
|
|
|
$query="INSERT INTO `users`(`username`, `password`,`admin`)
|
|
VALUES (:username, :password, :admin)
|
|
ON DUPLICATE KEY UPDATE `password`=:password, `admin`=:admin";
|
|
|
|
$sth=$this->newPDO()->prepare($query);
|
|
try{
|
|
$sth->bindValue(":username",$vboxRequest['u'],PDO::PARAM_STR);
|
|
$sth->bindValue(":password",($vboxRequest['p']?$np:$q['password']),PDO::PARAM_STR);
|
|
$sth->bindValue(":admin",($vboxRequest['a']?"1":"0"),PDO::PARAM_STR);
|
|
|
|
$sth->execute();
|
|
}catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Remove the user $user
|
|
* @param string $user Username to remove
|
|
*/
|
|
function deleteUser($user)
|
|
{
|
|
$sth=$this->newPDO()->prepare("DELETE FROM users WHERE username=:username");
|
|
try{
|
|
$sth->bindValue(":username",$user,PDO::PARAM_STR);
|
|
$sth->execute();
|
|
}catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
|
|
|
|
}
|
|
}
|