From d429ddcbf5e72902112f19656cc7486a8debc114 Mon Sep 17 00:00:00 2001 From: Jerry Padgett Date: Tue, 4 Dec 2018 20:43:34 -0500 Subject: [PATCH] capabilities upgrade (#2007) - create separate fhir and oemr api route arrays - added context to dispatch i.e running clients in authenticated session - migrating Fhir Provider Client to REST - add method for non token acl check --- _rest_config.php | 22 ++++++++++++++++++--- _rest_routes.inc.php | 19 +++++++++++------- apis/dispatch.php | 34 +++++++++++++++++++++++++-------- rest_controllers/AuthRestController.php | 5 +++++ 4 files changed, 62 insertions(+), 18 deletions(-) diff --git a/_rest_config.php b/_rest_config.php index 72c414527..72e674f7f 100644 --- a/_rest_config.php +++ b/_rest_config.php @@ -9,7 +9,6 @@ * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 */ - // also a handy place to add utility methods // class RestConfig @@ -23,6 +22,9 @@ class RestConfig /** @var routemap is an array of patterns and routes */ public static $ROUTE_MAP; + /** @var fhir routemap is an array of patterns and routes */ + public static $FHIR_ROUTE_MAP; + /** @var app root is the root directory of the application */ public static $APP_ROOT; @@ -82,12 +84,26 @@ class RestConfig } /** - * Returns the context, used for storing session information - * @return Context + * Returns the api's context in form of token. e.g api called from OpenEMR authorized session. + * @return token or false if not local. */ function GetContext() { if ($this->context == null) { + $local_auth = isset($_SERVER['HTTP_APPSECRET']) ? $_SERVER['HTTP_APPSECRET'] : false; + if ($local_auth) { + session_id($local_auth); // a must for cURL. See Fhir Provider Client request. + } else { + session_name("OpenEMR"); // works for browser/ajax. + } + session_start(); + $app_token = isset($_SERVER['HTTP_APPTOKEN']) ? $_SERVER['HTTP_APPTOKEN'] : false; + $session_verified = ($app_token === $local_auth); // @todo future may force any http client to pass session id + if (isset($_SESSION['authUserID']) && !empty($_SESSION['authUser'])) { + $this->context = $_SESSION['csrf_token']; + } else { + session_destroy(); + } } return $this->context; diff --git a/_rest_routes.inc.php b/_rest_routes.inc.php index 1283b2d90..cf3d12c08 100644 --- a/_rest_routes.inc.php +++ b/_rest_routes.inc.php @@ -28,18 +28,12 @@ use OpenEMR\RestControllers\ONoteRestController; use OpenEMR\RestControllers\DocumentRestController; use OpenEMR\RestControllers\InsuranceRestController; use OpenEMR\RestControllers\MessageRestController; -use OpenEMR\RestControllers\FhirPatientRestController; -use OpenEMR\RestControllers\FhirEncounterRestController; RestConfig::$ROUTE_MAP = array( "POST /api/auth" => function () { $data = (array)(json_decode(file_get_contents("php://input"))); return (new AuthRestController())->authenticate($data); }, - "POST /fhir/auth" => function () { - $data = (array)(json_decode(file_get_contents("php://input"))); - return (new AuthRestController())->authenticate($data); - }, "GET /api/facility" => function () { authorization_check("admin", "users"); return (new FacilityRestController())->getAll(); @@ -323,7 +317,18 @@ RestConfig::$ROUTE_MAP = array( }, "DELETE /api/patient/:pid/message/:mid" => function ($pid, $mid) { authorization_check("patients", "notes"); - return (new MessageRestController())->delete($pid, $mid, $data); + return (new MessageRestController())->delete($pid, $mid); + }, + +); + +use OpenEMR\RestControllers\FhirPatientRestController; +use OpenEMR\RestControllers\FhirEncounterRestController; + +RestConfig::$FHIR_ROUTE_MAP = array( + "POST /fhir/auth" => function () { + $data = (array)(json_decode(file_get_contents("php://input"))); + return (new AuthRestController())->authenticate($data); }, "GET /fhir/Patient" => function () { authorization_check("patients", "demo"); diff --git a/apis/dispatch.php b/apis/dispatch.php index c54bb6da8..2bc9d9a79 100644 --- a/apis/dispatch.php +++ b/apis/dispatch.php @@ -15,9 +15,11 @@ require_once("./../_rest_config.php"); $gbl = RestConfig::GetInstance(); -$routes = $gbl::$ROUTE_MAP; +$context = $gbl->GetContext(); $base_path = $gbl::$ROOT_URL; +$routes = array(); $resource = ''; + // Parse needed information from Redirect or REQUEST_URI if (!empty($_REQUEST['_REWRITE_COMMAND'])) { $resource = "/" . $_REQUEST['_REWRITE_COMMAND']; @@ -33,14 +35,15 @@ if (!empty($_REQUEST['_REWRITE_COMMAND'])) { } } +$ignoreAuth = true; // Maintain site id for multi site compatibility. -// token is a 32 character hash followed by hex encoded site id. +// token is a 32 character hash followed by hex encoded 4 char api flag and site id. if (is_authentication($resource)) { // Get a site id from initial login authentication. $data = (array)(json_decode(file_get_contents("php://input"))); $site = empty($data['client_id']) ? "default" : $data['client_id']; $_GET['site'] = $site; -} else { +} elseif (!$context) { $token = get_bearer_token(); if (strlen($token) > 40) { $api_token = substr($token, 0, 32); @@ -55,9 +58,12 @@ if (is_authentication($resource)) { http_response_code(401); exit(); } +} else { + // continue already authorized session. + // let globals verify again. + $ignoreAuth = false; } -$ignoreAuth = true; require_once("./../interface/globals.php"); require_once("./../library/acl.inc"); @@ -66,11 +72,14 @@ if (!$GLOBALS['rest_api']) { exit(); } // api flag must be four chars +// Pass only routes for current api. // if (is_fhir_request($resource)) { $_SESSION['api'] = 'fhir'; + $routes = $gbl::$FHIR_ROUTE_MAP; } else { $_SESSION['api'] = 'oemr'; + $routes = $gbl::$ROUTE_MAP; } use OpenEMR\Common\Http\HttpRestRouteHandler; @@ -128,17 +137,26 @@ function authentication_check($resource) function authorization_check($section, $value) { - $authRestController = new AuthRestController(); - $result = $authRestController->aclCheck($_SERVER["HTTP_X_API_TOKEN"], $section, $value); + global $context; + $authRestController = new AuthRestController(); + if ($context) { + $result = $authRestController->aclCheckByUsername($_SESSION['authUser'], $section, $value); + } else { + $result = $authRestController->aclCheck($_SERVER["HTTP_X_API_TOKEN"], $section, $value); + } if (!$result) { http_response_code(401); exit(); } } -authentication_check($resource); +if (!$context) { + authentication_check($resource); +} // dispatch $routes called by ref. HttpRestRouteHandler::dispatch($routes, $resource, $_SERVER["REQUEST_METHOD"]); // Tear down session for security. -$gbl->destroySession(); +if (!$context) { + $gbl->destroySession(); +} diff --git a/rest_controllers/AuthRestController.php b/rest_controllers/AuthRestController.php index 5c97d9877..ccb28e29e 100644 --- a/rest_controllers/AuthRestController.php +++ b/rest_controllers/AuthRestController.php @@ -91,6 +91,11 @@ class AuthRestController return acl_check($section, $value, $username); } + public function aclCheckByUsername($username, $section, $value) + { + return acl_check($section, $value, $username); + } + public function optionallyAddMoreTokenTime($token) { $tokenResult = sqlQuery("SELECT user_id, token, expiry FROM api_token WHERE token=?", array($token)); -- 2.11.4.GIT