METRON-1337 List of facets should not be hardcoded (merrimanr) closes apache/metron#853
Project: http://git-wip-us.apache.org/repos/asf/metron/repo Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/e22479e6 Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/e22479e6 Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/e22479e6 Branch: refs/heads/master Commit: e22479e62fab2ae64de1ab803e0f9f0a5fab98b3 Parents: 9b4b402 Author: merrimanr <[email protected]> Authored: Tue Mar 6 08:09:22 2018 -0600 Committer: merrimanr <[email protected]> Committed: Tue Mar 6 08:09:22 2018 -0600 ---------------------------------------------------------------------- .../CURRENT/configuration/metron-rest-env.xml | 12 + .../common-services/METRON/CURRENT/metainfo.xml | 7 + .../CURRENT/package/scripts/metron_service.py | 10 + .../package/scripts/params/params_linux.py | 7 +- .../package/scripts/params/status_params.py | 7 +- .../CURRENT/package/scripts/rest_commands.py | 69 +++- .../CURRENT/package/scripts/rest_master.py | 14 +- .../alert-filters/alert-filters.e2e-spec.ts | 11 +- .../meta-alerts/meta-alert.e2e-spec.ts | 5 +- .../alerts-list/tree-view/tree-view.e2e-spec.ts | 5 +- .../alert-filters/alert-filters.component.ts | 4 +- .../src/app/model/search-request.ts | 2 +- .../app/shared/group-by/group-by.component.ts | 4 +- .../apache/metron/rest/model/AlertProfile.java | 88 ----- .../metron/rest/model/AlertsUIUserSettings.java | 90 +++++ metron-interface/metron-rest/README.md | 53 ++- .../apache/metron/rest/MetronRestConstants.java | 4 + .../apache/metron/rest/config/HBaseConfig.java | 55 +++ .../metron/rest/controller/AlertController.java | 119 ------- .../rest/controller/AlertsUIController.java | 124 +++++++ .../metron/rest/controller/UserController.java | 3 +- .../rest/repository/AlertProfileRepository.java | 25 -- .../metron/rest/service/AlertService.java | 39 --- .../rest/service/AlertsProfileService.java | 32 -- .../metron/rest/service/AlertsUIService.java | 41 +++ .../apache/metron/rest/service/UserService.java | 33 ++ .../rest/service/impl/AlertServiceImpl.java | 97 ------ .../service/impl/AlertsProfileServiceImpl.java | 66 ---- .../rest/service/impl/AlertsUIServiceImpl.java | 131 +++++++ .../rest/service/impl/SearchServiceImpl.java | 22 +- .../src/main/resources/application-test.yml | 2 + .../src/main/resources/application.yml | 9 +- .../metron/rest/config/HBaseConfigTest.java | 69 ++++ .../apache/metron/rest/config/TestConfig.java | 26 +- .../AlertControllerIntegrationTest.java | 345 ------------------- .../AlertsUIControllerIntegrationTest.java | 340 ++++++++++++++++++ .../SearchControllerIntegrationTest.java | 61 +++- .../UserControllerIntegrationTest.java | 40 ++- .../rest/service/impl/AlertServiceImplTest.java | 152 -------- .../service/impl/AlertsUIServiceImplTest.java | 180 ++++++++++ .../service/impl/SearchServiceImplTest.java | 60 +++- .../elasticsearch/dao/ElasticsearchDao.java | 23 +- .../metron/hbase/client/UserSettingsClient.java | 175 ++++++++++ .../hbase/client/UserSettingsClientTest.java | 101 ++++++ .../apache/metron/hbase/mock/MockHTable.java | 7 +- .../indexing/dao/search/SearchRequest.java | 15 +- .../metron/indexing/dao/search/SortField.java | 15 + .../apache/metron/indexing/dao/InMemoryDao.java | 18 + 48 files changed, 1742 insertions(+), 1075 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml ---------------------------------------------------------------------- diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml index 8ba29b5..78ea27e 100644 --- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml +++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml @@ -144,4 +144,16 @@ <editable-only-at-install>true</editable-only-at-install> </value-attributes> </property> + <property> + <name>user_settings_hbase_table</name> + <value>user_settings</value> + <description>The HBase table which will hold user settings</description> + <display-name>User Settings HBase Table</display-name> + </property> + <property> + <name>user_settings_hbase_cf</name> + <value>cf</value> + <description>The HBase column family which will hold user settings in HBase.</description> + <display-name>User Settings HBase Column Family</display-name> + </property> </configuration> http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml ---------------------------------------------------------------------- diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml index 2b5b405..7a680a4 100644 --- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml +++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml @@ -241,6 +241,13 @@ </auto-deploy> </dependency> <dependency> + <name>HBASE/HBASE_CLIENT</name> + <scope>host</scope> + <auto-deploy> + <enabled>true</enabled> + </auto-deploy> + </dependency> + <dependency> <name>ZOOKEEPER/ZOOKEEPER_SERVER</name> <scope>cluster</scope> <auto-deploy> http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py ---------------------------------------------------------------------- diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py index 330d3c0..2478b8b 100644 --- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py +++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py @@ -94,6 +94,16 @@ def build_global_config_patch(params, patch_file): "op": "add", "path": "/profiler.client.period.duration.units", "value": "{{profiler_period_units}}" + }, + { + "op": "add", + "path": "/user.settings.hbase.table", + "value": "{{user_settings_hbase_table}}" + }, + { + "op": "add", + "path": "/user.settings.hbase.cf", + "value": "{{user_settings_hbase_cf}}" } ] """ http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py ---------------------------------------------------------------------- diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py index 3506fab..ceb9e4e 100755 --- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py +++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py @@ -72,7 +72,6 @@ metron_zookeeper_config_path = status_params.metron_zookeeper_config_path zk_configured_flag_file = status_params.zk_configured_flag_file parsers_configured_flag_file = status_params.parsers_configured_flag_file parsers_acl_configured_flag_file = status_params.parsers_acl_configured_flag_file -rest_acl_configured_flag_file = status_params.rest_acl_configured_flag_file enrichment_kafka_configured_flag_file = status_params.enrichment_kafka_configured_flag_file enrichment_kafka_acl_configured_flag_file = status_params.enrichment_kafka_acl_configured_flag_file enrichment_hbase_configured_flag_file = status_params.enrichment_hbase_configured_flag_file @@ -84,6 +83,10 @@ indexing_hbase_configured_flag_file = status_params.indexing_hbase_configured_fl indexing_hbase_acl_configured_flag_file = status_params.indexing_hbase_acl_configured_flag_file indexing_hdfs_perm_configured_flag_file = status_params.indexing_hdfs_perm_configured_flag_file elasticsearch_template_installed_flag_file = status_params.elasticsearch_template_installed_flag_file +rest_kafka_configured_flag_file = status_params.rest_kafka_configured_flag_file +rest_kafka_acl_configured_flag_file = status_params.rest_kafka_acl_configured_flag_file +rest_hbase_configured_flag_file = status_params.rest_hbase_configured_flag_file +rest_hbase_acl_configured_flag_file = status_params.rest_hbase_acl_configured_flag_file global_properties_template = config['configurations']['metron-env']['elasticsearch-properties'] # Elasticsearch hosts and port management @@ -249,6 +252,8 @@ metron_rest_pid = 'metron-rest.pid' metron_indexing_classpath = config['configurations']['metron-rest-env']['metron_indexing_classpath'] metron_rest_classpath = config['configurations']['metron-rest-env']['metron_rest_classpath'] metron_sysconfig = config['configurations']['metron-rest-env']['metron_sysconfig'] +user_settings_hbase_table = status_params.user_settings_hbase_table +user_settings_hbase_cf = status_params.user_settings_hbase_cf # Enrichment geoip_url = config['configurations']['metron-enrichment-env']['geoip_url'] http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py ---------------------------------------------------------------------- diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py index 62cfc7a..ed2edfb 100644 --- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py +++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py @@ -37,7 +37,6 @@ zk_configured_flag_file = metron_zookeeper_config_path + '/../metron_zookeeper_c parsers = config['configurations']['metron-parsers-env']['parsers'] parsers_configured_flag_file = metron_zookeeper_config_path + '/../metron_parsers_configured' parsers_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_parsers_acl_configured' -rest_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_acl_configured' # Enrichment metron_enrichment_topology = 'enrichment' @@ -81,6 +80,12 @@ elasticsearch_template_installed_flag_file = metron_zookeeper_config_path + '/.. # REST metron_rest_port = config['configurations']['metron-rest-env']['metron_rest_port'] +rest_kafka_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_kafka_configured' +rest_kafka_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_kafka_acl_configured' +rest_hbase_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_hbase_configured' +rest_hbase_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_hbase_acl_configured' +user_settings_hbase_table = config['configurations']['metron-rest-env']['user_settings_hbase_table'] +user_settings_hbase_cf = config['configurations']['metron-rest-env']['user_settings_hbase_cf'] # Alerts UI metron_alerts_ui_host = default("/clusterHostInfo/metron_alerts_ui_hosts", [hostname])[0] http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py ---------------------------------------------------------------------- diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py index 4f717bb..e97af05 100755 --- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py +++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py @@ -33,13 +33,19 @@ from metron_security import kinit # Wrap major operations and functionality in this class class RestCommands: __params = None - __acl_configured = False + __kafka_configured = False + __kafka_acl_configured = False + __hbase_configured = False + __hbase_acl_configured = False def __init__(self, params): if params is None: raise ValueError("params argument is required for initialization") self.__params = params - self.__acl_configured = os.path.isfile(self.__params.rest_acl_configured_flag_file) + self.__kafka_configured = os.path.isfile(self.__params.rest_kafka_configured_flag_file) + self.__kafka_acl_configured = os.path.isfile(self.__params.rest_kafka_acl_configured_flag_file) + self.__hbase_configured = os.path.isfile(self.__params.rest_hbase_configured_flag_file) + self.__hbase_acl_configured = os.path.isfile(self.__params.rest_hbase_acl_configured_flag_file) Directory(params.metron_rest_pid_dir, mode=0755, owner=params.metron_user, @@ -53,15 +59,33 @@ class RestCommands: create_parents=True ) - def is_acl_configured(self): - return self.__acl_configured - - def set_acl_configured(self): - metron_service.set_configured(self.__params.metron_user, self.__params.rest_acl_configured_flag_file, "Setting REST ACL configured to true") - def __get_topics(self): return [self.__params.metron_escalation_topic] + def is_kafka_configured(self): + return self.__kafka_configured + + def is_kafka_acl_configured(self): + return self.__kafka_acl_configured + + def is_hbase_configured(self): + return self.__hbase_configured + + def is_hbase_acl_configured(self): + return self.__hbase_acl_configured + + def set_kafka_configured(self): + metron_service.set_configured(self.__params.metron_user, self.__params.rest_kafka_configured_flag_file, "Setting Kafka configured to True for rest") + + def set_kafka_acl_configured(self): + metron_service.set_configured(self.__params.metron_user, self.__params.rest_kafka_acl_configured_flag_file, "Setting Kafka ACL configured to True for rest") + + def set_hbase_configured(self): + metron_service.set_configured(self.__params.metron_user, self.__params.rest_hbase_configured_flag_file, "Setting HBase configured to True for rest") + + def set_hbase_acl_configured(self): + metron_service.set_configured(self.__params.metron_user, self.__params.rest_hbase_acl_configured_flag_file, "Setting HBase ACL configured to True for rest") + def init_kafka_topics(self): Logger.info('Creating Kafka topics for rest') metron_service.init_kafka_topics(self.__params, self.__get_topics()) @@ -179,6 +203,35 @@ class RestCommands: self.__params.metron_rest_port, self.__params.metron_user) + def create_hbase_tables(self): + Logger.info("Creating HBase Tables") + metron_service.create_hbase_table(self.__params, + self.__params.user_settings_hbase_table, + self.__params.user_settings_hbase_cf) + Logger.info("Done creating HBase Tables") + self.set_hbase_configured() + + def set_hbase_acls(self): + Logger.info("Setting HBase ACLs") + if self.__params.security_enabled: + kinit(self.__params.kinit_path_local, + self.__params.hbase_keytab_path, + self.__params.hbase_principal_name, + execute_user=self.__params.hbase_user) + + cmd = "echo \"grant '{0}', 'RW', '{1}'\" | hbase shell -n" + add_rest_acl_cmd = cmd.format(self.__params.metron_user, self.__params.user_settings_hbase_table) + Execute(add_rest_acl_cmd, + tries=3, + try_sleep=5, + logoutput=False, + path='/usr/sbin:/sbin:/usr/local/bin:/bin:/usr/bin', + user=self.__params.hbase_user + ) + + Logger.info("Done setting HBase ACLs") + self.set_hbase_acl_configured() + def service_check(self, env): """ Performs a service check for the REST application http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py ---------------------------------------------------------------------- diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py index 2f419df..36a68c6 100755 --- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py +++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py @@ -26,9 +26,9 @@ from resource_management.libraries.functions.format import format from resource_management.libraries.functions.get_user_call_output import get_user_call_output from resource_management.libraries.script import Script +import metron_service from rest_commands import RestCommands - class RestMaster(Script): def install(self, env): @@ -43,11 +43,17 @@ class RestMaster(Script): content=Template("metron.j2") ) + metron_service.refresh_configs(params) + commands = RestCommands(params) - commands.init_kafka_topics() - if params.security_enabled and not commands.is_acl_configured(): + + if not commands.is_kafka_configured(): + commands.init_kafka_topics() + if not commands.is_hbase_configured(): + commands.create_hbase_tables() + if params.security_enabled and not commands.is_kafka_acl_configured(): commands.init_kafka_acls() - commands.set_acl_configured() + commands.set_kafka_acl_configured() def start(self, env, upgrade_type=None): from params import params http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts index 11b8ae3..b21e316 100644 --- a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts +++ b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts @@ -43,7 +43,7 @@ describe('metron-alerts facets', function() { }); it('should display facets data', () => { - let facetValues = [ 'enrichm...:country 3', 'host 9', 'ip_dst_addr 8', 'ip_src_addr 2', 'source:type 1' ]; + let facetValues = [ 'enrichm...:country 3', 'ip_dst_addr 8', 'ip_src_addr 2', 'source:type 1' ]; page.navgateToAlertList(); expect(page.getFacetsTitle()).toEqualBcoz(['Filters'], 'for Title as Filters'); @@ -55,19 +55,16 @@ describe('metron-alerts facets', function() { expect(page.getFacetState(1)).toEqualBcoz('collapse', 'for second facet'); expect(page.getFacetState(2)).toEqualBcoz('collapse', 'for third facet'); expect(page.getFacetState(3)).toEqualBcoz('collapse', 'for fourth facet'); - expect(page.getFacetState(4)).toEqualBcoz('collapse', 'for fifth facet'); page.toggleFacetState(0); page.toggleFacetState(1); page.toggleFacetState(2); page.toggleFacetState(3); - page.toggleFacetState(4); expect(page.getFacetState(0)).toEqualBcoz('collapse show', 'for first facet'); expect(page.getFacetState(1)).toEqualBcoz('collapse show', 'for second facet'); expect(page.getFacetState(2)).toEqualBcoz('collapse show', 'for third facet'); expect(page.getFacetState(3)).toEqualBcoz('collapse show', 'for fourth facet'); - expect(page.getFacetState(4)).toEqualBcoz('collapse show', 'for fifth facet'); }); it('should have all facet values', () => { @@ -84,8 +81,7 @@ describe('metron-alerts facets', function() { }; expect(page.getFacetValues(0)).toEqualBcoz({ US: '22', RU: '44', FR: '25' }, 'for enrichment facet'); - expect(page.getFacetValues(1)).toEqual(hostMap, 'for host facet'); - expect(page.getFacetValues(4)).toEqual({ alerts_ui_e2e: '169' }, 'for source:type facet'); + expect(page.getFacetValues(3)).toEqual({ alerts_ui_e2e: '169' }, 'for source:type facet'); }); it('should collapse all facets', () => { @@ -93,19 +89,16 @@ describe('metron-alerts facets', function() { expect(page.getFacetState(1)).toEqualBcoz('collapse show', 'for second facet'); expect(page.getFacetState(2)).toEqualBcoz('collapse show', 'for third facet'); expect(page.getFacetState(3)).toEqualBcoz('collapse show', 'for fourth facet'); - expect(page.getFacetState(4)).toEqualBcoz('collapse show', 'for fifth facet'); page.toggleFacetState(0); page.toggleFacetState(1); page.toggleFacetState(2); page.toggleFacetState(3); - page.toggleFacetState(4); expect(page.getFacetState(0)).toEqualBcoz('collapse', 'for first facet'); expect(page.getFacetState(1)).toEqualBcoz('collapse', 'for second facet'); expect(page.getFacetState(2)).toEqualBcoz('collapse', 'for third facet'); expect(page.getFacetState(3)).toEqualBcoz('collapse', 'for fourth facet'); - expect(page.getFacetState(4)).toEqualBcoz('collapse', 'for fifth facet'); }); }); http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts index 38bacee..00d677e 100644 --- a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts +++ b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts @@ -152,7 +152,6 @@ describe('meta-alerts workflow', function() { let groupByItems = { 'source:type': '1', 'ip_dst_addr': '7', - 'host': '9', 'enrichm...:country': '3', 'ip_src_addr': '2' }; @@ -215,8 +214,8 @@ describe('meta-alerts workflow', function() { expect(tablePage.getPaginationText()).toEqualBcoz('1 - 25 of 150', 'pagination text to be present'); // Meta Alert should appear in Filters - alertFacetsPage.toggleFacetState(4); - expect(alertFacetsPage.getFacetValues(4)).toEqual({'metaalert': '1' }, 'for source:type facet'); + alertFacetsPage.toggleFacetState(3); + expect(alertFacetsPage.getFacetValues(3)).toEqual({'metaalert': '1' }, 'for source:type facet'); // Meta Alert should not appear in Groups expect(treePage.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present'); http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts index 87636cd..339b19f 100644 --- a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts +++ b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts @@ -49,14 +49,13 @@ describe('metron-alerts tree view', function () { let groupByItems = { 'source:type': '1', 'ip_dst_addr': '8', - 'host': '9', 'enrichm...:country': '3', 'ip_src_addr': '2' }; - expect(page.getGroupByCount()).toEqualBcoz(Object.keys(groupByItems).length, '5 Group By Elements should be present'); + expect(page.getGroupByCount()).toEqualBcoz(Object.keys(groupByItems).length, '4 Group By Elements should be present'); expect(page.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present'); expect(page.getGroupByItemCounts()).toEqualBcoz(Object.keys(groupByItems).map(key => groupByItems[key]), - '5 Group By Elements values should be present'); + '4 Group By Elements values should be present'); }); it('drag and drop should change group order', () => { http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts index 2a78ecd..12d98e7 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts @@ -24,9 +24,11 @@ export class AlertFiltersComponent implements OnChanges { } prepareData() { + let facetFields = Object.keys(this.facets); + this.data = this.data.filter(collapsableData => facetFields.includes(collapsableData.groupName)); this.data.map(collapsableData => collapsableData.groupItems = []); - for (let key of Object.keys(this.facets)) { + for (let key of facetFields) { let facet = this.facets[key]; let facetItems: CollapseComponentDataItems[] = []; http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/src/app/model/search-request.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/model/search-request.ts b/metron-interface/metron-alerts/src/app/model/search-request.ts index 44e23db..ad174cf 100644 --- a/metron-interface/metron-alerts/src/app/model/search-request.ts +++ b/metron-interface/metron-alerts/src/app/model/search-request.ts @@ -25,5 +25,5 @@ export class SearchRequest { query: string; size: number; sort: SortField[]; - facetFields: string[] = Array.from(new Set(DEFAULT_FACETS.concat(DEFAULT_GROUPS))); + facetFields: string[] = []; } http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts b/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts index 1c6e633..2e034d5 100644 --- a/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts +++ b/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts @@ -45,7 +45,9 @@ export class GroupByComponent implements OnInit, OnChanges { } prepareData() { - for (let key of Object.keys(this.facets)) { + let facetFields = Object.keys(this.facets); + this.data = this.data.filter(groupByData => facetFields.includes(groupByData.name)); + for (let key of facetFields) { let facet = this.facets[key]; let count = Object.keys(facet).length; let groupByItem = this.data.filter(groupByData => groupByData.name === key)[0]; http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java deleted file mode 100644 index c126ce7..0000000 --- a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.metron.rest.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.Id; -import org.apache.metron.rest.converter.JsonConverter; - -@Entity -public class AlertProfile { - - @Id - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - private String id; - - @Convert(converter = JsonConverter.class) - private List<String> tableColumns; - - @Convert(converter = JsonConverter.class) - private List<SavedSearch> savedSearches; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public List<String> getTableColumns() { - return tableColumns; - } - - public void setTableColumns(List<String> tableColumns) { - this.tableColumns = tableColumns; - } - - public List<SavedSearch> getSavedSearches() { - return savedSearches; - } - - public void setSavedSearches(List<SavedSearch> savedSearches) { - this.savedSearches = savedSearches; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - AlertProfile that = (AlertProfile) o; - - return id != null ? id.equals(that.id) : that.id == null && - (tableColumns != null ? tableColumns.equals(that.tableColumns) : that.tableColumns == null && - (savedSearches != null ? savedSearches.equals(that.savedSearches) : that.savedSearches == null)); - } - - @Override - public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (tableColumns != null ? tableColumns.hashCode() : 0); - result = 31 * result + (savedSearches != null ? savedSearches.hashCode() : 0); - return result; - } -} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java new file mode 100644 index 0000000..7c92cf4 --- /dev/null +++ b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.metron.rest.model; + +import java.util.List; + +public class AlertsUIUserSettings { + + private String user; + + private List<String> tableColumns; + + private List<SavedSearch> savedSearches; + + private List<String> facetFields; + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public List<String> getTableColumns() { + return tableColumns; + } + + public void setTableColumns(List<String> tableColumns) { + this.tableColumns = tableColumns; + } + + public List<SavedSearch> getSavedSearches() { + return savedSearches; + } + + public void setSavedSearches(List<SavedSearch> savedSearches) { + this.savedSearches = savedSearches; + } + + public List<String> getFacetFields() { + return facetFields; + } + + public void setFacetFields(List<String> facetFields) { + this.facetFields = facetFields; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + AlertsUIUserSettings that = (AlertsUIUserSettings) o; + + return (user != null ? user.equals(that.user) : that.user == null) && + (tableColumns != null ? tableColumns.equals(that.tableColumns) : that.tableColumns == null) && + (savedSearches != null ? savedSearches.equals(that.savedSearches) : that.savedSearches == null) && + (facetFields != null ? facetFields.equals(that.facetFields) : that.facetFields == null); + } + + @Override + public int hashCode() { + int result = user != null ? user.hashCode() : 0; + result = 31 * result + (tableColumns != null ? tableColumns.hashCode() : 0); + result = 31 * result + (savedSearches != null ? savedSearches.hashCode() : 0); + result = 31 * result + (facetFields != null ? facetFields.hashCode() : 0); + return result; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/README.md ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/README.md b/metron-interface/metron-rest/README.md index d51dc52..25e112e 100644 --- a/metron-interface/metron-rest/README.md +++ b/metron-interface/metron-rest/README.md @@ -213,11 +213,11 @@ Request and Response objects are JSON formatted. The JSON schemas are available | | | ---------- | -| [ `POST /api/v1/alert/escalate`](#get-apiv1alertescalate)| -| [ `GET /api/v1/alert/profile`](#get-apiv1alertprofile)| -| [ `GET /api/v1/alert/profile/all`](#get-apiv1alertprofileall)| -| [ `DELETE /api/v1/alert/profile`](#delete-apiv1alertprofile)| -| [ `POST /api/v1/alert/profile`](#post-apiv1alertprofile)| +| [ `POST /api/v1/alerts/ui/escalate`](#get-apiv1alertsuiescalate)| +| [ `GET /api/v1/alerts/ui/settings`](#get-apiv1alertsuisettings)| +| [ `GET /api/v1/alerts/ui/settings/all`](#get-apiv1alertsuisettingsall)| +| [ `DELETE /api/v1/alerts/ui/settings`](#delete-apiv1alertsuisettings)| +| [ `POST /api/v1/alerts/ui/settings`](#post-apiv1alertsuisettings)| | [ `GET /api/v1/global/config`](#get-apiv1globalconfig)| | [ `DELETE /api/v1/global/config`](#delete-apiv1globalconfig)| | [ `POST /api/v1/global/config`](#post-apiv1globalconfig)| @@ -288,42 +288,41 @@ Request and Response objects are JSON formatted. The JSON schemas are available | [ `PUT /api/v1/update/replace`](#patch-apiv1updatereplace)| | [ `GET /api/v1/user`](#get-apiv1user)| -### `POST /api/v1/alert/escalate` +### `POST /api/v1/alerts/ui/escalate` * Description: Escalates a list of alerts by producing it to the Kafka escalate topic * Input: * alerts - The alerts to be escalated * Returns: * 200 - Alerts were escalated - -### `GET /api/v1/alert/profile` - * Description: Retrieves the current user's alerts profile + +### `GET /api/v1/alerts/ui/settings` + * Description: Retrieves the current user's settings * Returns: - * 200 - Alerts profile - * 404 - The current user does not have an alerts profile + * 200 - User settings + * 404 - he current user does not have settings -### `GET /api/v1/alert/profile/all` - * Description: Retrieves all users' alerts profiles. Only users that are part of the "ROLE_ADMIN" role are allowed to get all alerts profiles. +### `GET /api/v1/alerts/ui/settings/all` + * Description: Retrieves all users' settings. Only users that are part of the "ROLE_ADMIN" role are allowed to get all user settings. * Returns: - * 200 - List of all alerts profiles - * 403 - The current user does not have permission to get all alerts profiles + * 200 - List of all user settings + * 403 - The current user does not have permission to get all user settings -### `DELETE /api/v1/alert/profile` - * Description: Deletes a user's alerts profile. Only users that are part of the "ROLE_ADMIN" role are allowed to delete user alerts profiles. +### `DELETE /api/v1/alerts/ui/settings` + * Description: Deletes a user's settings. Only users that are part of the "ROLE_ADMIN" role are allowed to delete user settings. * Input: - * user - The user whose prolife will be deleted + * user - The user whose settings will be deleted * Returns: - * 200 - Alerts profile was deleted - * 403 - The current user does not have permission to delete alerts profiles - * 404 - Alerts profile could not be found + * 200 - User settings were deleted + * 403 - The current user does not have permission to delete user settings + * 404 - User settings could not be found -### `POST /api/v1/alert/profile` - * Description: Creates or updates the current user's alerts profile +### `POST /api/v1/alerts/ui/settings` + * Description: Creates or updates the current user's settings * Input: - * alertsProfile - The alerts profile to be saved + * alertsUIUserSettings - The user settings to be saved * Returns: - * 200 - Alerts profile updated. Returns saved alerts profile. - * 201 - Alerts profile created. Returns saved alerts profile. - + * 200 - User settings updated. Returns saved settings. + * 201 - User settings created. Returns saved settings. ### `GET /api/v1/global/config` * Description: Retrieves the current Global Config from Zookeeper http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java index f18d4cf..4567197 100644 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java @@ -59,6 +59,7 @@ public class MetronRestConstants { public static final String SEARCH_MAX_RESULTS = "search.max.results"; public static final String SEARCH_MAX_GROUPS = "search.max.groups"; + public static final String SEARCH_FACET_FIELDS_SPRING_PROPERTY = "search.facet.fields"; public static final String INDEX_DAO_IMPL = "index.dao.impl"; public static final String INDEX_HBASE_TABLE_PROVIDER_IMPL = "index.hbase.provider"; public static final String INDEX_WRITER_NAME = "index.writer.name"; @@ -68,4 +69,7 @@ public class MetronRestConstants { public static final String SECURITY_ROLE_USER = "USER"; public static final String SECURITY_ROLE_ADMIN = "ADMIN"; + + public static final String USER_SETTINGS_HBASE_TABLE_SPRING_PROPERTY = "user.settings.table"; + public static final String USER_SETTINGS_HBASE_CF_SPRING_PROPERTY = "user.settings.cf"; } http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java new file mode 100644 index 0000000..c96b9e8 --- /dev/null +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.metron.rest.config; + +import org.apache.metron.hbase.HTableProvider; +import org.apache.metron.hbase.client.UserSettingsClient; +import org.apache.metron.rest.RestException; +import org.apache.metron.rest.service.GlobalConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE; + +@Configuration +@Profile("!" + TEST_PROFILE) +public class HBaseConfig { + + @Autowired + private GlobalConfigService globalConfigService; + + @Autowired + public HBaseConfig(GlobalConfigService globalConfigService) { + this.globalConfigService = globalConfigService; + } + + @Bean() + public UserSettingsClient userSettingsClient() { + UserSettingsClient userSettingsClient = new UserSettingsClient(); + userSettingsClient.init(() -> { + try { + return globalConfigService.get(); + } catch (RestException e) { + throw new IllegalStateException("Unable to retrieve the global config.", e); + } + }, new HTableProvider()); + return userSettingsClient; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java deleted file mode 100644 index d8d5411..0000000 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.metron.rest.controller; - -import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import java.util.List; -import java.util.Map; -import org.apache.metron.rest.RestException; -import org.apache.metron.rest.model.AlertProfile; -import org.apache.metron.rest.service.AlertService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -/** - * The API resource that is used for alert-related operations. - */ -@RestController -@RequestMapping("/api/v1/alert") -public class AlertController { - - /** - * Service used to interact with alerts. - */ - @Autowired - private AlertService alertService; - - @ApiOperation(value = "Escalates a list of alerts by producing it to the Kafka escalate topic") - @ApiResponse(message = "Alerts were escalated", code = 200) - @RequestMapping(value = "/escalate", method = RequestMethod.POST) - ResponseEntity<Void> escalate(final @ApiParam(name = "alerts", value = "The alerts to be escalated", required = true) @RequestBody List<Map<String, Object>> alerts) throws RestException { - alertService.escalateAlerts(alerts); - return new ResponseEntity<>(HttpStatus.OK); - } - - @ApiOperation(value = "Retrieves the current user's alerts profile") - @ApiResponses(value = {@ApiResponse(message = "Alerts profile", code = 200), - @ApiResponse(message = "The current user does not have an alerts profile", code = 404)}) - @RequestMapping(value = "/profile", method = RequestMethod.GET) - ResponseEntity<AlertProfile> get() throws RestException { - AlertProfile alertsProfile = alertService.getProfile(); - if (alertsProfile != null) { - return new ResponseEntity<>(alertsProfile, HttpStatus.OK); - } else { - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - } - } - - @Secured({"ROLE_" + SECURITY_ROLE_ADMIN}) - @ApiOperation(value = "Retrieves all users' alerts profiles. Only users that are part of " - + "the \"ROLE_ADMIN\" role are allowed to get all alerts profiles.") - @ApiResponses(value = {@ApiResponse(message = "List of all alerts profiles", code = 200), - @ApiResponse(message = - "The current user does not have permission to get all alerts profiles", code = 403)}) - @RequestMapping(value = "/profile/all", method = RequestMethod.GET) - ResponseEntity<Iterable<AlertProfile>> findAll() throws RestException { - return new ResponseEntity<>(alertService.findAllProfiles(), HttpStatus.OK); - } - - @ApiOperation(value = "Creates or updates the current user's alerts profile") - @ApiResponses(value = { - @ApiResponse(message = "Alerts profile updated. Returns saved alerts profile.", code = 200), - @ApiResponse(message = "Alerts profile created. Returns saved alerts profile.", code = 201)}) - @RequestMapping(value = "/profile", method = RequestMethod.POST) - ResponseEntity<AlertProfile> save(@ApiParam(name = "alertsProfile", value = - "The alerts profile to be saved", required = true) @RequestBody AlertProfile alertsProfile) - throws RestException { - if (alertService.getProfile() == null) { - return new ResponseEntity<>(alertService.saveProfile(alertsProfile), HttpStatus.CREATED); - } else { - return new ResponseEntity<>(alertService.saveProfile(alertsProfile), HttpStatus.OK); - } - } - - @Secured({"ROLE_" + SECURITY_ROLE_ADMIN}) - @ApiOperation(value = "Deletes a user's alerts profile. Only users that are part of " - + "the \"ROLE_ADMIN\" role are allowed to delete user alerts profiles.") - @ApiResponses(value = {@ApiResponse(message = "Alerts profile was deleted", code = 200), - @ApiResponse(message = "The current user does not have permission to delete alerts profiles", - code = 403), - @ApiResponse(message = "Alerts profile could not be found", code = 404)}) - @RequestMapping(value = "/profile/{user}", method = RequestMethod.DELETE) - ResponseEntity<Void> delete( - @ApiParam(name = "user", value = "The user whose prolife will be deleted", required = true) - @PathVariable String user) - throws RestException { - if (alertService.deleteProfile(user)) { - return new ResponseEntity<>(HttpStatus.OK); - } else { - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - } - } -} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java new file mode 100644 index 0000000..fe2968f --- /dev/null +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java @@ -0,0 +1,124 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.metron.rest.controller; + +import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN; + +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import io.swagger.annotations.ApiResponses; +import org.apache.metron.rest.RestException; +import org.apache.metron.rest.model.AlertsUIUserSettings; +import org.apache.metron.rest.service.AlertsUIService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * The API resource that is used for alert-related operations. + */ +@RestController +@RequestMapping("/api/v1/alerts/ui") +public class AlertsUIController { + + /** + * Service used to interact with alerts. + */ + @Autowired + private AlertsUIService alertsUIService; + + @ApiOperation(value = "Escalates a list of alerts by producing it to the Kafka escalate topic") + @ApiResponse(message = "Alerts were escalated", code = 200) + @RequestMapping(value = "/escalate", method = RequestMethod.POST) + ResponseEntity<Void> escalate(final @ApiParam(name = "alerts", value = "The alerts to be escalated", required = true) @RequestBody List<Map<String, Object>> alerts) throws RestException { + alertsUIService.escalateAlerts(alerts); + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation(value = "Retrieves the current user's settings") + @ApiResponses(value = {@ApiResponse(message = "User settings", code = 200), + @ApiResponse(message = "The current user does not have settings", code = 404)}) + @RequestMapping(value = "/settings", method = RequestMethod.GET) + ResponseEntity<AlertsUIUserSettings> get() throws RestException { + Optional<AlertsUIUserSettings> alertUserSettings = alertsUIService.getAlertsUIUserSettings(); + if (alertUserSettings.isPresent()) { + return new ResponseEntity<>(alertUserSettings.get(), HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @Secured({"ROLE_" + SECURITY_ROLE_ADMIN}) + @ApiOperation(value = "Retrieves all users' settings. Only users that are part of " + + "the \"ROLE_ADMIN\" role are allowed to get all user settings.") + @ApiResponses(value = {@ApiResponse(message = "List of all user settings", code = 200), + @ApiResponse(message = + "The current user does not have permission to get all user settings", code = 403)}) + @RequestMapping(value = "/settings/all", method = RequestMethod.GET) + ResponseEntity<Map<String, AlertsUIUserSettings>> findAll() throws RestException { + return new ResponseEntity<>(alertsUIService.findAllAlertsUIUserSettings(), HttpStatus.OK); + } + + @ApiOperation(value = "Creates or updates the current user's settings") + @ApiResponses(value = { + @ApiResponse(message = "User settings updated. Returns saved settings.", code = 200), + @ApiResponse(message = "User settings created. Returns saved settings.", code = 201)}) + @RequestMapping(value = "/settings", method = RequestMethod.POST) + ResponseEntity<Void> save(@ApiParam(name = "alertsUIUserSettings", value = + "The user settings to be saved", required = true) @RequestBody AlertsUIUserSettings alertsUIUserSettings) + throws RestException { + ResponseEntity<Void> responseEntity; + if (alertsUIService.getAlertsUIUserSettings().isPresent()) { + responseEntity = new ResponseEntity<>(HttpStatus.OK); + } else { + responseEntity = new ResponseEntity<>(HttpStatus.CREATED); + } + alertsUIService.saveAlertsUIUserSettings(alertsUIUserSettings); + return responseEntity; + } + + @Secured({"ROLE_" + SECURITY_ROLE_ADMIN}) + @ApiOperation(value = "Deletes a user's settings. Only users that are part of " + + "the \"ROLE_ADMIN\" role are allowed to delete user settings.") + @ApiResponses(value = {@ApiResponse(message = "User settings were deleted", code = 200), + @ApiResponse(message = "The current user does not have permission to delete user settings", + code = 403), + @ApiResponse(message = "User settings could not be found", code = 404)}) + @RequestMapping(value = "/settings/{user}", method = RequestMethod.DELETE) + ResponseEntity<Void> delete( + @ApiParam(name = "user", value = "The user whose settings will be deleted", required = true) + @PathVariable String user) + throws RestException { + if (alertsUIService.deleteAlertsUIUserSettings(user)) { + return new ResponseEntity<>(HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java index 6bca938..b5f7765 100644 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java @@ -26,11 +26,12 @@ import org.springframework.web.bind.annotation.RestController; import java.security.Principal; @RestController +@RequestMapping("/api/v1/user") public class UserController { @ApiOperation(value = "Retrieves the current user") @ApiResponse(message = "Current user", code = 200) - @RequestMapping(value = "/api/v1/user", method = RequestMethod.GET) + @RequestMapping(method = RequestMethod.GET) public String user(Principal user) { return user.getName(); } http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java deleted file mode 100644 index 1466d90..0000000 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.metron.rest.repository; - -import org.apache.metron.rest.model.AlertProfile; -import org.springframework.data.repository.CrudRepository; - -public interface AlertProfileRepository extends CrudRepository<AlertProfile, String> { -} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java deleted file mode 100644 index a5f244b..0000000 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.metron.rest.service; - -import java.util.List; -import java.util.Map; -import org.apache.metron.rest.RestException; -import org.apache.metron.rest.model.AlertProfile; - -/** - * This is a set of operations created to interact with alerts. - */ -public interface AlertService { - - void escalateAlerts(List<Map<String, Object>> alerts) throws RestException; - - AlertProfile getProfile(); - - Iterable<AlertProfile> findAllProfiles(); - - AlertProfile saveProfile(AlertProfile alertsProfile); - - boolean deleteProfile(String user); -} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java deleted file mode 100644 index 84672b6..0000000 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.metron.rest.service; - -import org.apache.metron.rest.model.AlertProfile; - -public interface AlertsProfileService { - - AlertProfile get(); - - Iterable<AlertProfile> findAll(); - - AlertProfile save(AlertProfile alertsProfile); - - boolean delete(String user); -} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java new file mode 100644 index 0000000..cd9ff9d --- /dev/null +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.metron.rest.service; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.metron.rest.RestException; +import org.apache.metron.rest.model.AlertsUIUserSettings; + +/** + * This is a set of operations created to interact with alerts. + */ +public interface AlertsUIService { + + void escalateAlerts(List<Map<String, Object>> alerts) throws RestException; + + Optional<AlertsUIUserSettings> getAlertsUIUserSettings() throws RestException; + + Map<String, AlertsUIUserSettings> findAllAlertsUIUserSettings() throws RestException; + + void saveAlertsUIUserSettings(AlertsUIUserSettings userSettings) throws RestException; + + boolean deleteAlertsUIUserSettings(String user); +} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java new file mode 100644 index 0000000..5873c80 --- /dev/null +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.metron.rest.service; + +import org.apache.metron.rest.RestException; + +import java.util.Map; + +public interface UserService { + + String getUserSettings(String type) throws RestException; + + Map<String, String> findAllUserSettings(String type) throws RestException; + + void saveUserSettings(String settings, String type) throws RestException; + + boolean deleteUserSettings(String user, String type); +} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java deleted file mode 100644 index 73babbe..0000000 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.metron.rest.service.impl; - -import com.fasterxml.jackson.core.JsonProcessingException; -import java.util.List; -import java.util.Map; -import org.apache.metron.common.utils.JSONUtils; -import org.apache.metron.rest.MetronRestConstants; -import org.apache.metron.rest.RestException; -import org.apache.metron.rest.model.AlertProfile; -import org.apache.metron.rest.repository.AlertProfileRepository; -import org.apache.metron.rest.security.SecurityUtils; -import org.apache.metron.rest.service.AlertService; -import org.apache.metron.rest.service.KafkaService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.stereotype.Service; - -/** - * The default service layer implementation of {@link AlertService}. - * - * @see AlertService - */ -@Service -public class AlertServiceImpl implements AlertService { - - private Environment environment; - private final KafkaService kafkaService; - private AlertProfileRepository alertProfileRepository; - - @Autowired - public AlertServiceImpl(final KafkaService kafkaService, - final Environment environment, - final AlertProfileRepository alertsProfileRepository) { - this.kafkaService = kafkaService; - this.environment = environment; - this.alertProfileRepository = alertsProfileRepository; - } - - @Override - public void escalateAlerts(List<Map<String, Object>> alerts) throws RestException { - try { - for (Map<String, Object> alert : alerts) { - kafkaService.produceMessage( - environment.getProperty(MetronRestConstants.KAFKA_TOPICS_ESCALATION_PROPERTY), - JSONUtils.INSTANCE.toJSON(alert, false)); - } - } catch (JsonProcessingException e) { - throw new RestException(e); - } - } - - @Override - public AlertProfile getProfile() { - return alertProfileRepository.findOne(SecurityUtils.getCurrentUser()); - } - - @Override - public Iterable<AlertProfile> findAllProfiles() { - return alertProfileRepository.findAll(); - } - - @Override - public AlertProfile saveProfile(AlertProfile alertsProfile) { - String user = SecurityUtils.getCurrentUser(); - alertsProfile.setId(user); - return alertProfileRepository.save(alertsProfile); - } - - @Override - public boolean deleteProfile(String user) { - boolean success = true; - try { - alertProfileRepository.delete(user); - } catch (EmptyResultDataAccessException e) { - success = false; - } - return success; - } -} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java deleted file mode 100644 index 239dbdc..0000000 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.metron.rest.service.impl; - -import org.apache.metron.rest.model.AlertProfile; -import org.apache.metron.rest.repository.AlertProfileRepository; -import org.apache.metron.rest.security.SecurityUtils; -import org.apache.metron.rest.service.AlertsProfileService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.stereotype.Service; - -@Service -public class AlertsProfileServiceImpl implements AlertsProfileService { - - private AlertProfileRepository alertsProfileRepository; - - @Autowired - public AlertsProfileServiceImpl(AlertProfileRepository alertsProfileRepository) { - this.alertsProfileRepository = alertsProfileRepository; - } - - @Override - public AlertProfile get() { - return alertsProfileRepository.findOne(SecurityUtils.getCurrentUser()); - } - - @Override - public Iterable<AlertProfile> findAll() { - return alertsProfileRepository.findAll(); - } - - @Override - public AlertProfile save(AlertProfile alertsProfile) { - String user = SecurityUtils.getCurrentUser(); - alertsProfile.setId(user); - return alertsProfileRepository.save(alertsProfile); - } - - @Override - public boolean delete(String user) { - boolean success = true; - try { - alertsProfileRepository.delete(user); - } catch (EmptyResultDataAccessException e) { - success = false; - } - return success; - } -} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java new file mode 100644 index 0000000..7d0a8f8 --- /dev/null +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java @@ -0,0 +1,131 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.metron.rest.service.impl; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.metron.common.utils.JSONUtils; +import org.apache.metron.rest.MetronRestConstants; +import org.apache.metron.rest.RestException; +import org.apache.metron.rest.model.AlertsUIUserSettings; +import org.apache.metron.hbase.client.UserSettingsClient; +import org.apache.metron.rest.security.SecurityUtils; +import org.apache.metron.rest.service.AlertsUIService; +import org.apache.metron.rest.service.KafkaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; + +/** + * The default service layer implementation of {@link AlertsUIService}. + * + * @see AlertsUIService + */ +@Service +public class AlertsUIServiceImpl implements AlertsUIService { + + public static final String ALERT_USER_SETTING_TYPE = "metron-alerts-ui"; + public static ThreadLocal<ObjectMapper> _mapper = ThreadLocal.withInitial(() -> + new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL)); + + private Environment environment; + private final KafkaService kafkaService; + private UserSettingsClient userSettingsClient; + + @Autowired + public AlertsUIServiceImpl(final KafkaService kafkaService, + final Environment environment, + final UserSettingsClient userSettingsClient) { + this.kafkaService = kafkaService; + this.environment = environment; + this.userSettingsClient = userSettingsClient; + } + + @Override + public void escalateAlerts(List<Map<String, Object>> alerts) throws RestException { + try { + for (Map<String, Object> alert : alerts) { + kafkaService.produceMessage( + environment.getProperty(MetronRestConstants.KAFKA_TOPICS_ESCALATION_PROPERTY), + JSONUtils.INSTANCE.toJSON(alert, false)); + } + } catch (JsonProcessingException e) { + throw new RestException(e); + } + } + + @Override + public Optional<AlertsUIUserSettings> getAlertsUIUserSettings() throws RestException { + try { + Optional<String> alertUserSettings = userSettingsClient.findOne(SecurityUtils.getCurrentUser(), ALERT_USER_SETTING_TYPE); + if (alertUserSettings.isPresent()) { + return Optional.of(_mapper.get().readValue(alertUserSettings.get(), AlertsUIUserSettings.class)); + } else { + return Optional.empty(); + } + } catch (IOException e) { + throw new RestException(e); + } + } + + @Override + public Map<String, AlertsUIUserSettings> findAllAlertsUIUserSettings() throws RestException { + Map<String, AlertsUIUserSettings> allAlertUserSettings = new HashMap<>(); + try { + Map<String, Optional<String>> alertUserSettingsStrings = userSettingsClient.findAll(ALERT_USER_SETTING_TYPE); + for (Map.Entry<String, Optional<String>> entry: alertUserSettingsStrings.entrySet()) { + Optional<String> alertUserSettings = entry.getValue(); + if (alertUserSettings.isPresent()) { + allAlertUserSettings.put(entry.getKey(), _mapper.get().readValue(alertUserSettings.get(), AlertsUIUserSettings.class)); + } + } + } catch (IOException e) { + throw new RestException(e); + } + return allAlertUserSettings; + } + + @Override + public void saveAlertsUIUserSettings(AlertsUIUserSettings alertsUIUserSettings) throws RestException{ + String user = SecurityUtils.getCurrentUser(); + try { + userSettingsClient.save(user, ALERT_USER_SETTING_TYPE, _mapper.get().writeValueAsString(alertsUIUserSettings)); + } catch (IOException e) { + throw new RestException(e); + } + } + + @Override + public boolean deleteAlertsUIUserSettings(String user) { + boolean success = true; + try { + userSettingsClient.delete(user, ALERT_USER_SETTING_TYPE); + } catch (IOException e) { + success = false; + } + return success; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java index 7cee3cc..e5bab08 100644 --- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java +++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java @@ -20,9 +20,11 @@ package org.apache.metron.rest.service.impl; import static org.apache.metron.common.Constants.ERROR_TYPE; import static org.apache.metron.indexing.dao.MetaAlertDao.METAALERT_TYPE; import static org.apache.metron.rest.MetronRestConstants.INDEX_WRITER_NAME; +import static org.apache.metron.rest.MetronRestConstants.SEARCH_FACET_FIELDS_SPRING_PROPERTY; import com.google.common.collect.Lists; import java.lang.invoke.MethodHandles; +import java.util.Arrays; import org.apache.metron.indexing.dao.IndexDao; import org.apache.metron.indexing.dao.search.GetRequest; import org.apache.metron.indexing.dao.search.GroupRequest; @@ -32,6 +34,8 @@ import org.apache.metron.indexing.dao.search.SearchRequest; import org.apache.metron.indexing.dao.search.SearchResponse; import org.apache.metron.indexing.dao.search.FieldType; import org.apache.metron.rest.RestException; +import org.apache.metron.rest.model.AlertsUIUserSettings; +import org.apache.metron.rest.service.AlertsUIService; import org.apache.metron.rest.service.SearchService; import org.apache.metron.rest.service.SensorIndexingConfigService; import org.slf4j.Logger; @@ -53,12 +57,15 @@ public class SearchServiceImpl implements SearchService { private IndexDao dao; private Environment environment; private SensorIndexingConfigService sensorIndexingConfigService; + private AlertsUIService alertsUIService; @Autowired - public SearchServiceImpl(IndexDao dao, Environment environment, SensorIndexingConfigService sensorIndexingConfigService) { + public SearchServiceImpl(IndexDao dao, Environment environment, + SensorIndexingConfigService sensorIndexingConfigService, AlertsUIService alertsUIService) { this.dao = dao; this.environment = environment; this.sensorIndexingConfigService = sensorIndexingConfigService; + this.alertsUIService = alertsUIService; } @Override @@ -70,6 +77,9 @@ public class SearchServiceImpl implements SearchService { indices.add(METAALERT_TYPE); searchRequest.setIndices(indices); } + if (searchRequest.getFacetFields() != null && searchRequest.getFacetFields().isEmpty()) { + searchRequest.setFacetFields(getDefaultFacetFields()); + } return dao.search(searchRequest); } catch(InvalidSearchException ise) { @@ -122,4 +132,14 @@ public class SearchServiceImpl implements SearchService { indices.remove(ERROR_TYPE); return indices; } + + private List<String> getDefaultFacetFields() throws RestException { + Optional<AlertsUIUserSettings> alertUserSettings = alertsUIService.getAlertsUIUserSettings(); + if (!alertUserSettings.isPresent() || alertUserSettings.get().getFacetFields() == null) { + String facetFieldsProperty = environment.getProperty(SEARCH_FACET_FIELDS_SPRING_PROPERTY, String.class, ""); + return Arrays.asList(facetFieldsProperty.split(",")); + } else { + return alertUserSettings.get().getFacetFields(); + } + } } http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/resources/application-test.yml ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/resources/application-test.yml b/metron-interface/metron-rest/src/main/resources/application-test.yml index 3cca5e0..891f554 100644 --- a/metron-interface/metron-rest/src/main/resources/application-test.yml +++ b/metron-interface/metron-rest/src/main/resources/application-test.yml @@ -44,6 +44,8 @@ storm: search: max: results: 100 + facet: + fields: ip_src_addr index: dao: http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/resources/application.yml ---------------------------------------------------------------------- diff --git a/metron-interface/metron-rest/src/main/resources/application.yml b/metron-interface/metron-rest/src/main/resources/application.yml index 03f4d72..3e75881 100644 --- a/metron-interface/metron-rest/src/main/resources/application.yml +++ b/metron-interface/metron-rest/src/main/resources/application.yml @@ -50,6 +50,8 @@ search: max: results: 1000 groups: 1000 + facet: + fields: source:type,ip_src_addr,ip_dst_addr,enrichments:geo:ip_dst_addr:country index: dao: @@ -64,4 +66,9 @@ meta: # By default, we use the ElasticsearchMetaAlertDao impl: org.apache.metron.elasticsearch.dao.ElasticsearchMetaAlertDao -spring.jpa.generate-ddl: true \ No newline at end of file +spring.jpa.generate-ddl: true + +user: + settings: + table: user_settings + cf: cf \ No newline at end of file
