Sources for file plugins/class/session.php in version 4.0 Beta 1
Click on a comment to hide it. Click here to show all comments.
/**
* Project: Xnyo 4: Bubbles
* File: plugins/class/session.php
*
* Version: 4.0-dev
* SVN Id: $Id: session.php 5 2007-05-18 03:49:07Z bok $
* SVN URL: $HeadURL:
http://svn.syd.wholesalebroadband.com.au/xnyo/trunk/plugins/class/session.php $
* Authors: Robert Amos <bok[at]odynia.org>
*
* Copyright (c) 2001-2007 Robert Amos <bok[at]odynia.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
/**
* This file implements the session and authentication modules of Xnyo
**/
class XnyoSession implements XnyoClassPlugin
{
// Plugin Information
public $_plugin_info = array
(
'name' => 'Xnyo Session/Authentication Plugin',
'description' => 'Controls and manages sessions',
'action' => XNYO_PLUGIN_ACTION_STORAGE,
'varname' => 'session'
);
// information storage
private $ip;
private $browser;
private $lastactivity;
private $expiry;
private $subnet;
private $xnyo;
/**
* Constructor
*
* Check current session to ensure it hasnt become invalid
**/
public function __construct ()
{
$this->xnyo = $GLOBALS['xnyo_parent'];
try
{
// have they logged in previously?
if (isset($_SESSION['_xnyo_auth']) && is_object($_SESSION['_xnyo_auth']))
{
// store a reference in the Xnyo Object
$this->xnyo->user = &$_SESSION['_xnyo_auth'];
$this->xnyo->smartyvar->user = (array)$this->xnyo->user;
// store a reference to the session timers etc
if (!is_array($_SESSION['_xnyo_session']))
throw new XnyoError('Session Timers not found in $_SESSION, forcing session timeout.');
$this->browser =& $_SESSION['_xnyo_session']['browser'];
$this->expiry =& $_SESSION['_xnyo_session']['expiry'];
$this->subnet =& $_SESSION['_xnyo_session']['subnet'];
// check the session expiration
if ($this->expiry !== 0)
{
if (XNYO_DEBUG) $this->xnyo->d('Checking session expiration.');
// check to see if now is greater than the timestamp we were supposed to expire
if (time() > $this->expiry)
throw new XnyoClient($this->xnyo->session->errors['session_timeout'], (time() -
$this->expiry), $this->xnyo->user->email);
// update timer
if (XNYO_DEBUG) $this->xnyo->d('Session not expired. Updating session time.');
$this->expiry = time() + $this->xnyo->session->lifetime;
}
// check the subnet is still in the same /24
if (XNYO_DEBUG) $this->xnyo->d('Checking session subnet.');
if ($this->subnet != $this->subnet())
throw new XnyoClient($this->xnyo->session->errors['subnet_change'], $this->subnet,
$this->subnet(), $this->xnyo->user->email);
// check the browser is still the same
if ($this->browser != $_SERVER['HTTP_USER_AGENT'])
throw new XnyoClient($this->xnyo->session->errors['browser_change'], $this->browser,
$_SERVER['HTTP_USER_AGENT'], $this->xnyo->user->email);
}
} catch (Exception $e)
{
$this->xnyo->storage->error->raise($e);
$this->logout();
}
}
/**
* Login
*
* Opens a session for the current user.
**/
public function login ($user, $pass, $domain=null)
{
try
{
// Authenticating user
if (XNYO_DEBUG) $this->xnyo->d('Authenticating new user.');
// filter both, just in case
$user = XnyoInput::username($user);
$pass = XnyoInput::password($pass);
// blank username?
if (empty($user))
throw new XnyoClient($this->xnyo->session->errors['blank_username']);
// blank password?
if (empty($pass))
throw new XnyoClient($this->xnyo->session->errors['blank_password']);
// no authentication handler?
if (!isset($this->xnyo->session->handler))
throw new XnyoError('No authentication plugin configured.');
// load plugin
$this->handler = $this->xnyo->load($this->xnyo->session->handler, XNYO_PLUGIN_AUTH);
// call the auth
$details = $this->handler->login($user, $pass, $domain);
// store details
$_SESSION['_xnyo_auth'] = $details;
$this->xnyo->user =& $_SESSION['_xnyo_auth'];
$this->xnyo->smartyvar->user = (array)$this->xnyo->user;
// store session information
$_SESSION['_xnyo_session'] = array
(
'expiry' => time() + $this->xnyo->session->lifetime,
'subnet' => $this->subnet(),
'browser' => $_SERVER['HTTP_USER_AGENT']
);
$this->expiry =& $_SESSION['_xnyo_session']['expiry'];
$this->subnet =& $_SESSION['_xnyo_session']['subnet'];
$this->browser =& $_SESSION['_xnyo_session']['browser'];
// all done
return true;
} catch (XnyoClient $e)
{
$this->xnyo->storage->error->raise($e);
return false;
}
}
/**
* Logout
*
* Closes the current session.
**/
public function logout ()
{
if (XNYO_DEBUG) $this->xnyo->d('Closing session for user <b>%s</b>.', $this->xnyo->user->email);
// destroy the user data
$user = clone $_SESSION['_xnyo_auth'];
unset($_SESSION['_xnyo_auth'], $_SESSION['_xnyo_session']);
// call the logout handler
if (!is_null($this->xnyo->session->logout_handler))
{
$c = $this->xnyo->session->logout_handler;
$x = new $c($user);
}
}
/**
* Check current session against the supplied access list
**/
public function check ($acl=null)
{
// no supplied groups? default allow
if (is_null($acl) || empty($acl))
return true;
// a string? make into an array - has to be a comma or semi-colon delimited list
if (!is_array($acl))
$acl = explode(',', str_replace(';', ',', $acl));
// spaces
array_walk($acl, 'trim');
// the special "none" ACL overrides all others, indicating they are not allowed to be logged in,
at all
if (in_array('none', $acl) && !isset($this->xnyo->user->email))
return true;
// likewise the "required" special ACL indicates that they only need to be logged in.
if (in_array('required', $acl) && isset($this->xnyo->user->email))
return true;
// loop over the group list
foreach ($acl as $a)
{
// we can specify usernames in an ACL, is this theirs?
if (strtolower($a) == strtolower($this->xnyo->user->email))
return true;
// is this a language?
if (substr($a, 0, 5) == 'lang:' && is_array($this->xnyo->session->languages))
{
$l = substr($a, 5);
// in the supported language list?
if (isset($this->xnyo->session->languages[$l]) || in_array($l, $this->xnyo->session->languages))
return true;
}
// we have a groups list
if (is_array($this->xnyo->user->groups))
{
// make the group specified into a regexp - we do allow wildcards though
$a = '/'.preg_quote($a, '/').'/';
$a = str_replace('\*', '.*?', $a);
// does this match any of the groups listed?
if (count(preg_grep($a, $this->xnyo->user->groups)) > 0)
return true;
}
}
// nothing matches
return false;
}
/**
* Subnet
*
* Make a /24 subnet
**/
public function subnet()
{
// make sure its a legal ip :)
$ip = XnyoInput::ip($_SERVER['REMOTE_ADDR']);
// replace the last segment
return substr($ip, 0, strrpos($ip, '.').'0/24');
}
/**
* Set an ACL
*
* Specifies an ACL for the page being accessed
**/
public function setacl ($acl, $redirect=null)
{
if (XNYO_DEBUG) $this->xnyo->d('Settings ACL for current page load to <b>%s</b>', (is_array($acl)
? join(',', $acl) : $acl));
// check it
try
{
if (!$this->check($acl))
throw new XnyoClient('<b>%s</b> attempted to access page requiring ACL <b>%s</b>',
(isset($this->xnyo->user->email) ? 'User '.$this->xnyo->user->email : 'Unauthenticated user'),
(is_array($acl) ? join(',', $acl) : $acl));
} catch (XnyoClient $e)
{
$this->xnyo->storage->error->raise($e);
if (!is_null($redirect))
header('Location: '.$redirect);
}
}
}
