Newer
Older
if (!isset($_POST['userid']) || !isset($_POST['token']))
return false;
elseif (!($_config = new Config('pwreset')))
return false;
elseif (($staff = StaffSession::lookup($_POST['userid'])) &&
$errors['msg'] = __('Invalid user-id given');
elseif (!($id = $_config->get($_POST['token']))
|| $id != $staff->getId())
$errors['msg'] = __('Invalid reset token');
elseif (!($ts = $_config->lastModified($_POST['token']))
&& ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
$errors['msg'] = __('Invalid reset token');
elseif (!$staff->forcePasswdRest())
$errors['msg'] = __('Unable to reset password');
else
return $staff;
}
function login($staff, $bk) {
$_SESSION['_staff']['reset-token'] = $_POST['token'];
Signal::send('auth.pwreset.login', $staff);
return parent::login($staff, $bk);
}
}
StaffAuthenticationBackend::register('PasswordResetTokenBackend');
/*
* AuthToken Authentication Backend
*
* Provides auto-login facility for end users with valid link
*
* Ticket used to loggin is tracked durring the session this is
* important in the future when auto-logins will be
* limited to single ticket view.
*/
class AuthTokenAuthentication extends UserAuthenticationBackend {
static $name = "Auth Token Authentication";
static $id = "authtoken";
function signOn() {
if ($_GET['auth']) {
if (($u = TicketUser::lookupByToken($_GET['auth'])))
$user = new ClientSession($u);
}
// Support old ticket based tokens.
elseif ($_GET['t'] && $_GET['e'] && $_GET['a']) {
if (($ticket = Ticket::lookupByNumber($_GET['t'], $_GET['e']))
// Using old ticket auth code algo - hardcoded here because it
// will be removed in ticket class in the upcoming rewrite
&& !strcasecmp($_GET['a'], md5($ticket->getId() . $_GET['e'] . SECRET_SALT))
&& ($owner = $ticket->getOwner()))
$user = new ClientSession($owner);
}
return $user;
}
function supportsInteractiveAuthentication() {
return false;
}
protected function getAuthKey($user) {
return null;
//Generate authkey based the type of ticket user
// It's required to validate users going forward.
$authkey = sprintf('%s%dt%dh%s', //XXX: Placeholder
($user->isOwner() ? 'o':'c'),
$user->getTicketId(),
md5($user->getId().$this->id));
protected function validate($authkey) {
$regex = '/^(?P<type>\w{1})(?P<id>\d+)t(?P<tid>\d+)h(?P<hash>.*)$/i';
$matches = array();
if (!preg_match($regex, $authkey, $matches))
return false;
$user = null;
switch ($matches['type']) {
case 'c': //Collaborator
$criteria = array(
'user_id' => $matches['id'],
'thread__ticket__ticket_id' => $matches['tid']
);
if (($c = Collaborator::lookup($criteria))
&& ($c->getTicketId() == $matches['tid']))
$user = new ClientSession($c);
break;
case 'o': //Ticket owner
if (($ticket = Ticket::lookup($matches['tid']))
&& ($o = $ticket->getOwner())
&& ($o->getId() == $matches['id']))
$user = new ClientSession($o);
break;
}
//Make sure the authkey matches.
if (!$user || strcmp($this->getAuthKey($user), $authkey))
return null;
UserAuthenticationBackend::register('AuthTokenAuthentication');
//Simple ticket lookup backend used to recover ticket access link.
// We're using authentication backend so we can guard aganist brute force
// attempts (which doesn't buy much since the link is emailed)
class AccessLinkAuthentication extends UserAuthenticationBackend {
static $name = "Ticket Access Link Authentication";
static $id = "authlink";
function authenticate($email, $number) {
if (!($ticket = Ticket::lookupByNumber($number))
|| !($user=User::lookup(array('emails__address' => $email))))
if (!($user = $this->_getTicketUser($ticket, $user)))
return false;
$_SESSION['_auth']['user-ticket'] = $number;
return new ClientSession($user);
}
function _getTicketUser($ticket, $user) {
if ($ticket->getUserId() == $user->getId())
$user = $ticket->getOwner();
// Collaborator?
elseif (!($user = Collaborator::lookup(array(
'user_id' => $user->getId(),
'thread__ticket__ticket_id' => $ticket->getId())
)))
return false; //Bro, we don't know you!
// We are not actually logging in the user....
global $cfg;
if (!$cfg->isClientEmailVerificationRequired()) {
return parent::login($user, $bk);
}
protected function validate($userid) {
$number = $_SESSION['_auth']['user-ticket'];
if (!($ticket = Ticket::lookupByNumber($number)))
return false;
if (!($user = User::lookup($userid)))
return false;
if (!($user = $this->_getTicketUser($ticket, $user)))
return false;
$user = new ClientSession($user);
$user->flagGuest();
return $user;
}
function supportsInteractiveAuthentication() {
return false;
}
}
UserAuthenticationBackend::register('AccessLinkAuthentication');
class osTicketClientAuthentication extends UserAuthenticationBackend {
static $name = "Local Client Authentication";
static $id = "client";
function authenticate($username, $password) {
if (!($acct = ClientAccount::lookupByUsername($username)))
if (($client = new ClientSession(new EndUser($acct->getUser())))
&& !$client->getId())
return false;
elseif (!$acct->checkPassword($password))
return false;
else
return $client;
}
}
UserAuthenticationBackend::register('osTicketClientAuthentication');
class ClientPasswordResetTokenBackend extends UserAuthenticationBackend {
static $id = "pwreset.client";
function supportsInteractiveAuthentication() {
return false;
}
function signOn($errors=array()) {
global $ost;
if (!isset($_POST['userid']) || !isset($_POST['token']))
return false;
elseif (!($_config = new Config('pwreset')))
return false;
elseif (!($acct = ClientAccount::lookupByUsername($_POST['userid']))
|| !$acct->getId()
|| !($client = new ClientSession(new EndUser($acct->getUser()))))
$errors['msg'] = __('Invalid user-id given');
elseif (!($id = $_config->get($_POST['token']))
|| $id != 'c'.$client->getId())
$errors['msg'] = __('Invalid reset token');
elseif (!($ts = $_config->lastModified($_POST['token']))
&& ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
$errors['msg'] = __('Invalid reset token');
elseif (!$acct->forcePasswdReset())
$errors['msg'] = __('Unable to reset password');
function login($client, $bk) {
$_SESSION['_client']['reset-token'] = $_POST['token'];
Signal::send('auth.pwreset.login', $client);
return parent::login($client, $bk);
}
UserAuthenticationBackend::register('ClientPasswordResetTokenBackend');
class ClientAcctConfirmationTokenBackend extends UserAuthenticationBackend {
static $id = "confirm.client";
function supportsInteractiveAuthentication() {
return false;
}
function signOn($errors=array()) {
global $ost;
if (!isset($_GET['token']))
return false;
elseif (!($_config = new Config('pwreset')))
return false;
elseif (!($id = $_config->get($_GET['token'])))
return false;
elseif (!($acct = ClientAccount::lookup(array('user_id'=>substr($id,1))))
|| $id != 'c'.$acct->getUserId()
|| !($client = new ClientSession(new EndUser($acct->getUser()))))
return false;
else
return $client;
}
}
UserAuthenticationBackend::register('ClientAcctConfirmationTokenBackend');
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
// ----- Password Policy --------------------------------------
class BadPassword extends Exception {}
class PasswordUpdateFailed extends Exception {}
abstract class PasswordPolicy {
static protected $registry = array();
/**
* Check a password and throw BadPassword with a meaningful message if
* the password cannot be accepted.
*/
abstract function processPassword($new, $current);
static function checkPassword($new, $current) {
foreach (static::allActivePolicies() as $P) {
$P->processPassword($new, $current);
}
}
static function allActivePolicies() {
$policies = array();
foreach (static::$registry as $P) {
if (is_string($P) && class_exists($P))
$P = new $P();
if ($P instanceof PasswordPolicy)
$policies[] = $P;
}
return $policies;
}
static function register($policy) {
static::$registry[] = $policy;
}
}
class osTicketPasswordPolicy
extends PasswordPolicy {
function processPassword($passwd, $current) {
if (strlen($passwd) < 6) {
throw new BadPassword(
__('Password must be at least 6 characters'));
}
// XXX: Changing case is technicall changing the password
if (0 === strcasecmp($passwd, $current)) {
throw new BadPassword(
__('New password MUST be different from the current password!'));
}
}
}
PasswordPolicy::register('osTicketPasswordPolicy');