3 * Authorization functions.
5 * LICENSE: This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
17 * @author Rod Roark <rod@sunsetsystems.com>
18 * @author Brady Miller <brady.g.miller@gmail.com>
19 * @author Kevin Yeh <kevin.y@integralemr.com>
20 * @author ViCarePlus <visolve_emr@visolve.com>
22 * @link http://www.open-emr.org
25 //----------THINGS WE ALWAYS DO
27 require_once("{$GLOBALS['srcdir']}/log.inc");
28 // added for the phpGACL group check -- JRM
29 require_once("{$GLOBALS['srcdir']}/acl.inc");
30 require_once("$srcdir/authentication/login_operations.php");
32 $incoming_site_id = '';
34 if (isset($_GET['auth']) && ($_GET['auth'] == "login") && isset($_POST['authUser']) &&
35 isset($_POST['clearPass']) && isset($_POST['authProvider'])) {
36 $clearPass=$_POST['clearPass'];
38 if (!empty($_POST['languageChoice'])) {
39 $_SESSION['language_choice'] = $_POST['languageChoice'];
41 $_SESSION['language_choice'] = 1;
44 // set language direction according to language choice. Later in globals.php we'll override main theme name if needed.
45 $_SESSION['language_direction'] = getLanguageDir($_SESSION['language_choice']);
47 if (!validate_user_password($_POST['authUser'], $clearPass, $_POST['authProvider']) || !verify_user_gacl_group($_POST['authUser'])) {
48 $_SESSION['loginfailure'] = 1;
52 //If password expiration option is enabled call authCheckExpired() to check whether login user password is expired or not
54 if ($GLOBALS['password_expiration_days'] != 0) {
55 if (authCheckExpired($_POST['authUser'])) {
60 $ip=$_SERVER['REMOTE_ADDR'];
61 $_SESSION['loginfailure'] = null;
62 unset($_SESSION['loginfailure']);
63 //store the very first initial timestamp for timeout errors
64 $_SESSION["last_update"] = time();
65 } else if ((isset($_GET['auth'])) && ($_GET['auth'] == "logout")) {
66 //If session has timed out / been destroyed, logout record for null user/provider will be invalid.
67 if (!empty($_SESSION['authUser']) && !empty($_SESSION['authProvider'])) {
68 newEvent("logout", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "success");
71 authLoginScreen(true);
73 if (authCheckSession()) {
74 if (isset($_SESSION['pid']) && empty($GLOBALS['DAEMON_FLAG'])) {
75 require_once("{$GLOBALS['srcdir']}/patient.inc");
77 $logpatient = getPatientData($_SESSION['pid'], "lname, fname, mname");
78 newEvent("view", $_SESSION['authUser'], $_SESSION['authProvider'],
79 "{$logpatient['lname']}, {$logpatient['fname']} {$logpatient['mname']} :: encounter " .
80 $_SESSION['encounter']);
85 //newEvent("view", $_SESSION['authUser'], $_SESSION['authProvider'], $_SERVER['REQUEST_URI']);
87 newEvent("login", $_POST['authUser'], $_POST['authProvider'], 0, "insufficient data sent");
92 if (!isset($_SESSION["last_update"])) {
95 //if page has not been updated in a given period of time, we call login screen
96 //--Note can't perform nice logout if skip_timeout_reset is set since these are called
97 //via ajax scripts where this output is not getting sent to browser.
98 //--Note DAEMON_FLAG is ok because it is run from a frame in the browser.
99 if (((time() - $_SESSION["last_update"]) > $timeout) && empty($_REQUEST['skip_timeout_reset'])) {
100 newEvent("logout", $_SESSION['authUser'], $_SESSION['authProvider'], 0, "timeout");
102 authLoginScreen(true);
104 // Have a mechanism to skip the timeout reset mechanism if a skip_timeout_reset parameter exists. This
105 // can be used by scripts that continually request information from the server; for example the Messages
106 // and Reminders automated intermittent requests that happen in the Messages Center script and in
107 // the left navigation menu script.
108 if (empty($GLOBALS['DAEMON_FLAG']) && empty($_REQUEST['skip_timeout_reset'])) {
109 $_SESSION["last_update"] = time();
116 //----------THINGS WE DO IF WE STILL LIKE YOU
118 function authCheckSession()
120 if (isset($_SESSION['authId'])) {
121 // If active directory was used, check a different session variable (as there is no password in database).
122 if ($GLOBALS['use_active_directory']) {
123 if ($_SESSION['active_directory_auth']) {
130 $authDB = privQuery("select ".implode(",", array(TBL_USERS.".".COL_ID,
131 TBL_USERS.".".COL_UNM,
132 TBL_USERS_SECURE.".".COL_PWD,
133 TBL_USERS_SECURE.".".COL_ID))
134 . " FROM ". implode(",", array(TBL_USERS,TBL_USERS_SECURE))
135 . " WHERE ". TBL_USERS.".".COL_ID." = ? "
136 . " AND ". TBL_USERS.".".COL_UNM . "=" . TBL_USERS_SECURE.".".COL_UNM
137 . " AND ". TBL_USERS.".".COL_ACTIVE . "=1", array($_SESSION['authId']));
138 if ($_SESSION['authUser'] == $authDB['username']
139 && $_SESSION['authPass'] == $authDB['password'] ) {
149 function authCloseSession()
151 // Before destroying the session, save its site_id so that the next
152 // login will default to that same site.
153 global $incoming_site_id;
154 $incoming_site_id = $_SESSION['site_id'];
158 unset($_COOKIE[session_name()]);
161 function authLoginScreen($timed_out = false)
163 // See comment in authCloseSession().
164 global $incoming_site_id;
167 // Find the top level window for this instance of OpenEMR, set a flag indicating
168 // session timeout has occurred, and reload the login page into it. This is so
169 // that beforeunload event handlers will not obstruct the process in this case.
171 while (w.opener) { // in case we are in a dialog window
176 <?php if ($timed_out) { ?>
177 w.top.timed_out = true;
179 w.top.location.href = '<?php echo "{$GLOBALS['login_screen']}?error=1&site=$incoming_site_id"; ?>';
185 // Check if the user's password has expired beyond the grace limit.
186 // If so, deactivate the user
187 function authCheckExpired($user)
189 $result = sqlStatement("select pwd_expiration_date from users where username = ?", array($user));
190 if ($row = sqlFetchArray($result)) {
191 $pwd_expires = $row['pwd_expiration_date'];
194 $current_date = date("Y-m-d");
195 if ($pwd_expires != "0000-00-00") {
196 $grace_time1 = date("Y-m-d", strtotime($pwd_expires . "+".$GLOBALS['password_grace_time'] ."days"));
199 if (($grace_time1 != "") && strtotime($current_date) > strtotime($grace_time1)) {
200 sqlStatement("update users set active=0 where username = ?", array($user));
201 $_SESSION['loginfailure'] = 1;
208 function getUserList($cols = '*', $limit = 'all', $start = '0')
210 if ($limit = "all") {
211 $rez = sqlStatement("select $cols from users where username != '' order by date DESC");
213 $rez = sqlStatement("select $cols from users where username != '' order by date DESC limit $limit, $start");
216 for ($iter = 0; $row = sqlFetchArray($rez); $iter++) {
223 function getProviderList($cols = '*', $limit = 'all', $start = '0')
225 if ($limit = "all") {
226 $rez = sqlStatement("select $cols from `groups` order by date DESC");
228 $rez = sqlStatement("select $cols from `groups` order by date DESC limit $limit, $start");
231 for ($iter = 0; $row = sqlFetchArray($rez); $iter++) {
238 function addGroup($groupname)
240 return sqlInsert("insert into `groups` (name) values (?)", array($groupname));
243 function delGroup($group_id)
245 return sqlQuery("delete from `groups` where id = ? limit 0,1", array($group_id));
248 /***************************************************************
250 //Function currently user by new post calendar code to determine
251 //if a given user is in a group with another user
252 //and if so to allow editing of that users events
254 //*************************************************************/
256 function validateGroupStatus($user_to_be_checked, $group_user)
258 if (isset($user_to_be_checked) && isset($group_user)) {
259 if ($user_to_be_checked == $group_user) {
261 } elseif ($_SESSION['authorizeduser'] == 1) {
265 $query = "SELECT `groups`.`name` FROM `users`,`groups` WHERE users.username = ? " .
266 "AND users.username = `groups`.`user` group by `groups`.`name`";
267 $result = sqlStatement($query, array($user_to_be_checked));
269 $usertbcGroups = array();
271 while ($row = sqlFetchArray($result)) {
272 $usertbcGroups[] = $row[0];
275 $query = "SELECT `groups`.`name` FROM `users`,`groups` WHERE users.username = ? " .
276 "AND users.username = `groups`.`user` group by `groups`.`name`";
277 $result = sqlStatement($query, array($group_user));
279 $usergGroups = array();
281 while ($row = sqlFetchArray($result)) {
282 $usergGroups[] = $row[0];
285 foreach ($usertbcGroups as $group) {
286 if (in_array($group, $usergGroups)) {
296 // Attempt to update the user's password, password history, and password expiration.
297 // Verify that the new password does not match the last three passwords used.
298 // Return true if successfull, false on failure
299 function UpdatePasswordHistory($userid, $pwd)
301 $result = sqlStatement("select password, pwd_history1, pwd_history2 from users where id = ?", array($userid));
302 if ($row = sqlFetchArray($result)) {
303 $previous_pwd1=$row['password'];
304 $previous_pwd2=$row['pwd_history1'];
305 $previous_pwd3=$row['pwd_history2'];
308 if (($pwd != $previous_pwd1) && ($pwd != $previous_pwd2) && ($pwd != $previous_pwd3)) {
309 sqlStatement("update users set pwd_history2=?, pwd_history1=?,password=? where id=?", array($previous_pwd2,$previous_pwd1,$pwd,$userid));
310 if ($GLOBALS['password_expiration_days'] != 0) {
311 $exp_days=$GLOBALS['password_expiration_days'];
312 $exp_date = date('Y-m-d', strtotime("+$exp_days days"));
313 sqlStatement("update users set pwd_expiration_date=? where id=?", array($exp_date,$userid));