From 1b4f2a6408d09346e584b70cc2ce665e5f0d9c6a Mon Sep 17 00:00:00 2001 From: iglocska Date: Tue, 27 Jan 2015 10:41:43 +0100 Subject: [PATCH] Password complexity definable by admin - administrators can use a regex and a length setting to define password requirements - old behavior used if left untouched --- app/Model/Server.php | 32 +++++++++++++++++++++++++++++--- app/Model/User.php | 21 +++++++++++++++++---- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/app/Model/Server.php b/app/Model/Server.php index cd88414c1..83c5fd9ea 100755 --- a/app/Model/Server.php +++ b/app/Model/Server.php @@ -428,6 +428,22 @@ class Server extends AppModel { 'type' => 'string', 'editable' => false, ), + 'password_policy_length' => array( + 'level' => 2, + 'description' => 'Password length requirement. If it is not set or it is set to 0, then the default value is assumed (6).', + 'value' => '', + 'errorMessage' => '', + 'test' => 'testPasswordLength', + 'type' => 'numeric', + ), + 'password_policy_complexity' => array( + 'level' => 2, + 'description' => 'Password complexity requirement. Leave it empty for the default setting (3 out of 4, with either a digit or a special char) or enter your own regex. Keep in mind that the length is checked in another key. Example (simple 4 out of 4): /(?=.*[0-9])(?=.*[!@#$%^&*_-])(?=.*[A-Z])(?=.*[a-z]).*$/', + 'value' => '', + 'errorMessage' => '', + 'test' => 'testPasswordRegex', + 'type' => 'string', + ), ), 'SecureAuth' => array( 'branch' => 1, @@ -467,9 +483,6 @@ class Server extends AppModel { if ($jobId) { $job = ClassRegistry::init('Job'); $job->read(null, $jobId); - App::import('Component','Auth'); - $this->Auth = new AuthComponent(new ComponentCollection()); - $this->Auth->login($user); $email = "Scheduled job"; } else { $email = $user['email']; @@ -656,6 +669,7 @@ class Server extends AppModel { 'model_id' => $id, 'email' => $user['email'], 'action' => 'pull', + 'user_id' => $user['id'], 'title' => 'Pull from ' . $server['Server']['url'] . ' initiated by ' . $email, 'change' => count($successes) . ' events and ' . count($pulledProposals) . ' proposals pulled or updated. ' . count($fails) . ' events failed or didn\'t need an update.' )); @@ -969,6 +983,18 @@ class Server extends AppModel { return $this->__testForFile($value, APP . 'webroot' . DS . 'img' . DS . 'custom'); } + public function testPasswordLength($value) { + $numeric = $this->testforNumeric($value); + if ($numeric !== true) return $numeric; + if ($numeric < 0) return 'Length cannot be negative, set a positive integer or 0 (to choose the default option).'; + return true; + } + + public function testPasswordRegex($value) { + if (!empty($value) && @preg_match($value, 'test') === false) return 'Invalid regex.'; + return true; + } + // never come here directly, always go through a secondary check like testForTermsFile in order to also pass along the expected file path private function __testForFile($value, $path) { diff --git a/app/Model/User.php b/app/Model/User.php index 66743e8f2..7765dadd1 100755 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -38,8 +38,8 @@ class User extends AppModel { ), 'password' => array( 'minlength' => array( - 'rule' => array('minlength', 6), - 'message' => 'A password of a minimum length of 6 is required.', + 'rule' => array('passwordLength'), + 'message' => 'Password length requirement not met.', //'allowEmpty' => false, 'required' => true, //'last' => false, // Stop validation after this rule @@ -47,7 +47,7 @@ class User extends AppModel { ), 'complexity' => array( 'rule' => array('complexPassword'), - 'message' => 'The password must contain at least one upper-case, one lower-case, one (digits or special character).', + 'message' => 'Password complexity requirement not met.', //'allowEmpty' => false, //'required' => true, //'last' => false, // Stop validation after this rule @@ -294,17 +294,30 @@ class User extends AppModel { } } + public function passwordLength($check) { + $length = Configure::read('Security.password_policy_length'); + if (empty($length) || $length < 0) $length = 6; + $value = array_values($check); + $value = $value[0]; + if (strlen($value) < $length) return false; + return true; + } + public function complexPassword($check) { /* + default password: 6 characters minimum 1 or more upper-case letters 1 or more lower-case letters 1 or more digits or special characters example: "EasyPeasy34" + If Security.password_policy_complexity is set and valid, use the regex provided. */ + $regex = Configure::read('Security.password_policy_complexity'); + if (empty($regex) || @preg_match($regex, 'test') === false) $regex = '/((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/'; $value = array_values($check); $value = $value[0]; - return preg_match('/((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/', $value); + return preg_match($regex, $value); } public function identicalFieldValues($field=array(), $compareField=null) {