prepping docker setting for care coordination module autoconfiguration (#4447)
[openemr.git] / library / auth.inc
blob7b4ea2f99122e21eeb8e619832f9261885c35d66
1 <?php
3 /**
4  * Authorization functions.
5  *
6  * @package   OpenEMR
7  * @link      https://www.open-emr.org
8  * @author    Rod Roark <rod@sunsetsystems.com>
9  * @author    Brady Miller <brady.g.miller@gmail.com>
10  * @author    Kevin Yeh <kevin.y@integralemr.com>
11  * @author    ViCarePlus <visolve_emr@visolve.com>
12  * @author    Ken Chapple <ken@mi-squared.com>
13  * @author    cfapress
14  * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
15  * @copyright Copyright (c) 2021 Ken Chapple <ken@mi-squared.com>
16  * @license   https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
17  */
19 use OpenEMR\Common\Auth\AuthUtils;
20 use OpenEMR\Common\Logging\EventAuditLogger;
21 use OpenEMR\Common\Session\SessionTracker;
22 use OpenEMR\Services\UserService;
24 $incoming_site_id = '';
25 // This is the conditional that ensures that the submission has the required parameters to attempt a login
26 if (
27     isset($_GET['auth'])
28     && ($_GET['auth'] == "login")
29     && isset($_POST['new_login_session_management'])
30     && (
31         // Either normal login or google sign-in
32         (isset($_POST['authUser']) && isset($_POST['clearPass']))
33         || (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id']) && !empty($_POST['used_google_signin']) && !empty($_POST['google_signin_token']))
34     )
35 ) {
36     // Attempt login
38     // set the language
39     if (!empty($_POST['languageChoice'])) {
40         $_SESSION['language_choice'] = $_POST['languageChoice'];
41     } else {
42         $_SESSION['language_choice'] = 1;
43     }
45     // set language direction according to language choice. Later in globals.php we'll override main theme name if needed.
46     $_SESSION['language_direction'] = getLanguageDir($_SESSION['language_choice']);
48     // Note we are purposefully keeping $_POST['clearPass'], which is needed for MFA to work. It is cleared from memory after a
49     //  unsuccessful or successful login
50     $passTemp = $_POST['clearPass'];
52     $login_success = false;
53     if (
54         !empty($GLOBALS['google_signin_enabled']) &&
55         !empty($GLOBALS['google_signin_client_id']) &&
56         !empty($_POST['used_google_signin']) &&
57         !empty($_POST['google_signin_token'])
58     ) {
59         // google sign-in
60         $login_success = AuthUtils::verifyGoogleSignIn($_POST['google_signin_token']);
61     } else {
62         // normal login
63         $login_success = (new AuthUtils('login'))->confirmPassword($_POST['authUser'], $passTemp);
64     }
66     if ($login_success !== true) {
67         // login attempt failed
68         $_SESSION['loginfailure'] = 1;
69         if (function_exists('sodium_memzero')) {
70             sodium_memzero($_POST["clearPass"]);
71         } else {
72             $_POST["clearPass"] = '';
73         }
74         authLoginScreen();
75     }
77     // login attempt success
78     $_SESSION['loginfailure'] = null;
79     unset($_SESSION['loginfailure']);
81     // skip the session expiration check below since the entry in session_tracker is not ready yet
82     $skipSessionExpirationCheck = true;
83 } elseif ((isset($_GET['auth'])) && ($_GET['auth'] == "logout")) {
84     // Logout
85     // If session has timed out / been destroyed, logout record for null user/provider will be invalid.
86     if (!empty($_SESSION['authUser']) && !empty($_SESSION['authProvider'])) {
87         if ((isset($_GET['timeout'])) && ($_GET['timeout'] == "1")) {
88             EventAuditLogger::instance()->newEvent("logout", $_SESSION['authUser'], $_SESSION['authProvider'], 0, "timeout, so force logout");
89         } else {
90             EventAuditLogger::instance()->newEvent("logout", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "success");
91         }
92     }
93     authCloseSession();
94     authLoginScreen(true);
95 } else {
96     // Check if session is valid (already logged in user)
97     if (!AuthUtils::authCheckSession()) {
98         // Session is not valid (this should only happen if a user's password is changed via another session while the user is logged in)
99         EventAuditLogger::instance()->newEvent("logout", $_SESSION['authUser'], $_SESSION['authProvider'], 0, "authCheckSession() check failed, so force logout");
100         authCloseSession();
101         authLoginScreen(true);
102     }
105 // Ensure user has not timed out, if applicable
106 // Have a mechanism to skip the timeout and timeout reset mechanisms if a skip_timeout_reset parameter exists. This
107 //  can be used by scripts that continually request information from the server; for example the Messages
108 //  and Reminders automated intermittent requests.
109 // Also skipping this all on login since entry in session_tracker is not ready yet
110 if (empty($skipSessionExpirationCheck) && empty($_REQUEST['skip_timeout_reset'])) {
111     if (!SessionTracker::isSessionExpired()) {
112         SessionTracker::updateSessionExpiration();
113     } else {
114         // User has timed out.
115         EventAuditLogger::instance()->newEvent("logout", $_SESSION['authUser'], $_SESSION['authProvider'], 0, "timeout, so force logout");
116         authCloseSession();
117         authLoginScreen(true);
118     }
121 require_once(dirname(__FILE__) . "/../src/Common/Session/SessionUtil.php");
122 function authCloseSession()
124   // Before destroying the session, save its site_id so that the next
125   // login will default to that same site.
126     global $incoming_site_id;
127     $incoming_site_id = $_SESSION['site_id'];
128     OpenEMR\Common\Session\SessionUtil::coreSessionDestroy();
131 function authLoginScreen($timed_out = false)
133   // See comment in authCloseSession().
134     global $incoming_site_id;
135     ?>
136 <script>
137  // Find the top level window for this instance of OpenEMR, set a flag indicating
138  // session timeout has occurred, and reload the login page into it.  This is so
139  // that beforeunload event handlers will not obstruct the process in this case.
140  var w = window;
141  while (w.opener) { // in case we are in a dialog window
142   var wtmp = w;
143   w = w.opener;
144   wtmp.close();
146     <?php if ($timed_out) { ?>
147  w.top.timed_out = true;
148 <?php } ?>
149  w.top.location.href = '<?php echo "{$GLOBALS['login_screen']}?error=1&site=$incoming_site_id"; ?>';
150 </script>
151     <?php
152     exit;