Changeset:
a0b36004fb72
https://sourceforge.net/p/mrbs/hg-code/ci/a0b36004fb7277e6ac4fdc089c7608fa6a9500b6
Author:
John Beranek <[email protected]>
Date:
Wed Sep 16 22:04:55 2015 +0100
Log message:
Added support for the 'db' auth scheme to store password hashs in
PHP's 'password_hash' format. If the password_hash() function
is functional (as determined by the password_compat library)
new/changed passwords will be encrypted using password_hash().
Existing passwords in md5 format will continue to work,
administrators can see the hash format a user's entry is using
in the "User list".
diffstat:
tables.my.sql | 5 +-
tables.pg.sql | 5 +-
web/auth/auth_db.inc | 38 +++-
web/dbsys.inc | 2 +-
web/defaultincludes.inc | 2 +-
web/edit_users.php | 38 +++-
web/lang/lang.en | 1 +
web/password_compat/password.php | 317 +++++++++++++++++++++++++++++++++++++++
web/upgrade/45/mysql.sql | 9 +
web/upgrade/45/pgsql.sql | 9 +
10 files changed, 403 insertions(+), 23 deletions(-)
diffs (truncated from 552 to 300 lines):
diff -r fda14c6e06f7 -r a0b36004fb72 tables.my.sql
--- a/tables.my.sql Tue Sep 15 21:24:31 2015 +0100
+++ b/tables.my.sql Wed Sep 16 22:04:55 2015 +0100
@@ -181,7 +181,8 @@
id int NOT NULL auto_increment,
level smallint DEFAULT '0' NOT NULL, /* play safe and give no rights */
name varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci,
- password varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci,
+ password varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci,
+ hash_format varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci,
email varchar(75) CHARACTER SET utf8 COLLATE utf8_general_ci,
PRIMARY KEY (id),
@@ -189,6 +190,6 @@
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO mrbs_variables (variable_name, variable_content)
- VALUES ( 'db_version', '44');
+ VALUES ( 'db_version', '45');
INSERT INTO mrbs_variables (variable_name, variable_content)
VALUES ( 'local_db_version', '1');
diff -r fda14c6e06f7 -r a0b36004fb72 tables.pg.sql
--- a/tables.pg.sql Tue Sep 15 21:24:31 2015 +0100
+++ b/tables.pg.sql Wed Sep 16 22:04:55 2015 +0100
@@ -173,13 +173,14 @@
id serial primary key,
level smallint DEFAULT '0' NOT NULL, /* play safe and give no rights */
name varchar(30),
- password varchar(40),
+ password varchar(255),
+ hash_format varchar(16),
email varchar(75),
CONSTRAINT mrbs_uq_name UNIQUE (name)
);
INSERT INTO mrbs_variables (variable_name, variable_content)
- VALUES ('db_version', '44');
+ VALUES ('db_version', '45');
INSERT INTO mrbs_variables (variable_name, variable_content)
VALUES ('local_db_version', '1');
diff -r fda14c6e06f7 -r a0b36004fb72 web/auth/auth_db.inc
--- a/web/auth/auth_db.inc Tue Sep 15 21:24:31 2015 +0100
+++ b/web/auth/auth_db.inc Wed Sep 16 22:04:55 2015 +0100
@@ -35,28 +35,48 @@
function authValidateUser($user, $pass)
{
global $tbl_users;
+ $result = 0;
- // No sql_escape() required on $pass because it's put in the database as an
MD5,
- // which is safe. The escaping for $user is done by
sql_syntax_casesensitive_equals()
- $pass = md5($pass);
-
// We use sql_syntax_casesensitive_equals() rather than just '=' because '='
in MySQL
// permits trailing spacings, eg 'john' = 'john '. We could use LIKE, but
that then
// permits wildcards, so we could use a comnination of LIKE and '=' but
that's a bit
// messy. WE could use STRCMP, but that's MySQL only.
- $sql = "SELECT COUNT(*)
+ $sql = "SELECT password, hash_format
FROM $tbl_users
- WHERE " . sql_syntax_casesensitive_equals('name',
utf8_strtolower($user)) . "
- AND password='$pass'
+ WHERE " .
+ sql_syntax_casesensitive_equals('name', utf8_strtolower($user)) .
+ "
LIMIT 1";
- $result = sql_query1($sql);
- if ($result == -1)
+ $res = sql_query($sql);
+ if ($res == FALSE)
{
trigger_error(sql_error(), E_USER_WARNING);
return 0;
}
+ $row = sql_row_keyed($res, 0);
+
+ switch ($row['hash_format'])
+ {
+ case 'md5':
+ if (md5($pass) == $row['password'])
+ {
+ $result = 1;
+ }
+ break;
+
+ case 'php_hash':
+ if (password_verify($pass, $row['password']))
+ {
+ $result = 1;
+ }
+ break;
+
+ default:
+ trigger_error("Invalid hash format in DB!", E_USER_WARNING);
+ }
+
return $result;
}
diff -r fda14c6e06f7 -r a0b36004fb72 web/dbsys.inc
--- a/web/dbsys.inc Tue Sep 15 21:24:31 2015 +0100
+++ b/web/dbsys.inc Wed Sep 16 22:04:55 2015 +0100
@@ -23,7 +23,7 @@
}
-$db_schema_version = 44;
+$db_schema_version = 45;
$local_db_schema_version = 1;
// Include the abstraction configured to be used for the default MRBS
diff -r fda14c6e06f7 -r a0b36004fb72 web/defaultincludes.inc
--- a/web/defaultincludes.inc Tue Sep 15 21:24:31 2015 +0100
+++ b/web/defaultincludes.inc Wed Sep 16 22:04:55 2015 +0100
@@ -17,6 +17,6 @@
require_once "theme.inc";
require_once "functions.inc";
require_once "dbsys.inc";
+require_once("password_compat/password.php");
require_once "mrbs_auth.inc";
require "standard_vars.inc.php";
-
diff -r fda14c6e06f7 -r a0b36004fb72 web/edit_users.php
--- a/web/edit_users.php Tue Sep 15 21:24:31 2015 +0100
+++ b/web/edit_users.php Wed Sep 16 22:04:55 2015 +0100
@@ -348,6 +348,8 @@
case 'password':
echo "<input type=\"hidden\" name=\"" . $params['name'] ."\"
value=\"". htmlspecialchars($params['value']) . "\">\n";
break;
+ case 'hash_format':
+ break;
default:
echo "<div>\n";
switch($key)
@@ -543,13 +545,19 @@
$q_string .= "&Id=$Id";
continue;
}
- // first, get all the other form variables and put them into an array,
$values, which
- // we will use for entering into the database assuming we pass validation
- $values[$fieldname] = get_form_var(VAR_PREFIX. $fieldname, $type);
- // Truncate the field to the maximum length as a precaution.
- if (isset($maxlength["users.$fieldname"]))
+
+ // The value of 'hash_format' is determined below, in the special
+ // case code for 'password', so we don't set it here
+ if ($fieldname != 'hash_format')
{
- $values[$fieldname] = utf8_substr($values[$fieldname], 0,
$maxlength["users.$fieldname"]);
+ // first, get all the other form variables and put them into an array,
$values, which
+ // we will use for entering into the database assuming we pass
validation
+ $values[$fieldname] = get_form_var(VAR_PREFIX. $fieldname, $type);
+ // Truncate the field to the maximum length as a precaution.
+ if (isset($maxlength["users.$fieldname"]))
+ {
+ $values[$fieldname] = utf8_substr($values[$fieldname], 0,
$maxlength["users.$fieldname"]);
+ }
}
// we will also put the data into a query string which we will use for
passing
// back to this page if we fail validation. This will enable us to
reload the
@@ -568,14 +576,28 @@
case 'password':
// password: if the password field is blank it means
// that the user doesn't want to change the password
- // so don't do anything; otherwise get the MD5 hash.
+ // so don't do anything; otherwise calculate the hash.
// Note: we don't put the password in the query string
// for security reasons.
if (!empty($password0))
{
- $values[$fieldname]=md5($password0);
+ if (PasswordCompat\binary\check())
+ {
+ $hash = password_hash($password0, PASSWORD_DEFAULT);
+ $hash_format = 'php_hash';
+ }
+ else
+ {
+ $hash = md5($password0);
+ $hash_format = 'md5';
+ }
+ $values[$fieldname] = $hash;
+ $values['hash_format'] = $hash_format;
}
break;
+ case 'hash_format':
+ // We override hash_format, above
+ break;
case 'level':
// level: set a safe default (lowest level of access)
// if there is no value set
diff -r fda14c6e06f7 -r a0b36004fb72 web/lang/lang.en
--- a/web/lang/lang.en Tue Sep 15 21:24:31 2015 +0100
+++ b/web/lang/lang.en Wed Sep 16 22:04:55 2015 +0100
@@ -215,6 +215,7 @@
$vocab["please_login"] = "Please log in";
$vocab["users.name"] = "Name";
$vocab["users.password"] = "Password";
+$vocab["users.hash_format"] = "Hash format";
$vocab["users.level"] = "Rights";
$vocab["unknown_user"] = "Unknown user";
$vocab["you_are"] = "You are";
diff -r fda14c6e06f7 -r a0b36004fb72 web/password_compat/password.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/password_compat/password.php Wed Sep 16 22:04:55 2015 +0100
@@ -0,0 +1,317 @@
+<?php
+/**
+ * A Compatibility library with PHP 5.5's simplified password hashing API.
+ *
+ * @author Anthony Ferrara <[email protected]>
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @copyright 2012 The Authors
+ */
+
+namespace {
+
+ if (!defined('PASSWORD_BCRYPT')) {
+ /**
+ * PHPUnit Process isolation caches constants, but not function
declarations.
+ * So we need to check if the constants are defined separately from
+ * the functions to enable supporting process isolation in userland
+ * code.
+ */
+ define('PASSWORD_BCRYPT', 1);
+ define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
+ define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
+ }
+
+ if (!function_exists('password_hash')) {
+
+ /**
+ * Hash the password using the specified algorithm
+ *
+ * @param string $password The password to hash
+ * @param int $algo The algorithm to use (Defined by PASSWORD_*
constants)
+ * @param array $options The options for the algorithm to use
+ *
+ * @return string|false The hashed password, or false on error.
+ */
+ function password_hash($password, $algo, array $options = array()) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_hash to
function", E_USER_WARNING);
+ return null;
+ }
+ if (is_null($password) || is_int($password)) {
+ $password = (string) $password;
+ }
+ if (!is_string($password)) {
+ trigger_error("password_hash(): Password must be a string",
E_USER_WARNING);
+ return null;
+ }
+ if (!is_int($algo)) {
+ trigger_error("password_hash() expects parameter 2 to be long,
" . gettype($algo) . " given", E_USER_WARNING);
+ return null;
+ }
+ $resultLength = 0;
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ $cost = PASSWORD_BCRYPT_DEFAULT_COST;
+ if (isset($options['cost'])) {
+ $cost = (int) $options['cost'];
+ if ($cost < 4 || $cost > 31) {
+ trigger_error(sprintf("password_hash(): Invalid
bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
+ return null;
+ }
+ }
+ // The length of salt to generate
+ $raw_salt_len = 16;
+ // The length required in the final serialization
+ $required_salt_len = 22;
+ $hash_format = sprintf("$2y$%02d$", $cost);
+ // The expected length of the final crypt() output
+ $resultLength = 60;
+ break;
+ default:
+ trigger_error(sprintf("password_hash(): Unknown password
hashing algorithm: %s", $algo), E_USER_WARNING);
+ return null;
+ }
+ $salt_req_encoding = false;
+ if (isset($options['salt'])) {
+ switch (gettype($options['salt'])) {
+ case 'NULL':
+ case 'boolean':
+ case 'integer':
+ case 'double':
+ case 'string':
+ $salt = (string) $options['salt'];
+ break;
+ case 'object':
+ if (method_exists($options['salt'], '__tostring')) {
+ $salt = (string) $options['salt'];
+ break;
+ }
+ case 'array':
+ case 'resource':
+ default:
------------------------------------------------------------------------------
Monitor Your Dynamic Infrastructure at Any Scale With Datadog!
Get real-time metrics from all of your servers, apps and tools
in one place.
SourceForge users - Click here to start your Free Trial of Datadog now!
http://pubads.g.doubleclick.net/gampad/clk?id=241902991&iu=/4140
_______________________________________________
Mrbs-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mrbs-commits