Skip to content

Commit

Permalink
fix: Support google single sign on mode for esign of encounters and f…
Browse files Browse the repository at this point in the history
…orms (openemr#7255) (openemr#7274)

* Even with google single sign on it still requires user to use password from openEMR while signing the encounter.
Google single sign on works perfectly with the login but when it comes to signing an encounter single sign on doesn't work. It requires openEMR user password.

* openemr#7255- Escaped some params for JavaScript context.

---------

Co-authored-by: GauravSontakke <[email protected]>
Co-authored-by: hKhatri <[email protected]>
  • Loading branch information
3 people committed Mar 18, 2024
1 parent 4e9f4c0 commit dc1e6ee
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 8 deletions.
8 changes: 8 additions & 0 deletions interface/patient_file/encounter/forms.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@
}
?>


<?php
// If google sign-in enable then add scripts.
if (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) {?>
<script src="https://accounts.google.com/gsi/client" async defer></script>
<script src="<?php echo $GLOBALS['web_root']?>/library/js/gSignIn.js"></script>
<?php } ?>

<script>
$(function () {
var formConfig = <?php echo $esignApi->formConfigToJson(); ?>;
Expand Down
31 changes: 29 additions & 2 deletions library/ESign/Encounter/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public function esign_form_view()
$form->action = '#';
$signable = new Encounter_Signable($form->encounterId);
$form->showLock = false;
$form->displayGoogleSignin = (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) ? true : false;
$form->googleSigninClientID = $GLOBALS['google_signin_client_id'];

if (
$signable->isLocked() === false &&
$GLOBALS['lock_esign_all'] &&
Expand Down Expand Up @@ -74,6 +77,17 @@ public function esign_form_submit()
$status = self::STATUS_FAILURE;
$password = $this->getRequest()->getParam('password', '');
$encounterId = $this->getRequest()->getParam('encounterId', '');

// If google sign-in enable
$usedGoogleSignin = $this->getRequest()->getParam('used_google_signin', '');
$googleSigninToken = $this->getRequest()->getParam('google_signin_token', '');
$force_google = (
!empty($GLOBALS['google_signin_enabled']) &&
!empty($GLOBALS['google_signin_client_id']) &&
!empty($usedGoogleSignin) &&
!empty($googleSigninToken)
) ? 1 : 0;

// Lock if 'Lock e-signed encounters and their forms' option is set,
// unless esign_lock_toggle option is enable in globals, then check the request param
$lock = false;
Expand All @@ -85,7 +99,20 @@ public function esign_form_submit()
}

$amendment = $this->getRequest()->getParam('amendment', '');
if ((new AuthUtils())->confirmPassword($_SESSION['authUser'], $password)) {

// If google sign-in enable then valid google sign-in
if ($force_google === 1) {
$valid = false;
$uPayload = AuthUtils::verifyGoogleSignIn($googleSigninToken, false);
if (!empty($uPayload) && isset($uPayload['id']) && $uPayload['id'] == $_SESSION['authUserID']) {
$valid = true;
}
$gMessage = xlt("Invalid google log in");
} else {
$valid = (new AuthUtils())->confirmPassword($_SESSION['authUser'], $password);
}

if ($valid) {
$signable = new Encounter_Signable($encounterId);
if ($signable->sign($_SESSION['authUserID'], $lock, $amendment)) {
$message = xlt("Form signed successfully");
Expand All @@ -94,7 +121,7 @@ public function esign_form_submit()
$message = xlt("An error occured signing the form");
}
} else {
$message = xlt("The password you entered is invalid");
$message = (isset($gMessage) && !empty($gMessage)) ? $gMessage : xlt("The password you entered is invalid");
}

$response = new Response($status, $message);
Expand Down
27 changes: 25 additions & 2 deletions library/ESign/Form/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public function esign_form_view()
$form->action = '#';
$signable = new Form_Signable($form->formId, $form->formDir, $form->encounterId);
$form->showLock = false;
$form->displayGoogleSignin = (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) ? true : false;
$form->googleSigninClientID = $GLOBALS['google_signin_client_id'];
if (
$signable->isLocked() === false &&
$GLOBALS['lock_esign_individual'] &&
Expand Down Expand Up @@ -77,6 +79,17 @@ public function esign_form_submit()
$formId = $this->getRequest()->getParam('formId', '');
$formDir = $this->getRequest()->getParam('formDir', '');
$encounterId = $this->getRequest()->getParam('encounterId', '');

// If google sign-in enable
$usedGoogleSignin = $this->getRequest()->getParam('used_google_signin', '');
$googleSigninToken = $this->getRequest()->getParam('google_signin_token', '');
$force_google = (
!empty($GLOBALS['google_signin_enabled']) &&
!empty($GLOBALS['google_signin_client_id']) &&
!empty($usedGoogleSignin) &&
!empty($googleSigninToken)
) ? 1 : 0;

// Always lock, unless esign_lock_toggle option is enable in globals
$lock = true;
if ($GLOBALS['esign_lock_toggle']) {
Expand All @@ -85,7 +98,17 @@ public function esign_form_submit()

$amendment = $this->getRequest()->getParam('amendment', '');

$valid = (new AuthUtils())->confirmPassword($_SESSION['authUser'], $password);
// If google sign-in enable then valid google sign-in
if ($force_google === 1) {
$valid = false;
$uPayload = AuthUtils::verifyGoogleSignIn($googleSigninToken, false);
if (!empty($uPayload) && isset($uPayload['id']) && $uPayload['id'] == $_SESSION['authUserID']) {
$valid = true;
}
$gMessage = xlt("Invalid google log in");
} else {
$valid = (new AuthUtils())->confirmPassword($_SESSION['authUser'], $password);
}

if ($valid) {
$factory = new Form_Factory($formId, $formDir, $encounterId);
Expand All @@ -97,7 +120,7 @@ public function esign_form_submit()
$message = xlt("An error occured signing the form");
}
} else {
$message = xlt("The password you entered is invalid");
$message = (isset($gMessage) && !empty($gMessage)) ? $gMessage : xlt("The password you entered is invalid");
}

$response = new Response($status, $message);
Expand Down
37 changes: 35 additions & 2 deletions library/ESign/views/encounter/esign_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
<span id='esign-signature-form-prompt'><?php echo xlt("Your password is your signature"); ?></span>
</div>

<div class="esign-signature-form-element">
<div class="esign-signature-form-element gs-hide-element">
<label for='password'><?php echo xlt('Password');?></label>
<input type='password' id='password' name='password' size='10' />
</div>

<div class="esign-signature-form-element">
<div class="esign-signature-form-element gs-hide-element">
<span id='esign-signature-form-prompt'><?php echo xlt("Checking the lock checkbox will prevent any futher edits on any forms in this encounter."); ?></span>
</div>

Expand All @@ -49,6 +49,26 @@
<div class="esign-signature-form-element">
<textarea name='amendment' id='amendment' placeholder='<?php echo xla("Enter an amendment..."); ?>'></textarea>
</div>

<!-- Google sign in for esign -->
<?php if ($this->form->displayGoogleSignin) { ?>
<div class="mb-3 mt-2">
<div class="g_id_signin" data-type="standard" ></div>
<div>
<input type="hidden" id="used-google-signin" name="used_google_signin" value="">
<input type="hidden" id="google-signin-token" name="google_signin_token" value="">
<div id="google-signin" onclick="return gsi.do_google_signin();">
<!-- This message is displayed if the google platform API cannot render the button -->
<span id="google-signin-service-unreachable-alert" style="display:none;">
<?php echo xlt('Google Sign-In is enabled but the service is unreachable.');?>
</span>
</div>
<div id="google-signout">
<a href="#" onclick="gsi.signOut();"><?php echo xlt('Sign out');?></a>
</div>
</div>
</div>
<?php } ?>

<div class="esign-signature-form-element">
<input type='submit' class="btn btn-secondary btn-sm" value='<?php echo xla('Back'); ?>' id='esign-back-button' />
Expand All @@ -61,3 +81,16 @@

</form>
</div>

<!-- Google sign in for esign -->
<?php if ($this->form->displayGoogleSignin) { ?>
<script type="text/javascript">
let gsi = Object.create(GoogleSigin);
gsi.init(<?php echo js_escape($this->form->googleSigninClientID); ?>, {
ele : '#esign-form-container',
signin_btn : '#esign-sign-button-encounter',
error_container : '#esign-signature-form'
});
</script>
<?php } ?>
<!-- End -->
37 changes: 35 additions & 2 deletions library/ESign/views/form/esign_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
<div id='esign-form-container'>
<form id='esign-signature-form' method='post' action='<?php echo attr($this->form->action); ?>'>

<div class="esign-signature-form-element">
<div class="esign-signature-form-element gs-hide-element">
<span id='esign-signature-form-prompt'><?php echo xlt("Your password is your signature"); ?></span>
</div>

<div class="esign-signature-form-element form-group">
<div class="esign-signature-form-element form-group gs-hide-element">
<label for='password'><?php echo xlt('Password'); ?></label>
<input type='password' class="form-control" id='password' name='password' size='10' placeholder="<?php echo xla("Enter your password to sign the form"); ?>" />
</div>
Expand All @@ -46,6 +46,26 @@
<label for='amendment'><?php echo xlt("Amendment"); ?></label>
<textarea class="form-control" name='amendment' id='amendment' placeholder='<?php echo xla("Enter an amendment..."); ?>'></textarea>
</div>

<!-- Google sign in for esign -->
<?php if ($this->form->displayGoogleSignin) { ?>
<div class="mb-3 mt-2">
<div class="g_id_signin" data-type="standard" ></div>
<div>
<input type="hidden" id="used-google-signin" name="used_google_signin" value="">
<input type="hidden" id="google-signin-token" name="google_signin_token" value="">
<div id="google-signin" onclick="return gsi.do_google_signin();">
<!-- This message is displayed if the google platform API cannot render the button -->
<span id="google-signin-service-unreachable-alert" style="display:none;">
<?php echo xlt('Google Sign-In is enabled but the service is unreachable.');?>
</span>
</div>
<div id="google-signout">
<a href="#" onclick="gsi.signOut();"><?php echo xlt('Sign out');?></a>
</div>
</div>
</div>
<?php } ?>

<div class="esign-signature-form-element">
<input type='submit' class="btn btn-secondary btn-sm" value='<?php echo xla('Back'); ?>' id='esign-back-button' />
Expand All @@ -60,3 +80,16 @@

</form>
</div>

<!-- Google sign in for esign -->
<?php if ($this->form->displayGoogleSignin) { ?>
<script type="text/javascript">
let gsi = Object.create(GoogleSigin);
gsi.init(<?php echo js_escape($this->form->googleSigninClientID); ?>, {
ele : '#esign-form-container',
signin_btn : '#esign-sign-button-form',
error_container : '#esign-signature-form'
});
</script>
<?php } ?>
<!-- End -->
76 changes: 76 additions & 0 deletions library/js/gSignIn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
var GoogleSigin = {
client_id: '',
google_signin : false,
ele: null,
hide_element : '.gs-hide-element',
signin_btn : '.form-google-sign-button',
error_container: null,
init: function(client_id, params = {}) {
this.client_id = client_id;
this.ele = Object.prototype.hasOwnProperty.call(params, 'ele') ? $(params['ele']) : null;
this.hide_element = Object.prototype.hasOwnProperty.call(params, 'hide_element') ? params['hide_element'] : this.hide_element;
this.signin_btn = Object.prototype.hasOwnProperty.call(params, 'signin_btn') ? params['signin_btn'] : this.signin_btn;
this.error_container = Object.prototype.hasOwnProperty.call(params, 'error_container') ? params['error_container'] : this.error_container;

$(this.ele).find('#google-signout').hide();

google.accounts.id.initialize({
client_id: this.client_id,
callback: (googleUser) => { this.onSignInSuccess(googleUser, this) }
});

this.renderButton();
},
renderButton: function() {
google.accounts.id.renderButton(
$(this.ele).find("#google-signin")[0],
{
'theme': 'outline',
'prompt': 'select_account',
'scope': 'profile email',
'onsuccess': (googleUser) => { this.onSignInSuccess(googleUser, this) },
'onfailure': (error) => { this.onSignInFailure(error, this) }
} // customization attributes
);
},
onSignInSuccess: function(googleUser, thisele) {

const id_token = googleUser.credential;

if(thisele.error_container != "") {
$(thisele.error_container).find("#form-error-container").remove();
}

$(thisele.ele).find('#used-google-signin').val(true);
$(thisele.ele).find('#google-signin-token').val(id_token);
$(thisele.ele).find('#google-signout').show();
$(thisele.ele).find(this.hide_element).hide();

var element = thisele.ele[0].querySelector(thisele.signin_btn);

element.click();
element.disabled = true;

},
onSignInFailure: function(error, thisele) {
if(thisele.error_container != "") {
$(thisele.error_container).find("#form-error-container").remove();
$(thisele.error_container).append("<div id='form-error-container' class='error'>Please use google log in</div>");
}


},
do_google_signin: function() {
this.google_signin = true;
},
signOut: function() {
this.google_signin = false;
const auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
$(this.ele).find('#used-google-signin').val('');
$(this.ele).find('#google-signin-token').val('');
$(this.ele).find('#google-signout').hide();
$(this.ele).find(this.hide_element).show();
});
}
};

0 comments on commit dc1e6ee

Please sign in to comment.