fix add_edit_amendments.php
[openemr.git] / library / authentication / password_change.php
blobab9bfbaa8adec9afccbc924e50399b7f572f3c11
1 <?php
2 /**
3 * Function used when changing a user's password
4 * (either the user's own password or an administrator updating a different user)
5 *
6 * Copyright (C) 2013 Kevin Yeh <kevin.y@integralemr.com> and OEMR <www.oemr.org>
8 * LICENSE: This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
19 * @package OpenEMR
20 * @author Kevin Yeh <kevin.y@integralemr.com>
21 * @link http://www.open-emr.org
23 require_once("$srcdir/authentication/common_operations.php");
25 /**
26 * Does the new password meet the security requirements?
28 * @param type $pwd the password to test
29 * @param type $errMsg why there was a failure
30 * @return boolean is the password good enough?
32 function test_password_strength($pwd,&$errMsg)
34 $require_strong=$GLOBALS['secure_password'] !=0;
35 if($require_strong)
37 if(strlen($pwd)<8)
39 $errMsg=xl("Password too short. Minimum 8 characters required.");
40 return false;
42 $features=0;
43 $reg_security=array("/[a-z]+/","/[A-Z]+/","/\d+/","/[\W_]+/");
44 foreach($reg_security as $expr)
46 if(preg_match($expr,$pwd))
48 $features++;
51 if($features<3)
53 $errMsg=xl("Password does not meet minimum requirements and should contain at least three of the four following items: A number, a lowercase letter, an uppercase letter, a special character (Not a leter or number).");
54 return false;
57 return true;
59 /**
60 * Setup or change a user's password
62 * @param type $activeUser ID of who is trying to make the change (either the user himself, or an administrator)
63 * @param type $targetUser ID of what account's password is to be updated (for a new user this doesn't exist yet).
64 * @param type $currentPwd the active user's current password
65 * @param type $newPwd the new password for the target user
66 * @param type $errMsg passed by reference to return any
67 * @param type $create Are we creating a new user or
68 * @param type $insert_sql SQL to run to create the row in "users" (and generate a new id) when needed.
69 * @param type $new_username The username for a new user
70 * @param type $newid Return by reference of the ID of a created user
71 * @return boolean Was the password successfully updated/created? If false, then $errMsg will tell you why it failed.
73 function update_password($activeUser,$targetUser,&$currentPwd,&$newPwd,&$errMsg,$create=false,$insert_sql="",$new_username=null,&$newid=null)
75 $userSQL="SELECT ".implode(",",array(COL_PWD,COL_SALT,COL_PWD_H1,COL_SALT_H1,COL_PWD_H2,COL_SALT_H2))
76 ." FROM ".TBL_USERS_SECURE
77 ." WHERE ".COL_ID."=?";
78 $userInfo=privQuery($userSQL,array($targetUser));
80 // Verify the active user's password
81 $changingOwnPassword = $activeUser==$targetUser;
82 // True if this is the current user changing their own password
83 if($changingOwnPassword)
85 if($create)
87 $errMsg=xl("Trying to create user with existing username!");
88 return false;
90 // If this user is changing his own password, then confirm that they have the current password correct
91 $hash_current = oemr_password_hash($currentPwd,$userInfo[COL_SALT]);
92 if(($hash_current!=$userInfo[COL_PWD]))
94 $errMsg=xl("Incorrect password!");
95 return false;
98 else {
99 // If this is an administrator changing someone else's password, then check that they have the password right
101 $adminSQL=" SELECT ".implode(",",array(COL_PWD,COL_SALT))
102 ." FROM ".TBL_USERS_SECURE
103 ." WHERE ".COL_ID."=?";
104 $adminInfo=privQuery($adminSQL,array($activeUser));
105 $hash_admin = oemr_password_hash($currentPwd,$adminInfo[COL_SALT]);
106 if($hash_admin!=$adminInfo[COL_PWD])
108 $errMsg=xl("Incorrect password!");
109 return false;
111 if(!acl_check('admin', 'users'))
114 $errMsg=xl("Not authorized to manage users!");
115 return false;
118 // End active user check
121 //Test password validity
122 if(strlen($newPwd)==0)
124 $errMsg=xl("Empty Password Not Allowed");
125 return false;
127 if(!test_password_strength($newPwd,$errMsg))
129 return false;
131 // End password validty checks
133 if($userInfo===false)
135 // No userInfo means either a new user, or an existing user who has not been migrated to blowfish yet
136 // In these cases don't worry about password history
137 if($create)
139 privStatement($insert_sql,array());
140 $getUserID= " SELECT ".COL_ID
141 ." FROM ".TBL_USERS
142 ." WHERE ".COL_UNM."=?";
143 $user_id=privQuery($getUserID,array($new_username));
144 initializePassword($new_username,$user_id[COL_ID],$newPwd);
145 $newid=$user_id[COL_ID];
147 else
149 $getUserNameSQL="SELECT ".COL_UNM
150 ." FROM ".TBL_USERS
151 ." WHERE ".COL_ID."=?";
152 $unm=privQuery($getUserNameSQL,array($targetUser));
153 if($unm===false)
155 $errMsg=xl("Unknown user id:".$targetUser);
156 return false;
158 initializePassword($unm[COL_UNM],$targetUser,$newPwd);
159 purgeCompatabilityPassword($unm[COL_UNM],$targetUser);
163 else
164 { // We are trying to update the password of an existing user
166 if($create)
168 $errMsg=xl("Trying to create user with existing username!");
169 return false;
172 $forbid_reuse=$GLOBALS['password_history'] != 0;
173 if($forbid_reuse)
175 // password reuse disallowed
176 $hash_current = oemr_password_hash($newPwd,$userInfo[COL_SALT]);
177 $hash_history1 = oemr_password_hash($newPwd,$userInfo[COL_SALT_H1]);
178 $hash_history2 = oemr_password_hash($newPwd,$userInfo[COL_SALT_H2]);
179 if(($hash_current==$userInfo[COL_PWD])
180 ||($hash_history1==$userInfo[COL_PWD_H1])
181 || ($hash_history2==$userInfo[COL_PWD_H2]))
183 $errMsg=xl("Reuse of three previous passwords not allowed!");
184 return false;
188 // Everything checks out at this point, so update the password record
189 $newSalt = oemr_password_salt();
190 $newHash = oemr_password_hash($newPwd,$newSalt);
191 $updateParams=array();
192 $updateSQL= "UPDATE ".TBL_USERS_SECURE;
193 $updateSQL.=" SET ".COL_PWD."=?,".COL_SALT."=?"; array_push($updateParams,$newHash); array_push($updateParams,$newSalt);
194 if($forbid_reuse){
195 $updateSQL.=",".COL_PWD_H1."=?".",".COL_SALT_H1."=?"; array_push($updateParams,$userInfo[COL_PWD]); array_push($updateParams,$userInfo[COL_SALT]);
196 $updateSQL.=",".COL_PWD_H2."=?".",".COL_SALT_H2."=?"; array_push($updateParams,$userInfo[COL_PWD_H1]); array_push($updateParams,$userInfo[COL_SALT_H1]);
199 $updateSQL.=" WHERE ".COL_ID."=?"; array_push($updateParams,$targetUser);
200 privStatement($updateSQL,$updateParams);
202 // If the user is changing their own password, we need to update the session
203 if($changingOwnPassword)
205 $_SESSION['authPass']=$newHash;
209 if($GLOBALS['password_expiration_days'] != 0){
210 $exp_days=$GLOBALS['password_expiration_days'];
211 $exp_date = date('Y-m-d', strtotime("+$exp_days days"));
212 privStatement("update users set pwd_expiration_date=? where id=?",array($exp_date,$targetUser));
214 return true;