feat: #6525 Use EHR authorization for SMART Apps (#6628)
commitf3ebdb02e14aee2c5fd54656064a9d399635f813
authorStephen Nielson <snielson@discoverandchange.com>
Tue, 15 Aug 2023 14:02:03 +0000 (15 10:02 -0400)
committerGitHub <noreply@github.com>
Tue, 15 Aug 2023 14:02:03 +0000 (15 10:02 -0400)
tree75555507862c6a94b36e2ffcdc0f0417bcdd5585
parent6aad5dfded2e82c0659a407322af1b279ffafa4a
feat: #6525 Use EHR authorization for SMART Apps (#6628)

* #6525 Use EHR authorization for SMART Apps

First stab at #6525 by allowing the EHR to launch a smart app and reuse the
authorization context that the currently logged in user has.

I introduce a global that by default is off to allow OpenEMR
administrators to enable smart apps to skip the authorization screen
when the smart app is launched inside the EHR.

I refactored the launch sequence now to be an on-demand generation of
the launch token using javascript instead of generating the token and
stuffing it into the html.

I added a flag on the individual client app to turn on or off the
authorization skip flag.  This gives admins control over allowing apps
to launch immediately inside the EHR without requiring an authorization
/ authentication step.

I expanded the size of the SMART app window so that the app can take up
more of the window and offer more functionality.  I'm wondering if we
should offer different size options based upon the registered intent, or
if there is some mechanism the app can communicate of how much real
estate it wants to take up.

The app will receive any permissions it requests that was originally
granted in its registration request.  The flow will continue to discard
permissions that were not granted in the original registration request
or were reduced in a subset of the refresh token.

Added to the launch token the currently authenticated user and the type
of user.  Right now the ehr-launch is only inside the provider side of
things, but I put in infrastructure so we can later extend it to launch
inside the patient portal.

I originally relied on opening up the OpenEMR session cookie, but this
doesn't work if the SMART app is hosted on a domain other than the
domain OpenEMR is running under.  Browsers will drop the cookies on the
browser redirect as its not considered a first-party origin so we have
to rely on the launch token being the authority for the authentication /
authorization.

I'm thinking that for more security in order to prevent replay attacks
we need to store the generated launch token in the database, time
expire it, and make it a one time use token.  If a repeat is detected
we should invalidate all of the current user's access tokens and do
some kind of notification to the administrator. I'm not sure yet if this
is warranted, but it seems like we should treat this as serious as what
we do with the refresh token.

* In-EHR launch use session cookies instead of token

By switching to a javascript submitted form on the authorize page to
establish a first party context I was able to retrieve the session
cookies and verify the user is logged in, even inside of a third party
dialog.

If for some reason the third party cookie doesn't exist it brings up the
standard login form.

The downside of this approach is a bit slower processing as an
additional round trip to the client has to happen to submit the first
party form.  Also, switching between the openemr session an oauth2
session has to deal with brief session locking and filesystem access if
that is how the php sessions are configured.

Overall though this eliminates the security loophole of someone
grabbing the launch token via js or some other mechanism and logging in
as a user just using the launch token.  Now we can tie it to the
specific logged in session and close down that security issue.

* Style fixes.

* Add in missing sql column.

* Fix kernel mispelling

Fix the kernel mispelling the authorization controller.

* Removing user uuid, added main intent tab

Somehow the rebase removed the user uuid stuff that was part of the
original wip.

Added a main intent tab for launching smart apps in one of the OpenEMR
tab.

Added a few more debug logs.
16 files changed:
interface/patient_file/summary/demographics.php
interface/smart/ehr-launch-client.php
library/globals.inc.php
library/js/utility.js
oauth2/smart/ehr-launch-autosubmit.html.twig [new file with mode: 0644]
sql/7_0_1-to-7_0_2_upgrade.sql
sql/database.sql
src/Common/Auth/OpenIDConnect/Entities/ClientEntity.php
src/Common/Auth/OpenIDConnect/Repositories/ClientRepository.php
src/Common/Auth/OpenIDConnect/SMARTSessionTokenContextBuilder.php
src/Common/Session/SessionUtil.php
src/FHIR/SMART/ClientAdminController.php
src/FHIR/SMART/SMARTLaunchToken.php
src/FHIR/SMART/SmartLaunchController.php
src/RestControllers/AuthorizationController.php
src/RestControllers/SMART/SMARTAuthorizationController.php