http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-deployment/roles/ambari_config/vars/single_node_vm.yml ---------------------------------------------------------------------- diff --git a/metron-deployment/roles/ambari_config/vars/single_node_vm.yml b/metron-deployment/roles/ambari_config/vars/single_node_vm.yml index 482fafd..4c3cbce 100644 --- a/metron-deployment/roles/ambari_config/vars/single_node_vm.yml +++ b/metron-deployment/roles/ambari_config/vars/single_node_vm.yml @@ -31,6 +31,7 @@ hbase_slave: [HBASE_REGIONSERVER] es_master: [ES_MASTER] kibana_master: [KIBANA_MASTER] metron_indexing: [METRON_INDEXING] +metron_profiler: [METRON_PROFILER] metron_enrichment_master : [METRON_ENRICHMENT_MASTER] metron_parsers : [METRON_PARSERS] metron_rest: [METRON_REST] @@ -38,8 +39,8 @@ metron_management_ui: [METRON_MANAGEMENT_UI] metron_components: > {{ hadoop_master | union(zookeeper_master) | union(storm_master) | union(hbase_master) | union(hadoop_slave) | union(zookeeper_slave) | - union(storm_slave) | union(kafka_broker) | union(hbase_slave) | union(kibana_master) | union(metron_indexing) | - union(metron_enrichment_master) | union(metron_parsers) | union(metron_rest) | union(metron_management_ui) | union(es_master) }} + union(storm_slave) | union(kafka_broker) | union(hbase_slave) | union(kibana_master) | union(metron_indexing) | union(metron_profiler) | + union(metron_enrichment_master) | union(metron_parsers) | union(metron_rest) | union(metron_management_ui) | union(es_master) }} cluster_name: "metron_cluster" blueprint_name: "metron_blueprint" @@ -82,7 +83,7 @@ configurations: yarn.nodemanager.log-dirs: '{{ nodemanager_log_dirs }}' yarn.nodemanager.resource.memory-mb : '{{ nodemanager_mem_mb }}' - storm-site: - supervisor.slots.ports: "[6700, 6701, 6702, 6703]" + supervisor.slots.ports: "[6700, 6701, 6702, 6703, 6704]" storm.local.dir: '{{ storm_local_dir }}' topology.classpath: '{{ topology_classpath }}' - kafka-env:
http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-deployment/roles/ambari_config/vars/small_cluster.yml ---------------------------------------------------------------------- diff --git a/metron-deployment/roles/ambari_config/vars/small_cluster.yml b/metron-deployment/roles/ambari_config/vars/small_cluster.yml index af22cb6..45b15f3 100644 --- a/metron-deployment/roles/ambari_config/vars/small_cluster.yml +++ b/metron-deployment/roles/ambari_config/vars/small_cluster.yml @@ -31,6 +31,7 @@ es_master: [ES_MASTER] es_slave: [ES_SLAVE] kibana_master: [KIBANA_MASTER] metron_indexing: [METRON_INDEXING] +metron_profiler: [METRON_PROFILER] metron_enrichment_master : [METRON_ENRICHMENT_MASTER] metron_parsers : [METRON_PARSERS] metron_rest: [METRON_REST] @@ -43,7 +44,7 @@ master_2_components: "{{ zookeeper_master | union(storm_master) | union(spark_ma master_2_host: - "{{groups.ambari_slave[1]}}" metron_components: > - {{ metron_indexing | union(metron_enrichment_master) | union(metron_parsers) | union(metron_rest) | union(metron_management_ui) | union(hadoop_slave) | union(storm_slave) | + {{ metron_indexing | union(metron_profiler) | union(metron_enrichment_master) | union(metron_parsers) | union(metron_rest) | union(metron_management_ui) | union(hadoop_slave) | union(storm_slave) | union(kafka_broker) | union(hbase_slave) | union(hadoop_clients) }} metron_host: - "{{ groups.metron[0] }}" @@ -80,7 +81,7 @@ configurations: yarn.nodemanager.log-dirs: '{{ nodemanager_log_dirs| default("/hadoop/yarn/log") }}' yarn.nodemanager.resource.memory-mb : '{{ nodemanager_mem_mb }}' - storm-site: - supervisor.slots.ports: "[6700, 6701, 6702, 6703]" + supervisor.slots.ports: "[6700, 6701, 6702, 6703, 6704]" storm.local.dir: '{{ storm_local_dir | default("/hadoop/storm") }}' topology.classpath: '{{ topology_classpath }}' - kafka-broker: http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/README.md ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/README.md b/metron-interface/metron-alerts/README.md index adba151..db7f038 100644 --- a/metron-interface/metron-alerts/README.md +++ b/metron-interface/metron-alerts/README.md @@ -17,15 +17,17 @@ ## Development Setup -Install all the dependent node_modules using the following command -``` -cd metron/metron-interface/metron-alerts -npm install -``` -UI can be run by using the following command -``` -./scripts/start-dev.sh -``` +1. Install all the dependent node_modules using the following command + ``` + cd metron/metron-interface/metron-alerts + npm install + ``` +1. UI can be run by using the following command + ``` + ./scripts/start-dev.sh + ``` +1. You can view the GUI @http://localhost:4200 . The default credentials for login are admin/password + **NOTE**: *In the development mode ui by default connects to ES at http://node1:9200 for fetching data. If you wish to change it you can change the ES url at metron/metron-interface/metron-alerts/proxy.conf.json* ## E2E Tests @@ -44,6 +46,8 @@ An expressjs server is available for mocking the elastic search api. npm run e2e ``` +1. E2E tests uses data from full-dev wherever applicable. The tests assume rest-api's are available @http://node1:8082 + **NOTE**: *e2e tests covers all the general workflows and we will extend them as we need* ## Mpack Integration http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/alerts-server-e2e.js ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/alerts-server-e2e.js b/metron-interface/metron-alerts/alerts-server-e2e.js index e30ef44..2a5f80b 100644 --- a/metron-interface/metron-alerts/alerts-server-e2e.js +++ b/metron-interface/metron-alerts/alerts-server-e2e.js @@ -29,9 +29,10 @@ var serveStatic = require('serve-static'); var favicon = require('serve-favicon'); var proxy = require('http-proxy-middleware'); var argv = require('optimist') - .demand(['p']) + .demand(['p', 'r']) .usage('Usage: server.js -p [port]') .describe('p', 'Port to run metron alerts ui') + .describe('r', 'Url where metron rest application is available') .argv; var port = argv.p; @@ -73,13 +74,19 @@ var searchResult = function(req, res){ return; } - var filter = req.body.query.query_string.query; + var responseMap = { + total: 0, + results: obj.hits.hits + }; + + var filter = req.body.query; + if (filter !== '*') { filter = filter.replace(/\\/g, ''); var lastIndex = filter.lastIndexOf(':'); var key = filter.substr(0, lastIndex); var value = filter.substr(lastIndex+1); - obj.hits.hits = obj.hits.hits.filter(function (hits) { + responseMap.results = obj.hits.hits.filter(function (hits) { return hits._source[key] === value; }); } @@ -88,7 +95,7 @@ var searchResult = function(req, res){ if (sortField) { var key = Object.keys(sortField)[0]; var order = sortField[key].order; - obj.hits.hits = obj.hits.hits.sort(function(o1, o2) { + responseMap.results = obj.hits.hits.sort(function(o1, o2) { if (!o1._source[key] || !o2._source[key]) { return -1; } @@ -102,9 +109,15 @@ var searchResult = function(req, res){ }); } - obj.hits.total = obj.hits.hits.length; - obj.hits.hits = obj.hits.hits.splice(req.body.from, req.body.size); - res.json(obj); + responseMap.total = responseMap.results.length; + responseMap.results = responseMap.results.splice(req.body.from, req.body.size); + + responseMap.results.map(function (obj) { + obj.id = obj._id; + obj.source = obj._source; + }); + + res.json(responseMap); }); }; @@ -128,7 +141,9 @@ app.use(serveStatic(path.join(__dirname, 'dist'), { setHeaders: setCustomCacheControl })); -app.post('^/search/*', searchResult); +app.use('/api/v1/user', proxy(conf.elastic)); +app.use('/logout', proxy(conf.elastic)); +app.post('/api/v1/search/search', searchResult); app.use('/_cluster', clusterState); app.get('/alerts-list', indexHTML); app.get('', indexHTML); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts index 454ee6e..b27df7e 100644 --- a/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts +++ b/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts @@ -18,14 +18,25 @@ */ import { MetronAlertsPage } from './alerts-list.po'; import { customMatchers } from '../matchers/custom-matchers'; +import { LoginPage } from '../login/login.po'; describe('metron-alerts App', function() { let page: MetronAlertsPage; - let columnNames = [ 'Score', '_id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichm...:country', + let loginPage: LoginPage; + let columnNames = [ 'Score', 'id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichm...:country', 'ip_dst_addr', 'host', 'alert_status', '', '' ]; - let colNamesColumnConfig = [ 'score', '_id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country', + let colNamesColumnConfig = [ 'score', 'id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country', 'ip_dst_addr', 'host', 'alert_status' ]; + beforeAll(() => { + loginPage = new LoginPage(); + loginPage.login(); + }); + + afterAll(() => { + loginPage.logout(); + }); + beforeEach(() => { page = new MetronAlertsPage(); jasmine.addMatchers(customMatchers); @@ -126,7 +137,7 @@ describe('metron-alerts App', function() { page.clickConfigureTable(); expect(page.getSelectedColumnNames()).toEqual(colNamesColumnConfig, 'for default selected column names'); - page.toggleSelectCol('_id'); + page.toggleSelectCol('id'); page.toggleSelectCol('guid', 'method'); expect(page.getSelectedColumnNames()).toEqual(newColNamesColumnConfig, 'for guid added to selected column names'); page.saveConfigureColumns(); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts index 55d2a6e..fb3e3cd 100644 --- a/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts +++ b/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts @@ -18,12 +18,23 @@ */ import { MetronAlertsPage } from '../alerts-list.po'; import {customMatchers} from '../../matchers/custom-matchers'; +import {LoginPage} from '../../login/login.po'; describe('metron-alerts configure table', function() { let page: MetronAlertsPage; - let colNamesColumnConfig = [ 'score', '_id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country', + let loginPage: LoginPage; + let colNamesColumnConfig = [ 'score', 'id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country', 'ip_dst_addr', 'host', 'alert_status' ]; + beforeAll(() => { + loginPage = new LoginPage(); + loginPage.login(); + }); + + afterAll(() => { + loginPage.logout(); + }); + beforeEach(() => { page = new MetronAlertsPage(); jasmine.addMatchers(customMatchers); @@ -38,7 +49,7 @@ describe('metron-alerts configure table', function() { page.clickConfigureTable(); expect(page.getSelectedColumnNames()).toEqual(colNamesColumnConfig, 'for default selected column names'); - page.toggleSelectCol('_id'); + page.toggleSelectCol('id'); page.toggleSelectCol('guid', 'method'); expect(page.getSelectedColumnNames()).toEqual(newColNamesColumnConfig, 'for guid added to selected column names'); page.saveConfigureColumns(); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts index fc02e12..85127dc 100644 --- a/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts +++ b/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts @@ -18,9 +18,20 @@ */ import { customMatchers } from '../../matchers/custom-matchers'; import {MetronAlertsPage} from '../alerts-list.po'; +import {LoginPage} from '../../login/login.po'; describe('metron-alerts Search', function() { let page: MetronAlertsPage; + let loginPage: LoginPage; + + beforeAll(() => { + loginPage = new LoginPage(); + loginPage.login(); + }); + + afterAll(() => { + loginPage.logout(); + }); beforeEach(() => { page = new MetronAlertsPage(); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts b/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts new file mode 100644 index 0000000..dc53889 --- /dev/null +++ b/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts @@ -0,0 +1,44 @@ +/** + * 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. + */ +import { LoginPage } from './login.po'; + +describe('login to application', function() { + let page: LoginPage; + + beforeEach(() => { + page = new LoginPage(); + }); + + it('should display error message for invalid credentials', () => { + page.navigateToLogin(); + page.setUserNameAndPassword('admin', 'admin'); + page.submitLoginForm(); + expect(page.getErrorMessage()).toEqual('Login failed for admin'); + }); + + it('should login for valid credentials', () => { + page.navigateToLogin(); + page.setUserNameAndPassword('admin', 'password'); + page.submitLoginForm(); + }); + + it('should logout', () => { + page.logout(); + expect(page.getLocation()).toEqual('http://localhost:4200/login'); + }); +}); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/e2e/login/login.po.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/login/login.po.ts b/metron-interface/metron-alerts/e2e/login/login.po.ts new file mode 100644 index 0000000..b3e9769 --- /dev/null +++ b/metron-interface/metron-alerts/e2e/login/login.po.ts @@ -0,0 +1,65 @@ +/** + * 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. + */ +import { browser, element, by } from 'protractor'; +import {waitForElementVisibility} from '../utils/e2e_util'; + +export class LoginPage { + navigateToLogin() { + return browser.get('/'); + } + + login() { + browser.wait(function() {return element(by.css('input.form-control')).isPresent(); }); + this.setUserNameAndPassword('admin', 'password'); + this.submitLoginForm(); + browser.waitForAngularEnabled(false); + browser.wait(function() {return element(by.css('.logout')).isPresent(); }); + } + + logout() { + browser.waitForAngularEnabled(false); + element.all(by.css('.alert .close')).click(); + element.all(by.css('.logout-link')).click(); + browser.sleep(2000); + } + + setUserNameAndPassword(userName: string, password: string) { + element.all(by.css('input.form-control')).get(0).sendKeys(userName); + element.all(by.css('input.form-control')).get(1).sendKeys(password); + } + + submitLoginForm() { + return element.all(by.buttonText('LOG IN')).click(); + } + + getErrorMessage() { + browser.waitForAngularEnabled(false); + let errElement = element(by.css('div[style="color:#a94442"]')); + return waitForElementVisibility(errElement).then(() => { + return errElement.getText().then((message) => { + return message.replace(/\n/, '').replace(/LOG\ IN$/, ''); + }); + }); + } + + getLocation() { + return browser.getCurrentUrl().then(url => { + return url; + }); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/e2e/utils/e2e_util.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/e2e/utils/e2e_util.ts b/metron-interface/metron-alerts/e2e/utils/e2e_util.ts new file mode 100644 index 0000000..836818e --- /dev/null +++ b/metron-interface/metron-alerts/e2e/utils/e2e_util.ts @@ -0,0 +1,30 @@ +import { browser, protractor } from 'protractor'; + +export function changeURL(url: string) { + return browser.get(url).then(() => { + return browser.getCurrentUrl().then((newURL) => { + return newURL; + }); + }); +} + +export function waitForElementInVisibility (_element ) { + let EC = protractor.ExpectedConditions; + return browser.wait(EC.invisibilityOf(_element)); +} + +export function waitForElementPresence (_element ) { + let EC = protractor.ExpectedConditions; + return browser.wait(EC.presenceOf(_element)); +} + +export function waitForElementVisibility (_element ) { + let EC = protractor.ExpectedConditions; + return browser.wait(EC.visibilityOf(_element)); +} + +export function waitForStalenessOf (_element ) { + let EC = protractor.ExpectedConditions; + return browser.wait(EC.stalenessOf(_element)); +} + http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/protractor.conf.js ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/protractor.conf.js b/metron-interface/metron-alerts/protractor.conf.js index 082f1bf..189195c 100644 --- a/metron-interface/metron-alerts/protractor.conf.js +++ b/metron-interface/metron-alerts/protractor.conf.js @@ -25,10 +25,19 @@ var SpecReporter = require('jasmine-spec-reporter').SpecReporter; exports.config = { allScriptsTimeout: 25000, specs: [ - './e2e/**/*.e2e-spec.ts' + './e2e/login/login.e2e-spec.ts', + '/e2e/alerts-list/alerts-list.e2e-spec.ts', + './e2e/alerts-list/configure-table/configure-table.e2e-spec.ts', + './e2e/alerts-list/save-search/save-search.e2e-spec.ts' ], capabilities: { - 'browserName': 'chrome' + 'browserName': 'chrome', + 'chromeOptions': { + 'prefs': { + 'credentials_enable_service': false, + 'profile': { 'password_manager_enabled': false} + } + } }, directConnect: true, baseUrl: 'http://localhost:4200/', http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/proxy.conf.json ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/proxy.conf.json b/metron-interface/metron-alerts/proxy.conf.json index 38f3e90..27d1ee9 100644 --- a/metron-interface/metron-alerts/proxy.conf.json +++ b/metron-interface/metron-alerts/proxy.conf.json @@ -1,10 +1,10 @@ { "/api/v1": { - "target": "http://localhost:8080", + "target": "http://node1:8082", "secure": false }, "/logout": { - "target": "http://localhost:8080", + "target": "http://node1:8082", "secure": false }, "/search": { http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/scripts/alerts-server.js ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/alerts-server.js b/metron-interface/metron-alerts/scripts/alerts-server.js index 84504cc..6fb35c9 100644 --- a/metron-interface/metron-alerts/scripts/alerts-server.js +++ b/metron-interface/metron-alerts/scripts/alerts-server.js @@ -27,9 +27,10 @@ var serveStatic = require('serve-static'); var favicon = require('serve-favicon'); var proxy = require('http-proxy-middleware'); var argv = require('optimist') - .demand(['p', 'r']) + .demand(['p', 'r', 'e']) .alias('r', 'resturl') - .usage('Usage: server.js -p [port] -r [restUrl]') + .alias('e', 'elasticurl') + .usage('Usage: server.js -p [port] -r [restUrl] -e [elasticURL]') .describe('p', 'Port to run metron management ui') .describe('r', 'Url where metron rest application is available') .argv; @@ -38,8 +39,13 @@ var port = argv.p; var metronUIAddress = ''; var ifaces = os.networkInterfaces(); var restUrl = argv.r || argv.resturl; +var elasticUrl = argv.e || argv.elasticurl; var conf = { "elastic": { + "target": elasticUrl, + "secure": false + }, + "rest": { "target": restUrl, "secure": false } @@ -71,7 +77,7 @@ var rewriteSearchProxy = proxy({ app.use(compression()); -app.use('/search', rewriteSearchProxy); +app.use('/api', proxy(conf.rest)); app.use('/_cluster', proxy(conf.elastic)); app.use(favicon(path.join(__dirname, '../alerts-ui/favicon.ico'))); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh b/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh index 0c97f88..7516fd0 100755 --- a/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh +++ b/metron-interface/metron-alerts/scripts/start-server-for-e2e.sh @@ -17,4 +17,5 @@ # SCRIPTS_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $SCRIPTS_ROOT/.. && npm run build -node $SCRIPTS_ROOT/../alerts-server-e2e.js -p 4200 +node $SCRIPTS_ROOT/../alerts-server-e2e.js -p 4200 -r http://node1:8082 + http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/_variables.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/_variables.scss b/metron-interface/metron-alerts/src/_variables.scss index 8bb37b2..1a5fa86 100644 --- a/metron-interface/metron-alerts/src/_variables.scss +++ b/metron-interface/metron-alerts/src/_variables.scss @@ -87,6 +87,9 @@ $placeholder-color: $dove-grey; $nav-content-nav-width: 200px; +$login-label: #606060; +$black: #000000; + @mixin place-holder-text { font-family: Roboto; http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html index afc93eb..703b676 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html @@ -15,7 +15,7 @@ <div class="container-fluid"> <div class="row mb-3"> <div class="col-md-10"> - <div class="form-title" appAlertSeverity [severity]="alert['threat:triage:score']"> {{ alert['threat:triage:score'] }} {{ alert._id }}</div> + <div class="form-title" appAlertSeverity [severity]="alertSource['threat:triage:score']"> {{ alertSource['threat:triage:score'] }} {{ alertSource.guid }}</div> </div> <div class="col-md-2"><i class="fa fa-times pull-right close-button" aria-hidden="true" (click)="goBack()"></i></div> </div> @@ -40,7 +40,7 @@ </div> <div class="ml-1 my-4 form"> <div *ngFor="let field of alertFields" class="row"> - <div class="col-6 mb-1 key">{{ field }}</div> <div class="col-6"> {{ alert._source[field] }} </div> + <div class="col-6 mb-1 key">{{ field }}</div> <div class="col-6"> {{ alertSource[field] }} </div> </div> </div> </div> http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts index 218ceff..915c0c1 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts @@ -20,6 +20,7 @@ import {Router, ActivatedRoute} from '@angular/router'; import {AlertService} from '../../service/alert.service'; import {Alert} from '../../model/alert'; import {WorkflowService} from '../../service/workflow.service'; +import {AlertSource} from '../../model/alert-source'; export enum AlertState { NEW, OPEN, ESCALATE, DISMISS, RESOLVE @@ -33,11 +34,10 @@ export enum AlertState { export class AlertDetailsComponent implements OnInit { alertId = ''; - alertIndex = ''; - alertType = ''; + alertSourceType = ''; alertState = AlertState; selectedAlertState: AlertState = AlertState.NEW; - alert: Alert = new Alert(); + alertSource: AlertSource = new AlertSource(); alertFields: string[] = []; constructor(private router: Router, @@ -51,54 +51,68 @@ export class AlertDetailsComponent implements OnInit { } getData() { - this.alertsService.getAlert(this.alertIndex, this.alertType, this.alertId).subscribe(alert => { - this.alert = alert; - this.alertFields = Object.keys(alert._source).filter(field => !field.includes(':ts') && field !== 'original_string').sort(); + this.alertsService.getAlert(this.alertSourceType, this.alertId).subscribe(alert => { + this.alertSource = alert; + this.alertFields = Object.keys(alert).filter(field => !field.includes(':ts') && field !== 'original_string').sort(); }); } ngOnInit() { this.activatedRoute.params.subscribe(params => { - this.alertId = params['id']; - this.alertIndex = params['index']; - this.alertType = params['type']; + this.alertId = params['guid']; + this.alertSourceType = params['sourceType']; this.getData(); }); } processOpen() { + let tAlert = new Alert(); + tAlert.source = this.alertSource; + this.selectedAlertState = AlertState.OPEN; - this.alertsService.updateAlertState([this.alert], 'OPEN', '').subscribe(results => { + this.alertsService.updateAlertState([tAlert], 'OPEN', '').subscribe(results => { this.getData(); }); } processNew() { + let tAlert = new Alert(); + tAlert.source = this.alertSource; + this.selectedAlertState = AlertState.NEW; - this.alertsService.updateAlertState([this.alert], 'NEW', '').subscribe(results => { + this.alertsService.updateAlertState([tAlert], 'NEW', '').subscribe(results => { this.getData(); }); } processEscalate() { + let tAlert = new Alert(); + tAlert.source = this.alertSource; + this.selectedAlertState = AlertState.ESCALATE; - this.workflowService.start([this.alert]).subscribe(workflowId => { - this.alertsService.updateAlertState([this.alert], 'ESCALATE', workflowId).subscribe(results => { + this.workflowService.start([tAlert]).subscribe(workflowId => { + this.alertsService.updateAlertState([tAlert], 'ESCALATE', workflowId).subscribe(results => { this.getData(); }); }); } processDismiss() { + let tAlert = new Alert(); + tAlert.source = this.alertSource; + this.selectedAlertState = AlertState.DISMISS; - this.alertsService.updateAlertState([this.alert], 'DISMISS', '').subscribe(results => { + this.alertsService.updateAlertState([tAlert], 'DISMISS', '').subscribe(results => { this.getData(); }); } processResolve() { + let tAlert = new Alert(); + tAlert.source = this.alertSource; + this.selectedAlertState = AlertState.RESOLVE; - this.alertsService.updateAlertState([this.alert], 'RESOLVE', '').subscribe(results => { + this.alertsService.updateAlertState([tAlert], 'RESOLVE', '').subscribe(results => { this.getData(); }); } http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts index 11cf61c..bc4dd5b 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts +++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alerts-details.routing.ts @@ -20,5 +20,5 @@ import { RouterModule } from '@angular/router'; import {AlertDetailsComponent} from './alert-details.component'; export const routing: ModuleWithProviders = RouterModule.forChild([ - { path: 'details/:index/:type/:id', component: AlertDetailsComponent, outlet: 'dialog'} + { path: 'details/:sourceType/:guid', component: AlertDetailsComponent, outlet: 'dialog'} ]); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html index 1fb01bf..3707e9a 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html @@ -77,14 +77,14 @@ </thead> <tbody> <tr *ngFor="let alert of alerts" (click)="showDetails($event, alert)" [ngClass]="{'selected' : selectedAlerts.indexOf(alert) != -1}"> - <td (click)="onAddFilter(threatScoreFieldName, alert._source[threatScoreFieldName])"> - <div appAlertSeverity [severity]="alert._source[threatScoreFieldName]"> <a> {{ alert._source[threatScoreFieldName] ? alert._source[threatScoreFieldName] : '-' }} </a> </div> + <td (click)="onAddFilter(threatScoreFieldName, alert.source[threatScoreFieldName])"> + <div appAlertSeverity [severity]="alert.source[threatScoreFieldName]"> <a> {{ alert.source[threatScoreFieldName] ? alert.source[threatScoreFieldName] : '-' }} </a> </div> </td> <td *ngFor="let column of alertsColumnsToDisplay" #cell> <a (click)="onAddFilter(column.name, getValue(alert, column, false))" title="{{getValue(alert, column, true)}}" style="color:#689AA9">{{ getValue(alert, column, true) | centerEllipses:20:cell }}</a> </td> <td></td> - <td><input id="{{ alert._id }}" class="fontawesome-checkbox" type="checkbox" name="{{alert._id}}" (click)="selectRow($event, alert)" [checked]="selectedAlerts.indexOf(alert) != -1"><label attr.for="{{ alert._id }}"></label></td> + <td><input id="{{ alert.id }}" class="fontawesome-checkbox" type="checkbox" name="{{alert.id}}" (click)="selectRow($event, alert)" [checked]="selectedAlerts.indexOf(alert) != -1"><label attr.for="{{ alert.id }}"></label></td> </tr> </tbody> </table> http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts index e014ede..35cbeff 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {Component, OnInit, ViewChild, ElementRef} from '@angular/core'; +import {Component, OnInit, ViewChild, ElementRef, OnDestroy} from '@angular/core'; import {Router, NavigationStart} from '@angular/router'; import {Observable, Subscription} from 'rxjs/Rx'; @@ -44,7 +44,7 @@ import {ElasticsearchUtils} from '../../utils/elasticsearch-utils'; styleUrls: ['./alerts-list.component.scss'] }) -export class AlertsListComponent implements OnInit { +export class AlertsListComponent implements OnInit, OnDestroy { alertsColumns: ColumnMetadata[] = []; alertsColumnsToDisplay: ColumnMetadata[] = []; @@ -148,31 +148,23 @@ export class AlertsListComponent implements OnInit { getColumnNamesForQuery() { let fieldNames = this.alertsColumns.map(columnMetadata => columnMetadata.name); - fieldNames = fieldNames.filter(name => !(name === '_id' || name === 'alert_status')); + fieldNames = fieldNames.filter(name => !(name === 'id' || name === 'alert_status')); fieldNames.push(this.threatScoreFieldName); return fieldNames; } - getDataType(name: string): string { - if (name === this.threatScoreFieldName || name === '_id') { - return 'number'; - } - - return this.alertsColumns.filter(colMetaData => colMetaData.name === name)[0].type; - } - - getValue(alert: any, column: ColumnMetadata, formatData: boolean) { + getValue(alert: Alert, column: ColumnMetadata, formatData: boolean) { let returnValue = ''; try { switch (column.name) { - case '_id': + case 'id': returnValue = alert[column.name]; break; case 'alert_status': returnValue = 'NEW'; break; default: - returnValue = alert['_source'][column.name]; + returnValue = alert.source[column.name]; break; } } catch (e) {} @@ -184,6 +176,10 @@ export class AlertsListComponent implements OnInit { return returnValue; } + ngOnDestroy() { + this.tryStopPolling(); + } + ngOnInit() { this.getAlertColumnNames(true); this.addAlertColChangedListner(); @@ -233,8 +229,8 @@ export class AlertsListComponent implements OnInit { onSort(sortEvent: SortEvent) { let sortOrder = (sortEvent.sortOrder === Sort.ASC ? 'asc' : 'desc'); - let sortBy = sortEvent.sortBy === '_id' ? '_uid' : sortEvent.sortBy; - this.queryBuilder.setSort(sortBy, sortOrder, this.getDataType(sortEvent.sortBy)); + let sortBy = sortEvent.sortBy === 'id' ? '_uid' : sortEvent.sortBy; + this.queryBuilder.setSort(sortBy, sortOrder); this.search(); } @@ -345,12 +341,12 @@ export class AlertsListComponent implements OnInit { this.router.navigateByUrl('/alerts-list(dialog:configure-table)'); } - showDetails($event, alert: any) { + showDetails($event, alert: Alert) { if ($event.target.type !== 'checkbox' && $event.target.parentElement.firstChild.type !== 'checkbox' && $event.target.nodeName !== 'A') { this.selectedAlerts = []; this.selectedAlerts = [alert]; this.saveRefreshState(); - this.router.navigateByUrl('/alerts-list(dialog:details/' + alert._index + '/' + alert._type + '/' + alert._id + ')'); + this.router.navigateByUrl('/alerts-list(dialog:details/' + alert.source['source:type'] + '/' + alert.source.guid + ')'); } } http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts index 1a39e51..adc8cbb 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.module.ts @@ -30,7 +30,7 @@ import {ConfigureRowsModule} from '../configure-rows/configure-rows.module'; @NgModule({ imports: [routing, SharedModule, ConfigureRowsModule, MetronSorterModule, MetronTablePaginationModule, ListGroupModule, CollapseModule], - exports: [], + exports: [AlertsListComponent], declarations: [AlertsListComponent], providers: [AlertService], }) http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts index b651d26..9816f46 100644 --- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts +++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/query-builder.ts @@ -18,6 +18,7 @@ import {Filter} from '../../model/filter'; import {ColumnNamesService} from '../../service/column-names.service'; import {SearchRequest} from '../../model/search-request'; +import {SortField} from '../../model/sort-field'; export class QueryBuilder { private _searchRequest = new SearchRequest(); @@ -102,7 +103,7 @@ export class QueryBuilder { } setFields(fieldNames: string[]) { - this.searchRequest._source = fieldNames; + // this.searchRequest._source = fieldNames; } setFromAndSize(from: number, size: number) { @@ -110,15 +111,12 @@ export class QueryBuilder { this.searchRequest.size = size; } - setSort(sortBy: string, order: string, dataType: string) { - let sortQuery = {}; - sortQuery[sortBy] = { - order: order, - ignore_unmapped: true, - unmapped_type: dataType, - missing: '_last' - }; - this.searchRequest.sort = [sortQuery]; + setSort(sortBy: string, order: string) { + let sortField = new SortField(); + sortField.field = sortBy; + sortField.sortOrder = order; + + this.searchRequest.sort = [sortField]; } private updateFilters(tQuery: string, updateNameTransform = false) { http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/app-routing.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/app-routing.module.ts b/metron-interface/metron-alerts/src/app/app-routing.module.ts index d214650..8357d66 100644 --- a/metron-interface/metron-alerts/src/app/app-routing.module.ts +++ b/metron-interface/metron-alerts/src/app/app-routing.module.ts @@ -17,12 +17,16 @@ */ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; +import {AuthGuard} from './shared/auth-guard'; +import {LoginGuard} from './shared/login-guard'; const routes: Routes = [ - { path: '', redirectTo: 'alerts-list', pathMatch: 'full'}, - { path: 'alerts-list', loadChildren: 'app/alerts/alerts-list/alerts-list.module#AlertsListModule'}, - { path: 'save-search', loadChildren: 'app/alerts/save-search/save-search.module#SaveSearchModule'}, - { path: 'saved-searches', loadChildren: 'app/alerts/saved-searches/saved-searches.module.ts#SavedSearchesModule'} + { path: '', redirectTo: 'login', pathMatch: 'full'}, + { path: 'login', loadChildren: 'app/login/login.module#LoginModule', canActivate: [LoginGuard]}, + { path: 'alerts-list', loadChildren: 'app/alerts/alerts-list/alerts-list.module#AlertsListModule', canActivate: [AuthGuard]}, + { path: 'save-search', loadChildren: 'app/alerts/save-search/save-search.module#SaveSearchModule', canActivate: [AuthGuard]}, + { path: 'saved-searches', loadChildren: 'app/alerts/saved-searches/saved-searches.module.ts#SavedSearchesModule', + canActivate: [AuthGuard]} ]; @NgModule({ http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/app.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/app.component.html b/metron-interface/metron-alerts/src/app/app.component.html index 103642a..8867a9b 100644 --- a/metron-interface/metron-alerts/src/app/app.component.html +++ b/metron-interface/metron-alerts/src/app/app.component.html @@ -12,10 +12,11 @@ the specific language governing permissions and limitations under the License. --> <div class="container-fluid px-0"> - <nav class="navbar"> - <a class="navbar-brand" href="#"> + <nav class="navbar" *ngIf="loggedIn"> + <a class="" href="#"> <img alt="" src="../assets/images/logo.png" width="135" height="45"> </a> + <div class="logout ml-auto">Logged in as {{authService.currentUser}} - <span class="logout-link" (click)="authService.logout()">Logout</span></div> </nav> <div class="container-fluid"> <router-outlet></router-outlet> http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/app.component.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/app.component.scss b/metron-interface/metron-alerts/src/app/app.component.scss index ce52c56..8358e7f 100644 --- a/metron-interface/metron-alerts/src/app/app.component.scss +++ b/metron-interface/metron-alerts/src/app/app.component.scss @@ -19,7 +19,19 @@ .navbar { + flex-direction: row; background: $nav-bar-bg; padding: 0rem 1rem; + height: 50px; + line-height: 50px; max-height: 50px; } + +.logout { + padding-left: 10px; +} + +.logout-link{ + color: $all-ports; + cursor: pointer; +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/app.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/app.component.ts b/metron-interface/metron-alerts/src/app/app.component.ts index 73cce38..e5e0bf2 100644 --- a/metron-interface/metron-alerts/src/app/app.component.ts +++ b/metron-interface/metron-alerts/src/app/app.component.ts @@ -16,6 +16,7 @@ * limitations under the License. */ import { Component } from '@angular/core'; +import {AuthenticationService} from './service/authentication.service'; @Component({ selector: 'metron-alerts-root', @@ -23,4 +24,11 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.scss'] }) export class AppComponent { + loggedIn = false; + + constructor(private authService: AuthenticationService) { + this.authService.onLoginEvent.subscribe(result => { + this.loggedIn = result; + }); + } } http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/app.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/app.module.ts b/metron-interface/metron-alerts/src/app/app.module.ts index 26ea5f2..295c748 100644 --- a/metron-interface/metron-alerts/src/app/app.module.ts +++ b/metron-interface/metron-alerts/src/app/app.module.ts @@ -35,9 +35,13 @@ import {MetronDialogBox} from './shared/metron-dialog-box'; import {ConfigureRowsModule} from './alerts/configure-rows/configure-rows.module'; import {SwitchModule} from './shared/switch/switch.module'; import {ColumnNamesService} from './service/column-names.service'; -import {ElasticSearchLocalstorageImpl} from './service/elasticsearch-localstorage-impl'; import {DataSource} from './service/data-source'; -import {environment} from '../environments/environment.prod'; +import {RestApiImpl} from './service/rest-api-impl'; +import {LoginModule} from './login/login.module'; +import {AuthGuard} from './shared/auth-guard'; +import {AuthenticationService} from './service/authentication.service'; +import {LoginGuard} from './shared/login-guard'; + export function initConfig(config: ColumnNamesService) { @@ -53,6 +57,7 @@ export function initConfig(config: ColumnNamesService) { FormsModule, HttpModule, MetronAlertsRoutingModule, + LoginModule, AlertsListModule, AlertDetailsModule, ConfigureTableModule, @@ -62,7 +67,10 @@ export function initConfig(config: ColumnNamesService) { SwitchModule ], providers: [{ provide: APP_INITIALIZER, useFactory: initConfig, deps: [ColumnNamesService], multi: true }, - { provide: DataSource, useClass: environment.dataSource === 'elastic' ? ElasticSearchLocalstorageImpl : null}, + { provide: DataSource, useClass: RestApiImpl }, + AuthenticationService, + AuthGuard, + LoginGuard, ConfigureTableService, SaveSearchService, MetronDialogBox, http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/login/login.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/login/login.component.html b/metron-interface/metron-alerts/src/app/login/login.component.html new file mode 100644 index 0000000..5ae746f --- /dev/null +++ b/metron-interface/metron-alerts/src/app/login/login.component.html @@ -0,0 +1,28 @@ +<!-- + 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. + --> +<div class="fill login-pane" style=""> + <form (ngSubmit)="login()" class="login-card"> + <img class="logo-img-card" src="assets/images/logo.png"/> + <label class="label"> USERNAME </label> + <input class="form-control" name="user" [(ngModel)]="user" required autofocus> + <label class="label"> PASSWORD </label> + <input type="password" name="password" class="form-control" [(ngModel)]="password" required> + <div class="my-4" style="color:#a94442"> + {{loginFailure}} + <button class="btn btn-primary pull-right" type="submit" (click)="login()">LOG IN</button> + </div> + </form> +</div> http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/login/login.component.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/login/login.component.scss b/metron-interface/metron-alerts/src/app/login/login.component.scss new file mode 100644 index 0000000..b8d5416 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/login/login.component.scss @@ -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. + */ +@import "../../_variables.scss"; + +.login-pane { + position: fixed; + background: url(../../assets/images/login.jpg); + width: 100%; + height: 100%; + top: 0; + left: 0; +} + +.label +{ + font-size: 0.8em; + color: $login-label; +} + +.login-card +{ + top: 25%; + height: 380px; + width: 480px; + opacity: 0.8; + margin: 0 auto; + border: none; + padding: 20px 25px 30px; + background-color: $black; + display: block; + position: relative; +} + +.logo-img-card +{ + margin: 0 auto 10px; + display: block; + width: 390px; + height: 120px; +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/login/login.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/login/login.component.spec.ts b/metron-interface/metron-alerts/src/app/login/login.component.spec.ts new file mode 100644 index 0000000..0cf3554 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/login/login.component.spec.ts @@ -0,0 +1,65 @@ +/** + * 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. + */ +import {async, inject, TestBed} from '@angular/core/testing'; +import {AuthenticationService} from '../service/authentication.service'; +import {LoginComponent} from './login.component'; + +class MockAuthenticationService { + + public login(username: string, password: string, onError): void { + if (username === 'success') { + onError({status: 200}); + } + + if (username === 'failure') { + onError({status: 401}); + } + } +} + +describe('LoginComponent', () => { + + beforeEach(async(() => { + TestBed.configureTestingModule({ + providers: [ + LoginComponent, + {provide: AuthenticationService, useClass: MockAuthenticationService} + ] + }) + .compileComponents(); + + })); + + it('can instantiate login component', inject([LoginComponent], (loginComponent: LoginComponent) => { + expect(loginComponent instanceof LoginComponent).toBe(true); + })); + + it('can instantiate login component', inject([LoginComponent], (loginComponent: LoginComponent) => { + loginComponent.user = 'success'; + loginComponent.password = 'success'; + loginComponent.login(); + expect(loginComponent.loginFailure).toEqual(''); + + loginComponent.user = 'failure'; + loginComponent.password = 'failure'; + loginComponent.login(); + expect(loginComponent.loginFailure).toEqual('Login failed for failure'); + + })); + +}); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/login/login.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/login/login.component.ts b/metron-interface/metron-alerts/src/app/login/login.component.ts new file mode 100644 index 0000000..877e05b --- /dev/null +++ b/metron-interface/metron-alerts/src/app/login/login.component.ts @@ -0,0 +1,43 @@ +/** + * 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. + */ +import { Component } from '@angular/core'; +import { AuthenticationService } from '../service/authentication.service'; + +@Component({ + selector: 'metron-alerts-login', + templateUrl: 'login.component.html', + styleUrls: ['login.component.scss'], +}) +export class LoginComponent { + + user: string; + password: string; + loginFailure = ''; + + constructor(private authenticationService: AuthenticationService) { + } + + login(): void { + this.authenticationService.login(this.user, this.password, error => { + if (error.status === 401) { + this.loginFailure = 'Login failed for ' + this.user; + } + }); + } + +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/login/login.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/login/login.module.ts b/metron-interface/metron-alerts/src/app/login/login.module.ts new file mode 100644 index 0000000..8e14df3 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/login/login.module.ts @@ -0,0 +1,28 @@ +/** + * 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. + */ +import { NgModule } from '@angular/core'; +import {routing} from './login.routing'; +import {LoginComponent} from './login.component'; +import {SharedModule} from '../shared/shared.module'; + +@NgModule ({ + imports: [ SharedModule, routing ], + declarations: [LoginComponent], + exports: [LoginComponent] +}) +export class LoginModule { } http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/login/login.routing.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/login/login.routing.ts b/metron-interface/metron-alerts/src/app/login/login.routing.ts new file mode 100644 index 0000000..c810fd9 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/login/login.routing.ts @@ -0,0 +1,25 @@ +/** + * 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. + */ +import { ModuleWithProviders } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import {LoginComponent} from './login.component'; + + +export const routing: ModuleWithProviders = RouterModule.forChild([ + { path: '', component: LoginComponent} +]); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/model/alert-source.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/model/alert-source.ts b/metron-interface/metron-alerts/src/app/model/alert-source.ts new file mode 100644 index 0000000..cbf83d3 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/model/alert-source.ts @@ -0,0 +1,52 @@ +/** + * 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. + */ +export class AlertSource { + msg: string; + sig_rev: number; + ip_dst_port: number; + ethsrc: string; + tcpseq: number; + dgmlen: number; + tcpwindow: number; + tcpack: number; + protocol: string; + 'source:type': string; + ip_dst_addr: number; + original_string: string; + tos: number; + id: number; + ip_src_addr: string; + timestamp: number; + ethdst: string; + is_alert: boolean; + ttl: number; + ethlen: number; + iplen: number; + ip_src_port: number; + tcpflags: string; + guid: string; + sig_id: number; + sig_generator: number; + 'threat:triage:score': number; + 'threatinteljoinbolt:joiner:ts': number; + 'enrichmentsplitterbolt:splitter:begin:ts': number; + 'enrichmentjoinbolt:joiner:ts': number; + 'threatintelsplitterbolt:splitter:end:ts': number; + 'enrichmentsplitterbolt:splitter:end:ts': number; + 'threatintelsplitterbolt:splitter:begin:ts': number; +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/model/alert.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/model/alert.ts b/metron-interface/metron-alerts/src/app/model/alert.ts index de8113d..59843a0 100644 --- a/metron-interface/metron-alerts/src/app/model/alert.ts +++ b/metron-interface/metron-alerts/src/app/model/alert.ts @@ -1,3 +1,4 @@ +import {AlertSource} from './alert-source'; /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -16,46 +17,8 @@ * limitations under the License. */ export class Alert { - _index: string; - _type: string; - _id: string; - _score: number; - _timestamp: number; - _source: { - msg: string; - sig_rev: number; - ip_dst_port: number; - ethsrc: string; - tcpseq: number; - dgmlen: number; - tcpwindow: number; - tcpack: number; - protocol: string; - 'source:type': string; - ip_dst_addr: number; - original_string: string; - tos: number; - id: number; - ip_src_addr: string; - timestamp: number; - ethdst: string; - is_alert: boolean; - ttl: number; - ethlen: number; - iplen: number; - ip_src_port: number; - tcpflags: string; - guid: string; - sig_id: number; - sig_generator: number; - 'threat:triage:score': number; - 'threatinteljoinbolt:joiner:ts': number; - 'enrichmentsplitterbolt:splitter:begin:ts': number; - 'enrichmentjoinbolt:joiner:ts': number; - 'threatintelsplitterbolt:splitter:end:ts': number; - 'enrichmentsplitterbolt:splitter:end:ts': number; - 'threatintelsplitterbolt:splitter:begin:ts': number; - }; - + id: string; + score: number; + source: AlertSource; status: string; } http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/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 3c7443e..2150f2b 100644 --- a/metron-interface/metron-alerts/src/app/model/search-request.ts +++ b/metron-interface/metron-alerts/src/app/model/search-request.ts @@ -1,3 +1,4 @@ +import {SortField} from './sort-field'; /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -16,9 +17,10 @@ * limitations under the License. */ export class SearchRequest { - _source: string[]; - query = '*'; - from = 0; - size = 15; - sort: {}[] = [{ timestamp: {order : 'desc', ignore_unmapped: true, unmapped_type: 'date'} }]; + // _source: string[]; //TODO: This needs to be removed + from: number; + indices: string[] = ['websphere', 'snort', 'asa', 'bro', 'yaf']; + query: string; + size: number; + sort: SortField[]; } http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/model/sort-field.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/model/sort-field.ts b/metron-interface/metron-alerts/src/app/model/sort-field.ts new file mode 100644 index 0000000..601b370 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/model/sort-field.ts @@ -0,0 +1,21 @@ +/** + * 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. + */ +export class SortField { + field: string; + sortOrder: string; +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/service/alert.service.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/service/alert.service.ts b/metron-interface/metron-alerts/src/app/service/alert.service.ts index 6412dde..7dabc4f 100644 --- a/metron-interface/metron-alerts/src/app/service/alert.service.ts +++ b/metron-interface/metron-alerts/src/app/service/alert.service.ts @@ -26,6 +26,7 @@ import {Http} from '@angular/http'; import {DataSource} from './data-source'; import {AlertsSearchResponse} from '../model/alerts-search-response'; import {SearchRequest} from '../model/search-request'; +import {AlertSource} from '../model/alert-source'; @Injectable() export class AlertService { @@ -43,20 +44,22 @@ export class AlertService { public pollSearch(searchRequest: SearchRequest): Observable<AlertsSearchResponse> { return this.ngZone.runOutsideAngular(() => { - return Observable.interval(this.interval * 1000).switchMap(() => { - return this.dataSource.getAlerts(searchRequest); + return this.ngZone.run(() => { + return Observable.interval(this.interval * 1000).switchMap(() => { + return this.dataSource.getAlerts(searchRequest); + }); }); }); } - public getAlert(index: string, type: string, alertId: string): Observable<Alert> { - return this.dataSource.getAlert(index, type, alertId); + public getAlert(sourceType: string, alertId: string): Observable<AlertSource> { + return this.dataSource.getAlert(sourceType, alertId); } public updateAlertState(alerts: Alert[], state: string, workflowId: string) { let request = ''; for (let alert of alerts) { - request += '{ "update" : { "_index" : "' + alert._index + '", "_type" : "' + alert._type + '", "_id" : "' + alert._id + '" } }\n' + + request += '{ "update" : { "sensorType" : "' + alert.source['source:type'] + '", "guid" : "' + alert.source.guid + '" } }\n' + '{ "doc": { "alert_status": "' + state + '"'; if (workflowId) { request += ', "workflow_id": "' + workflowId + '"'; http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/service/authentication.service.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/service/authentication.service.ts b/metron-interface/metron-alerts/src/app/service/authentication.service.ts new file mode 100644 index 0000000..f4924a5 --- /dev/null +++ b/metron-interface/metron-alerts/src/app/service/authentication.service.ts @@ -0,0 +1,91 @@ +/** + * 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. + */ +import {Injectable, EventEmitter} from '@angular/core'; +import {Http, Headers, RequestOptions, Response} from '@angular/http'; +import {Router} from '@angular/router'; +import {Observable} from 'rxjs/Observable'; + +@Injectable() +export class AuthenticationService { + + private static USER_NOT_VERIFIED = 'USER-NOT-VERIFIED'; + private currentUser: string = AuthenticationService.USER_NOT_VERIFIED; + loginUrl = '/api/v1/user'; + logoutUrl = '/logout'; + defaultHeaders = {'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest'}; + onLoginEvent: EventEmitter<boolean> = new EventEmitter<boolean>(); + + constructor(private http: Http, private router: Router) { + this.init(); + } + + public init() { + this.getCurrentUser(new RequestOptions({headers: new Headers(this.defaultHeaders)})).subscribe((response: Response) => { + this.currentUser = response.text(); + if (this.currentUser) { + this.onLoginEvent.emit(true); + } + }, error => { + this.onLoginEvent.emit(false); + }); + } + + public login(username: string, password: string, onError): void { + let loginHeaders: Headers = new Headers(this.defaultHeaders); + loginHeaders.append('authorization', 'Basic ' + btoa(username + ':' + password)); + let loginOptions: RequestOptions = new RequestOptions({headers: loginHeaders}); + this.getCurrentUser(loginOptions).subscribe((response: Response) => { + this.currentUser = response.text(); + this.router.navigateByUrl('/alerts-list'); + this.onLoginEvent.emit(true); + }, + error => { + onError(error); + }); + } + + public logout(): void { + this.http.post(this.logoutUrl, {}, new RequestOptions({headers: new Headers(this.defaultHeaders)})).subscribe(response => { + this.currentUser = AuthenticationService.USER_NOT_VERIFIED; + this.onLoginEvent.emit(false); + this.router.navigateByUrl('/login'); + }, + error => { + console.log('Logout failed:', error); + this.router.navigateByUrl('/login'); + }); + } + + public checkAuthentication() { + if (!this.isAuthenticated()) { + this.router.navigateByUrl('/login'); + } + } + + public getCurrentUser(options: RequestOptions): Observable<Response> { + return this.http.get(this.loginUrl, options); + } + + public isAuthenticationChecked(): boolean { + return this.currentUser !== AuthenticationService.USER_NOT_VERIFIED; + } + + public isAuthenticated(): boolean { + return this.currentUser !== AuthenticationService.USER_NOT_VERIFIED && this.currentUser != null; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/service/data-source.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/service/data-source.ts b/metron-interface/metron-alerts/src/app/service/data-source.ts index 242fa3a..28ee384 100644 --- a/metron-interface/metron-alerts/src/app/service/data-source.ts +++ b/metron-interface/metron-alerts/src/app/service/data-source.ts @@ -18,14 +18,13 @@ import {Observable} from 'rxjs/Rx'; import {Injectable} from '@angular/core'; import {Http} from '@angular/http'; - -import {Alert} from '../model/alert'; import {ColumnMetadata} from '../model/column-metadata'; import {ColumnNames} from '../model/column-names'; import {TableMetadata} from '../model/table-metadata'; import {SaveSearch} from '../model/save-search'; import {AlertsSearchResponse} from '../model/alerts-search-response'; import {SearchRequest} from '../model/search-request'; +import {AlertSource} from '../model/alert-source'; @Injectable() export abstract class DataSource { @@ -35,7 +34,7 @@ export abstract class DataSource { // Calls to fetch alerts abstract getAlerts(searchRequest: SearchRequest): Observable<AlertsSearchResponse> - abstract getAlert(index: string, type: string, alertId: string): Observable<Alert> + abstract getAlert(sourceType: string, alertId: string): Observable<AlertSource> abstract updateAlertState(request: any): Observable<{}> // Calls to fetch default alert table column names and all the field names across all indexes http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/service/elasticsearch-localstorage-impl.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/service/elasticsearch-localstorage-impl.ts b/metron-interface/metron-alerts/src/app/service/elasticsearch-localstorage-impl.ts index 0cd2bce..f4e43d5 100644 --- a/metron-interface/metron-alerts/src/app/service/elasticsearch-localstorage-impl.ts +++ b/metron-interface/metron-alerts/src/app/service/elasticsearch-localstorage-impl.ts @@ -20,7 +20,6 @@ import {Headers, RequestOptions} from '@angular/http'; import {HttpUtil} from '../utils/httpUtil'; import {DataSource} from './data-source'; -import {Alert} from '../model/alert'; import {ColumnMetadata} from '../model/column-metadata'; import {ElasticsearchUtils} from '../utils/elasticsearch-utils'; import { @@ -33,11 +32,12 @@ import {TableMetadata} from '../model/table-metadata'; import {SaveSearch} from '../model/save-search'; import {AlertsSearchResponse} from '../model/alerts-search-response'; import {SearchRequest} from '../model/search-request'; +import {AlertSource} from '../model/alert-source'; export class ElasticSearchLocalstorageImpl extends DataSource { private defaultColumnMetadata = [ - new ColumnMetadata('_id', 'string'), + new ColumnMetadata('id', 'string'), new ColumnMetadata('timestamp', 'date'), new ColumnMetadata('source:type', 'string'), new ColumnMetadata('ip_src_addr', 'ip'), @@ -59,12 +59,11 @@ export class ElasticSearchLocalstorageImpl extends DataSource { .onErrorResumeNext(); } - getAlert(index: string, type: string, alertId: string): Observable<Alert> { - return this.http.get('/search/' + index + '/' + type + '/' + alertId, new RequestOptions({headers: new Headers(this.defaultHeaders)})) - .map(HttpUtil.extractData); + getAlert(sourceType: string, alertId: string): Observable<AlertSource> { + return Observable.throw('Method not implemented in ElasticSearchLocalstorageImpl'); } - updateAlertState(request: any) { + updateAlertState(request: any): Observable<{}> { return this.http.post('/search/_bulk', request, new RequestOptions({headers: new Headers(this.defaultHeaders)})) .map(HttpUtil.extractData) .catch(HttpUtil.handleError); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/service/rest-api-impl.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/service/rest-api-impl.ts b/metron-interface/metron-alerts/src/app/service/rest-api-impl.ts new file mode 100644 index 0000000..061708d --- /dev/null +++ b/metron-interface/metron-alerts/src/app/service/rest-api-impl.ts @@ -0,0 +1,46 @@ +/** + * 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. + */ +import {Observable} from 'rxjs/Rx'; +import {Headers, RequestOptions} from '@angular/http'; + +import {HttpUtil} from '../utils/httpUtil'; +import {AlertsSearchResponse} from '../model/alerts-search-response'; +import {SearchRequest} from '../model/search-request'; +import {ElasticSearchLocalstorageImpl} from './elasticsearch-localstorage-impl'; +import {AlertSource} from '../model/alert-source'; + +export class RestApiImpl extends ElasticSearchLocalstorageImpl { + + getAlerts(searchRequest: SearchRequest): Observable<AlertsSearchResponse> { + let url = '/api/v1/search/search'; + return this.http.post(url, searchRequest, new RequestOptions({headers: new Headers(this.defaultHeaders)})) + .map(HttpUtil.extractData) + .catch(HttpUtil.handleError) + .onErrorResumeNext(); + } + + getAlert(sourceType: string, alertId: string): Observable<AlertSource> { + let url = '/api/v1/search/findOne'; + let requestSchema = { guid: alertId, sensorType: sourceType}; + + return this.http.post(url, requestSchema, new RequestOptions({headers: new Headers(this.defaultHeaders)})) + .map(HttpUtil.extractData) + .catch(HttpUtil.handleError) + .onErrorResumeNext(); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/shared/auth-guard.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/shared/auth-guard.ts b/metron-interface/metron-alerts/src/app/shared/auth-guard.ts new file mode 100644 index 0000000..66c27cf --- /dev/null +++ b/metron-interface/metron-alerts/src/app/shared/auth-guard.ts @@ -0,0 +1,50 @@ +/** + * 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. + */ +import { Injectable } from '@angular/core'; +import { + CanActivate, + Router, + ActivatedRouteSnapshot, + RouterStateSnapshot +} from '@angular/router'; +import { Observable } from 'rxjs/Observable'; +import { AuthenticationService } from '../service/authentication.service'; + +@Injectable() +export class AuthGuard implements CanActivate { + + constructor(private authService: AuthenticationService, private router: Router) {} + + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + if (!this.authService.isAuthenticationChecked()) { + return Observable.create(observer => { + this.authService.onLoginEvent.subscribe(isLoggedIn => { + if (isLoggedIn) { + observer.next(true); + observer.complete(); + } else { + observer.next(false); + observer.complete(); + this.router.navigateByUrl('/login'); + } + }); + }); + } + return this.authService.isAuthenticated(); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/shared/login-guard.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/shared/login-guard.ts b/metron-interface/metron-alerts/src/app/shared/login-guard.ts new file mode 100644 index 0000000..d8b8f0d --- /dev/null +++ b/metron-interface/metron-alerts/src/app/shared/login-guard.ts @@ -0,0 +1,40 @@ +/** + * 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. + */ +import { Injectable } from '@angular/core'; +import { + CanActivate, + Router, + ActivatedRouteSnapshot, + RouterStateSnapshot +} from '@angular/router'; +import { AuthenticationService } from '../service/authentication.service'; + +// This guard will ensure that logout is called even if you call /login manually +@Injectable() +export class LoginGuard implements CanActivate { + + constructor(private authService: AuthenticationService, private router: Router) {} + + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + + this.authService.logout(); + + return true; + + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/utils/elasticsearch-utils.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/utils/elasticsearch-utils.ts b/metron-interface/metron-alerts/src/app/utils/elasticsearch-utils.ts index 62b7464..a86907b 100644 --- a/metron-interface/metron-alerts/src/app/utils/elasticsearch-utils.ts +++ b/metron-interface/metron-alerts/src/app/utils/elasticsearch-utils.ts @@ -50,7 +50,7 @@ export class ElasticsearchUtils { } } - columnMetadata.push(new ColumnMetadata('_id', 'string')); + columnMetadata.push(new ColumnMetadata('id', 'string')); return columnMetadata; } http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/app/utils/httpUtil.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/utils/httpUtil.ts b/metron-interface/metron-alerts/src/app/utils/httpUtil.ts index a93e66e..89d309f 100644 --- a/metron-interface/metron-alerts/src/app/utils/httpUtil.ts +++ b/metron-interface/metron-alerts/src/app/utils/httpUtil.ts @@ -18,6 +18,7 @@ import {Response} from '@angular/http'; import {Observable} from 'rxjs/Observable'; import {RestError} from '../model/rest-error'; + export class HttpUtil { public static extractString(res: Response): string { @@ -34,7 +35,10 @@ export class HttpUtil { // In a real world app, we might use a remote logging infrastructure // We'd also dig deeper into the error to get a better message let restError: RestError; - if (res.status !== 404) { + if (res.status === 401) { + restError = res.json(); + window.location.pathname = '/login'; + } else if (res.status !== 404) { restError = res.json(); } else { restError = new RestError(); http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-interface/metron-alerts/src/environments/environment.prod.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/environments/environment.prod.ts b/metron-interface/metron-alerts/src/environments/environment.prod.ts index 53fca2d..1b628e3 100644 --- a/metron-interface/metron-alerts/src/environments/environment.prod.ts +++ b/metron-interface/metron-alerts/src/environments/environment.prod.ts @@ -16,6 +16,5 @@ * limitations under the License. */ export const environment = { - production: true, - dataSource: 'elastic' + production: true }; http://git-wip-us.apache.org/repos/asf/metron/blob/43646650/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/StellarTransformation.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/StellarTransformation.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/StellarTransformation.java index a5d8689..2a22e21 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/StellarTransformation.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/field/transformation/StellarTransformation.java @@ -55,6 +55,17 @@ public class StellarTransformation implements FieldTransformation { intermediateVariables.put(oField, o); } } + else { + if(outputs.contains(oField)) { + ret.put(oField, o); + } + if( o != null ) { + intermediateVariables.put(oField, o); + } else { + // remove here, in case there are other statements + intermediateVariables.remove(oField); + } + } } catch(Exception ex) { throw new IllegalStateException( "Unable to process transformation: " + transformObj.toString()