Skip to content
Snippets Groups Projects
Commit 5ea8bff0 authored by Peter Rotich's avatar Peter Rotich
Browse files

Merge pull request #1868 from greezybacon/feature/pw-extensions


auth: Add concept of bk passwd update and policy

Reviewed-By: default avatarPeter Rotich <peter@osticket.com>
parents 546aedc6 57845b7f
No related branches found
No related tags found
No related merge requests found
......@@ -347,6 +347,38 @@ abstract class AuthenticationBackend {
return false;
}
/**
* Request the backend to update the password for a user. This method is
* the main entry for password updates so that password policies can be
* applied to the new password before passing the new password to the
* backend for updating.
*
* Throws:
* BadPassword — if password does not meet policy requirement
* PasswordUpdateFailed — if backend failed to update the password
*/
function setPassword($user, $password, $current=false) {
PasswordPolicy::checkPassword($password, $current);
$rv = $this->syncPassword($user, $password);
if ($rv) {
$info = array('password' => $password, 'current' => $current);
Signal::send('auth.pwchange', $user, $info);
}
return $rv;
}
/**
* Request the backend to update the user's password with the password
* given. This method should only be used if the backend advertises
* supported password updates with the supportsPasswordChange() method.
*
* Returns:
* true if the password was successfully updated and false otherwise.
*/
protected function syncPassword($user, $password) {
return false;
}
function supportsPasswordReset() {
return false;
}
......@@ -946,6 +978,14 @@ class osTicketAuthentication extends StaffAuthenticationBackend {
}
}
function supportsPasswordChange() {
return true;
}
function syncPassword($staff, $password) {
$staff->passwd = Passwd::hash($password);
}
}
StaffAuthenticationBackend::register('osTicketAuthentication');
......@@ -1228,4 +1268,56 @@ class ClientAcctConfirmationTokenBackend extends UserAuthenticationBackend {
}
}
UserAuthenticationBackend::register('ClientAcctConfirmationTokenBackend');
// ----- 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');
?>
......@@ -96,7 +96,13 @@ implements AuthenticatedUser, EmailContact {
}
function getAuthBackend() {
list($authkey, ) = explode(':', $this->getAuthKey());
list($bk, ) = explode(':', $this->getAuthKey());
// If administering a user other than yourself, fallback to the
// agent's declared backend, if any
if (!$bk && $this->backend)
$bk = $this->backend;
return StaffAuthenticationBackend::getBackend($authkey);
}
......@@ -157,6 +163,34 @@ implements AuthenticatedUser, EmailContact {
&& $this->passwd_change>($cfg->getPasswdResetPeriod()*30*24*60*60));
}
function setPassword($new, $current=false) {
// Allow the backend to update the password. This is the preferred
// method as it allows for integration with password policies and
// also allows for remotely updating the password where possible and
// supported.
if (!($bk = $this->getAuthBackend())
|| !$bk instanceof AuthBackend
) {
// Fallback to osTicket authentication token udpates
$bk = new osTicketAuthentication();
}
// And now for the magic
if (!$bk->supportsPasswordChange()) {
throw new PasswordUpdateFailed(
__('Authentication backend does not support password updates'));
}
if (!$bk->setPassword($this, $new, $current)) {
// Backend should throw PasswordUpdateFailed directly
return false;
}
// Successfully updated authentication tokens
$this->change_passwd = 0;
$this->cancelResetTokens();
$this->passwdreset = SqlFunction::NOW();
}
function canAccess($something) {
if ($something instanceof RestrictedAccess)
return $something->checkStaffPerm($this);
......@@ -493,8 +527,6 @@ implements AuthenticatedUser, EmailContact {
if(!$vars['passwd1'])
$errors['passwd1']=__('New password is required');
elseif($vars['passwd1'] && strlen($vars['passwd1'])<6)
$errors['passwd1']=__('Password must be at least 6 characters');
elseif($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2']))
$errors['passwd2']=__('Passwords do not match');
......@@ -512,13 +544,24 @@ implements AuthenticatedUser, EmailContact {
$errors['cpasswd']=__('Current password is required');
elseif(!$this->cmp_passwd($vars['cpasswd']))
$errors['cpasswd']=__('Invalid current password!');
elseif(!strcasecmp($vars['passwd1'], $vars['cpasswd']))
$errors['passwd1']=__('New password MUST be different from the current password!');
}
if($vars['default_signature_type']=='mine' && !$vars['signature'])
$errors['default_signature_type'] = __("You don't have a signature");
// Update the user's password if requested
if ($vars['passwd1']) {
try {
$this->setPassword($vars['passwd1'], $vars['cpasswd']);
}
catch (BadPassword $ex) {
$errors['passwd1'] = $ex->getMessage();
}
catch (PasswordUpdateFailed $ex) {
// TODO: Add a warning banner or crash the update
}
}
if($errors) return false;
$_SESSION['staff:lang'] = null;
......@@ -540,15 +583,6 @@ implements AuthenticatedUser, EmailContact {
$this->default_paper_size = $vars['default_paper_size'];
$this->lang = $vars['lang'];
if ($vars['passwd1']) {
$this->change_passwd = 0;
$this->passwdreset = SqlFunction::NOW();
$this->passwd = Passwd::hash($vars['passwd1']);
$info = array('password' => $vars['passwd1']);
Signal::send('auth.pwchange', $this, $info);
$this->cancelResetTokens();
}
return $this->save();
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment