diff options
author | Paul 'flowerysong' Arthur <flowerysong00@yahoo.com> | 2010-05-29 08:33:48 +0000 |
---|---|---|
committer | Paul 'flowerysong' Arthur <flowerysong00@yahoo.com> | 2010-05-29 08:33:48 +0000 |
commit | 67be60ae0997648e7ac4b2d5ab61996efedd630b (patch) | |
tree | 01d0704609d91719889c0151cd12867a081b33e5 /lib/class/vauth.class.php | |
parent | a94a213d72cc2982cba2952d721236cc62a6d9d4 (diff) | |
download | ampache-67be60ae0997648e7ac4b2d5ab61996efedd630b.tar.gz ampache-67be60ae0997648e7ac4b2d5ab61996efedd630b.tar.bz2 ampache-67be60ae0997648e7ac4b2d5ab61996efedd630b.zip |
Cleanup and rationalisation of authentication related code. Among other things,
fixes FS#99.
Diffstat (limited to 'lib/class/vauth.class.php')
-rw-r--r-- | lib/class/vauth.class.php | 337 |
1 files changed, 181 insertions, 156 deletions
diff --git a/lib/class/vauth.class.php b/lib/class/vauth.class.php index cc11328f..0568026b 100644 --- a/lib/class/vauth.class.php +++ b/lib/class/vauth.class.php @@ -27,17 +27,12 @@ */ class vauth { - /* Variables from DB */ - - /** * Constructor * This should never be called */ private function __construct() { - // Rien a faire - } // __construct /** @@ -45,10 +40,10 @@ class vauth { * This function is for opening a new session so we just verify that we * have a database connection, nothing more is needed */ - public static function open($save_path,$session_name) { + public static function open($save_path, $session_name) { if (!is_resource(Dba::dbh())) { - debug_event('SESSION','Error no database connection session failed','1'); + debug_event('SESSION', 'Error: no database connection session failed', '1'); return false; } @@ -58,7 +53,7 @@ class vauth { /** * close - * This is run on the end of a sessoin, nothing to do here for now + * This is run on the end of a session, nothing to do here for now */ public static function close() { @@ -75,7 +70,7 @@ class vauth { $results = self::get_session_data($key); if (!is_array($results)) { - debug_event('SESSION','Error unable to read session from key ' . $key . ' no data found','1'); + debug_event('SESSION', 'Error unable to read session from key ' . $key . ' no data found', '1'); return false; } @@ -85,22 +80,27 @@ class vauth { /** * write - * This saves the sessoin information into the database + * This saves the session information into the database */ - public static function write($key,$value) { + public static function write($key, $value) { if (NO_SESSION_UPDATE == '1') { return true; } $length = Config::get('session_length'); $value = Dba::escape($value); $key = Dba::escape($key); - // Check to see if remember me cookie is set, if so use remember length, otherwise use the session length - $expire = isset($_COOKIE[Config::get('session_name') . '_remember']) ? time() + Config::get('remember_length') : time() + Config::get('session_length'); - - $sql = "UPDATE `session` SET `value`='$value', `expire`='$expire' WHERE `id`='$key'"; + // Check to see if remember me cookie is set, if so use remember + // length, otherwise use the session length + $expire + = isset($_COOKIE[Config::get('session_name') . '_remember']) + ? time() + Config::get('remember_length') + : time() + Config::get('session_length'); + + $sql = "UPDATE `session` SET `value`='$value', " . + "`expire`='$expire' WHERE `id`='$key'"; $db_results = Dba::read($sql); - debug_event('SESSION','Writing to ' . $key . ' with expire ' . $expire . ' ' . Dba::error(),'6'); + debug_event('SESSION', 'Writing to ' . $key . ' with expire ' . $expire . ' ' . Dba::error(), '6'); return $db_results; @@ -120,10 +120,10 @@ class vauth { $sql = "DELETE FROM `session` WHERE `id`='$key'"; $db_results = Dba::write($sql); - debug_event('SESSION','Deleting Session with key:' . $key,'6'); + debug_event('SESSION', 'Deleting Session with key:' . $key, '6'); - // Destory our cookie! - setcookie(Config::get('session_name'),'',time() - 86400); + // Destroy our cookie! + setcookie(Config::get('session_name'), '', time() - 86400); return true; @@ -131,7 +131,7 @@ class vauth { /** * gc - * This function is randomly called and it cleans up the poo + * This function is randomly called and it cleans up the spoo */ public static function gc($maxlifetime) { @@ -152,7 +152,7 @@ class vauth { * This is the function used for the Ajax logouts, if no id is passed * it tries to find one from the session */ - public static function logout($key='',$relogin=true) { + public static function logout($key='', $relogin=true) { // If no key is passed try to find the session id $key = $key ? $key : session_id(); @@ -166,7 +166,7 @@ class vauth { $target = Config::get('web_path') . '/login.php'; } - // Do a quick check to see if this is an AJAX'd logout request + // Do a quick check to see if this is an AJAXed logout request // if so use the iframe to redirect if (AJAX_INCLUDE == '1') { ob_end_clean(); @@ -183,10 +183,8 @@ class vauth { $results['rfc3514'] = '<script type="text/javascript">reload_logout("'.$target.'")</script>'; echo xml_from_array($results); } - - - /* Redirect them to the login page */ - if (AJAX_INCLUDE != '1') { + else { + /* Redirect them to the login page */ header('Location: ' . $target); } @@ -206,19 +204,17 @@ class vauth { $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '" . time() . "'"; $db_results = Dba::read($sql); - $results = Dba::fetch_assoc($db_results); - - if (!count($results)) { - return false; + if ($results = Dba::fetch_assoc($db_results)) { + return $results; } - return $results; + return false; } // get_session_data /** * create_cookie - * This is seperated into its own function because of some flaws in + * This is separated into its own function because of some flaws in * specific webservers *cough* IIS *cough* which prevent us from setting * a cookie at the same time as a header redirect. As such on view of a * login a cookie is set with the proper name @@ -251,7 +247,7 @@ class vauth { $session_name = Config::get('session_name'); Config::set('cookie_life',$remember_length,'1'); - setcookie($session_name . '_remember',"Rappelez-vous, rappelez-vous le 27 mars",time() + $remember_length,'/'); + setcookie($session_name . '_remember',"Rappelez-vous, rappelez-vous le 27 mars", time() + $remember_length, '/'); } // create_remember_cookie @@ -273,16 +269,19 @@ class vauth { default: session_regenerate_id(); - // Before refresh we don't have the cookie so we have to use session ID + // Before refresh we don't have the cookie so we + // have to use session ID $key = session_id(); break; } // end switch on data type $username = Dba::escape($data['username']); - $ip = $_SERVER['REMOTE_ADDR'] ? Dba::escape(inet_pton($_SERVER['REMOTE_ADDR'])) : '0'; + $ip = $_SERVER['REMOTE_ADDR'] + ? Dba::escape(inet_pton($_SERVER['REMOTE_ADDR'])) + : '0'; $type = Dba::escape($data['type']); $value = Dba::escape($data['value']); - $agent = Dba::escape(substr($_SERVER['HTTP_USER_AGENT'],0,254)); + $agent = Dba::escape(substr($_SERVER['HTTP_USER_AGENT'], 0, 254)); $expire = Dba::escape(time() + Config::get('session_length')); /* We can't have null things here people */ @@ -294,11 +293,11 @@ class vauth { $db_results = Dba::write($sql); if (!$db_results) { - debug_event('SESSION',"Session Creation Failed with Query: $sql and " . Dba::error(),'1'); + debug_event('SESSION', "Session Creation Failed with Query: $sql and " . Dba::error(), '1'); return false; } - debug_event('SESSION','Session Created:' . $key,'6'); + debug_event('SESSION', 'Session Created:' . $key, '6'); return $key; @@ -306,14 +305,14 @@ class vauth { /** * check_session - * This checks for an existing sessoin and if it's still valid then go ahead and start it and return - * true + * This checks for an existing session. If it's still valid we go ahead + * and start it and return true. */ public static function check_session() { $session_name = Config::get('session_name'); - // No cookie n go! + // No cookie no go! if (!isset($_COOKIE[$session_name])) { return false; } // Check for a remember me @@ -321,7 +320,8 @@ class vauth { self::create_remember_cookie(); } - // Setup the cookie params before we start the session this is vital + // Set up the cookie params before we start the session. + // This is vital session_set_cookie_params( Config::get('cookie_life'), Config::get('cookie_path'), @@ -345,7 +345,7 @@ class vauth { * exists, it also provides an array of key'd data that may be required * based on the type */ - public static function session_exists($type,$key,$data=array()) { + public static function session_exists($type, $key, $data=array()) { // Switch on the type they pass switch ($type) { @@ -353,18 +353,24 @@ class vauth { case 'api': $key = Dba::escape($key); $time = time(); - $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '$time' AND `type`='$type'"; + $sql = "SELECT * FROM `session` WHERE " . + "`id`='$key' AND `expire` > '$time' " . + "AND `type`='$type'"; $db_results = Dba::read($sql); if (Dba::num_rows($db_results)) { return true; } break; - //FIXME: This should use the IN() mojo and compare against enabled auths case 'interface': $key = Dba::escape($key); $time = time(); - $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '$time' AND `type`!='api' AND `type`!='xml-rpc'"; + // Build a list of enabled authentication types + $enabled_types = implode("','", + Config::get('auth_methods')); + $sql = "SELECT * FROM `session` WHERE " . + "`id`='$key' AND `expire` > '$time' " . + "AND `type` IN('$enabled_types')"; $db_results = Dba::read($sql); if (Dba::num_rows($db_results)) { @@ -375,7 +381,9 @@ class vauth { $key = Dba::escape($key); $ip = Dba::escape(inet_pton($data['ip'])); $agent = Dba::escape($data['agent']); - $sql = "SELECT * FROM `session_stream` WHERE `id`='$key' AND `expire` > '$time' AND `ip`='$ip' AND `agent`='$agent'"; + $sql = "SELECT * FROM `session_stream` WHERE " . + "`id`='$key' AND `expire` > '$time' " . + "AND `ip`='$ip' AND `agent`='$agent'"; $db_results = Dba::read($sql); if (Dba::num_rows($db_results)) { @@ -395,19 +403,22 @@ class vauth { /** * session_extend - * This should really be extend_session but hey you gotta go with the flow - * this takes a SID and extends it's expire + * This should really be extend_session but hey you gotta go with the + * flow. + * This takes a SID and extends its expiration. */ public static function session_extend($sid) { $sid = Dba::escape($sid); - $expire = isset($_COOKIE[Config::get('session_name') . '_remember']) ? time() + Config::get('remember_length') : time() + Config::get('session_length'); + $expire = isset($_COOKIE[Config::get('session_name') . '_remember']) + ? time() + Config::get('remember_length') + : time() + Config::get('session_length'); $len = $expire - time(); $sql = "UPDATE `session` SET `expire`='$expire' WHERE `id`='$sid'"; $db_results = Dba::write($sql); - debug_event('SESSION','Session:' . $sid . ' Has been Extended to ' . date("r",$expire) . ' extension length ' . $len,'6'); + debug_event('SESSION', 'Session:' . $sid . ' has been extended to ' . date("r",$expire) . ' extension length ' . $len, '6'); return $db_results; @@ -415,7 +426,8 @@ class vauth { /** * _auto_init - * This function is called when the object is included, this sets up the session_save_handler + * This function is called when the object is included, this sets up the + * session_save_handler */ public static function _auto_init() { @@ -424,15 +436,21 @@ class vauth { exit; } - session_set_save_handler(array('vauth','open'),array('vauth','close'),array('vauth','read'),array('vauth','write'),array('vauth','destroy'),array('vauth','gc')); + session_set_save_handler( + array('vauth', 'open'), + array('vauth', 'close'), + array('vauth', 'read'), + array('vauth', 'write'), + array('vauth', 'destroy'), + array('vauth', 'gc')); } // auto init /** * ungimp_ie * This function sets the cache limiting to public if you are running - * some flavor of IE. The detection used here is very conservative so feel free - * to fix it. This only has to be done if we're rolling HTTPS + * some flavor of IE. The detection used here is very conservative so + * feel free to fix it. This only has to be done if we're rolling HTTPS. */ public static function ungimp_ie() { @@ -442,7 +460,8 @@ class vauth { // Try to detect IE $agent = trim($_SERVER['HTTP_USER_AGENT']); - if (strstr($agent,'MSIE') || strstr($agent,'Internet Explorer/')) { + if ((strpos($agent, 'MSIE') !== false) || + (strpos($agent,'Internet Explorer/') !== false)) { session_cache_limiter('public'); } @@ -452,22 +471,24 @@ class vauth { /** * authenticate - * This takes a username and password and then returns true or false - * based on what happens when we try to do the auth then + * This takes a username and password and then returns the results + * based on what happens when we try to do the auth. */ - public static function authenticate($username,$password) { + public static function authenticate($username, $password) { // Foreach the auth methods foreach (Config::get('auth_methods') as $method) { - // Build the function name and call the custom method on this class + // Build the function name and call it $function_name = $method . '_auth'; - if (!method_exists('vauth',$function_name)) { continue; } + if (!method_exists('vauth', $function_name)) { + continue; + } - $results = self::$function_name($username,$password); + $results = self::$function_name($username, $password); - // If we achive victory return + // If we achieve victory return if ($results['success']) { break; } } // end foreach @@ -478,48 +499,49 @@ class vauth { /** * mysql_auth - * This is the core function of authentication by ampache. It checks their current password - * and then tries to figure out if it can use the new SHA password hash or if it needs to fall - * back on the mysql method + * This is the core function of our built-in authentication. It checks + * their current password and then tries to figure out if it can use the + * new SHA password hash or if it needs to fall back on the old mysql + * method. */ - private static function mysql_auth($username,$password) { + private static function mysql_auth($username, $password) { $username = Dba::escape($username); - $password = Dba::escape($password); - - if (!strlen($password) OR !strlen($username)) { - Error::add('general',_('Error Username or Password incorrect, please try again')); - return false; - } - - // We have to pull the password in order to figure out how to handle it *cry* - $sql = "SELECT `password` FROM `user` WHERE `username`='$username'"; - $db_results = Dba::read($sql); - $row = Dba::fetch_assoc($db_results); - - // If it's using the old method then roll with that - if (substr($row['password'],0,1) == '*' OR strlen($row['password']) < 32) { - $response = self::vieux_mysql_auth($username,$password); - return $response; - } - // Use SHA2 now... cooking with fire, SHA3 in 2012 *excitement* - $password = hash('sha256',$password); - - $sql = "SELECT `username`,`id` FROM `user` WHERE `password`='$password' AND `username`='$username'"; - $db_results = Dba::read($sql); - - $row = Dba::fetch_assoc($db_results); + if (strlen($password) && strlen($username)) { + $sql = "SELECT `password` FROM `user` WHERE " . + "`username`='$username'"; + $db_results = Dba::read($sql); + if ($row = Dba::fetch_assoc($db_results)) { + + // If it's using the old method + if (substr($row['password'], 0, 1) == '*' || + strlen($row['password']) < 32) { + $password = Dba::escape(scrub_in($password)); + return self::vieux_mysql_auth($username, $password); + } - if (!count($row)) { - Error::add('general',_('Error Username or Password incorrect, please try again')); - return false; + // Use SHA2 now... cooking with fire. + // For backwards compatibility, we hash a couple + // of different variations of the password. + // Increases collision chances, but doesn't + // break things. + $hashed_password[] = hash('sha256', $password); + $hashed_password[] = hash('sha256', + Dba::escape(scrub_in($password))); + if(in_array($row['password'], $hashed_password)) { + $results['success'] = true; + $results['type'] = 'mysql'; + $results['username'] = $username; + return $results; + } + } } - $row['type'] = 'mysql'; - $row['success'] = true; - - return $row; + // Default to failure + $results['success'] = false; + $results['error'] = 'MySQL login attempt failed'; + return $results; } // mysql_auth @@ -527,47 +549,41 @@ class vauth { * vieux_mysql_auth * This is a private function, it should only be called by authenticate */ - private static function vieux_mysql_auth($username,$password) { + private static function vieux_mysql_auth($username, $password) { $password_check_sql = "PASSWORD('$password')"; - // This has to still be here because lots of people use old_password in their config file + // This has to still be here because lots of people use + // old_password in their config file $sql = "SELECT `password` FROM `user` WHERE `username`='$username'"; $db_results = Dba::read($sql); $row = Dba::fetch_assoc($db_results); - $sql = "SELECT version()"; + $sql = 'SELECT version()'; $db_results = Dba::read($sql); $version = Dba::fetch_row($db_results); - $mysql_version = substr(preg_replace("/(\d+)\.(\d+)\.(\d+).*/","$1$2$3",$version[0]),0,3); + $mysql_version = substr( + preg_replace("/(\d+)\.(\d+)\.(\d+).*/", "$1$2$3", + $version[0]), + 0, 3); - if ($mysql_version > "409" AND substr($row['password'],0,1) !== "*") { + if ($mysql_version > '409' && + substr($row['password'], 0, 1) !== "*") { $password_check_sql = "OLD_PASSWORD('$password')"; } $sql = "SELECT `username`,`id` FROM `user` WHERE `username`='$username' AND `password`=$password_check_sql"; $db_results = Dba::read($sql); - $results = Dba::fetch_assoc($db_results); - - if (!$results) { - Error::add('general',_('Error Username or Password incorrect, please try again')); - return false; + if (Dba::fetch_assoc($db_results)) { + $results['type'] = 'mysql'; + $results['password'] = 'old'; + $results['success'] = true; + } + else { + $results['success'] = false; + $results['error'] = 'Old MySQL login attempt failed'; } - - if (Config::get('prevent_multiple_logins')) { - $client = new User($results['id']); - $current_ip = $client->is_logged_in(); - if ($current_ip AND $current_ip != inet_pton($_SERVER['REMOTE_ADDR'])) { - debug_event('Login','Concurrent Login Failure, attempted to login from ' . $_SERVER['REMOTE_ADDR'] . ' and already logged in','1'); - Error::add('general','User Already Logged in'); - return false; - } - } // if prevent_multiple_logins - - $results['type'] = 'mysql'; - $results['password'] = 'old'; - $results['success'] = true; return $results; @@ -575,23 +591,26 @@ class vauth { /** * local_auth - * Check to make sure the pam_auth function is implemented (module is installed) then check the credentials + * Check to make sure the pam_auth function is implemented (module is + * installed), then check the credentials. */ - private static function local_auth($username,$password) { + private static function local_auth($username, $password) { if (!function_exists('pam_auth')) { - $results['success'] = false; - $results['error'] = "The PAM authentication PHP module is not installed."; + $results['success'] = false; + $results['error'] = 'The PAM PHP module is not installed'; return $results; } - if (pam_auth($username, $password, &$results['error'])) { - $results['success'] = true; - $results['type'] = 'local'; - $results['username'] = $username; + $password = scrub_in($password); + + if (pam_auth($username, $password)) { + $results['success'] = true; + $results['type'] = 'local'; + $results['username'] = $username; } else { - $results['success'] = false; - $results['error'] = "PAM login attempt failed"; + $results['success'] = false; + $results['error'] = 'PAM login attempt failed'; } return $results; @@ -599,15 +618,20 @@ class vauth { /** * ldap_auth - * Step one, connect to the LDAP server and perform a search for teh username provided. - * If its found, attempt to bind using that username and the password provided. - * Step two, figure out if they are authorized to use ampache: - * TODO: need implimented still: - * * require-group "The DN fetched from the LDAP directory (or the username passed by the client) occurs in the LDAP group" - * * require-dn "Grant access if the DN in the directive matches the DN fetched from the LDAP directory" - * * require-attribute "an attribute fetched from the LDAP directory matches the given value" + * Step one, connect to the LDAP server and perform a search for the + * username provided. + * Step two, attempt to bind using that username and the password + * provided. + * Step three, figure out if they are authorized to use ampache: + * TODO: in config but unimplemented: + * * require-group "The DN fetched from the LDAP directory (or the + * username passed by the client) occurs in the LDAP group" + * * require-dn "Grant access if the DN in the directive matches + * the DN fetched from the LDAP directory" + * * require-attribute "an attribute fetched from the LDAP + * directory matches the given value" */ - private static function ldap_auth($username,$password) { + private static function ldap_auth($username, $password) { $ldap_username = Config::get('ldap_username'); $ldap_password = Config::get('ldap_password'); @@ -635,7 +659,7 @@ class vauth { /* Set to Protocol 3 */ ldap_set_option($ldap_link, LDAP_OPT_PROTOCOL_VERSION, 3); - // bind using our auth, if we need to, for initial search for username + // bind using our auth if we need to for initial search if (!ldap_bind($ldap_link, $ldap_username, $ldap_password)) { $results['success'] = false; $results['error'] = "Could not bind to LDAP server."; @@ -647,17 +671,18 @@ class vauth { if ($info["count"] == 1) { $user_entry = ldap_first_entry($ldap_link, $sr); - $user_dn = ldap_get_dn($ldap_link, $user_entry); + $user_dn = ldap_get_dn($ldap_link, $user_entry); + $password = scrub_in($password); // bind using the user.. $retval = ldap_bind($ldap_link, $user_dn, $password); if ($retval) { ldap_close($ldap_link); - $results['success'] = true; - $results['type'] = "ldap"; + $results['success'] = true; + $results['type'] = "ldap"; $results['username'] = $username; - $results['name'] = $info[0][$ldap_name_field][0]; - $results['email'] = $info[0][$ldap_email_field][0]; + $results['name'] = $info[0][$ldap_name_field][0]; + $results['email'] = $info[0][$ldap_email_field][0]; return $results; @@ -669,7 +694,7 @@ class vauth { /* Default to bad news */ $results['success'] = false; - $results['error'] = "LDAP login attempt failed"; + $results['error'] = 'LDAP login attempt failed'; return $results; @@ -677,20 +702,20 @@ class vauth { /** * http_auth - * This auth method relies on HTTP auth from Apache + * This auth method relies on HTTP auth from the webserver */ - private static function http_auth($username) { + private static function http_auth($username, $password) { if (($_SERVER['REMOTE_USER'] == $username) || - ($_SERVER['HTTP_REMOTE_USER'] == $username)) { - $results['success'] = true; - $results['type'] = 'http'; - $results['username'] = $username; - $results['name'] = $username; - $results['email'] = ''; + ($_SERVER['HTTP_REMOTE_USER'] == $username)) { + $results['success'] = true; + $results['type'] = 'http'; + $results['username'] = $username; + $results['name'] = $username; + $results['email'] = ''; } else { $results['success'] = false; - $results['error'] = "HTTP auth: REMOTE_USER not set"; + $results['error'] = 'HTTP auth login attempt failed'; } return $results; } // http_auth |