You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
13 KiB
362 lines
13 KiB
2 years ago
|
<?php
|
||
|
|
||
|
/**
|
||
|
* This file contains functions that service ajax requests for
|
||
|
* ACL(php-gacl) administration within OpenEMR. All returns are
|
||
|
* done via xml.
|
||
|
*
|
||
|
* Important - Ensure that display_errors=Off in php.ini settings.
|
||
|
*
|
||
|
* @package OpenEMR
|
||
|
* @link https://www.open-emr.org
|
||
|
* @author Brady Miller <brady.g.miller@gmail.com>
|
||
|
* @author Rod Roark <rod@sunsetsystems.com>
|
||
|
* @copyright Copyright (c) 2007-2018 Brady Miller <brady.g.miller@gmail.com>
|
||
|
* @copyright Copyright (c) 2021 Rod Roark <rod@sunsetsystems.com>
|
||
|
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
|
||
|
*/
|
||
|
|
||
|
require_once("../../interface/globals.php");
|
||
|
require_once("$srcdir/user.inc");
|
||
|
|
||
|
use OpenEMR\Common\Acl\AclExtended;
|
||
|
use OpenEMR\Common\Acl\AclMain;
|
||
|
use OpenEMR\Common\Csrf\CsrfUtils;
|
||
|
use OpenEMR\Common\Logging\EventAuditLogger;
|
||
|
use OpenEMR\Services\UserService;
|
||
|
|
||
|
|
||
|
header("Content-type: text/xml");
|
||
|
header("Cache-Control: no-cache");
|
||
|
|
||
|
//initiate error array
|
||
|
$error = array();
|
||
|
|
||
|
//verify csrf
|
||
|
if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
|
||
|
echo error_xml(xl('Authentication Error'));
|
||
|
CsrfUtils::csrfNotVerified(false);
|
||
|
}
|
||
|
|
||
|
//ensure user has proper access
|
||
|
if (!AclMain::aclCheckCore('admin', 'acl')) {
|
||
|
echo error_xml(xl('ACL Administration Not Authorized'));
|
||
|
CsrfUtils::csrfNotVerified(false);
|
||
|
}
|
||
|
|
||
|
//Display red alert if Emergency Login ACL is activated for a user.
|
||
|
if ($_POST["action"] == "add") {
|
||
|
if (!empty($_POST["selection"]) && is_array($_POST["selection"]) && in_array("Emergency Login", $_POST["selection"])) {
|
||
|
array_push($error, (xl('Emergency Login ACL is chosen. The user is still in active state, please de-activate the user and activate the same when required during emergency situations. Visit Administration->Users for activation or de-activation.') ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//PROCESS USERNAME REQUESTS
|
||
|
if ($_POST["control"] == "username") {
|
||
|
if ($_POST["action"] == "list") {
|
||
|
//return username list with alert if user is not joined to group
|
||
|
echo username_listings_xml($error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//PROCESS MEMBERSHIP REQUESTS
|
||
|
if ($_POST["control"] == "membership") {
|
||
|
if ($_POST["action"] == "list") {
|
||
|
//return membership data
|
||
|
echo user_group_listings_xml($_POST["name"], $error);
|
||
|
}
|
||
|
|
||
|
if ($_POST["action"] == "add") {
|
||
|
if ($_POST["selection"][0] == "null") {
|
||
|
//no selection, return soft error, and just return membership data
|
||
|
array_push($error, (xl('No group was selected') . "!"));
|
||
|
echo user_group_listings_xml($_POST["name"], $error);
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
//add the group, then log it, then return updated membership data
|
||
|
AclExtended::addUserAros($_POST["name"], $_POST["selection"]);
|
||
|
EventAuditLogger::instance()->newEvent("security-administration-update", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "Added " . $_POST["name"] . " to following access group(s): " . implode(', ', $_POST["selection"]));
|
||
|
echo user_group_listings_xml($_POST["name"], $error);
|
||
|
}
|
||
|
|
||
|
if ($_POST["action"] == "remove") {
|
||
|
if ($_POST["selection"][0] == "null") {
|
||
|
//no selection, return soft error, and just return membership data
|
||
|
array_push($error, (xl('No group was selected') . "!"));
|
||
|
echo user_group_listings_xml($_POST["name"], $error);
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
// check if user is protected. If so, then state message unable to remove from admin group.
|
||
|
$userNametoID = (new UserService())->getIdByUsername($_POST["name"]);
|
||
|
if (checkUserSetting("gacl_protect", "1", $userNametoID) || ($_POST["name"] == "admin")) {
|
||
|
$gacl_protect = true;
|
||
|
} else {
|
||
|
$gacl_protect = false;
|
||
|
}
|
||
|
|
||
|
if ($gacl_protect && in_array("Administrators", $_POST["selection"])) {
|
||
|
//unable to remove admin user from administrators group, process remove,
|
||
|
// send soft error, then return data
|
||
|
array_push($error, (xl('Not allowed to remove this user from the Administrators group') . "!"));
|
||
|
AclExtended::removeUserAros($_POST["name"], $_POST["selection"]);
|
||
|
echo user_group_listings_xml($_POST["name"], $error);
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
//remove the group(s), then log it, then return updated membership data
|
||
|
AclExtended::removeUserAros($_POST["name"], $_POST["selection"]);
|
||
|
EventAuditLogger::instance()->newEvent("security-administration-update", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "Removed " . $_POST["name"] . " from following access group(s): " . implode(', ', $_POST["selection"]));
|
||
|
echo user_group_listings_xml($_POST["name"], $error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//PROCESS ACL REQUESTS
|
||
|
if ($_POST["control"] == "acl") {
|
||
|
if ($_POST["action"] == "list") {
|
||
|
//return acl titles with return values
|
||
|
echo AclExtended::aclListingsXml($error);
|
||
|
}
|
||
|
|
||
|
if ($_POST["action"] == "add") {
|
||
|
//validate form data
|
||
|
$form_error = false;
|
||
|
if (empty($_POST["title"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("title_" . xl('Need to enter title') . "!"));
|
||
|
} elseif (!ctype_alpha(str_replace(' ', '', $_POST["title"]))) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("title_" . xl('Please only use alphabetic characters') . "!"));
|
||
|
} elseif (AclExtended::aclExist($_POST["title"], false, $_POST["return_value"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("title_" . xl('Already used, choose another title') . "!"));
|
||
|
}
|
||
|
|
||
|
if (empty($_POST["identifier"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("identifier_" . xl('Need to enter identifier') . "!"));
|
||
|
} elseif (!ctype_alpha($_POST["identifier"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("identifier_" . xl('Please only use alphabetic characters with no spaces') . "!"));
|
||
|
} elseif (AclExtended::aclExist(false, $_POST["identifier"], $_POST["return_value"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("identifier_" . xl('Already used, choose another identifier') . "!"));
|
||
|
}
|
||
|
|
||
|
if (empty($_POST["return_value"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("return_" . xl('Need to enter a Return Value') . "!"));
|
||
|
}
|
||
|
|
||
|
if (empty($_POST["description"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("description_" . xl('Need to enter a description') . "!"));
|
||
|
} elseif (!ctype_alpha(str_replace(' ', '', $_POST["description"]))) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("description_" . xl('Please only use alphabetic characters') . "!"));
|
||
|
}
|
||
|
|
||
|
//process if data is valid
|
||
|
if (!$form_error) {
|
||
|
AclExtended::aclAdd($_POST["title"], $_POST["identifier"], $_POST["return_value"], $_POST["description"]);
|
||
|
echo "<?xml version=\"1.0\"?>\n" .
|
||
|
"<response>\n" .
|
||
|
"\t<success>SUCCESS</success>\n" .
|
||
|
"</response>\n";
|
||
|
} else { //$form_error = true, so return errors
|
||
|
echo error_xml($error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($_POST["action"] == "remove") {
|
||
|
//validate form data
|
||
|
$form_error = false;
|
||
|
if (empty($_POST["title"])) {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("aclTitle_" . xl('Need to enter title') . "!"));
|
||
|
}
|
||
|
|
||
|
if ($_POST["title"] == "Administrators") {
|
||
|
$form_error = true;
|
||
|
array_push($error, ("aclTitle_" . xl('Not allowed to delete the Administrators group') . "!"));
|
||
|
}
|
||
|
|
||
|
//process if data is valid
|
||
|
if (!$form_error) {
|
||
|
AclExtended::aclRemove($_POST["title"], $_POST["return_value"]);
|
||
|
echo "<?xml version=\"1.0\"?>\n" .
|
||
|
"<response>\n" .
|
||
|
"\t<success>SUCCESS</success>\n" .
|
||
|
"</response>\n";
|
||
|
} else { //$form_error = true, so return errors
|
||
|
echo error_xml($error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($_POST["action"] == "returns") {
|
||
|
//simply return all the possible acl return_values
|
||
|
echo AclExtended::returnValuesXml($error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//PROCESS ACO REQUESTS
|
||
|
if ($_POST["control"] == "aco") {
|
||
|
if ($_POST["action"] == "list") {
|
||
|
//send acl data
|
||
|
echo AclExtended::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
|
||
|
}
|
||
|
|
||
|
if ($_POST["action"] == "add") {
|
||
|
if ($_POST["selection"][0] == "null") {
|
||
|
//no selection, return soft error, and just return data
|
||
|
array_push($error, (xl('Nothing was selected') . "!"));
|
||
|
echo AclExtended::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
//add the aco, then return updated membership data
|
||
|
AclExtended::aclAddAcos($_POST["name"], $_POST["return_value"], $_POST["selection"]);
|
||
|
echo AclExtended::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
|
||
|
}
|
||
|
|
||
|
if ($_POST["action"] == "remove") {
|
||
|
if ($_POST["selection"][0] == "null") {
|
||
|
//no selection, return soft error, and just return data
|
||
|
array_push($error, (xl('Nothing was selected') . "!"));
|
||
|
echo AclExtended::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
if ($_POST["name"] == "Administrators") {
|
||
|
//will not allow removal of acos from Administrators ACL
|
||
|
array_push($error, (xl('Not allowed to inactivate anything from the Administrators ACL') . "!"));
|
||
|
echo AclExtended::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
//remove the acos, then return updated data
|
||
|
AclExtended::aclRemoveAcos($_POST["name"], $_POST["return_value"], $_POST["selection"]);
|
||
|
echo AclExtended::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Returns username listings via xml message.
|
||
|
// It will also include alert if user is not joined
|
||
|
// to a group yet
|
||
|
// $err = error strings (array)
|
||
|
//
|
||
|
function username_listings_xml($err)
|
||
|
{
|
||
|
$message = "<?xml version=\"1.0\"?>\n" .
|
||
|
"<response>\n";
|
||
|
$res = sqlStatement("select * from users where username != '' and active = 1 order by username");
|
||
|
for ($iter = 0; $row = sqlFetchArray($res); $iter++) {
|
||
|
$result4[$iter] = $row;
|
||
|
}
|
||
|
|
||
|
foreach ($result4 as $iter) {
|
||
|
// Skip this user if logged-in user does not have all of its permissions.
|
||
|
// Note that a superuser now has all permissions.
|
||
|
if (!AclExtended::iHavePermissionsOf($iter['username'])) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$message .= "\t<user>\n" .
|
||
|
"\t\t<username>" . $iter["username"] . "</username>\n";
|
||
|
$username_acl_groups = AclExtended::aclGetGroupTitles($iter["username"]);
|
||
|
if (!$username_acl_groups) {
|
||
|
//not joined to any group, so send alert
|
||
|
$message .= "\t\t<alert>no membership</alert>\n";
|
||
|
}
|
||
|
|
||
|
$message .= "\t</user>\n";
|
||
|
}
|
||
|
|
||
|
if (isset($err)) {
|
||
|
foreach ($err as $value) {
|
||
|
$message .= "\t<error>" . $value . "</error>\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$message .= "</response>\n";
|
||
|
return $message;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Returns user group listings(active and inactive lists)
|
||
|
// via xml message.
|
||
|
// $username = username
|
||
|
// $err = error strings (array)
|
||
|
//
|
||
|
function user_group_listings_xml($username, $err)
|
||
|
{
|
||
|
$list_acl_groups = AclExtended::aclGetGroupTitleList();
|
||
|
$username_acl_groups = AclExtended::aclGetGroupTitles($username);
|
||
|
//note aclGetGroupTitles() returns a 0 if user in no groups
|
||
|
|
||
|
$message = "<?xml version=\"1.0\"?>\n" .
|
||
|
"<response>\n" .
|
||
|
"\t<inactive>\n";
|
||
|
foreach ($list_acl_groups as $value) {
|
||
|
if ((!$username_acl_groups) || (!(in_array($value, $username_acl_groups)))) {
|
||
|
$message .= "\t\t<group>\n";
|
||
|
$message .= "\t\t\t<value>" . $value . "</value>\n";
|
||
|
|
||
|
// Modified 6-2009 by BM - Translate gacl group name if applicable
|
||
|
$message .= "\t\t\t<label>" . xl_gacl_group($value) . "</label>\n";
|
||
|
|
||
|
$message .= "\t\t</group>\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$message .= "\t</inactive>\n" .
|
||
|
"\t<active>\n";
|
||
|
if ($username_acl_groups) {
|
||
|
foreach ($username_acl_groups as $value) {
|
||
|
$message .= "\t\t<group>\n";
|
||
|
$message .= "\t\t\t<value>" . $value . "</value>\n";
|
||
|
|
||
|
// Modified 6-2009 by BM - Translate gacl group name if applicable
|
||
|
$message .= "\t\t\t<label>" . xl_gacl_group($value) . "</label>\n";
|
||
|
|
||
|
$message .= "\t\t</group>\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$message .= "\t</active>\n";
|
||
|
if (isset($err)) {
|
||
|
foreach ($err as $value) {
|
||
|
$message .= "\t<error>" . $value . "</error>\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$message .= "</response>\n";
|
||
|
return $message;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Returns error string(s) via xml
|
||
|
// $err = error (string or array)
|
||
|
//
|
||
|
function error_xml($err)
|
||
|
{
|
||
|
$message = "<?xml version=\"1.0\"?>\n" .
|
||
|
"<response>\n";
|
||
|
if (is_array($err)) {
|
||
|
foreach ($err as $value) {
|
||
|
$message .= "\t<error>" . $value . "</error>\n";
|
||
|
}
|
||
|
} else {
|
||
|
$message .= "\t<error>" . $err . "</error>\n";
|
||
|
}
|
||
|
|
||
|
$message .= "</response>\n";
|
||
|
return $message;
|
||
|
}
|