diff options
author | Christian Schneider | 2007-10-11 00:39:30 +0000 |
---|---|---|
committer | Christian Schneider | 2007-10-11 00:39:30 +0000 |
commit | 35fe33f7364329dacf415c950bff01b6de9ef88e (patch) | |
tree | b0e6b018b50038ca20266723c53750268f508df5 /it_user.class | |
parent | 1f95711ff3e9697cd85a54545ab42e5fd3611317 (diff) | |
download | itools-35fe33f7364329dacf415c950bff01b6de9ef88e.tar.gz itools-35fe33f7364329dacf415c950bff01b6de9ef88e.tar.bz2 itools-35fe33f7364329dacf415c950bff01b6de9ef88e.zip |
Populated release branch
Diffstat (limited to 'it_user.class')
-rw-r--r-- | it_user.class | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/it_user.class b/it_user.class new file mode 100644 index 0000000..b0bb05b --- /dev/null +++ b/it_user.class @@ -0,0 +1,505 @@ +<?php +/* +** $Id$ +** +** Copyright (C) 1995-2007 by the ITools Authors. +** This file is part of ITools - the Internet Tools Library +** +** ITools is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 3 of the License, or +** (at your option) any later version. +** +** ITools 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. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see <http://www.gnu.org/licenses/>. +** +** it_user.class - User management and authentication +*/ + +/* PUBLIC and guaranteed to stay in same order (but not value) forever */ +define('IT_USER_STATUS_FAILED', 1); /* Wrong password given */ +define('IT_USER_STATUS_UNKNOWN', 2); /* Not logged in, no UID */ +define('IT_USER_STATUS_ANONYMOUS', 3); /* Not logged in, UID known */ +define('IT_USER_STATUS_KNOWN', 4); /* Not logged in, UID,username known */ +define('IT_USER_STATUS_SESSION', 5); /* Has a valid session */ + +/* PRIVATE */ +define('_IT_USER_UID_COOKIE', 'UID'); +define('_IT_USER_UID_COOKIE_LIFETIME', 0x7FFFFFFF); /* Forever :-) */ +define('_IT_USER_STATUS_INVALID', 0); /* INTERNAL: Not yet evaluated */ + +class it_user extends it_dbi +{ + /* PRIVATE */ + var $status; # Current status (IT_USER_STATUS_...) + var $session; # Session object + var $sessioninitialized = false; + + var $login_identifier_required = false; + var $login_identifier; + var $domain; + var $lifetime; + var $secret; + var $urlauthenticationcode = 'uac'; # Name of UAC url parameter + + var $uid; + var $username; + + /* + * Used by login(), contains unvalidated user data to give overloading + * functions a way of accessing it. + */ + var $workrecord; + + +/** + * Constructor + * @param $p array(key => value) of configuration data + */ +function it_user($p) +{ + $this->p = $p + array( + 'uid_field' => 'ID', + 'table' => 'T_Users', + 'username_field' => 'Username', + 'password_field' => 'Password', + 'uidcookiename' => _IT_USER_UID_COOKIE, + 'sessioncookiename' => null + ); + + # Default to uid being primary key, may change later + $this->it_dbi(array('table' => $this->p['table'], 'keyfield' => $this->p['uid_field'])); + + $this->session = new it_session; + $this->status = _IT_USER_STATUS_INVALID; +} + + +/** + * Post processing, called by ITools after reading a database record + * @access private + */ +function _read_post_process() +{ + parent::_read_post_process(); + + # If read succeeded, get UID. This is necessary because it's only set if a cookie is present (i.e. in web-context) + if (isset($this->{$this->p['uid_field']})) + $this->uid = $this->{$this->p['uid_field']}; + + # Get username from database field (shortcut) + $this->username = $this->{$this->p['username_field']}; +} + + +function set_session_cookie_name($sessioncookiename) +{ + $this->p['sessioncookiename'] = $sessioncookiename; +} + + +function set_uid_cookie_name($uidcookiename) +{ + $this->p['uidcookiename'] = $uidcookiename; +} + + +function set_domain($domain) +{ + $this->domain = $domain; +} + + +function set_session_lifetime($lifetime) +{ + $this->lifetime = $lifetime; +} + + +function set_login_identifier($login_identifier) +{ + $this->login_identifier_required = true; + $this->login_identifier = $login_identifier; +} + + +function _init_session() +{ + if (!$this->sessioninitialized) + { + # Using non-standard values for session? + if ($this->p['sessioncookiename']) + $this->session->set_cookiename($this->p['sessioncookiename']); + + if (isset($this->domain)) + $this->session->set_domain($this->domain); + + if (isset($this->lifetime)) + $this->session->set_lifetime($this->lifetime); + + if (isset($this->secret)) + $this->session->set_secret($this->secret); + + $this->session->init(); + $this->sessioninitialized = true; + } +} + + +function get_status() +{ + if ($this->status == _IT_USER_STATUS_INVALID) + { + $this->_init_session(); + + if ($this->session->is_valid()) + { + $this->status = IT_USER_STATUS_SESSION; + $this->_set_uid($this->session->get_uid()); + $this->read($this->uid); + + # username == uid means we don't have a username yet + if ($this->username == $this->uid) + $this->username = ""; + } + else if (isset($_COOKIE[$this->p['uidcookiename']]) && ($this->uid = substr($_COOKIE[$this->p['uidcookiename']], 0, 32))) + { + $this->read($this->uid); + + if ($this->username == $this->uid) + $this->username = ""; + + $this->status = $this->username ? IT_USER_STATUS_KNOWN : IT_USER_STATUS_ANONYMOUS; + } + else + { + $this->status = IT_USER_STATUS_UNKNOWN; + $this->username = ''; + + if ($this->p['uid_field']) + $this->_set_uid($this->create_uid()); + } + } + + return $this->status; +} + + +function get_username() +{ + return $this->username; +} + + +function get_uid() +{ + return $this->uid; +} + + +function _set_uid($uid) +{ + $this->uid = $uid; + + if (!isset($_COOKIE[$this->p['uidcookiename']]) || ($_COOKIE[$this->p['uidcookiename']] != $uid)) + { + @setcookie($this->p['uidcookiename'], $uid, _IT_USER_UID_COOKIE_LIFETIME, "/", $this->domain); + $_COOKIE[$this->p['uidcookiename']] = $uid; + } +} + + +/* Return session status of this user: Is she logged in? */ +function is_logged_in() +{ + return $this->status == IT_USER_STATUS_SESSION; +} + + +/** + * Try to log in user. Use get_status() to check result. + * NOTE: Must not be called AFTER get_status() has been used. + * @param $username User ID to login + * @param $password Password to authenticate login + * @param $ignorepassword True if you want to login anyway (e.g. 'su') + * @return non-false if successful, false on error + */ +function login($username, $password, $ignorepassword = false, $withsession = true) +{ + $result = false; + + $this->_init_session(); + $this->workrecord = new it_dbi(array('table' => $this->p['table'], 'keyfield' => $this->p['username_field'])); + + if ($this->workrecord->read($username)) + { + if ($ignorepassword || $this->check_password($password, $this->workrecord->{$this->p['password_field']})) + { + $this->session->set_uid($this->workrecord->{$this->p['uid_field']}); + if ($withsession) + $result = $this->session->set_valid(true, $this->login_identifier_required, $this->login_identifier); + else + $result = $_COOKIE[$this->p['uidcookiename']] = $this->session->get_uid(); + } + } + + if ($result && ($this->session->get_uid() == $this->workrecord->{$this->p['uid_field']})) + $this->username = $this->workrecord->{$this->p['username_field']}; + + $this->status = $result ? _IT_USER_STATUS_INVALID : IT_USER_STATUS_FAILED; + + return $result; +} + + +/* + * Logout user. + * NOTE: Must not be called AFTER get_status() has been used. + */ +function logout() +{ + $this->_init_session(); + $this->session->set_valid(false); +} + + +/* + * Throw away all user information and restart from scratch... + */ +function purge() +{ + $this->status = _IT_USER_STATUS_INVALID; + $this->_set_uid($this->create_uid()); + $this->username = ""; + $this->session->purge(); +} + + +/* + * Create user database record. + * @param $tags Fields to set (uid and username are optional) + * @see it_dbi::insert() + */ +function create($tags) +{ + # Make sure UID is always set in database records + if ($this->p['uid_field']) + { + if (!$this->uid) + $this->_set_uid($this->create_uid()); + + $tags[$this->p['uid_field']] = $this->uid; + } + + # Create dummy but unique username if none given + if (!$tags[$this->p['username_field']] && !$this->{$this->p['username_field']}) + $tags[$this->p['username_field']] = $this->uid; + + if ($result = $this->insert($tags)) + $this->_set_uid($this->{$this->p['uid_field']}); + + return $result; +} + + +/* + * Create unique identifier used for anonymously users, Override if you want + * different type of UIDs. + * Returns newly created uid + */ +function create_uid() +{ + return md5(uniqid(rand())); /* random garbage */ +} + + +/* + * Create a login identifier and set session to login identifier 'secret' value + * Returns a value to be put into the login <form> which has to be passed to + * login() to create a valid session + */ +function create_login_identifier() +{ + return $this->session->create_login_identifier(); +} + + +/* + * Create a random password with given length. + */ +function create_password($length = 8, $charset = 'abcdefghjkpqrstuvwxyz23456789ABCDEFGHJKPRSTUVWXYZ') +{ + $result = ""; + + mt_srand((double)microtime() * 1000000); + + for ($i = 0; $i < $length; $i++) + $result .= substr($charset, mt_rand(0, strlen($charset) - 1), 1); + + return $result; +} + + +/* + * Crypt the password, same function is used in check_login_status + * You can use unencrypted passwords if you extend the user class and + * override this function. + */ +function crypt_password($password) +{ + $result = $this->query("SELECT PASSWORD('" . mysql_real_escape_string($password) . "')"); + list($pw) = mysql_fetch_array($result); + + return $pw; +} + + +/* + * Crypt the password and compare it to cryptedpassword. + */ +function check_password($password, $cryptedpassword) +{ + return $this->crypt_password($password) == $cryptedpassword; +} + + +/* + * Check if cookies are enabled. + * NOTE: Only works if you used create_login_identifier() on previous page + */ +function has_cookies() +{ + return $this->session->has_cookies(); +} + + +/* + * Check if $name would be an acceptable username + */ +function is_valid_username($name) +{ + if ((strlen($name) >= 2) && (strlen($name) <= 32)) + { + if (!ereg('["\'\\&\$+]', $name)) + return true; + } + return false; +} + + +/* + * Check if $word would be an acceptable password + */ +function is_valid_password($word) +{ + if ((strlen($word) >= 2) && (strlen($word) <= 32)) + { + if (!ereg('["\'\\&\$+]', $word)) + return true; + } + return false; +} + + +/* + * Sign string with current user id or session + * @param $text Text to be signed + * @param $withsession Sign with session if true, with uid if false + * @return Signature for $text + */ +function create_signature($text, $withsession = true) +{ + if ($withsession) + { + switch ($this->get_status()) + { + case IT_USER_STATUS_SESSION: + $result = $this->session->create_signature($text); + break; + + default: + $result = md5("$this->secret,$text,$this->secret"); + break; + } + } + else + { + /* Sign with UID only */ + $result = md5("$this->secret,$this->uid,$text,$this->secret"); + } + + return $result; +} + +/* + * Check signature for string with current user id or session + * @param $text Text which was signed + * @param $signature Signature to be checked + * @param $withsession Signed with session if true, with uid if false + * @return True if signature ok, false otherwise + */ +function check_signature($text, $signature, $withsession = true) +{ + if ($withsession) + { + switch ($this->get_status()) + { + case IT_USER_STATUS_SESSION: + $result = $this->session->check_signature($text, $signature); + break; + + default: + $result = (md5("$this->secret,$text,$this->secret") == $signature); + break; + } + } + else + { + /* Sign with UID only */ + $result = ($this->create_signature($text, false) == $signature); + } + + return $result; +} + +/* + * Sign an url with parameters + * @param $url URL to sign + * @param $withsession Signed with session if true, with uid if false + * @return Signed url + */ +function sign_url($url, $withsession = false) +{ + if (strstr($url, '?')) + $url .= "&$this->urlauthenticationcode=" . $this->create_signature(str_replace('&', '&', $url), $withsession); + + return $url; +} + +/* + * Check if url GET parameters are properly signed and not modified + * @param $withsession Signed with session if true, with uid if false + * @return False if url was modified + */ +function check_url($withsession = false) +{ + $result = true; /* Default to true for url without parameters */ + + if (!empty($_SERVER['QUERY_STRING'])) + { + $url = ereg_replace("&?$this->urlauthenticationcode=[a-zA-Z0-9]*", '', $_SERVER['REQUEST_URI']); + + $result = $this->check_signature($url, $GLOBALS[$this->urlauthenticationcode], $withsession); + } + + return $result; +} + +} /* End class it_user */ + +?> |