├── excel ├── Advanced Search.xlsm └── README.md ├── incident_overview ├── screenshot.png ├── src │ └── main │ │ ├── webapp │ │ ├── images │ │ │ ├── flourish4.png │ │ │ ├── user-profile_32.png │ │ │ └── user-profile-light_32.png │ │ ├── WEB-INF │ │ │ └── web.xml │ │ ├── map │ │ │ ├── css │ │ │ │ ├── d3.parcoords.css │ │ │ │ ├── main.css │ │ │ │ ├── tipsy.css │ │ │ │ ├── throbber.css │ │ │ │ └── floatingCircles.css │ │ │ └── js │ │ │ │ └── jquery.tipsy.js │ │ ├── css │ │ │ ├── d3.slider.css │ │ │ └── vis.css │ │ ├── js │ │ │ ├── queue.v1.min.js │ │ │ ├── jquery.vticker.min.js │ │ │ ├── topojson.v1.min.js │ │ │ └── d3.slider.js │ │ └── index.jsp │ │ ├── resources │ │ ├── qradar.properties │ │ ├── META-INF │ │ │ └── persistence.xml │ │ └── log4j.xml │ │ ├── java │ │ └── com │ │ │ └── ibm │ │ │ └── si │ │ │ └── qradar │ │ │ └── offenseviz │ │ │ ├── core │ │ │ ├── Status.java │ │ │ ├── OffenseCleaner.java │ │ │ ├── OffenseVizContextListener.java │ │ │ └── OffenseCollector.java │ │ │ ├── dao │ │ │ ├── Dao.java │ │ │ ├── BaseDao.java │ │ │ ├── SourceDao.java │ │ │ ├── DestinationDao.java │ │ │ └── OffenseDao.java │ │ │ ├── jpa │ │ │ ├── GeographicEndpoint.java │ │ │ ├── Source.java │ │ │ └── Destination.java │ │ │ ├── util │ │ │ ├── XForceToken.java │ │ │ ├── JsonProcessingExceptionMapper.java │ │ │ ├── PersistenceUtil.java │ │ │ ├── PropertiesReader.java │ │ │ └── XForceUtil.java │ │ │ ├── api │ │ │ ├── OffenseVizApplication.java │ │ │ ├── IPLookupResource.java │ │ │ └── OffenseResource.java │ │ │ ├── geoip │ │ │ ├── GeoInfo.java │ │ │ └── GeoipUtil.java │ │ │ ├── model │ │ │ └── OffenseBucket.java │ │ │ └── conf │ │ │ └── QRadarConfig.java │ │ ├── etc │ │ └── server.xml │ │ └── sql │ │ └── create-db.sql ├── build.gradle ├── README.md └── LICENSE ├── offense_visualizer ├── screenshot.png ├── views.py ├── manifest.json ├── package_as_app.sh ├── README.md ├── visualizer.html └── visualizer.js ├── README.md └── LICENSE /excel/Advanced Search.xlsm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-security-intelligence/visualizations/HEAD/excel/Advanced Search.xlsm -------------------------------------------------------------------------------- /incident_overview/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-security-intelligence/visualizations/HEAD/incident_overview/screenshot.png -------------------------------------------------------------------------------- /offense_visualizer/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-security-intelligence/visualizations/HEAD/offense_visualizer/screenshot.png -------------------------------------------------------------------------------- /offense_visualizer/views.py: -------------------------------------------------------------------------------- 1 | __author__ = 'IBM' 2 | 3 | from app import app 4 | 5 | @app.route('/') 6 | def index(): 7 | return "Hello, World!" 8 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/images/flourish4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-security-intelligence/visualizations/HEAD/incident_overview/src/main/webapp/images/flourish4.png -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/images/user-profile_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-security-intelligence/visualizations/HEAD/incident_overview/src/main/webapp/images/user-profile_32.png -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/images/user-profile-light_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-security-intelligence/visualizations/HEAD/incident_overview/src/main/webapp/images/user-profile-light_32.png -------------------------------------------------------------------------------- /offense_visualizer/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"Offense Visualizer", 3 | "description":"Offense Visualizer", 4 | "version":"0.0.1", 5 | "uuid":"98b0706a-d07a-498f-b732-966adc53adff", 6 | "log_level":"INFO", 7 | 8 | "areas": [{ 9 | "url": "static/visualizer.html", 10 | "text": "Offense Visualizer", 11 | "id": "OffenseVisualizer", 12 | "description": "Offense Visualizer" 13 | }] 14 | } 15 | 16 | -------------------------------------------------------------------------------- /incident_overview/src/main/resources/qradar.properties: -------------------------------------------------------------------------------- 1 | auth_token=dbcb19b4-b7bf-41de-ab6c-18b03c16ab68 2 | url=9.21.118.219 3 | qradar_timeZone=America/Halifax 4 | update_interval_seconds=300 5 | default_latitude=45.945332 6 | default_longitude=-66.691904 7 | cleanup_old_offense_interval=60 8 | xforce_api_url=xforce-api.mybluemix.net 9 | xforce_web_url=exchange.xforce.ibmcloud.com 10 | default_country=Canada 11 | default_city=Fredericton -------------------------------------------------------------------------------- /incident_overview/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jdbc/postgres 5 | com.ibm.si.qradar.offenseviz.jpa.Offense 6 | com.ibm.si.qradar.offenseviz.jpa.Destination 7 | com.ibm.si.qradar.offenseviz.jpa.Source 8 | 9 | 10 | -------------------------------------------------------------------------------- /offense_visualizer/package_as_app.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | FILE=com.ibm.offense_visualizer.0.0.1.zip 3 | 4 | echo "Enter the IP or hostname of your QRadar console:" 5 | read HOST 6 | echo 7 | 8 | DIR="`dirname $0`" 9 | cd $DIR 10 | mkdir -p app/static 11 | cp *.py app 12 | cp *.js app/static 13 | cp *.css app/static 14 | cp *.html app/static 15 | rm -f $FILE 16 | zip -r $FILE app manifest.json 17 | rm -Rf app 18 | echo 19 | 20 | curl -u admin -k --header "Content-Type: application/zip" --data-binary "@$FILE" https://$HOST/api/gui_app_framework/application_creation_task 21 | 22 | echo 23 | echo "If the above text contains CREATING, then this operation succeeded. Wait a few minutes, then refresh the QRadar UI" 24 | -------------------------------------------------------------------------------- /excel/README.md: -------------------------------------------------------------------------------- 1 | Advanced Search.xlsx 2 | 3 | This spreadsheet allows to run a QRadar advanced search and return the resuls directly into Excel for 4 | visualisation and/or further data analysis. 5 | 6 | The spreadsheet is very straightforward. On the first work sheet, called "Config", you configure: 7 | 8 | - the QRadar service IP address, 9 | - the security token to use to access the server (created from the "Authorized services" icon in the admin tab) 10 | - The name of worksheet into which the query results will be placed 11 | - The query itself 12 | 13 | Once you have done this, simply hit the 'Run Query' button, which will invoke a macro and run the query. 14 | 15 | It is recommended not to pull millions of events or flows back into excel, instead your query should filter and/or aggregate the data -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/core/Status.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.core; 14 | 15 | public enum Status { 16 | OPEN, 17 | HIDDEN, 18 | CLOSED 19 | } 20 | -------------------------------------------------------------------------------- /incident_overview/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | This repository contains samples of visualization add-ons to QRadar, utilizing public REST APIs. 3 | 4 | These samples are provided for reference purposes on an "as is" basis, and are without warranties of any kind. 5 | 6 | Any issues discovered using the samples should not be directed to QRadar support, but be reported on the Github issues tracker. 7 | 8 | incident_overview 9 | ================== 10 | A stand alone visualization that displays incidents from QRadar. Incidents are represented based on magnitude and linked via IP addresses. Details (including geographic map and IP relationship chart) of the offense are available by clicking on an incident. Originally shown at RSA 2015 and Blackhat 2015. 11 | 12 | offense_visualizer 13 | ============== 14 | A visualization that runs in a web browser, showing an interactive bubble chart of offenses 15 | 16 | excel 17 | ===== 18 | Ability to execute an advanced query directly from excel and have the results come back into excel 19 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/dao/Dao.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.dao; 14 | 15 | import java.util.List; 16 | 17 | public interface Dao { 18 | void persist(E entity); 19 | void remove(E entity); 20 | E findById(K id); 21 | List findAll(); 22 | } 23 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | offense-viz 4 | 5 | index.html 6 | index.htm 7 | index.jsp 8 | default.html 9 | default.htm 10 | default.jsp 11 | 12 | 13 | 14 | com.ibm.si.qradar.offenseviz.api.OffenseVizApplication 15 | 16 | 17 | com.ibm.si.qradar.offenseviz.api.OffenseVizApplication 18 | /api/* 19 | 20 | 21 | 22 | com.ibm.si.qradar.offenseviz.core.OffenseVizContextListener 23 | 24 | 25 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/jpa/GeographicEndpoint.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.jpa; 14 | 15 | public interface GeographicEndpoint { 16 | 17 | public String getIp(); 18 | 19 | public void setLatitude(Double latitude); 20 | 21 | public void setLongitude(Double longitude); 22 | 23 | public void setCountry(String country); 24 | 25 | public void setCity(String city); 26 | 27 | public void setInternal(boolean isInternal); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/util/XForceToken.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.util; 14 | 15 | import com.fasterxml.jackson.annotation.JsonProperty; 16 | 17 | public class XForceToken { 18 | 19 | @JsonProperty("token") 20 | private String token; 21 | 22 | public XForceToken() {} 23 | 24 | public String getToken() { 25 | return token; 26 | } 27 | 28 | public void setToken(String token) { 29 | this.token = token; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/map/css/d3.parcoords.css: -------------------------------------------------------------------------------- 1 | .parcoords > svg, .parcoords > canvas { 2 | font-size: 16px; 3 | font-family: Helvetica, Arial, sans-serif; 4 | position: absolute; 5 | } 6 | 7 | .parcoords .axis .tick > text { 8 | font-size: 10px; 9 | } 10 | 11 | .parcoords > canvas { 12 | pointer-events: none; 13 | } 14 | 15 | .parcoords text.label { 16 | cursor: default; 17 | } 18 | 19 | .parcoords rect.background { 20 | fill: transparent; 21 | } 22 | .parcoords rect.background:hover { 23 | fill: rgba(120,120,120,0.2); 24 | } 25 | .parcoords .resize rect { 26 | fill: rgba(0,0,0,0.1); 27 | } 28 | .parcoords rect.extent { 29 | fill: rgba(255,255,255,0.25); 30 | stroke: rgba(0,0,0,0.6); 31 | } 32 | .parcoords .axis line, .parcoords .axis path { 33 | fill: none; 34 | stroke: #222; 35 | shape-rendering: crispEdges; 36 | } 37 | .parcoords canvas { 38 | opacity: 1; 39 | -moz-transition: opacity 0.3s; 40 | -webkit-transition: opacity 0.3s; 41 | -o-transition: opacity 0.3s; 42 | } 43 | .parcoords canvas.faded { 44 | opacity: 0.25; 45 | } 46 | .parcoords { 47 | -webkit-touch-callout: none; 48 | -webkit-user-select: none; 49 | -khtml-user-select: none; 50 | -moz-user-select: none; 51 | -ms-user-select: none; 52 | user-select: none; 53 | } 54 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/dao/BaseDao.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.dao; 14 | 15 | import javax.persistence.EntityManager; 16 | import javax.persistence.PersistenceContext; 17 | 18 | import com.ibm.si.qradar.offenseviz.util.PersistenceUtil; 19 | 20 | public abstract class BaseDao implements Dao{ 21 | 22 | protected EntityManager entityManager; 23 | 24 | public BaseDao(EntityManager entityManager) { 25 | this.entityManager = entityManager; 26 | } 27 | 28 | public EntityManager getEntityManager() { 29 | return entityManager; 30 | } 31 | 32 | public void setEntityManager(EntityManager entityManager) { 33 | this.entityManager = entityManager; 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/util/JsonProcessingExceptionMapper.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.util; 14 | 15 | import com.fasterxml.jackson.core.JsonProcessingException; 16 | 17 | import javax.ws.rs.core.MediaType; 18 | import javax.ws.rs.core.Response; 19 | import javax.ws.rs.core.Response.Status; 20 | import javax.ws.rs.ext.ExceptionMapper; 21 | import javax.ws.rs.ext.Provider; 22 | 23 | @Provider 24 | public class JsonProcessingExceptionMapper implements ExceptionMapper { 25 | 26 | @Override 27 | public Response toResponse(JsonProcessingException exception) { 28 | String message = exception.getMessage(); 29 | return Response.status(Status.BAD_REQUEST).type(MediaType.TEXT_PLAIN) 30 | .entity("The supplied JSON was not well formed: " + message) 31 | .build(); 32 | } 33 | } -------------------------------------------------------------------------------- /incident_overview/src/main/etc/server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jsp-2.2 6 | localConnector-1.0 7 | jaxrs-1.1 8 | jdbc-4.0 9 | jpa-2.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/util/PersistenceUtil.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.util; 14 | 15 | import javax.persistence.EntityManagerFactory; 16 | import javax.persistence.Persistence; 17 | import org.slf4j.LoggerFactory; 18 | import org.slf4j.Logger; 19 | 20 | public class PersistenceUtil { 21 | 22 | private static final EntityManagerFactory entityManagerFactory; 23 | private static final Logger logger = LoggerFactory.getLogger(PersistenceUtil.class); 24 | 25 | static { 26 | try { 27 | entityManagerFactory = Persistence.createEntityManagerFactory("offense-viz"); 28 | } catch (Throwable e) { 29 | logger.error("Initial SessionFactory creation failed " + e.getMessage()); 30 | throw new ExceptionInInitializerError(e); 31 | } 32 | } 33 | 34 | public static EntityManagerFactory getEntityManagerFactory() { 35 | return entityManagerFactory; 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/css/d3.slider.css: -------------------------------------------------------------------------------- 1 | .d3-slider { 2 | position: relative; 3 | font-family: Verdana,Arial,sans-serif; 4 | font-size: 1.1em; 5 | border: 1px solid #aaaaaa; 6 | z-index: 2; 7 | } 8 | 9 | .d3-slider-horizontal { 10 | height: .8em; 11 | } 12 | 13 | .d3-slider-range { 14 | background:#2980b9; 15 | left:0px; 16 | right:0px; 17 | height: 0.8em; 18 | position: absolute; 19 | } 20 | 21 | .d3-slider-range-vertical { 22 | background:#2980b9; 23 | left:0px; 24 | right:0px; 25 | position: absolute; 26 | top:0; 27 | } 28 | 29 | .d3-slider-vertical { 30 | width: .8em; 31 | height: 100px; 32 | } 33 | 34 | .d3-slider-handle { 35 | position: absolute; 36 | width: 1.2em; 37 | height: 1.2em; 38 | border: 1px solid #d3d3d3; 39 | border-radius: 4px; 40 | background: #eee; 41 | background: linear-gradient(to bottom, #eee 0%, #ddd 100%); 42 | z-index: 3; 43 | } 44 | 45 | .d3-slider-handle:hover { 46 | border: 1px solid #999999; 47 | } 48 | 49 | .d3-slider-horizontal .d3-slider-handle { 50 | top: -.3em; 51 | margin-left: -.6em; 52 | } 53 | 54 | .d3-slider-axis { 55 | position: relative; 56 | z-index: 1; 57 | } 58 | 59 | .d3-slider-axis-bottom { 60 | top: .8em; 61 | } 62 | 63 | .d3-slider-axis-right { 64 | left: .8em; 65 | } 66 | 67 | .d3-slider-axis path { 68 | stroke-width: 0; 69 | fill: none; 70 | } 71 | 72 | .d3-slider-axis line { 73 | fill: none; 74 | stroke: #aaa; 75 | shape-rendering: crispEdges; 76 | } 77 | 78 | .d3-slider-axis text { 79 | font-size: 11px; 80 | } 81 | 82 | .d3-slider-vertical .d3-slider-handle { 83 | left: -.25em; 84 | margin-left: 0; 85 | margin-bottom: -.6em; 86 | } -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/util/PropertiesReader.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.util; 14 | 15 | import java.io.FileInputStream; 16 | import java.io.FileNotFoundException; 17 | import java.io.IOException; 18 | import java.io.InputStream; 19 | import java.util.Properties; 20 | 21 | public class PropertiesReader { 22 | 23 | public Properties getProperties(String filename) throws IOException { 24 | Properties properties = new Properties(); 25 | InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filename); 26 | 27 | if (inputStream != null) { 28 | properties.load(inputStream); 29 | } else { 30 | throw new FileNotFoundException(String.format("Properties file %s was not found in the classpath", filename)); 31 | } 32 | 33 | return properties; 34 | } 35 | 36 | public Properties getPropertiesFile(String filename) throws IOException { 37 | Properties properties = new Properties(); 38 | InputStream inputStream = new FileInputStream("/opt/" + filename); 39 | properties.load(inputStream); 40 | return properties; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /incident_overview/src/main/sql/create-db.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE offenseviz; 2 | 3 | CREATE TABLE offense( 4 | id BIGSERIAL PRIMARY KEY NOT NULL, 5 | seen_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now(), 6 | offense_id BIGINT, 7 | credibility INT, 8 | remote_destination_count INT, 9 | assigned_to TEXT, 10 | source_count INT, 11 | start_time TIMESTAMP WITHOUT TIME ZONE, 12 | inactive BOOLEAN, 13 | protected BOOLEAN, 14 | policy_category_count INT, 15 | description TEXT, 16 | category_count INT, 17 | relevance INT, 18 | device_count INT, 19 | security_category_count INT, 20 | flow_count INT, 21 | event_count INT, 22 | offense_source TEXT, 23 | status VARCHAR(16), 24 | magnitude INT, 25 | severity INT, 26 | username_count INT, 27 | closing_user TEXT, 28 | follow_up BOOLEAN, 29 | closing_reason_id INT, 30 | close_time TIMESTAMP WITHOUT TIME ZONE, 31 | source_network TEXT, 32 | last_updated_time TIMESTAMP WITHOUT TIME ZONE, 33 | offense_type INT 34 | ); 35 | 36 | CREATE TABLE source ( 37 | id BIGINT PRIMARY KEY NOT NULL, 38 | ip VARCHAR(16), 39 | network TEXT, 40 | username TEXT, 41 | latitude double precision, 42 | longitude double precision, 43 | country VARCHAR(100), 44 | city VARCHAR(100), 45 | internal BOOLEAN NOT NULL default false 46 | ); 47 | 48 | CREATE TABLE destination ( 49 | id BIGINT PRIMARY KEY NOT NULL, 50 | ip VARCHAR(16), 51 | network TEXT, 52 | username TEXT, 53 | latitude double precision, 54 | longitude double precision, 55 | country VARCHAR(100), 56 | city VARCHAR(100), 57 | internal BOOLEAN NOT NULL default false 58 | ); 59 | 60 | CREATE TABLE offense_source_link ( 61 | id BIGSERIAL PRIMARY KEY NOT NULL, 62 | offense_id BIGINT REFERENCES offense(id), 63 | source_id BIGINT REFERENCES source(id) 64 | ); 65 | 66 | CREATE TABLE offense_dest_link ( 67 | id BIGSERIAL PRIMARY KEY NOT NULL, 68 | offense_id BIGINT REFERENCES offense(id), 69 | dest_id BIGINT REFERENCES destination(id) 70 | ); 71 | 72 | CREATE TABLE offense_category ( 73 | offense_id BIGINT REFERENCES offense(id) NOT NULL, 74 | name TEXT NOT NULL 75 | ); 76 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/api/OffenseVizApplication.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.api; 14 | 15 | import java.util.Collections; 16 | import java.util.HashSet; 17 | import java.util.Set; 18 | 19 | import javax.ws.rs.core.Application; 20 | 21 | import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; 22 | import com.ibm.si.qradar.offenseviz.util.JsonProcessingExceptionMapper; 23 | 24 | public class OffenseVizApplication extends Application{ 25 | 26 | private Set singletons = Collections.emptySet(); 27 | 28 | public OffenseVizApplication() { 29 | Set s = new HashSet(); 30 | JacksonJsonProvider jsonProvider = new JacksonJsonProvider(); 31 | s.add(jsonProvider); 32 | setSingletons(s); 33 | } 34 | 35 | private void setSingletons(final Set singletons) { 36 | this.singletons = singletons; 37 | } 38 | 39 | public Set> getClasses() { 40 | HashSet> classes = new HashSet>(); 41 | 42 | // Resources 43 | classes.add(OffenseResource.class); 44 | classes.add(IPLookupResource.class); 45 | 46 | // Providers 47 | classes.add(JsonProcessingExceptionMapper.class); 48 | 49 | return classes; 50 | } 51 | 52 | @Override 53 | public Set getSingletons() { 54 | return singletons; 55 | } 56 | } 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/dao/SourceDao.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.dao; 14 | 15 | import java.util.List; 16 | 17 | import javax.persistence.EntityManager; 18 | import javax.persistence.TypedQuery; 19 | 20 | import com.ibm.si.qradar.offenseviz.jpa.Source; 21 | 22 | public class SourceDao extends BaseDao { 23 | 24 | public SourceDao(EntityManager entityManager) { 25 | super(entityManager); 26 | } 27 | 28 | @Override 29 | public void persist(Source entity) { 30 | // TODO Auto-generated method stub 31 | 32 | } 33 | 34 | @Override 35 | public void remove(Source entity) { 36 | // TODO Auto-generated method stub 37 | 38 | } 39 | 40 | @Override 41 | public Source findById(Long id) { 42 | // TODO Auto-generated method stub 43 | return null; 44 | } 45 | 46 | @Override 47 | public List findAll() { 48 | // TODO Auto-generated method stub 49 | return null; 50 | } 51 | 52 | public List findAllIds() { 53 | TypedQuery query = entityManager.createNamedQuery("Source.findAllIds", Long.class); 54 | List results = query.getResultList(); 55 | return results; 56 | } 57 | 58 | public Source merge(Source source) { 59 | entityManager.getTransaction().begin(); 60 | Source merged = entityManager.merge(source); 61 | entityManager.getTransaction().commit(); 62 | return merged; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /offense_visualizer/README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | ABOUT 4 | ===== 5 | 6 | This is a sample of how you can build advanced visualizations using the offense API. In this sample, we will use D3 (http://d3js.org) and a helper library called NVD3 (http://nvd3.org) to draw some fancy bubble charts of our offenses. 7 | 8 | 9 | REQUIREMENTS 10 | =========== 11 | 12 | The only requirement to run this sample is an active QRadar instance with offenses to deploy it on. 13 | 14 | DETAILED DESCRIPTION 15 | =========== 16 | 17 | The way this sample works is quite simple. We make a request to the "/api/siem/offenses" endpoint to get all the information we know about offenses encoded as JSON. We then load this information into a graphing framework to draw the offense information based on various attributes. 18 | 19 | HOW TO DEPLOY 20 | =========== 21 | 22 | Method 1, Deploy As App ( 7.2.6 and later only ): 23 | 24 | Copy the files to a machine, and run the package_as_app.sh script. The script will prompt you for the QRadar console IP address, as well as the password for the 'admin' user. It will then deploy the visualization as new tab in QRadar. 25 | 26 | Method 2, Manual ( pre 7.2.6 ): 27 | 28 | To deploy the sample, copy all of the files in this directory (using SCP) to your QRadar server into the location /opt/qradar/webapps/console/offense_visualizer. You can then access the sample at the following URL: https://[QRadar IP]/console/offense_visualizer/visualizer.html - feel free to bookmark this URL for quick reference. 29 | 30 | LICENSE 31 | =========== 32 | 33 | Copyright (c) 2013 IBM 34 | 35 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in 36 | compliance with the License. You may obtain a copy of the License at 37 | 38 | http://www.apache.org/licenses/LICENSE-2.0 39 | 40 | Unless required by applicable law or agreed to in writing, software distributed under the License is 41 | distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 42 | See the License for the specific language governing permissions and limitations under the License. 43 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/map/css/main.css: -------------------------------------------------------------------------------- 1 | #map { 2 | position:relative; 3 | background-color: #fff; 4 | border: none; 5 | } 6 | .background { 7 | fill: none; 8 | pointer-events: all; 9 | } 10 | .countries { 11 | /*fill: #cde; 12 | stroke: #fff;*/ 13 | fill: #cccccc; 14 | stroke: #fff; 15 | stroke-linejoin: round; 16 | stroke-linecap: round; 17 | } 18 | .markerpoint { 19 | fill: #000000; 20 | stroke: #ffffff; 21 | stroke-linecap: round; 22 | stroke-linejoin: round; 23 | } 24 | 25 | .markerpoint circle { 26 | cursor: pointer; 27 | } 28 | 29 | .markerpoint circle:hover { 30 | /*stroke: #f0ff00;*/ 31 | /*fill: #333333;*/ 32 | opacity: 0.75; 33 | } 34 | 35 | .travelMarker { 36 | stroke: #00649D; 37 | fill: #82D1F5; 38 | opacity: 0.75; 39 | } 40 | 41 | .travelMarker:hover { 42 | /*stroke: #333333;*/ 43 | opacity: 1; 44 | } 45 | 46 | .lineConnect { 47 | stroke: #00BFF2; 48 | fill: none; 49 | opacity: 0.5; 50 | } 51 | 52 | /* .lineConnect:hover { 53 | opacity: 0.75; 54 | } */ 55 | 56 | #graph > svg { 57 | height:150px; 58 | width: inherit; 59 | } 60 | 61 | div.tooltip { 62 | color: #222; 63 | background: #fff; 64 | padding: .5em; 65 | text-shadow: #f5f5f5 0 1px 0; 66 | border-radius: 2px; 67 | box-shadow: 0px 0px 2px 0px #a6a6a6; 68 | opacity: 0.9; 69 | position: fixed; 70 | } 71 | 72 | .overlay { 73 | position:absolute; 74 | top:0; 75 | left:0; 76 | right:0; 77 | bottom:0; 78 | /* background-color:rgba(0, 0, 0, 0.2); */ 79 | background: url(data:;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNUmK/OAAAAATSURBVBhXY2RgYNgHxGAAYuwDAA78AjwwRoQYAAAAAElFTkSuQmCC) repeat scroll transparent\9; 80 | z-index:9999; 81 | color:black; 82 | text-align: center; 83 | } 84 | 85 | .overlay_txt { 86 | display: inline-block; 87 | vertical-align: middle; 88 | margin-top: 100px; 89 | padding: 10px 15px; 90 | position:relative; 91 | font-weight:bold; 92 | } -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/core/OffenseCleaner.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.core; 14 | 15 | import java.sql.Timestamp; 16 | import java.util.Calendar; 17 | 18 | import javax.persistence.EntityManager; 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import com.ibm.si.qradar.offenseviz.conf.QRadarConfig; 24 | import com.ibm.si.qradar.offenseviz.dao.OffenseDao; 25 | import com.ibm.si.qradar.offenseviz.util.PersistenceUtil; 26 | 27 | public class OffenseCleaner implements Runnable { 28 | 29 | private OffenseDao offenseDao; 30 | private static final Logger logger = LoggerFactory.getLogger(OffenseCleaner.class); 31 | 32 | @Override 33 | public void run() { 34 | EntityManager entityManager = null; 35 | 36 | try { 37 | entityManager = PersistenceUtil.getEntityManagerFactory().createEntityManager(); 38 | offenseDao = new OffenseDao(entityManager); 39 | cleanupOldOffenses(); 40 | } catch (Exception e) { 41 | logger.error("Could not clean up old offenses", e); 42 | } finally { 43 | if(entityManager != null) { 44 | entityManager.close(); 45 | } 46 | } 47 | } 48 | 49 | private void cleanupOldOffenses() { 50 | int cleanupInterval = QRadarConfig.getInstance().getCleanupIntervalMinutes(); 51 | Long now = Calendar.getInstance().getTimeInMillis(); 52 | Long maxAge = now - (cleanupInterval * 60 * 1000); 53 | offenseDao.cleanupOldOffenses(new Timestamp(maxAge)); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/js/queue.v1.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012, Michael Bostock 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * The name Michael Bostock may not be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 22 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 25 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | !function(){function n(n){function e(){for(;i=ap;){var u=a++,e=c[u],o=t.call(e,1);o.push(l(u)),++p,e[0].apply(null,o)}}function l(n){return function(u,t){--p,null==s&&(null!=u?(s=u,a=d=0/0,o()):(c[n]=t,--d?i||e():o()))}}function o(){null!=s?m(s):f?m(s,c):m.apply(null,[s].concat(c))}var r,i,f,c=[],a=0,p=0,d=0,s=null,m=u;return n||(n=1/0),r={defer:function(){return s||(c.push(arguments),++d,e()),r},await:function(n){return m=n,f=!1,d||o(),r},awaitAll:function(n){return m=n,f=!0,d||o(),r}}}function u(){}var t=[].slice;n.version="1.0.7","function"==typeof define&&define.amd?define(function(){return n}):"object"==typeof module&&module.exports?module.exports=n:this.queue=n}(); -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/dao/DestinationDao.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.dao; 14 | 15 | import java.util.List; 16 | 17 | import javax.persistence.EntityManager; 18 | import javax.persistence.TypedQuery; 19 | 20 | import com.ibm.si.qradar.offenseviz.jpa.Destination; 21 | import com.ibm.si.qradar.offenseviz.jpa.Source; 22 | 23 | public class DestinationDao extends BaseDao { 24 | 25 | public DestinationDao(EntityManager entityManager) { 26 | super(entityManager); 27 | } 28 | 29 | @Override 30 | public void persist(Destination entity) { 31 | // TODO Auto-generated method stub 32 | 33 | } 34 | 35 | @Override 36 | public void remove(Destination entity) { 37 | // TODO Auto-generated method stub 38 | 39 | } 40 | 41 | @Override 42 | public Destination findById(Long id) { 43 | // TODO Auto-generated method stub 44 | return null; 45 | } 46 | 47 | @Override 48 | public List findAll() { 49 | // TODO Auto-generated method stub 50 | return null; 51 | } 52 | 53 | public List findAllIds() { 54 | TypedQuery query = entityManager.createNamedQuery("Destination.findAllIds", Long.class); 55 | List results = query.getResultList(); 56 | return results; 57 | } 58 | 59 | public Destination merge(Destination dest) { 60 | entityManager.getTransaction().begin(); 61 | Destination merged = entityManager.merge(dest); 62 | entityManager.getTransaction().commit(); 63 | return merged; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/core/OffenseVizContextListener.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.core; 14 | 15 | import java.util.concurrent.Executors; 16 | import java.util.concurrent.ScheduledExecutorService; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | import javax.servlet.ServletContext; 20 | import javax.servlet.ServletContextEvent; 21 | import javax.servlet.ServletContextListener; 22 | 23 | import com.ibm.si.qradar.offenseviz.conf.QRadarConfig; 24 | 25 | public class OffenseVizContextListener implements ServletContextListener { 26 | 27 | private ScheduledExecutorService scheduledExecutor; 28 | 29 | public void contextInitialized(ServletContextEvent sce) { 30 | ServletContext context = sce.getServletContext(); 31 | scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); 32 | context.setAttribute("MY_EXECUTOR", scheduledExecutor); 33 | 34 | initStartupJobs(); 35 | } 36 | 37 | private void initStartupJobs() { 38 | int updateInterval = QRadarConfig.getInstance().getUpdateInterval(); 39 | int cleanupInterval = QRadarConfig.getInstance().getCleanupIntervalMinutes(); 40 | scheduledExecutor.scheduleAtFixedRate(new OffenseCollector(), 0, updateInterval, TimeUnit.SECONDS); 41 | scheduledExecutor.scheduleAtFixedRate(new OffenseCleaner(), cleanupInterval, cleanupInterval, TimeUnit.MINUTES); 42 | } 43 | 44 | public void contextDestroyed(ServletContextEvent sce) { 45 | ServletContext context = sce.getServletContext(); 46 | scheduledExecutor.shutdownNow(); // or process/wait until all pending jobs are done 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/geoip/GeoInfo.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.geoip; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import com.maxmind.geoip2.record.Location; 19 | 20 | public class GeoInfo { 21 | private Double latitude; 22 | private Double longitude; 23 | private String country; 24 | private String city; 25 | 26 | public GeoInfo(Location location) { 27 | this.latitude = location.getLatitude(); 28 | this.longitude = location.getLongitude(); 29 | } 30 | 31 | public GeoInfo(Double latitude, Double longitude, String country, String city) { 32 | this.latitude = latitude; 33 | this.longitude = longitude; 34 | this.country = country; 35 | this.city = city; 36 | } 37 | 38 | public Double getLatitude() { 39 | return latitude; 40 | } 41 | 42 | public void setLatitude(Double latitude) { 43 | this.latitude = latitude; 44 | } 45 | 46 | public Double getLongitude() { 47 | return longitude; 48 | } 49 | 50 | public void setLongitude(Double longitude) { 51 | this.longitude = longitude; 52 | } 53 | 54 | public List asArray() { 55 | List list = new ArrayList(); 56 | list.add(longitude.toString()); 57 | list.add(latitude.toString()); 58 | list.add(country); 59 | list.add(city); 60 | return list; 61 | } 62 | 63 | public String getCountry() { 64 | return country; 65 | } 66 | 67 | public void setCountry(String country) { 68 | this.country = country; 69 | } 70 | 71 | public String getCity() { 72 | return city; 73 | } 74 | 75 | public void setCity(String city) { 76 | this.city = city; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/map/css/tipsy.css: -------------------------------------------------------------------------------- 1 | .tipsy { font-size: 10px; position: absolute; padding: 5px; z-index: 100000; } 2 | .tipsy-inner { background-color: #00649D; color: #FFF; max-width: 200px; padding: 5px 8px 4px 8px; text-align: center; } 3 | 4 | /* Rounded corners */ 5 | .tipsy-inner { border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; } 6 | 7 | /* Uncomment for shadow */ 8 | /*.tipsy-inner { box-shadow: 0 0 5px #00649D000; -webkit-box-shadow: 0 0 5px #00649D000; -moz-box-shadow: 0 0 5px #00649D000; }*/ 9 | 10 | .tipsy-arrow { position: absolute; width: 0; height: 0; line-height: 0; border: 5px dashed #00649D; } 11 | 12 | /* Rules to colour arrows */ 13 | .tipsy-arrow-n { border-bottom-color: #00649D; } 14 | .tipsy-arrow-s { border-top-color: #00649D; } 15 | .tipsy-arrow-e { border-left-color: #00649D; } 16 | .tipsy-arrow-w { border-right-color: #00649D; } 17 | 18 | .tipsy-n .tipsy-arrow { top: 0px; left: 50%; margin-left: -5px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent; } 19 | .tipsy-nw .tipsy-arrow { top: 0; left: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;} 20 | .tipsy-ne .tipsy-arrow { top: 0; right: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;} 21 | .tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; } 22 | .tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; } 23 | .tipsy-se .tipsy-arrow { bottom: 0; right: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; } 24 | .tipsy-e .tipsy-arrow { right: 0; top: 50%; margin-top: -5px; border-left-style: solid; border-right: none; border-top-color: transparent; border-bottom-color: transparent; } 25 | .tipsy-w .tipsy-arrow { left: 0; top: 50%; margin-top: -5px; border-right-style: solid; border-left: none; border-top-color: transparent; border-bottom-color: transparent; } 26 | 27 | .tipsy th { 28 | padding-right: 5px; 29 | font-weight: 700; 30 | text-align: left; 31 | } 32 | .tipsy td { 33 | text-align: left; 34 | } 35 | .tipsy table { 36 | margin-bottom: 5px; 37 | } -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/api/IPLookupResource.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.api; 14 | 15 | import javax.ws.rs.GET; 16 | import javax.ws.rs.Path; 17 | import javax.ws.rs.Produces; 18 | import javax.ws.rs.QueryParam; 19 | import javax.ws.rs.core.MediaType; 20 | import javax.ws.rs.core.Response; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import com.ibm.si.qradar.offenseviz.conf.QRadarConfig; 26 | import com.ibm.si.qradar.offenseviz.geoip.GeoInfo; 27 | import com.ibm.si.qradar.offenseviz.geoip.GeoipUtil; 28 | 29 | @Path("/iplookup") 30 | public class IPLookupResource { 31 | 32 | private static final Logger logger = LoggerFactory.getLogger(IPLookupResource.class); 33 | private static final Double defaultLatitude = QRadarConfig.getInstance().getDefaultLatitude(); 34 | private static final Double defaultLongitude = QRadarConfig.getInstance().getDefaultLongitude(); 35 | private static final String defaultCountry = QRadarConfig.getInstance().getDefaultCountry(); 36 | private static final String defaultCity = QRadarConfig.getInstance().getDefaultCity(); 37 | 38 | @GET 39 | @Produces(MediaType.APPLICATION_JSON) 40 | public Response lookupIpAddress(@QueryParam("ip") String ipAddress) { 41 | Response response; 42 | GeoipUtil geoipUtil = null; 43 | 44 | if(ipAddress != null) { 45 | GeoInfo ginfo = null; 46 | 47 | try { 48 | geoipUtil = new GeoipUtil(); 49 | ginfo = geoipUtil.getGeoInfo(ipAddress); 50 | if(ginfo == null) { 51 | ginfo = new GeoInfo(defaultLatitude, defaultLongitude, defaultCountry, defaultCity); 52 | } 53 | } catch (Exception e) { 54 | logger.debug("Couldn't look up IP", e); 55 | } finally { 56 | geoipUtil.dispose(); 57 | } 58 | response = Response.ok().entity(ginfo.asArray()).build(); 59 | } else { 60 | response = Response.ok().build(); 61 | } 62 | return response; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/model/OffenseBucket.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.model; 14 | 15 | import java.sql.Timestamp; 16 | import java.text.SimpleDateFormat; 17 | import java.util.ArrayList; 18 | import java.util.Calendar; 19 | import java.util.Date; 20 | import java.util.List; 21 | 22 | import com.ibm.si.qradar.offenseviz.conf.QRadarConfig; 23 | import com.ibm.si.qradar.offenseviz.jpa.Offense; 24 | 25 | public class OffenseBucket { 26 | 27 | private Timestamp bucketTime; 28 | private List offenses; 29 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss"); 30 | 31 | public OffenseBucket(Timestamp bucketTime, List offenses) { 32 | this.bucketTime = bucketTime; 33 | this.offenses = processOffenseList(offenses); 34 | } 35 | 36 | private List processOffenseList(List allOffenses) { 37 | int interval = QRadarConfig.getInstance().getUpdateInterval(); 38 | Timestamp maxAge = calculateMaxAge(interval, bucketTime); 39 | List offensesWithinInterval = new ArrayList(); 40 | 41 | for (Offense offense : allOffenses) { 42 | if (offense.getSeenAt().before(bucketTime) 43 | && offense.getSeenAt().after(maxAge)) { 44 | offensesWithinInterval.add(offense); 45 | } 46 | } 47 | 48 | return offensesWithinInterval; 49 | } 50 | 51 | private Timestamp calculateMaxAge(int interval, Timestamp bucketTime) { 52 | Calendar cal = Calendar.getInstance(); 53 | cal.setTimeInMillis(bucketTime.getTime()); 54 | cal.add(Calendar.SECOND, -interval); 55 | Timestamp maxAge = new Timestamp(cal.getTime().getTime()); 56 | return maxAge; 57 | } 58 | 59 | public Timestamp getBucketTime() { 60 | return bucketTime; 61 | } 62 | 63 | public void setBucketTime(Timestamp bucketTime) { 64 | this.bucketTime = bucketTime; 65 | } 66 | 67 | public List getOffenses() { 68 | return offenses; 69 | } 70 | 71 | public void setOffenses(List offenses) { 72 | this.offenses = offenses; 73 | } 74 | 75 | @Override 76 | public String toString() { 77 | return "OffenseBucket [\n\tbucketTime=" + dateFormat.format(new Date(bucketTime.getTime())) 78 | + ", \n\toffenseCount =" + String.valueOf(offenses.size()) + "\n]"; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/geoip/GeoipUtil.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.geoip; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.net.InetAddress; 18 | import java.net.URISyntaxException; 19 | import java.net.URL; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import com.maxmind.geoip2.DatabaseReader; 25 | import com.maxmind.geoip2.exception.GeoIp2Exception; 26 | import com.maxmind.geoip2.model.CityResponse; 27 | import com.maxmind.geoip2.record.City; 28 | import com.maxmind.geoip2.record.Country; 29 | import com.maxmind.geoip2.record.Location; 30 | 31 | public class GeoipUtil { 32 | 33 | private static final Logger logger = LoggerFactory.getLogger(GeoipUtil.class); 34 | static final ClassLoader loader = GeoipUtil.class.getClassLoader(); 35 | String databaseFilename = "GeoLite2-City.mmdb"; 36 | DatabaseReader reader; 37 | File database; 38 | 39 | public GeoipUtil() throws URISyntaxException, IOException { 40 | try { 41 | URL resourceUrl = loader.getResource(databaseFilename); 42 | //database = new File(resourceUrl.toURI()); 43 | database = new File("/opt/" + databaseFilename); 44 | reader = new DatabaseReader.Builder(database).build(); 45 | } catch (Exception e) { 46 | reader = null; 47 | logger.info("Could not load geo lookup db", e); 48 | } 49 | } 50 | 51 | public GeoInfo getGeoInfo(String ipAddressIn ) throws IOException { 52 | if( reader != null) { 53 | try { 54 | InetAddress ipAddress = InetAddress.getByName(ipAddressIn); 55 | CityResponse response = reader.city(ipAddress); 56 | City city = response.getCity(); 57 | Country country = response.getCountry(); 58 | Location loc = response.getLocation(); 59 | 60 | GeoInfo gInfo = new GeoInfo(loc); 61 | gInfo.setCity(city.getName()); 62 | gInfo.setCountry(country.getName()); 63 | 64 | return gInfo; 65 | } catch(GeoIp2Exception geoE) { 66 | logger.info(String.format("Could not lookup country of %s", ipAddressIn)); 67 | return null; 68 | } 69 | } else { 70 | return null; 71 | } 72 | } 73 | 74 | public void dispose() { 75 | try { 76 | if(reader != null) { 77 | reader.close(); 78 | } 79 | } catch (IOException e) { 80 | logger.error("Could not close GeoIP reader.", e); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/js/jquery.vticker.min.js: -------------------------------------------------------------------------------- 1 | /*! vTicker 1.15 2 | http://richhollis.github.com/vticker/ | http://richhollis.github.com/vticker/license/ | based on Jubgits vTicker http://www.jugbit.com/jquery-vticker-vertical-news-ticker/ */ 3 | (function(d){var n={speed:700,pause:4E3,showItems:1,mousePause:!0,height:0,animate:!0,margin:0,padding:0,startPaused:!1},c={moveUp:function(a,b){c.animate(a,b,"up")},moveDown:function(a,b){c.animate(a,b,"down")},animate:function(a,b,e){var c=a.itemHeight,f=a.options,k=a.element,g=k.children("ul"),l="up"===e?"li:first":"li:last";k.trigger("vticker.beforeTick");var m=g.children(l).clone(!0);0a.itemCount||f.next.call(this,{animate:b.animate})},startInterval:function(){var a=d(this).data("state"),b= 5 | this;a.intervalId=setInterval(function(){c.nextUsePause.call(b)},a.options.pause)},stopInterval:function(){var a=d(this).data("state");a&&(a.intervalId&&clearInterval(a.intervalId),a.intervalId=void 0)},restartInterval:function(){c.stopInterval.call(this);c.startInterval.call(this)}},f={init:function(a){f.stop.call(this);var b=jQuery.extend({},n);a=d.extend(b,a);var b=d(this),e={itemCount:b.children("ul").children("li").length,itemHeight:0,itemMargin:0,element:b,animating:!1,options:a,isPaused:a.startPaused? 6 | !0:!1,pausedByCode:!1};d(this).data("state",e);b.css({overflow:"hidden",position:"relative"}).children("ul").css({position:"absolute",margin:0,padding:0}).children("li").css({margin:a.margin,padding:a.padding});isNaN(a.height)||0===a.height?(b.children("ul").children("li").each(function(){var a=d(this);a.height()>e.itemHeight&&(e.itemHeight=a.height())}),b.children("ul").children("li").each(function(){d(this).height(e.itemHeight)}),b.height((e.itemHeight+(a.margin+2*a.padding))*a.showItems+a.margin)): 7 | b.height(a.height);var h=this;a.startPaused||c.startInterval.call(h);a.mousePause&&b.bind("mouseenter",function(){!0!==e.isPaused&&(e.pausedByCode=!0,c.stopInterval.call(h),f.pause.call(h,!0))}).bind("mouseleave",function(){if(!0!==e.isPaused||e.pausedByCode)e.pausedByCode=!1,f.pause.call(h,!1),c.startInterval.call(h)})},pause:function(a){var b=d(this).data("state");if(b){if(2>b.itemCount)return!1;b.isPaused=a;b=b.element;a?(d(this).addClass("paused"),b.trigger("vticker.pause")):(d(this).removeClass("paused"), 8 | b.trigger("vticker.resume"))}},next:function(a){var b=d(this).data("state");if(b){if(b.animating||2>b.itemCount)return!1;c.restartInterval.call(this);c.moveUp(b,a)}},prev:function(a){var b=d(this).data("state");if(b){if(b.animating||2>b.itemCount)return!1;c.restartInterval.call(this);c.moveDown(b,a)}},stop:function(){d(this).data("state")&&c.stopInterval.call(this)},remove:function(){var a=d(this).data("state");a&&(c.stopInterval.call(this),a=a.element,a.unbind(),a.remove())}};d.fn.vTicker=function(a){if(f[a])return f[a].apply(this, 9 | Array.prototype.slice.call(arguments,1));if("object"!==typeof a&&a)d.error("Method "+a+" does not exist on jQuery.vTicker");else return f.init.apply(this,arguments)}})(jQuery); -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/dao/OffenseDao.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.dao; 14 | 15 | import java.sql.Timestamp; 16 | import java.util.List; 17 | 18 | import javax.persistence.EntityManager; 19 | import javax.persistence.TypedQuery; 20 | 21 | import com.ibm.si.qradar.offenseviz.jpa.Destination; 22 | import com.ibm.si.qradar.offenseviz.jpa.Offense; 23 | import com.ibm.si.qradar.offenseviz.jpa.Source; 24 | 25 | public class OffenseDao extends BaseDao{ 26 | 27 | public OffenseDao(EntityManager entityManager) { 28 | super(entityManager); 29 | } 30 | 31 | @Override 32 | public void persist(Offense offense) { 33 | entityManager.getTransaction().begin(); 34 | entityManager.persist(offense); 35 | entityManager.getTransaction().commit(); 36 | } 37 | 38 | @Override 39 | public void remove(Offense offense) { 40 | // TODO Auto-generated method stub 41 | 42 | } 43 | 44 | @Override 45 | public Offense findById(Long id) { 46 | // TODO Auto-generated method stub 47 | return null; 48 | } 49 | 50 | @Override 51 | public List findAll() { 52 | TypedQuery query = entityManager.createNamedQuery("Offense.findAll", Offense.class); 53 | List results = query.getResultList(); 54 | return results; 55 | } 56 | 57 | public List findRecent(Timestamp oldestLastSeenTime) { 58 | TypedQuery query = entityManager.createNamedQuery("Offense.findRecent", Offense.class); 59 | query.setParameter("min_last_seen_time", oldestLastSeenTime); 60 | List results = query.getResultList(); 61 | return results; 62 | } 63 | 64 | public List findByTimestamp(Timestamp oldest, Timestamp newest) { 65 | TypedQuery query = entityManager.createNamedQuery("Offense.findByTimestamp", Offense.class); 66 | query.setParameter("min_last_seen_time", oldest); 67 | query.setParameter("max_last_seen_time", newest); 68 | List results = query.getResultList(); 69 | return results; 70 | } 71 | 72 | public void cleanupOldOffenses(Timestamp maxAge) { 73 | TypedQuery query = entityManager.createNamedQuery("Offense.cleanupOldByTimestamp", Offense.class); 74 | query.setParameter("max_last_seen_time", maxAge); 75 | List offensesToDelete = query.getResultList(); 76 | 77 | entityManager.getTransaction().begin(); 78 | 79 | for(Offense offense : offensesToDelete) { 80 | List sources = offense.getSourceList(); 81 | for(int i = sources.size() - 1; i >= 0 ; i--) { 82 | offense.getSourceList().remove(i); 83 | } 84 | 85 | List dests = offense.getDestinationList(); 86 | for(int i = dests.size() - 1; i >= 0 ; i--) { 87 | offense.getDestinationList().remove(i); 88 | } 89 | 90 | entityManager.remove(offense); 91 | } 92 | 93 | entityManager.getTransaction().commit(); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/jpa/Source.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.jpa; 14 | 15 | import java.io.Serializable; 16 | 17 | import javax.persistence.Entity; 18 | import javax.persistence.Id; 19 | import javax.persistence.NamedQueries; 20 | import javax.persistence.NamedQuery; 21 | 22 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 23 | import com.fasterxml.jackson.annotation.JsonProperty; 24 | 25 | 26 | /** 27 | * The persistent class for the source database table. 28 | * 29 | */ 30 | @Entity 31 | @NamedQueries({ 32 | @NamedQuery(name="Source.findAll", query="SELECT s FROM Source s"), 33 | @NamedQuery(name="Source.findAllIds", query="SELECT s.id FROM Source s"), 34 | }) 35 | @JsonIgnoreProperties(ignoreUnknown=true) 36 | public class Source implements Serializable, GeographicEndpoint { 37 | private static final long serialVersionUID = 1L; 38 | 39 | @Id 40 | private Long id; 41 | 42 | @JsonProperty("source_ip") 43 | private String ip; 44 | 45 | private String network; 46 | 47 | @JsonProperty("user") 48 | private String username; 49 | 50 | private Double latitude; 51 | 52 | private Double longitude; 53 | 54 | private String country; 55 | 56 | private String city; 57 | 58 | private boolean internal; 59 | 60 | public Source() { 61 | } 62 | 63 | public Source(Integer id) { 64 | this.id = Long.valueOf(id); 65 | } 66 | 67 | public String getCountry(){ 68 | return this.country; 69 | } 70 | 71 | public void setCountry(String country){ 72 | this.country = country; 73 | } 74 | 75 | public String getCity(){ 76 | return this.city; 77 | } 78 | 79 | public void setCity(String city){ 80 | this.city = city; 81 | } 82 | 83 | public Long getId() { 84 | return this.id; 85 | } 86 | 87 | public void setId(Long id) { 88 | this.id = id; 89 | } 90 | 91 | public String getIp() { 92 | return this.ip; 93 | } 94 | 95 | public void setIp(String ip) { 96 | this.ip = ip; 97 | } 98 | 99 | public String getNetwork() { 100 | return this.network; 101 | } 102 | 103 | public void setNetwork(String network) { 104 | this.network = network; 105 | } 106 | 107 | public String getUsername() { 108 | return this.username; 109 | } 110 | 111 | public void setUsername(String username) { 112 | this.username = username; 113 | } 114 | 115 | public Double getLatitude() { 116 | return latitude; 117 | } 118 | 119 | public void setLatitude(Double latitude) { 120 | this.latitude = latitude; 121 | } 122 | 123 | public Double getLongitude() { 124 | return longitude; 125 | } 126 | 127 | public void setLongitude(Double longitude) { 128 | this.longitude = longitude; 129 | } 130 | 131 | public boolean isInternal() { 132 | return internal; 133 | } 134 | 135 | public void setInternal(boolean internal) { 136 | this.internal = internal; 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/jpa/Destination.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.jpa; 14 | 15 | import java.io.Serializable; 16 | 17 | import javax.persistence.Entity; 18 | import javax.persistence.Id; 19 | import javax.persistence.NamedQueries; 20 | import javax.persistence.NamedQuery; 21 | 22 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 23 | import com.fasterxml.jackson.annotation.JsonProperty; 24 | 25 | 26 | /** 27 | * The persistent class for the destination database table. 28 | * 29 | */ 30 | @Entity 31 | @NamedQueries({ 32 | @NamedQuery(name="Destination.findAll", query="SELECT d FROM Destination d"), 33 | @NamedQuery(name="Destination.findAllIds", query="SELECT d.id FROM Destination d"), 34 | }) 35 | @JsonIgnoreProperties(ignoreUnknown=true) 36 | public class Destination implements Serializable, GeographicEndpoint { 37 | private static final long serialVersionUID = 1L; 38 | 39 | @Id 40 | private Long id; 41 | 42 | @JsonProperty("local_destination_ip") 43 | private String ip; 44 | 45 | private String network; 46 | 47 | @JsonProperty("user") 48 | private String username; 49 | 50 | private Double latitude; 51 | 52 | private Double longitude; 53 | 54 | private String country; 55 | 56 | private String city; 57 | 58 | private boolean internal; 59 | 60 | public Destination() { 61 | } 62 | 63 | public Destination(Integer id) { 64 | this.id = Long.valueOf(id); 65 | } 66 | 67 | public String getCountry(){ 68 | return this.country; 69 | } 70 | 71 | public void setCountry(String country){ 72 | this.country = country; 73 | } 74 | 75 | public String getCity(){ 76 | return this.city; 77 | } 78 | 79 | public void setCity(String city){ 80 | this.city = city; 81 | } 82 | 83 | public Long getId() { 84 | return this.id; 85 | } 86 | 87 | public void setId(Long id) { 88 | this.id = id; 89 | } 90 | 91 | public String getIp() { 92 | return this.ip; 93 | } 94 | 95 | public void setIp(String ip) { 96 | this.ip = ip; 97 | } 98 | 99 | public String getNetwork() { 100 | return this.network; 101 | } 102 | 103 | public void setNetwork(String network) { 104 | this.network = network; 105 | } 106 | 107 | public String getUsername() { 108 | return this.username; 109 | } 110 | 111 | public void setUsername(String username) { 112 | this.username = username; 113 | } 114 | 115 | public Double getLatitude() { 116 | return latitude; 117 | } 118 | 119 | public void setLatitude(Double latitude) { 120 | this.latitude = latitude; 121 | } 122 | 123 | public Double getLongitude() { 124 | return longitude; 125 | } 126 | 127 | public void setLongitude(Double longitude) { 128 | this.longitude = longitude; 129 | } 130 | 131 | public boolean isInternal() { 132 | return internal; 133 | } 134 | 135 | public void setInternal(boolean internal) { 136 | this.internal = internal; 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /incident_overview/build.gradle: -------------------------------------------------------------------------------- 1 | import org.gradle.plugins.ide.eclipse.model.Facet 2 | import groovy.xml.MarkupBuilder 3 | 4 | apply plugin: 'java' 5 | apply plugin: 'war' 6 | apply plugin: 'eclipse-wtp' 7 | 8 | jar.archiveName = "incident-overview.jar" 9 | 10 | eclipse{ 11 | wtp { 12 | facet { 13 | facet name: 'jst.java', type: Facet.FacetType.fixed 14 | facet name: 'jst.web', type: Facet.FacetType.fixed 15 | facet name: 'jst.java', version: '1.7' 16 | facet name: 'jst.web', version: '3.0' 17 | facet name: 'wst.jsdt.web', version: '1.0' 18 | facet name: 'jpt.jpa', version: '2.0' 19 | facet name: 'jst.jaxrs', version: '1.1' 20 | 21 | file { 22 | withXml { 23 | def node = it.asNode() 24 | node.appendNode('runtime', [name: 'WebSphere Application Server Liberty Profile']) 25 | } 26 | } 27 | } 28 | 29 | File facetPrefsFile = file('.settings/org.eclipse.wst.common.project.facet.core.prefs.xml') 30 | facetPrefsFile.parentFile.mkdirs() 31 | def writer = new StringWriter() 32 | def xml = new MarkupBuilder(writer) 33 | xml.root() { 34 | facet(id:'jpt.jpa') { 35 | node(name:'libprov') { 36 | attribute(name:'provider-id', value:'jpa-no-op-library-provider') 37 | } 38 | } 39 | facet(id:'jst.jaxrs') { 40 | node(name:'libprov') { 41 | attribute(name:'provider-id', value:'com.ibm.ast.ws.jaxrs.liberty.library') 42 | } 43 | } 44 | } 45 | facetPrefsFile.write(writer.toString()); 46 | 47 | File jptPrefsFile = file('.settings/org.eclipse.jpt.core.prefs') 48 | jptPrefsFile.write('eclipse.preferences.version=1\n') 49 | jptPrefsFile.append('org.eclipse.jpt.core.platform=eclipselink2_0\n') 50 | jptPrefsFile.append('org.eclipse.jpt.jpa.core.discoverAnnotatedClasses=false\n') 51 | } 52 | } 53 | 54 | repositories { 55 | mavenCentral() 56 | } 57 | 58 | dependencies { 59 | providedCompile( 60 | 'javax.servlet:javax.servlet-api:3.1.0', 61 | 'javax.ws.rs:jsr311-api:1.1.1', 62 | 'javax.annotation:jsr250-api:1.0', 63 | 'org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.1' 64 | ) 65 | compile( 66 | 'log4j:log4j:1.2.17', 67 | 'org.slf4j:slf4j-api:1.7.9', 68 | 'org.slf4j:slf4j-log4j12:1.7.9', 69 | 'org.apache.httpcomponents:httpclient:4.3.6', 70 | 'com.fasterxml.jackson.core:jackson-core:2.5.0', 71 | 'com.fasterxml.jackson.core:jackson-annotations:2.5.0', 72 | 'com.fasterxml.jackson.core:jackson-databind:2.5.0', 73 | 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.0', 74 | 'org.apache.commons:commons-lang3:3.0', 75 | 'com.maxmind.geoip2:geoip2:2.1.0' 76 | ) 77 | } 78 | 79 | configurations { 80 | openjpac { 81 | visible false 82 | } 83 | } 84 | 85 | dependencies { 86 | openjpac ( 87 | 'org.apache.openjpa:openjpa-all:2.2.1' 88 | ) 89 | } 90 | 91 | compileJava { 92 | inputs.files "src/main/java/META-INF/persistence.xml" 93 | } 94 | compileJava << { 95 | logger.info 'Enhancing JPA entities ...' 96 | def pFile = file("src/main/resources/META-INF/persistence.xml") 97 | if( pFile.exists() ) { 98 | ant { 99 | taskdef(name:'openjpac', classname:'org.apache.openjpa.ant.PCEnhancerTask', classpath:configurations.openjpac.asPath) 100 | openjpac { 101 | config (propertiesFile: pFile) 102 | classpath { 103 | sourceSets.main.java.srcDirs.findAll{ it.exists() }.each { pathelement(location: it) } 104 | pathelement(location: sourceSets.main.output.classesDir) 105 | pathelement(path: configurations.compile.asPath) 106 | } 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/map/css/throbber.css: -------------------------------------------------------------------------------- 1 | /* 2 | http://css-spinners.com/#/spinners/ 3 | 4 | Copyright (c) 2013 John W. Long and Julia Elman 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | @-webkit-keyframes throbber { 27 | 0% { 28 | background: #dde2e7; 29 | } 30 | 31 | 10% { 32 | background: #6b9dc8; 33 | } 34 | 35 | 40% { 36 | background: #dde2e7; 37 | } 38 | } 39 | 40 | @-moz-keyframes throbber { 41 | 0% { 42 | background: #dde2e7; 43 | } 44 | 45 | 10% { 46 | background: #6b9dc8; 47 | } 48 | 49 | 40% { 50 | background: #dde2e7; 51 | } 52 | } 53 | 54 | @-o-keyframes throbber { 55 | 0% { 56 | background: #dde2e7; 57 | } 58 | 59 | 10% { 60 | background: #6b9dc8; 61 | } 62 | 63 | 40% { 64 | background: #dde2e7; 65 | } 66 | } 67 | 68 | @keyframes throbber { 69 | 0% { 70 | background: #dde2e7; 71 | } 72 | 73 | 10% { 74 | background: #6b9dc8; 75 | } 76 | 77 | 40% { 78 | background: #dde2e7; 79 | } 80 | } 81 | 82 | /* :not(:required) hides these rules from IE9 and below */ 83 | .throbber:not(:required) { 84 | -webkit-animation: throbber 1500ms 300ms infinite ease-out; 85 | -moz-animation: throbber 1500ms 300ms infinite ease-out; 86 | -ms-animation: throbber 1500ms 300ms infinite ease-out; 87 | -o-animation: throbber 1500ms 300ms infinite ease-out; 88 | animation: throbber 1500ms 300ms infinite ease-out; 89 | background: #dde2e7; 90 | display: inline-block; 91 | position: relative; 92 | text-indent: -9999px; 93 | width: 5px; 94 | height: 10px; 95 | margin: 0 5px; 96 | } 97 | .throbber:not(:required):before, .throbber:not(:required):after { 98 | background: #dde2e7; 99 | content: '\x200B'; 100 | display: inline-block; 101 | width: 5px; 102 | height: 10px; 103 | position: absolute; 104 | bottom: 0; 105 | } 106 | .throbber:not(:required):before { 107 | -webkit-animation: throbber 1500ms 150ms infinite ease-out; 108 | -moz-animation: throbber 1500ms 150ms infinite ease-out; 109 | -ms-animation: throbber 1500ms 150ms infinite ease-out; 110 | -o-animation: throbber 1500ms 150ms infinite ease-out; 111 | animation: throbber 1500ms 150ms infinite ease-out; 112 | left: -10px; 113 | } 114 | .throbber:not(:required):after { 115 | -webkit-animation: throbber 1500ms 450ms infinite ease-out; 116 | -moz-animation: throbber 1500ms 450ms infinite ease-out; 117 | -ms-animation: throbber 1500ms 450ms infinite ease-out; 118 | -o-animation: throbber 1500ms 450ms infinite ease-out; 119 | animation: throbber 1500ms 450ms infinite ease-out; 120 | right: -10px; 121 | } -------------------------------------------------------------------------------- /incident_overview/src/main/webapp/map/css/floatingCircles.css: -------------------------------------------------------------------------------- 1 | #floatingCirclesG{ 2 | margin-left: 259px; 3 | position:relative; 4 | width:200px; 5 | height:200px; 6 | -moz-transform:scale(0.6); 7 | -webkit-transform:scale(0.6); 8 | -ms-transform:scale(0.6); 9 | -o-transform:scale(0.6); 10 | transform:scale(0.6); 11 | } 12 | 13 | .f_circleG{ 14 | position:absolute; 15 | background-color:#FFFFFF; 16 | height:36px; 17 | width:36px; 18 | -moz-border-radius:18px; 19 | -moz-animation-name:f_fadeG; 20 | -moz-animation-duration:1.44s; 21 | -moz-animation-iteration-count:infinite; 22 | -moz-animation-direction:normal; 23 | -webkit-border-radius:18px; 24 | -webkit-animation-name:f_fadeG; 25 | -webkit-animation-duration:1.44s; 26 | -webkit-animation-iteration-count:infinite; 27 | -webkit-animation-direction:normal; 28 | -ms-border-radius:18px; 29 | -ms-animation-name:f_fadeG; 30 | -ms-animation-duration:1.44s; 31 | -ms-animation-iteration-count:infinite; 32 | -ms-animation-direction:normal; 33 | -o-border-radius:18px; 34 | -o-animation-name:f_fadeG; 35 | -o-animation-duration:1.44s; 36 | -o-animation-iteration-count:infinite; 37 | -o-animation-direction:normal; 38 | border-radius:18px; 39 | animation-name:f_fadeG; 40 | animation-duration:1.44s; 41 | animation-iteration-count:infinite; 42 | animation-direction:normal; 43 | } 44 | 45 | #frotateG_01{ 46 | left:0; 47 | top:82px; 48 | -moz-animation-delay:0.54s; 49 | -webkit-animation-delay:0.54s; 50 | -ms-animation-delay:0.54s; 51 | -o-animation-delay:0.54s; 52 | animation-delay:0.54s; 53 | } 54 | 55 | #frotateG_02{ 56 | left:24px; 57 | top:24px; 58 | -moz-animation-delay:0.72s; 59 | -webkit-animation-delay:0.72s; 60 | -ms-animation-delay:0.72s; 61 | -o-animation-delay:0.72s; 62 | animation-delay:0.72s; 63 | } 64 | 65 | #frotateG_03{ 66 | left:82px; 67 | top:0; 68 | -moz-animation-delay:0.9s; 69 | -webkit-animation-delay:0.9s; 70 | -ms-animation-delay:0.9s; 71 | -o-animation-delay:0.9s; 72 | animation-delay:0.9s; 73 | } 74 | 75 | #frotateG_04{ 76 | right:24px; 77 | top:24px; 78 | -moz-animation-delay:1.08s; 79 | -webkit-animation-delay:1.08s; 80 | -ms-animation-delay:1.08s; 81 | -o-animation-delay:1.08s; 82 | animation-delay:1.08s; 83 | } 84 | 85 | #frotateG_05{ 86 | right:0; 87 | top:82px; 88 | -moz-animation-delay:1.26s; 89 | -webkit-animation-delay:1.26s; 90 | -ms-animation-delay:1.26s; 91 | -o-animation-delay:1.26s; 92 | animation-delay:1.26s; 93 | } 94 | 95 | #frotateG_06{ 96 | right:24px; 97 | bottom:24px; 98 | -moz-animation-delay:1.44s; 99 | -webkit-animation-delay:1.44s; 100 | -ms-animation-delay:1.44s; 101 | -o-animation-delay:1.44s; 102 | animation-delay:1.44s; 103 | } 104 | 105 | #frotateG_07{ 106 | left:82px; 107 | bottom:0; 108 | -moz-animation-delay:1.62s; 109 | -webkit-animation-delay:1.62s; 110 | -ms-animation-delay:1.62s; 111 | -o-animation-delay:1.62s; 112 | animation-delay:1.62s; 113 | } 114 | 115 | #frotateG_08{ 116 | left:24px; 117 | bottom:24px; 118 | -moz-animation-delay:1.8s; 119 | -webkit-animation-delay:1.8s; 120 | -ms-animation-delay:1.8s; 121 | -o-animation-delay:1.8s; 122 | animation-delay:1.8s; 123 | } 124 | 125 | @-moz-keyframes f_fadeG{ 126 | 0%{ 127 | background-color:#000000} 128 | 129 | 100%{ 130 | background-color:#FFFFFF} 131 | 132 | } 133 | 134 | @-webkit-keyframes f_fadeG{ 135 | 0%{ 136 | background-color:#000000} 137 | 138 | 100%{ 139 | background-color:#FFFFFF} 140 | 141 | } 142 | 143 | @-ms-keyframes f_fadeG{ 144 | 0%{ 145 | background-color:#000000} 146 | 147 | 100%{ 148 | background-color:#FFFFFF} 149 | 150 | } 151 | 152 | @-o-keyframes f_fadeG{ 153 | 0%{ 154 | background-color:#000000} 155 | 156 | 100%{ 157 | background-color:#FFFFFF} 158 | 159 | } 160 | 161 | @keyframes f_fadeG{ 162 | 0%{ 163 | background-color:#000000} 164 | 165 | 100%{ 166 | background-color:#FFFFFF} 167 | 168 | } -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/util/XForceUtil.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.util; 14 | 15 | import java.io.BufferedReader; 16 | import java.io.IOException; 17 | import java.io.InputStreamReader; 18 | import java.net.URI; 19 | import java.net.URISyntaxException; 20 | import java.security.KeyManagementException; 21 | import java.security.KeyStoreException; 22 | import java.security.NoSuchAlgorithmException; 23 | import java.security.cert.CertificateException; 24 | import java.security.cert.X509Certificate; 25 | 26 | import org.apache.http.client.ClientProtocolException; 27 | import org.apache.http.client.methods.CloseableHttpResponse; 28 | import org.apache.http.client.methods.HttpGet; 29 | import org.apache.http.client.utils.URIBuilder; 30 | import org.apache.http.conn.ssl.AllowAllHostnameVerifier; 31 | import org.apache.http.conn.ssl.SSLContextBuilder; 32 | import org.apache.http.conn.ssl.TrustStrategy; 33 | import org.apache.http.impl.client.CloseableHttpClient; 34 | import org.apache.http.impl.client.HttpClients; 35 | 36 | import com.fasterxml.jackson.core.JsonParseException; 37 | import com.fasterxml.jackson.databind.JsonMappingException; 38 | import com.fasterxml.jackson.databind.ObjectMapper; 39 | import com.ibm.si.qradar.offenseviz.conf.QRadarConfig; 40 | 41 | public class XForceUtil { 42 | 43 | private static final String XFORCE_API_AUTH_TOKEN_PATH = "/auth/anonymousToken"; 44 | 45 | public String getXForceAuthToken(String xforceUrl) { 46 | String token = null; 47 | 48 | try { 49 | CloseableHttpClient httpclient = getHttpClient(); 50 | URI uri = getURI(xforceUrl, XFORCE_API_AUTH_TOKEN_PATH); 51 | String json = executeGet(uri, httpclient); 52 | XForceToken xforceToken = getToken(json); 53 | token = xforceToken.getToken(); 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | 58 | return token; 59 | } 60 | 61 | private CloseableHttpClient getHttpClient() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { 62 | CloseableHttpClient httpclient = HttpClients.custom(). 63 | setHostnameVerifier(new AllowAllHostnameVerifier()). 64 | setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() 65 | { 66 | public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException 67 | { 68 | return true; 69 | } 70 | }).build()).build(); 71 | 72 | return httpclient; 73 | } 74 | 75 | private URI getURI(String url, String path) throws URISyntaxException { 76 | URI uri = new URIBuilder().setScheme("https") 77 | .setHost(url) 78 | .setPath(path) 79 | .build(); 80 | 81 | return uri; 82 | } 83 | 84 | private String executeGet(URI uri, CloseableHttpClient httpclient) throws ClientProtocolException, IOException { 85 | HttpGet httpget = new HttpGet(uri); 86 | CloseableHttpResponse response = httpclient.execute(httpget); 87 | BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8")); 88 | String json = reader.readLine(); 89 | response.close(); 90 | return json; 91 | } 92 | 93 | private XForceToken getToken(String json) throws JsonParseException, JsonMappingException, IOException { 94 | ObjectMapper mapper = new ObjectMapper(); 95 | XForceToken token = mapper.readValue(json, XForceToken.class); 96 | return token; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/api/OffenseResource.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.api; 14 | 15 | import java.sql.Timestamp; 16 | import java.text.SimpleDateFormat; 17 | import java.util.ArrayList; 18 | import java.util.Calendar; 19 | import java.util.Date; 20 | import java.util.List; 21 | import java.util.Random; 22 | 23 | import javax.annotation.Resource; 24 | import javax.persistence.EntityManager; 25 | import javax.servlet.ServletContext; 26 | import javax.ws.rs.GET; 27 | import javax.ws.rs.Path; 28 | import javax.ws.rs.Produces; 29 | import javax.ws.rs.QueryParam; 30 | import javax.ws.rs.core.GenericEntity; 31 | import javax.ws.rs.core.MediaType; 32 | import javax.ws.rs.core.Response; 33 | 34 | import org.slf4j.Logger; 35 | import org.slf4j.LoggerFactory; 36 | 37 | import com.google.api.client.util.Lists; 38 | import com.ibm.si.qradar.offenseviz.conf.QRadarConfig; 39 | import com.ibm.si.qradar.offenseviz.dao.OffenseDao; 40 | import com.ibm.si.qradar.offenseviz.jpa.Offense; 41 | import com.ibm.si.qradar.offenseviz.model.OffenseBucket; 42 | import com.ibm.si.qradar.offenseviz.util.PersistenceUtil; 43 | 44 | @Path("/offenses") 45 | public class OffenseResource { 46 | 47 | @Resource ServletContext servletContext; 48 | private static final Logger logger = LoggerFactory.getLogger(OffenseResource.class); 49 | private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 50 | 51 | @GET 52 | @Produces( MediaType.APPLICATION_JSON ) 53 | public Response getOffenses(@QueryParam("buckets") Integer bucketCount) { 54 | List buckets = buildOffenseBuckets(bucketCount); 55 | 56 | GenericEntity> entity = new GenericEntity>( 57 | Lists.newArrayList(buckets)) { 58 | }; 59 | 60 | Response response = Response.ok().entity(entity).build(); 61 | 62 | return response; 63 | } 64 | 65 | private List buildOffenseBuckets(int bucketCount) { 66 | EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager(); 67 | OffenseDao offenseDao = new OffenseDao(em); 68 | 69 | Long mostRecentBucketMillis = getLastBucketTime(); 70 | Timestamp mostRecentTimestamp = new Timestamp(mostRecentBucketMillis); 71 | Timestamp oldestLastSeenTimestamp = calculateAge(bucketCount, mostRecentBucketMillis); 72 | 73 | List offensesInTimeRange = offenseDao.findByTimestamp(oldestLastSeenTimestamp, mostRecentTimestamp); 74 | em.close(); 75 | 76 | Date now = new Date(mostRecentTimestamp.getTime()); 77 | Date then = new Date(oldestLastSeenTimestamp.getTime()); 78 | 79 | logger.debug(String.format("We found %s offenses in between %s and %s", 80 | offensesInTimeRange.size(), 81 | dateFormat.format(then), 82 | dateFormat.format(now))); 83 | 84 | List buckets = new ArrayList(); 85 | for(int i = 0; i < bucketCount; i++) { 86 | Timestamp bucketTime = calculateAge(i, mostRecentTimestamp.getTime()); 87 | OffenseBucket bucket = new OffenseBucket(bucketTime, offensesInTimeRange); 88 | buckets.add(bucket); 89 | } 90 | 91 | return buckets; 92 | } 93 | 94 | private Long getLastBucketTime() { 95 | Long startupTime = QRadarConfig.getInstance().getStartupTime(); 96 | Long interval = Long.valueOf(QRadarConfig.getInstance().getUpdateInterval() * 1000); 97 | Long now = Calendar.getInstance().getTimeInMillis(); 98 | Long delta = now - startupTime; 99 | Long modulo = delta % interval; 100 | Long maxBucketTime = now - modulo; 101 | 102 | return maxBucketTime; 103 | } 104 | 105 | private Timestamp calculateAge(int bucketCount, long nowMillis) { 106 | int interval = QRadarConfig.getInstance().getUpdateInterval(); 107 | int seconds = interval * bucketCount; 108 | 109 | Timestamp original = new Timestamp(nowMillis); 110 | Calendar cal = Calendar.getInstance(); 111 | cal.setTimeInMillis(original.getTime()); 112 | cal.add(Calendar.SECOND, -seconds); 113 | Timestamp maxAge = new Timestamp(cal.getTimeInMillis()); 114 | 115 | return maxAge; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /incident_overview/src/main/java/com/ibm/si/qradar/offenseviz/conf/QRadarConfig.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | Copyright (c) 2015, IBM 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | *********************************************************/ 12 | 13 | package com.ibm.si.qradar.offenseviz.conf; 14 | 15 | import java.io.IOException; 16 | import java.util.Calendar; 17 | import java.util.Properties; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import com.ibm.si.qradar.offenseviz.util.PropertiesReader; 23 | import com.ibm.si.qradar.offenseviz.util.XForceToken; 24 | import com.ibm.si.qradar.offenseviz.util.XForceUtil; 25 | 26 | public class QRadarConfig { 27 | 28 | private static final Logger logger = LoggerFactory.getLogger(QRadarConfig.class); 29 | private static QRadarConfig instance = new QRadarConfig(); 30 | private static final String QRADAR_CONFIG_FILENAME = "qradar.properties"; 31 | private static final int DEFAULT_CLEANUP_INTERVAL = 60; 32 | 33 | private String authorizationToken; 34 | private String url; 35 | private String updateInterval; 36 | private Double defaultLongitude; 37 | private Double defaultLatitude; 38 | private String defaultCountry; 39 | private String defaultCity; 40 | private String xforceApiUrl; 41 | private String xforceWebUrl; 42 | private String xforceAuthToken; 43 | private Long startupTime; 44 | private String qradarTimeZone; 45 | private String cleanupIntervalMinutes; 46 | 47 | public String getQradarTimeZone() { 48 | return qradarTimeZone; 49 | } 50 | 51 | public void setQradarTimeZone(String qradarTimeZone) { 52 | this.qradarTimeZone = qradarTimeZone; 53 | } 54 | 55 | public static QRadarConfig getInstance() { 56 | return instance; 57 | } 58 | 59 | private QRadarConfig() { 60 | refreshConfig(); 61 | } 62 | 63 | public void refreshConfig() { 64 | Properties qradarProperties = new Properties(); 65 | PropertiesReader propReader = new PropertiesReader(); 66 | try { 67 | qradarProperties = propReader.getProperties(QRADAR_CONFIG_FILENAME); 68 | authorizationToken = qradarProperties.getProperty("auth_token"); 69 | url = qradarProperties.getProperty("url"); 70 | updateInterval = qradarProperties.getProperty("update_interval_seconds"); 71 | defaultLatitude = Double.valueOf(qradarProperties.getProperty("default_latitude")); 72 | defaultLongitude = Double.valueOf(qradarProperties.getProperty("default_longitude")); 73 | xforceApiUrl = qradarProperties.getProperty("xforce_api_url"); 74 | xforceWebUrl = qradarProperties.getProperty("xforce_web_url"); 75 | defaultCountry = qradarProperties.getProperty("default_country"); 76 | defaultCity = qradarProperties.getProperty("default_city"); 77 | cleanupIntervalMinutes = qradarProperties.getProperty("cleanup_old_offense_interval"); 78 | 79 | XForceUtil xforceTokenUtil = new XForceUtil(); 80 | xforceAuthToken = xforceTokenUtil.getXForceAuthToken(xforceApiUrl); 81 | 82 | Calendar calendar = Calendar.getInstance(); 83 | startupTime = calendar.getTimeInMillis(); 84 | qradarTimeZone = qradarProperties.getProperty("qradar_timeZone"); 85 | 86 | } catch (IOException e) { 87 | logger.error("There was a problem loading email configuration file.", e); 88 | } 89 | } 90 | 91 | public String getAuthorizationToken() { 92 | return authorizationToken; 93 | } 94 | 95 | public String getUrl() { 96 | return url; 97 | } 98 | 99 | public int getUpdateInterval() { 100 | return Integer.parseInt(updateInterval); 101 | } 102 | 103 | public Double getDefaultLongitude() { 104 | return defaultLongitude; 105 | } 106 | 107 | public void setDefaultLongitude(Double defaultLongitude) { 108 | this.defaultLongitude = defaultLongitude; 109 | } 110 | 111 | public Double getDefaultLatitude() { 112 | return defaultLatitude; 113 | } 114 | 115 | public void setDefaultLatitude(Double defaultLatitude) { 116 | this.defaultLatitude = defaultLatitude; 117 | } 118 | 119 | public String getXforceApiUrl() { 120 | return xforceApiUrl; 121 | } 122 | 123 | public void setXforceApiUrl(String xforceApiUrl) { 124 | this.xforceApiUrl = xforceApiUrl; 125 | } 126 | 127 | public String getXforceWebUrl() { 128 | return xforceWebUrl; 129 | } 130 | 131 | public void setXforceWebUrl(String xforceWebUrl) { 132 | this.xforceWebUrl = xforceWebUrl; 133 | } 134 | 135 | public String getXforceAuthToken() { 136 | return xforceAuthToken; 137 | } 138 | 139 | public void setXforceAuthToken(String xforceAuthToken) { 140 | this.xforceAuthToken = xforceAuthToken; 141 | } 142 | 143 | public String getDefaultCountry() { 144 | return defaultCountry; 145 | } 146 | 147 | public void setDefaultCountry(String defaultCountry) { 148 | this.defaultCountry = defaultCountry; 149 | } 150 | 151 | public String getDefaultCity() { 152 | return defaultCity; 153 | } 154 | 155 | public void setDefaultCity(String defaultCity) { 156 | this.defaultCity = defaultCity; 157 | } 158 | 159 | public Long getStartupTime() { 160 | return startupTime; 161 | } 162 | 163 | public int getCleanupIntervalMinutes() { 164 | int minutes; 165 | try { 166 | minutes = Integer.parseInt(this.cleanupIntervalMinutes); 167 | } catch (NumberFormatException e) { 168 | minutes = DEFAULT_CLEANUP_INTERVAL; 169 | } 170 | return minutes; 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /offense_visualizer/visualizer.html: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 149 | 193 | 194 | 195 | 196 | Offense Visualizer - Last 24 Hours 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | Graph Options 208 | X Axis 209 | 210 | Start Time 211 | Last Updated Time 212 | Log Count 213 | Flow Count 214 | Source Count 215 | Destination Count 216 | Username Count 217 | Category Count 218 | Magnitude 219 | Credibility 220 | Severity 221 | Relevance 222 | 223 | Y Axis 224 | 225 | Start Time 226 | Last Updated Time 227 | Log Count 228 | Flow Count 229 | Source Count 230 | Destination Count 231 | Username Count 232 | Category Count 233 | Magnitude 234 | Credibility 235 | Severity 236 | Relevance 237 | 238 | Size 239 | 240 | Magnitude 241 | Credibility 242 | Severity 243 | Relevance 244 | 245 | Colorization 246 | 247 | Offense Type 248 | Offense Category 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 |