diff --git a/CHANGELOG.md b/CHANGELOG.md
index 02e3c3793a..5ba48d92e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ All notable changes to the Wazuh app project will be documented in this file.
- Added a title to the agent name input of the deploy a new agent section. [#5429](https://github.com/wazuh/wazuh-kibana-app/pull/5429)
- Added callout below the agent name entry of the deploy a new agent section. [#5429](https://github.com/wazuh/wazuh-kibana-app/pull/5429)
- Added new CLI to generate API data from specification file [#5519](https://github.com/wazuh/wazuh-kibana-app/pull/5519)
+- Added specific RBAC permissions to Security section [#5551](https://github.com/wazuh/wazuh-kibana-app/pull/5551)
### Changed
diff --git a/docker/imposter/security/security-actions.json b/docker/imposter/security/security-actions.json
new file mode 100644
index 0000000000..88ba661fa8
--- /dev/null
+++ b/docker/imposter/security/security-actions.json
@@ -0,0 +1,716 @@
+{
+ "data": {
+ "active-response:command": {
+ "description": "Execute active response commands in the agents",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["active-response:command"],
+ "resources": ["agent:id:001", "agent:group:atlantic"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /active-response"]
+ },
+ "agent:delete": {
+ "description": "Delete agents",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["agent:delete"],
+ "resources": ["agent:id:010", "agent:group:pacific"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["DELETE /agents"]
+ },
+ "agent:read": {
+ "description": "Access agents information (id, name, group, last keep alive, etc)",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["agent:read"],
+ "resources": ["agent:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /agents",
+ "GET /agents/{agent_id}/config/{component}/{configuration}",
+ "GET /agents/{agent_id}/group/is_sync",
+ "GET /agents/{agent_id}/key",
+ "GET /agents/{agent_id}/daemons/stats",
+ "GET /agents/{agent_id}/stats/{component}",
+ "GET /groups/{group_id}/agents",
+ "GET /agents/no_group",
+ "GET /agents/outdated",
+ "GET /agents/stats/distinct",
+ "GET /agents/summary/os",
+ "GET /agents/summary/status",
+ "GET /overview/agents"
+ ]
+ },
+ "agent:create": {
+ "description": "Create new agents",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["agent:create"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "POST /agents",
+ "POST /agents/insert",
+ "POST /agents/insert/quick"
+ ]
+ },
+ "agent:modify_group": {
+ "description": "Change the group of agents",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["agent:modify_group"],
+ "resources": ["agent:id:004", "agent:group:us-east"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "DELETE /agents/{agent_id}/group",
+ "DELETE /agents/{agent_id}/group/{group_id}",
+ "PUT /agents/{agent_id}/group/{group_id}",
+ "DELETE /agents/group",
+ "PUT /agents/group"
+ ]
+ },
+ "group:modify_assignments": {
+ "description": "Change the agents assigned to the group",
+ "resources": ["group:id"],
+ "example": {
+ "actions": ["group:modify_assignments"],
+ "resources": ["group:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "DELETE /agents/{agent_id}/group",
+ "DELETE /agents/{agent_id}/group/{group_id}",
+ "PUT /agents/{agent_id}/group/{group_id}",
+ "DELETE /agents/group",
+ "PUT /agents/group"
+ ]
+ },
+ "agent:restart": {
+ "description": "Restart agents",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["agent:restart"],
+ "resources": ["agent:id:050", "agent:id:049"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "PUT /agents/{agent_id}/restart",
+ "PUT /agents/group/{group_id}/restart",
+ "PUT /agents/node/{node_id}/restart",
+ "PUT /agents/restart"
+ ]
+ },
+ "agent:upgrade": {
+ "description": "Upgrade the version of the agents",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["agent:upgrade"],
+ "resources": ["agent:id:001", "agent:group:mediterranean"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "PUT /agents/upgrade",
+ "PUT /agents/upgrade_custom",
+ "GET /agents/upgrade_result"
+ ]
+ },
+ "group:delete": {
+ "description": "Delete agent groups",
+ "resources": ["group:id"],
+ "example": {
+ "actions": ["group:delete"],
+ "resources": ["group:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["DELETE /groups"]
+ },
+ "group:read": {
+ "description": "Access agent groups information (id, name, agents, etc)",
+ "resources": ["group:id"],
+ "example": {
+ "actions": ["group:create"],
+ "resources": ["group:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /groups",
+ "GET /groups/{group_id}/agents",
+ "GET /groups/{group_id}/configuration",
+ "GET /groups/{group_id}/files",
+ "GET /groups/{group_id}/files/{file_name}/json",
+ "GET /groups/{group_id}/files/{file_name}/xml",
+ "GET /overview/agents"
+ ]
+ },
+ "group:create": {
+ "description": "Create new agent groups",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["group:create"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["POST /groups"]
+ },
+ "group:update_config": {
+ "description": "Change the configuration of agent groups",
+ "resources": ["group:id"],
+ "example": {
+ "actions": ["group:update_config"],
+ "resources": ["group:id:*"],
+ "effect": "deny"
+ },
+ "related_endpoints": ["PUT /groups/{group_id}/configuration"]
+ },
+ "cluster:read": {
+ "description": "Read Wazuh's cluster nodes configuration",
+ "resources": ["node:id"],
+ "example": {
+ "actions": ["cluster:read"],
+ "resources": ["node:id:worker1", "node:id:worker3"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "PUT /agents/node/{node_id}/restart",
+ "GET /cluster/local/info",
+ "GET /cluster/nodes",
+ "GET /cluster/healthcheck",
+ "GET /cluster/ruleset/synchronization",
+ "GET /cluster/local/config",
+ "GET /cluster/{node_id}/status",
+ "GET /cluster/{node_id}/info",
+ "GET /cluster/{node_id}/configuration",
+ "GET /cluster/{node_id}/daemons/stats",
+ "GET /cluster/{node_id}/stats",
+ "GET /cluster/{node_id}/stats/hourly",
+ "GET /cluster/{node_id}/stats/weekly",
+ "GET /cluster/{node_id}/stats/analysisd",
+ "GET /cluster/{node_id}/stats/remoted",
+ "GET /cluster/{node_id}/logs",
+ "GET /cluster/{node_id}/logs/summary",
+ "PUT /cluster/restart",
+ "GET /cluster/configuration/validation",
+ "GET /cluster/{node_id}/configuration/{component}/{configuration}"
+ ]
+ },
+ "agent:reconnect": {
+ "description": "Force reconnect agents",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["agent:reconnect"],
+ "resources": ["agent:id:050", "agent:id:049"],
+ "effect": "deny"
+ },
+ "related_endpoints": ["PUT /agents/reconnect"]
+ },
+ "ciscat:read": {
+ "description": "Access CIS-CAT results for agents",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["ciscat:read"],
+ "resources": ["agent:id:001", "agent:id:003", "agent:group:default"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "GET /ciscat/{agent_id}/results",
+ "GET /experimental/ciscat/results"
+ ]
+ },
+ "cluster:status": {
+ "description": "Check Wazuh's cluster general status",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["cluster:status"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["GET /cluster/status"]
+ },
+ "cluster:read_api_config": {
+ "description": "Check Wazuh's cluster nodes API configuration",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["cluster:read_api_config"],
+ "resources": ["node:id:worker1", "node:id:worker3"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["GET /cluster/api/config"]
+ },
+ "cluster:update_config": {
+ "description": "Change the Wazuh's cluster node configuration",
+ "resources": ["node:id"],
+ "example": {
+ "actions": ["cluster:update_config"],
+ "resources": ["node:id:worker1"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /cluster/{node_id}/configuration"]
+ },
+ "cluster:restart": {
+ "description": "Restart Wazuh's cluster nodes",
+ "resources": ["node:id"],
+ "example": {
+ "actions": ["cluster:restart"],
+ "resources": ["node:id:worker1"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /cluster/restart"]
+ },
+ "lists:read": {
+ "description": "Read cdb lists files",
+ "resources": ["list:file"],
+ "example": {
+ "actions": ["lists:read"],
+ "resources": ["list:file:audit-keys"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "GET /lists",
+ "GET /lists/files/{filename}",
+ "GET /lists/files"
+ ]
+ },
+ "lists:update": {
+ "description": "Update or upload cdb lists files",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["lists:update"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /lists/files/{filename}"]
+ },
+ "lists:delete": {
+ "description": "Delete cdb lists files",
+ "resources": ["list:file"],
+ "example": {
+ "actions": ["lists:delete"],
+ "resources": ["list:file:audit-keys"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "PUT /lists/files/{filename}",
+ "DELETE /lists/files/{filename}"
+ ]
+ },
+ "logtest:run": {
+ "description": "Run logtest tool or end a logtest session",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["logtest:run"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /logtest", "DELETE /logtest/sessions/{token}"]
+ },
+ "manager:read": {
+ "description": "Read Wazuh manager configuration",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["manager:read"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /manager/status",
+ "GET /manager/info",
+ "GET /manager/configuration",
+ "GET /manager/daemons/stats",
+ "GET /manager/stats",
+ "GET /manager/stats/hourly",
+ "GET /manager/stats/weekly",
+ "GET /manager/stats/analysisd",
+ "GET /manager/stats/remoted",
+ "GET /manager/logs",
+ "GET /manager/logs/summary",
+ "PUT /manager/restart",
+ "GET /manager/configuration/validation",
+ "GET /manager/configuration/{component}/{configuration}"
+ ]
+ },
+ "manager:update_config": {
+ "description": "Update current Wazuh manager configuration",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["manager:update_config"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /manager/configuration"]
+ },
+ "manager:read_api_config": {
+ "description": "Read Wazuh manager API configuration",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["manager:read_api_config"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["GET /manager/api/config"]
+ },
+ "manager:restart": {
+ "description": "Restart Wazuh managers",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["manager:restart"],
+ "resources": ["*:*:*"],
+ "effect": "deny"
+ },
+ "related_endpoints": ["PUT /manager/restart"]
+ },
+ "mitre:read": {
+ "description": "Access information from MITRE database",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["mitre:read"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /mitre/groups",
+ "GET /mitre/metadata",
+ "GET /mitre/mitigations",
+ "GET /mitre/references",
+ "GET /mitre/software",
+ "GET /mitre/tactics",
+ "GET /mitre/techniques"
+ ]
+ },
+ "rootcheck:run": {
+ "description": "Run agents rootcheck scan",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["rootcheck:run"],
+ "resources": ["agent:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /rootcheck"]
+ },
+ "rootcheck:read": {
+ "description": "Access information from agents rootcheck database",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["rootcheck:read"],
+ "resources": ["agent:id:011"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /rootcheck/{agent_id}",
+ "GET /rootcheck/{agent_id}/last_scan"
+ ]
+ },
+ "rootcheck:clear": {
+ "description": "Clear the agents rootcheck database",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["rootcheck:clear"],
+ "resources": ["agent:id:*"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "DELETE /rootcheck/{agent_id}",
+ "DELETE /experimental/rootcheck"
+ ]
+ },
+ "rules:read": {
+ "description": "Read rules files",
+ "resources": ["rule:file"],
+ "example": {
+ "actions": ["rules:read"],
+ "resources": ["rule:file:0610-win-ms_logs_rules.xml"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /rules",
+ "GET /rules/groups",
+ "GET /rules/requirement/{requirement}",
+ "GET /rules/files",
+ "GET /rules/files/{filename}"
+ ]
+ },
+ "rules:update": {
+ "description": "Update or upload custom rule files",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["rules:update"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /rules/files/{filename}"]
+ },
+ "rules:delete": {
+ "description": "Delete custom rule files",
+ "resources": ["rule:file"],
+ "example": {
+ "actions": ["rules:delete"],
+ "resources": ["rule:file:0610-win-ms_logs_rules.xml"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "PUT /rules/files/{filename}",
+ "DELETE /rules/files/{filename}"
+ ]
+ },
+ "sca:read": {
+ "description": "Access agents security configuration assessment",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["sca:read"],
+ "resources": ["agent:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /sca/{agent_id}",
+ "GET /sca/{agent_id}/checks/{policy_id}"
+ ]
+ },
+ "syscheck:run": {
+ "description": "Run agents syscheck scan",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["syscheck:run"],
+ "resources": ["agent:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /syscheck"]
+ },
+ "syscheck:read": {
+ "description": "Access information from agents syscheck database",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["syscheck:read"],
+ "resources": ["agent:id:011", "agent:group:us-west"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /syscheck/{agent_id}",
+ "GET /syscheck/{agent_id}/last_scan"
+ ]
+ },
+ "syscheck:clear": {
+ "description": "Clear the agents syscheck database",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["syscheck:clear"],
+ "resources": ["agent:id:*"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "DELETE /syscheck/{agent_id}",
+ "DELETE /experimental/syscheck"
+ ]
+ },
+ "decoders:read": {
+ "description": "Read decoders files",
+ "resources": ["decoder:file"],
+ "example": {
+ "actions": ["decoders:read"],
+ "resources": ["decoder:file:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /decoders",
+ "GET /decoders/files",
+ "GET /decoders/files/{filename}",
+ "GET /decoders/parents"
+ ]
+ },
+ "decoders:update": {
+ "description": "Update or upload custom decoder files",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["decoders:update"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /decoders/files/{filename}"]
+ },
+ "decoders:delete": {
+ "description": "Delete custom decoder files",
+ "resources": ["decoder:file"],
+ "example": {
+ "actions": ["decoders:delete"],
+ "resources": ["decoder:file:local_decoder.xml"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "PUT /decoders/files/{filename}",
+ "DELETE /decoders/files/{filename}"
+ ]
+ },
+ "syscollector:read": {
+ "description": "Access agents syscollector information",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["syscollector:read"],
+ "resources": ["agent:id:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /experimental/syscollector/hardware",
+ "GET /experimental/syscollector/netaddr",
+ "GET /experimental/syscollector/netiface",
+ "GET /experimental/syscollector/netproto",
+ "GET /experimental/syscollector/os",
+ "GET /experimental/syscollector/packages",
+ "GET /experimental/syscollector/ports",
+ "GET /experimental/syscollector/processes",
+ "GET /experimental/syscollector/hotfixes",
+ "GET /syscollector/{agent_id}/hardware",
+ "GET /syscollector/{agent_id}/hotfixes",
+ "GET /syscollector/{agent_id}/netaddr",
+ "GET /syscollector/{agent_id}/netiface",
+ "GET /syscollector/{agent_id}/netproto",
+ "GET /syscollector/{agent_id}/os",
+ "GET /syscollector/{agent_id}/packages",
+ "GET /syscollector/{agent_id}/ports",
+ "GET /syscollector/{agent_id}/processes"
+ ]
+ },
+ "security:edit_run_as": {
+ "description": "Change the value of the allow_run_as flag for a user",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["security:edit_run_as"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /security/users/{user_id}/run_as"]
+ },
+ "security:read": {
+ "description": "Access information about system security resources",
+ "resources": ["policy:id", "role:id", "user:id", "rule:id"],
+ "example": {
+ "actions": ["security:read"],
+ "resources": ["policy:id:*", "role:id:2", "user:id:5", "rule:id:3"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /security/users",
+ "GET /security/roles",
+ "GET /security/rules",
+ "GET /security/policies"
+ ]
+ },
+ "security:create_user": {
+ "description": "Create new system users",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["security:create_user"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["POST /security/users"]
+ },
+ "security:delete": {
+ "description": "Delete system security resources",
+ "resources": ["policy:id", "role:id", "user:id", "rule:id"],
+ "example": {
+ "actions": ["security:update"],
+ "resources": ["policy:id:*", "role:id:3", "user:id:4", "rule:id:2"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "DELETE /security/users",
+ "DELETE /security/roles",
+ "DELETE /security/rules",
+ "DELETE /security/policies",
+ "DELETE /security/users/{user_id}/roles",
+ "DELETE /security/roles/{role_id}/policies",
+ "DELETE /security/roles/{role_id}/rules"
+ ]
+ },
+ "security:update": {
+ "description": "Update the information of system security resources",
+ "resources": ["policy:id", "role:id", "user:id", "rule:id"],
+ "example": {
+ "actions": ["security:update"],
+ "resources": ["policy:id:*", "role:id:4", "user:id:3", "rule:id:4"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "PUT /security/users/{user_id}",
+ "PUT /security/roles/{role_id}",
+ "PUT /security/rules/{rule_id}",
+ "PUT /security/policies/{policy_id}",
+ "POST /security/users/{user_id}/roles",
+ "POST /security/roles/{role_id}/policies",
+ "POST /security/roles/{role_id}/rules"
+ ]
+ },
+ "security:create": {
+ "description": "Create new system security resources",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["security:create"],
+ "resources": ["*:*:*"],
+ "effect": "deny"
+ },
+ "related_endpoints": [
+ "POST /security/roles",
+ "POST /security/rules",
+ "POST /security/policies"
+ ]
+ },
+ "security:read_config": {
+ "description": "Read current system security configuration",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["security:read_config"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["GET /security/config"]
+ },
+ "security:update_config": {
+ "description": "Update current system security configuration",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["security:update_config"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /security/config", "DELETE /security/config"]
+ },
+ "task:status": {
+ "description": "Access task's status information",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["task:status"],
+ "resources": ["*:*:*"],
+ "effect": "deny"
+ },
+ "related_endpoints": ["GET /tasks/status"]
+ },
+ "vulnerability:run": {
+ "description": "Allow running a vulnerability detector scan",
+ "resources": ["*:*"],
+ "example": {
+ "actions": ["vulnerability:run"],
+ "resources": ["*:*:*"],
+ "effect": "allow"
+ },
+ "related_endpoints": ["PUT /vulnerability"]
+ },
+ "vulnerability:read": {
+ "description": "Allow reading agents' vulnerabilities information",
+ "resources": ["agent:id", "agent:group"],
+ "example": {
+ "actions": ["vulnerability:read"],
+ "resources": ["agent:id:011", "agent:group:us-west"],
+ "effect": "allow"
+ },
+ "related_endpoints": [
+ "GET /vulnerability/{agent_id}",
+ "GET /vulnerability/{agent_id}/last_scan",
+ "GET /vulnerability/{agent_id}/summary/{field}"
+ ]
+ }
+ },
+ "error": 0
+}
diff --git a/docker/imposter/security/security-me-policies.js b/docker/imposter/security/security-me-policies.js
new file mode 100644
index 0000000000..90af38c452
--- /dev/null
+++ b/docker/imposter/security/security-me-policies.js
@@ -0,0 +1,349 @@
+var userPoliciesMap = {
+ PLUGIN_SECURITY_USERS_ALL: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_DENY_USERS: {
+ 'security:read': {
+ 'user:id:*': 'deny',
+ 'role:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_DENY_ROLES: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_DENY_USERS_ROLES: {
+ 'security:read': {
+ 'user:id:*': 'deny',
+ 'role:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_DENY_CREATE_USER: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_ALLOW_CREATE_USER_DENY_EDIT_RUN_AS: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'allow',
+ },
+ 'security:edit_run_as': {
+ '*:*:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_ALLOW_EDIT_USER: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'allow',
+ },
+ 'security:update': {
+ 'user:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_ALLOW_EDIT_USER_ID_101: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'allow',
+ },
+ 'security:update': {
+ 'user:id:101': 'deny',
+ 'user:id:102': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_ALLOW_CREATE_USER_DENY_UPDATE_USER: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'allow',
+ },
+ 'security:update': {
+ 'user:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_ALLOW_CREATE_USER_ALLOW_UPDATE_USER_DENY_EDIT_RUN_AS: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'allow',
+ },
+ 'security:update': {
+ 'user:id:*': 'allow',
+ },
+ 'security:edit_run_as': {
+ 'user:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_DENY_EDIT_USER: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'allow',
+ },
+ 'security:update': {
+ 'user:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_USERS_DENY_DELETE_USER_101: {
+ 'security:read': {
+ 'user:id:*': 'allow',
+ 'role:id:*': 'allow',
+ },
+ 'security:create_user': {
+ '*:*:*': 'allow',
+ },
+ 'security:delete': {
+ 'user:id:100': 'allow',
+ 'user:id:101': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_ALLOW_READ_ROLES_POLICIES: {
+ 'security:read': {
+ 'role:id:*': 'allow',
+ 'policy:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_ALLOW_READ_POLICIES_DENY_READ_ROLE: {
+ 'security:read': {
+ 'role:id:*': 'deny',
+ 'policy:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_DENY_READ_POLICIES_ALLOW_READ_ROLE: {
+ 'security:read': {
+ 'role:id:*': 'allow',
+ 'policy:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_DENY_READ_POLICIES_DENY_READ_ROLE: {
+ 'security:read': {
+ 'role:id:*': 'deny',
+ 'policy:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_DENY_CREATE_POLICY: {
+ 'security:read': {
+ 'role:id:*': 'allow',
+ 'policy:id:*': 'allow',
+ },
+ 'security:create': {
+ '*:*:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_ALL_DENY_DELETE_ROLE_101_ALLOW_ROLE_102: {
+ 'security:read': {
+ 'role:id:*': 'allow',
+ 'policy:id:*': 'allow',
+ },
+ 'security:delete': {
+ 'role:id:101': 'deny',
+ 'role:id:102': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_DENY_UPDATE_ROLE_101_ALLOW_UPDATE_ROLE_102: {
+ 'security:read': {
+ 'role:id:*': 'allow',
+ 'policy:id:*': 'allow',
+ },
+ 'security:update': {
+ 'role:id:101': 'deny',
+ 'role:id:102': 'allow',
+ },
+ 'security:delete': {
+ 'role:id:101': 'deny',
+ 'role:id:102': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_POLICIES_ALLOW_READ_POLICIES: {
+ 'security:read': {
+ 'policy:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_POLICIES_DENY_READ_POLICIES: {
+ 'security:read': {
+ 'policy:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_POLICIES_ALLOW_READ_POLICIES_DENY_DELETE_101_ALLOW_DELETE_102:
+ {
+ 'security:read': {
+ 'policy:id:*': 'allow',
+ },
+ 'security:delete': {
+ 'policy:id:101': 'deny',
+ 'policy:id:102': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_POLICIES_DENY_CREATE_POLICY: {
+ 'security:read': {
+ 'policy:id:*': 'allow',
+ },
+ 'security:create': {
+ '*:*:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_POLICIES_DENY_UPDATE_POLICY: {
+ 'security:read': {
+ 'policy:id:*': 'allow',
+ },
+ 'security:update': {
+ 'policy:id:100': 'deny',
+ 'policy:id:101': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_POLICIES_ALLOW_CREATE_POLICY: {
+ 'security:read': {
+ 'policy:id:*': 'allow',
+ },
+ 'security:create': {
+ '*:*:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_ALLOW_READ_ROLES_MAPPING: {
+ 'security:read': {
+ 'rule:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_DENY_READ_ROLES_MAPPING: {
+ 'security:read': {
+ 'role:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_DENY_READ_RULES_MAPPING: {
+ 'security:read': {
+ 'rule:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_DENY_READ_ROLE_DENY_READ_RULES_MAPPING: {
+ 'security:read': {
+ 'role:id:*': 'deny',
+ 'rule:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_ALLOW_READ_ROLES_MAPPING_DENY_DELETE_ROLE_MAPPING_101:
+ {
+ 'security:read': {
+ 'rule:id:*': 'allow',
+ },
+ 'security:delete': {
+ 'rule:id:101': 'deny',
+ 'rule:id:102': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_ALLOW_READ_ROLES_MAPPING_DENY_CREATE_ROLE_MAPPING:
+ {
+ 'security:read': {
+ 'rule:id:*': 'allow',
+ },
+ 'security:create': {
+ '*:*:*:': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_ALLOW_READ_ROLES_MAPPING_ALLOW_CREATE_ROLE_MAPPING:
+ {
+ 'security:read': {
+ 'rule:id:*': 'allow',
+ },
+ 'security:create': {
+ '*:*:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_ALLOW_READ_ROLES_MAPPING_ALLOW_CREATE_ROLE_MAPPING_ALLOW_UPDATE_ROLE_MAPPING_DENY_DELETE_ROLE_MAPPING:
+ {
+ 'security:read': {
+ 'rule:id:*': 'allow',
+ },
+ 'security:create': {
+ '*:*:*': 'allow',
+ },
+ 'security:update': {
+ 'rule:id:*': 'allow',
+ },
+ 'security:delete': {
+ 'rule:id:*': 'deny',
+ },
+ rbac_mode: 'black',
+ },
+ PLUGIN_SECURITY_ROLES_MAPPING_ALLOW_READ_ROLES_MAPPING_ALLOW_CREATE_ROLE_MAPPING_DENY_UPDATE_ROLE_MAPPING_ALLOW_DELETE_ROLE_MAPPING:
+ {
+ 'security:read': {
+ 'rule:id:*': 'allow',
+ },
+ 'security:create': {
+ '*:*:*': 'allow',
+ },
+ 'security:update': {
+ 'rule:id:*': 'deny',
+ },
+ 'security:delete': {
+ 'rule:id:*': 'allow',
+ },
+ rbac_mode: 'black',
+ },
+};
+
+var selectedUserPolicy = userPoliciesMap['PLUGIN_SECURITY_USERS_ALL'];
+
+var response = {
+ data: selectedUserPolicy,
+ message: 'Current user processed policies information was returned',
+ error: 0,
+};
+
+respond().withStatusCode(200).withData(JSON.stringify(response));
diff --git a/docker/imposter/security/security_policies.json b/docker/imposter/security/security-policies.json
similarity index 95%
rename from docker/imposter/security/security_policies.json
rename to docker/imposter/security/security-policies.json
index 565a90284c..928b625433 100644
--- a/docker/imposter/security/security_policies.json
+++ b/docker/imposter/security/security-policies.json
@@ -402,6 +402,26 @@
"effect": "deny"
},
"roles": [100]
+ },
+ {
+ "id": 101,
+ "name": "custom_manager_deny_read",
+ "policy": {
+ "actions": ["manager:read", "cluster:read"],
+ "resources": ["*:*:*", "node:id:*"],
+ "effect": "deny"
+ },
+ "roles": [100]
+ },
+ {
+ "id": 102,
+ "name": "custom_manager_deny_read2",
+ "policy": {
+ "actions": ["manager:read", "cluster:read"],
+ "resources": ["*:*:*", "node:id:*"],
+ "effect": "deny"
+ },
+ "roles": [100]
}
],
"total_affected_items": 36,
diff --git a/docker/imposter/security/security_roles.json b/docker/imposter/security/security-roles.json
similarity index 82%
rename from docker/imposter/security/security_roles.json
rename to docker/imposter/security/security-roles.json
index a6ea88acb3..02ad41c2ae 100644
--- a/docker/imposter/security/security_roles.json
+++ b/docker/imposter/security/security-roles.json
@@ -52,6 +52,20 @@
"policies": [29, 30],
"users": [],
"rules": []
+ },
+ {
+ "id": 101,
+ "name": "custom_role",
+ "policies": [29, 30],
+ "users": [],
+ "rules": []
+ },
+ {
+ "id": 102,
+ "name": "custom_role2",
+ "policies": [29, 30],
+ "users": [],
+ "rules": []
}
],
"total_affected_items": 8,
diff --git a/docker/imposter/security/security-rules.json b/docker/imposter/security/security-rules.json
new file mode 100644
index 0000000000..91fa8308bc
--- /dev/null
+++ b/docker/imposter/security/security-rules.json
@@ -0,0 +1,57 @@
+{
+ "data": {
+ "affected_items": [
+ {
+ "id": 1,
+ "name": "wui_elastic_admin",
+ "rule": {
+ "FIND": {
+ "username": "elastic"
+ }
+ },
+ "roles": [
+ 1
+ ]
+ },
+ {
+ "id": 2,
+ "name": "wui_opendistro_admin",
+ "rule": {
+ "FIND": {
+ "username": "admin"
+ }
+ },
+ "roles": [
+ 1
+ ]
+ },
+ {
+ "id": 101,
+ "name": "custom_rule1",
+ "rule": {
+ "FIND": {
+ "username": "admin"
+ }
+ },
+ "roles": [
+ 1
+ ]
+ },
+ {
+ "id": 102,
+ "name": "custom_rule2",
+ "rule": {
+ "FIND": {
+ "username": "admin"
+ }
+ },
+ "roles": [
+ 2
+ ]
+ }
+ ],
+ "total_affected_items": 4,
+ "total_failed_items": 0,
+ "failed_items": []
+ }
+}
diff --git a/docker/imposter/security/users.json b/docker/imposter/security/users.json
new file mode 100644
index 0000000000..8292e68ef1
--- /dev/null
+++ b/docker/imposter/security/users.json
@@ -0,0 +1,63 @@
+{
+ "data": {
+ "affected_items": [
+ {
+ "id": 1,
+ "username": "wazuh",
+ "allow_run_as": true,
+ "roles": [1]
+ },
+ {
+ "id": 2,
+ "username": "wazuh-wui",
+ "allow_run_as": true,
+ "roles": []
+ },
+ {
+ "id": 3,
+ "username": "administrator",
+ "allow_run_as": true,
+ "roles": [2]
+ },
+ {
+ "id": 4,
+ "username": "guest",
+ "allow_run_as": false,
+ "roles": []
+ },
+ {
+ "id": 5,
+ "username": "normal",
+ "allow_run_as": false,
+ "roles": [4, 5, 6]
+ },
+ {
+ "id": 6,
+ "username": "ossec",
+ "allow_run_as": true,
+ "roles": [2, 5]
+ },
+ {
+ "id": 7,
+ "username": "rbac",
+ "allow_run_as": false,
+ "roles": [3, 4, 5]
+ },
+ {
+ "id": 100,
+ "username": "python",
+ "allow_run_as": true,
+ "roles": []
+ },
+ {
+ "id": 101,
+ "username": "custom_user",
+ "allow_run_as": true,
+ "roles": []
+ }
+ ],
+ "total_affected_items": 8,
+ "total_failed_items": 0,
+ "failed_items": []
+ }
+}
diff --git a/docker/imposter/wazuh-config.yml b/docker/imposter/wazuh-config.yml
index 94298f0363..4b56023218 100755
--- a/docker/imposter/wazuh-config.yml
+++ b/docker/imposter/wazuh-config.yml
@@ -649,6 +649,9 @@ resources:
# Get current user processed policies
- method: GET
path: /security/users/me/policies
+ response:
+ statusCode: 200
+ scriptFile: security/security-me-policies.js
# Revoke JWT tokens
- method: PUT
@@ -661,6 +664,9 @@ resources:
# List RBAC actions
- method: GET
path: /security/actions
+ response:
+ statusCode: 200
+ staticFile: security/security-actions.json
# List RBAC resources
- method: GET
@@ -669,6 +675,9 @@ resources:
# List users
- method: GET
path: /security/users
+ response:
+ statusCode: 200
+ staticFile: security/users.json
# Add users
- method: POST
@@ -687,7 +696,7 @@ resources:
path: /security/roles
response:
statusCode: 200
- staticFile: security/security_roles.json
+ staticFile: security/security-roles.json
# Add role
- method: POST
@@ -704,6 +713,9 @@ resources:
# List security rules
- method: GET
path: /security/rules
+ response:
+ statusCode: 200
+ staticFile: security/security-rules.json
# Add security rule
- method: POST
@@ -722,7 +734,7 @@ resources:
path: /security/policies
response:
statusCode: 200
- staticFile: security/security_policies.json
+ staticFile: security/security-policies.json
# Add policy
- method: POST
diff --git a/plugins/main/common/constants.ts b/plugins/main/common/constants.ts
index e01586d620..426d72d2ea 100644
--- a/plugins/main/common/constants.ts
+++ b/plugins/main/common/constants.ts
@@ -105,6 +105,10 @@ export const WAZUH_CONFIGURATION_CACHE_TIME = 10000; // time in ms;
// Reserved ids for Users/Role mapping
export const WAZUH_API_RESERVED_ID_LOWER_THAN = 100;
+export const WAZUH_API_RESERVED_WUI_SECURITY_RULES = [
+ 1,
+ 2
+];
// Wazuh data path
const WAZUH_DATA_PLUGIN_PLATFORM_BASE_PATH = 'data';
diff --git a/plugins/main/public/components/security/main.tsx b/plugins/main/public/components/security/main.tsx
index be1f8713a6..fff3f9d4f8 100644
--- a/plugins/main/public/components/security/main.tsx
+++ b/plugins/main/public/components/security/main.tsx
@@ -6,9 +6,7 @@ import {
EuiFlexItem,
EuiTabs,
EuiTab,
- EuiPanel,
EuiCallOut,
- EuiEmptyPrompt,
EuiSpacer,
} from '@elastic/eui';
import { Users } from './users/users';
@@ -17,18 +15,18 @@ import { Policies } from './policies/policies';
import { GenericRequest } from '../../react-services/generic-request';
import { API_USER_STATUS_RUN_AS } from '../../../server/lib/cache-api-user-has-run-as';
import { AppState } from '../../react-services/app-state';
-import { ErrorHandler } from '../../react-services/error-handler';
import { RolesMapping } from './roles-mapping/roles-mapping';
import {
withReduxProvider,
withGlobalBreadcrumb,
- withUserAuthorizationPrompt,
withErrorBoundary,
} from '../common/hocs';
import { compose } from 'redux';
-import { WAZUH_ROLE_ADMINISTRATOR_NAME, PLUGIN_PLATFORM_NAME } from '../../../common/constants';
+import {
+ PLUGIN_PLATFORM_NAME,
+ UI_LOGGER_LEVELS,
+} from '../../../common/constants';
import { updateSecuritySection } from '../../redux/actions/securityActions';
-import { UI_LOGGER_LEVELS } from '../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../react-services/common-services';
import { getPluginDataPath } from '../../../common/plugin';
@@ -60,12 +58,13 @@ export const WzSecurity = compose(
withErrorBoundary,
withReduxProvider,
withGlobalBreadcrumb([{ text: '' }, { text: 'Security' }]),
- withUserAuthorizationPrompt(null, [WAZUH_ROLE_ADMINISTRATOR_NAME])
)(() => {
const dispatch = useDispatch();
// Get the initial tab when the component is initiated
- const securityTabRegExp = new RegExp(`tab=(${tabs.map((tab) => tab.id).join('|')})`);
+ const securityTabRegExp = new RegExp(
+ `tab=(${tabs.map(tab => tab.id).join('|')})`,
+ );
const tab = window.location.href.match(securityTabRegExp);
const selectedTabId = (tab && tab[1]) || 'users';
@@ -73,7 +72,11 @@ export const WzSecurity = compose(
const checkRunAsUser = async () => {
const currentApi = AppState.getCurrentAPI();
try {
- const ApiCheck = await GenericRequest.request('POST', '/api/check-api', currentApi);
+ const ApiCheck = await GenericRequest.request(
+ 'POST',
+ '/api/check-api',
+ currentApi,
+ );
return ApiCheck.data.allow_run_as;
} catch (error) {
throw new Error(error);
@@ -107,8 +110,11 @@ export const WzSecurity = compose(
dispatch(updateSecuritySection(selectedTabId));
}, []);
- const onSelectedTabChanged = (id) => {
- window.location.href = window.location.href.replace(`tab=${selectedTabId}`, `tab=${id}`);
+ const onSelectedTabChanged = id => {
+ window.location.href = window.location.href.replace(
+ `tab=${selectedTabId}`,
+ `tab=${id}`,
+ );
};
const renderTabs = () => {
@@ -125,20 +131,22 @@ export const WzSecurity = compose(
));
};
- const isNotRunAs = (allowRunAs) => {
+ const isNotRunAs = allowRunAs => {
let runAsWarningTxt = '';
switch (allowRunAs) {
case API_USER_STATUS_RUN_AS.HOST_DISABLED:
- runAsWarningTxt =
- `For the role mapping to take effect, enable run_as in ${getPluginDataPath('config/wazuh.yml')} configuration file, restart the ${PLUGIN_PLATFORM_NAME} service and clear your browser cache and cookies.`;
+ runAsWarningTxt = `For the role mapping to take effect, enable run_as in ${getPluginDataPath(
+ 'config/wazuh.yml',
+ )} configuration file, restart the ${PLUGIN_PLATFORM_NAME} service and clear your browser cache and cookies.`;
break;
case API_USER_STATUS_RUN_AS.USER_NOT_ALLOWED:
runAsWarningTxt =
'The role mapping has no effect because the current Wazuh API user has allow_run_as disabled.';
break;
case API_USER_STATUS_RUN_AS.ALL_DISABLED:
- runAsWarningTxt =
- `For the role mapping to take effect, enable run_as in ${getPluginDataPath('config/wazuh.yml')} configuration file and set the current Wazuh API user allow_run_as to true. Restart the ${PLUGIN_PLATFORM_NAME} service and clear your browser cache and cookies.`;
+ runAsWarningTxt = `For the role mapping to take effect, enable run_as in ${getPluginDataPath(
+ 'config/wazuh.yml',
+ )} configuration file and set the current Wazuh API user allow_run_as to true. Restart the ${PLUGIN_PLATFORM_NAME} service and clear your browser cache and cookies.`;
break;
default:
runAsWarningTxt =
@@ -149,7 +157,11 @@ export const WzSecurity = compose(
return (
-
+
@@ -161,7 +173,7 @@ export const WzSecurity = compose(
{renderTabs()}
-
+
{selectedTabId === 'users' && }
{selectedTabId === 'roles' && }
{selectedTabId === 'policies' && }
diff --git a/plugins/main/public/components/security/policies/create-policy.tsx b/plugins/main/public/components/security/policies/create-policy.tsx
index 078448db98..65f2cbf086 100644
--- a/plugins/main/public/components/security/policies/create-policy.tsx
+++ b/plugins/main/public/components/security/policies/create-policy.tsx
@@ -22,6 +22,7 @@ import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../react-services/common-services';
import { WzFlyout } from '../../common/flyouts';
+import { WzButtonPermissions } from '../../common/permissions/button';
export const CreatePolicyFlyout = ({ closeFlyout }) => {
const [isModalVisible, setIsModalVisible] = useState(false);
@@ -54,7 +55,7 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
type: 'icon',
color: 'danger',
icon: 'trash',
- onClick: (action) => removeAction(action),
+ onClick: action => removeAction(action),
},
],
},
@@ -76,7 +77,7 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
type: 'icon',
color: 'danger',
icon: 'trash',
- onClick: (resource) => removeResource(resource),
+ onClick: resource => removeResource(resource),
},
],
},
@@ -94,8 +95,16 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
];
async function getData() {
- const resourcesRequest = await WzRequest.apiReq('GET', '/security/resources', {});
- const actionsRequest = await WzRequest.apiReq('GET', '/security/actions', {});
+ const resourcesRequest = await WzRequest.apiReq(
+ 'GET',
+ '/security/resources',
+ {},
+ );
+ const actionsRequest = await WzRequest.apiReq(
+ 'GET',
+ '/security/actions',
+ {},
+ );
const resourcesData = resourcesRequest?.data?.data || {};
setAvailableResources(resourcesData);
@@ -109,8 +118,10 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
dropdownDisplay: (
<>
{x}
-
- {actionsData[x].description}
+
+
+ {actionsData[x].description}
+
>
),
@@ -121,7 +132,7 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
const loadResources = () => {
let allResources = [];
- addedActions.forEach((x) => {
+ addedActions.forEach(x => {
const res = (availableActions[x.action] || {})['resources'];
allResources = allResources.concat(res);
});
@@ -134,8 +145,10 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
dropdownDisplay: (
<>
{x}
-
- {availableResources[x].description}
+
+
+ {availableResources[x].description}
+
>
),
@@ -144,24 +157,20 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
setResources(resources);
};
- const removeAction = (action) => {
- setAddedActions(addedActions.filter((x) => x !== action));
+ const removeAction = action => {
+ setAddedActions(addedActions.filter(x => x !== action));
};
const createPolicy = async () => {
try {
- const result = await WzRequest.apiReq(
- 'POST',
- '/security/policies',
- {
- name: policyName,
- policy: {
- actions: addedActions.map((x) => x.action),
- resources: addedResources.map((x) => x.resource),
- effect: effectValue,
- },
- }
- );
+ const result = await WzRequest.apiReq('POST', '/security/policies', {
+ name: policyName,
+ policy: {
+ actions: addedActions.map(x => x.action),
+ resources: addedResources.map(x => x.resource),
+ effect: effectValue,
+ },
+ });
const resultData = (result.data || {}).data;
if (resultData.failed_items && resultData.failed_items.length) {
return;
@@ -195,10 +204,11 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
const addResource = () => {
if (
- !addedResources.filter((x) => x.resource === `${resourceValue}:${resourceIdentifierValue}`)
- .length
+ !addedResources.filter(
+ x => x.resource === `${resourceValue}:${resourceIdentifierValue}`,
+ ).length
) {
- setAddedResources((addedResources) => [
+ setAddedResources(addedResources => [
...addedResources,
{ resource: `${resourceValue}:${resourceIdentifierValue}` },
]);
@@ -207,34 +217,37 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
};
const addAction = () => {
- if (!addedActions.filter((x) => x.action === actionValue).length) {
- setAddedActions((addedActions) => [...addedActions, { action: actionValue }]);
+ if (!addedActions.filter(x => x.action === actionValue).length) {
+ setAddedActions(addedActions => [
+ ...addedActions,
+ { action: actionValue },
+ ]);
}
setActionValue('');
};
- const removeResource = (resource) => {
- setAddedResources(addedResources.filter((x) => x !== resource));
+ const removeResource = resource => {
+ setAddedResources(addedResources.filter(x => x !== resource));
};
- const onChangePolicyName = (e) => {
+ const onChangePolicyName = e => {
setPolicyName(e.target.value);
};
- const onChangeResourceValue = async (value) => {
+ const onChangeResourceValue = async value => {
setResourceValue(value);
setResourceIdentifierValue('');
};
- const onChangeActionValue = async (value) => {
+ const onChangeActionValue = async value => {
setActionValue(value);
};
- const onEffectValueChange = (value) => {
+ const onEffectValueChange = value => {
setEffectValue(value);
};
- const onChangeResourceIdentifierValue = async (e) => {
+ const onChangeResourceIdentifierValue = async e => {
setResourceIdentifierValue(e.target.value);
};
@@ -243,7 +256,7 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
@@ -251,7 +264,7 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
+ confirmButtonText='Yes, do it'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -291,34 +304,37 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
<>
-
+
New policy
-
-
+
+
onChangePolicyName(e)}
- aria-label=""
+ onChange={e => onChangePolicyName(e)}
+ aria-label=''
/>
onChangeActionValue(value)}
- itemLayoutAlign="top"
+ onChange={value => onChangeActionValue(value)}
+ itemLayoutAlign='top'
hasDividers
/>
@@ -327,9 +343,9 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
addAction()}
- iconType="plusInCircle"
+ iconType='plusInCircle'
disabled={!actionValue}
>
Add
@@ -339,10 +355,13 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
{!!addedActions.length && (
<>
-
+
-
+
>
@@ -351,15 +370,15 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
onChangeResourceValue(value)}
- itemLayoutAlign="top"
+ onChange={value => onChangeResourceValue(value)}
+ itemLayoutAlign='top'
hasDividers
disabled={!addedActions.length}
/>
@@ -367,14 +386,14 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
onChangeResourceIdentifierValue(e)}
+ onChange={e => onChangeResourceIdentifierValue(e)}
disabled={!resourceValue}
/>
@@ -382,9 +401,9 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
addResource()}
- iconType="plusInCircle"
+ iconType='plusInCircle'
disabled={!resourceIdentifierValue}
>
Add
@@ -394,27 +413,39 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
{!!addedResources.length && (
<>
-
+
-
+
>
)}
-
+
onEffectValueChange(value)}
+ onChange={value => onEffectValueChange(value)}
/>
- {
createPolicy();
@@ -422,7 +453,7 @@ export const CreatePolicyFlyout = ({ closeFlyout }) => {
fill
>
Create policy
-
+
diff --git a/plugins/main/public/components/security/policies/edit-policy.tsx b/plugins/main/public/components/security/policies/edit-policy.tsx
index 2830589dc4..13e2e50c79 100644
--- a/plugins/main/public/components/security/policies/edit-policy.tsx
+++ b/plugins/main/public/components/security/policies/edit-policy.tsx
@@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
import {
EuiButton,
EuiTitle,
- EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
EuiForm,
@@ -17,7 +16,6 @@ import {
EuiFieldText,
EuiConfirmModal,
EuiOverlayMask,
- EuiOutsideClickDetector,
} from '@elastic/eui';
import { WzRequest } from '../../../react-services/wz-request';
import { ErrorHandler } from '../../../react-services/error-handler';
@@ -27,6 +25,7 @@ import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/
import { getErrorOrchestrator } from '../../../react-services/common-services';
import _ from 'lodash';
import { WzFlyout } from '../../common/flyouts';
+import { WzButtonPermissions } from '../../common/permissions/button';
export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
const isReserved = WzAPIUtils.isReservedID(policy.id);
@@ -59,21 +58,27 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
const updatePolicy = async () => {
try {
- const actions = addedActions.map((item) => item.action);
- const resources = addedResources.map((item) => item.resource);
- const response = await WzRequest.apiReq('PUT', `/security/policies/${policy.id}`, {
- policy: {
- actions: actions,
- resources: resources,
- effect: effectValue,
+ const actions = addedActions.map(item => item.action);
+ const resources = addedResources.map(item => item.resource);
+ const response = await WzRequest.apiReq(
+ 'PUT',
+ `/security/policies/${policy.id}`,
+ {
+ policy: {
+ actions: actions,
+ resources: resources,
+ effect: effectValue,
+ },
},
- });
+ );
const data = (response.data || {}).data;
if (data.failed_items && data.failed_items.length) {
return;
}
- ErrorHandler.info('Role was successfully updated with the selected policies');
+ ErrorHandler.info(
+ 'Role was successfully updated with the selected policies',
+ );
closeFlyout();
} catch (error) {
const options = {
@@ -92,8 +97,16 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
};
async function getData() {
- const resources_request = await WzRequest.apiReq('GET', '/security/resources', {});
- const actions_request = await WzRequest.apiReq('GET', '/security/actions', {});
+ const resources_request = await WzRequest.apiReq(
+ 'GET',
+ '/security/resources',
+ {},
+ );
+ const actions_request = await WzRequest.apiReq(
+ 'GET',
+ '/security/actions',
+ {},
+ );
const resources_data = ((resources_request || {}).data || {}).data || {};
setAvailableResources(resources_data);
@@ -107,8 +120,10 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
dropdownDisplay: (
<>
{x}
-
- {actions_data[x].description}
+
+
+ {actions_data[x].description}
+
>
),
@@ -119,7 +134,7 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
const loadResources = () => {
let allResources = [];
- addedActions.forEach((x) => {
+ addedActions.forEach(x => {
const res = (availableActions[x.action] || {})['resources'];
allResources = allResources.concat(res);
});
@@ -132,8 +147,10 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
dropdownDisplay: (
<>
{x}
-
- {(availableResources[x] || {}).description}
+
+
+ {(availableResources[x] || {}).description}
+
>
),
@@ -144,14 +161,14 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
const initData = () => {
const policies = ((policy || {}).policy || {}).actions || [];
- const initPolicies = policies.map((item) => {
+ const initPolicies = policies.map(item => {
return { action: item };
});
setAddedActions(initPolicies);
setInitialAddedActions(initPolicies);
const resources = ((policy || {}).policy || {}).resources || [];
- const initResources = resources.map((item) => {
+ const initResources = resources.map(item => {
return { resource: item };
});
setAddedResources(initResources);
@@ -161,7 +178,7 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
setInitialEffectValue(policy.policy.effect);
};
- const onEffectValueChange = (value) => {
+ const onEffectValueChange = value => {
setEffectValue(value);
};
@@ -176,19 +193,22 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
},
];
- const onChangeActionValue = async (value) => {
+ const onChangeActionValue = async value => {
setActionValue(value);
};
const addAction = () => {
- if (!addedActions.filter((x) => x.action === actionValue).length) {
- setAddedActions((addedActions) => [...addedActions, { action: actionValue }]);
+ if (!addedActions.filter(x => x.action === actionValue).length) {
+ setAddedActions(addedActions => [
+ ...addedActions,
+ { action: actionValue },
+ ]);
}
setActionValue('');
};
- const removeAction = (action) => {
- setAddedActions(addedActions.filter((x) => x !== action));
+ const removeAction = action => {
+ setAddedActions(addedActions.filter(x => x !== action));
};
const actions_columns = [
@@ -208,7 +228,7 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
enabled: () => !isReserved,
color: 'danger',
icon: 'trash',
- onClick: (action) => removeAction(action),
+ onClick: action => removeAction(action),
},
],
},
@@ -231,13 +251,13 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
color: 'danger',
enabled: () => !isReserved,
icon: 'trash',
- onClick: (resource) => removeResource(resource),
+ onClick: resource => removeResource(resource),
},
],
},
];
- const onChangeResourceValue = async (value) => {
+ const onChangeResourceValue = async value => {
setResourceValue(value);
setResourceIdentifierValue('');
};
@@ -247,20 +267,21 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
return (keys[resourceValue] || ':').split(':')[1];
};
- const onChangeResourceIdentifierValue = async (e) => {
+ const onChangeResourceIdentifierValue = async e => {
setResourceIdentifierValue(e.target.value);
};
- const removeResource = (resource) => {
- setAddedResources(addedResources.filter((x) => x !== resource));
+ const removeResource = resource => {
+ setAddedResources(addedResources.filter(x => x !== resource));
};
const addResource = () => {
if (
- !addedResources.filter((x) => x.resource === `${resourceValue}:${resourceIdentifierValue}`)
- .length
+ !addedResources.filter(
+ x => x.resource === `${resourceValue}:${resourceIdentifierValue}`,
+ ).length
) {
- setAddedResources((addedResources) => [
+ setAddedResources(addedResources => [
...addedResources,
{ resource: `${resourceValue}:${resourceIdentifierValue}` },
]);
@@ -273,14 +294,14 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
+ confirmButtonText='Yes, do it'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -311,38 +332,41 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
<>
-
+
Edit policy {policy.name}
- {isReserved && Reserved}
+ {isReserved && Reserved}
-
-
+
+
{}}
- aria-label=""
+ aria-label=''
/>
onChangeActionValue(value)}
- itemLayoutAlign="top"
+ onChange={value => onChangeActionValue(value)}
+ itemLayoutAlign='top'
hasDividers
/>
@@ -352,7 +376,7 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
addAction()}
- iconType="plusInCircle"
+ iconType='plusInCircle'
disabled={!actionValue || isReserved}
>
Add
@@ -362,10 +386,13 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
{!!addedActions.length && (
<>
-
+
-
+
>
@@ -374,14 +401,14 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
onChangeResourceValue(value)}
- itemLayoutAlign="top"
+ onChange={value => onChangeResourceValue(value)}
+ itemLayoutAlign='top'
hasDividers
disabled={!addedActions.length || isReserved}
/>
@@ -389,13 +416,13 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
onChangeResourceIdentifierValue(e)}
+ onChange={e => onChangeResourceIdentifierValue(e)}
disabled={!resourceValue || isReserved}
/>
@@ -404,7 +431,7 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
addResource()}
- iconType="plusInCircle"
+ iconType='plusInCircle'
disabled={!resourceIdentifierValue || isReserved}
>
Add
@@ -414,26 +441,40 @@ export const EditPolicyFlyout = ({ policy, closeFlyout }) => {
{!!addedResources.length && (
<>
-
+
-
+
>
)}
-
+
onEffectValueChange(value)}
+ onChange={value => onEffectValueChange(value)}
/>
-
+
Apply
-
+
diff --git a/plugins/main/public/components/security/policies/policies-table.tsx b/plugins/main/public/components/security/policies/policies-table.tsx
index 3b9f3df383..7f5d5fea2a 100644
--- a/plugins/main/public/components/security/policies/policies-table.tsx
+++ b/plugins/main/public/components/security/policies/policies-table.tsx
@@ -1,15 +1,20 @@
-import React, { useState, useEffect } from 'react';
-import { EuiInMemoryTable, EuiBadge, EuiToolTip, EuiButtonIcon } from '@elastic/eui';
+import React from 'react';
+import { EuiInMemoryTable, EuiBadge } from '@elastic/eui';
import { WzRequest } from '../../../react-services/wz-request';
import { ErrorHandler } from '../../../react-services/error-handler';
import { WzAPIUtils } from '../../../react-services/wz-api-utils';
-import { WzButtonModalConfirm } from '../../common/buttons';
+import { WzButtonPermissionsModalConfirm } from '../../common/buttons';
import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../react-services/common-services';
-export const PoliciesTable = ({ policies, loading, editPolicy, updatePolicies }) => {
- const getRowProps = (item) => {
+export const PoliciesTable = ({
+ policies,
+ loading,
+ editPolicy,
+ updatePolicies,
+}) => {
+ const getRowProps = item => {
const { id } = item;
return {
'data-test-subj': `row-${id}`,
@@ -19,14 +24,18 @@ export const PoliciesTable = ({ policies, loading, editPolicy, updatePolicies })
};
};
- const confirmDeletePolicy = (item) => {
+ const confirmDeletePolicy = item => {
return async () => {
try {
- const response = await WzRequest.apiReq('DELETE', `/security/policies/`, {
- params: {
- policy_ids: item.id,
+ const response = await WzRequest.apiReq(
+ 'DELETE',
+ `/security/policies/`,
+ {
+ params: {
+ policy_ids: item.id,
+ },
},
- });
+ );
const data = (response.data || {}).data;
if (data.failed_items && data.failed_items.length) {
return;
@@ -48,7 +57,7 @@ export const PoliciesTable = ({ policies, loading, editPolicy, updatePolicies })
getErrorOrchestrator().handleError(options);
}
};
- }
+ };
const columns = [
{
@@ -68,7 +77,7 @@ export const PoliciesTable = ({ policies, loading, editPolicy, updatePolicies })
field: 'policy.actions',
name: 'Actions',
sortable: true,
- render: (actions) => {
+ render: actions => {
return (actions || []).join(', ');
},
truncateText: true,
@@ -88,8 +97,12 @@ export const PoliciesTable = ({ policies, loading, editPolicy, updatePolicies })
{
field: 'id',
name: 'Status',
- render: (item) => {
- return WzAPIUtils.isReservedID(item) && Reserved;
+ render: item => {
+ return (
+ WzAPIUtils.isReservedID(item) && (
+ Reserved
+ )
+ );
},
width: 150,
sortable: false,
@@ -98,10 +111,13 @@ export const PoliciesTable = ({ policies, loading, editPolicy, updatePolicies })
align: 'right',
width: '5%',
name: 'Actions',
- render: (item) => (
-
ev.stopPropagation()}>
-
(
+ ev.stopPropagation()}>
+
),
diff --git a/plugins/main/public/components/security/policies/policies.tsx b/plugins/main/public/components/security/policies/policies.tsx
index a2718d5e5e..92b8da437a 100644
--- a/plugins/main/public/components/security/policies/policies.tsx
+++ b/plugins/main/public/components/security/policies/policies.tsx
@@ -5,15 +5,18 @@ import {
EuiPageContentHeaderSection,
EuiPageContentBody,
EuiButton,
- EuiTitle
+ EuiTitle,
} from '@elastic/eui';
import { PoliciesTable } from './policies-table';
import { WzRequest } from '../../../react-services/wz-request';
import { EditPolicyFlyout } from './edit-policy';
import { CreatePolicyFlyout } from './create-policy';
+import { withUserAuthorizationPrompt } from '../../common/hocs';
+import { WzButtonPermissions } from '../../common/permissions/button';
-
-export const Policies = () => {
+export const Policies = withUserAuthorizationPrompt([
+ { action: 'security:read', resource: 'policy:id:*' },
+])(() => {
const [policies, setPolicies] = useState('');
const [loading, setLoading] = useState(false);
const [isCreatingPolicy, setIsCreatingPolicy] = useState(false);
@@ -22,11 +25,7 @@ export const Policies = () => {
const getPolicies = async () => {
setLoading(true);
- const request = await WzRequest.apiReq(
- 'GET',
- '/security/policies',
- {}
- );
+ const request = await WzRequest.apiReq('GET', '/security/policies', {});
const policies = request?.data?.data?.affected_items || [];
setPolicies(policies);
setLoading(false);
@@ -36,7 +35,7 @@ export const Policies = () => {
getPolicies();
}, []);
- const editPolicy = (item) => {
+ const editPolicy = item => {
setEditingPolicy(item);
setIsEditingPolicy(true);
};
@@ -51,18 +50,18 @@ export const Policies = () => {
await getPolicies();
};
-
let editFlyout;
if (isEditingPolicy) {
editFlyout = (
-
+
);
}
let flyout;
if (isCreatingPolicy) {
- flyout = (
-
- );
+ flyout = ;
}
return (
@@ -74,18 +73,19 @@ export const Policies = () => {
- {
- !loading
- &&
-
- setIsCreatingPolicy(true)}>
- Create policy
-
- {flyout}
- {editFlyout}
-
- }
+ {!loading && (
+
+ setIsCreatingPolicy(true)}
+ >
+ Create policy
+
+ {flyout}
+ {editFlyout}
+
+ )}
@@ -98,4 +98,4 @@ export const Policies = () => {
);
-};
+});
diff --git a/plugins/main/public/components/security/roles-mapping/components/roles-mapping-create.tsx b/plugins/main/public/components/security/roles-mapping/components/roles-mapping-create.tsx
index 7b8d980041..068d105787 100644
--- a/plugins/main/public/components/security/roles-mapping/components/roles-mapping-create.tsx
+++ b/plugins/main/public/components/security/roles-mapping/components/roles-mapping-create.tsx
@@ -41,16 +41,16 @@ export const RolesMappingCreate = ({
const [isModalVisible, setIsModalVisible] = useState(false);
const [hasChanges, setHasChanges] = useState(false);
const getRolesList = () => {
- const list = roles.map((item) => {
+ const list = roles.map(item => {
return { label: rolesEquivalences[item.id], id: item.id };
});
return list;
};
- const createRule = async (toSaveRule) => {
+ const createRule = async toSaveRule => {
try {
setIsLoading(true);
- const formattedRoles = selectedRoles.map((item) => {
+ const formattedRoles = selectedRoles.map(item => {
return item.id;
});
const newRule = await RulesServices.CreateRule({
@@ -58,7 +58,9 @@ export const RolesMappingCreate = ({
rule: toSaveRule,
});
await Promise.all(
- formattedRoles.map(async (role) => await RolesServices.AddRoleRules(role, [newRule.id]))
+ formattedRoles.map(
+ async role => await RolesServices.AddRoleRules(role, [newRule.id]),
+ ),
);
ErrorHandler.info('Role mapping was successfully created');
} catch (error) {
@@ -84,7 +86,7 @@ export const RolesMappingCreate = ({
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
@@ -92,7 +94,7 @@ export const RolesMappingCreate = ({
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
+ confirmButtonText='Yes, do it'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -122,40 +124,40 @@ export const RolesMappingCreate = ({
<>
-
+
Create new role mapping
-
+
setRuleName(e.target.value)}
+ onChange={e => setRuleName(e.target.value)}
/>
{
+ onChange={roles => {
setSelectedRoles(roles);
}}
isClearable={true}
- data-test-subj="demoComboBox"
+ data-test-subj='demoComboBox'
/>
@@ -163,13 +165,24 @@ export const RolesMappingCreate = ({
createRule(rule)}
+ save={rule => createRule(rule)}
+ saveButtonPermissions={[
+ { action: 'security:create', resource: '*:*:*' },
+ ...(selectedRoles.length > 0
+ ? [
+ {
+ action: 'security:update',
+ resource: 'rule:id:*',
+ },
+ ]
+ : []),
+ ]}
initialRule={false}
isReserved={false}
isLoading={isLoading}
internalUsers={internalUsers}
currentPlatform={currentPlatform}
- onFormChange={(hasChange) => {
+ onFormChange={hasChange => {
setHasChangeMappingRules(hasChange);
}}
>
diff --git a/plugins/main/public/components/security/roles-mapping/components/roles-mapping-edit.tsx b/plugins/main/public/components/security/roles-mapping/components/roles-mapping-edit.tsx
index 6f44f3f2e4..4b11df21f1 100644
--- a/plugins/main/public/components/security/roles-mapping/components/roles-mapping-edit.tsx
+++ b/plugins/main/public/components/security/roles-mapping/components/roles-mapping-edit.tsx
@@ -1,7 +1,6 @@
import React, { useEffect, useState } from 'react';
import {
EuiTitle,
- EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
EuiForm,
@@ -12,7 +11,6 @@ import {
EuiBadge,
EuiComboBox,
EuiOverlayMask,
- EuiOutsideClickDetector,
EuiConfirmModal,
EuiFieldText,
} from '@elastic/eui';
@@ -36,31 +34,33 @@ export const RolesMappingEdit = ({
onSave,
currentPlatform,
}) => {
- const getEquivalences = (roles) => {
- const list = roles.map((item) => {
+ const getEquivalences = roles => {
+ const list = roles.map(item => {
return { label: rolesEquivalences[item], id: item };
});
return list;
};
- const [selectedRoles, setSelectedRoles] = useState(getEquivalences(rule.roles));
+ const [selectedRoles, setSelectedRoles] = useState(
+ getEquivalences(rule.roles),
+ );
const [ruleName, setRuleName] = useState(rule.name);
const [isLoading, setIsLoading] = useState(false);
const [hasChangeMappingRules, setHasChangeMappingRules] = useState(false);
const [isModalVisible, setIsModalVisible] = useState(false);
const [hasChanges, setHasChanges] = useState(false);
- const getRolesList = (roles) => {
- const list = roles.map((item) => {
+ const getRolesList = roles => {
+ const list = roles.map(item => {
return { label: rolesEquivalences[item.id], id: item.id };
});
return list;
};
- const editRule = async (toSaveRule) => {
+ const editRule = async toSaveRule => {
try {
setIsLoading(true);
- const formattedRoles = selectedRoles.map((item) => {
+ const formattedRoles = selectedRoles.map(item => {
return item.id;
});
@@ -69,18 +69,20 @@ export const RolesMappingEdit = ({
rule: toSaveRule,
});
- const toAdd = formattedRoles.filter((value) => !rule.roles.includes(value));
- const toRemove = rule.roles.filter((value) => !formattedRoles.includes(value));
+ const toAdd = formattedRoles.filter(value => !rule.roles.includes(value));
+ const toRemove = rule.roles.filter(
+ value => !formattedRoles.includes(value),
+ );
await Promise.all(
- toAdd.map(async (role) => {
+ toAdd.map(async role => {
return RolesServices.AddRoleRules(role, [rule.id]);
- })
+ }),
);
await Promise.all(
- toRemove.map(async (role) => {
+ toRemove.map(async role => {
return RolesServices.RemoveRoleRules(role, [rule.id]);
- })
+ }),
);
ErrorHandler.info('Role mapping was successfully updated');
@@ -108,7 +110,7 @@ export const RolesMappingEdit = ({
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
@@ -116,8 +118,8 @@ export const RolesMappingEdit = ({
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
- defaultFocusedButton="confirm"
+ confirmButtonText='Yes, do it'
+ defaultFocusedButton='confirm'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -129,7 +131,11 @@ export const RolesMappingEdit = ({
useEffect(() => {
const initialRoles = getEquivalences(rule.roles);
- if (rule.name != ruleName || !_.isEqual(initialRoles, selectedRoles) || hasChangeMappingRules) {
+ if (
+ rule.name != ruleName ||
+ !_.isEqual(initialRoles, selectedRoles) ||
+ hasChangeMappingRules
+ ) {
setHasChanges(true);
} else {
setHasChanges(false);
@@ -144,45 +150,47 @@ export const RolesMappingEdit = ({
<>
-
+
Edit {rule.name}
- {WzAPIUtils.isReservedID(rule.id) && Reserved}
+ {WzAPIUtils.isReservedID(rule.id) && (
+ Reserved
+ )}
-
+
setRuleName(e.target.value)}
- aria-label=""
+ onChange={e => setRuleName(e.target.value)}
+ aria-label=''
/>
{
+ onChange={roles => {
setSelectedRoles(roles);
}}
isClearable={true}
- data-test-subj="demoComboBox"
+ data-test-subj='demoComboBox'
/>
@@ -190,13 +198,38 @@ export const RolesMappingEdit = ({
editRule(rule)}
+ save={rule => editRule(rule)}
+ saveButtonPermissions={[
+ // Require security:update:{rule_id} if some roles were added
+ ...(selectedRoles
+ .map(item => item.id)
+ .filter(value => !rule.roles.includes(value)).length > 0
+ ? [
+ {
+ action: 'security:update',
+ resource: `rule:id:${rule.id}`,
+ },
+ ]
+ : []),
+ // Require security:delete:{rule_id} if some roles were removed
+ ...(rule.roles.filter(
+ value =>
+ !selectedRoles.map(item => item.id).includes(value),
+ ) > 0
+ ? [
+ {
+ action: 'security:delete',
+ resource: `rule:id:${rule.id}`,
+ },
+ ]
+ : []),
+ ]}
initialRule={rule.rule}
isLoading={isLoading}
isReserved={WzAPIUtils.isReservedID(rule.id)}
internalUsers={internalUsers}
currentPlatform={currentPlatform}
- onFormChange={(hasChange) => setHasChangeMappingRules(hasChange)}
+ onFormChange={hasChange => setHasChangeMappingRules(hasChange)}
>
diff --git a/plugins/main/public/components/security/roles-mapping/components/roles-mapping-table.tsx b/plugins/main/public/components/security/roles-mapping/components/roles-mapping-table.tsx
index 3a04543a39..5efe9cbb14 100644
--- a/plugins/main/public/components/security/roles-mapping/components/roles-mapping-table.tsx
+++ b/plugins/main/public/components/security/roles-mapping/components/roles-mapping-table.tsx
@@ -1,6 +1,5 @@
import React from 'react';
import {
- EuiSpacer,
EuiToolTip,
EuiInMemoryTable,
EuiBadge,
@@ -10,14 +9,20 @@ import {
SortDirection,
} from '@elastic/eui';
import { ErrorHandler } from '../../../../react-services/error-handler';
-import { WzButtonModalConfirm } from '../../../common/buttons';
+import { WzButtonPermissionsModalConfirm } from '../../../common/buttons';
import { WzAPIUtils } from '../../../../react-services/wz-api-utils';
import RulesServices from '../../rules/services';
-import { UI_LOGGER_LEVELS } from '../../../../../common/constants';
+import { UI_LOGGER_LEVELS, WAZUH_API_RESERVED_WUI_SECURITY_RULES } from '../../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../../react-services/common-services';
-export const RolesMappingTable = ({ rolesEquivalences, rules, loading, editRule, updateRules }) => {
+export const RolesMappingTable = ({
+ rolesEquivalences,
+ rules,
+ loading,
+ editRule,
+ updateRules,
+}) => {
const getRowProps = item => {
const { id } = item;
return {
@@ -26,7 +31,7 @@ export const RolesMappingTable = ({ rolesEquivalences, rules, loading, editRule,
};
};
- const onDeleteRoleMapping = (item) => {
+ const onDeleteRoleMapping = item => {
return async () => {
try {
await RulesServices.DeleteRules([item.id]);
@@ -47,7 +52,7 @@ export const RolesMappingTable = ({ rolesEquivalences, rules, loading, editRule,
getErrorOrchestrator().handleError(options);
}
};
- }
+ };
const columns: EuiBasicTableColumn[] = [
{
@@ -71,12 +76,12 @@ export const RolesMappingTable = ({ rolesEquivalences, rules, loading, editRule,
const tmpRoles = item.map((role, idx) => {
return (
- {rolesEquivalences[role]}
+ {rolesEquivalences[role]}
);
});
return (
-
+
{tmpRoles}
);
@@ -86,20 +91,23 @@ export const RolesMappingTable = ({ rolesEquivalences, rules, loading, editRule,
{
field: 'id',
name: 'Status',
- render (item, obj){
- if(WzAPIUtils.isReservedID(item)){
- if( (obj.id === 1 || obj.id === 2)){
- return(
+ render(item, obj) {
+ if (WzAPIUtils.isReservedID(item)) {
+ if (WAZUH_API_RESERVED_WUI_SECURITY_RULES.includes(obj.id)) {
+ return (
- Reserved
-
- wazuh-wui
+ Reserved
+
+
+ wazuh-wui
+
);
- }
- else
- return Reserved;
+ } else return Reserved;
}
},
width: '300',
@@ -111,22 +119,26 @@ export const RolesMappingTable = ({ rolesEquivalences, rules, loading, editRule,
name: 'Actions',
render: item => (
ev.stopPropagation()}>
-
),
diff --git a/plugins/main/public/components/security/roles-mapping/components/rule-editor.tsx b/plugins/main/public/components/security/roles-mapping/components/rule-editor.tsx
index bd2fdc77ea..0e4cab31b0 100644
--- a/plugins/main/public/components/security/roles-mapping/components/rule-editor.tsx
+++ b/plugins/main/public/components/security/roles-mapping/components/rule-editor.tsx
@@ -2,7 +2,6 @@ import React, { useState, useEffect, Fragment } from 'react';
import {
EuiToolTip,
EuiButtonIcon,
- EuiButton,
EuiTitle,
EuiFormRow,
EuiFlexGroup,
@@ -30,11 +29,21 @@ import { WAZUH_SECURITY_PLUGIN_OPEN_DISTRO_FOR_ELASTICSEARCH } from '../../../..
import 'brace/mode/json';
import 'brace/snippets/json';
import 'brace/ext/language_tools';
-import "brace/ext/searchbox";
+import 'brace/ext/searchbox';
import _ from 'lodash';
import { webDocumentationLink } from '../../../../../common/services/web_documentation';
+import { WzButtonPermissions } from '../../../common/permissions/button';
-export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalUsers, currentPlatform,onFormChange }) => {
+export const RuleEditor = ({
+ save,
+ initialRule,
+ isLoading,
+ isReserved,
+ internalUsers,
+ currentPlatform,
+ onFormChange,
+ saveButtonPermissions = [],
+}) => {
const [logicalOperator, setLogicalOperator] = useState('OR');
const [isLogicalPopoverOpen, setIsLogicalPopoverOpen] = useState(false);
const [isJsonEditor, setIsJsonEditor] = useState(false);
@@ -42,13 +51,19 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
const [hasWrongFormat, setHasWrongFormat] = useState(false);
const [rules, setRules] = useState([]);
const [initialRules, setInitialRules] = useState([]);
- const [initialInternalUserRules, setInitialInternalUserRules] = useState([]);
+ const [initialInternalUserRules, setInitialInternalUserRules] = useState<
+ any[]
+ >([]);
const [internalUserRules, setInternalUserRules] = useState([]);
- const [internalUsersOptions, setInternalUsersOptions] = useState[]>(
- []
- );
- const [selectedUsers, setSelectedUsers] = useState[]>([]);
- const [initialSelectedUsers, setInitialSelectedUsers] = useState[]>([]);
+ const [internalUsersOptions, setInternalUsersOptions] = useState<
+ EuiComboBoxOptionOption[]
+ >([]);
+ const [selectedUsers, setSelectedUsers] = useState<
+ EuiComboBoxOptionOption[]
+ >([]);
+ const [initialSelectedUsers, setInitialSelectedUsers] = useState<
+ EuiComboBoxOptionOption[]
+ >([]);
const [initialLogicalOperator, setInitialLogicalOperator] = useState('OR');
const searchOperationOptions = [
@@ -57,14 +72,23 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
{ value: 'MATCH', text: 'MATCH' },
{ value: 'MATCH$', text: 'MATCH$' },
];
- const default_user_field = currentPlatform === WAZUH_SECURITY_PLUGIN_OPEN_DISTRO_FOR_ELASTICSEARCH ? 'user_name' : 'username';
- const default_rule = { user_field: default_user_field, searchOperation: 'FIND', value: 'wazuh' };
+ const default_user_field =
+ currentPlatform === WAZUH_SECURITY_PLUGIN_OPEN_DISTRO_FOR_ELASTICSEARCH
+ ? 'user_name'
+ : 'username';
+ const default_rule = {
+ user_field: default_user_field,
+ searchOperation: 'FIND',
+ value: 'wazuh',
+ };
useEffect(() => {
if (initialRule) {
setStateFromRule(JSON.stringify(initialRule));
const rulesResult = getRulesFromJson(JSON.stringify(initialRule));
- const _selectedUsers = getSelectedUsersFromRules(rulesResult.internalUsersRules);
+ const _selectedUsers = getSelectedUsersFromRules(
+ rulesResult.internalUsersRules,
+ );
setInitialLogicalOperator(rulesResult.logicalOperator);
setInitialRules(rulesResult.customRules);
setInitialInternalUserRules(rulesResult.internalUsersRules);
@@ -74,7 +98,10 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
useEffect(() => {
if (internalUsers.length) {
- const users = internalUsers.map(user => ({ label: user.user, id: user.user }));
+ const users = internalUsers.map(user => ({
+ label: user.user,
+ id: user.user,
+ }));
setInternalUsersOptions(users);
}
}, [internalUsers]);
@@ -84,7 +111,9 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
if (!rulesResult.wrongFormat) {
setRules(rulesResult.customRules);
setInternalUserRules(rulesResult.internalUsersRules);
- const _selectedUsers = getSelectedUsersFromRules(rulesResult.internalUsersRules);
+ const _selectedUsers = getSelectedUsersFromRules(
+ rulesResult.internalUsersRules,
+ );
setSelectedUsers(_selectedUsers);
setIsJsonEditor(false);
} else {
@@ -126,13 +155,11 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
setRules(rulesTmp);
};
- const getRulesFromJson = (jsonRule) => {
+ const getRulesFromJson = jsonRule => {
if (jsonRule !== '{}' && jsonRule !== '') {
// empty json is valid
- const { customRules, internalUsersRules, wrongFormat, logicalOperator } = decodeJsonRule(
- jsonRule,
- internalUsers
- );
+ const { customRules, internalUsersRules, wrongFormat, logicalOperator } =
+ decodeJsonRule(jsonRule, internalUsers);
setLogicalOperator(logicalOperator);
setHasWrongFormat(wrongFormat);
@@ -156,36 +183,36 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
-
+
updateUserField(e, idx)}
- aria-label=""
+ aria-label=''
/>
-
+
onSelectorChange(e, idx)}
- aria-label="Use aria labels when no actual label is in use"
+ aria-label='Use aria labels when no actual label is in use'
/>
-
+
updateValueField(e, idx)}
- aria-label=""
+ aria-label=''
/>
@@ -193,15 +220,15 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
removeRule(idx)}
- iconType="trash"
- color="danger"
- aria-label="Remove rule"
+ iconType='trash'
+ color='danger'
+ aria-label='Remove rule'
/>
-
+
@@ -218,7 +245,11 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
};
const openJsonEditor = () => {
- const ruleObject = getJsonFromRule(internalUserRules, rules, logicalOperator);
+ const ruleObject = getJsonFromRule(
+ internalUserRules,
+ rules,
+ logicalOperator,
+ );
setRuleJson(JSON.stringify(ruleObject, undefined, 2));
setIsJsonEditor(true);
@@ -236,9 +267,12 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
const getSwitchVisualButton = () => {
if (hasWrongFormat) {
return (
-
+
openVisualEditor()}
>
@@ -248,7 +282,7 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
);
} else {
return (
- openVisualEditor()}>
+ openVisualEditor()}>
Switch to visual editor
);
@@ -270,7 +304,11 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
const onChangeSelectedUsers = selectedUsers => {
setSelectedUsers(selectedUsers);
const tmpInternalUsersRules = selectedUsers.map(user => {
- return { user_field: default_user_field, searchOperation: 'FIND', value: user.id };
+ return {
+ user_field: default_user_field,
+ searchOperation: 'FIND',
+ value: user.id,
+ };
});
setInternalUserRules(tmpInternalUsersRules);
};
@@ -279,11 +317,11 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
if (
!_.isEqual(initialSelectedUsers, selectedUsers) ||
!_.isEqual(initialRules, rules) ||
- !_.isEqual(initialInternalUserRules, internalUserRules)||
+ !_.isEqual(initialInternalUserRules, internalUserRules) ||
!_.isEqual(initialLogicalOperator, logicalOperator)
- ){
- onFormChange(true)
- } else{
+ ) {
+ onFormChange(true);
+ } else {
onFormChange(false);
}
}, [selectedUsers, rules, internalUserRules, logicalOperator]);
@@ -299,10 +337,12 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
Assign roles to users who match these rules.
Learn more
@@ -316,96 +356,104 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
)) || (
-
-
- Map internal users
-
-
-
-
-
-
- Custom rules
-
-
- {logicalOperator === 'AND' ? 'All are true' : 'Any are true'}
-
- }
- isOpen={isLogicalPopoverOpen}
- closePopover={closeLogicalPopover}
- anchorPosition="downCenter"
- >
-
-
-
- selectOperator('AND')}
- >
- {logicalOperator === 'AND' && }All are true
+
+
+ Map internal users
+
+
+
+
+
+
+ Custom rules
+
+
+ {logicalOperator === 'AND'
+ ? 'All are true'
+ : 'Any are true'}
+
+ }
+ isOpen={isLogicalPopoverOpen}
+ closePopover={closeLogicalPopover}
+ anchorPosition='downCenter'
+ >
+
+
+
+ selectOperator('AND')}
+ >
+ {logicalOperator === 'AND' && (
+
+ )}
+ All are true
-
-
-
-
- selectOperator('OR')}
- >
- {logicalOperator === 'OR' && }Any are true
+
+
+
+
+ selectOperator('OR')}
+ >
+ {logicalOperator === 'OR' && (
+
+ )}
+ Any are true
-
-
-
-
- {printRules()}
+
+
+
+
+ {printRules()}
- addNewRule()}
- >
- Add new rule
+ addNewRule()}
+ >
+ Add new rule
-
- )}
+
+ )}
{(isJsonEditor && getSwitchVisualButton()) || (
- openJsonEditor()}>
+ openJsonEditor()}>
Switch to JSON editor
)}
@@ -415,9 +463,16 @@ export const RuleEditor = ({ save, initialRule, isLoading, isReserved, internalU
- saveRule()}>
+ saveRule()}
+ >
Save role mapping
-
+
>
diff --git a/plugins/main/public/components/security/roles-mapping/roles-mapping.tsx b/plugins/main/public/components/security/roles-mapping/roles-mapping.tsx
index bf20790523..7bf8deaefb 100644
--- a/plugins/main/public/components/security/roles-mapping/roles-mapping.tsx
+++ b/plugins/main/public/components/security/roles-mapping/roles-mapping.tsx
@@ -4,16 +4,7 @@ import {
EuiPageContentHeader,
EuiPageContentHeaderSection,
EuiPageContentBody,
- EuiButton,
EuiTitle,
- EuiOverlayMask,
- EuiSpacer,
- EuiText,
- EuiModal,
- EuiModalBody,
- EuiModalFooter,
- EuiModalHeader,
- EuiModalHeaderTitle,
} from '@elastic/eui';
import { RolesMappingTable } from './components/roles-mapping-table';
import { RolesMappingEdit } from './components/roles-mapping-edit';
@@ -29,17 +20,27 @@ import { useSelector } from 'react-redux';
import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../react-services/common-services';
+import { withUserAuthorizationPrompt } from '../../common/hocs';
+import { WzButtonPermissions } from '../../common/permissions/button';
-export const RolesMapping = () => {
+export const RolesMapping = withUserAuthorizationPrompt([
+ { action: 'security:read', resource: 'role:id:*' },
+ { action: 'security:read', resource: 'rule:id:*' },
+])(() => {
const [isEditingRule, setIsEditingRule] = useState(false);
const [isCreatingRule, setIsCreatingRule] = useState(false);
const [rules, setRules] = useState([]);
const [loadingTable, setLoadingTable] = useState(true);
const [selectedRule, setSelectedRule] = useState({});
const [rolesEquivalences, setRolesEquivalences] = useState({});
- const [rolesLoading, roles, rolesError] = useApiService(RolesServices.GetRoles, {});
+ const [rolesLoading, roles, rolesError] = useApiService(
+ RolesServices.GetRoles,
+ {},
+ );
const [internalUsers, setInternalUsers] = useState([]);
- const currentPlatform = useSelector((state: any) => state.appStateReducers.currentPlatform);
+ const currentPlatform = useSelector(
+ (state: any) => state.appStateReducers.currentPlatform,
+ );
useEffect(() => {
initData();
@@ -49,7 +50,7 @@ export const RolesMapping = () => {
if (!rolesLoading && (roles || [])) {
const _rolesObject = (roles || []).reduce(
(rolesObj, role) => ({ ...rolesObj, [role.id]: role.name }),
- {}
+ {},
);
setRolesEquivalences(_rolesObject);
}
@@ -57,7 +58,7 @@ export const RolesMapping = () => {
ErrorHandler.handle('There was an error loading roles');
}
}, [rolesLoading]);
-
+
const getInternalUsers = async () => {
try {
const wazuhSecurity = new WazuhSecurity();
@@ -122,13 +123,13 @@ export const RolesMapping = () => {
const updateRoles = async () => {
await getRules();
};
-
+
let editFlyout;
if (isEditingRule) {
editFlyout = (
{
+ closeFlyout={isVisible => {
setIsEditingRule(isVisible);
initData();
}}
@@ -142,9 +143,9 @@ export const RolesMapping = () => {
}
let createFlyout;
if (isCreatingRule) {
- editFlyout = (
+ createFlyout = (
{
+ closeFlyout={isVisible => {
setIsCreatingRule(isVisible);
initData();
}}
@@ -161,19 +162,21 @@ export const RolesMapping = () => {
- Role mapping
+ Roles mapping
{!loadingTable && (
- {
setIsCreatingRule(true);
}}
>
Create Role mapping
-
+
{createFlyout}
{editFlyout}
@@ -185,7 +188,7 @@ export const RolesMapping = () => {
rolesEquivalences={rolesEquivalences}
loading={loadingTable || rolesLoading}
rules={rules}
- editRule={(item) => {
+ editRule={item => {
setSelectedRule(item);
setIsEditingRule(true);
}}
@@ -194,4 +197,4 @@ export const RolesMapping = () => {
);
-};
+});
diff --git a/plugins/main/public/components/security/roles/create-role.tsx b/plugins/main/public/components/security/roles/create-role.tsx
index 7ddb27780e..832954df28 100644
--- a/plugins/main/public/components/security/roles/create-role.tsx
+++ b/plugins/main/public/components/security/roles/create-role.tsx
@@ -1,14 +1,11 @@
import React, { useState, useEffect } from 'react';
import {
- EuiButton,
EuiTitle,
- EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
EuiForm,
EuiFieldText,
EuiOverlayMask,
- EuiOutsideClickDetector,
EuiFormRow,
EuiSpacer,
EuiComboBox,
@@ -17,8 +14,8 @@ import {
import { WzRequest } from '../../../react-services/wz-request';
import { ErrorHandler } from '../../../react-services/error-handler';
-import { WzOverlayMask } from '../../common/util';
import { WzFlyout } from '../../common/flyouts';
+import { WzButtonPermissions } from '../../common/permissions/button';
export const CreateRole = ({ closeFlyout }) => {
const [policies, setPolicies] = useState([]);
@@ -32,12 +29,16 @@ export const CreateRole = ({ closeFlyout }) => {
const [hasChanges, setHasChanges] = useState(false);
async function getData() {
- const policies_request = await WzRequest.apiReq('GET', '/security/policies', {});
- const policies = ((((policies_request || {}).data || {}).data || {}).affected_items || []).map(
- (x) => {
- return { label: x.name, id: x.id };
- }
+ const policies_request = await WzRequest.apiReq(
+ 'GET',
+ '/security/policies',
+ {},
);
+ const policies = (
+ (((policies_request || {}).data || {}).data || {}).affected_items || []
+ ).map(x => {
+ return { label: x.name, id: x.id };
+ });
setPolicies(policies);
}
@@ -71,31 +72,37 @@ export const CreateRole = ({ closeFlyout }) => {
if (data.affected_items && data.affected_items) {
roleId = data.affected_items[0].id;
}
- const policiesId = selectedPolicies.map((policy) => {
+ const policiesId = selectedPolicies.map(policy => {
return policy.id;
});
- const policyResult = await WzRequest.apiReq('POST', `/security/roles/${roleId}/policies`, {
- params: {
- policy_ids: policiesId.toString(),
+ const policyResult = await WzRequest.apiReq(
+ 'POST',
+ `/security/roles/${roleId}/policies`,
+ {
+ params: {
+ policy_ids: policiesId.toString(),
+ },
},
- });
+ );
const policiesData = (policyResult.data || {}).data;
if (policiesData.failed_items && policiesData.failed_items.length) {
return;
}
- ErrorHandler.info('Role was successfully created with the selected policies');
+ ErrorHandler.info(
+ 'Role was successfully created with the selected policies',
+ );
} catch (error) {
ErrorHandler.handle(error, 'There was an error');
}
closeFlyout(false);
};
- const onChangeRoleName = (e) => {
+ const onChangeRoleName = e => {
setRoleName(e.target.value);
};
- const onChangePolicies = (selectedPolicies) => {
+ const onChangePolicies = selectedPolicies => {
setSelectedPolicies(selectedPolicies);
};
@@ -104,7 +111,7 @@ export const CreateRole = ({ closeFlyout }) => {
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
@@ -112,7 +119,7 @@ export const CreateRole = ({ closeFlyout }) => {
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
+ confirmButtonText='Yes, do it'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -123,7 +130,10 @@ export const CreateRole = ({ closeFlyout }) => {
}
useEffect(() => {
- if (initialSelectedPolies.length != selectedPolicies.length || initialRoleName != roleName) {
+ if (
+ initialSelectedPolies.length != selectedPolicies.length ||
+ initialRoleName != roleName
+ ) {
setHasChanges(true);
} else {
setHasChanges(false);
@@ -138,44 +148,52 @@ export const CreateRole = ({ closeFlyout }) => {
<>
-
+
New role
-
+
onChangeRoleName(e)}
- aria-label=""
+ onChange={e => onChangeRoleName(e)}
+ aria-label=''
/>
-
+
Create role
-
+
diff --git a/plugins/main/public/components/security/roles/edit-role-table.tsx b/plugins/main/public/components/security/roles/edit-role-table.tsx
index c75bc893ab..f12fba2967 100644
--- a/plugins/main/public/components/security/roles/edit-role-table.tsx
+++ b/plugins/main/public/components/security/roles/edit-role-table.tsx
@@ -1,122 +1,137 @@
-import React, { useState, useEffect } from 'react';
-import {
- EuiBasicTable,
- EuiButtonIcon,
- EuiDescriptionList,
-} from '@elastic/eui';
+import React, { useState } from 'react';
+import { EuiBasicTable, EuiButtonIcon, EuiDescriptionList } from '@elastic/eui';
import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
import { WzRequest } from '../../../react-services/wz-request';
import { ErrorHandler } from '../../../react-services/error-handler';
+import { WzButtonPermissions } from '../../common/permissions/button';
+export const EditRolesTable = ({
+ policies,
+ role,
+ onChange,
+ isDisabled,
+ loading,
+}) => {
+ const [isLoading, setIsLoading] = useState(false);
+ const [pageIndex, setPageIndex] = useState(0);
+ const [pageSize, setPageSize] = useState(10);
+ const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState({});
+ const onTableChange = ({ page = {}, sort = {} }) => {
+ const { index: pageIndex, size: pageSize } = page;
+ setPageIndex(pageIndex);
+ setPageSize(pageSize);
+ };
-export const EditRolesTable = ({ policies, role, onChange, isDisabled, loading}) => {
- const [isLoading, setIsLoading] = useState(false);
- const [pageIndex, setPageIndex] = useState(0);
- const [pageSize, setPageSize] = useState(10);
- const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState({});
-
- const onTableChange = ({ page = {}, sort = {} }) => {
- const { index: pageIndex, size: pageSize } = page;
- setPageIndex(pageIndex);
- setPageSize(pageSize);
- };
+ const formatPolicies = policiesArray => {
+ return policiesArray.map(policy => {
+ return policies.find(item => item.id === policy);
+ });
+ };
- const formatPolicies = (policiesArray) => {
- return policiesArray.map(policy => {
- return policies.find(item => item.id === policy)
- })
- }
+ const getItems = () => {
+ if (loading) return { pageOfItems: [], totalItemCount: 0 };
+ const items = formatPolicies(
+ role.policies.slice(
+ pageIndex * pageSize,
+ pageIndex * pageSize + pageSize,
+ ),
+ );
+ return { pageOfItems: items, totalItemCount: role.policies.length };
+ };
- const getItems = () => {
- if(loading) return { pageOfItems: [], totalItemCount: 0};
- const items = formatPolicies(role.policies.slice(pageIndex*pageSize, pageIndex*pageSize + pageSize));
- return { pageOfItems: items, totalItemCount: role.policies.length}
- }
+ const { pageOfItems, totalItemCount } = getItems();
- const { pageOfItems, totalItemCount } = getItems();
-
- const toggleDetails = item => {
- const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap };
- if (itemIdToExpandedRowMapValues[item.id]) {
- delete itemIdToExpandedRowMapValues[item.id];
- } else {
-
- const listItems = [
- {
- title: 'Actions',
- description: `${item.policy.actions}`,
- },
- {
- title: 'Resources',
- description: `${item.policy.resources}`,
- },
- {
- title: 'Effect',
- description: `${item.policy.effect}`,
- },
- ];
- itemIdToExpandedRowMapValues[item.id] = (
-
- );
- }
- setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues);
- };
- const columns = [
+ const toggleDetails = item => {
+ const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap };
+ if (itemIdToExpandedRowMapValues[item.id]) {
+ delete itemIdToExpandedRowMapValues[item.id];
+ } else {
+ const listItems = [
{
- field: 'label',
- name: 'Policies',
- sortable: false,
- truncateText: true
+ title: 'Actions',
+ description: `${item.policy.actions}`,
},
{
- name: 'Actions',
- actions: [
- {
- name: 'Remove',
- description: 'Remove',
- type: 'icon',
- color: 'danger',
- icon: 'trash',
- enabled : () => !isDisabled && !isLoading,
- onClick: async(item) => {
- try{
- setIsLoading(true);
- const response = await WzRequest.apiReq(
- 'DELETE',
- `/security/roles/${role.id}/policies`,
- {
- params: {
- policy_ids: item.id
- }
- }
- );
- const removePolicy = (response.data || {}).data;
- if (removePolicy.failed_items && removePolicy.failed_items.length) {
- setIsLoading(false);
- return;
- }
- ErrorHandler.info(`Policy was successfully removed from role ${role.name}`);
- await onChange();
- }catch(err){ }
- setIsLoading(false);
- },
- },
- ],
+ title: 'Resources',
+ description: `${item.policy.resources}`,
},
{
- align: RIGHT_ALIGNMENT,
- width: '40px',
- isExpander: true,
+ title: 'Effect',
+ description: `${item.policy.effect}`,
+ },
+ ];
+ itemIdToExpandedRowMapValues[item.id] = (
+
+ );
+ }
+ setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues);
+ };
+ const columns = [
+ {
+ field: 'label',
+ name: 'Policies',
+ sortable: false,
+ truncateText: true,
+ },
+ {
+ name: 'Actions',
+ actions: [
+ {
render: item => (
- toggleDetails(item)}
- aria-label={itemIdToExpandedRowMap[item.id] ? 'Collapse' : 'Expand'}
- iconType={itemIdToExpandedRowMap[item.id] ? 'arrowUp' : 'arrowDown'}
+ {
+ try {
+ setIsLoading(true);
+ const response = await WzRequest.apiReq(
+ 'DELETE',
+ `/security/roles/${role.id}/policies`,
+ {
+ params: {
+ policy_ids: item.id,
+ },
+ },
+ );
+ const removePolicy = (response.data || {}).data;
+ if (
+ removePolicy.failed_items &&
+ removePolicy.failed_items.length
+ ) {
+ setIsLoading(false);
+ return;
+ }
+ ErrorHandler.info(
+ `Policy was successfully removed from role ${role.name}`,
+ );
+ await onChange();
+ } catch (err) {}
+ setIsLoading(false);
+ }}
/>
),
},
- ];
+ ],
+ },
+ {
+ align: RIGHT_ALIGNMENT,
+ width: '40px',
+ isExpander: true,
+ render: item => (
+ toggleDetails(item)}
+ aria-label={itemIdToExpandedRowMap[item.id] ? 'Collapse' : 'Expand'}
+ iconType={itemIdToExpandedRowMap[item.id] ? 'arrowUp' : 'arrowDown'}
+ />
+ ),
+ },
+ ];
const pagination = {
pageIndex: pageIndex,
@@ -129,7 +144,7 @@ export const EditRolesTable = ({ policies, role, onChange, isDisabled, loading})
<>
{
const [isLoading, setIsLoading] = useState(true);
const [currentRole, setCurrentRole] = useState({});
- const [isReserved, setIsReserved] = useState(reservedRoles.includes(role.name));
+ const [isReserved, setIsReserved] = useState(
+ reservedRoles.includes(role.name),
+ );
const [policies, setPolicies] = useState([]);
const [selectedPolicies, setSelectedPolicies] = useState([]);
const [selectedPoliciesError, setSelectedPoliciesError] = useState(false);
@@ -50,27 +49,41 @@ export const EditRole = ({ role, closeFlyout }) => {
async function getData() {
try {
setIsLoading(true);
- const roleDataResponse = await WzRequest.apiReq('GET', '/security/roles', {
- params: {
- role_ids: role.id,
+ const roleDataResponse = await WzRequest.apiReq(
+ 'GET',
+ '/security/roles',
+ {
+ params: {
+ role_ids: role.id,
+ },
},
- });
- const roleData = (((roleDataResponse.data || {}).data || {}).affected_items || [])[0];
+ );
+ const roleData = (((roleDataResponse.data || {}).data || {})
+ .affected_items || [])[0];
setCurrentRole(roleData);
- const policies_request = await WzRequest.apiReq('GET', '/security/policies', {});
+ const policies_request = await WzRequest.apiReq(
+ 'GET',
+ '/security/policies',
+ {},
+ );
const selectedPoliciesCopy = [];
- const policies = (
- (((policies_request || {}).data || {}).data || {}).affected_items || []
- ).map((x) => {
- const currentPolicy = { label: x.name, id: x.id, roles: x.roles, policy: x.policy };
- if (roleData.policies.includes(x.id)) {
- selectedPoliciesCopy.push(currentPolicy);
- return false;
- } else {
- return currentPolicy;
- }
- });
- const filteredPolicies = policies.filter((item) => item !== false);
+ const policies = (policies_request?.data?.data?.affected_items || []).map(
+ x => {
+ const currentPolicy = {
+ label: x.name,
+ id: x.id,
+ roles: x.roles,
+ policy: x.policy,
+ };
+ if (roleData.policies.includes(x.id)) {
+ selectedPoliciesCopy.push(currentPolicy);
+ return false;
+ } else {
+ return currentPolicy;
+ }
+ },
+ );
+ const filteredPolicies = policies.filter(item => item !== false);
setAssignedPolicies(selectedPoliciesCopy);
setPolicies(filteredPolicies);
} catch (error) {
@@ -94,20 +107,26 @@ export const EditRole = ({ role, closeFlyout }) => {
try {
let roleId = currentRole.id;
- const policiesId = selectedPolicies.map((policy) => {
+ const policiesId = selectedPolicies.map(policy => {
return policy.id;
});
- const policyResult = await WzRequest.apiReq('POST', `/security/roles/${roleId}/policies`, {
- params: {
- policy_ids: policiesId.toString(),
+ const policyResult = await WzRequest.apiReq(
+ 'POST',
+ `/security/roles/${roleId}/policies`,
+ {
+ params: {
+ policy_ids: policiesId.toString(),
+ },
},
- });
+ );
const policiesData = (policyResult.data || {}).data;
if (policiesData.failed_items && policiesData.failed_items.length) {
return;
}
- ErrorHandler.info('Role was successfully updated with the selected policies');
+ ErrorHandler.info(
+ 'Role was successfully updated with the selected policies',
+ );
setSelectedPolicies([]);
await update();
} catch (error) {
@@ -130,7 +149,7 @@ export const EditRole = ({ role, closeFlyout }) => {
await getData();
};
- const onChangePolicies = (selectedPolicies) => {
+ const onChangePolicies = selectedPolicies => {
setSelectedPolicies(selectedPolicies);
};
@@ -139,14 +158,14 @@ export const EditRole = ({ role, closeFlyout }) => {
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
+ confirmButtonText='Yes, do it'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -164,45 +183,52 @@ export const EditRole = ({ role, closeFlyout }) => {
return (
<>
-
+
-
+
Edit {role.name} role
- {isReserved && Reserved}
+ {isReserved && Reserved}
-
+
-
-
+
Add policy
-
+
diff --git a/plugins/main/public/components/security/roles/roles-table.tsx b/plugins/main/public/components/security/roles/roles-table.tsx
index 597a8d029a..20a66adcc4 100644
--- a/plugins/main/public/components/security/roles/roles-table.tsx
+++ b/plugins/main/public/components/security/roles/roles-table.tsx
@@ -5,20 +5,25 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiToolTip,
- EuiButtonIcon,
EuiSpacer,
EuiLoadingSpinner,
} from '@elastic/eui';
import { WzRequest } from '../../../react-services/wz-request';
import { ErrorHandler } from '../../../react-services/error-handler';
-import { WzButtonModalConfirm } from '../../common/buttons';
+import { WzButtonPermissionsModalConfirm } from '../../common/buttons';
import { WzAPIUtils } from '../../../react-services/wz-api-utils';
import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../react-services/common-services';
-export const RolesTable = ({ roles, policiesData, loading, editRole, updateRoles }) => {
- const getRowProps = (item) => {
+export const RolesTable = ({
+ roles,
+ policiesData,
+ loading,
+ editRole,
+ updateRoles,
+}) => {
+ const getRowProps = item => {
const { id } = item;
return {
'data-test-subj': `row-${id}`,
@@ -26,7 +31,7 @@ export const RolesTable = ({ roles, policiesData, loading, editRole, updateRoles
};
};
- const onConfirmDeleteRole = (item) => {
+ const onConfirmDeleteRole = item => {
return async () => {
try {
const response = await WzRequest.apiReq('DELETE', `/security/roles/`, {
@@ -55,7 +60,7 @@ export const RolesTable = ({ roles, policiesData, loading, editRole, updateRoles
getErrorOrchestrator().handleError(options);
}
};
- }
+ };
const columns = [
{
@@ -75,32 +80,37 @@ export const RolesTable = ({ roles, policiesData, loading, editRole, updateRoles
{
field: 'policies',
name: 'Policies',
- render: (policies) => {
+ render: policies => {
return (
(policiesData && (
-
- {policies.map((policy) => {
- const data = (policiesData || []).find((x) => x.id === policy) || {};
+
+ {policies.map(policy => {
+ const data =
+ (policiesData || []).find(x => x.id === policy) || {};
return (
data.name && (
Actions
- {((data.policy || {}).actions || []).join(', ')}
-
+
+ {((data.policy || {}).actions || []).join(', ')}
+
+
Resources
- {((data.policy || {}).resources || []).join(', ')}
-
+
+ {((data.policy || {}).resources || []).join(', ')}
+
+
Effect
{(data.policy || {}).effect}
}
>
{}}
onClickAriaLabel={`${data.name} policy`}
title={null}
@@ -113,7 +123,7 @@ export const RolesTable = ({ roles, policiesData, loading, editRole, updateRoles
);
})}
- )) ||
+ )) ||
);
},
sortable: true,
@@ -121,8 +131,12 @@ export const RolesTable = ({ roles, policiesData, loading, editRole, updateRoles
{
field: 'id',
name: 'Status',
- render: (item) => {
- return WzAPIUtils.isReservedID(item) && Reserved;
+ render: item => {
+ return (
+ WzAPIUtils.isReservedID(item) && (
+ Reserved
+ )
+ );
},
width: 150,
sortable: false,
@@ -131,10 +145,13 @@ export const RolesTable = ({ roles, policiesData, loading, editRole, updateRoles
align: 'right',
width: '5%',
name: 'Actions',
- render: (item) => (
-
ev.stopPropagation()}>
-
(
+ ev.stopPropagation()}>
+
),
diff --git a/plugins/main/public/components/security/roles/roles.tsx b/plugins/main/public/components/security/roles/roles.tsx
index f181f1bb77..fc2dc63107 100644
--- a/plugins/main/public/components/security/roles/roles.tsx
+++ b/plugins/main/public/components/security/roles/roles.tsx
@@ -4,47 +4,39 @@ import {
EuiPageContentHeader,
EuiPageContentHeaderSection,
EuiPageContentBody,
- EuiButton,
EuiTitle,
- EuiFlyout,
- EuiOverlayMask,
- EuiFlyoutHeader,
- EuiFlyoutBody,
- EuiForm,
- EuiFormRow,
- EuiSpacer,
- EuiFieldText,
- EuiComboBox
} from '@elastic/eui';
import { RolesTable } from './roles-table';
-import { WzRequest } from '../../../react-services/wz-request'
+import { WzRequest } from '../../../react-services/wz-request';
import { CreateRole } from './create-role';
import { EditRole } from './edit-role';
+import { withUserAuthorizationPrompt } from '../../common/hocs';
+import { WzButtonPermissions } from '../../common/permissions/button';
-export const Roles = () => {
+export const Roles = withUserAuthorizationPrompt([
+ { action: 'security:read', resource: 'role:id:*' },
+ { action: 'security:read', resource: 'policy:id:*' },
+])(() => {
const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
const [isEditFlyoutVisible, setIsEditFlyoutVisible] = useState(false);
const [editingRole, setEditingRole] = useState(false);
- const [roles, setRoles] = useState([])
- const [policiesData, setPoliciesData] = useState([])
+ const [roles, setRoles] = useState([]);
+ const [policiesData, setPoliciesData] = useState([]);
const [loadingTable, setLoadingTable] = useState(false);
-
async function getData() {
setLoadingTable(true);
- const roles_request = await WzRequest.apiReq(
- 'GET',
- '/security/roles',
- {}
- );
- const roles = (((roles_request || {}).data || {}).data || {}).affected_items || [];
+ const roles_request = await WzRequest.apiReq('GET', '/security/roles', {});
+ const roles =
+ (((roles_request || {}).data || {}).data || {}).affected_items || [];
setRoles(roles);
const policies_request = await WzRequest.apiReq(
'GET',
'/security/policies',
- {}
+ {},
);
- const policiesData = (((policies_request || {}).data || {}).data || {}).affected_items || [];
+ const policiesData =
+ (((policies_request || {}).data || {}).data || {}).affected_items || [];
setPoliciesData(policiesData);
setLoadingTable(false);
}
@@ -56,26 +48,30 @@ export const Roles = () => {
let flyout;
if (isFlyoutVisible) {
flyout = (
- {
+ {
setIsFlyoutVisible(isVisible);
await getData();
- }} />
+ }}
+ />
);
}
- const editRole = (item) => {
+ const editRole = item => {
setEditingRole(item);
setIsEditFlyoutVisible(true);
- }
+ };
let editFlyout;
if (isEditFlyoutVisible) {
editFlyout = (
- {
+ {
setIsEditFlyoutVisible(isVisible);
await getData();
- }} />
+ }}
+ />
);
}
@@ -88,23 +84,30 @@ export const Roles = () => {
- {
- !loadingTable
- &&
-
- setIsFlyoutVisible(true)}>
- Create role
-
- {flyout}
- {editFlyout}
-
- }
+ {!loadingTable && (
+
+ setIsFlyoutVisible(true)}
+ >
+ Create role
+
+ {flyout}
+ {editFlyout}
+
+ )}
-
+
);
-};
\ No newline at end of file
+});
diff --git a/plugins/main/public/components/security/users/components/create-user.tsx b/plugins/main/public/components/security/users/components/create-user.tsx
index 9ff0a3a072..2e4bc9288b 100644
--- a/plugins/main/public/components/security/users/components/create-user.tsx
+++ b/plugins/main/public/components/security/users/components/create-user.tsx
@@ -1,8 +1,6 @@
import React, { useEffect, useRef, useState } from 'react';
import {
- EuiButton,
EuiTitle,
- EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
EuiForm,
@@ -14,7 +12,6 @@ import {
EuiFieldPassword,
EuiFieldText,
EuiOverlayMask,
- EuiOutsideClickDetector,
EuiPanel,
EuiConfirmModal,
} from '@elastic/eui';
@@ -34,9 +31,12 @@ import { WzFlyout } from '../../../common/flyouts';
export const CreateUser = ({ closeFlyout }) => {
const [selectedRoles, setSelectedRole] = useState([]);
- const [rolesLoading, roles, rolesError] = useApiService(RolesServices.GetRoles, {});
+ const [rolesLoading, roles, rolesError] = useApiService(
+ RolesServices.GetRoles,
+ {},
+ );
const rolesOptions: any = roles
- ? roles.map((item) => {
+ ? roles.map(item => {
return { label: item.name, id: item.id };
})
: [];
@@ -65,7 +65,7 @@ export const CreateUser = ({ closeFlyout }) => {
else userNameRef.current = true;
},
300,
- [userName]
+ [userName],
);
const passwordRef = useRef(false);
@@ -75,7 +75,7 @@ export const CreateUser = ({ closeFlyout }) => {
else passwordRef.current = true;
},
300,
- [password]
+ [password],
);
const confirmPasswordRef = useRef(false);
@@ -85,7 +85,7 @@ export const CreateUser = ({ closeFlyout }) => {
else confirmPasswordRef.current = true;
},
300,
- [confirmPassword]
+ [confirmPassword],
);
useDebouncedEffect(
@@ -93,13 +93,18 @@ export const CreateUser = ({ closeFlyout }) => {
setShowApply(isValidForm(false));
},
300,
- [userName, password, confirmPassword]
+ [userName, password, confirmPassword],
);
const validations = {
userName: [
{ fn: () => (userName.trim() === '' ? 'The user name is required' : '') },
- { fn: () => (userName.trim().includes(' ') ? 'The user name cannot contain spaces' : '') },
+ {
+ fn: () =>
+ userName.trim().includes(' ')
+ ? 'The user name cannot contain spaces'
+ : '',
+ },
{
fn: () =>
!userName.match(/^.{4,20}$/)
@@ -111,21 +116,29 @@ export const CreateUser = ({ closeFlyout }) => {
{ fn: () => (password === '' ? 'The password is required' : '') },
{
fn: () =>
- !password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,64}$/)
+ !password.match(
+ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,64}$/,
+ )
? 'The password must contain a length between 8 and 64 characters, and must contain at least one upper and lower case letter, a number and a symbol.'
: '',
},
],
confirmPassword: [
- { fn: () => (confirmPassword === '' ? 'The confirm password is required' : '') },
- { fn: () => (confirmPassword !== password ? `Passwords don't match.` : '') },
+ {
+ fn: () =>
+ confirmPassword === '' ? 'The confirm password is required' : '',
+ },
+ {
+ fn: () =>
+ confirmPassword !== password ? `Passwords don't match.` : '',
+ },
],
};
const validateFields = (fields, showErrors = true) => {
const _formErrors = { ...formErrors };
let isValid = true;
- fields.forEach((field) => {
+ fields.forEach(field => {
const error = validations[field].reduce((currentError, validation) => {
return !!currentError ? currentError : validation.fn();
}, '');
@@ -157,7 +170,8 @@ export const CreateUser = ({ closeFlyout }) => {
try {
const user = await UsersServices.CreateUser(userData);
await addRoles(user.id);
- if (allowRunAsData) await UsersServices.UpdateAllowRunAs(user.id, allowRunAsData);
+ if (allowRunAsData)
+ await UsersServices.UpdateAllowRunAs(user.id, allowRunAsData);
ErrorHandler.info('User was successfully created');
closeFlyout(true);
@@ -178,30 +192,31 @@ export const CreateUser = ({ closeFlyout }) => {
}
};
- const addRoles = async (userId) => {
- const formattedRoles = selectedRoles.map((item) => {
+ const addRoles = async userId => {
+ const formattedRoles = selectedRoles.map(item => {
return item.id;
});
- if (formattedRoles.length > 0) await UsersServices.AddUserRoles(userId, formattedRoles);
+ if (formattedRoles.length > 0)
+ await UsersServices.AddUserRoles(userId, formattedRoles);
};
- const onChangeRoles = (selectedRoles) => {
+ const onChangeRoles = selectedRoles => {
setSelectedRole(selectedRoles);
};
- const onChangeUserName = (e) => {
+ const onChangeUserName = e => {
setUserName(e.target.value);
};
- const onChangePassword = (e) => {
+ const onChangePassword = e => {
setPassword(e.target.value);
};
- const onChangeConfirmPassword = (e) => {
+ const onChangeConfirmPassword = e => {
setConfirmPassword(e.target.value);
};
- const onChangeAllowRunAs = (e) => {
+ const onChangeAllowRunAs = e => {
setAllowRunAs(e.target.checked);
};
@@ -210,7 +225,7 @@ export const CreateUser = ({ closeFlyout }) => {
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
@@ -218,7 +233,7 @@ export const CreateUser = ({ closeFlyout }) => {
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
+ confirmButtonText='Yes, do it'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -250,94 +265,114 @@ export const CreateUser = ({ closeFlyout }) => {
<>
-
+
Create new user
-
+
-
+
User data
onChangeUserName(e)}
- aria-label=""
+ onChange={e => onChangeUserName(e)}
+ aria-label=''
isInvalid={!!formErrors.userName}
/>
onChangePassword(e)}
- aria-label=""
+ onChange={e => onChangePassword(e)}
+ aria-label=''
isInvalid={!!formErrors.password}
/>
onChangeConfirmPassword(e)}
- aria-label=""
+ onChange={e => onChangeConfirmPassword(e)}
+ aria-label=''
isInvalid={!!formErrors.confirmPassword}
/>
-
+
onChangeAllowRunAs(e)}
- aria-label=""
+ permissions={[
+ { action: 'security:edit_run_as', resource: '*:*:*' },
+ ]}
+ onChange={e => onChangeAllowRunAs(e)}
+ aria-label=''
/>
-
+
User roles
-
+
-
+
Apply
-
+
diff --git a/plugins/main/public/components/security/users/components/edit-user.tsx b/plugins/main/public/components/security/users/components/edit-user.tsx
index 2f6123df25..12ced6d42b 100644
--- a/plugins/main/public/components/security/users/components/edit-user.tsx
+++ b/plugins/main/public/components/security/users/components/edit-user.tsx
@@ -1,6 +1,5 @@
import React, { useRef, useState, useEffect } from 'react';
import {
- EuiButton,
EuiTitle,
EuiFlyoutHeader,
EuiFlyoutBody,
@@ -35,12 +34,15 @@ import { WzFlyout } from '../../../common/flyouts';
export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
const userRolesFormatted =
currentUser.roles && currentUser.roles.length
- ? currentUser.roles.map((item) => ({ label: rolesObject[item], id: item }))
+ ? currentUser.roles.map(item => ({ label: rolesObject[item], id: item }))
: [];
const [selectedRoles, setSelectedRole] = useState(userRolesFormatted);
- const [rolesLoading, roles, rolesError] = useApiService(RolesServices.GetRoles, {});
+ const [rolesLoading, roles, rolesError] = useApiService(
+ RolesServices.GetRoles,
+ {},
+ );
const rolesOptions: any = roles
- ? roles.map((item) => {
+ ? roles.map(item => {
return { label: item.name, id: item.id };
})
: [];
@@ -50,7 +52,9 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
const [confirmPassword, setConfirmPassword] = useState('');
const [initialPassword] = useState('');
const [hasChanges, setHasChanges] = useState(false);
- const [allowRunAs, setAllowRunAs] = useState(currentUser.allow_run_as);
+ const [allowRunAs, setAllowRunAs] = useState(
+ currentUser.allow_run_as,
+ );
const [isModalVisible, setIsModalVisible] = useState(false);
const [formErrors, setFormErrors] = useState({
password: '',
@@ -65,7 +69,7 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
else passwordRef.current = true;
},
300,
- [password]
+ [password],
);
const confirmPasswordRef = useRef(false);
@@ -75,7 +79,7 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
else confirmPasswordRef.current = true;
},
300,
- [confirmPassword]
+ [confirmPassword],
);
useDebouncedEffect(
@@ -84,12 +88,12 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
isValidForm(false) &&
(allowRunAs !== currentUser.allow_run_as ||
password !== '' ||
- Object.values(getRolesDiff()).some((i) => i.length));
+ Object.values(getRolesDiff()).some(i => i.length));
setShowApply(_showApply);
},
300,
- [password, confirmPassword, allowRunAs, selectedRoles]
+ [password, confirmPassword, allowRunAs, selectedRoles],
);
const validations = {
@@ -97,18 +101,25 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
{
fn: () =>
password !== '' &&
- !password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,64}$/)
+ !password.match(
+ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,64}$/,
+ )
? 'The password must contain a length between 8 and 64 characters, and must contain at least one upper and lower case letter, a number and a symbol.'
: '',
},
],
- confirmPassword: [{ fn: () => (confirmPassword !== password ? `Passwords don't match.` : '') }],
+ confirmPassword: [
+ {
+ fn: () =>
+ confirmPassword !== password ? `Passwords don't match.` : '',
+ },
+ ],
};
const validateFields = (fields, showErrors = true) => {
const _formErrors = { ...formErrors };
let isValid = true;
- fields.forEach((field) => {
+ fields.forEach(field => {
const error = validations[field].reduce((currentError, validation) => {
return !!currentError ? currentError : validation.fn();
}, '');
@@ -136,7 +147,9 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
const allowRunAsData: boolean = allowRunAs;
if (allowRunAsData != currentUser.allow_run_as)
- userPromises.push(UsersServices.UpdateAllowRunAs(currentUser.id, allowRunAsData));
+ userPromises.push(
+ UsersServices.UpdateAllowRunAs(currentUser.id, allowRunAsData),
+ );
if (password) {
userData.password = password;
@@ -167,32 +180,37 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
};
const getRolesDiff = () => {
- const formattedRoles = selectedRoles.map((item) => item.id);
- const _userRolesFormatted = userRolesFormatted.map((role) => role.id);
- const toAdd = formattedRoles.filter((value) => !_userRolesFormatted.includes(value));
- const toRemove = _userRolesFormatted.filter((value) => !formattedRoles.includes(value));
+ const formattedRoles = selectedRoles.map(item => item.id);
+ const _userRolesFormatted = userRolesFormatted.map(role => role.id);
+ const toAdd = formattedRoles.filter(
+ value => !_userRolesFormatted.includes(value),
+ );
+ const toRemove = _userRolesFormatted.filter(
+ value => !formattedRoles.includes(value),
+ );
return { toAdd, toRemove };
};
const updateRoles = async () => {
const { toAdd, toRemove } = getRolesDiff();
if (toAdd.length) await UsersServices.AddUserRoles(currentUser.id, toAdd);
- if (toRemove.length) await UsersServices.RemoveUserRoles(currentUser.id, toRemove);
+ if (toRemove.length)
+ await UsersServices.RemoveUserRoles(currentUser.id, toRemove);
};
- const onChangeRoles = (selectedRoles) => {
+ const onChangeRoles = selectedRoles => {
setSelectedRole(selectedRoles);
};
- const onChangePassword = (e) => {
+ const onChangePassword = e => {
setPassword(e.target.value);
};
- const onChangeConfirmPassword = (e) => {
+ const onChangeConfirmPassword = e => {
setConfirmPassword(e.target.value);
};
- const onChangeAllowRunAs = (e) => {
+ const onChangeAllowRunAs = e => {
setAllowRunAs(e.target.checked);
};
@@ -201,7 +219,7 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
modal = (
{
setIsModalVisible(false);
closeFlyout(false);
@@ -209,7 +227,7 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
}}
onCancel={() => setIsModalVisible(false)}
cancelButtonText="No, don't do it"
- confirmButtonText="Yes, do it"
+ confirmButtonText='Yes, do it'
>
There are unsaved changes. Are you sure you want to proceed?
@@ -221,8 +239,10 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
useEffect(() => {
if (
- initialPassword != password || initialPassword != confirmPassword ||
- !_.isEqual(userRolesFormatted, selectedRoles) || allowRunAs != currentUser.allow_run_as
+ initialPassword != password ||
+ initialPassword != confirmPassword ||
+ !_.isEqual(userRolesFormatted, selectedRoles) ||
+ allowRunAs != currentUser.allow_run_as
) {
setHasChanges(true);
} else {
@@ -238,65 +258,70 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
<>
-
+
Edit {currentUser.username} user
{WzAPIUtils.isReservedID(currentUser.id) && (
- Reserved
+ Reserved
)}
-
+
-
+
Run as
-
+
onChangeAllowRunAs(e)}
- aria-label=""
+ permissions={[
+ { action: 'security:edit_run_as', resource: '*:*:*' },
+ ]}
+ onChange={e => onChangeAllowRunAs(e)}
+ aria-label=''
disabled={WzAPIUtils.isReservedID(currentUser.id)}
/>
-
+
Password
onChangePassword(e)}
- aria-label=""
+ onChange={e => onChangePassword(e)}
+ aria-label=''
isInvalid={!!formErrors.password}
disabled={WzAPIUtils.isReservedID(currentUser.id)}
/>
onChangeConfirmPassword(e)}
- aria-label=""
+ onChange={e => onChangeConfirmPassword(e)}
+ aria-label=''
isInvalid={!!formErrors.confirmPassword}
disabled={WzAPIUtils.isReservedID(currentUser.id)}
/>
@@ -304,18 +329,18 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
-
+
Roles
-
+
@@ -324,14 +349,31 @@ export const EditUser = ({ currentUser, closeFlyout, rolesObject }) => {
-
Apply
-
+
diff --git a/plugins/main/public/components/security/users/components/users-table.tsx b/plugins/main/public/components/security/users/components/users-table.tsx
index b0add823bb..9f9bb51f91 100644
--- a/plugins/main/public/components/security/users/components/users-table.tsx
+++ b/plugins/main/public/components/security/users/components/users-table.tsx
@@ -8,7 +8,7 @@ import {
EuiBasicTableColumn,
SortDirection,
} from '@elastic/eui';
-import { WzButtonModalConfirm } from '../../../common/buttons';
+import { WzButtonPermissionsModalConfirm } from '../../../common/buttons';
import UsersServices from '../services';
import { ErrorHandler } from '../../../../react-services/error-handler';
import { WzAPIUtils } from '../../../../react-services/wz-api-utils';
@@ -16,7 +16,13 @@ import { UI_LOGGER_LEVELS } from '../../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../../react-services/common-services';
-export const UsersTable = ({ users, editUserFlyover, rolesLoading, roles, onSave }) => {
+export const UsersTable = ({
+ users,
+ editUserFlyover,
+ rolesLoading,
+ roles,
+ onSave,
+}) => {
const getRowProps = item => {
const { id } = item;
return {
@@ -25,7 +31,7 @@ export const UsersTable = ({ users, editUserFlyover, rolesLoading, roles, onSave
};
};
- const onConfirmDeleteUser = (item) => {
+ const onConfirmDeleteUser = item => {
return async () => {
try {
await UsersServices.DeleteUsers([item.id]);
@@ -67,18 +73,18 @@ export const UsersTable = ({ users, editUserFlyover, rolesLoading, roles, onSave
dataType: 'boolean',
render: userRoles => {
if (rolesLoading) {
- return ;
+ return ;
}
if (!userRoles || !userRoles.length) return <>>;
const tmpRoles = userRoles.map((userRole, idx) => {
return (
- {roles[userRole]}
+ {roles[userRole]}
);
});
return (
-
+
{tmpRoles}
);
@@ -91,21 +97,26 @@ export const UsersTable = ({ users, editUserFlyover, rolesLoading, roles, onSave
name: 'Actions',
render: item => (
ev.stopPropagation()}>
-
),
diff --git a/plugins/main/public/components/security/users/users.tsx b/plugins/main/public/components/security/users/users.tsx
index f837cc6d0c..4672e4c18e 100644
--- a/plugins/main/public/components/security/users/users.tsx
+++ b/plugins/main/public/components/security/users/users.tsx
@@ -4,9 +4,7 @@ import {
EuiPageContentHeader,
EuiPageContentHeaderSection,
EuiPageContentBody,
- EuiButton,
EuiTitle,
- EuiOverlayMask,
EuiEmptyPrompt,
} from '@elastic/eui';
import { UsersTable } from './components/users-table';
@@ -20,13 +18,21 @@ import { Role } from '../roles/types/role.type';
import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../react-services/common-services';
+import { withUserAuthorizationPrompt } from '../../common/hocs';
+import { WzButtonPermissions } from '../../common/permissions/button';
-export const Users = () => {
+export const Users = withUserAuthorizationPrompt([
+ { action: 'security:read', resource: 'user:id:*' },
+ { action: 'security:read', resource: 'role:id:*' },
+])(() => {
const [isEditFlyoutVisible, setIsEditFlyoutVisible] = useState(false);
const [isCreateFlyoutVisible, setIsCreateFlyoutVisible] = useState(false);
const [editingUser, setEditingUser] = useState({});
const [users, setUsers] = useState([] as User[]);
- const [rolesLoading, roles, rolesError] = useApiService(RolesServices.GetRoles, {});
+ const [rolesLoading, roles, rolesError] = useApiService(
+ RolesServices.GetRoles,
+ {},
+ );
const [securityError, setSecurityError] = useState(false);
const [rolesObject, setRolesObject] = useState({});
@@ -56,7 +62,7 @@ export const Users = () => {
if (!rolesLoading && (roles || []).length) {
const _rolesObject = (roles || []).reduce(
(rolesObj, role) => ({ ...rolesObj, [role.id]: role.name }),
- {}
+ {},
);
setRolesObject(_rolesObject);
}
@@ -75,7 +81,7 @@ export const Users = () => {
setIsEditFlyoutVisible(false);
};
- const closeCreateFlyout = async (refresh) => {
+ const closeCreateFlyout = async refresh => {
if (refresh) await getUsers();
setIsCreateFlyoutVisible(false);
};
@@ -83,7 +89,7 @@ export const Users = () => {
if (securityError) {
return (
You need permission to manage users}
body={Contact your system administrator.
}
/>
@@ -91,18 +97,16 @@ export const Users = () => {
}
if (isEditFlyoutVisible) {
editFlyout = (
-
+
);
}
if (isCreateFlyoutVisible) {
- createFlyout = (
-
- );
+ createFlyout = ;
}
const showEditFlyover = item => {
@@ -119,14 +123,20 @@ export const Users = () => {
- {
- !rolesLoading
- &&
+ {!rolesLoading && (
- setIsCreateFlyoutVisible(true)}>Create user
+ setIsCreateFlyoutVisible(true)}
+ >
+ Create user
+
{createFlyout}
- }
+ )}
@@ -141,4 +151,4 @@ export const Users = () => {
{editFlyout}
);
-};
+});