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

Reply via email to