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

<?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;
}