diff --git a/ci/Dockerfile b/ci/Dockerfile deleted file mode 100644 index 308f01373..000000000 --- a/ci/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -ARG DOCKER_VERSION_ARG -FROM opensearchstaging/opensearch:${DOCKER_VERSION_ARG} -#FROM phaseshiftstudio/opensearch:2.4.0-old-with-security -SHELL ["/bin/bash","-x","-e","-c"] -ARG PLUGIN_ARG -ENV PLUGIN ${PLUGIN_ARG} -RUN if [ -d /usr/share/opensearch/plugins/opensearch-security-analytics ]; then /usr/share/opensearch/bin/opensearch-plugin remove opensearch-security-analytics; fi; - -ADD build/distributions/$PLUGIN /tmp/ -ADD ./ /opt/opensearch-security-analytics -USER root -COPY --chown=opensearch:opensearch ci/roles.yml /usr/share/opensearch/config/opensearch-security/roles.yml -RUN chown -R opensearch:opensearch /opt/opensearch-security-analytics -USER opensearch -RUN /usr/share/opensearch/bin/opensearch-plugin install --batch file:/tmp/$PLUGIN \ No newline at end of file diff --git a/ci/docker_build.sh b/ci/docker_build.sh deleted file mode 100755 index 41c0a0dbe..000000000 --- a/ci/docker_build.sh +++ /dev/null @@ -1,20 +0,0 @@ -plugin=`basename $(ls build/distributions/*.zip)` -list_of_files=`ls` -list_of_all_files=`ls build/distributions/` -version=`echo $plugin|awk -F- '{print $3}'| cut -d. -f 1-3` -plugin_version=`echo $plugin | cut -d '-' -f 4 | cut -d '.' -f 1-3` -qualifier=`echo $plugin|awk -F- '{print $4}'| cut -d. -f 1-1` -candidate_version=`echo $plugin|awk -F- '{print $5}'| cut -d. -f 1-1` -docker_version=2.4.0 - -[[ -z $candidate_version ]] && candidate_version=$qualifier && qualifier="" - -echo plugin version plugin_version qualifier candidate_version docker_version -echo "($plugin) ($version) ($plugin_version) ($qualifier) ($candidate_version) ($docker_version)" -echo $ls $list_of_all_files - -docker pull opensearchstaging/opensearch:$docker_version -docker build -t opensearch-alerting-security-analytics:$docker_version \ - --build-arg DOCKER_VERSION_ARG="$docker_version" \ - --build-arg PLUGIN_ARG="$plugin" \ - -f ci/Dockerfile . diff --git a/ci/roles.yml b/ci/roles.yml deleted file mode 100644 index d692f60ae..000000000 --- a/ci/roles.yml +++ /dev/null @@ -1,292 +0,0 @@ -_meta: - type: "roles" - config_version: 2 - -# Restrict users so they can only view visualization and dashboard on OpenSearchDashboards -kibana_read_only: - reserved: true - -# The security REST API access role is used to assign specific users access to change the security settings through the REST API. -security_rest_api_access: - reserved: true - -# Allows users to view monitors, destinations and alerts -alerting_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/alerting/alerts/get' - - 'cluster:admin/opendistro/alerting/destination/get' - - 'cluster:admin/opendistro/alerting/monitor/get' - - 'cluster:admin/opendistro/alerting/monitor/search' - - 'cluster:admin/opensearch/alerting/findings/get' - -# Allows users to view and acknowledge alerts -alerting_ack_alerts: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/alerting/alerts/*' - -# Allows users to use all alerting functionality -alerting_full_access: - reserved: true - cluster_permissions: - - 'cluster_monitor' - - 'cluster:admin/opendistro/alerting/*' - - 'cluster:admin/opensearch/alerting/*' - - 'cluster:admin/opensearch/notifications/feature/publish' - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - 'indices_monitor' - - 'indices:admin/aliases/get' - - 'indices:admin/mappings/get' - -# Allow users to read Anomaly Detection detectors and results -anomaly_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/ad/detector/info' - - 'cluster:admin/opendistro/ad/detector/search' - - 'cluster:admin/opendistro/ad/detectors/get' - - 'cluster:admin/opendistro/ad/result/search' - - 'cluster:admin/opendistro/ad/tasks/search' - - 'cluster:admin/opendistro/ad/detector/validate' - - 'cluster:admin/opendistro/ad/result/topAnomalies' - -# Allows users to use all Anomaly Detection functionality -anomaly_full_access: - reserved: true - cluster_permissions: - - 'cluster_monitor' - - 'cluster:admin/opendistro/ad/*' - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - 'indices_monitor' - - 'indices:admin/aliases/get' - - 'indices:admin/mappings/get' - -# Allows users to read Notebooks -notebooks_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/notebooks/list' - - 'cluster:admin/opendistro/notebooks/get' - -# Allows users to all Notebooks functionality -notebooks_full_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/notebooks/create' - - 'cluster:admin/opendistro/notebooks/update' - - 'cluster:admin/opendistro/notebooks/delete' - - 'cluster:admin/opendistro/notebooks/get' - - 'cluster:admin/opendistro/notebooks/list' - -# Allows users to read observability objects -observability_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/observability/get' - -# Allows users to all Observability functionality -observability_full_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/observability/create' - - 'cluster:admin/opensearch/observability/update' - - 'cluster:admin/opensearch/observability/delete' - - 'cluster:admin/opensearch/observability/get' - -# Allows users to read and download Reports -reports_instances_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/reports/instance/list' - - 'cluster:admin/opendistro/reports/instance/get' - - 'cluster:admin/opendistro/reports/menu/download' - -# Allows users to read and download Reports and Report-definitions -reports_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/reports/definition/get' - - 'cluster:admin/opendistro/reports/definition/list' - - 'cluster:admin/opendistro/reports/instance/list' - - 'cluster:admin/opendistro/reports/instance/get' - - 'cluster:admin/opendistro/reports/menu/download' - -# Allows users to all Reports functionality -reports_full_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/reports/definition/create' - - 'cluster:admin/opendistro/reports/definition/update' - - 'cluster:admin/opendistro/reports/definition/on_demand' - - 'cluster:admin/opendistro/reports/definition/delete' - - 'cluster:admin/opendistro/reports/definition/get' - - 'cluster:admin/opendistro/reports/definition/list' - - 'cluster:admin/opendistro/reports/instance/list' - - 'cluster:admin/opendistro/reports/instance/get' - - 'cluster:admin/opendistro/reports/menu/download' - -# Allows users to use all asynchronous-search functionality -asynchronous_search_full_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/asynchronous_search/*' - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - 'indices:data/read/search*' - -# Allows users to read stored asynchronous-search results -asynchronous_search_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opendistro/asynchronous_search/get' - -# Allows user to use all index_management actions - ism policies, rollups, transforms -index_management_full_access: - reserved: true - cluster_permissions: - - "cluster:admin/opendistro/ism/*" - - "cluster:admin/opendistro/rollup/*" - - "cluster:admin/opendistro/transform/*" - - "cluster:admin/opensearch/notifications/feature/publish" - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - 'indices:admin/opensearch/ism/*' - -# Allows users to use all cross cluster replication functionality at leader cluster -cross_cluster_replication_leader_full_access: - reserved: true - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - "indices:admin/plugins/replication/index/setup/validate" - - "indices:data/read/plugins/replication/changes" - - "indices:data/read/plugins/replication/file_chunk" - -# Allows users to use all cross cluster replication functionality at follower cluster -cross_cluster_replication_follower_full_access: - reserved: true - cluster_permissions: - - "cluster:admin/plugins/replication/autofollow/update" - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - "indices:admin/plugins/replication/index/setup/validate" - - "indices:data/write/plugins/replication/changes" - - "indices:admin/plugins/replication/index/start" - - "indices:admin/plugins/replication/index/pause" - - "indices:admin/plugins/replication/index/resume" - - "indices:admin/plugins/replication/index/stop" - - "indices:admin/plugins/replication/index/update" - - "indices:admin/plugins/replication/index/status_check" - -# Allow users to read ML stats/models/tasks -ml_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/ml/stats/nodes' - - 'cluster:admin/opensearch/ml/models/get' - - 'cluster:admin/opensearch/ml/models/search' - - 'cluster:admin/opensearch/ml/tasks/get' - - 'cluster:admin/opensearch/ml/tasks/search' - -# Allows users to use all ML functionality -ml_full_access: - reserved: true - cluster_permissions: - - 'cluster_monitor' - - 'cluster:admin/opensearch/ml/*' - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - 'indices_monitor' - -# Allows users to use all Notifications functionality -notifications_full_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/notifications/*' - -# Allows users to read Notifications config/channels -notifications_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/notifications/configs/get' - - 'cluster:admin/opensearch/notifications/features' - - 'cluster:admin/opensearch/notifications/channels/get' - -# Allows users to use all snapshot management functionality -snapshot_management_full_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/snapshot_management/*' - - 'cluster:admin/opensearch/notifications/feature/publish' - - 'cluster:admin/repository/*' - - 'cluster:admin/snapshot/*' - -# Allows users to see snapshots, repositories, and snapshot management policies -snapshot_management_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/snapshot_management/policy/get' - - 'cluster:admin/opensearch/snapshot_management/policy/search' - - 'cluster:admin/opensearch/snapshot_management/policy/explain' - - 'cluster:admin/repository/get' - - 'cluster:admin/snapshot/get' - -# Allows user to use point in time functionality -point_in_time_full_access: - reserved: true - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - 'manage_point_in_time' - -# Allows users to see security analytics detectors and others -security_analytics_read_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/securityanalytics/alerts/get' - - 'cluster:admin/opensearch/securityanalytics/detector/get' - - 'cluster:admin/opensearch/securityanalytics/detector/search' - - 'cluster:admin/opensearch/securityanalytics/findings/get' - - 'cluster:admin/opensearch/securityanalytics/mapping/get' - - 'cluster:admin/opensearch/securityanalytics/mapping/view/get' - - 'cluster:admin/opensearch/securityanalytics/rule/get' - - 'cluster:admin/opensearch/securityanalytics/rule/search' - -# Allows users to use all security analytics functionality -security_analytics_full_access: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/securityanalytics/alerts/*' - - 'cluster:admin/opensearch/securityanalytics/detector/*' - - 'cluster:admin/opensearch/securityanalytics/findings/*' - - 'cluster:admin/opensearch/securityanalytics/mapping/*' - - 'cluster:admin/opensearch/securityanalytics/rule/*' - index_permissions: - - index_patterns: - - '*' - allowed_actions: - - 'indices:admin/mapping/put' - - 'indices:admin/mappings/get' - -# Allows users to view and acknowledge alerts -security_analytics_ack_alerts: - reserved: true - cluster_permissions: - - 'cluster:admin/opensearch/securityanalytics/alerts/*' diff --git a/src/test/java/org/opensearch/securityanalytics/SecurityAnalyticsRestTestCase.java b/src/test/java/org/opensearch/securityanalytics/SecurityAnalyticsRestTestCase.java index 7cb512963..df0ecca18 100644 --- a/src/test/java/org/opensearch/securityanalytics/SecurityAnalyticsRestTestCase.java +++ b/src/test/java/org/opensearch/securityanalytics/SecurityAnalyticsRestTestCase.java @@ -18,7 +18,6 @@ import org.junit.After; import org.opensearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.opensearch.action.search.SearchResponse; -import org.opensearch.client.Client; import org.opensearch.client.Request; import org.opensearch.client.RequestOptions; import org.opensearch.client.Response; @@ -73,7 +72,7 @@ import static org.opensearch.action.admin.indices.create.CreateIndexRequest.MAPPINGS; import static org.opensearch.securityanalytics.TestHelpers.sumAggregationTestRule; import static org.opensearch.securityanalytics.TestHelpers.productIndexAvgAggRule; -import static org.opensearch.securityanalytics.util.RuleTopicIndices.ruleTopicIndexMappings; +import static org.opensearch.securityanalytics.TestHelpers.windowsIndexMapping; import static org.opensearch.securityanalytics.util.RuleTopicIndices.ruleTopicIndexSettings; public class SecurityAnalyticsRestTestCase extends OpenSearchRestTestCase { @@ -109,6 +108,22 @@ protected void createRuleTopicIndex(String detectorType, String additionalMappin } } + protected final List clusterPermissions = List.of( + "cluster:admin/opensearch/securityanalytics/detector/*", + "cluster:admin/opendistro/alerting/alerts/*", + "cluster:admin/opendistro/alerting/findings/*", + "cluster:admin/opensearch/securityanalytics/mapping/*", + "cluster:admin/opensearch/securityanalytics/rule/*" + ); + + protected final List indexPermissions = List.of( + "indices:admin/mappings/get", + "indices:admin/mapping/put", + "indices:data/read/search" + ); + + protected static String TEST_HR_ROLE = "hr_role"; + protected String createTestIndex(String index, String mapping) throws IOException { createTestIndex(index, mapping, Settings.EMPTY); return index; @@ -1012,7 +1027,7 @@ protected RestClient buildClient(Settings settings, HttpHost[] hosts) throws IOE } - protected void createCustomRoleWithIndexPermissions(String name, List clusterPermissions, List indexPermission, List indexPatterns) throws IOException { + protected void createIndexRole(String name, List clusterPermissions, List indexPermission, List indexPatterns) throws IOException { Response response; try { response = client().performRequest(new Request("GET", String.format(Locale.getDefault(), "/_plugins/_security/api/roles/%s", name))); @@ -1059,7 +1074,7 @@ protected void createCustomRole(String name, String clusterPermissions) throws I client().performRequest(request); } - protected void createUser(String name, String passwd, String[] backendRoles) throws IOException { + public void createUser(String name, String passwd, String[] backendRoles) throws IOException { Request request = new Request("PUT", String.format(Locale.getDefault(), "/_plugins/_security/api/internalusers/%s", name)); String broles = String.join(",", backendRoles); //String roles = String.join(",", customRoles); @@ -1101,7 +1116,7 @@ protected void createUserWithDataAndCustomRole(String userName, String userPass protected void createUserWithDataAndCustomRole(String userName, String userPasswd, String roleName, String[] backendRoles, List clusterPermissions, List indexPermissions, List indexPatterns) throws IOException { String[] users = {userName}; createUser(userName, userPasswd, backendRoles); - createCustomRoleWithIndexPermissions(roleName, clusterPermissions, indexPermissions, indexPatterns); + createIndexRole(roleName, clusterPermissions, indexPermissions, indexPatterns); createUserRolesMapping(roleName, users); } @@ -1111,16 +1126,31 @@ protected void createUserWithData(String userName, String userPasswd, String ro createUserRolesMapping(roleName, users); } - + public void createUserWithTestData(String user, String index, String role, String [] backendRoles, List indexPermissions) throws IOException{ + String[] users = {user}; + createUser(user, user, backendRoles); + createTestIndex(client(), index, windowsIndexMapping(), Settings.EMPTY); + createIndexRole(role, Collections.emptyList(), indexPermissions, List.of(index)); + createUserRolesMapping(role, users); + } protected void deleteUser(String name) throws IOException { Request request = new Request("DELETE", String.format(Locale.getDefault(), "/_plugins/_security/api/internalusers/%s", name)); client().performRequest(request); } - protected void deleteRole(String name) throws IOException{ - Request request = new Request("DELETE", String.format(Locale.getDefault(), "/_plugins/_security/api/roles/%s", name)); - client().performRequest(request); + protected void tryDeletingRole(String name) throws IOException{ + Response response; + try { + response = client().performRequest(new Request("GET", String.format(Locale.getDefault(), "/_plugins/_security/api/roles/%s", name))); + } catch (ResponseException ex) { + response = ex.getResponse(); + } + // Role already exists + if(response.getStatusLine().getStatusCode() == RestStatus.OK.getStatus()) { + Request request = new Request("DELETE", String.format(Locale.getDefault(), "/_plugins/_security/api/roles/%s", name)); + client().performRequest(request); + } } @Override diff --git a/src/test/java/org/opensearch/securityanalytics/alerts/SecureAlertsRestApiIT.java b/src/test/java/org/opensearch/securityanalytics/alerts/SecureAlertsRestApiIT.java index 6039f16ea..1ab77714a 100644 --- a/src/test/java/org/opensearch/securityanalytics/alerts/SecureAlertsRestApiIT.java +++ b/src/test/java/org/opensearch/securityanalytics/alerts/SecureAlertsRestApiIT.java @@ -22,7 +22,6 @@ import org.opensearch.search.SearchHit; import org.opensearch.securityanalytics.SecurityAnalyticsPlugin; import org.opensearch.securityanalytics.SecurityAnalyticsRestTestCase; -import org.opensearch.securityanalytics.action.AlertDto; import org.opensearch.securityanalytics.config.monitors.DetectorMonitorConfig; import org.opensearch.securityanalytics.model.Detector; import org.opensearch.securityanalytics.model.DetectorInput; @@ -34,7 +33,6 @@ import java.util.stream.Collectors; import static org.opensearch.securityanalytics.TestHelpers.*; -import static org.opensearch.securityanalytics.settings.SecurityAnalyticsSettings.*; public class SecureAlertsRestApiIT extends SecurityAnalyticsRestTestCase { @@ -63,252 +61,265 @@ public void cleanup() throws IOException { @SuppressWarnings("unchecked") public void testGetAlerts_byDetectorId_success() throws IOException { - String index = createTestIndex(randomIndex(), windowsIndexMapping()); + try { + String[] backendHrRoles = {TEST_HR_BACKEND_ROLE}; + String index = randomIndex(); + createUserWithTestData(user, index, TEST_HR_ROLE, backendHrRoles, indexPermissions); - String rule = randomRule(); + String rule = randomRule(); - Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.RULE_BASE_URI, Collections.singletonMap("category", randomDetectorType()), + Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.RULE_BASE_URI, Collections.singletonMap("category", randomDetectorType()), new StringEntity(rule), new BasicHeader("Content-Type", "application/json")); - Assert.assertEquals("Create rule failed", RestStatus.CREATED, restStatus(createResponse)); + Assert.assertEquals("Create rule failed", RestStatus.CREATED, restStatus(createResponse)); - Map responseBody = asMap(createResponse); + Map responseBody = asMap(createResponse); - String createdId = responseBody.get("_id").toString(); + String createdId = responseBody.get("_id").toString(); - // Execute CreateMappingsAction to add alias mapping for index - Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); - // both req params and req body are supported - createMappingRequest.setJsonEntity( + // Execute CreateMappingsAction to add alias mapping for index + Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); + // both req params and req body are supported + createMappingRequest.setJsonEntity( "{ \"index_name\":\"" + index + "\"," + - " \"rule_topic\":\"" + randomDetectorType() + "\", " + - " \"partial\":true" + - "}" - ); + " \"rule_topic\":\"" + randomDetectorType() + "\", " + + " \"partial\":true" + + "}" + ); - Response response = userClient.performRequest(createMappingRequest); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + Response response = userClient.performRequest(createMappingRequest); + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); - createAlertingMonitorConfigIndex(null); - Action triggerAction = randomAction(createDestination()); + createAlertingMonitorConfigIndex(null); + Action triggerAction = randomAction(createDestination()); - Detector detector = randomDetectorWithInputsAndTriggers(List.of(new DetectorInput("windows detector for security analytics", List.of("windows"), List.of(new DetectorRule(createdId)), - getRandomPrePackagedRules().stream().map(DetectorRule::new).collect(Collectors.toList()))), + Detector detector = randomDetectorWithInputsAndTriggers(List.of(new DetectorInput("windows detector for security analytics", List.of("windows"), List.of(new DetectorRule(createdId)), + getRandomPrePackagedRules().stream().map(DetectorRule::new).collect(Collectors.toList()))), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(), List.of(createdId), List.of(), List.of("attack.defense_evasion"), List.of(triggerAction)))); - createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); - Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); + createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); + Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); - responseBody = asMap(createResponse); + responseBody = asMap(createResponse); - createdId = responseBody.get("_id").toString(); + createdId = responseBody.get("_id").toString(); - String request = "{\n" + + String request = "{\n" + " \"query\" : {\n" + " \"match\":{\n" + " \"_id\": \"" + createdId + "\"\n" + " }\n" + " }\n" + "}"; - List hits = executeSearch(Detector.DETECTORS_INDEX, request); - SearchHit hit = hits.get(0); + List hits = executeSearch(Detector.DETECTORS_INDEX, request); + SearchHit hit = hits.get(0); - String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); + String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); - indexDoc(index, "1", randomDoc()); + indexDoc(index, "1", randomDoc()); - Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); - Map executeResults = entityAsMap(executeResponse); + Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); + Map executeResults = entityAsMap(executeResponse); - int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); - Assert.assertEquals(6, noOfSigmaRuleMatches); + int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); + Assert.assertEquals(6, noOfSigmaRuleMatches); - Assert.assertEquals(1, ((Map) executeResults.get("trigger_results")).values().size()); + Assert.assertEquals(1, ((Map) executeResults.get("trigger_results")).values().size()); - for (Map.Entry> triggerResult: ((Map>) executeResults.get("trigger_results")).entrySet()) { - Assert.assertEquals(1, ((Map) triggerResult.getValue().get("action_results")).values().size()); + for (Map.Entry> triggerResult: ((Map>) executeResults.get("trigger_results")).entrySet()) { + Assert.assertEquals(1, ((Map) triggerResult.getValue().get("action_results")).values().size()); - for (Map.Entry> alertActionResult: ((Map>) triggerResult.getValue().get("action_results")).entrySet()) { - Map actionResults = alertActionResult.getValue(); + for (Map.Entry> alertActionResult: ((Map>) triggerResult.getValue().get("action_results")).entrySet()) { + Map actionResults = alertActionResult.getValue(); - for (Map.Entry actionResult: actionResults.entrySet()) { - Map actionOutput = ((Map>) actionResult.getValue()).get("output"); - String expectedMessage = triggerAction.getSubjectTemplate().getIdOrCode().replace("{{ctx.detector.name}}", detector.getName()) + for (Map.Entry actionResult: actionResults.entrySet()) { + Map actionOutput = ((Map>) actionResult.getValue()).get("output"); + String expectedMessage = triggerAction.getSubjectTemplate().getIdOrCode().replace("{{ctx.detector.name}}", detector.getName()) .replace("{{ctx.trigger.name}}", "test-trigger").replace("{{ctx.trigger.severity}}", "1"); - Assert.assertEquals(expectedMessage, actionOutput.get("subject")); - Assert.assertEquals(expectedMessage, actionOutput.get("message")); + Assert.assertEquals(expectedMessage, actionOutput.get("subject")); + Assert.assertEquals(expectedMessage, actionOutput.get("message")); + } } } - } - request = "{\n" + + request = "{\n" + " \"query\" : {\n" + " \"match_all\":{\n" + " }\n" + " }\n" + "}"; - hits = new ArrayList<>(); + hits = new ArrayList<>(); - while (hits.size() == 0) { - hits = executeSearch(DetectorMonitorConfig.getAlertsIndex(randomDetectorType()), request); - } + while (hits.size() == 0) { + hits = executeSearch(DetectorMonitorConfig.getAlertsIndex(randomDetectorType()), request); + } - // try to do get finding as a user with read access - String userRead = "userReadAlert"; - String[] backendRoles = { TEST_IT_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); - RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - - // Call GetAlerts API - Map params = new HashMap<>(); - params.put("detector_id", createdId); - Response getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - Map getAlertsBody = asMap(getAlertsResponse); - Assert.assertEquals(1, getAlertsBody.get("total_alerts")); - - // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector - enableOrDisableFilterBy("true"); - try { - getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - } catch (ResponseException e) - { - assertEquals("Get alert failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); - } - finally { - userReadOnlyClient.close(); - deleteUser(userRead); - } + // try to do get finding as a user with read access + String userRead = "userReadAlert"; + String[] backendRoles = { TEST_IT_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); + RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + + // Call GetAlerts API + Map params = new HashMap<>(); + params.put("detector_id", createdId); + Response getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); + Map getAlertsBody = asMap(getAlertsResponse); + Assert.assertEquals(1, getAlertsBody.get("total_alerts")); + + // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector + enableOrDisableFilterBy("true"); + try { + getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); + } catch (ResponseException e) + { + assertEquals("Get alert failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } - // recreate user with matching backend roles and try again - String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - getAlertsBody = asMap(getAlertsResponse); - Assert.assertEquals(1, getAlertsBody.get("total_alerts")); - userReadOnlyClient.close(); - - // update user with no backend roles and try again - createUser(userRead, userRead, EMPTY_ARRAY); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - try { + // recreate user with matching backend roles and try again + String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - } catch (ResponseException e) - { - assertEquals("Get alert failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); - } - finally { + getAlertsBody = asMap(getAlertsResponse); + Assert.assertEquals(1, getAlertsBody.get("total_alerts")); userReadOnlyClient.close(); - deleteUser(userRead); + + // update user with no backend roles and try again + createUser(userRead, userRead, EMPTY_ARRAY); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + try { + getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); + } catch (ResponseException e) + { + assertEquals("Get alert failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } + } finally { + tryDeletingRole(TEST_HR_ROLE); } + } public void testGetAlerts_byDetectorType_success() throws IOException, InterruptedException { - String index = createTestIndex(randomIndex(), windowsIndexMapping()); - - // Execute CreateMappingsAction to add alias mapping for index - Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); - // both req params and req body are supported - createMappingRequest.setJsonEntity( + try { + String[] backendHrRoles = {TEST_HR_BACKEND_ROLE}; + String index = randomIndex(); + createUserWithTestData(user, index, TEST_HR_ROLE, backendHrRoles, indexPermissions); + + // Execute CreateMappingsAction to add alias mapping for index + Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); + // both req params and req body are supported + createMappingRequest.setJsonEntity( "{ \"index_name\":\"" + index + "\"," + - " \"rule_topic\":\"" + randomDetectorType() + "\", " + - " \"partial\":true" + - "}" - ); + " \"rule_topic\":\"" + randomDetectorType() + "\", " + + " \"partial\":true" + + "}" + ); - Response response = userClient.performRequest(createMappingRequest); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + Response response = userClient.performRequest(createMappingRequest); + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); - Detector detector = randomDetectorWithTriggers(getRandomPrePackagedRules(), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(randomDetectorType()), List.of(), List.of(), List.of(), List.of()))); + Detector detector = randomDetectorWithTriggers(getRandomPrePackagedRules(), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(randomDetectorType()), List.of(), List.of(), List.of(), List.of()))); - Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); - Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); + Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); + Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); - Map responseBody = asMap(createResponse); + Map responseBody = asMap(createResponse); - String createdId = responseBody.get("_id").toString(); + String createdId = responseBody.get("_id").toString(); - String request = "{\n" + + String request = "{\n" + " \"query\" : {\n" + " \"match\":{\n" + " \"_id\": \"" + createdId + "\"\n" + " }\n" + " }\n" + "}"; - List hits = executeSearch(Detector.DETECTORS_INDEX, request); - SearchHit hit = hits.get(0); + List hits = executeSearch(Detector.DETECTORS_INDEX, request); + SearchHit hit = hits.get(0); - String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); + String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); - indexDoc(index, "1", randomDoc()); + indexDoc(index, "1", randomDoc()); - client().performRequest(new Request("POST", "_refresh")); + client().performRequest(new Request("POST", "_refresh")); - Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); - Map executeResults = entityAsMap(executeResponse); - int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); - Assert.assertEquals(5, noOfSigmaRuleMatches); + Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); + Map executeResults = entityAsMap(executeResponse); + int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); + Assert.assertEquals(5, noOfSigmaRuleMatches); - request = "{\n" + + request = "{\n" + " \"query\" : {\n" + " \"match_all\":{\n" + " }\n" + " }\n" + "}"; - hits = new ArrayList<>(); + hits = new ArrayList<>(); - while (hits.size() == 0) { - hits = executeSearch(DetectorMonitorConfig.getAlertsIndex(randomDetectorType()), request); - } + while (hits.size() == 0) { + hits = executeSearch(DetectorMonitorConfig.getAlertsIndex(randomDetectorType()), request); + } - // try to do get finding as a user with read access - String userRead = "userReadAlert"; - String[] backendRoles = { TEST_IT_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); - RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - - // Call GetAlerts API - Map params = new HashMap<>(); - params.put("detectorType", randomDetectorType()); - Response getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - Map getAlertsBody = asMap(getAlertsResponse); - Assert.assertEquals(1, getAlertsBody.get("total_alerts")); - - // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector - enableOrDisableFilterBy("true"); - try { - getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - } catch (ResponseException e) - { - assertEquals("Get alert failed", RestStatus.NOT_FOUND, restStatus(e.getResponse())); - } - finally { - userReadOnlyClient.close(); - deleteUser(userRead); - } + // try to do get finding as a user with read access + String userRead = "userReadAlert"; + String[] backendRoles = { TEST_IT_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); + RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + + // Call GetAlerts API + Map params = new HashMap<>(); + params.put("detectorType", randomDetectorType()); + Response getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); + Map getAlertsBody = asMap(getAlertsResponse); + Assert.assertEquals(1, getAlertsBody.get("total_alerts")); + + // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector + enableOrDisableFilterBy("true"); + try { + getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); + } catch (ResponseException e) + { + assertEquals("Get alert failed", RestStatus.NOT_FOUND, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } - // recreate user with matching backend roles and try again - String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - getAlertsBody = asMap(getAlertsResponse); - Assert.assertEquals(1, getAlertsBody.get("total_alerts")); - userReadOnlyClient.close(); - - // update user with no backend roles and try again - createUser(userRead, userRead, EMPTY_ARRAY); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - try { + // recreate user with matching backend roles and try again + String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); - } catch (ResponseException e) - { - assertEquals("Get alert failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); - } - finally { + getAlertsBody = asMap(getAlertsResponse); + Assert.assertEquals(1, getAlertsBody.get("total_alerts")); userReadOnlyClient.close(); - deleteUser(userRead); + + // update user with no backend roles and try again + createUser(userRead, userRead, EMPTY_ARRAY); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + try { + getAlertsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.ALERTS_BASE_URI, params, null); + } catch (ResponseException e) + { + assertEquals("Get alert failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } + } finally { + tryDeletingRole(TEST_HR_ROLE); } } diff --git a/src/test/java/org/opensearch/securityanalytics/findings/SecureFindingRestApiIT.java b/src/test/java/org/opensearch/securityanalytics/findings/SecureFindingRestApiIT.java index e95235bab..2b42b6861 100644 --- a/src/test/java/org/opensearch/securityanalytics/findings/SecureFindingRestApiIT.java +++ b/src/test/java/org/opensearch/securityanalytics/findings/SecureFindingRestApiIT.java @@ -66,248 +66,260 @@ public void cleanup() throws IOException { @SuppressWarnings("unchecked") public void testGetFindings_byDetectorId_success() throws IOException { - String index = createTestIndex(randomIndex(), windowsIndexMapping()); - - // Execute CreateMappingsAction to add alias mapping for index - Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); - // both req params and req body are supported - createMappingRequest.setJsonEntity( + try { + String[] backendHrRoles = {TEST_HR_BACKEND_ROLE}; + String index = randomIndex(); + createUserWithTestData(user, index, TEST_HR_ROLE, backendHrRoles, indexPermissions); + + // Execute CreateMappingsAction to add alias mapping for index + Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); + // both req params and req body are supported + createMappingRequest.setJsonEntity( "{ \"index_name\":\"" + index + "\"," + " \"rule_topic\":\"" + randomDetectorType() + "\", " + " \"partial\":true" + "}" - ); - - Response response = userClient.performRequest(createMappingRequest); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); - - Detector detector = randomDetectorWithTriggers(getRandomPrePackagedRules(), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(randomDetectorType()), List.of(), List.of(), List.of(), List.of()))); - - Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); - Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); - - Map responseBody = asMap(createResponse); - - String createdId = responseBody.get("_id").toString(); - - String request = "{\n" + - " \"query\" : {\n" + - " \"match\":{\n" + - " \"_id\": \"" + createdId + "\"\n" + - " }\n" + - " }\n" + - "}"; - List hits = executeSearch(Detector.DETECTORS_INDEX, request); - SearchHit hit = hits.get(0); - - String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); - - indexDoc(index, "1", randomDoc()); + ); + + Response response = userClient.performRequest(createMappingRequest); + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + + Detector detector = randomDetectorWithTriggers(getRandomPrePackagedRules(), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(randomDetectorType()), List.of(), List.of(), List.of(), List.of()))); + + Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); + Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); + + Map responseBody = asMap(createResponse); + + String createdId = responseBody.get("_id").toString(); + + String request = "{\n" + + " \"query\" : {\n" + + " \"match\":{\n" + + " \"_id\": \"" + createdId + "\"\n" + + " }\n" + + " }\n" + + "}"; + List hits = executeSearch(Detector.DETECTORS_INDEX, request); + SearchHit hit = hits.get(0); + + String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get( + "monitor_id")).get(0); + + indexDoc(index, "1", randomDoc()); + + Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); + Map executeResults = entityAsMap(executeResponse); + + int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); + Assert.assertEquals(5, noOfSigmaRuleMatches); + + // try to do get finding as a user with read access + String userRead = "userReadFinding"; + String[] backendRoles = { TEST_IT_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); + RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + // Call GetFindings API + Map params = new HashMap<>(); + params.put("detector_id", createdId); + Response getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); + Map getFindingsBody = entityAsMap(getFindingsResponse); + Assert.assertEquals(1, getFindingsBody.get("total_findings")); + + // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector + enableOrDisableFilterBy("true"); + try { + getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); + } catch (ResponseException e) + { + assertEquals("Get finding failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } - Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); - Map executeResults = entityAsMap(executeResponse); - - int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); - Assert.assertEquals(5, noOfSigmaRuleMatches); - - // try to do get finding as a user with read access - String userRead = "userReadFinding"; - String[] backendRoles = { TEST_IT_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); - RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - // Call GetFindings API - Map params = new HashMap<>(); - params.put("detector_id", createdId); - Response getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - Map getFindingsBody = entityAsMap(getFindingsResponse); - Assert.assertEquals(1, getFindingsBody.get("total_findings")); - - // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector - enableOrDisableFilterBy("true"); - try { + // recreate user with matching backend roles and try again + String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - } catch (ResponseException e) - { - assertEquals("Get finding failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); - } - finally { + getFindingsBody = entityAsMap(getFindingsResponse); + Assert.assertEquals(1, getFindingsBody.get("total_findings")); userReadOnlyClient.close(); - deleteUser(userRead); - } - - // recreate user with matching backend roles and try again - String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - getFindingsBody = entityAsMap(getFindingsResponse); - Assert.assertEquals(1, getFindingsBody.get("total_findings")); - userReadOnlyClient.close(); // update user with no backend roles and try again - createUser(userRead, userRead, EMPTY_ARRAY); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - try { - getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - } catch (ResponseException e) - { - assertEquals("Get finding failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + createUser(userRead, userRead, EMPTY_ARRAY); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + try { + getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); + } catch (ResponseException e) + { + assertEquals("Get finding failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } + } finally { + tryDeletingRole(TEST_HR_ROLE); } - finally { - userReadOnlyClient.close(); - deleteUser(userRead); - } - } public void testGetFindings_byDetectorType_success() throws IOException { - String index1 = createTestIndex(randomIndex(), windowsIndexMapping()); + try { + String index1 = createTestIndex(randomIndex(), windowsIndexMapping()); - // Execute CreateMappingsAction to add alias mapping for index - Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); - // both req params and req body are supported - createMappingRequest.setJsonEntity( + // Execute CreateMappingsAction to add alias mapping for index + Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); + // both req params and req body are supported + createMappingRequest.setJsonEntity( "{ \"index_name\":\"" + index1 + "\"," + - " \"rule_topic\":\"" + randomDetectorType() + "\", " + - " \"partial\":true" + - "}" - ); - // index 2 - String index2 = createTestIndex("netflow_test", netFlowMappings()); - - // Execute CreateMappingsAction to add alias mapping for index - createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); - // both req params and req body are supported - createMappingRequest.setJsonEntity( + " \"rule_topic\":\"" + randomDetectorType() + "\", " + + " \"partial\":true" + + "}" + ); + Response response = userClient.performRequest(createMappingRequest); + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + // index 2 + String index2 = createTestIndex("netflow_test", netFlowMappings()); + // Execute CreateMappingsAction to add alias mapping for index + createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); + // both req params and req body are supported + createMappingRequest.setJsonEntity( "{ \"index_name\":\"" + index2 + "\"," + " \"rule_topic\":\"netflow\", " + " \"partial\":true" + "}" ); - Response response = userClient.performRequest(createMappingRequest); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); - // Detector 1 - WINDOWS - Detector detector1 = randomDetectorWithTriggers(getRandomPrePackagedRules(), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(randomDetectorType()), List.of(), List.of(), List.of(), List.of()))); - Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector1)); - Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); - - Map responseBody = asMap(createResponse); - - String createdId = responseBody.get("_id").toString(); - - String request = "{\n" + - " \"query\" : {\n" + - " \"match\":{\n" + - " \"_id\": \"" + createdId + "\"\n" + - " }\n" + - " }\n" + - "}"; - List hits = executeSearch(Detector.DETECTORS_INDEX, request); - SearchHit hit = hits.get(0); - String monitorId1 = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); - // Detector 2 - NETWORK - DetectorInput inputNetflow = new DetectorInput("windows detector for security analytics", List.of("netflow_test"), Collections.emptyList(), - getPrePackagedRules("network").stream().map(DetectorRule::new).collect(Collectors.toList())); - Detector detector2 = randomDetectorWithTriggers( - getPrePackagedRules("network"), - List.of(new DetectorTrigger(null, "test-trigger", "1", List.of("network"), List.of(), List.of(), List.of(), List.of())), - Detector.DetectorType.NETWORK, - inputNetflow - ); - - createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector2)); - Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); - - responseBody = asMap(createResponse); - - createdId = responseBody.get("_id").toString(); - - request = "{\n" + - " \"query\" : {\n" + - " \"match\":{\n" + - " \"_id\": \"" + createdId + "\"\n" + - " }\n" + - " }\n" + - "}"; - hits = executeSearch(Detector.DETECTORS_INDEX, request); - hit = hits.get(0); - String monitorId2 = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); - - indexDoc(index1, "1", randomDoc()); - indexDoc(index2, "1", randomDoc()); - // execute monitor 1 - Response executeResponse = executeAlertingMonitor(monitorId1, Collections.emptyMap()); - Map executeResults = entityAsMap(executeResponse); - - int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); - Assert.assertEquals(3, noOfSigmaRuleMatches); - - // execute monitor 2 - executeResponse = executeAlertingMonitor(monitorId2, Collections.emptyMap()); - executeResults = entityAsMap(executeResponse); - - noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); - Assert.assertEquals(1, noOfSigmaRuleMatches); - - client().performRequest(new Request("POST", "_refresh")); - - - // try to do get finding as a user with read access - String userRead = "userReadFinding"; - String[] backendRoles = { TEST_IT_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); - RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - - - // Call GetFindings API for first detector - Map params = new HashMap<>(); - params.put("detectorType", detector1.getDetectorType().toUpperCase()); - Response getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - Map getFindingsBody = entityAsMap(getFindingsResponse); - Assert.assertEquals(1, getFindingsBody.get("total_findings")); - // Call GetFindings API for second detector - params.clear(); - params.put("detectorType", detector2.getDetectorType().toUpperCase()); - getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - getFindingsBody = entityAsMap(getFindingsResponse); - Assert.assertEquals(1, getFindingsBody.get("total_findings")); - - // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector - enableOrDisableFilterBy("true"); - try { + response = userClient.performRequest(createMappingRequest); + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + // Detector 1 - WINDOWS + Detector detector1 = randomDetectorWithTriggers(getRandomPrePackagedRules(), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(randomDetectorType()), List.of(), List.of(), List.of(), List.of()))); + Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector1)); + Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); + + Map responseBody = asMap(createResponse); + + String createdId = responseBody.get("_id").toString(); + + String request = "{\n" + + " \"query\" : {\n" + + " \"match\":{\n" + + " \"_id\": \"" + createdId + "\"\n" + + " }\n" + + " }\n" + + "}"; + List hits = executeSearch(Detector.DETECTORS_INDEX, request); + SearchHit hit = hits.get(0); + String monitorId1 = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); + // Detector 2 - NETWORK + DetectorInput inputNetflow = new DetectorInput("windows detector for security analytics", List.of("netflow_test"), Collections.emptyList(), + getPrePackagedRules("network").stream().map(DetectorRule::new).collect(Collectors.toList())); + Detector detector2 = randomDetectorWithTriggers( + getPrePackagedRules("network"), + List.of(new DetectorTrigger(null, "test-trigger", "1", List.of("network"), List.of(), List.of(), List.of(), List.of())), + Detector.DetectorType.NETWORK, + inputNetflow + ); + + createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector2)); + Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); + + responseBody = asMap(createResponse); + + createdId = responseBody.get("_id").toString(); + + request = "{\n" + + " \"query\" : {\n" + + " \"match\":{\n" + + " \"_id\": \"" + createdId + "\"\n" + + " }\n" + + " }\n" + + "}"; + hits = executeSearch(Detector.DETECTORS_INDEX, request); + hit = hits.get(0); + String monitorId2 = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); + + indexDoc(index1, "1", randomDoc()); + indexDoc(index2, "1", randomDoc()); + // execute monitor 1 + Response executeResponse = executeAlertingMonitor(monitorId1, Collections.emptyMap()); + Map executeResults = entityAsMap(executeResponse); + + int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get( + "input_results")).get("results")).get(0).size(); + Assert.assertEquals(5, noOfSigmaRuleMatches); + + // execute monitor 2 + executeResponse = executeAlertingMonitor(monitorId2, Collections.emptyMap()); + executeResults = entityAsMap(executeResponse); + + noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get( + "input_results")).get("results")).get(0).size(); + Assert.assertEquals(1, noOfSigmaRuleMatches); + + client().performRequest(new Request("POST", "_refresh")); + + // try to do get finding as a user with read access + String userRead = "userReadFinding"; + String[] backendRoles = { TEST_IT_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); + RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + + + // Call GetFindings API for first detector + Map params = new HashMap<>(); + params.put("detectorType", detector1.getDetectorType().toUpperCase()); + Response getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); + Map getFindingsBody = entityAsMap(getFindingsResponse); + Assert.assertEquals(1, getFindingsBody.get("total_findings")); + // Call GetFindings API for second detector + params.clear(); + params.put("detectorType", detector2.getDetectorType().toUpperCase()); getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - } catch (ResponseException e) - { - assertEquals("Get finding failed", RestStatus.NOT_FOUND, restStatus(e.getResponse())); - } - finally { + getFindingsBody = entityAsMap(getFindingsResponse); + Assert.assertEquals(1, getFindingsBody.get("total_findings")); + + // Enable backend filtering and try to read finding as a user with no backend roles matching the user who created the detector + enableOrDisableFilterBy("true"); + try { + getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); + } catch (ResponseException e) + { + assertEquals("Get finding failed", RestStatus.NOT_FOUND, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } + + // recreate user with matching backend roles and try again + String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); + getFindingsBody = entityAsMap(getFindingsResponse); + Assert.assertEquals(1, getFindingsBody.get("total_findings")); userReadOnlyClient.close(); - deleteUser(userRead); - } - - // recreate user with matching backend roles and try again - String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - getFindingsBody = entityAsMap(getFindingsResponse); - Assert.assertEquals(1, getFindingsBody.get("total_findings")); - userReadOnlyClient.close(); - // update user with no backend roles and try again - createUser(userRead, userRead, EMPTY_ARRAY); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - try { - getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); - } catch (ResponseException e) - { - assertEquals("Get finding failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); - } - finally { - userReadOnlyClient.close(); - deleteUser(userRead); + // update user with no backend roles and try again + createUser(userRead, userRead, EMPTY_ARRAY); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + try { + getFindingsResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null); + } catch (ResponseException e) + { + assertEquals("Get finding failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } + } finally { + tryDeletingRole(TEST_HR_ROLE); } } } diff --git a/src/test/java/org/opensearch/securityanalytics/resthandler/SecureDetectorRestApiIT.java b/src/test/java/org/opensearch/securityanalytics/resthandler/SecureDetectorRestApiIT.java index f44e5f422..46de914e6 100644 --- a/src/test/java/org/opensearch/securityanalytics/resthandler/SecureDetectorRestApiIT.java +++ b/src/test/java/org/opensearch/securityanalytics/resthandler/SecureDetectorRestApiIT.java @@ -38,7 +38,6 @@ public class SecureDetectorRestApiIT extends SecurityAnalyticsRestTestCase { static String SECURITY_ANALYTICS_FULL_ACCESS_ROLE = "security_analytics_full_access"; static String SECURITY_ANALYTICS_READ_ACCESS_ROLE = "security_analytics_read_access"; static String TEST_HR_BACKEND_ROLE = "HR"; - static String CUSTOM_HR_ROLE = "HR"; static String TEST_IT_BACKEND_ROLE = "IT"; @@ -47,20 +46,6 @@ public class SecureDetectorRestApiIT extends SecurityAnalyticsRestTestCase { Map.entry(SECURITY_ANALYTICS_READ_ACCESS_ROLE, "cluster:admin/opendistro/securityanalytics/detector/read") ); - private final List clusterPermissions = List.of( - "cluster:admin/opensearch/securityanalytics/detector/*", - "cluster:admin/opendistro/alerting/alerts/*", - "cluster:admin/opendistro/alerting/findings/*", - "cluster:admin/opensearch/securityanalytics/mapping/*", - "cluster:admin/opensearch/securityanalytics/rule/*" - ); - - private final List indexPermissions = List.of( - "indices:admin/mappings/get", - "indices:admin/mapping/put", - "indices:data/read/search" - ); - private RestClient userClient; private final String user = "userDetector"; @@ -82,102 +67,107 @@ public void cleanup() throws IOException { @SuppressWarnings("unchecked") public void testCreateDetectorWithFullAccess() throws IOException { - String[] users = {user}; - //createUserRolesMapping("alerting_full_access", users); - String index = createTestIndex(client(), randomIndex(), windowsIndexMapping(), Settings.EMPTY); + try { + //createUserRolesMapping("alerting_full_access", users); + String[] backendHrRoles = { TEST_HR_BACKEND_ROLE }; + String index = randomIndex(); + createUserWithTestData(user, index, TEST_HR_ROLE, backendHrRoles, indexPermissions); - // Execute CreateMappingsAction to add alias mapping for index - Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); - // both req params and req body are supported - createMappingRequest.setJsonEntity( + // Execute CreateMappingsAction to add alias mapping for index + Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); + // both req params and req body are supported + createMappingRequest.setJsonEntity( "{ \"index_name\":\"" + index + "\"," + - " \"rule_topic\":\"" + randomDetectorType() + "\", " + - " \"partial\":true" + - "}" - ); - - Response response = userClient.performRequest(createMappingRequest); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + " \"rule_topic\":\"" + randomDetectorType() + "\", " + + " \"partial\":true" + + "}" + ); - Detector detector = randomDetector(getRandomPrePackagedRules()); + Response response = userClient.performRequest(createMappingRequest); + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); - Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); - Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); + Detector detector = randomDetector(getRandomPrePackagedRules()); - Map responseBody = asMap(createResponse); + Response createResponse = makeRequest(userClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); + Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); - String createdId = responseBody.get("_id").toString(); - int createdVersion = Integer.parseInt(responseBody.get("_version").toString()); - Assert.assertNotEquals("response is missing Id", Detector.NO_ID, createdId); - Assert.assertTrue("incorrect version", createdVersion > 0); - Assert.assertEquals("Incorrect Location header", String.format(Locale.getDefault(), "%s/%s", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, createdId), createResponse.getHeader("Location")); - Assert.assertFalse(((Map) responseBody.get("detector")).containsKey("rule_topic_index")); - Assert.assertFalse(((Map) responseBody.get("detector")).containsKey("findings_index")); - Assert.assertFalse(((Map) responseBody.get("detector")).containsKey("alert_index")); + Map responseBody = asMap(createResponse); - String request = "{\n" + + String createdId = responseBody.get("_id").toString(); + int createdVersion = Integer.parseInt(responseBody.get("_version").toString()); + Assert.assertNotEquals("response is missing Id", Detector.NO_ID, createdId); + Assert.assertTrue("incorrect version", createdVersion > 0); + Assert.assertEquals("Incorrect Location header", String.format(Locale.getDefault(), "%s/%s", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, createdId), createResponse.getHeader("Location")); + Assert.assertFalse(((Map) responseBody.get("detector")).containsKey("rule_topic_index")); + Assert.assertFalse(((Map) responseBody.get("detector")).containsKey("findings_index")); + Assert.assertFalse(((Map) responseBody.get("detector")).containsKey("alert_index")); + + String request = "{\n" + " \"query\" : {\n" + " \"match\":{\n" + " \"_id\": \"" + createdId + "\"\n" + " }\n" + " }\n" + "}"; - List hits = executeSearch(Detector.DETECTORS_INDEX, request); - SearchHit hit = hits.get(0); + List hits = executeSearch(Detector.DETECTORS_INDEX, request); + SearchHit hit = hits.get(0); - String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); + String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); - indexDoc(index, "1", randomDoc()); + indexDoc(index, "1", randomDoc()); - Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); - Map executeResults = entityAsMap(executeResponse); + Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); + Map executeResults = entityAsMap(executeResponse); - int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); - Assert.assertEquals(5, noOfSigmaRuleMatches); + int noOfSigmaRuleMatches = ((List>) ((Map) executeResults.get("input_results")).get("results")).get(0).size(); + Assert.assertEquals(5, noOfSigmaRuleMatches); - // try to do get detector as a user with read access - String userRead = "userRead"; - String[] backendRoles = { TEST_IT_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); - RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - Response getResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + createdId, Collections.emptyMap(), null); - Map getResponseBody = asMap(getResponse); - Assert.assertEquals(createdId, getResponseBody.get("_id")); + // try to do get detector as a user with read access + String userRead = "userRead"; + String[] backendRoles = { TEST_IT_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, backendRoles ); + RestClient userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); + Response getResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + createdId, Collections.emptyMap(), null); + Map getResponseBody = asMap(getResponse); + Assert.assertEquals(createdId, getResponseBody.get("_id")); - // Enable backend filtering and try to read detector as a user with no backend roles matching the user who created the detector - enableOrDisableFilterBy("true"); - try { + // Enable backend filtering and try to read detector as a user with no backend roles matching the user who created the detector + enableOrDisableFilterBy("true"); + try { + getResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + createdId, Collections.emptyMap(), null); + } catch (ResponseException e) + { + assertEquals("Get detector failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); + } + finally { + userReadOnlyClient.close(); + deleteUser(userRead); + } + + // recreate user with matching backend roles and try again + String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; + createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); + userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); getResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + createdId, Collections.emptyMap(), null); - } catch (ResponseException e) - { - assertEquals("Get detector failed", RestStatus.FORBIDDEN, restStatus(e.getResponse())); - } - finally { + getResponseBody = asMap(getResponse); + Assert.assertEquals(createdId, getResponseBody.get("_id")); + + //Search on id should give one result + String queryJson = "{ \"query\": { \"match\": { \"_id\" : \"" + createdId + "\"} } }"; + HttpEntity requestEntity = new NStringEntity(queryJson, ContentType.APPLICATION_JSON); + Response searchResponse = makeRequest(userReadOnlyClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + "_search", Collections.emptyMap(), requestEntity); + Map searchResponseBody = asMap(searchResponse); + Assert.assertNotNull("response is not null", searchResponseBody); + Map searchResponseHits = (Map) searchResponseBody.get("hits"); + Map searchResponseTotal = (Map) searchResponseHits.get("total"); + Assert.assertEquals(1, searchResponseTotal.get("value")); + userReadOnlyClient.close(); deleteUser(userRead); + } finally { + tryDeletingRole(TEST_HR_ROLE); } - - // recreate user with matching backend roles and try again - String[] newBackendRoles = { TEST_HR_BACKEND_ROLE }; - createUserWithData( userRead, userRead, SECURITY_ANALYTICS_READ_ACCESS_ROLE, newBackendRoles ); - userReadOnlyClient = new SecureRestClientBuilder(getClusterHosts().toArray(new HttpHost[]{}), isHttps(), userRead, userRead).setSocketTimeout(60000).build(); - getResponse = makeRequest(userReadOnlyClient, "GET", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + createdId, Collections.emptyMap(), null); - getResponseBody = asMap(getResponse); - Assert.assertEquals(createdId, getResponseBody.get("_id")); - - //Search on id should give one result - String queryJson = "{ \"query\": { \"match\": { \"_id\" : \"" + createdId + "\"} } }"; - HttpEntity requestEntity = new NStringEntity(queryJson, ContentType.APPLICATION_JSON); - Response searchResponse = makeRequest(userReadOnlyClient, "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + "_search", Collections.emptyMap(), requestEntity); - Map searchResponseBody = asMap(searchResponse); - Assert.assertNotNull("response is not null", searchResponseBody); - Map searchResponseHits = (Map) searchResponseBody.get("hits"); - Map searchResponseTotal = (Map) searchResponseHits.get("total"); - Assert.assertEquals(1, searchResponseTotal.get("value")); - - userReadOnlyClient.close(); - deleteUser(userRead); } public void testCreateDetectorWithNoBackendRoles() throws IOException { @@ -279,11 +269,11 @@ public void testCreateDetectorIndexAccess() throws IOException { } finally { if(clientWithoutAccess!= null) clientWithoutAccess.close(); deleteUser(userWithoutAccess); - deleteRole(roleNameWithoutIndexPatternAccess); + tryDeletingRole(roleNameWithoutIndexPatternAccess); if (clientWithAccess != null) clientWithAccess.close(); deleteUser(userWithAccess); - deleteRole(roleNameWithIndexPatternAccess); + tryDeletingRole(roleNameWithIndexPatternAccess); } } @@ -355,12 +345,11 @@ public void testUpdateDetectorIndexAccess() throws IOException { } finally { if (clientWithoutAccess != null) clientWithoutAccess.close(); deleteUser(userWithoutAccess); - deleteRole(roleNameWithoutIndexPatternAccess); + tryDeletingRole(roleNameWithoutIndexPatternAccess); if (clientWithAccess != null) clientWithAccess.close(); deleteUser(userWithAccess); - deleteRole(roleNameWithIndexPatternAccess); + tryDeletingRole(roleNameWithIndexPatternAccess); } } - } \ No newline at end of file diff --git a/src/test/resources/alerting/opensearch-alerting-2.4.0.0.zip b/src/test/resources/alerting/opensearch-alerting-2.4.0.0.zip deleted file mode 100644 index ae41d56d1..000000000 Binary files a/src/test/resources/alerting/opensearch-alerting-2.4.0.0.zip and /dev/null differ diff --git a/src/test/resources/notifications-core/opensearch-notifications-core-2.4.0.0.zip b/src/test/resources/notifications-core/opensearch-notifications-core-2.4.0.0.zip deleted file mode 100644 index 954f8d7eb..000000000 Binary files a/src/test/resources/notifications-core/opensearch-notifications-core-2.4.0.0.zip and /dev/null differ diff --git a/src/test/resources/notifications/opensearch-notifications-2.4.0.0.zip b/src/test/resources/notifications/opensearch-notifications-2.4.0.0.zip deleted file mode 100644 index da37f6a9b..000000000 Binary files a/src/test/resources/notifications/opensearch-notifications-2.4.0.0.zip and /dev/null differ