Fixes for restoreSession logic. (#4378)
[openemr.git] / interface / login / login.php
blobd5a16bc31f39a9c3baf48a15a82fe57c801beda9
1 <?php
3 /**
4 * Login screen.
6 * @package OpenEMR
7 * @link http://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 Scott Wakefield <scott.wakefield@gmail.com>
12 * @author ViCarePlus <visolve_emr@visolve.com>
13 * @author Julia Longtin <julialongtin@diasp.org>
14 * @author cfapress
15 * @author markleeds
16 * @author Tyler Wrenn <tyler@tylerwrenn.com>
17 * @author Ken Chapple <ken@mi-squared.com>
18 * @author Daniel Pflieger <daniel@mi-squared.com> <daniel@growlingflea.com>
19 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
20 * @copyright Copyright (c) 2020 Tyler Wrenn <tyler@tylerwrenn.com>
21 * @copyright Copyright (c) 2021 Ken Chapple <ken@mi-squared.com>
22 * @copyright Copyright (c) 2021 Daniel Pflieger <daniel@mi-squared.com> <daniel@growlingflea.com>
23 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
26 use OpenEMR\Core\Header;
27 use OpenEMR\Services\FacilityService;
29 $ignoreAuth = true;
30 // Set $sessionAllowWrite to true to prevent session concurrency issues during authorization related code
31 $sessionAllowWrite = true;
32 require_once("../globals.php");
34 // mdsupport - Add 'App' functionality for user interfaces without standard menu and frames
35 // If this script is called with app parameter, validate it without showing other apps.
37 // Build a list of valid entries
38 $emr_app = array();
39 $rs = sqlStatement(
40 "SELECT option_id, title,is_default FROM list_options
41 WHERE list_id=? and activity=1 ORDER BY seq, option_id",
42 array ('apps')
44 if (sqlNumRows($rs)) {
45 while ($app = sqlFetchArray($rs)) {
46 $app_req = explode('?', trim($app['title']));
47 if (! file_exists('../' . $app_req[0])) {
48 continue;
51 $emr_app [trim($app ['option_id'])] = trim($app ['title']);
52 if ($app ['is_default']) {
53 $emr_app_def = $app ['option_id'];
58 $div_app = '';
59 if (count($emr_app)) {
60 // Standard app must exist
61 $std_app = 'main/main_screen.php';
62 if (!in_array($std_app, $emr_app)) {
63 $emr_app['*OpenEMR'] = $std_app;
66 if (isset($_REQUEST['app']) && $emr_app[$_REQUEST['app']]) {
67 $div_app = sprintf('<input type="hidden" name="appChoice" value="%s">', attr($_REQUEST['app']));
68 } else {
69 foreach ($emr_app as $opt_disp => $opt_value) {
70 $opt_htm .= sprintf(
71 '<option value="%s" %s>%s</option>\n',
72 attr($opt_disp),
73 ($opt_disp == $opt_default ? 'selected="selected"' : ''),
74 text(xl_list_label($opt_disp))
78 $div_app = sprintf(
80 <div id="divApp" class="form-group">
81 <label for="appChoice" class="text-right">%s:</label>
82 <div>
83 <select class="form-control" id="selApp" name="appChoice" size="1">%s</select>
84 </div>
85 </div>',
86 xlt('App'),
87 $opt_htm
92 // This code allows configurable positioning in the login page
93 $loginrow = "row login-row align-items-center m-5";
95 if ($GLOBALS['login_page_layout'] == 'left') {
96 $logoarea = "col-md-6 login-bg-left py-3 px-5 py-md-login order-1 order-md-2";
97 $formarea = "col-md-6 p-5 login-area-left order-2 order-md-1";
98 } else if ($GLOBALS['login_page_layout'] == 'right') {
99 $logoarea = "col-md-6 login-bg-right py-3 px-5 py-md-login order-1 order-md-1";
100 $formarea = "col-md-6 p-5 login-area-right order-2 order-md-2";
101 } else {
102 $logoarea = "col-12 login-bg-center py-3 px-5 order-1";
103 $formarea = "col-12 p-5 login-area-center order-2";
104 $loginrow = "row login-row login-row-center align-items-center";
108 <html>
109 <head>
110 <?php Header::setupHeader(); ?>
112 <title><?php echo text($openemr_name) . " " . xlt('Login'); ?></title>
114 <?php
115 if (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) { ?>
116 <meta name="google-signin-client_id" content="<?php echo $GLOBALS['google_signin_client_id']; ?>">
117 <?php } ?>
118 <script>
119 var registrationTranslations = <?php echo json_encode(array(
120 'title' => xla('OpenEMR Product Registration'),
121 'pleaseProvideValidEmail' => xla('Please provide a valid email address'),
122 'success' => xla('Success'),
123 'registeredSuccess' => xla('Your installation of OpenEMR has been registered'),
124 'submit' => xla('Submit'),
125 'noThanks' => xla('No Thanks'),
126 'registeredEmail' => xla('Registered email'),
127 'registeredId' => xla('Registered id'),
128 'genericError' => xla('Error. Try again later'),
129 'closeTooltip' => ''
130 )); ?>;
132 var registrationConstants = <?php echo json_encode(array(
133 'webroot' => $GLOBALS['webroot']
134 )); ?>;
135 </script>
137 <script src="<?php echo $webroot ?>/interface/product_registration/product_registration_service.js?v=<?php echo $v_js_includes; ?>"></script>
138 <script src="<?php echo $webroot ?>/interface/product_registration/product_registration_controller.js?v=<?php echo $v_js_includes; ?>"></script>
140 <script>
141 $(function () {
142 init();
144 var productRegistrationController = new ProductRegistrationController();
145 productRegistrationController.getProductRegistrationStatus(function(err, data) {
146 if (err) { return; }
148 if (data.statusAsString === 'UNREGISTERED') {
149 productRegistrationController.showProductRegistrationModal();
154 function init() {
155 $("#authUser").focus();
158 function transmit_form(element) {
159 // disable submit button to insert a notification of working
160 element.disabled = true;
161 // nothing fancy. mainly for mobile.
162 element.innerHTML = '<i class="fa fa-sync fa-spin"></i> ' + jsText(<?php echo xlj("Authenticating"); ?>);
163 <?php if (session_name()) { ?>
164 <?php $scparams = session_get_cookie_params(); ?>
165 // Delete the session cookie by setting its expiration date in the past.
166 // This forces the server to create a new session ID.
167 var olddate = new Date();
168 olddate.setFullYear(olddate.getFullYear() - 1);
169 var mycookie = <?php echo json_encode(session_name()); ?> + '=' + <?php echo json_encode(session_id()); ?> +
170 '; path=' + <?php echo json_encode($scparams['path']); ?> +
171 '; domain=' + <?php echo json_encode($scparams['domain']); ?> +
172 '; expires=' + olddate.toGMTString();
173 var samesite = <?php echo json_encode(empty($scparams['samesite']) ? '' : $scparams['samesite']); ?>;
174 if (samesite) {
175 mycookie += '; SameSite=' + samesite;
177 document.cookie = mycookie;
178 <?php } ?>
179 return true;
181 </script>
182 </head>
183 <body class="login">
184 <form method="POST" id="login_form" autocomplete="off" action="../main/main_screen.php?auth=login&site=<?php echo attr($_SESSION['site_id']); ?>" target="_top" name="login_form">
185 <div class="<?php echo $loginrow; ?>">
186 <div class="<?php echo $formarea; ?>">
187 <input type='hidden' name='new_login_session_management' value='1' />
189 <?php
190 // collect default language id
191 $res2 = sqlStatement("select * from lang_languages where lang_description = ?", array($GLOBALS['language_default']));
192 for ($iter = 0; $row = sqlFetchArray($res2); $iter++) {
193 $result2[$iter] = $row;
196 if (count($result2) == 1) {
197 $defaultLangID = $result2[0]["lang_id"];
198 $defaultLangName = $result2[0]["lang_description"];
199 } else {
200 //default to english if any problems
201 $defaultLangID = 1;
202 $defaultLangName = "English";
205 // set session variable to default so login information appears in default language
206 $_SESSION['language_choice'] = $defaultLangID;
207 // collect languages if showing language menu
208 if ($GLOBALS['language_menu_login']) {
209 // sorting order of language titles depends on language translation options.
210 $mainLangID = empty($_SESSION['language_choice']) ? '1' : $_SESSION['language_choice'];
211 // Use and sort by the translated language name.
212 $sql = "SELECT ll.lang_id, " .
213 "IF(LENGTH(ld.definition),ld.definition,ll.lang_description) AS trans_lang_description, " .
214 "ll.lang_description " .
215 "FROM lang_languages AS ll " .
216 "LEFT JOIN lang_constants AS lc ON lc.constant_name = ll.lang_description " .
217 "LEFT JOIN lang_definitions AS ld ON ld.cons_id = lc.cons_id AND " .
218 "ld.lang_id = ? " .
219 "ORDER BY IF(LENGTH(ld.definition),ld.definition,ll.lang_description), ll.lang_id";
220 $res3 = SqlStatement($sql, array($mainLangID));
222 for ($iter = 0; $row = sqlFetchArray($res3); $iter++) {
223 $result3[$iter] = $row;
226 if (count($result3) == 1) {
227 //default to english if only return one language
228 echo "<input type='hidden' name='languageChoice' value='1' />\n";
230 } else {
231 echo "<input type='hidden' name='languageChoice' value='" . attr($defaultLangID) . "' />\n";
234 if ($GLOBALS['login_into_facility']) {
235 $facilityService = new FacilityService();
236 $facilities = $facilityService->getAllFacility();
237 $facilitySelected = ($GLOBALS['set_facility_cookie'] && isset($_COOKIE['pc_facility'])) ? $_COOKIE['pc_facility'] : null;
240 <?php if (isset($_SESSION['relogin']) && ($_SESSION['relogin'] == 1)) { // Begin relogin dialog ?>
241 <div class="alert alert-info m-1 font-weight-bold">
242 <?php echo xlt('Password security has recently been upgraded.') . '&nbsp;&nbsp;' . xlt('Please login again.'); ?>
243 </div>
244 <?php unset($_SESSION['relogin']);
246 if (isset($_SESSION['loginfailure']) && ($_SESSION['loginfailure'] == 1)) { // Begin login failure block ?>
247 <div class="alert alert-danger login-failure m-1">
248 <?php echo xlt('Invalid username or password'); ?>
249 </div>
250 <?php } // End login failure block ?>
251 <div id="standard-auth-username" class="form-group">
252 <label for="authUser" class="text-right"><?php echo xlt('Username:'); ?></label>
253 <input type="text" class="form-control" id="authUser" name="authUser" placeholder="<?php echo xla('Username:'); ?>" />
254 </div>
255 <div id="standard-auth-password" class="form-group">
256 <label for="clearPass" class="text-right"><?php echo xlt('Password:'); ?></label>
257 <input type="password" class="form-control" id="clearPass" name="clearPass" placeholder="<?php echo xla('Password:'); ?>" />
258 </div>
259 <?php echo $div_app; ?>
260 <?php if ($GLOBALS['language_menu_login'] && (count($result3) != 1)) : // Begin language menu block ?>
261 <div class="form-group">
262 <label for="language" class="text-right"><?php echo xlt('Language'); ?>:</label>
263 <div>
264 <select class="form-control" name="languageChoice" size="1">
265 <?php
266 echo "<option selected='selected' value='" . attr($defaultLangID) . "'>" . xlt('Default') . " - " . xlt($defaultLangName) . "</option>\n";
267 foreach ($result3 as $iter) :
268 if ($GLOBALS['language_menu_showall']) {
269 if (!$GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
270 continue; // skip the dummy language
273 echo "<option value='" . attr($iter['lang_id']) . "'>" . text($iter['trans_lang_description']) . "</option>\n";
274 } else {
275 if (in_array($iter['lang_description'], $GLOBALS['language_menu_show'])) {
276 if (!$GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
277 continue; // skip the dummy language
280 echo "<option value='" . attr($iter['lang_id']) . "'>" . text($iter['trans_lang_description']) . "</option>\n";
283 endforeach; ?>
284 </select>
285 </div>
286 </div>
287 <?php endif; // End language menu block ?>
288 <?php if ($GLOBALS['login_into_facility']) { // Begin facilities menu block ?>
289 <div class="form-group">
290 <label for="facility" class="text-right"><?php echo xlt('Facility'); ?>:</label>
291 <div>
292 <select class="form-control" name="facility" size="1">
293 <option value="user_default"><?php echo xlt('My default facility'); ?></option>
294 <?php foreach ($facilities as $facility) { ?>
295 <?php if (!is_null($facilitySelected) && $facilitySelected == $facility['id']) { ?>
296 <option value="<?php echo attr($facility['id']);?>" selected><?php echo text($facility['name']);?></option>
297 <?php } else { ?>
298 <option value="<?php echo attr($facility['id']);?>"><?php echo text($facility['name']);?></option>
299 <?php } ?>
300 <?php } ?>
301 </select>
302 </div>
303 </div>
304 <?php } // End facilities menu block ?>
305 <div class="form-group oe-pull-away">
306 <button id="login-button" type="submit" class="btn btn-login btn-lg" onClick="transmit_form(this)"><i class="fa fa-sign-in-alt"></i>&nbsp;&nbsp;<?php echo xlt('Login');?></button>
307 </div>
308 <div class="form-group">
309 <?php if (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) { ?>
310 <input type="hidden" id="used-google-signin" name="used_google_signin" value="">
311 <input type="hidden" id="google-signin-token" name="google_signin_token" value="">
312 <div id="google-signin" onclick="return do_google_signin();">
313 <!-- This message is displayed if the google platform API cannot render the button -->
314 <span id="google-signin-service-unreachable-alert" style="display:none;"><?php echo xlt('Google Sign-In is enabled but the service is unreachable.'); ?></span>
315 </div>
316 <div id="google-signout">
317 <a href="#" onclick="signOut();"><?php echo xlt('Sign out'); ?></a>
318 </div>
319 <?php } ?>
320 </div>
321 </div>
322 <div class="<?php echo $logoarea; ?>">
323 <?php $extraLogo = $GLOBALS['extra_logo_login']; ?>
324 <?php if ($extraLogo) { ?>
325 <div class="text-center">
326 <span class="d-inline-block w-40"><?php echo file_get_contents($GLOBALS['images_static_absolute'] . "/login-logo.svg"); ?></span>
327 <span class="d-inline-block w-15 login-bg-text-color"><i class="fas fa-plus fa-2x"></i></span>
328 <span class="d-inline-block w-40"><?php echo $logocode; ?></span>
329 </div>
330 <?php } else { ?>
331 <div class="mx-auto m-4 w-75">
332 <?php echo file_get_contents($GLOBALS['images_static_absolute'] . "/login-logo.svg"); ?>
333 </div>
334 <?php } ?>
335 <div class="text-center login-title-label">
336 <?php if ($GLOBALS['show_label_login']) { ?>
337 <?php echo text($openemr_name); ?>
338 <?php } ?>
339 </div>
340 <?php
341 // Figure out how to display the tiny logos
342 $t1 = $GLOBALS['tiny_logo_1'];
343 $t2 = $GLOBALS['tiny_logo_2'];
344 if ($t1 && !$t2) {
345 echo $tinylogocode1;
346 } if ($t2 && !$t1) {
347 echo $tinylogocode2;
348 } if ($t1 && $t2) { ?>
349 <div class="row mb-3">
350 <div class="col-sm-6"><?php echo $tinylogocode1;?></div>
351 <div class="col-sm-6"><?php echo $tinylogocode2;?></div>
352 </div>
353 <?php } ?>
354 <p class="text-center lead font-weight-normal login-bg-text-color"><?php echo xlt('The most popular open-source Electronic Health Record and Medical Practice Management solution.'); ?></p>
355 <p class="text-center small"><a href="../../acknowledge_license_cert.html" class="login-bg-text-color" target="main"><?php echo xlt('Acknowledgments, Licensing and Certification'); ?></a></p>
356 </div>
357 </div>
358 <div class="product-registration-modal modal fade">
359 <div class="modal-dialog modal-dialog-centered">
360 <div class="modal-content">
361 <div class="modal-header"></div>
362 <div class="modal-body">
363 <p class="context"><?php echo xlt("Register your installation with OEMR to receive important notifications, such as security fixes and new release announcements."); ?></p>
364 <input placeholder="<?php echo xlt('email'); ?>" type="email" class="email w-100 text-body form-control" />
365 <p class="message font-italic"></p>
366 </div>
367 <div class="modal-footer">
368 <button type="button" class="btn btn-secondary submit"><?php echo xlt("Submit"); ?></button>
369 <button type="button" class="btn btn-secondary nothanks"><?php echo xlt("No Thanks"); ?></button>
370 </div>
371 </div>
372 </div>
373 </div>
374 </form>
375 </body>
376 </html>
377 <?php if (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) { ?>
378 <script type="text/javascript">
380 // This variable controls whether we should login to OpenEMR
381 // so we only login if "Sign in with Google button" was clicked
382 let google_signin = false;
384 // Hide the google signout link unless we are signed-in
385 // This isn't really ever displayed, because once we sign-in with google,
386 // we automatically log into the app
387 $('#google-signout').hide();
389 // Click-handler for signin button
390 function do_google_signin() {
391 google_signin = true;
394 // When Google sign-in successful, sign in to the app, but only
395 // if the button was clicked (otherwise we would automatically login)
396 function onSignInSuccess(googleUser) {
397 if (google_signin === true) {
398 const auth_response = googleUser.getAuthResponse();
399 const id_token = auth_response.id_token;
400 $('.login-failure').hide();
401 $('#used-google-signin').val(true);
402 $('#google-signin-token').val(id_token);
403 $('#google-signout').show();
404 $('#standard-auth-username, #standard-auth-password').hide();
405 var element = document.getElementById('login-button');
406 transmit_form(element);
410 function onSignInFailure(error) {
411 $('.login-failure').show();
414 function renderButton() {
415 gapi.signin2.render('google-signin', {
416 'prompt': 'select_account',
417 'scope': 'profile email',
418 'width': 240,
419 'height': 50,
420 'longtitle': true,
421 'theme': 'dark',
422 'onsuccess': onSignInSuccess,
423 'onfailure': onSignInFailure
427 function signOut() {
428 google_signin = false;
429 const auth2 = gapi.auth2.getAuthInstance();
430 auth2.signOut().then(function () {
431 $('#used-google-signin').val('');
432 $('#google-signin-token').val('');
433 $('#google-signout').hide();
434 $('#standard-auth-username, #standard-auth-password').show();
438 $.getScript('https://apis.google.com/js/platform.js', function(data, textStatus, jqxh ) {
439 // When the auth2 library is loaded, log out so the user has to sign into google
440 gapi.load('auth2', function() {
441 gapi.auth2.init().then(function () {
442 signOut();
446 // Render the "Sign in with Google" button
447 renderButton();
448 }).fail(function (jqxhr, settings, exception) {
449 $('#google-signin-service-unreachable-alert').show();
451 </script>
452 <?php } ?>