Guest User

Untitled

a guest
Dec 29th, 2018
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 19.94 KB | None | 0 0
  1. <?php
  2.  
  3. class Auth
  4. {
  5.     // Singleton object. Leave $me alone.
  6.     private static $me;
  7.     public $id;
  8.     public $username;
  9.     public $level_id;
  10.     public $user; // DBObject User object (if available)
  11.  
  12.     // Call with no arguments to attempt to restore a previous logged in session
  13.     // which then falls back to a guest user (which can then be logged in using
  14.     // $this->login($username, $rawPassword). Or pass a user_id to simply login that user. The
  15.     // $seriously is just a safeguard to be certain you really do want to blindly
  16.     // login a user. Set it to true.
  17.     private function __construct($userToImpersonate = null)
  18.     {
  19.         $this->id = null;
  20.         $this->username = null;
  21.         $this->level_id = 0;
  22.         $this->package_id = 0;
  23.         $this->level = UserPeer::getLevelLabel($this->level_id);
  24.         $this->user = null;
  25.  
  26.         if(class_exists('User') && (is_subclass_of('User', 'DBObject')))
  27.         {
  28.             $this->user = new User();
  29.         }
  30.  
  31.         if(!is_null($userToImpersonate))
  32.         {
  33.             return $this->impersonate($userToImpersonate);
  34.         }
  35.  
  36.         if($this->attemptSessionLogin())
  37.         {
  38.             return;
  39.         }
  40.     }
  41.  
  42.     /**
  43.      * Standard singleton
  44.      * @return Auth
  45.      */
  46.     public static function getAuth($userToImpersonate = null)
  47.     {
  48.         if(is_null(self::$me))
  49.         {
  50.             self::$me = new Auth($userToImpersonate);
  51.         }
  52.  
  53.         return self::$me;
  54.     }
  55.  
  56.     // You'll typically call this function when a user logs in using
  57.     // a form. Pass in their username and password.
  58.     // Takes a username and a *plain text* password
  59.     public function login($username, $rawPassword, $fromLoginForm = false)
  60.     {
  61.         $rs = $this->convertPassword($username, $rawPassword);
  62.         if($rs == false)
  63.         {
  64.             return false;
  65.         }
  66.  
  67.         return $this->attemptLogin($username, $rawPassword, false, $fromLoginForm);
  68.     }
  69.  
  70.     // manage convertions to sha256, this code is only for migration
  71.     public function convertPassword($username, $rawPassword)
  72.     {
  73.         // get database
  74.         $db = Database::getDatabase();
  75.  
  76.         // check for existing user
  77.         $user = $db->getRow('SELECT id, password FROM users WHERE username = ' . $db->quote($username));
  78.         if($user === false)
  79.         {
  80.             return false;
  81.         }
  82.  
  83.         // see if it matches the one entered
  84.         if($user['password'] == md5($rawPassword))
  85.         {
  86.             // create new password
  87.             $sha256Password = Password::createHash($rawPassword);
  88.  
  89.             // update user with new
  90.             $db->query('UPDATE users SET password = :password WHERE id = :id', array('password' => $sha256Password, 'id' => $user['id']));
  91.         }
  92.  
  93.         return true;
  94.     }
  95.  
  96.     public function logout()
  97.     {
  98.         $Config = Config::getConfig();
  99.  
  100.         $this->id = null;
  101.         $this->username = null;
  102.         $this->level_id = 0;
  103.         $this->package_id = 0;
  104.         $this->level = 'guest';
  105.         $this->user = null;
  106.  
  107.         if(class_exists('User') && (is_subclass_of('User', 'DBObject')))
  108.         {
  109.             $this->user = new User();
  110.         }
  111.  
  112.         $_SESSION['user'] = '';
  113.         unset($_SESSION['user']);
  114.         if(isset($_SESSION['_old_user']))
  115.         {
  116.             // revert old session if this is a logout of impersonate user
  117.             $_SESSION['user'] = $_SESSION['_old_user'];
  118.             $_SESSION['_old_user'] = '';
  119.             unset($_SESSION['_old_user']);
  120.  
  121.             // redirect to file manager as old user
  122.             coreFunctions::redirect(WEB_ROOT . '/account_home.html');
  123.         }
  124.         else
  125.         {
  126.             // clear session
  127.             session_destroy();
  128.             setcookie('spf', '.', time() - 3600, '/', $Config->authDomain);
  129.         }
  130.     }
  131.  
  132.     // Is a user logged in? This was broken out into its own function
  133.     // in case extra logic is ever required beyond a simple bool value.
  134.     public function loggedIn()
  135.     {
  136.         return $this->level_id > 0;
  137.     }
  138.  
  139.     // Helper function that redirects away from 'admin only' pages
  140.     public function requireAdmin()
  141.     {
  142.         // check for login attempts
  143.         if(isset($_REQUEST['username']) && isset($_REQUEST['password']))
  144.         {
  145.             $this->login($_REQUEST['username'], $_REQUEST['password']);
  146.         }
  147.  
  148.         // ensure it's an admin user
  149.         $this->requireAccessLevel(20, ADMIN_WEB_ROOT . "/login.php?error=1");
  150.     }
  151.  
  152.     // Helper function that redirects away from 'member only' pages
  153.     public function requireUser($url)
  154.     {
  155.         $this->requireAccessLevel(1, $url);
  156.     }
  157.  
  158.     /*
  159.      * Function to handle access rights and minimum permission levels for access.
  160.      * The higher the number the greater the permission requirement. See the
  161.      * database table called 'user_level' for the permission level_ids.
  162.      *
  163.      * @param type $level
  164.      */
  165.     public function requireAccessLevel($minRequiredLevel = 0, $redirectOnFailure = 'login.php')
  166.     {
  167.         // check for login attempts
  168.         if(isset($_REQUEST['username']) && isset($_REQUEST['password']))
  169.         {
  170.             $this->login($_REQUEST['username'], $_REQUEST['password']);
  171.         }
  172.  
  173.         $userType = UserPeer::getLevelTypeFromPackageId($this->package_id);
  174.         switch($minRequiredLevel)
  175.         {
  176.             case 0:
  177.                 if(in_array($userType, array('moderator', 'free', 'paid', 'admin', 'guest', 'nonuser')))
  178.                 {
  179.                     return true;
  180.                 }
  181.                 break;
  182.             case 1:
  183.                 if(in_array($userType, array('moderator', 'free', 'paid', 'admin')))
  184.                 {
  185.                     return true;
  186.                 }
  187.                 break;
  188.             case 20:
  189.                 if(in_array($userType, array('admin')))
  190.                 {
  191.                     return true;
  192.                 }
  193.                 break;
  194.             case 10:
  195.                 if(in_array($userType, array('moderator', 'admin')))
  196.                 {
  197.                     return true;
  198.                 }
  199.                 break;
  200.             case 2:
  201.                 if(in_array($userType, array('moderator', 'paid', 'admin')))
  202.                 {
  203.                     return true;
  204.                 }
  205.                 break;
  206.         }
  207.  
  208.         if(strlen($redirectOnFailure))
  209.         {
  210.             coreFunctions::redirect($redirectOnFailure);
  211.         }
  212.  
  213.         return false;
  214.     }
  215.  
  216.     public function hasAccessLevel($minRequiredLevel = 0)
  217.     {
  218.         return $this->requireAccessLevel($minRequiredLevel, null);
  219.     }
  220.  
  221.     // Login a user simply by passing in their username or id. Does
  222.     // not check against a password. Useful for allowing an admin user
  223.     // to temporarily login as a standard user for troubleshooting.
  224.     // Takes an id or username
  225.     public function impersonate($userToImpersonate)
  226.     {
  227.         $db = Database::getDatabase();
  228.         if(is_int($userToImpersonate))
  229.         {
  230.             $row = $db->getRow('SELECT * FROM users WHERE id = ' . (int) $userToImpersonate . ' LIMIT 1');
  231.         }
  232.         else
  233.         {
  234.             $row = $db->getRow('SELECT * FROM users WHERE username = ' . $db->quote($userToImpersonate) . ' LIMIT 1');
  235.         }
  236.  
  237.         if(is_array($row))
  238.         {
  239.             $this->id = $row['id'];
  240.             $this->username = $row['username'];
  241.             $this->email = $row['email'];
  242.             $this->package_id = $row['level_id'];
  243.             $this->level_id = UserPeer::getLevelIdFromPackageId($this->package_id);
  244.             $this->level = UserPeer::getLevelLabel($this->level_id);
  245.             $this->paidExpiryDate = $row['paidExpiryDate'];
  246.             $this->paymentTracker = $row['paymentTracker'];
  247.  
  248.             // load any additional user info if DBObject and User are available
  249.             $this->user = new User();
  250.             $this->user->id = $row['id'];
  251.             $this->user->load($row);
  252.  
  253.             // store in session
  254.             $this->storeSessionData();
  255.  
  256.             return true;
  257.         }
  258.  
  259.         return false;
  260.     }
  261.  
  262.     // Attempt to login using data stored in the current session
  263.     private function attemptSessionLogin()
  264.     {
  265.         if(isset($_SESSION['user']))
  266.         {
  267.             $sessionAuth = unserialize($_SESSION['user']);
  268.             if(is_object($sessionAuth))
  269.             {
  270.                 foreach($sessionAuth AS $k => $v)
  271.                 {
  272.                     $this->$k = $v;
  273.                 }
  274.             }
  275.  
  276.             return true;
  277.         }
  278.  
  279.         return false;
  280.     }
  281.  
  282.     // The function that actually verifies an attempted login and
  283.     // processes it if successful.
  284.     // Takes a username and a raw password
  285.     public function attemptLogin($username, $rawPassword, $sessionLogin = false, $fromLoginForm = false)
  286.     {
  287.         $db = Database::getDatabase();
  288.         $Config = Config::getConfig();
  289.  
  290.         // We SELECT * so we can load the full user record into the user DBObject later
  291.         $row = $db->getRow('SELECT * FROM users WHERE username = ' . $db->quote($username) . ' LIMIT 1');
  292.         if($row === false)
  293.         {
  294.             // log failure
  295.             Auth::logFailedLoginAttempt(coreFunctions::getUsersIPAddress(), $loginUsername);
  296.  
  297.             return false;
  298.         }
  299.  
  300.         // validate password
  301.         if($sessionLogin == false)
  302.         {
  303.             if(Password::validatePassword($rawPassword, $row['password']) === false)
  304.             {
  305.                 // log failure
  306.                 Auth::logFailedLoginAttempt(coreFunctions::getUsersIPAddress(), $loginUsername);
  307.  
  308.                 return false;
  309.             }
  310.         }
  311.  
  312.         // check for openssl, required for login
  313.         if(!extension_loaded('openssl'))
  314.         {
  315.             return false;
  316.         }
  317.  
  318.         // make sure account is active
  319.         if($row['status'] != "active")
  320.         {
  321.             return false;
  322.         }
  323.         else
  324.         {
  325.             // check user isn't banned from logging in
  326.             $bannedIp = bannedIP::getBannedIPData();
  327.             if($bannedIp)
  328.             {
  329.                 if($bannedIp['banType'] == 'Login')
  330.                 {
  331.                     return false;
  332.                 }
  333.             }
  334.         }
  335.  
  336.         // stop account sharing
  337.         if($fromLoginForm == true)
  338.         {
  339.             Auth::clearSessionByUserId($row['id']);
  340.         }
  341.  
  342.         $this->id = $row['id'];
  343.         $this->username = $row['username'];
  344.         $this->email = $row['email'];
  345.         $this->package_id = $row['level_id'];
  346.         $this->level_id = UserPeer::getLevelIdFromPackageId($this->package_id);
  347.         $this->level = UserPeer::getLevelLabel($this->level_id);
  348.         $this->paidExpiryDate = $row['paidExpiryDate'];
  349.         $this->paymentTracker = $row['paymentTracker'];
  350.  
  351.         // load any additional user info if DBObject and User are available
  352.         $this->user = new User();
  353.         $this->user->id = $row['id'];
  354.         $this->user->load($row);
  355.  
  356.         // update lastlogindate
  357.         $iPAddress = coreFunctions::getUsersIPAddress();
  358.         if($sessionLogin == false)
  359.         {
  360.             $db->query('UPDATE users SET lastlogindate = NOW(), lastloginip = :ip WHERE id = :id LIMIT 1', array('ip' => $iPAddress, 'id' => $this->id));
  361.         }
  362.  
  363.         // remove any failed logins for the IP address
  364.         Auth::clearAllLoginAttemptsForIp($iPAddress);
  365.  
  366.         // log IP address for login
  367.         if($fromLoginForm == true)
  368.         {
  369.             Auth::logSuccessfulLogin($this->id, $iPAddress);
  370.         }
  371.  
  372.         // delete old session data
  373.         $this->purgeOldSessionData();
  374.  
  375.         // setup session
  376.         $this->storeSessionData();
  377.         if(($sessionLogin == false) && (SITE_CONFIG_LANGUAGE_USER_SELECT_LANGUAGE == 'yes'))
  378.         {
  379.             $this->setSessionLanguage();
  380.         }
  381.  
  382.         return true;
  383.     }
  384.  
  385.     public function purgeOldSessionData()
  386.     {
  387.         // get database
  388.         $db = Database::getDatabase();
  389.  
  390.         // delete old session data
  391.         $db->query('DELETE FROM `sessions` WHERE `updated_on` < :updated_on', array('updated_on' => time() - (60 * 60 * 24 * 2))); // 2 days
  392.     }
  393.  
  394.     // reload session, used for account upgrades
  395.     public function reloadSession()
  396.     {
  397.         if($this->id == 0)
  398.         {
  399.             return false;
  400.         }
  401.  
  402.         // reload the user object
  403.         $this->user = UserPeer::loadUserById($this->id);
  404.  
  405.         // update the auth object
  406.         $this->id = $this->user->id;
  407.         $this->username = $this->user->username;
  408.         $this->email = $this->user->email;
  409.         $this->package_id = $this->user->level_id;
  410.         $this->level_id = UserPeer::getLevelIdFromPackageId($this->package_id);
  411.         $this->level = UserPeer::getLevelLabel($this->level_id);
  412.  
  413.         // setup session
  414.         $this->storeSessionData();
  415.     }
  416.  
  417.     public function getAccountScreenName()
  418.     {
  419.         return $this->user->getAccountScreenName();
  420.     }
  421.  
  422.     private function setSessionLanguage()
  423.     {
  424.         $db = Database::getDatabase();
  425.         $languageName = $db->getValue("SELECT languageName FROM language WHERE isActive = 1 AND id = " . $db->escape($this->user->languageId) . " LIMIT 1");
  426.         if($languageName)
  427.         {
  428.             $_SESSION['_t'] = $languageName;
  429.         }
  430.     }
  431.  
  432.     // stores current object in session
  433.     private function storeSessionData()
  434.     {
  435.         $_SESSION['user'] = serialize($this);
  436.     }
  437.  
  438.     private function createHashedPassword($rawPassword)
  439.     {
  440.         return MD5($rawPassword);
  441.     }
  442.    
  443.     // The function that actually verifies an attempted login and
  444.     // processes it if successful.
  445.     // Takes an API key pair
  446.     // @TODO - merge this with the attemptLogin function above
  447.     public function loginUsingApiPair($key1, $key2)
  448.     {
  449.         $db = Database::getDatabase();
  450.  
  451.         // check the api keys
  452.         $foundKeys = (int)$db->getValue('SELECT user_id FROM apiv2_api_key WHERE key_public = :key_public AND key_secret = :key_secret LIMIT 1', array(
  453.             'key_public' => $key1,
  454.             'key_secret' => $key2,
  455.         ));
  456.         if(!$foundKeys)
  457.         {
  458.            
  459.             // log failure
  460.             Auth::logFailedLoginAttempt(coreFunctions::getUsersIPAddress());
  461.  
  462.             return false;
  463.         }
  464.        
  465.         // we found the user, setup the session
  466.         $row = $db->getRow('SELECT * FROM users WHERE id = ' . (int)$foundKeys . ' LIMIT 1');
  467.         if($row === false)
  468.         {
  469.             return false;
  470.         }
  471.  
  472.         // make sure account is active
  473.         if($row['status'] != "active")
  474.         {
  475.             return false;
  476.         }
  477.         else
  478.         {
  479.             // check user isn't banned from logging in
  480.             $bannedIp = bannedIP::getBannedIPData();
  481.             if($bannedIp)
  482.             {
  483.                 if($bannedIp['banType'] == 'Login')
  484.                 {
  485.                     return false;
  486.                 }
  487.             }
  488.         }
  489.  
  490.         $this->id = $row['id'];
  491.         $this->username = $row['username'];
  492.         $this->email = $row['email'];
  493.         $this->package_id = $row['level_id'];
  494.         $this->level_id = UserPeer::getLevelIdFromPackageId($this->package_id);
  495.         $this->level = UserPeer::getLevelLabel($this->level_id);
  496.         $this->paidExpiryDate = $row['paidExpiryDate'];
  497.         $this->paymentTracker = $row['paymentTracker'];
  498.  
  499.         // load any additional user info if DBObject and User are available
  500.         $this->user = new User();
  501.         $this->user->id = $row['id'];
  502.         $this->user->load($row);
  503.  
  504.         // update lastlogindate
  505.         $iPAddress = coreFunctions::getUsersIPAddress();
  506.         $db->query('UPDATE users SET lastlogindate = NOW(), lastloginip = :ip WHERE id = :id LIMIT 1', array('ip' => $iPAddress, 'id' => $this->id));
  507.  
  508.         // remove any failed logins for the IP address
  509.         Auth::clearAllLoginAttemptsForIp($iPAddress);
  510.  
  511.         // log IP address for login
  512.         Auth::logSuccessfulLogin($this->id, $iPAddress);
  513.  
  514.         // delete old session data
  515.         $this->purgeOldSessionData();
  516.  
  517.         // setup session
  518.         $this->storeSessionData();
  519.  
  520.         return true;
  521.     }
  522.  
  523.     public static function logFailedLoginAttempt($ipAddress, $loginUsername = '')
  524.     {
  525.         // clear anything older than 24 hours
  526.         self::clearOldLoginAttempts();
  527.  
  528.         // get database
  529.         $db = Database::getDatabase();
  530.  
  531.         // add failed login attempt
  532.         $dbInsert = new DBObject("login_failure", array("ip_address", "date_added", "username"));
  533.         $dbInsert->ip_address = $ipAddress;
  534.         $dbInsert->date_added = coreFunctions::sqlDateTime();
  535.         $dbInsert->username = $loginUsername;
  536.         $dbInsert->insert();
  537.  
  538.         // block IP address if greater than x failed logins
  539.         if((int) SITE_CONFIG_SECURITY_BLOCK_IP_LOGIN_ATTEMPTS > 0)
  540.         {
  541.             $failedAttempts = (int) $db->getValue('SELECT COUNT(id) AS total FROM login_failure WHERE ip_address = ' . $db->quote($ipAddress));
  542.             if($failedAttempts >= SITE_CONFIG_SECURITY_BLOCK_IP_LOGIN_ATTEMPTS)
  543.             {
  544.                 // add IP address to block list
  545.                 $dbInsert = new DBObject("banned_ips", array("ipAddress", "banType", "banNotes", "dateBanned", "banExpiry"));
  546.                 $dbInsert->ipAddress = $ipAddress;
  547.                 $dbInsert->banType = 'Login';
  548.                 $dbInsert->banNotes = 'Banned after too many failed logins.';
  549.                 $dbInsert->dateBanned = coreFunctions::sqlDateTime();
  550.                 $dbInsert->banExpiry = date('Y-m-d H:i:s', strtotime('+24 hours'));
  551.                 $dbInsert->insert();
  552.             }
  553.         }
  554.     }
  555.  
  556.     public static function clearOldLoginAttempts()
  557.     {
  558.         // get database
  559.         $db = Database::getDatabase();
  560.  
  561.         // clear anything older than 24 hours
  562.         $db->query('DELETE FROM login_failure WHERE date_added < DATE_SUB(NOW(), INTERVAL 24 HOUR)');
  563.     }
  564.  
  565.     public static function clearAllLoginAttemptsForIp($ipAddress)
  566.     {
  567.         // get database
  568.         $db = Database::getDatabase();
  569.  
  570.         // clear anything older than 24 hours
  571.         $db->query('DELETE FROM login_failure WHERE ip_address = ' . $db->quote($ipAddress));
  572.     }
  573.  
  574.     public static function logSuccessfulLogin($userId, $ipAddress)
  575.     {
  576.         // clear anything older than 1 month
  577.         self::clearOldSuccessfulLogins();
  578.  
  579.         // get database
  580.         $db = Database::getDatabase();
  581.  
  582.         // try to find country code based on IP address
  583.         $countryCode = Stats::getCountry($ipAddress);
  584.         if(($countryCode == 'unknown') || ($countryCode == 'ZZ') || (!$countryCode))
  585.         {
  586.             $countryCode = '';
  587.         }
  588.         $countryCode = substr($countryCode, 0, 2);
  589.  
  590.         // add failed login attempt
  591.         $dbInsert = new DBObject("login_success", array("ip_address", "date_added", "user_id", "country_code"));
  592.         $dbInsert->ip_address = $ipAddress;
  593.         $dbInsert->date_added = coreFunctions::sqlDateTime();
  594.         $dbInsert->user_id = $userId;
  595.         $dbInsert->country_code = $countryCode;
  596.         $dbInsert->insert();
  597.     }
  598.  
  599.     public static function clearOldSuccessfulLogins()
  600.     {
  601.         // get database
  602.         $db = Database::getDatabase();
  603.  
  604.         // clear anything older than 1 month
  605.         $db->query('DELETE FROM login_success WHERE date_added < DATE_SUB(NOW(), INTERVAL 1 MONTH)');
  606.     }
  607.  
  608.     public static function clearSessionByUserId($userId)
  609.     {
  610.         // deletes any existing sessions for the same user id
  611.         if((SITE_CONFIG_PREMIUM_USER_BLOCK_ACCOUNT_SHARING == 'yes') && coreFunctions::currentIsMainSite())
  612.         {
  613.             $db = Database::getDatabase();
  614.             $db->query('DELETE FROM sessions WHERE user_id = ' . (int) $userId);
  615.         }
  616.     }
  617.  
  618.     public static function paymentCompleteReLogin()
  619.     {
  620.        
  621.     }
  622.  
  623. }
Add Comment
Please, Sign In to add comment