Fully responsive globals.php with vertical menu (#2460)
[openemr.git] / interface / usergroup / mfa_totp.php
blob229dc7ff72c599fcbb6a764feb6d8857864602bb
1 <?php
2 /**
3 * App Based TOTP Support
5 * @package OpenEMR
6 * @link http://www.open-emr.org
7 * @author Anthony Zullo <anthonykzullo@gmail.com>
8 * @author Rod Roark <rod@sunsetsystems.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @copyright Copyright (c) 2019 Anthony Zullo <anthonykzullo@gmail.com>
11 * @copyright Copyright (c) 2018 Rod Roark <rod@sunsetsystems.com>
12 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
13 * @license https://github.com/openemr/openemr/blob/master/LICENSE CNU General Public License 3
17 require_once('../globals.php');
18 require_once("$srcdir/classes/Totp.class.php");
19 require_once("$srcdir/options.inc.php");
21 use OpenEMR\Common\Crypto\CryptoGen;
22 use OpenEMR\Core\Header;
23 use OpenEMR\OeUI\OemrUI;
25 $userid = $_SESSION['authId'];
26 $action = $_REQUEST['action'];
27 $user_name = getUserIDInfo($userid);
28 $user_full_name = $user_name['fname'] . " " . $user_name['lname'];
31 <html>
32 <head>
33 <?php Header::setupHeader(); ?>
34 <title><?php echo xlt('TOTP Registration'); ?></title>
35 <script>
37 function doregister(step, error) {
38 var f = document.forms[0];
39 f.action.value = step;
40 if (error) {
41 f.error.value = error;
43 f.action.value = step;
44 top.restoreSession();
45 f.submit();
48 function docancel() {
49 var redirectUrl = 'mfa_registrations.php';
50 window.location.href = 'mfa_registrations.php';
53 $(function() {
54 $('#clearPass').focus();
55 });
56 </script>
57 <style>
58 p {
59 text-align: center
61 .alert-msg {
62 font-size:100%;
63 font-weight:700;
65 </style>
66 <?php
67 $arrOeUiSettings = array(
68 'heading_title' => xl('Register Time Based One Time Password Key') . " - " . xl('TOTP'),
69 'include_patient_name' => false,
70 'expandable' => false,
71 'expandable_files' => array(),//all file names need suffix _xpd
72 'action' => "",//conceal, reveal, search, reset, link or back
73 'action_title' => "",
74 'action_href' => "",//only for actions - reset, link or back
75 'show_help_icon' => false,
76 'help_file_name' => ""
78 $oemr_ui = new OemrUI($arrOeUiSettings);
80 </head>
81 <body class="body_top">
82 <div id="container_div" class="<?php echo $oemr_ui->oeContainer();?>">
83 <?php
84 // If current step is reg1 or reg2, display the header
85 if ($action == 'reg1' || $action == 'reg2') { ?>
86 <div id="container_div" class="<?php echo $oemr_ui->oeContainer();?>">
87 <div class="row">
88 <div class="col-sm-12">
89 <div class="page-header">
90 <?php echo $oemr_ui->pageHeading() . "\r\n"; ?>
91 </div>
92 </div>
93 </div>
94 <?php
95 } ?> <div class="row">
96 <div class="col-sm-12">
97 <form method='post' class="form-horizontal" action='mfa_totp.php' onsubmit='return top.restoreSession()'>
98 <input type="hidden" name="csrf_token_form" value="<?php echo attr(collectCsrfToken()); ?>" />
103 <?php
104 // step 1 is to verify the password
105 if ($action == 'reg1') {
106 $error = (isset($_GET["error"])) ? $_GET["error"] : false;
108 <div>
109 <fieldset>
110 <legend><?php echo xlt('Provide Password for') . " " . $user_full_name; ?></legend>
111 <div class="row">
112 <div class="col-sm-12">
113 <?php if ($error == "auth") { ?>
114 <div class="alert alert-danger alert-msg login-failure m-1">
115 <?php echo xlt('Invalid password'); ?>
116 </div>
117 <?php } ?>
118 <p><?php echo xlt('In order to register your device, please provide your OpenEMR login password'); ?></p>
119 <div class="col-sm-4 col-sm-offset-4">
120 <input type="password" class="form-control" id="clearPass" name="clearPass" placeholder="<?php echo xla('Password'); ?>:" >
121 </div>
122 </div>
123 </div>
124 </fieldset>
125 <div class="form-group clearfix">
126 <div class="col-sm-12 text-left position-override">
127 <button type="button" class="btn btn-default btn-save" value="<?php echo xla('Submit'); ?>" onclick="doregister('reg2')"><?php echo xlt('Submit'); ?></button>
128 <button type="button" class="btn btn-link btn-cancel btn-separate-left" value="<?php echo xla('Cancel'); ?>" onclick="docancel()" ><?php echo xlt('Cancel'); ?></button>
129 </div>
130 </div>
131 </div>
132 <?php
133 // step 2 is to validate password and display qr code
134 } elseif ($action == 'reg2') {
135 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
136 csrfNotVerified();
139 // Redirect back to step 1 if user password is incorrect
140 if (!confirm_user_password($_SESSION['authUser'], $_POST['clearPass'])) {
141 header("Location: mfa_totp.php?action=reg1&error=auth");
142 exit();
145 // Determines whether existing TOTP method exists already
146 $existingSecret = privQuery(
147 "SELECT var1 FROM login_mfa_registrations WHERE " .
148 "`user_id` = ? AND `method` = 'TOTP'",
149 array($userid)
151 if (empty($existingSecret['var1'])) {
152 $secret = false;
153 $doesExist = false;
154 } else {
155 $cryptoGen = new CryptoGen();
156 $secret = $cryptoGen->decryptStandard($existingSecret['var1']);
157 $doesExist = true;
160 // Generate a new QR code or existing QR code
161 $googleAuth = new Totp($secret, $_SESSION['authUser']);
162 $qr = $googleAuth->generateQrCode();
165 // if secret did not exist previously, stores secret in session variable for saving
166 if (!$doesExist) {
167 $_SESSION['totpSecret'] = $googleAuth->getSecret();
170 <fieldset>
171 <legend><?php echo xlt('Register TOTP Key for') . " " . $user_full_name; ?></legend>
172 <div class="row">
173 <div class="col-sm-12">
174 <?php if (!$doesExist) { ?>
176 <?php echo xlt('Scan the following QR code with your preferred authenticator app to register a new TOTP key.'); ?>
177 </p>
178 <?php } else { // $doesExist ?>
180 <?php echo xlt('Your current TOTP key QR code is displayed below.'); ?>
181 </p>
182 <?php } ?>
183 <br>
184 <img src="<?php echo attr($qr); ?>" class="img-responsive center-block" style="height:200px !Important"/>
185 <br>
186 <p><?php echo xlt('Example authenticator apps include:'); ?></p>
187 <div class="col-sm-4 col-sm-offset-4">
188 <ul>
189 <li><?php echo xlt('Google Auth'); ?>
190 (<a href="https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8" target="_blank" rel="noopener">
191 <?php echo xlt('ios'); ?>
192 </a>,
193 <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en" target="_blank" rel="noopener">
194 <?php echo xlt('android'); ?>
195 </a>)</li>
196 <li><?php echo xlt('Authy'); ?>
197 (<a href="https://itunes.apple.com/us/app/authy/id494168017?mt=8" target="_blank" rel="noopener"><?php echo xlt('ios'); ?></a>, <a href="https://play.google.com/store/apps/details?id=com.authy.authy&hl=en" target="_blank" rel="noopener"><?php echo xlt('android'); ?></a>)</li>
198 </ul>
199 </div>
200 </div>
201 </div>
202 </fieldset>
203 <div class="form-group clearfix">
204 <div class="col-sm-12 text-left position-override">
205 <?php if (!$doesExist) { ?>
206 <button type="button" class="btn btn-default btn-save" value="<?php echo xla('Register'); ?>" onclick="doregister('reg3')"><?php echo xlt('Register'); ?></button>
207 <button type="button" class="btn btn-link btn-cancel btn-separate-left" value="<?php echo xla('Cancel'); ?>" onclick="docancel()" ><?php echo xlt('Cancel'); ?></button>
208 <?php } else { // $doesExist ?>
209 <button type="button" class="btn btn-link btn-back btn-separate-left" value="<?php echo xla('Back'); ?>" onclick="docancel()" ><?php echo xlt('Back'); ?></button>
210 <?php } ?>
211 </div>
212 </div>
213 </div>
214 <?php
215 // step 3 is to save the qr code
216 } elseif ($action == 'reg3') {
217 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
218 csrfNotVerified();
221 echo "<script>\n";
223 // Verify that no TOTP method exists already
224 $row = privQuery(
225 "SELECT COUNT(*) AS count FROM login_mfa_registrations WHERE " .
226 "`user_id` = ? AND `method` = 'TOTP'",
227 array($userid)
231 if (empty($row['count']) && isset($_SESSION['totpSecret'])) {
232 $cryptoGen = new CryptoGen();
233 privStatement(
234 "INSERT INTO login_mfa_registrations " .
235 "(`user_id`, `method`, `name`, `var1`, `var2`) VALUES " .
236 "(?, 'TOTP', 'App Based 2FA', ?, '')",
237 array($userid, $cryptoGen->encryptStandard($_SESSION['totpSecret']))
239 unset($_SESSION['totpSecret']);
240 } else {
241 echo " alert(" . xlj('TOTP Method already exists and is enabled. Try again.') . ");\n";
244 echo "window.location.href = 'mfa_registrations.php';\n";
245 echo "</script>\n";
249 <input type='hidden' name='action' value='' />
250 <input type='hidden' name='error' value='' />
251 </form>
252 </div>
253 </div>
254 </div><!--end of container div -->
255 <?php $oemr_ui->oeBelowContainerDiv();?>
256 </body>
257 </html>