diff --git a/Security.MD b/Security.MD
index 9eab4bf3a..35b89b446 100644
--- a/Security.MD
+++ b/Security.MD
@@ -8,7 +8,7 @@ In order to give the community time to respond and upgrade we strongly urge you
### Password Storage
-OpenCATS uses MD5 hashing to store passwords. This will be replaced in future versions
+OpenCATS hashes user passwords using PHP’s password_hash() and verifies them with password_verify(), using PASSWORD_DEFAULT (the default algorithm selected by the running PHP version).
### XSS
diff --git a/db/cats_schema.sql b/db/cats_schema.sql
index 37c551a95..033b654c7 100755
--- a/db/cats_schema.sql
+++ b/db/cats_schema.sql
@@ -859,7 +859,7 @@ insert into `module_schema`(`module_schema_id`,`name`,`version`) values (9,'ext
insert into `module_schema`(`module_schema_id`,`name`,`version`) values (10,'graphs',0);
insert into `module_schema`(`module_schema_id`,`name`,`version`) values (11,'home',0);
insert into `module_schema`(`module_schema_id`,`name`,`version`) values (12,'import',0);
-insert into `module_schema`(`module_schema_id`,`name`,`version`) values (13,'install',363);
+insert into `module_schema`(`module_schema_id`,`name`,`version`) values (13,'install',365);
insert into `module_schema`(`module_schema_id`,`name`,`version`) values (14,'joborders',0);
insert into `module_schema`(`module_schema_id`,`name`,`version`) values (15,'lists',0);
insert into `module_schema`(`module_schema_id`,`name`,`version`) values (16,'login',0);
@@ -1072,7 +1072,7 @@ CREATE TABLE `user` (
`site_id` int(11) NOT NULL DEFAULT '0',
`user_name` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`email` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL,
- `password` varchar(128) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
+ `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`access_level` int(11) NOT NULL DEFAULT '100',
`can_change_password` int(1) NOT NULL DEFAULT '1',
`is_test_user` int(1) NOT NULL DEFAULT '0',
@@ -1105,7 +1105,7 @@ CREATE TABLE `user` (
/*Data for the table `user` */
-insert into `user`(`user_id`,`site_id`,`user_name`,`email`,`password`,`access_level`,`can_change_password`,`is_test_user`,`last_name`,`first_name`,`is_demo`,`categories`,`session_cookie`,`pipeline_entries_per_page`,`column_preferences`,`force_logout`,`title`,`phone_work`,`phone_cell`,`phone_other`,`address`,`notes`,`company`,`city`,`state`,`zip_code`,`country`,`can_see_eeo_info`) values (1,1,'admin','admin@testdomain.com','admin',500,1,0,'Administrator','CATS',0,NULL,'CATS=e29233aabf2cdb71373582023ff9747e',15,'a:4:{s:31:\"home:ImportantPipelineDashboard\";a:6:{i:0;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:1;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:6:\"Status\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:8:\"Position\";s:5:\"width\";i:275;}i:4;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:210;}i:5;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:80;}}s:18:\"home:CallsDataGrid\";a:2:{i:0;a:2:{s:4:\"name\";s:4:\"Time\";s:5:\"width\";i:90;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:175;}}s:39:\"candidates:candidatesListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:85;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";i:215;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:25:\"activity:ActivityDataGrid\";a:7:{i:0;a:2:{s:4:\"name\";s:4:\"Date\";s:5:\"width\";i:110;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:9:\"Regarding\";s:5:\"width\";i:125;}i:4;a:2:{s:4:\"name\";s:8:\"Activity\";s:5:\"width\";i:65;}i:5;a:2:{s:4:\"name\";s:5:\"Notes\";s:5:\"width\";i:240;}i:6;a:2:{s:4:\"name\";s:10:\"Entered By\";s:5:\"width\";i:60;}}}',0,'','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
+insert into `user`(`user_id`,`site_id`,`user_name`,`email`,`password`,`access_level`,`can_change_password`,`is_test_user`,`last_name`,`first_name`,`is_demo`,`categories`,`session_cookie`,`pipeline_entries_per_page`,`column_preferences`,`force_logout`,`title`,`phone_work`,`phone_cell`,`phone_other`,`address`,`notes`,`company`,`city`,`state`,`zip_code`,`country`,`can_see_eeo_info`) values (1,1,'admin','admin@testdomain.com',md5('cats'),500,1,0,'Administrator','CATS',0,NULL,'CATS=e29233aabf2cdb71373582023ff9747e',15,'a:4:{s:31:\"home:ImportantPipelineDashboard\";a:6:{i:0;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:1;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:6:\"Status\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:8:\"Position\";s:5:\"width\";i:275;}i:4;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:210;}i:5;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:80;}}s:18:\"home:CallsDataGrid\";a:2:{i:0;a:2:{s:4:\"name\";s:4:\"Time\";s:5:\"width\";i:90;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:175;}}s:39:\"candidates:candidatesListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:85;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";i:215;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:25:\"activity:ActivityDataGrid\";a:7:{i:0;a:2:{s:4:\"name\";s:4:\"Date\";s:5:\"width\";i:110;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:9:\"Regarding\";s:5:\"width\";i:125;}i:4;a:2:{s:4:\"name\";s:8:\"Activity\";s:5:\"width\";i:65;}i:5;a:2:{s:4:\"name\";s:5:\"Notes\";s:5:\"width\";i:240;}i:6;a:2:{s:4:\"name\";s:10:\"Entered By\";s:5:\"width\";i:60;}}}',0,'','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
insert into `user`(`user_id`,`site_id`,`user_name`,`email`,`password`,`access_level`,`can_change_password`,`is_test_user`,`last_name`,`first_name`,`is_demo`,`categories`,`session_cookie`,`pipeline_entries_per_page`,`column_preferences`,`force_logout`,`title`,`phone_work`,`phone_cell`,`phone_other`,`address`,`notes`,`company`,`city`,`state`,`zip_code`,`country`,`can_see_eeo_info`) values (1250,180,'cats@rootadmin','0','cantlogin',0,0,0,'Automated','CATS',0,NULL,NULL,15,NULL,0,'','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
/*Table structure for table `user_login` */
diff --git a/installwizard.php b/installwizard.php
index 911d5fd39..ba56d4ab6 100755
--- a/installwizard.php
+++ b/installwizard.php
@@ -416,7 +416,7 @@
You may now login to OpenCATS. If it is a new installation, use the following logon information:
Username: admin
- Password: admin
+ Password: cats
OpenCATS will periodically check for new versions of the software from catsone.com, and will send non confidential information about your
diff --git a/lib/Users.php b/lib/Users.php
old mode 100755
new mode 100644
index e4b75e615..5420b02c3
--- a/lib/Users.php
+++ b/lib/Users.php
@@ -90,7 +90,7 @@ public function add($lastName, $firstName, $email, $username, $password,
$accessLevel, $eeoIsVisible = false, $userSiteID = -1)
{
- $md5pwd = $password == LDAPUSER_PASSWORD ? $password : md5($password);
+ $hashedPassword = $password == LDAPUSER_PASSWORD ? $password : $this->hashPassword($password);
$userSiteID = $userSiteID < 0 ? $this->_siteID : $userSiteID;
$sql = sprintf(
"INSERT INTO user (
@@ -118,7 +118,7 @@ public function add($lastName, $firstName, $email, $username, $password,
%s
)",
$this->_db->makeQueryString($username),
- $this->_db->makeQueryString($md5pwd),
+ $this->_db->makeQueryString($hashedPassword),
$this->_db->makeQueryInteger($accessLevel),
$this->_db->makeQueryString($email),
$this->_db->makeQueryString($firstName),
@@ -676,7 +676,19 @@ public function changePassword($userID, $currentPassword, $newPassword)
}
/* Is the user's supplied password correct? */
- if ($rs['password'] !== md5($currentPassword))
+ /* FIXME: This code relies on verifyAndMigratePassword() to handle both legacy
+ * MD5 hashes and modern password_hash() output. If verifyAndMigratePassword()
+ * is changed in a future release (for example when removing MD5 support or
+ * switching to a different algorithm), this password check must be reviewed
+ * and adjusted accordingly.
+ *
+ * Previous MD5-only implementation for reference:
+ * if ($rs['password'] !== md5($currentPassword))
+ * {
+ * return LOGIN_INVALID_PASSWORD;
+ * }
+ */
+ if (!$this->verifyAndMigratePassword($userID, $currentPassword, $rs['password']))
{
return LOGIN_INVALID_PASSWORD;
}
@@ -694,14 +706,15 @@ public function changePassword($userID, $currentPassword, $newPassword)
}
/* Change the user's password. */
+ $newPasswordHash = $this->hashPassword($newPassword);
$sql = sprintf(
"UPDATE
user
SET
- password = md5(%s)
+ password = %s
WHERE
user.user_id = %s",
- $this->_db->makeQueryString($newPassword),
+ $this->_db->makeQueryString($newPasswordHash),
$this->_db->makeQueryInteger($userID)
);
$this->_db->query($sql);
@@ -748,14 +761,15 @@ public function resetPassword($userID, $newPassword)
}
/* Change the user's password. */
+ $newPasswordHash = $this->hashPassword($newPassword);
$sql = sprintf(
"UPDATE
user
SET
- password = md5(%s)
+ password = %s
WHERE
user.user_id = %s",
- $this->_db->makeQueryString($newPassword),
+ $this->_db->makeQueryString($newPasswordHash),
$this->_db->makeQueryInteger($userID)
);
$this->_db->query($sql);
@@ -798,7 +812,8 @@ public function isCorrectLogin($username, $password)
"SELECT
user.user_name AS username,
user.password AS password,
- user.access_level AS accessLevel
+ user.access_level AS accessLevel,
+ user.user_id AS userID
FROM
user
WHERE
@@ -837,10 +852,12 @@ public function isCorrectLogin($username, $password)
return LOGIN_INVALID_USER;
} else {
/* Is the user's supplied password correct? */
- if ($rs['password'] !== md5($password))
+ if (!$this->verifyAndMigratePassword((int) $rs['userID'], $password, $rs['password']))
{
return LOGIN_INVALID_PASSWORD;
}
+
+ $this->rehashPasswordIfNeeded((int) $rs['userID'], $rs['password'], $password);
}
if (!$existsInDB && $existsInLDAP) {
@@ -1236,6 +1253,81 @@ public function getAutomatedUser()
return $rs;
}
+ private function hashPassword($password)
+ {
+ return password_hash($password, PASSWORD_DEFAULT);
+ }
+
+ /**
+ * Upgrades an existing password hash to the current PASSWORD_DEFAULT algorithm/options
+ * after a successful login, if password_needs_rehash() indicates that an update
+ * is required.
+ *
+ * @param int $userID ID of the user whose password hash may be updated.
+ * @param string $storedHash Hash value as it was read from the database before verification.
+ * @param string $password Plain-text password that was just successfully verified.
+ *
+ * @return void
+ */
+ private function rehashPasswordIfNeeded($userID, $storedHash, $password)
+ {
+ if ($this->isLegacyPasswordHash($storedHash) || $storedHash === LDAPUSER_PASSWORD)
+ {
+ return;
+ }
+
+ if (password_needs_rehash($storedHash, PASSWORD_DEFAULT))
+ {
+ $this->updatePasswordHash($userID, $password);
+ }
+ }
+
+ /* FIXME: The following methods exist only for backwards compatibility with legacy MD5 password hashes.
+ * They also perform a one-time lazy migration from MD5 to password_hash().
+ * After several releases with the new algorithm in place, this MD5-related code should be removed
+ * from the codebase.
+ */
+
+ private function isLegacyPasswordHash($hash)
+ {
+ return (bool) preg_match('/^[0-9a-f]{32}$/i', $hash);
+ }
+
+ private function verifyAndMigratePassword($userID, $password, $storedHash)
+ {
+ if ($this->isLegacyPasswordHash($storedHash))
+ {
+ if (md5($password) !== $storedHash)
+ {
+ return false;
+ }
+
+ $this->updatePasswordHash($userID, $password);
+
+ return true;
+ }
+
+ return password_verify($password, $storedHash);
+ }
+
+ private function updatePasswordHash($userID, $password)
+ {
+ $sql = sprintf(
+ "UPDATE
+ user
+ SET
+ password = %s
+ WHERE
+ user.user_id = %s",
+ $this->_db->makeQueryString($this->hashPassword($password)),
+ $this->_db->makeQueryInteger($userID)
+ );
+
+ $this->_db->query($sql);
+ }
+
+ // End of temporary MD5 compatibility and lazy migration code.
+
public function isUserLDAP($userID)
{
$sql = sprintf(
diff --git a/modules/install/Schema.php b/modules/install/Schema.php
index 495405504..6a98eb076 100755
--- a/modules/install/Schema.php
+++ b/modules/install/Schema.php
@@ -1328,6 +1328,10 @@ public static function get()
'364' => '
UPDATE user SET password = md5(password) WHERE can_change_password=1;
',
+ '365' => '
+ ALTER TABLE `user`
+ MODIFY `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT \'\';
+ ',
);
}
diff --git a/modules/install/ajax/ui.php b/modules/install/ajax/ui.php
index 53db04e79..b512f5af5 100755
--- a/modules/install/ajax/ui.php
+++ b/modules/install/ajax/ui.php
@@ -1045,7 +1045,7 @@
MySQLConnect();
/* Determine if a default user is set. */
- $rs = MySQLQuery("SELECT * FROM user WHERE user_name = 'admin' AND password = 'cats'");
+ $rs = MySQLQuery("SELECT * FROM user WHERE user_name = 'admin' AND password = md5('cats')");
if ($rs && mysqli_fetch_row($rs))
{
//Default user set
diff --git a/test/data/test.sql b/test/data/test.sql
index 18748e05b..5037dde81 100644
--- a/test/data/test.sql
+++ b/test/data/test.sql
@@ -1615,7 +1615,7 @@ CREATE TABLE `user` (
LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
-INSERT INTO `user` VALUES (1,1,'admin','admin@testdomain.com','21232f297a57a5a743894a0e4a801fc3',500,1,0,'Administrator','CATS',0,NULL,'CATS=63141ada1735df1a81579c547b172ca0',15,'a:11:{s:31:\"home:ImportantPipelineDashboard\";a:6:{i:0;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:1;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:6:\"Status\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:8:\"Position\";s:5:\"width\";i:275;}i:4;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:210;}i:5;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:80;}}s:18:\"home:CallsDataGrid\";a:2:{i:0;a:2:{s:4:\"name\";s:4:\"Time\";s:5:\"width\";i:90;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:175;}}s:39:\"candidates:candidatesListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";s:3:\"119\";}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";s:3:\"149\";}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";s:3:\"280\";}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";s:2:\"72\";}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:25:\"activity:ActivityDataGrid\";a:7:{i:0;a:2:{s:4:\"name\";s:4:\"Date\";s:5:\"width\";i:110;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:9:\"Regarding\";s:5:\"width\";i:125;}i:4;a:2:{s:4:\"name\";s:8:\"Activity\";s:5:\"width\";i:65;}i:5;a:2:{s:4:\"name\";s:5:\"Notes\";s:5:\"width\";i:240;}i:6;a:2:{s:4:\"name\";s:10:\"Entered By\";s:5:\"width\";i:60;}}s:37:\"joborders:JobOrdersListByViewDataGrid\";a:12:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:2:\"ID\";s:5:\"width\";i:26;}i:2;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:55;}i:3;a:2:{s:4:\"name\";s:5:\"Title\";s:5:\"width\";i:170;}i:4;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:135;}i:5;a:2:{s:4:\"name\";s:4:\"Type\";s:5:\"width\";i:30;}i:6;a:2:{s:4:\"name\";s:6:\"Status\";s:5:\"width\";i:40;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:55;}i:8;a:2:{s:4:\"name\";s:3:\"Age\";s:5:\"width\";i:30;}i:9;a:2:{s:4:\"name\";s:9:\"Submitted\";s:5:\"width\";i:18;}i:10;a:2:{s:4:\"name\";s:8:\"Pipeline\";s:5:\"width\";i:18;}i:11;a:2:{s:4:\"name\";s:9:\"Recruiter\";s:5:\"width\";i:65;}}s:37:\"companies:CompaniesListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:255;}i:2;a:2:{s:4:\"name\";s:4:\"Jobs\";s:5:\"width\";i:40;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:90;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:5:\"Phone\";s:5:\"width\";i:85;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:35:\"contacts:ContactsListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:80;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:80;}i:3;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:135;}i:4;a:2:{s:4:\"name\";s:5:\"Title\";s:5:\"width\";i:135;}i:5;a:2:{s:4:\"name\";s:10:\"Work Phone\";s:5:\"width\";i:85;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:85;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:19:\"lists:ListsDataGrid\";a:7:{i:0;a:2:{s:4:\"name\";s:5:\"Count\";s:5:\"width\";i:45;}i:1;a:2:{s:4:\"name\";s:11:\"Description\";s:5:\"width\";i:355;}i:2;a:2:{s:4:\"name\";s:9:\"Data Type\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:9:\"List Type\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:75;}i:5;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:6;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:53:\"candidates:candidatesSavedListByViewDataGrid:s:1:\"1\";\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:85;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";i:200;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:13:\"Added To List\";s:5:\"width\";i:75;}}s:53:\"candidates:candidatesSavedListByViewDataGrid:s:1:\"2\";\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:85;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";i:200;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:13:\"Added To List\";s:5:\"width\";i:75;}}s:51:\"companies:companiesSavedListByViewDataGrid:s:1:\"3\";\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:255;}i:2;a:2:{s:4:\"name\";s:4:\"Jobs\";s:5:\"width\";i:40;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:90;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:5:\"Phone\";s:5:\"width\";i:85;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}}',0,'','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0),(1250,180,'cats@rootadmin','0','cantlogin',0,0,0,'Automated','CATS',0,NULL,NULL,15,NULL,0,'','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
+INSERT INTO `user` VALUES (1,1,'admin','admin@testdomain.com','0832c1202da8d382318e329a7c133ea0',500,1,0,'Administrator','CATS',0,NULL,'CATS=63141ada1735df1a81579c547b172ca0',15,'a:11:{s:31:\"home:ImportantPipelineDashboard\";a:6:{i:0;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:1;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:6:\"Status\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:8:\"Position\";s:5:\"width\";i:275;}i:4;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:210;}i:5;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:80;}}s:18:\"home:CallsDataGrid\";a:2:{i:0;a:2:{s:4:\"name\";s:4:\"Time\";s:5:\"width\";i:90;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:175;}}s:39:\"candidates:candidatesListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";s:3:\"119\";}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";s:3:\"149\";}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";s:3:\"280\";}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";s:2:\"72\";}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:25:\"activity:ActivityDataGrid\";a:7:{i:0;a:2:{s:4:\"name\";s:4:\"Date\";s:5:\"width\";i:110;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:85;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:9:\"Regarding\";s:5:\"width\";i:125;}i:4;a:2:{s:4:\"name\";s:8:\"Activity\";s:5:\"width\";i:65;}i:5;a:2:{s:4:\"name\";s:5:\"Notes\";s:5:\"width\";i:240;}i:6;a:2:{s:4:\"name\";s:10:\"Entered By\";s:5:\"width\";i:60;}}s:37:\"joborders:JobOrdersListByViewDataGrid\";a:12:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:2:\"ID\";s:5:\"width\";i:26;}i:2;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:55;}i:3;a:2:{s:4:\"name\";s:5:\"Title\";s:5:\"width\";i:170;}i:4;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:135;}i:5;a:2:{s:4:\"name\";s:4:\"Type\";s:5:\"width\";i:30;}i:6;a:2:{s:4:\"name\";s:6:\"Status\";s:5:\"width\";i:40;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:55;}i:8;a:2:{s:4:\"name\";s:3:\"Age\";s:5:\"width\";i:30;}i:9;a:2:{s:4:\"name\";s:9:\"Submitted\";s:5:\"width\";i:18;}i:10;a:2:{s:4:\"name\";s:8:\"Pipeline\";s:5:\"width\";i:18;}i:11;a:2:{s:4:\"name\";s:9:\"Recruiter\";s:5:\"width\";i:65;}}s:37:\"companies:CompaniesListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:255;}i:2;a:2:{s:4:\"name\";s:4:\"Jobs\";s:5:\"width\";i:40;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:90;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:5:\"Phone\";s:5:\"width\";i:85;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:35:\"contacts:ContactsListByViewDataGrid\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:80;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:80;}i:3;a:2:{s:4:\"name\";s:7:\"Company\";s:5:\"width\";i:135;}i:4;a:2:{s:4:\"name\";s:5:\"Title\";s:5:\"width\";i:135;}i:5;a:2:{s:4:\"name\";s:10:\"Work Phone\";s:5:\"width\";i:85;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:85;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:19:\"lists:ListsDataGrid\";a:7:{i:0;a:2:{s:4:\"name\";s:5:\"Count\";s:5:\"width\";i:45;}i:1;a:2:{s:4:\"name\";s:11:\"Description\";s:5:\"width\";i:355;}i:2;a:2:{s:4:\"name\";s:9:\"Data Type\";s:5:\"width\";i:75;}i:3;a:2:{s:4:\"name\";s:9:\"List Type\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:75;}i:5;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:6;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}s:53:\"candidates:candidatesSavedListByViewDataGrid:s:1:\"1\";\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:85;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";i:200;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:13:\"Added To List\";s:5:\"width\";i:75;}}s:53:\"candidates:candidatesSavedListByViewDataGrid:s:1:\"2\";\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:31;}i:1;a:2:{s:4:\"name\";s:10:\"First Name\";s:5:\"width\";i:75;}i:2;a:2:{s:4:\"name\";s:9:\"Last Name\";s:5:\"width\";i:85;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:75;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:10:\"Key Skills\";s:5:\"width\";i:200;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:13:\"Added To List\";s:5:\"width\";i:75;}}s:51:\"companies:companiesSavedListByViewDataGrid:s:1:\"3\";\";a:9:{i:0;a:2:{s:4:\"name\";s:11:\"Attachments\";s:5:\"width\";i:10;}i:1;a:2:{s:4:\"name\";s:4:\"Name\";s:5:\"width\";i:255;}i:2;a:2:{s:4:\"name\";s:4:\"Jobs\";s:5:\"width\";i:40;}i:3;a:2:{s:4:\"name\";s:4:\"City\";s:5:\"width\";i:90;}i:4;a:2:{s:4:\"name\";s:5:\"State\";s:5:\"width\";i:50;}i:5;a:2:{s:4:\"name\";s:5:\"Phone\";s:5:\"width\";i:85;}i:6;a:2:{s:4:\"name\";s:5:\"Owner\";s:5:\"width\";i:65;}i:7;a:2:{s:4:\"name\";s:7:\"Created\";s:5:\"width\";i:60;}i:8;a:2:{s:4:\"name\";s:8:\"Modified\";s:5:\"width\";i:60;}}}',0,'','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0),(1250,180,'cats@rootadmin','0','cantlogin',0,0,0,'Automated','CATS',0,NULL,NULL,15,NULL,0,'','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/test/features/bootstrap/FeatureContext.php b/test/features/bootstrap/FeatureContext.php
index d3eb75e7b..e327c2451 100644
--- a/test/features/bootstrap/FeatureContext.php
+++ b/test/features/bootstrap/FeatureContext.php
@@ -37,7 +37,7 @@ class FeatureContext extends MinkContext implements Context, SnippetAcceptingCon
public function __construct()
{
$this->roleData = array(
- 'Administrator' => new Role('admin', 'admin'),
+ 'Administrator' => new Role('admin', 'cats'),
'User' => new Role('john@mycompany.net', 'john99')
);
}
diff --git a/test/features/login.feature b/test/features/login.feature
index ac60cbf0d..53dbbca01 100644
--- a/test/features/login.feature
+++ b/test/features/login.feature
@@ -34,7 +34,7 @@ Feature: Login
Scenario: Login as administrator
Given I am on "/"
And I fill in "Username" with "admin"
- And I fill in "Password" with "admin"
+ And I fill in "Password" with "cats"
When I press "Login"
Then I should not see "Invalid username or password"
And I should see "Administrator"
@@ -62,4 +62,4 @@ Feature: Login
And I should not see "Add Job Orders"
-
\ No newline at end of file
+