4 * This file contains functions that service ajax requests for
5 * ACL(php-gacl) administration within OpenEMR. All returns are
8 * Important - Ensure that display_errors=Off in php.ini settings.
11 * @link https://www.open-emr.org
12 * @author Brady Miller <brady.g.miller@gmail.com>
13 * @author Rod Roark <rod@sunsetsystems.com>
14 * @copyright Copyright (c) 2007-2018 Brady Miller <brady.g.miller@gmail.com>
15 * @copyright Copyright (c) 2021 Rod Roark <rod@sunsetsystems.com>
16 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
19 require_once("../../interface/globals.php");
20 require_once("$srcdir/user.inc.php");
22 use OpenEMR\Common\Acl\AclExtended
;
23 use OpenEMR\Common\Acl\AclMain
;
24 use OpenEMR\Common\Csrf\CsrfUtils
;
25 use OpenEMR\Common\Logging\EventAuditLogger
;
26 use OpenEMR\Services\UserService
;
29 header("Content-type: text/xml");
30 header("Cache-Control: no-cache");
32 //initiate error array
36 if (!CsrfUtils
::verifyCsrfToken($_POST["csrf_token_form"])) {
37 echo error_xml(xl('Authentication Error'));
38 CsrfUtils
::csrfNotVerified(false);
41 //ensure user has proper access
42 if (!AclMain
::aclCheckCore('admin', 'acl')) {
43 echo error_xml(xl('ACL Administration Not Authorized'));
44 CsrfUtils
::csrfNotVerified(false);
47 //Display red alert if Emergency Login ACL is activated for a user.
48 if ($_POST["action"] == "add") {
49 if (!empty($_POST["selection"]) && is_array($_POST["selection"]) && in_array("Emergency Login", $_POST["selection"])) {
50 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.') ));
54 //PROCESS USERNAME REQUESTS
55 if ($_POST["control"] == "username") {
56 if ($_POST["action"] == "list") {
57 //return username list with alert if user is not joined to group
58 echo username_listings_xml($error);
63 //PROCESS MEMBERSHIP REQUESTS
64 if ($_POST["control"] == "membership") {
65 if ($_POST["action"] == "list") {
66 //return membership data
67 echo user_group_listings_xml($_POST["name"], $error);
70 if ($_POST["action"] == "add") {
71 if ($_POST["selection"][0] == "null") {
72 //no selection, return soft error, and just return membership data
73 array_push($error, (xl('No group was selected') . "!"));
74 echo user_group_listings_xml($_POST["name"], $error);
78 //add the group, then log it, then return updated membership data
79 AclExtended
::addUserAros($_POST["name"], $_POST["selection"]);
80 EventAuditLogger
::instance()->newEvent("security-administration-update", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "Added " . $_POST["name"] . " to following access group(s): " . implode(', ', $_POST["selection"]));
81 echo user_group_listings_xml($_POST["name"], $error);
84 if ($_POST["action"] == "remove") {
85 if ($_POST["selection"][0] == "null") {
86 //no selection, return soft error, and just return membership data
87 array_push($error, (xl('No group was selected') . "!"));
88 echo user_group_listings_xml($_POST["name"], $error);
92 // check if user is protected. If so, then state message unable to remove from admin group.
93 $userNametoID = (new UserService())->getIdByUsername($_POST["name"]);
94 if (checkUserSetting("gacl_protect", "1", $userNametoID) ||
($_POST["name"] == "admin")) {
97 $gacl_protect = false;
100 if ($gacl_protect && in_array("Administrators", $_POST["selection"])) {
101 //unable to remove admin user from administrators group, process remove,
102 // send soft error, then return data
103 array_push($error, (xl('Not allowed to remove this user from the Administrators group') . "!"));
104 AclExtended
::removeUserAros($_POST["name"], $_POST["selection"]);
105 echo user_group_listings_xml($_POST["name"], $error);
109 //remove the group(s), then log it, then return updated membership data
110 AclExtended
::removeUserAros($_POST["name"], $_POST["selection"]);
111 EventAuditLogger
::instance()->newEvent("security-administration-update", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "Removed " . $_POST["name"] . " from following access group(s): " . implode(', ', $_POST["selection"]));
112 echo user_group_listings_xml($_POST["name"], $error);
117 //PROCESS ACL REQUESTS
118 if ($_POST["control"] == "acl") {
119 if ($_POST["action"] == "list") {
120 //return acl titles with return values
121 echo AclExtended
::aclListingsXml($error);
124 if ($_POST["action"] == "add") {
127 if (empty($_POST["title"])) {
129 array_push($error, ("title_" . xl('Need to enter title') . "!"));
130 } elseif (!ctype_alpha(str_replace(' ', '', $_POST["title"]))) {
132 array_push($error, ("title_" . xl('Please only use alphabetic characters') . "!"));
133 } elseif (AclExtended
::aclExist($_POST["title"], false, $_POST["return_value"])) {
135 array_push($error, ("title_" . xl('Already used, choose another title') . "!"));
138 if (empty($_POST["identifier"])) {
140 array_push($error, ("identifier_" . xl('Need to enter identifier') . "!"));
141 } elseif (!ctype_alpha($_POST["identifier"])) {
143 array_push($error, ("identifier_" . xl('Please only use alphabetic characters with no spaces') . "!"));
144 } elseif (AclExtended
::aclExist(false, $_POST["identifier"], $_POST["return_value"])) {
146 array_push($error, ("identifier_" . xl('Already used, choose another identifier') . "!"));
149 if (empty($_POST["return_value"])) {
151 array_push($error, ("return_" . xl('Need to enter a Return Value') . "!"));
154 if (empty($_POST["description"])) {
156 array_push($error, ("description_" . xl('Need to enter a description') . "!"));
157 } elseif (!ctype_alpha(str_replace(' ', '', $_POST["description"]))) {
159 array_push($error, ("description_" . xl('Please only use alphabetic characters') . "!"));
162 //process if data is valid
164 AclExtended
::aclAdd($_POST["title"], $_POST["identifier"], $_POST["return_value"], $_POST["description"]);
165 echo "<?xml version=\"1.0\"?>\n" .
167 "\t<success>SUCCESS</success>\n" .
169 } else { //$form_error = true, so return errors
170 echo error_xml($error);
174 if ($_POST["action"] == "remove") {
177 if (empty($_POST["title"])) {
179 array_push($error, ("aclTitle_" . xl('Need to enter title') . "!"));
182 if ($_POST["title"] == "Administrators") {
184 array_push($error, ("aclTitle_" . xl('Not allowed to delete the Administrators group') . "!"));
187 //process if data is valid
189 AclExtended
::aclRemove($_POST["title"], $_POST["return_value"]);
190 echo "<?xml version=\"1.0\"?>\n" .
192 "\t<success>SUCCESS</success>\n" .
194 } else { //$form_error = true, so return errors
195 echo error_xml($error);
199 if ($_POST["action"] == "returns") {
200 //simply return all the possible acl return_values
201 echo AclExtended
::returnValuesXml($error);
206 //PROCESS ACO REQUESTS
207 if ($_POST["control"] == "aco") {
208 if ($_POST["action"] == "list") {
210 echo AclExtended
::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
213 if ($_POST["action"] == "add") {
214 if ($_POST["selection"][0] == "null") {
215 //no selection, return soft error, and just return data
216 array_push($error, (xl('Nothing was selected') . "!"));
217 echo AclExtended
::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
221 //add the aco, then return updated membership data
222 AclExtended
::aclAddAcos($_POST["name"], $_POST["return_value"], $_POST["selection"]);
223 echo AclExtended
::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
226 if ($_POST["action"] == "remove") {
227 if ($_POST["selection"][0] == "null") {
228 //no selection, return soft error, and just return data
229 array_push($error, (xl('Nothing was selected') . "!"));
230 echo AclExtended
::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
234 if ($_POST["name"] == "Administrators") {
235 //will not allow removal of acos from Administrators ACL
236 array_push($error, (xl('Not allowed to inactivate anything from the Administrators ACL') . "!"));
237 echo AclExtended
::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
241 //remove the acos, then return updated data
242 AclExtended
::aclRemoveAcos($_POST["name"], $_POST["return_value"], $_POST["selection"]);
243 echo AclExtended
::acoListingsXml($_POST["name"], $_POST["return_value"], $error);
249 // Returns username listings via xml message.
250 // It will also include alert if user is not joined
252 // $err = error strings (array)
254 function username_listings_xml($err)
256 $message = "<?xml version=\"1.0\"?>\n" .
258 $res = sqlStatement("select * from users where username != '' and active = 1 order by username");
259 for ($iter = 0; $row = sqlFetchArray($res); $iter++
) {
260 $result4[$iter] = $row;
263 foreach ($result4 as $iter) {
264 // Skip this user if logged-in user does not have all of its permissions.
265 // Note that a superuser now has all permissions.
266 if (!AclExtended
::iHavePermissionsOf($iter['username'])) {
270 $message .= "\t<user>\n" .
271 "\t\t<username>" . $iter["username"] . "</username>\n";
272 $username_acl_groups = AclExtended
::aclGetGroupTitles($iter["username"]);
273 if (!$username_acl_groups) {
274 //not joined to any group, so send alert
275 $message .= "\t\t<alert>no membership</alert>\n";
278 $message .= "\t</user>\n";
282 foreach ($err as $value) {
283 $message .= "\t<error>" . $value . "</error>\n";
287 $message .= "</response>\n";
292 // Returns user group listings(active and inactive lists)
294 // $username = username
295 // $err = error strings (array)
297 function user_group_listings_xml($username, $err)
299 $list_acl_groups = AclExtended
::aclGetGroupTitleList();
300 $username_acl_groups = AclExtended
::aclGetGroupTitles($username);
301 //note aclGetGroupTitles() returns a 0 if user in no groups
303 $message = "<?xml version=\"1.0\"?>\n" .
306 foreach ($list_acl_groups as $value) {
307 if ((!$username_acl_groups) ||
(!(in_array($value, $username_acl_groups)))) {
308 $message .= "\t\t<group>\n";
309 $message .= "\t\t\t<value>" . $value . "</value>\n";
311 // Modified 6-2009 by BM - Translate gacl group name if applicable
312 $message .= "\t\t\t<label>" . xl_gacl_group($value) . "</label>\n";
314 $message .= "\t\t</group>\n";
318 $message .= "\t</inactive>\n" .
320 if ($username_acl_groups) {
321 foreach ($username_acl_groups as $value) {
322 $message .= "\t\t<group>\n";
323 $message .= "\t\t\t<value>" . $value . "</value>\n";
325 // Modified 6-2009 by BM - Translate gacl group name if applicable
326 $message .= "\t\t\t<label>" . xl_gacl_group($value) . "</label>\n";
328 $message .= "\t\t</group>\n";
332 $message .= "\t</active>\n";
334 foreach ($err as $value) {
335 $message .= "\t<error>" . $value . "</error>\n";
339 $message .= "</response>\n";
344 // Returns error string(s) via xml
345 // $err = error (string or array)
347 function error_xml($err)
349 $message = "<?xml version=\"1.0\"?>\n" .
351 if (is_array($err)) {
352 foreach ($err as $value) {
353 $message .= "\t<error>" . $value . "</error>\n";
356 $message .= "\t<error>" . $err . "</error>\n";
359 $message .= "</response>\n";