Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sun, Jan 5, 9:30 PM

in-portal

Index: branches/5.2.x/core/kernel/utility/formatters/password_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/password_formatter.php (revision 16008)
+++ branches/5.2.x/core/kernel/utility/formatters/password_formatter.php (revision 16009)
@@ -1,337 +1,337 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kPasswordFormatter extends kFormatter
{
/**
* Instance of PHPPass
*
* @var PasswordHash
* @access protected
*/
protected $_phpPass;
/**
* Creates formatter instance
*
* @access public
*/
public function __construct()
{
parent::__construct();
$this->_phpPass = $this->Application->makeClass('PasswordHash', Array (8, false));
}
/**
* The method is supposed to alter config options or configure object in some way based on its usage of formatters
* The methods is called for every field with formatter defined when configuring item.
* Could be used for adding additional VirtualFields to an object required by some special Formatter
*
* @param string $field_name
* @param array $field_options
* @param kDBBase $object
*/
function PrepareOptions($field_name, &$field_options, &$object)
{
if ( !isset($field_options['verify_field']) ) {
return;
}
$add_fields = Array ();
$options = Array (
'master_field' => $field_name,
// 'error_field' => $field_name,
'formatter' => 'kPasswordFormatter'
);
$copy_options = Array ('hashing_method', 'hashing_method_field', 'salt', 'required', 'skip_empty');
foreach ($copy_options as $copy_option) {
if ( array_key_exists($copy_option, $field_options) ) {
$options[$copy_option] = $field_options[$copy_option];
}
}
$add_fields[$field_options['verify_field']] = $options;
$add_fields[$field_name . '_plain'] = Array ('type' => 'string', 'error_field' => $field_name);
$add_fields[$field_options['verify_field'] . '_plain'] = Array ('type' => 'string', 'error_field' => $field_options['verify_field']);
$virtual_fields = $object->getVirtualFields();
$add_fields = kUtil::array_merge_recursive($add_fields, $virtual_fields);
$object->setVirtualFields($add_fields);
}
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format = null)
{
return $value;
}
/**
* Performs password & verify password field validation
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
list ($password_field, $verify_field) = $this->_getPasswordFields($value, $field_name, $object);
$options = $object->GetFieldOptions($field_name);
$salt = $object->GetFieldOption($password_field, 'salt', false, '');
$hashing_method = isset($options['hashing_method']) ? $options['hashing_method'] : $object->GetDBField($options['hashing_method_field']);
if ( $object->GetFieldOption($password_field, 'verify_field_set') && $object->GetFieldOption($verify_field, 'master_field_set') ) {
$new_password = $object->GetDBField($password_field . '_plain');
$verify_password = $object->GetDBField($verify_field . '_plain');
if ( $new_password == '' && $verify_password == '' ) {
$stored_hash = $object->GetDBField($password_field);
if ( !$this->checkPassword('', $stored_hash, $hashing_method) ) {
// return empty string causing password from database to stay
return $value;
}
else {
return $this->hashPassword($value, $salt, $hashing_method);
}
}
// determine admin or front
$phrase_error_prefix = $this->Application->isAdmin ? 'la' : 'lu';
if ( $new_password != $verify_password ) {
// passwords don't match (no matter what is their length)
$object->SetError($verify_field, 'passwords_do_not_match', $phrase_error_prefix . '_passwords_do_not_match');
}
$min_length = $this->Application->ConfigValue('Min_Password'); // for error message too
$min_length = $object->GetFieldOption($password_field, 'min_length', false, $min_length);
if ( mb_strlen($new_password) < $min_length ) {
- $error_msg = '+' . sprintf($this->Application->Phrase($phrase_error_prefix . '_passwords_too_short'), $min_length); // + -> not phrase
+ $error_msg = '+' . sprintf($this->Application->Phrase($phrase_error_prefix . '_passwords_too_short', false), $min_length); // + -> not phrase
$object->SetError($password_field, 'passwords_min_length', $error_msg);
}
}
if ( $value == '' ) {
// new value is empty - return hash from database
return $object->GetDBField($field_name);
}
return $this->hashPassword($value, $salt, $hashing_method);
}
/**
* Finds out names of password and verify password fields and updates "_plain" virtual field
*
* @param string $value
* @param string $field_name
* @param kDBItem $object
* @return Array
* @access protected
*/
protected function _getPasswordFields($value, $field_name, &$object)
{
$options = $object->GetFieldOptions($field_name);
$flip_count = 0;
$password_field = $verify_field = '';
$fields = Array ('master_field', 'verify_field');
// 1. collect values from both Password and VerifyPassword fields
while ($flip_count < 2) {
if ( getArrayValue($options, $fields[0]) ) {
$tmp_field = $options[$fields[0]];
$object->SetDBField($field_name . '_plain', $value);
if ( !$object->GetFieldOption($tmp_field, $fields[1] . '_set') ) {
$object->SetFieldOption($tmp_field, $fields[1] . '_set', true);
}
$password_field = $options[$fields[0]];
$verify_field = $field_name;
}
$fields = array_reverse($fields);
$flip_count++;
}
return Array ($password_field, $verify_field);
}
/**
* Creates hash from given password and salt
*
* @param string $password
* @param string $salt
* @param int $hashing_method
* @return string
* @throws InvalidArgumentException
* @access public
*/
public function hashPassword($password, $salt = null, $hashing_method = PasswordHashingMethod::PHPPASS)
{
switch ( $hashing_method ) {
case PasswordHashingMethod::NONE:
return $password;
break;
case PasswordHashingMethod::MD5:
return $this->_md5hash($password, $salt, false);
break;
case PasswordHashingMethod::MD5_AND_PHPPASS:
return $this->_phpPass->hashPassword($this->_md5hash($password, $salt, true));
break;
case PasswordHashingMethod::PHPPASS:
return $this->_phpPass->hashPassword($password);
break;
default:
throw new InvalidArgumentException('Unknown password hashing method "' . $hashing_method . '"');
break;
}
}
/**
* Checks, that user password is valid
*
* @param string $password Non-hashed password provided by user
* @param string $stored_hash Hash, calculated before from correct user password (must have salt inside)
* @param int $hashing_method Hash generation method
* @return bool
* @access public
* @throws InvalidArgumentException
*/
public function checkPassword($password, $stored_hash = null, $hashing_method = PasswordHashingMethod::PHPPASS)
{
$salt = '';
if ( $hashing_method != PasswordHashingMethod::PHPPASS && strpos($stored_hash, ':') !== false ) {
list ($salt, $stored_hash) = explode(':', $stored_hash, 2);
}
switch ( $hashing_method ) {
case PasswordHashingMethod::NONE:
return $password == $stored_hash;
break;
case PasswordHashingMethod::MD5:
return $this->_md5hash($password, $salt, false) == $stored_hash;
break;
case PasswordHashingMethod::MD5_AND_PHPPASS:
$password_hashed = preg_match('/^[a-f0-9]{32}$/', $password);
return $this->_phpPass->checkPassword($this->_md5hash($password, $salt, $password_hashed), $stored_hash);
break;
case PasswordHashingMethod::PHPPASS:
return $this->_phpPass->checkPassword($password, $stored_hash);
break;
default:
throw new InvalidArgumentException('Unknown password hashing method "' . $hashing_method . '"');
break;
}
}
/**
* Checks a password stored as system setting using phppass with fallback to salted md5
*
* @param string $setting_name
* @param string $password
* @param int $hashing_method
* @return bool
* @access public
*/
public function checkPasswordFromSetting($setting_name, $password, $hashing_method = PasswordHashingMethod::PHPPASS)
{
$stored_hash = $this->Application->ConfigValue($setting_name);
$stored_hash = $this->prepareHash($stored_hash, 'b38', $hashing_method);
if ( $this->checkPassword($password, $stored_hash, $hashing_method) ) {
return true;
}
if ( $hashing_method != PasswordHashingMethod::MD5 ) {
if ( $this->checkPasswordFromSetting($setting_name, $password, PasswordHashingMethod::MD5) ) {
// rehash password on the go using more secure algorithm
$this->Application->SetConfigValue($setting_name, $this->hashPassword($password));
return true;
}
}
return false;
}
/**
* Ensures, that salt is always present in the hash
*
* @param string $stored_hash
* @param string $salt
* @param int $hashing_method
* @return string
* @access public
*/
public function prepareHash($stored_hash, $salt = '', $hashing_method = PasswordHashingMethod::PHPPASS)
{
if ( $hashing_method == PasswordHashingMethod::PHPPASS ) {
return $stored_hash;
}
// embed salt into hash generated not by phppass
return $salt . ':' . $stored_hash;
}
/**
* Hashes password using MD5 algorithm
*
* @param string $password
* @param string $salt
* @param bool $password_hashed
* @return string
* @access protected
*/
protected function _md5hash($password, $salt = null, $password_hashed = false)
{
if ( !$password_hashed ) {
$password = md5($password);
}
if ( isset($salt) && $salt ) {
return md5($password . $salt);
}
// if empty salt, assume, that it's not passed at all
return $password;
}
-}
\ No newline at end of file
+}

Event Timeline