|
|
@@ -108,6 +108,83 @@ class PasswordableBehavior extends ModelBehavior {
|
|
|
);
|
|
|
|
|
|
/**
|
|
|
+ * Adding validation rules
|
|
|
+ * also adds and merges config settings (direct + configure)
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function setup(Model $Model, $config = array()) {
|
|
|
+ $defaults = $this->_defaultConfig;
|
|
|
+ if ($configureDefaults = Configure::read('Passwordable')) {
|
|
|
+ $defaults = $configureDefaults + $defaults;
|
|
|
+ }
|
|
|
+ $this->settings[$Model->alias] = $config + $defaults;
|
|
|
+
|
|
|
+ // BC comp
|
|
|
+ if ($this->settings[$Model->alias]['allowEmpty']) {
|
|
|
+ $this->settings[$Model->alias]['require'] = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ $formField = $this->settings[$Model->alias]['formField'];
|
|
|
+ $formFieldRepeat = $this->settings[$Model->alias]['formFieldRepeat'];
|
|
|
+ $formFieldCurrent = $this->settings[$Model->alias]['formFieldCurrent'];
|
|
|
+
|
|
|
+ if ($formField === $this->settings[$Model->alias]['field']) {
|
|
|
+ throw new CakeException('Invalid setup - the form field must to be different from the model field (' . $this->settings[$Model->alias]['field'] . ').');
|
|
|
+ }
|
|
|
+
|
|
|
+ $rules = $this->_validationRules;
|
|
|
+ foreach ($rules as $field => $fieldRules) {
|
|
|
+ foreach ($fieldRules as $key => $rule) {
|
|
|
+ $rule['allowEmpty'] = !$this->settings[$Model->alias]['require'];
|
|
|
+
|
|
|
+ if ($key === 'between') {
|
|
|
+ $rule['rule'][1] = $this->settings[$Model->alias]['minLength'];
|
|
|
+ $rule['message'][1] = $this->settings[$Model->alias]['minLength'];
|
|
|
+ $rule['rule'][2] = $this->settings[$Model->alias]['maxLength'];
|
|
|
+ $rule['message'][2] = $this->settings[$Model->alias]['maxLength'];
|
|
|
+ }
|
|
|
+
|
|
|
+ $fieldRules[$key] = $rule;
|
|
|
+ }
|
|
|
+ $rules[$field] = $fieldRules;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add the validation rules if not already attached
|
|
|
+ if (!isset($Model->validate[$formField])) {
|
|
|
+ $Model->validator()->add($formField, $rules['formField']);
|
|
|
+ }
|
|
|
+ if (!isset($Model->validate[$formFieldRepeat])) {
|
|
|
+ $ruleSet = $rules['formFieldRepeat'];
|
|
|
+ $ruleSet['validateIdentical']['rule'][1] = $formField;
|
|
|
+ $Model->validator()->add($formFieldRepeat, $ruleSet);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($this->settings[$Model->alias]['current'] && !isset($Model->validate[$formFieldCurrent])) {
|
|
|
+ $Model->validator()->add($formFieldCurrent, $rules['formFieldCurrent']);
|
|
|
+
|
|
|
+ if (!$this->settings[$Model->alias]['allowSame']) {
|
|
|
+ $Model->validator()->add($formField, 'validateNotSame', array(
|
|
|
+ 'rule' => array('validateNotSame', $formField, $formFieldCurrent),
|
|
|
+ 'message' => 'valErrPwdSameAsBefore',
|
|
|
+ 'allowEmpty' => !$this->settings[$Model->alias]['require'],
|
|
|
+ 'last' => true,
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ } elseif (!isset($Model->validate[$formFieldCurrent])) {
|
|
|
+ // Try to match the password against the hash in the DB
|
|
|
+ if (!$this->settings[$Model->alias]['allowSame']) {
|
|
|
+ $Model->validator()->add($formField, 'validateNotSame', array(
|
|
|
+ 'rule' => array('validateNotSameHash', $formField),
|
|
|
+ 'message' => 'valErrPwdSameAsBefore',
|
|
|
+ 'allowEmpty' => !$this->settings[$Model->alias]['require'],
|
|
|
+ 'last' => true,
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* If not implemented in AppModel
|
|
|
*
|
|
|
* Note: requires the used Auth component to be App::uses() loaded.
|
|
|
@@ -143,14 +220,6 @@ class PasswordableBehavior extends ModelBehavior {
|
|
|
}
|
|
|
|
|
|
return $this->_validateSameHash($Model, $pwd);
|
|
|
-
|
|
|
-
|
|
|
- if (!empty($this->settings[$Model->alias]['passwordHasher'])) {
|
|
|
- $authConfig['passwordHasher'] = $this->settings[$Model->alias]['passwordHasher'];
|
|
|
- }
|
|
|
- $this->Auth->authenticate = array(
|
|
|
- $this->settings[$Model->alias]['authType'] => $authConfig
|
|
|
- );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -219,148 +288,6 @@ class PasswordableBehavior extends ModelBehavior {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * PasswordableBehavior::_validateSameHash()
|
|
|
- *
|
|
|
- * @param Model $Model
|
|
|
- * @param string $pwd
|
|
|
- * @return bool Success
|
|
|
- */
|
|
|
- protected function _validateSameHash(Model $Model, $pwd) {
|
|
|
- $field = $this->settings[$Model->alias]['field'];
|
|
|
- $type = $this->settings[$Model->alias]['hashType'];
|
|
|
- $salt = $this->settings[$Model->alias]['hashSalt'];
|
|
|
- if ($this->settings[$Model->alias]['authType'] === 'Blowfish') {
|
|
|
- $type = 'blowfish';
|
|
|
- $salt = false;
|
|
|
- }
|
|
|
-
|
|
|
- $primaryKey = $Model->data[$Model->alias][$Model->primaryKey];
|
|
|
- $dbValue = $Model->field($field, array($Model->primaryKey => $primaryKey));
|
|
|
- if (!$dbValue && $pwd) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if ($type === 'blowfish' && function_exists('password_hash') && !empty($this->settings[$Model->alias]['passwordHasher'])) {
|
|
|
- $value = $pwd;
|
|
|
- } else {
|
|
|
- if ($type === 'blowfish') {
|
|
|
- $salt = $dbValue;
|
|
|
- }
|
|
|
- $value = Security::hash($pwd, $type, $salt);
|
|
|
- }
|
|
|
-
|
|
|
- if ($type === 'blowfish' && function_exists('password_hash') && !empty($this->settings[$Model->alias]['passwordHasher'])) {
|
|
|
- $PasswordHasher = $this->_getPasswordHasher($this->settings[$Model->alias]['passwordHasher']);
|
|
|
- return $PasswordHasher->check($value, $dbValue);
|
|
|
- }
|
|
|
- return $value === $dbValue;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * PasswordableBehavior::_getPasswordHasher()
|
|
|
- *
|
|
|
- * @param mixed $hasher Name or options array.
|
|
|
- * @return PasswordHasher
|
|
|
- */
|
|
|
- protected function _getPasswordHasher($hasher) {
|
|
|
- $class = $hasher;
|
|
|
- $config = array();
|
|
|
- if (is_array($hasher)) {
|
|
|
- $class = $hasher['className'];
|
|
|
- unset($hasher['className']);
|
|
|
- $config = $hasher;
|
|
|
- }
|
|
|
-
|
|
|
- list($plugin, $class) = pluginSplit($class, true);
|
|
|
- $className = $class . 'PasswordHasher';
|
|
|
- App::uses($className, $plugin . 'Controller/Component/Auth');
|
|
|
- if (!class_exists($className)) {
|
|
|
- throw new CakeException(__d('cake_dev', 'Password hasher class "%s" was not found.', $class));
|
|
|
- }
|
|
|
- if (!is_subclass_of($className, 'AbstractPasswordHasher')) {
|
|
|
- throw new CakeException(__d('cake_dev', 'Password hasher must extend AbstractPasswordHasher class.'));
|
|
|
- }
|
|
|
- return new $className($config);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Adding validation rules
|
|
|
- * also adds and merges config settings (direct + configure)
|
|
|
- *
|
|
|
- * @return void
|
|
|
- */
|
|
|
- public function setup(Model $Model, $config = array()) {
|
|
|
- $defaults = $this->_defaultConfig;
|
|
|
- if ($configureDefaults = Configure::read('Passwordable')) {
|
|
|
- $defaults = $configureDefaults + $defaults;
|
|
|
- }
|
|
|
- $this->settings[$Model->alias] = $config + $defaults;
|
|
|
-
|
|
|
- // BC comp
|
|
|
- if ($this->settings[$Model->alias]['allowEmpty']) {
|
|
|
- $this->settings[$Model->alias]['require'] = false;
|
|
|
- }
|
|
|
-
|
|
|
- $formField = $this->settings[$Model->alias]['formField'];
|
|
|
- $formFieldRepeat = $this->settings[$Model->alias]['formFieldRepeat'];
|
|
|
- $formFieldCurrent = $this->settings[$Model->alias]['formFieldCurrent'];
|
|
|
-
|
|
|
- if ($formField === $this->settings[$Model->alias]['field']) {
|
|
|
- throw new CakeException('Invalid setup - the form field must to be different from the model field (' . $this->settings[$Model->alias]['field'] . ').');
|
|
|
- }
|
|
|
-
|
|
|
- $rules = $this->_validationRules;
|
|
|
- foreach ($rules as $field => $fieldRules) {
|
|
|
- foreach ($fieldRules as $key => $rule) {
|
|
|
- $rule['allowEmpty'] = !$this->settings[$Model->alias]['require'];
|
|
|
-
|
|
|
- if ($key === 'between') {
|
|
|
- $rule['rule'][1] = $this->settings[$Model->alias]['minLength'];
|
|
|
- $rule['message'][1] = $this->settings[$Model->alias]['minLength'];
|
|
|
- $rule['rule'][2] = $this->settings[$Model->alias]['maxLength'];
|
|
|
- $rule['message'][2] = $this->settings[$Model->alias]['maxLength'];
|
|
|
- }
|
|
|
-
|
|
|
- $fieldRules[$key] = $rule;
|
|
|
- }
|
|
|
- $rules[$field] = $fieldRules;
|
|
|
- }
|
|
|
-
|
|
|
- // Add the validation rules if not already attached
|
|
|
- if (!isset($Model->validate[$formField])) {
|
|
|
- $Model->validator()->add($formField, $rules['formField']);
|
|
|
- }
|
|
|
- if (!isset($Model->validate[$formFieldRepeat])) {
|
|
|
- $ruleSet = $rules['formFieldRepeat'];
|
|
|
- $ruleSet['validateIdentical']['rule'][1] = $formField;
|
|
|
- $Model->validator()->add($formFieldRepeat, $ruleSet);
|
|
|
- }
|
|
|
-
|
|
|
- if ($this->settings[$Model->alias]['current'] && !isset($Model->validate[$formFieldCurrent])) {
|
|
|
- $Model->validator()->add($formFieldCurrent, $rules['formFieldCurrent']);
|
|
|
-
|
|
|
- if (!$this->settings[$Model->alias]['allowSame']) {
|
|
|
- $Model->validator()->add($formField, 'validateNotSame', array(
|
|
|
- 'rule' => array('validateNotSame', $formField, $formFieldCurrent),
|
|
|
- 'message' => 'valErrPwdSameAsBefore',
|
|
|
- 'allowEmpty' => !$this->settings[$Model->alias]['require'],
|
|
|
- 'last' => true,
|
|
|
- ));
|
|
|
- }
|
|
|
- } elseif (!isset($Model->validate[$formFieldCurrent])) {
|
|
|
- // Try to match the password against the hash in the DB
|
|
|
- if (!$this->settings[$Model->alias]['allowSame']) {
|
|
|
- $Model->validator()->add($formField, 'validateNotSame', array(
|
|
|
- 'rule' => array('validateNotSameHash', $formField),
|
|
|
- 'message' => 'valErrPwdSameAsBefore',
|
|
|
- 'allowEmpty' => !$this->settings[$Model->alias]['require'],
|
|
|
- 'last' => true,
|
|
|
- ));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
* Preparing the data
|
|
|
*
|
|
|
* @return bool Success
|
|
|
@@ -456,12 +383,49 @@ class PasswordableBehavior extends ModelBehavior {
|
|
|
|
|
|
}
|
|
|
|
|
|
- // Update whitelist
|
|
|
$this->_modifyWhitelist($Model, true);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * PasswordableBehavior::_validateSameHash()
|
|
|
+ *
|
|
|
+ * @param Model $Model
|
|
|
+ * @param string $pwd
|
|
|
+ * @return bool Success
|
|
|
+ */
|
|
|
+ protected function _validateSameHash(Model $Model, $pwd) {
|
|
|
+ $field = $this->settings[$Model->alias]['field'];
|
|
|
+ $type = $this->settings[$Model->alias]['hashType'];
|
|
|
+ $salt = $this->settings[$Model->alias]['hashSalt'];
|
|
|
+ if ($this->settings[$Model->alias]['authType'] === 'Blowfish') {
|
|
|
+ $type = 'blowfish';
|
|
|
+ $salt = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ $primaryKey = $Model->data[$Model->alias][$Model->primaryKey];
|
|
|
+ $dbValue = $Model->field($field, array($Model->primaryKey => $primaryKey));
|
|
|
+ if (!$dbValue && $pwd) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($type === 'blowfish' && function_exists('password_hash') && !empty($this->settings[$Model->alias]['passwordHasher'])) {
|
|
|
+ $value = $pwd;
|
|
|
+ } else {
|
|
|
+ if ($type === 'blowfish') {
|
|
|
+ $salt = $dbValue;
|
|
|
+ }
|
|
|
+ $value = Security::hash($pwd, $type, $salt);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($type === 'blowfish' && function_exists('password_hash') && !empty($this->settings[$Model->alias]['passwordHasher'])) {
|
|
|
+ $PasswordHasher = $this->_getPasswordHasher($this->settings[$Model->alias]['passwordHasher']);
|
|
|
+ return $PasswordHasher->check($value, $dbValue);
|
|
|
+ }
|
|
|
+ return $value === $dbValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* Modify the model's whitelist.
|
|
|
*
|
|
|
* Since 2.5 behaviors can also modify the whitelist for validate, thus this behavior can now
|
|
|
@@ -491,4 +455,31 @@ class PasswordableBehavior extends ModelBehavior {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * PasswordableBehavior::_getPasswordHasher()
|
|
|
+ *
|
|
|
+ * @param mixed $hasher Name or options array.
|
|
|
+ * @return PasswordHasher
|
|
|
+ */
|
|
|
+ protected function _getPasswordHasher($hasher) {
|
|
|
+ $class = $hasher;
|
|
|
+ $config = array();
|
|
|
+ if (is_array($hasher)) {
|
|
|
+ $class = $hasher['className'];
|
|
|
+ unset($hasher['className']);
|
|
|
+ $config = $hasher;
|
|
|
+ }
|
|
|
+
|
|
|
+ list($plugin, $class) = pluginSplit($class, true);
|
|
|
+ $className = $class . 'PasswordHasher';
|
|
|
+ App::uses($className, $plugin . 'Controller/Component/Auth');
|
|
|
+ if (!class_exists($className)) {
|
|
|
+ throw new CakeException(__d('cake_dev', 'Password hasher class "%s" was not found.', $class));
|
|
|
+ }
|
|
|
+ if (!is_subclass_of($className, 'AbstractPasswordHasher')) {
|
|
|
+ throw new CakeException(__d('cake_dev', 'Password hasher must extend AbstractPasswordHasher class.'));
|
|
|
+ }
|
|
|
+ return new $className($config);
|
|
|
+ }
|
|
|
+
|
|
|
}
|