diff --git a/Web/Lang/en/messages.mo b/Web/Lang/en/messages.mo
index 126ec7f..8ee8389 100644
Binary files a/Web/Lang/en/messages.mo and b/Web/Lang/en/messages.mo differ
diff --git a/Web/Lang/en/messages.po b/Web/Lang/en/messages.po
index e5510f3..27efb97 100644
--- a/Web/Lang/en/messages.po
+++ b/Web/Lang/en/messages.po
@@ -5182,3 +5182,21 @@ msgstr "The API host groups are named sets of API hosts which can be used to ass
msgid "Assign to API host groups:"
msgstr "Assign to API host groups:"
+
+msgid "Bacula Console ACL"
+msgstr "Bacula Console ACL"
+
+msgid "Assigned"
+msgstr "Assigned"
+
+msgid "unassign"
+msgstr "unassign"
+
+msgid "Set API host access to resources"
+msgstr "Set API host access to resources"
+
+msgid "Set user API host access to resources"
+msgstr "Set user API host access to resources"
+
+msgid "Set API host group access to resources"
+msgstr "Set API host group access to resources"
diff --git a/Web/Lang/fr/messages.mo b/Web/Lang/fr/messages.mo
index 75d822f..3cc2f5e 100644
Binary files a/Web/Lang/fr/messages.mo and b/Web/Lang/fr/messages.mo differ
diff --git a/Web/Lang/fr/messages.po b/Web/Lang/fr/messages.po
index e93e693..0cd53d6 100644
--- a/Web/Lang/fr/messages.po
+++ b/Web/Lang/fr/messages.po
@@ -5193,3 +5193,21 @@ msgstr "The API host groups are named sets of API hosts which can be used to ass
msgid "Assign to API host groups:"
msgstr "Assign to API host groups:"
+
+msgid "Bacula Console ACL"
+msgstr "Bacula Console ACL"
+
+msgid "Assigned"
+msgstr "Assigned"
+
+msgid "unassign"
+msgstr "unassign"
+
+msgid "Set API host access to resources"
+msgstr "Set API host access to resources"
+
+msgid "Set user API host access to resources"
+msgstr "Set user API host access to resources"
+
+msgid "Set API host group access to resources"
+msgstr "Set API host group access to resources"
diff --git a/Web/Lang/ja/messages.mo b/Web/Lang/ja/messages.mo
index ccc7169..25c68c8 100644
Binary files a/Web/Lang/ja/messages.mo and b/Web/Lang/ja/messages.mo differ
diff --git a/Web/Lang/ja/messages.po b/Web/Lang/ja/messages.po
index 05db446..bcc6bbc 100644
--- a/Web/Lang/ja/messages.po
+++ b/Web/Lang/ja/messages.po
@@ -5256,3 +5256,21 @@ msgstr "The API host groups are named sets of API hosts which can be used to ass
msgid "Assign to API host groups:"
msgstr "Assign to API host groups:"
+
+msgid "Bacula Console ACL"
+msgstr "Bacula Console ACL"
+
+msgid "Assigned"
+msgstr "Assigned"
+
+msgid "unassign"
+msgstr "unassign"
+
+msgid "Set API host access to resources"
+msgstr "Set API host access to resources"
+
+msgid "Set user API host access to resources"
+msgstr "Set user API host access to resources"
+
+msgid "Set API host group access to resources"
+msgstr "Set API host group access to resources"
diff --git a/Web/Lang/ko/messages.mo b/Web/Lang/ko/messages.mo
index 84eba4c..73bea67 100644
Binary files a/Web/Lang/ko/messages.mo and b/Web/Lang/ko/messages.mo differ
diff --git a/Web/Lang/ko/messages.po b/Web/Lang/ko/messages.po
index f51b0ac..b108ef1 100644
--- a/Web/Lang/ko/messages.po
+++ b/Web/Lang/ko/messages.po
@@ -5198,3 +5198,21 @@ msgstr "The API host groups are named sets of API hosts which can be used to ass
msgid "Assign to API host groups:"
msgstr "Assign to API host groups:"
+
+msgid "Bacula Console ACL"
+msgstr "Bacula Console ACL"
+
+msgid "Assigned"
+msgstr "Assigned"
+
+msgid "unassign"
+msgstr "unassign"
+
+msgid "Set API host access to resources"
+msgstr "Set API host access to resources"
+
+msgid "Set user API host access to resources"
+msgstr "Set user API host access to resources"
+
+msgid "Set API host group access to resources"
+msgstr "Set API host group access to resources"
diff --git a/Web/Lang/pl/messages.mo b/Web/Lang/pl/messages.mo
index e0fad7b..0291f01 100644
Binary files a/Web/Lang/pl/messages.mo and b/Web/Lang/pl/messages.mo differ
diff --git a/Web/Lang/pl/messages.po b/Web/Lang/pl/messages.po
index 767b8c7..5361e79 100644
--- a/Web/Lang/pl/messages.po
+++ b/Web/Lang/pl/messages.po
@@ -5193,3 +5193,21 @@ msgstr "The API host groups are named sets of API hosts which can be used to ass
msgid "Assign to API host groups:"
msgstr "Assign to API host groups:"
+
+msgid "Bacula Console ACL"
+msgstr "Bacula Console ACL"
+
+msgid "Assigned"
+msgstr "Assigned"
+
+msgid "unassign"
+msgstr "unassign"
+
+msgid "Set API host access to resources"
+msgstr "Set API host access to resources"
+
+msgid "Set user API host access to resources"
+msgstr "Set user API host access to resources"
+
+msgid "Set API host group access to resources"
+msgstr "Set API host group access to resources"
diff --git a/Web/Lang/pt/messages.mo b/Web/Lang/pt/messages.mo
index 405dfe8..8932a06 100644
Binary files a/Web/Lang/pt/messages.mo and b/Web/Lang/pt/messages.mo differ
diff --git a/Web/Lang/pt/messages.po b/Web/Lang/pt/messages.po
index c420cff..e371cc0 100644
--- a/Web/Lang/pt/messages.po
+++ b/Web/Lang/pt/messages.po
@@ -5193,3 +5193,21 @@ msgstr "The API host groups are named sets of API hosts which can be used to ass
msgid "Assign to API host groups:"
msgstr "Assign to API host groups:"
+
+msgid "Bacula Console ACL"
+msgstr "Bacula Console ACL"
+
+msgid "Assigned"
+msgstr "Assigned"
+
+msgid "unassign"
+msgstr "unassign"
+
+msgid "Set API host access to resources"
+msgstr "Set API host access to resources"
+
+msgid "Set user API host access to resources"
+msgstr "Set user API host access to resources"
+
+msgid "Set API host group access to resources"
+msgstr "Set API host group access to resources"
diff --git a/Web/Lang/ru/messages.mo b/Web/Lang/ru/messages.mo
index 8f623a1..3057ceb 100644
Binary files a/Web/Lang/ru/messages.mo and b/Web/Lang/ru/messages.mo differ
diff --git a/Web/Lang/ru/messages.po b/Web/Lang/ru/messages.po
index 905bf30..be745f6 100644
--- a/Web/Lang/ru/messages.po
+++ b/Web/Lang/ru/messages.po
@@ -5192,3 +5192,21 @@ msgstr "The API host groups are named sets of API hosts which can be used to ass
msgid "Assign to API host groups:"
msgstr "Assign to API host groups:"
+
+msgid "Bacula Console ACL"
+msgstr "Bacula Console ACL"
+
+msgid "Assigned"
+msgstr "Assigned"
+
+msgid "unassign"
+msgstr "unassign"
+
+msgid "Set API host access to resources"
+msgstr "Set API host access to resources"
+
+msgid "Set user API host access to resources"
+msgstr "Set user API host access to resources"
+
+msgid "Set API host group access to resources"
+msgstr "Set API host group access to resources"
diff --git a/Web/Pages/Security.page b/Web/Pages/Security.page
index 2ef6be9..98bb141 100644
--- a/Web/Pages/Security.page
+++ b/Web/Pages/Security.page
@@ -1257,6 +1257,24 @@ var oUserList = {
{
data: 'username',
render: function (data, type, row) {
+ let btns = '';
+
+ // Set access button
+ const span = document.createElement('SPAN');
+ const access_btn = document.createElement('BUTTON');
+ access_btn.className = 'w3-button w3-green';
+ access_btn.type = 'button';
+ const i = document.createElement('I');
+ i.className = 'fas fa-edit';
+ const label = document.createTextNode(' <%[ Set access ]%>');
+ access_btn.appendChild(i);
+ access_btn.innerHTML += ' ';
+ access_btn.appendChild(label);
+ access_btn.setAttribute('onclick', 'oUsers.load_user_access_window("' + data + '")');
+ span.appendChild(access_btn);
+ span.style.marginRight = '5px';
+ btns += span.outerHTML;
+
var btn_edit = document.createElement('BUTTON');
btn_edit.className = 'w3-button w3-green';
btn_edit.type = 'button';
@@ -1268,7 +1286,9 @@ var oUserList = {
btn_edit.style.marginRight = '8px';
btn_edit.appendChild(label_edit);
btn_edit.setAttribute('onclick', 'oUsers.load_user_window(\'' + data + '\')');
- return btn_edit.outerHTML;
+ btns += btn_edit.outerHTML;
+
+ return btns;
}
}
],
@@ -1283,7 +1303,7 @@ var oUserList = {
targets: 0
},
{
- className: 'action_col',
+ className: 'action_col_long',
orderable: false,
targets: [ 11 ]
},
@@ -1424,6 +1444,36 @@ var oUsers = {
},
save_user_cb: function() {
document.getElementById('user_window').style.display = 'none';
+ },
+ load_user_access_window: function(name) {
+ this.clear_access_window();
+ document.getElementById('<%=$this->UserAPIHostResourceAccessName->ClientID%>').value = name;
+ const cb = <%=$this->LoadUserAPIHostResourceAccess->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(name);
+ cb.dispatch();
+ document.getElementById('user_access_window_title').textContent = name;
+ document.getElementById('user_access_window').style.display = 'block';
+ },
+ clear_access_window: function() {
+ // empty fields
+ [
+ '<%=$this->UserAPIHostResourceAccessJobs->ClientID%>'
+ ].forEach((id) => {
+ $('#' + id).empty();
+ });
+
+ // reset radio buttons
+ document.getElementById('<%=$this->UserAPIHostResourceAccessAllResources->ClientID%>').checked = true;
+ document.getElementById('user_access_window_error').style.display = 'none';
+ document.getElementById('user_access_window_console').style.display = 'none';
+ document.getElementById('user_access_window_select_jobs').style.display = 'none';
+ document.getElementById('user_access_window_select_access').style.display = 'none';
+ },
+ unassign_console: function() {
+ const api_host = document.getElementById('<%=$this->UserAPIHostList->ClientID%>').value;
+ const cb = <%=$this->UnassignUserAPIHostConsole->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(api_host);
+ cb.dispatch();
}
}
@@ -1673,6 +1723,112 @@ $(function() {
+
@@ -3353,6 +3509,27 @@ var oAPIHostList = {
{
data: 'name',
render: function (data, type, row) {
+ let btns = '';
+
+ // Set access button
+ if (data !== 'Main') {
+ const span = document.createElement('SPAN');
+ const access_btn = document.createElement('BUTTON');
+ access_btn.className = 'w3-button w3-green';
+ access_btn.type = 'button';
+ const i = document.createElement('I');
+ i.className = 'fas fa-edit';
+ const label = document.createTextNode(' <%[ Set access ]%>');
+ access_btn.appendChild(i);
+ access_btn.innerHTML += ' ';
+ access_btn.appendChild(label);
+ access_btn.setAttribute('onclick', 'oAPIHosts.load_access_window("' + data + '")');
+ span.appendChild(access_btn);
+ span.style.marginRight = '5px';
+ btns += span.outerHTML;
+ }
+
+ // Edit button
var btn_edit = document.createElement('BUTTON');
btn_edit.className = 'w3-button w3-green';
btn_edit.type = 'button';
@@ -3364,7 +3541,9 @@ var oAPIHostList = {
btn_edit.style.marginRight = '8px';
btn_edit.appendChild(label_edit);
btn_edit.setAttribute('onclick', 'oAPIHosts.load_api_host_window(\'' + data + '\')');
- return btn_edit.outerHTML;
+ btns += btn_edit.outerHTML;
+
+ return btns;
}
}
],
@@ -3379,7 +3558,7 @@ var oAPIHostList = {
targets: 0
},
{
- className: 'action_col',
+ className: 'action_col_long',
orderable: false,
targets: [ 6 ]
},
@@ -3504,6 +3683,35 @@ var oAPIHosts = {
},
save_api_host_cb: function() {
document.getElementById('api_host_window').style.display = 'none';
+ },
+ load_access_window: function(name) {
+ this.clear_access_window();
+ document.getElementById('api_host_access_window_console').style.display = 'none';
+ const cb = <%=$this->LoadAPIHostResourceAccess->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(name);
+ cb.dispatch();
+ document.getElementById('api_host_access_window_title').textContent = name;
+ document.getElementById('api_host_access_window').style.display = 'block';
+ document.getElementById('<%=$this->APIHostResourceAccessName->ClientID%>').value = name;
+ },
+ clear_access_window: function() {
+ // empty fields
+ [
+ '<%=$this->APIHostResourceAccessJobs->ClientID%>'
+ ].forEach((id) => {
+ $('#' + id).empty();
+ });
+
+ // reset radio buttons
+ document.getElementById('<%=$this->APIHostResourceAccessAllResources->ClientID%>').checked = true;
+ document.getElementById('api_host_access_window_select_jobs').style.display = 'none';
+ document.getElementById('api_host_access_window_error').style.display = 'none';
+ },
+ unassign_console: function() {
+ const api_host = document.getElementById('<%=$this->APIHostResourceAccessName->ClientID%>').value;
+ const cb = <%=$this->UnassignAPIHostConsole->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(api_host);
+ cb.dispatch();
}
}
@@ -3905,6 +4113,85 @@ $(function() {
+
+
+
+ ×
+ - <%[ Set API host access to resources ]%>
+
+
+
+
<%[ Access to all shared API host resources (all jobs, all clients, all storages...etc.) ]%>
+
<%[ Access to selected resources only ]%>
+
+
+
+
+
+
+
+
+
+ const radio = document.getElementById('<%=$this->APIHostResourceAccessSelectedResources->ClientID%>');
+ sender.enabled = radio.checked;
+
+
+
+
<%[ Use CTRL + left-click to multiple item selection ]%>
+
+
+
+
+ <%[ Cancel ]%>
+
+ <%[ Save ]%>
+
+
+
+
+
+
+ document.getElementById('get_api_host_window_loader').style.visibility = 'visible';
+
+
+ document.getElementById('get_api_host_window_loader').style.visibility = 'hidden';
+
+
+
+
<%[ The API host groups are named sets of API hosts which can be used to assign to users instead of assigning single API hosts. The API group function is more flexible solution than assigning API hosts directly and may be useful in environments where users have access to more than one API host. ]%>
@@ -4000,6 +4287,25 @@ var oAPIHostGroupList = {
{
data: 'name',
render: function (data, type, row) {
+ let btns = '';
+
+ // Set access button
+ const span = document.createElement('SPAN');
+ const access_btn = document.createElement('BUTTON');
+ access_btn.className = 'w3-button w3-green';
+ access_btn.type = 'button';
+ const i = document.createElement('I');
+ i.className = 'fas fa-edit';
+ const label = document.createTextNode(' <%[ Set access ]%>');
+ access_btn.appendChild(i);
+ access_btn.innerHTML += ' ';
+ access_btn.appendChild(label);
+ access_btn.setAttribute('onclick', 'oAPIHostGroups.load_access_window("' + data + '")');
+ span.appendChild(access_btn);
+ span.style.marginRight = '5px';
+ btns += span.outerHTML;
+
+ // Edit button
const btn_edit = document.createElement('BUTTON');
btn_edit.className = 'w3-button w3-green';
btn_edit.type = 'button';
@@ -4011,7 +4317,9 @@ var oAPIHostGroupList = {
btn_edit.style.marginRight = '8px';
btn_edit.appendChild(label_edit);
btn_edit.setAttribute('onclick', 'oAPIHostGroups.load_api_host_group_window(\'' + data + '\')');
- return btn_edit.outerHTML;
+ btns += btn_edit.outerHTML;
+
+ return btns;
}
}
],
@@ -4026,7 +4334,7 @@ var oAPIHostGroupList = {
targets: 0
},
{
- className: 'action_col',
+ className: 'action_col_long',
orderable: false,
targets: [ 4 ]
},
@@ -4119,6 +4427,36 @@ var oAPIHostGroups = {
},
save_api_host_group_cb: function() {
document.getElementById('api_host_group_window').style.display = 'none';
+ },
+ load_access_window: function(name) {
+ this.clear_access_window();
+ document.getElementById('<%=$this->APIHostGroupAPIHostResourceAccessName->ClientID%>').value = name;
+ const cb = <%=$this->LoadAPIHostGroupAPIHostResourceAccess->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(name);
+ cb.dispatch();
+ document.getElementById('api_host_group_access_window_title').textContent = name;
+ document.getElementById('api_host_group_access_window').style.display = 'block';
+ },
+ clear_access_window: function() {
+ // empty fields
+ [
+ '<%=$this->APIHostGroupAPIHostResourceAccessJobs->ClientID%>'
+ ].forEach((id) => {
+ $('#' + id).empty();
+ });
+
+ // reset radio buttons
+ document.getElementById('<%=$this->APIHostGroupAPIHostResourceAccessAllResources->ClientID%>').checked = true;
+ document.getElementById('api_host_group_access_window_error').style.display = 'none';
+ document.getElementById('api_host_group_access_window_console').style.display = 'none';
+ document.getElementById('api_host_group_access_window_select_jobs').style.display = 'none';
+ document.getElementById('api_host_group_access_window_select_access').style.display = 'none';
+ },
+ unassign_console: function() {
+ const api_host = document.getElementById('<%=$this->APIHostGroupAPIHostList->ClientID%>').value;
+ const cb = <%=$this->UnassignAPIHostGroupAPIHostConsole->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(api_host);
+ cb.dispatch();
}
}
@@ -4211,4 +4549,110 @@ $(function() {
+
+
+
+ ×
+ - <%[ Set API host group access to resources ]%>
+
+
+
+
+
+
+
+ document.getElementById('get_api_host_group_loader').style.visibility = 'visible';
+ const sa = document.getElementById('api_host_group_access_window_select_access');
+ sa.style.display = 'none';
+
+
+ document.getElementById('get_api_host_group_loader').style.visibility = 'hidden';
+ const el = document.getElementById('<%=$this->APIHostGroupAPIHostList->ClientID%>');
+ const sa = document.getElementById('api_host_group_access_window_select_access');
+ const err = document.getElementById('api_host_group_access_window_error');
+ if (err.style.display == 'none') {
+ sa.style.display = el.value ? 'block' : 'none';
+ } else {
+ sa.style.display = 'none';
+ }
+
+
+
+
+
+
+
<%[ Access to all shared API host resources (all jobs, all clients, all storages...etc.) ]%>
+
<%[ Access to selected resources only ]%>
+
+
+
+
+
+
+
+
+ const radio = document.getElementById('<%=$this->APIHostResourceAccessSelectedResources->ClientID%>');
+ sender.enabled = radio.checked;
+
+
+
+
<%[ Use CTRL + left-click to multiple item selection ]%>
+
+
+
+
+
+
+ <%[ Cancel ]%>
+
+ <%[ Save ]%>
+
+
+
+
+
+
+ document.getElementById('get_api_host_group_loader').style.visibility = 'visible';
+
+
+ document.getElementById('get_api_host_group_loader').style.visibility = 'hidden';
+
+
+
+
diff --git a/Web/Pages/Security.php b/Web/Pages/Security.php
index fcf5392..ea495e4 100644
--- a/Web/Pages/Security.php
+++ b/Web/Pages/Security.php
@@ -34,6 +34,8 @@
use Prado\Web\UI\ActiveControls\TCallback;
use Prado\Web\UI\ActiveControls\TCallbackEventParameter;
use Prado\Web\UI\TCommandEventParameter;
+use Bacularis\Common\Modules\AuthOAuth2;
+use Bacularis\Common\Modules\AuthBasic;
use Bacularis\Common\Modules\AuditLog;
use Bacularis\Common\Modules\Ldap;
use Bacularis\Common\Modules\Logging;
@@ -230,12 +232,18 @@ private function setRoles($control, $def_val = null)
*
* @param object $control control which contains API host list
* @param mixed $def_val default value or null if no default value to set
- * @param bool determines if add first blank item
- * @param mixed $add_blank_item
+ * @param bool $add_blank_item determines if add first blank item
+ * @param array $sel_api_hosts defines selected list of API hosts to set. If not set, all API hosts are taken
*/
- private function setAPIHosts($control, $def_val = null, $add_blank_item = true)
+ private function setAPIHosts($control, $def_val = null, $add_blank_item = true, $sel_api_hosts = [])
{
- $api_hosts = array_keys($this->getModule('host_config')->getConfig());
+ $api_hosts = [];
+ if (count($sel_api_hosts) > 0) {
+ $api_hosts = $sel_api_hosts;
+ } else {
+ $host_config = $this->getModule('host_config')->getConfig();
+ $api_hosts = array_keys($host_config);
+ }
if ($add_blank_item) {
array_unshift($api_hosts, '');
}
@@ -2237,6 +2245,318 @@ public function trimIps($ips)
return $ips;
}
+ /**
+ * Load user window with API hosts and API host groups access settings.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function loadUserAPIHostResourceAccessWindow($sender, $param)
+ {
+ $username = $this->UserAPIHostResourceAccessName->Value;
+
+ $user_config = $this->getModule('user_config')->getUserConfig($username);
+ if (count($user_config) > 0) {
+ $api_hosts = [];
+ if ($user_config['api_hosts_method'] === WebUserConfig::API_HOST_METHOD_HOSTS) {
+ $api_hosts = $user_config['api_hosts'];
+ } elseif ($user_config['api_hosts_method'] === WebUserConfig::API_HOST_METHOD_HOST_GROUPS) {
+ $host_groups = $this->getModule('host_group_config');
+ $api_hosts = $host_groups->getAPIHostsByGroups($user_config['api_host_groups']);
+ }
+ if (count($api_hosts) == 1 && $api_hosts[0] === HostConfig::MAIN_CATALOG_HOST) {
+ $host_config = $this->getModule('host_config')->getConfig();
+ $api_hosts = array_keys($host_config);
+ }
+ // strip main API host
+ $cbf = function ($host) {
+ return ($host !== HostConfig::MAIN_CATALOG_HOST);
+ };
+ $api_hosts = array_filter($api_hosts, $cbf);
+ $this->setAPIHosts($this->UserAPIHostList, null, true, $api_hosts);
+ }
+ }
+
+ /**
+ * Set user window with API hosts and API host groups access settings.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function setUserAPIHostResourceAccessWindow($sender, $param)
+ {
+ $api_host = $this->UserAPIHostList->getSelectedValue();
+ $this->setAPIHostJobs(
+ $this->UserAPIHostResourceAccessJobs,
+ $api_host,
+ 'user_access_window_error'
+ );
+ $this->setUserAPIHostConsole($api_host);
+ }
+
+ /**
+ * Set user API host console.
+ *
+ * @param string $api_host API host name
+ * @param bool $set_state determine if state (all/selected resources) should be changed
+ */
+ private function setUserAPIHostConsole($api_host, $set_state = true)
+ {
+ $console = $this->isAPIHostConsole($api_host);
+ $cb = $this->getCallbackClient();
+ $cb->hide('user_access_window_console');
+ if (!empty($console)) {
+ $cb->show('user_access_window_select_jobs');
+ $cb->show('user_access_window_console');
+ if ($set_state) {
+ $this->UserAPIHostResourceAccessSelectedResources->Checked = true;
+ }
+ } else {
+ if ($set_state) {
+ $cb->hide('user_access_window_select_jobs');
+ $this->UserAPIHostResourceAccessAllResources->Checked = true;
+ }
+ }
+ }
+
+ /**
+ * Unassign console from API host.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function unassignUserAPIHostConsole($sender, $param)
+ {
+ $api_host = $param->getCallbackParameter();
+ $success = $this->unassignAPIHostConsoleInternal($api_host);
+ if ($success) {
+ $this->setAPIHostJobs(
+ $this->UserAPIHostResourceAccessJobs,
+ $api_host,
+ 'user_access_window_error'
+ );
+ $this->setUserAPIHostConsole($api_host, false);
+ $cb = $this->getCallbackClient();
+ $cb->hide('user_access_window_console');
+ }
+ }
+
+ /**
+ * Save user window with API hosts and API host groups.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function saveUserAPIHostResourceAccess($sender, $param)
+ {
+ $api_host = $this->UserAPIHostList->getSelectedValue();
+ if ($this->UserAPIHostResourceAccessAllResources->Checked) {
+ $state = $this->setResourceConsole(
+ $api_host,
+ '',
+ 'user_access_window_error'
+ );
+ if ($state) {
+ $this->setAPIHostJobs(
+ $this->UserAPIHostResourceAccessJobs,
+ $api_host,
+ 'user_access_window_error'
+ );
+ $this->setUserAPIHostConsole($api_host);
+ }
+ } elseif ($this->UserAPIHostResourceAccessSelectedResources->Checked) {
+ $selected_indices = $this->UserAPIHostResourceAccessJobs->getSelectedIndices();
+ $jobs = [];
+ foreach ($selected_indices as $indice) {
+ for ($i = 0; $i < $this->UserAPIHostResourceAccessJobs->getItemCount(); $i++) {
+ if ($i === $indice) {
+ $jobs[] = $this->UserAPIHostResourceAccessJobs->Items[$i]->Value;
+ }
+ }
+ }
+ $console = $this->setJobResourceAccess($api_host, $jobs);
+ if ($console) {
+ $state = $this->setResourceConsole(
+ $api_host,
+ $console,
+ 'user_access_window_error'
+ );
+ if ($state) {
+ $this->setAPIHostJobs(
+ $this->UserAPIHostResourceAccessJobs,
+ $api_host,
+ 'user_access_window_error'
+ );
+ }
+ $this->setUserAPIHostConsole($api_host);
+ }
+ }
+ }
+
+ /**
+ * Load API host set resource access window.
+ *
+ * @param TActiveDropDownList $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function loadAPIHostResourceAccessWindow($sender, $param)
+ {
+ $api_host = $param->getCallbackParameter();
+ $this->setAPIHostJobs(
+ $this->APIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_access_window_error'
+ );
+ $this->setAPIHostConsole($api_host);
+ }
+
+ /**
+ * Save window with API hosts.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function saveAPIHostResourceAccess($sender, $param)
+ {
+ $api_host = $this->APIHostResourceAccessName->Value;
+ $cb = $this->getCallbackClient();
+ if ($this->APIHostResourceAccessAllResources->Checked) {
+ $state = $this->setResourceConsole(
+ $api_host,
+ '',
+ 'api_host_access_window_error'
+ );
+ if ($state) {
+ $this->setAPIHostJobs(
+ $this->APIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_access_window_error'
+ );
+ $this->setAPIHostConsole($api_host);
+ $cb->hide('api_host_access_window');
+ }
+ } elseif ($this->APIHostResourceAccessSelectedResources->Checked) {
+ $selected_indices = $this->APIHostResourceAccessJobs->getSelectedIndices();
+ $jobs = [];
+ foreach ($selected_indices as $indice) {
+ for ($i = 0; $i < $this->APIHostResourceAccessJobs->getItemCount(); $i++) {
+ if ($i === $indice) {
+ $jobs[] = $this->APIHostResourceAccessJobs->Items[$i]->Value;
+ }
+ }
+ }
+ $console = $this->setJobResourceAccess($api_host, $jobs);
+ if ($console) {
+ $state = $this->setResourceConsole(
+ $api_host,
+ $console,
+ 'api_host_access_window_error'
+ );
+ if ($state) {
+ $this->setAPIHostJobs(
+ $this->APIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_access_window_error'
+ );
+ $this->setAPIHostConsole($api_host);
+ $cb->hide('api_host_access_window');
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if Bacula Console ACL is assigned to given API host.
+ *
+ * @param string $api_host API host name
+ * @return bool true if console is set, otherwise false
+ */
+ private function isAPIHostConsole($api_host)
+ {
+ $console = false;
+ $host_config = $this->getModule('host_config')->getHostConfig($api_host);
+ if (count($host_config) == 0) {
+ // API host does not exist
+ return $console;
+ }
+
+ if ($host_config['auth_type'] === AuthBasic::NAME) {
+ $basic_users_result = $this->getModule('api')->get(
+ ['basic', 'users', $host_config['login']],
+ $api_host
+ );
+ if ($basic_users_result->error !== 0) {
+ return $console;
+ }
+ $console = !empty($basic_users_result->output->bconsole_cfg_path);
+ } elseif ($host_config['auth_type'] === AuthOAuth2::NAME) {
+ $oauth2_client_result = $this->getModule('api')->get(
+ ['oauth2', 'clients', $host_config['client_id']],
+ $api_host
+ );
+
+ $oa2 = new OAuth2Record();
+ $oa2::deleteByPk($api_host);
+
+ if ($oauth2_client_result->error !== 0) {
+ return $console;
+ }
+ $console = !empty($oauth2_client_result->output->bconsole_cfg_path);
+ }
+ return $console;
+ }
+
+ /**
+ * Set API host job list control.
+ *
+ * @param object $control control to set jobs
+ * @param string $api_host API host name
+ * @param string $error_el_id error element identifier
+ */
+ private function setAPIHostJobs($control, $api_host, $error_el_id)
+ {
+ $cb = $this->getCallbackClient();
+ $result = $this->getModule('api')->get(['jobs', 'resnames'], $api_host);
+ if ($result->error === 0) {
+ $res = array_values((array) $result->output);
+ $jobs = array_shift($res);
+ $control->DataSource = array_combine($jobs, $jobs);
+ $control->dataBind();
+ $cb->hide($error_el_id);
+ } else {
+ $emsg = 'Error while loading API host resources. Please check connection with this API host. ErrorCode: %d, ErrorMsg: %s';
+ $emsg = sprintf($emsg, $result->error, $result->output);
+ $cb->update(
+ $error_el_id,
+ $emsg
+ );
+ $cb->show($error_el_id);
+ }
+ }
+
+ /**
+ * Set API host console.
+ *
+ * @param string $api_host API host name
+ * @param bool $set_state determine if state (all/selected resources) should be changed
+ */
+ private function setAPIHostConsole($api_host, $set_state = true)
+ {
+ $console = $this->isAPIHostConsole($api_host);
+ $cb = $this->getCallbackClient();
+ if (!empty($console)) {
+ $cb->show('api_host_access_window_select_jobs');
+ $cb->show('api_host_access_window_console');
+ if ($set_state) {
+ $this->APIHostResourceAccessSelectedResources->Checked = true;
+ }
+ } else {
+ if ($set_state) {
+ $this->APIHostResourceAccessAllResources->Checked = true;
+ }
+ }
+ }
+
/**
* Initialize values in API host group modal window.
*
@@ -2268,6 +2588,265 @@ public function setAPIHostGroupList($sender, $param)
]);
}
+ /**
+ * Set resource access for given jobs.
+ * Create console with the jobs and all dependent resources (Clients, Filesets...etc)
+ *
+ * @param string $api_host api host name
+ * @param array $jobs job names
+ * @return string console name or empty string on error
+ */
+ private function setJobResourceAccess($api_host, $jobs)
+ {
+ $result = $this->getModule('api')->get([
+ 'config',
+ 'dir',
+ 'Job',
+ '?apply_jobdefs=1'
+ ], $api_host);
+
+ $cb = $this->getCallbackClient();
+ if ($result->error !== 0) {
+ $cb->update(
+ 'api_host_access_window_error',
+ $result->output
+ );
+ $cb->show('api_host_access_window_error');
+ return '';
+ }
+
+ $acls = [
+ 'Name' => 'Console - ' . $api_host,
+ 'Password' => $this->getModule('crypto')->getRandomString(40),
+ 'JobAcl' => [],
+ 'ClientAcl' => [],
+ 'StorageAcl' => [],
+ 'FilesetAcl' => [],
+ 'PoolAcl' => [],
+ 'ScheduleAcl' => [],
+ 'CatalogAcl' => ['*all*'],
+ 'WhereAcl' => ['*all*'],
+ 'CommandAcl' => JobInfo::COMMAND_ACL_USED_BY_WEB
+ ];
+ for ($i = 0; $i < count($jobs); $i++) {
+ for ($j = 0; $j < count($result->output); $j++) {
+ if ($result->output[$j]->Job->Name === $jobs[$i]) {
+ // job
+ $acls['JobAcl'][] = $result->output[$j]->Job->Name;
+ // client
+ if (!in_array($result->output[$j]->Job->Client, $acls['ClientAcl'])) {
+ $acls['ClientAcl'][] = $result->output[$j]->Job->Client;
+ }
+ // storage
+ $acls['StorageAcl'] = array_merge($acls['StorageAcl'], $result->output[$j]->Job->Storage);
+ $acls['StorageAcl'] = array_unique($acls['StorageAcl']);
+ // fileset
+ if (!in_array($result->output[$j]->Job->Fileset, $acls['FilesetAcl'])) {
+ $acls['FilesetAcl'][] = $result->output[$j]->Job->Fileset;
+ }
+ // pool
+ if (!in_array($result->output[$j]->Job->Pool, $acls['PoolAcl'])) {
+ $acls['PoolAcl'][] = $result->output[$j]->Job->Pool;
+ }
+ // schedule
+ if (property_exists($result->output[$j]->Job, 'Schedule') && !in_array($result->output[$j]->Job->Schedule, $acls['ScheduleAcl'])) {
+ $acls['ScheduleAcl'][] = $result->output[$j]->Job->Schedule;
+ }
+ break;
+ }
+ }
+ }
+
+ $result = $this->getModule('api')->set([
+ 'config',
+ 'dir',
+ 'Console',
+ $acls['Name']
+ ], [
+ 'config' => json_encode($acls)
+ ], $api_host);
+
+ if ($result->error === 0) {
+ $this->getModule('api')->set(['console'], ['reload']);
+ } else {
+ $cb->update(
+ 'api_host_access_window_error',
+ $result->output
+ );
+ $cb->show('api_host_access_window_error');
+ return '';
+ }
+ return $acls['Name'];
+ }
+
+ /**
+ * Set resource access with Consoles for given API host.
+ * If console is not given, full access is set.
+ *
+ * @param string $api_host API host name
+ * @param string $console console name
+ * @param string $error_el_id error message container element identifier
+ * @return bool console setting state, true for success, otherwise false
+ */
+ private function setResourceConsole($api_host, $console = '', $error_el_id = '')
+ {
+ $state = false;
+ $host_config = $this->getModule('host_config')->getHostConfig($api_host);
+ $cb = $this->getCallbackClient();
+ if (count($host_config) == 0) {
+ $cb->update(
+ $error_el_id,
+ "API host $api_host does not exist"
+ );
+ $cb->show($error_el_id);
+ return $state;
+ }
+
+ $result = $this->getModule('api')->get(['directors'], $api_host);
+ if ($result->error !== 0) {
+ $cb->update(
+ $error_el_id,
+ $result->output
+ );
+ $cb->show($error_el_id);
+ return $state;
+ }
+ $director = $result->output[0];
+ if ($host_config['auth_type'] === AuthBasic::NAME) {
+ $username = $host_config['login'];
+ $config = [
+ 'username' => $username,
+ 'bconsole_cfg_path' => ''
+ ];
+ if (!empty($console) && !empty($director)) {
+ $config['console'] = $console;
+ $config['director'] = $director;
+ }
+ $result = $this->getModule('api')->set([
+ 'basic',
+ 'users',
+ $username
+ ], $config, $api_host);
+ if ($result->error === 0) {
+ $state = true;
+ } else {
+ $cb->update(
+ $error_el_id,
+ $result->output
+ );
+ $cb->show($error_el_id);
+ return $state;
+ }
+ } elseif ($host_config['auth_type'] === AuthOAuth2::NAME) {
+ $client_id = $host_config['client_id'];
+ $config = [
+ 'client_id' => $client_id,
+ 'bconsole_cfg_path' => ''
+ ];
+ if (!empty($console) && !empty($director)) {
+ $config['console'] = $console;
+ $config['director'] = $director;
+ }
+ $result = $this->getModule('api')->set([
+ 'oauth2',
+ 'clients',
+ $client_id
+ ], $config, $api_host);
+
+ $oa2 = new OAuth2Record();
+ $oa2::deleteByPk($api_host);
+
+ if ($result->error === 0) {
+ $state = true;
+ } else {
+ $cb->update(
+ $error_el_id,
+ $result->output
+ );
+ $cb->show($error_el_id);
+ return $state;
+ }
+ }
+ return $state;
+ }
+
+ /**
+ * Unassign console from API host.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function unassignAPIHostConsole($sender, $param)
+ {
+ $api_host = $param->getCallbackParameter();
+ $success = $this->unassignAPIHostConsoleInternal($api_host);
+ if ($success) {
+ $this->setAPIHostJobs(
+ $this->APIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_access_window_error'
+ );
+ $this->setAPIHostConsole($api_host, false);
+ $cb = $this->getCallbackClient();
+ $cb->hide('api_host_access_window_console');
+ }
+ }
+
+ /**
+ * Unassign console from API host (internal);
+ *
+ * @param string $api_host API host name
+ * @return bool true if console unassigned successfully, otherwise false
+ */
+ private function unassignAPIHostConsoleInternal($api_host)
+ {
+ $host_config = $this->getModule('host_config')->getHostConfig($api_host);
+ if (count($host_config) == 0) {
+ // API host does not exist
+ return;
+ }
+
+ $state = false;
+ if ($host_config['auth_type'] === AuthBasic::NAME) {
+ $basic_users_result = $this->getModule('api')->get(
+ ['basic', 'users', $host_config['login']],
+ $api_host
+ );
+ if ($basic_users_result->error !== 0) {
+ return $state;
+ }
+ $basic_users_result->output->bconsole_cfg_path = '';
+
+ $basic_users_result = $this->getModule('api')->set(
+ ['basic', 'users', $host_config['login']],
+ (array) $basic_users_result->output,
+ $api_host
+ );
+ $state = ($basic_users_result->error === 0);
+ } elseif ($host_config['auth_type'] === AuthOAuth2::NAME) {
+ $oauth2_client_result = $this->getModule('api')->get(
+ ['oauth2', 'clients', $host_config['client_id']],
+ $api_host
+ );
+ if ($oauth2_client_result->error !== 0) {
+ return $state;
+ }
+ $oauth2_client_result->output->bconsole_cfg_path = '';
+
+ $oauth2_client_result = $this->getModule('api')->set(
+ ['oauth2', 'clients', $host_config['client_id']],
+ (array) $oauth2_client_result->output,
+ $api_host
+ );
+
+ $oa2 = new OAuth2Record();
+ $oa2::deleteByPk($api_host);
+
+ $state = ($oauth2_client_result->error === 0);
+ }
+ return $state;
+ }
+
/**
* Load data in API host group modal window.
*
@@ -2355,6 +2934,9 @@ public function saveAPIHostGroup($sender, $param)
}
}
+ // refresh user window
+ $this->initUserWindow();
+
// refresh API host group window
$this->initAPIHostGroupWindow();
}
@@ -2382,5 +2964,151 @@ public function removeAPIHostGroups($sender, $param)
}
}
$this->setAPIHostGroupList(null, null);
+
+ // refresh user window
+ $this->initUserWindow();
+ }
+
+
+ /**
+ * Load API host groups access settings window.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function loadAPIHostGroupAPIHostResourceAccessWindow($sender, $param)
+ {
+ $host_group = $this->APIHostGroupAPIHostResourceAccessName->Value;
+ $ahg = $this->getModule('host_group_config');
+ $is_host_group = $ahg->isHostGroupConfig($host_group);
+ if ($is_host_group) {
+ $api_hosts = $ahg->getAPIHostsByGroups([$host_group]);
+ if (count($api_hosts) == 1 && $api_hosts[0] === HostConfig::MAIN_CATALOG_HOST) {
+ $host_config = $this->getModule('host_config')->getConfig();
+ $api_hosts = array_keys($host_config);
+ }
+ // strip main API host
+ $cbf = function ($host) {
+ return ($host !== HostConfig::MAIN_CATALOG_HOST);
+ };
+ $api_hosts = array_filter($api_hosts, $cbf);
+ $this->setAPIHosts($this->APIHostGroupAPIHostList, null, true, $api_hosts);
+ }
+ }
+
+ /**
+ * Set API host groups access settings window.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function setAPIHostGroupAPIHostResourceAccessWindow($sender, $param)
+ {
+ $api_host = $this->APIHostGroupAPIHostList->getSelectedValue();
+ $this->setAPIHostJobs(
+ $this->APIHostGroupAPIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_group_access_window_error'
+ );
+ $this->setAPIHostGroupAPIHostConsole($api_host);
+ }
+
+ /**
+ * Set user API host console.
+ *
+ * @param string $api_host API host name
+ * @param bool $set_state determine if state (all/selected resources) should be changed
+ */
+ private function setAPIHostGroupAPIHostConsole($api_host, $set_state = true)
+ {
+ $console = $this->isAPIHostConsole($api_host);
+ $cb = $this->getCallbackClient();
+ $cb->hide('api_host_group_access_window_console');
+ if (!empty($console)) {
+ $cb->show('api_host_group_access_window_select_jobs');
+ $cb->show('api_host_group_access_window_console');
+ if ($set_state) {
+ $this->APIHostGroupAPIHostResourceAccessSelectedResources->Checked = true;
+ }
+ } else {
+ if ($set_state) {
+ $cb->hide('api_host_group_access_window_select_jobs');
+ $this->APIHostGroupAPIHostResourceAccessAllResources->Checked = true;
+ }
+ }
+ }
+
+ /**
+ * Unassign console from API host.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function unassignAPIHostGroupAPIHostConsole($sender, $param)
+ {
+ $api_host = $param->getCallbackParameter();
+ $success = $this->unassignAPIHostConsoleInternal($api_host);
+ if ($success) {
+ $this->setAPIHostJobs(
+ $this->APIHostGroupAPIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_group_access_window_error'
+ );
+ $this->setAPIHostGroupAPIHostConsole($api_host, false);
+ $cb = $this->getCallbackClient();
+ $cb->hide('api_host_group_access_window_console');
+ }
+ }
+
+ /**
+ * Save API host groups access settings window.
+ *
+ * @param TCallback $sender sender object
+ * @param TCallbackEventParameter $param callback parameter
+ */
+ public function saveAPIHostGroupAPIHostResourceAccess($sender, $param)
+ {
+ $api_host = $this->APIHostGroupAPIHostList->getSelectedValue();
+ if ($this->APIHostGroupAPIHostResourceAccessAllResources->Checked) {
+ $state = $this->setResourceConsole(
+ $api_host,
+ '',
+ 'api_host_group_access_window_error'
+ );
+ if ($state) {
+ $this->setAPIHostJobs(
+ $this->APIHostGroupAPIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_group_access_window_error'
+ );
+ $this->setAPIHostConsole($api_host);
+ }
+ } elseif ($this->APIHostGroupAPIHostResourceAccessSelectedResources->Checked) {
+ $selected_indices = $this->APIHostGroupAPIHostResourceAccessJobs->getSelectedIndices();
+ $jobs = [];
+ foreach ($selected_indices as $indice) {
+ for ($i = 0; $i < $this->APIHostGroupAPIHostResourceAccessJobs->getItemCount(); $i++) {
+ if ($i === $indice) {
+ $jobs[] = $this->APIHostGroupAPIHostResourceAccessJobs->Items[$i]->Value;
+ }
+ }
+ }
+ $console = $this->setJobResourceAccess($api_host, $jobs);
+ if ($console) {
+ $state = $this->setResourceConsole(
+ $api_host,
+ $console,
+ 'api_host_group_access_window_error'
+ );
+ if ($state) {
+ $this->setAPIHostJobs(
+ $this->APIHostGroupAPIHostResourceAccessJobs,
+ $api_host,
+ 'api_host_group_access_window_error'
+ );
+ }
+ $this->setAPIHostGroupAPIHostConsole($api_host);
+ }
+ }
}
}