Browse Source

updated Libraries/Aauth

- added phpdoc
- updated functions
v3-dev
REJack 7 years ago
parent
commit
01949e66d6
  1. 513
      Libraries/Aauth.php

513
Libraries/Aauth.php

@ -1,20 +1,108 @@
<?php namespace Magefly\Aauth\Libraries; <?php namespace Magefly\Aauth\Libraries;
class Aauth { /**
* Aauth is a User Authorization Library for CodeIgniter 4.x, which aims to make
public $errors = array(); * easy some essential jobs such as login, permissions and access operations.
public $infos = array(); * Despite ease of use, it has also very advanced features like groupping,
public $flash_errors = array(); * access management, public access etc..
public $flash_infos = array(); *
* @package Aauth
function __construct() { * @author Magefly Team
$this->config = new Magefly\Aauth\Config\Aauth(); * @copyright 2018 Magefly
* @copyright 2014-2018 British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://github.com/magefly/CodeIgniter-Aauth
* @version 3.0.0-pre
*
* @todo separate (on some level) the unvalidated users from the "banned" users
*/
class Aauth
{
/**
* Variable for loading the config array into
*
* @var object
*/
private $config;
/**
* Variable for loading the session service into
*
* @var object
*/
private $session;
/**
* Array to store error messages
*
* @var array
*/
private $errors = [];
/**
* Local temporary storage for current flash errors
*
* Used to update current flash data list since flash data is only available on the next page refresh
*
* @var array
*/
private $flashErrors = [];
/**
* Array to store info messages
*
* @var array
*/
private $infos = [];
/**
* Local temporary storage for current flash infos
*
* Used to update current flash data list since flash data is only available on the next page refresh
*
* @var array
*/
private $flashInfos = [];
/**
* Array to cache permission-ids.
*
* @var array
*/
private $cachePermId = [];
/**
* Array to cache group-ids.
*
* @var array
*/
private $cacheGroupId = [];
/**
* Constructor
*
* Prepares config & session variable.
*/
function __construct()
{
$this->config = new \Magefly\Aauth\Config\Aauth();
$this->session = \Config\Services::session(); $this->session = \Config\Services::session();
} }
/**
* Create user
*
* Creates a new user
*
* @param string $email User's email address
* @param string $password User's password
* @param string $username User's username
*
* @return int|bool False if create fails or returns user id if successful
*/
public function createUser($email, $password, $username = null) public function createUser($email, $password, $username = null)
{ {
$user = new \Magefly\Aauth\Models\UserModel(); $userModel = new \Magefly\Aauth\Models\UserModel();
$data['email'] = $email; $data['email'] = $email;
$data['password'] = $password; $data['password'] = $password;
@ -24,32 +112,43 @@ class Aauth {
$data['username'] = $username; $data['username'] = $username;
} }
if ($user_id = $user->insert($data)) if ($userId = $userModel->insert($data))
{ {
return $user_id; return $userId;
} }
$this->error($user->errors()); $this->error($userModel->errors());
return false; return false;
} }
public function updateUser($user_id, $email = null, $password = null, $username = null) /**
* Update user
*
* Updates existing user details
*
* @param int $user_id User id to update
* @param string|bool $email User's email address, or FALSE if not to be updated
* @param string|bool $password User's password, or FALSE if not to be updated
* @param string|bool $name User's name, or FALSE if not to be updated
*
* @return bool Update fails/succeeds
*/
public function updateUser($userId, $email = null, $password = null, $username = null)
{ {
$user = new \Magefly\Aauth\Models\UserModel(); $userModel = new \Magefly\Aauth\Models\UserModel();
$data = []; $data = [];
if ( ! $user->exists($user_id)) if ( ! $userModel->existsById($userId))
{ {
$this->error(lang('Aauth.notFoundUser')); $this->error(lang('Aauth.notFoundUser'));
return false; return false;
} }
else if ( ! $email && ! $password && ! $username)
if ( ! $email && ! $password && ! $username)
{ {
return false; return false;
} }
$data['id'] = $user_id; $data['id'] = $userId;
if ($email) if ($email)
{ {
@ -66,149 +165,192 @@ class Aauth {
$data['username'] = $username; $data['username'] = $username;
} }
if ($user->update($user_id, $data)) if ($userModel->update($userId, $data))
{ {
return $user_id; return true;
} }
$this->error($user->errors()); $this->error($userModel->errors());
return false; return false;
} }
public function deleteUser(int $user_id) /**
* Delete user
*
*/
public function deleteUser(int $userId)
{ {
$user = new \Magefly\Aauth\Models\UserModel(); $userModel = new \Magefly\Aauth\Models\UserModel();
$data = []; $data = [];
if ( ! $user->exists($user_id)) if ( ! $userModel->existsById($userId))
{ {
$this->error(lang('Aauth.notFoundUser')); $this->error(lang('Aauth.notFoundUser'));
return false; return false;
} }
else if ($userModel->delete($userId))
if ($user->delete($user_id))
{ {
return true; return true;
} }
} }
public function listUsers(int $limit = 0, int $offset = 0, bool $include_banneds = null, array $order_by = null) /**
* List users
*
* Return users as an object array
*
* @todo bool|int $group_par Specify group id to list group or FALSE for all users
*
* @param string $limit Limit of users to be returned
* @param bool $offset Offset for limited number of users
* @param bool $include_banneds Include banned users
* @param string $sort Order by MYSQL string (e.g. 'name ASC', 'email DESC')
*
* @return array Array of users
*/
public function listUsers(int $limit = 0, int $offset = 0, bool $includeBanneds = null, array $orderBy = null)
{ {
$user = new \Magefly\Aauth\Models\UserModel(); $userModel = new \Magefly\Aauth\Models\UserModel();
$options = []; $options = [];
$user = $userModel->limit($limit, $offset);
// bool $group_par = null, // bool $group_par = null,
if ( ! $include_banneds) if ( ! $includeBanneds)
{ {
$options['where'] = ['banned' => 0]; $user->where('banned', 0);
} }
if ($order_by) if ($orderBy)
{ {
$options['order_by'] = $order_by; $user->orderBy($orderBy[0], $orderBy[1]);
} }
return $user->findAllExtra($limit, $offset, $options); return $user->findAll();
} }
public function login(string $identifier, string $password, bool $remember = null, bool $totp_code = null)
/**
* Login user
*
* Check provided details against the database. Add items to error array on fail, create session if success
*
* @todo add TOTP
* @todo add reCAPTCHA
* @todo add Remeber Cookie aka LoginToken (new DB)
*
* @param string $email
* @param string $pass
* @param bool $remember
* @param bool $totpCode
*
* @return bool Indicates successful login.
*/
public function login(string $identifier, string $password, bool $remember = null, bool $totpCode = null)
{ {
$user = new \Magefly\Aauth\Models\UserModel(); $userModel = new \Magefly\Aauth\Models\UserModel();
$loginAttempt = new \Magefly\Aauth\Models\LoginAttemptModel(); $loginAttemptModel = new \Magefly\Aauth\Models\LoginAttemptModel();
$userVariableModel = new \Magefly\Aauth\Models\UserVariableModel();
helper('cookie'); helper('cookie');
delete_cookie('user'); delete_cookie('user');
if ($this->config->loginProtection && ! $loginAttemptModel->update())
if ($this->config->loginProtection && ! $loginAttempt->update())
{ {
$this->error(lang('Aauth.loginAttemptsExceeded')); $this->error(lang('Aauth.loginAttemptsExceeded'));
return false; return false;
} }
// if($this->config_vars['ddos_protection'] && $this->config_vars['recaptcha_active'] && $loginAttempt->get() > $this->config_vars['recaptcha_login_attempts']){ // if($this->config->ddos_protection && $this->config->recaptcha_active && $loginAttempts->get() > $this->config->recaptcha_login_attempts){
// $this->CI->load->helper('recaptchalib'); // $this->CI->load->helper('recaptchalib');
// $reCaptcha = new ReCaptcha( $this->config_vars['recaptcha_secret']); // $reCaptcha = new ReCaptcha( $this->config->recaptcha_secret);
// $resp = $reCaptcha->verifyResponse( $this->CI->input->server("REMOTE_ADDR"), $this->CI->input->post("g-recaptcha-response") ); // $resp = $reCaptcha->verifyResponse( $this->CI->input->server("REMOTE_ADDR"), $this->CI->input->post("g-recaptcha-response") );
// if( ! $resp->success){ // if( ! $resp->success){
// $this->error($this->CI->lang->line('aauth_error_recaptcha_not_correct')); // $this->error($this->CI->lang->line('aauth_error_recaptcha_not_correct'));
// return FALSE; // return false;
// } // }
// } // }
if ($this->config->loginUseUsername)
{ if ($this->config->loginUseUsername)
{
if ( ! $identifier OR strlen($password) < $this->config->passwordMin OR strlen($password) > $this->config->passwordMax) if ( ! $identifier OR strlen($password) < $this->config->passwordMin OR strlen($password) > $this->config->passwordMax)
{ {
$this->error(lang('Aauth.loginFailedName')); $this->error(lang('Aauth.loginFailedName'));
return FALSE; return false;
} }
$db_identifier = 'username'; if ($user = $userModel->where('username', $identifier)->first())
{
}else{ $this->error(lang('Aauth.notFoundUser'));
$validation = \Config\Services::validation(); return false;
}
}
else
{
$validation = \Config\Services::validation();
if( ! $validation->check($identifier, 'valid_email') OR strlen($password) < $this->config->passwordMin OR strlen($password) > $this->config->passwordMax) if ( ! $validation->check($identifier, 'valid_email') OR strlen($password) < $this->config->passwordMin OR strlen($password) > $this->config->passwordMax)
{ {
$this->error(lang('Aauth.loginFailedEmail')); $this->error(lang('Aauth.loginFailedEmail'));
return FALSE; return false;
}
if ( ! $user = $userModel->where('email', $identifier)->first())
{
$this->error(lang('Aauth.notFoundUser'));
return false;
} }
$db_identifier = 'email';
}
$query = null;
$query = $this->aauth_db->where($db_identifier, $identifier);
$query = $this->aauth_db->where('banned', 1);
$query = $this->aauth_db->where('verification_code !=', '');
$query = $this->aauth_db->get($this->config_vars['users']);
if ($query->num_rows() > 0) {
$this->error($this->CI->lang->line('aauth_error_account_not_verified'));
return FALSE;
} }
// to find user id, create sessions and cookies
$query = $this->aauth_db->where($db_identifier, $identifier);
$query = $this->aauth_db->get($this->config_vars['users']); if ($user['banned'] && ! empty($userVariableModel->get($user['id'], 'verification_code', true)))
if($query->num_rows() == 0){ {
$this->error($this->CI->lang->line('aauth_error_no_user')); $this->error(lang('Aauth.notVerified'));
return FALSE; return false;
} }
if($this->config_vars['totp_active'] == TRUE AND $this->config_vars['totp_only_on_ip_change'] == FALSE AND $this->config_vars['totp_two_step_login_active'] == TRUE){ else if ($user['banned'])
if($this->config_vars['totp_two_step_login_active'] == TRUE){ {
$this->CI->session->set_userdata('totp_required', true); $this->error(lang('Aauth.invalidUserBanned'));
return false;
}
if ($this->config->totpEnabled && ! $this->config->totpOnIpChange && $this->config->totpLogin)
{
if ($this->config->totpLogin == true)
{
$this->session->set('totp_required', true);
} }
$query = null;
$query = $this->aauth_db->where($db_identifier, $identifier); $totp_secret = $userVariableModel->get($user['id'], 'totp_secret', true);
$query = $this->aauth_db->get($this->config_vars['users']); if ( ! empty($totp_secret) && ! $totp_code) {
$totp_secret = $query->row()->totp_secret; $this->error(lang('Aauth.requiredTOTPCode'));
if ($query->num_rows() > 0 AND !$totp_code) { return false;
$this->error($this->CI->lang->line('aauth_error_totp_code_required')); } else {
return FALSE; if( ! empty($totp_secret)){
}else {
if(!empty($totp_secret)){
$this->CI->load->helper('googleauthenticator'); $this->CI->load->helper('googleauthenticator');
$ga = new PHPGangsta_GoogleAuthenticator(); $ga = new PHPGangsta_GoogleAuthenticator();
$checkResult = $ga->verifyCode($totp_secret, $totp_code, 0); $checkResult = $ga->verifyCode($totp_secret, $totp_code, 0);
if (!$checkResult) { if ( ! $checkResult) {
$this->error($this->CI->lang->line('aauth_error_totp_code_invalid')); $this->error(lang('Aauth.invalidTOTPCode'));
return FALSE; return false;
} }
} }
} }
} }
if($this->config_vars['totp_active'] == TRUE AND $this->config_vars['totp_only_on_ip_change'] == TRUE){ else if ($this->config->totpEnabled && $this->config->totpOnIpChange)
{
$query = null; $query = null;
$query = $this->aauth_db->where($db_identifier, $identifier); $query = $this->aauth_db->where($db_identifier, $identifier);
$query = $this->aauth_db->get($this->config_vars['users']); $query = $this->aauth_db->get($this->config->users);
$totp_secret = $query->row()->totp_secret; $totp_secret = $query->row()->totp_secret;
$ip_address = $query->row()->ip_address; $ip_address = $query->row()->ip_address;
$current_ip_address = $this->CI->input->ip_address(); $current_ip_address = $this->CI->input->ip_address();
if ($query->num_rows() > 0 AND !$totp_code) { if ($query->num_rows() > 0 AND !$totp_code) {
if($ip_address != $current_ip_address ){ if($ip_address != $current_ip_address ){
if($this->config_vars['totp_two_step_login_active'] == FALSE){ if($this->config->totpLogin == false){
$this->error($this->CI->lang->line('aauth_error_totp_code_required')); $this->error($this->CI->lang->line('aauth_error_totp_code_required'));
return FALSE; return false;
} else if($this->config_vars['totp_two_step_login_active'] == TRUE){ } else if($this->config->totpLogin == true){
$this->CI->session->set_userdata('totp_required', true); $this->session->set('totp_required', true);
} }
} }
}else { }else {
@ -219,87 +361,119 @@ class Aauth {
$checkResult = $ga->verifyCode($totp_secret, $totp_code, 0); $checkResult = $ga->verifyCode($totp_secret, $totp_code, 0);
if (!$checkResult) { if (!$checkResult) {
$this->error($this->CI->lang->line('aauth_error_totp_code_invalid')); $this->error($this->CI->lang->line('aauth_error_totp_code_invalid'));
return FALSE; return false;
} }
} }
} }
} }
} }
$query = null;
$query = $this->aauth_db->where($db_identifier, $identifier); if ( ! $user['banned'] && password_verify($password, $user['password']))
$query = $this->aauth_db->where('banned', 0); {
$query = $this->aauth_db->get($this->config_vars['users']); $data = [
$row = $query->row(); 'id' => $user['id'],
// if email and pass matches and not banned 'username' => $user['username'],
$password = ($this->config_vars['use_password_hash'] ? $password : $this->hash_password($password, $row->id)); 'email' => $user['email'],
if ( $query->num_rows() != 0 && $this->verify_password($password, $row->password) ) { 'loggedin' => true
// If email and pass matches ];
// create session
$data = array( $this->session->set($data);
'id' => $row->id,
'username' => $row->username, // if ( $remember ){
'email' => $row->email, // helper('text');
'loggedin' => TRUE // $this->CI->load->helper('string');
); // $expire = $this->config->loginRemember;
$this->CI->session->set_userdata($data); // $remember_date = date("Y-m-d", strtotime($expire) );
if ( $remember ){ // $random_string = random_string('alnum', 16);
$this->CI->load->helper('string'); // $this->updateRemember($row->id, $random_string, $remember_date );
$expire = $this->config_vars['remember']; // $cookie = array(
$today = date("Y-m-d"); // 'name' => 'user',
$remember_date = date("Y-m-d", strtotime($today . $expire) ); // 'value' => $row->id . "-" . $random_string,
$random_string = random_string('alnum', 16); // 'expire' => 99*999*999,
$this->update_remember($row->id, $random_string, $remember_date ); // 'path' => '/',
$cookie = array( // );
'name' => 'user', // $this->CI->input->set_cookie($cookie);
'value' => $row->id . "-" . $random_string, // }
'expire' => 99*999*999,
'path' => '/', $userModel->updateLastLogin($user['id']);
); $userModel->updateLastActivity($user['id']);
$this->CI->input->set_cookie($cookie);
} if ($this->config->loginAttemptRemoveSuccessful)
// update last login {
$this->update_last_login($row->id); $loginAttemptModel->delete();
$this->update_activity();
if($this->config_vars['remove_successful_attempts'] == TRUE){
$this->reset_login_attempts();
} }
return TRUE;
return true;
} }
// if not matches else
else { {
$this->error($this->CI->lang->line('aauth_error_login_failed_all')); $this->error(lang('Aauth.loginFailedAll'));
return FALSE; return false;
} }
} }
/**
* Error
*
* Add message to error array and set flash data
*
* @param string $message Message to add to array
* @param bool $flashdata if TRUE add $message to CI flashdata (deflault: FALSE)
*/
public function error($message = '', $flashdata = null) public function error($message = '', $flashdata = null)
{ {
$this->errors[] = $message; $this->errors[] = $message;
if ($flashdata) if ($flashdata)
{ {
$this->flash_errors[] = $message; $this->flashErrors[] = $message;
$this->session->set('errors', $this->flash_errors); $this->session->set('errors', $this->flashErrors);
$this->session->setFlashdata('errors'); $this->session->setFlashdata('errors');
} }
} }
/**
* Keep Errors
*
* Keeps the flashdata errors for one more page refresh. Optionally adds the default errors into the
* flashdata list. This should be called last in your controller, and with care as it could continue
* to revive all errors and not let them expire as intended.
* Benefitial when using Ajax Requests
*
* @see http://ellislab.com/codeigniter/user-guide/libraries/sessions.html
*
* @param bool $include_non_flash TRUE if it should stow basic errors as flashdata (default = FALSE)
*/
public function keepErrors($includeNonFlash = null) public function keepErrors($includeNonFlash = null)
{ {
if ($includeNonFlash) if ($includeNonFlash)
$this->flash_errors = array_merge($this->flash_errors, $this->errors); $this->flashErrors = array_merge($this->flashErrors, $this->errors);
$this->flash_errors = array_merge($this->flash_errors, (array)$this->session->getFlashdata('errors')); $this->flashErrors = array_merge($this->flashErrors, (array)$this->session->getFlashdata('errors'));
$this->session->set('errors', $this->flash_errors); $this->session->set('errors', $this->flashErrors);
$this->session->setFlashdata('errors'); $this->session->setFlashdata('errors');
} }
/**
* Get Errors Array
*
* Return array of errors
*
* @return array Array of messages, empty array if no errors
*/
public function getErrorsArray() public function getErrorsArray()
{ {
return $this->errors; return $this->errors;
} }
/**
* Print Errors
*
* Prints string of errors separated by delimiter
*
* @param string $divider Separator for errors
*/
public function printErrors($divider = '<br />', $return = null) public function printErrors($divider = '<br />', $return = null)
{ {
$msg = ''; $msg = '';
@ -322,39 +496,79 @@ class Aauth {
echo $msg; echo $msg;
} }
/**
* Clear Errors
*
* Removes errors from error list and clears all associated flashdata
*/
public function clearErrors() public function clearErrors()
{ {
$this->errors = array(); $this->errors = [];
$this->session->remove('errors'); $this->session->remove('errors');
} }
/**
* Info
*
* Add message to info array and set flash data
*
* @param string $message Message to add to infos array
* @param boolean $flashdata if TRUE add $message to CI flashdata (deflault: FALSE)
*/
public function info($message = '', $flashdata = null) public function info($message = '', $flashdata = null)
{ {
$this->infos[] = $message; $this->infos[] = $message;
if ($flashdata) if ($flashdata)
{ {
$this->flash_infos[] = $message; $this->flashInfos[] = $message;
$this->session->set('infos', $this->flash_infos); $this->session->set('infos', $this->flashInfos);
$this->session->setFlashdata('infos'); $this->session->setFlashdata('infos');
} }
} }
/**
* Keep Infos
*
* Keeps the flashdata infos for one more page refresh. Optionally adds the default infos into the
* flashdata list. This should be called last in your controller, and with care as it could continue
* to revive all infos and not let them expire as intended.
* Benefitial by using Ajax Requests
*
* @see http://ellislab.com/codeigniter/user-guide/libraries/sessions.html
*
* @param boolean $include_non_flash TRUE if it should stow basic infos as flashdata (default = FALSE)
*/
public function keepInfos($includeNonFlash = null) public function keepInfos($includeNonFlash = null)
{ {
if ($includeNonFlash) if ($includeNonFlash)
$this->flash_infos = array_merge($this->flash_infos, $this->infos); $this->flashInfos = array_merge($this->flashInfos, $this->infos);
$this->flash_infos = array_merge($this->flash_infos, (array)$this->session->getFlashdata('infos')); $this->flashInfos = array_merge($this->flashInfos, (array)$this->session->getFlashdata('infos'));
$this->session->set('infos', $this->flash_infos); $this->session->set('infos', $this->flashInfos);
$this->session->setFlashdata('infos'); $this->session->setFlashdata('infos');
} }
/**
* Get Info Array
*
* Return array of infos
*
* @return array Array of messages, empty array if no errors
*/
public function getInfosArray() public function getInfosArray()
{ {
return $this->infos; return $this->infos;
} }
/**
* Print Info
*
* Print string of info separated by delimiter
*
* @param string $divider Separator for info
*
*/
public function printInfos($divider = '<br />', $return = null) public function printInfos($divider = '<br />', $return = null)
{ {
$msg = ''; $msg = '';
@ -375,9 +589,14 @@ class Aauth {
echo $msg; echo $msg;
} }
/**
* Clear Info List
*
* Removes info messages from info list and clears all associated flashdata
*/
public function clearInfos() public function clearInfos()
{ {
$this->infos = array(); $this->infos = [];
$this->session->remove('infos'); $this->session->remove('infos');
} }
} }

Loading…
Cancel
Save