diff --git a/api/pacman-api-asset/src/main/java/com/tmobile/pacman/api/asset/repository/SearchRepositoryImpl.java b/api/pacman-api-asset/src/main/java/com/tmobile/pacman/api/asset/repository/SearchRepositoryImpl.java index f4ecc8514..33a7feb8b 100644 --- a/api/pacman-api-asset/src/main/java/com/tmobile/pacman/api/asset/repository/SearchRepositoryImpl.java +++ b/api/pacman-api-asset/src/main/java/com/tmobile/pacman/api/asset/repository/SearchRepositoryImpl.java @@ -1,685 +1,685 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.asset.repository; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import joptsimple.internal.Strings; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.entity.ContentType; -import org.apache.http.nio.entity.NStringEntity; -import org.apache.http.util.EntityUtils; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Repository; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.tmobile.pacman.api.asset.AssetConstants; -import com.tmobile.pacman.api.asset.domain.SearchResult; -import com.tmobile.pacman.api.asset.service.AssetService; -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; -import com.tmobile.pacman.api.commons.repo.PacmanRdsRepository; -import com.tmobile.pacman.api.commons.utils.PacHttpUtils; - -/** - * Implemented class for SearchRepository and all its method - */ -@Repository -public class SearchRepositoryImpl implements SearchRepository { - - private static final Logger LOGGER = LoggerFactory.getLogger(SearchRepositoryImpl.class); - private static final String PROTOCOL = "http://"; - @Autowired - private PacmanRdsRepository rdsRepository; - - @Value("${elastic-search.host}") - private String esHost; - @Value("${elastic-search.port}") - private int esPort; - @Value("${vulnerability.types}") - private String configuredVulnTargetTypes; - - @Autowired - ElasticSearchRepository esRepository; - - @Autowired - AssetService assetService; - - private static RestClient restClient; - - private static Map> categoryToRefineByMap = new HashMap<>(); - private static Map> categoryToReturnFieldsMap = new HashMap<>(); - - private synchronized void fetchConfigFromDB() { - - if (categoryToRefineByMap.size() > 0 || categoryToReturnFieldsMap.size() > 0) { - return; - } - - String query = "select SEARCH_CATEGORY,RESOURCE_TYPE,REFINE_BY_FIELDS,RETURN_FIELDS FROM OmniSearch_Config"; - List> resultsList = rdsRepository.getDataFromPacman(query); - - Iterator> rowIterator = resultsList.iterator(); - - while (rowIterator.hasNext()) { - Map currentRowMap = rowIterator.next(); - String searchCategory = currentRowMap.get("SEARCH_CATEGORY") != null - ? currentRowMap.get("SEARCH_CATEGORY").toString().trim() : ""; - String resourceType = currentRowMap.get("RESOURCE_TYPE") != null - ? currentRowMap.get("RESOURCE_TYPE").toString().trim() : ""; - String refineByFields = currentRowMap.get("REFINE_BY_FIELDS") != null - ? currentRowMap.get("REFINE_BY_FIELDS").toString().trim() : ""; - String returnFields = currentRowMap.get("RETURN_FIELDS") != null - ? currentRowMap.get("RETURN_FIELDS").toString().trim() : ""; - - Map resourceTypeToRefineByMap = categoryToRefineByMap.get(searchCategory); - if (null == resourceTypeToRefineByMap) { - resourceTypeToRefineByMap = new HashMap<>(); - } - resourceTypeToRefineByMap.put(resourceType, refineByFields); - - Map resourceTypeToReturnFieldMap = categoryToReturnFieldsMap.get(searchCategory); - if (null == resourceTypeToReturnFieldMap) { - resourceTypeToReturnFieldMap = new HashMap<>(); - } - resourceTypeToReturnFieldMap.put(resourceType, returnFields); - - categoryToRefineByMap.put(searchCategory, resourceTypeToRefineByMap); - categoryToReturnFieldsMap.put(searchCategory, resourceTypeToReturnFieldMap); - - } - } - - @Override - public SearchResult fetchSearchResultsAndSetTotal(String ag, String domain, boolean includeAllAssets, - String targetType, String searchText, Map> lowLevelFilters, int from, int size, - SearchResult result, String searchCategory) throws DataException { - - if (categoryToRefineByMap.size() == 0 || categoryToReturnFieldsMap.size() == 0) { - - fetchConfigFromDB(); - - } - - Map mustFilter = new LinkedHashMap<>(); - Map mustTermsFilter = new LinkedHashMap<>(); - - lowLevelFilters.forEach((displayName, valueList) -> { - String esFieldName = getFieldMappingsForSearch(targetType, false, searchCategory).get(displayName) - + ".keyword"; - mustTermsFilter.put(esFieldName, valueList); - }); - - String esType = null; - - if (AssetConstants.ASSETS.equals(searchCategory)) { - if (!includeAllAssets) { - mustFilter.put(Constants.LATEST, Constants.TRUE); - } - mustFilter.put(AssetConstants.UNDERSCORE_ENTITY, Constants.TRUE); - if (null == targetType) { - mustTermsFilter.put(AssetConstants.UNDERSCORE_ENTITY_TYPE_KEYWORD, getTypesForDomain(ag, domain)); - } - esType = targetType; - } - - if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { - mustFilter.put("type.keyword", "issue"); - mustTermsFilter.put("issueStatus.keyword", Arrays.asList("open", "exempted")); - if (null == targetType) { - esType = null; - mustTermsFilter.put("targetType.keyword", getTypesForDomain(ag, domain)); - - } else { - esType = "issue_" + targetType; - } - - } - - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - mustFilter.put(Constants.LATEST, Constants.TRUE); - mustTermsFilter.put(Constants.SEVEITY_LEVEL, - Arrays.asList(Constants.THREE, Constants.FOUR, Constants.FIVE)); - - if (null != targetType) { - mustFilter.put("_index", "aws_" + targetType); - } - esType = Constants.VULN_INFO; - } - long start = System.currentTimeMillis(); - - if (!Strings.isNullOrEmpty(searchText)) { - searchText = "\"" + searchText + "\""; - } - List> results = new ArrayList<>(); - if (!AssetConstants.VULNERABILITIES.equals(searchCategory)) { - - List> sortFieldsMapList = new ArrayList<>(); - Map resourceIdSort = new HashMap<>(); - resourceIdSort.put("_resourceid.keyword", "asc"); - sortFieldsMapList.add(resourceIdSort); - - StringBuilder urlToQuery = new StringBuilder(PROTOCOL + esHost + ":" + esPort + "/" + ag); - if (!Strings.isNullOrEmpty(esType)) { - urlToQuery.append("/").append(esType); - } - urlToQuery.append("/").append("_search?from=").append(from).append("&size=").append(size); - - Map query = new HashMap<>(); - query.put("query", esRepository.buildQuery(mustFilter, null, null, searchText, mustTermsFilter, null)); - query.put("_source", getReturnFieldsForSearch(targetType, searchCategory)); - query.put("sort", resourceIdSort); - - String resultJson = invokeESCall("GET", urlToQuery.toString(), new Gson().toJson(query)); - - Gson serializer = new GsonBuilder().create(); - Map response = (Map) serializer.fromJson(resultJson, Object.class); - if (response.containsKey("hits")) { - Map hits = (Map) response.get("hits"); - long total = Double.valueOf(hits.get("total").toString()).longValue(); - result.setTotal(total); - } - esRepository.processResponseAndSendTheScrollBack(resultJson, results); - - } else { - List returnFields = getReturnFieldsForSearch(targetType, searchCategory); - String docQueryString = ""; - docQueryString = new StringBuilder(docQueryString).append("[").toString(); - int count = 0; - for (String returnField : returnFields) { - if (count == 0) { - docQueryString = new StringBuilder(docQueryString).append("doc['").append(returnField) - .append("'].value").toString(); - } else { - docQueryString = new StringBuilder(docQueryString).append("doc['").append(returnField) - .append(".keyword'].value").toString(); - - } - count++; - - if (count < returnFields.size()) { - docQueryString = new StringBuilder(docQueryString).append(" +'~'+").toString(); - } - - } - docQueryString = docQueryString + "]"; - - String url = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.VULN_INFO + "/" - + Constants.SEARCH; - Map query = new HashMap<>(); - query.put("query", esRepository.buildQuery(mustFilter, null, null, searchText, mustTermsFilter, null)); - - String queryString = new Gson().toJson(query); - String payload = queryString.substring(0, queryString.length() - 1) - + ", \"aggs\": {\"qids\": {\"terms\": {\"script\": \"" + docQueryString + "\",\"size\": 10000}}}}"; - String responseJson = ""; - try { - long startAggs = System.currentTimeMillis(); - LOGGER.debug("To get vuln aggs without dups, url is: {} and payload is: {}", url, payload); - responseJson = PacHttpUtils.doHttpPost(url, payload); - LOGGER.debug(AssetConstants.DEBUG_RESPONSEJSON, responseJson); - long endAggs = System.currentTimeMillis(); - LOGGER.debug("Time taken for ES call(vuln aggs sans dups) is: {}", (endAggs - startAggs)); - results = getDistFromVulnAggsResult(responseJson, returnFields); - } catch (Exception e) { - LOGGER.error("Failed to retrieve vuln aggs for omni search ", e); - } - - } - - results = pruneResults(results, targetType, searchCategory); - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - result.setTotal(results.size()); - - int end = from + size; - if (end > (results.size())) { - from = 0; - end = results.size(); - } - results = results.subList(from, end); - } - - result.setResults(results); - long end = System.currentTimeMillis(); - LOGGER.debug("Time taken to perform search for Search Category {} is: {}", searchCategory, (end - start)); - - return result; - - } - - @Override - public List> fetchTargetTypes(String ag, String searchText, String searchCategory, - String domain, boolean includeAllAssets) throws DataException { - - if (categoryToRefineByMap.size() == 0 || categoryToReturnFieldsMap.size() == 0) { - - fetchConfigFromDB(); - - } - - List> resourceTypeBucketList = new ArrayList<>(); - - String aggStringForHighLevelEntities = ""; - if (AssetConstants.ASSETS.equals(searchCategory)) { - aggStringForHighLevelEntities = "\"targetTypes\":{\"terms\":{\"field\":\"_entitytype.keyword\",\"size\":10000}}"; - } - - if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { - aggStringForHighLevelEntities = "\"targetTypes\":{\"terms\":{\"field\":\"targetType.keyword\",\"size\":10000}}"; - } - - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - aggStringForHighLevelEntities = "\"targetTypes\":{\"terms\":{\"field\":\"_index\",\"size\":10000},\"aggs\":{\"unique\":{\"cardinality\":{\"field\":\"" - + getReturnFieldsForSearch(null, searchCategory).get(0) + "\"}}}}"; - } - - String payLoadStr = createPayLoad(aggStringForHighLevelEntities, searchText, searchCategory, null, - includeAllAssets); - - String firstUrl = ""; - - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - firstUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.VULN_INFO + "/" + Constants.SEARCH; - } else { - firstUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.SEARCH; - } - String responseJson = ""; - - try { - long start = System.currentTimeMillis(); - LOGGER.debug("To get targetTypes:URL is: {} and payload is : {}", firstUrl, payLoadStr); - responseJson = PacHttpUtils.doHttpPost(firstUrl, payLoadStr); - LOGGER.debug(AssetConstants.DEBUG_RESPONSEJSON, responseJson); - long end = System.currentTimeMillis(); - LOGGER.debug("Time taken for ES call(targetType) for Search Category {} is: {}", searchCategory, - (end - start)); - - } catch (Exception e) { - LOGGER.error("Failed to retrieve high level entity types for omni search ", e); - return resourceTypeBucketList; - } - - resourceTypeBucketList = getDistributionFromAggResult(responseJson, "targetTypes"); - - // Atleast one refinement should be defined for the entity. If not, kick - // it out - removeResourceTypeIfNoMappingDefined(resourceTypeBucketList, searchCategory); - - removeResourceTypeIfNotAttachedToDomain(ag, resourceTypeBucketList, domain); - - return resourceTypeBucketList; - } - - private List getTypesForDomain(String ag, String domain) { - List> domainData = assetService.getTargetTypesForAssetGroup(ag, domain); - List typesForDomain = new ArrayList<>(); - domainData.forEach(domainMap -> { - domainMap.forEach((key, value) -> { - if (key.equals("type")) { - typesForDomain.add(value.toString()); - } - }); - }); - return typesForDomain; - } - - private synchronized void removeResourceTypeIfNotAttachedToDomain(String ag, - List> resourceTypeBucketList, String domain) { - - List typesForDomain = getTypesForDomain(ag, domain); - - Iterator> resourceIterator = resourceTypeBucketList.iterator(); - while (resourceIterator.hasNext()) { - String resourceType = resourceIterator.next().get(AssetConstants.FIELDNAME).toString(); - if (!typesForDomain.contains(resourceType)) { - resourceIterator.remove(); - } - } - } - - private synchronized void removeResourceTypeIfNoMappingDefined(List> resourceTypeBucketList, - String searchCategory) { - Iterator> resourceIterator = resourceTypeBucketList.iterator(); - while (resourceIterator.hasNext()) { - String resourceType = resourceIterator.next().get(AssetConstants.FIELDNAME).toString(); - Map fieldMapping = getFieldMappingsForSearch(resourceType, false, searchCategory); - if (fieldMapping.isEmpty()) { - resourceIterator.remove(); - } - } - } - - @Override - public Map>> fetchDistributionForTargetType(String ag, String resourceType, - String searchText, String searchCategory, boolean includeAllAssets) { - - Map>> returnBucketMap = new LinkedHashMap<>(); - - // Prepare aggregation string based on what resourceType we are - // dealing with - StringBuilder aggregationStrBuffer = new StringBuilder(); - Map fieldMapping = getFieldMappingsForSearch(resourceType, false, searchCategory); - if (fieldMapping.isEmpty()) { - return returnBucketMap; - } - - fieldMapping.forEach((displayName, esFieldName) -> { - aggregationStrBuffer.append( - "\"" + displayName + "\":{\"terms\":{\"field\":\"" + esFieldName + ".keyword\",\"size\":10000}"); - - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - - aggregationStrBuffer.append(",\"aggs\":{\"unique\":{\"cardinality\":{\"field\":\"" - + getReturnFieldsForSearch(resourceType, searchCategory).get(0) + "\"}}}"); - } - aggregationStrBuffer.append("}"); - - // Trailing comma - aggregationStrBuffer.append(","); - }); - - // Remove the trailing comma, because of the iteration above - String aggStringForLowLevelMenu = aggregationStrBuffer.toString().substring(0, - aggregationStrBuffer.toString().length() - 1); - - String lowLevelPayLoadStr = createPayLoad(aggStringForLowLevelMenu, searchText, searchCategory, resourceType, - includeAllAssets); - - String secondUrl = null; - if (AssetConstants.ASSETS.equals(searchCategory)) { - secondUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + resourceType + "/" + Constants.SEARCH; - } - if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { - secondUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + "issue_" + resourceType + "/" - + Constants.SEARCH; - } - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - secondUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.VULN_INFO + "/" - + Constants.SEARCH; - } - - try { - LOGGER.debug("To get distribution, the URL is: {} and the payload is: {}", secondUrl, lowLevelPayLoadStr); - long start = System.currentTimeMillis(); - final String lowLevelResponseJson = invokeESCall("GET", secondUrl, lowLevelPayLoadStr); - LOGGER.debug(AssetConstants.DEBUG_RESPONSEJSON, lowLevelResponseJson); - long end = System.currentTimeMillis(); - LOGGER.debug("Search Category {}", searchCategory); - LOGGER.debug("Target type {}", resourceType); - LOGGER.debug("Time taken for ES call(refineBy) is: {}", (end - start)); - - fieldMapping.forEach((displayName, esFieldName) -> { - List> detailsBucketList = getDistributionFromAggResult(lowLevelResponseJson, - displayName); - if (!detailsBucketList.isEmpty()) { - returnBucketMap.put(displayName, detailsBucketList); - } - - }); - } catch (Exception e) { - LOGGER.error("Error fetching distributions from ES:", e); - } - - return returnBucketMap; - } - - private List> getDistributionFromAggResult(String responseJson, String aggName) { - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = jsonParser.parse(responseJson).getAsJsonObject(); - JsonArray types = resultJson.get("aggregations").getAsJsonObject().get(aggName).getAsJsonObject().get("buckets") - .getAsJsonArray(); - List> bucketList = new ArrayList<>(); - for (JsonElement type : types) { - JsonObject typeObj = type.getAsJsonObject(); - String fieldName = typeObj.get("key").getAsString(); - - // To handle vulnerabilities type - if (fieldName.startsWith("aws_")) { - fieldName = fieldName.substring(4); - } - - long count = typeObj.get("doc_count").getAsLong(); - JsonElement uniqueNumberElement = typeObj.get("unique"); - if (null != uniqueNumberElement) { - count = uniqueNumberElement.getAsJsonObject().get("value").getAsLong(); - } - Map typeMap = new HashMap<>(); - typeMap.put(AssetConstants.FIELDNAME, fieldName); - typeMap.put("count", count); - bucketList.add(typeMap); - } - - return bucketList; - } - - private List> getDistFromVulnAggsResult(String responseJson, List returnFields) { - - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = jsonParser.parse(responseJson).getAsJsonObject(); - JsonArray types = resultJson.get("aggregations").getAsJsonObject().get("qids").getAsJsonObject().get("buckets") - .getAsJsonArray(); - List> bucketList = new ArrayList<>(); - for (JsonElement type : types) { - int count = 0; - Map map = new HashMap<>(); - JsonObject typeObj = type.getAsJsonObject(); - String key = typeObj.get("key").getAsString(); - StringTokenizer vulnkeyTokenizer = new StringTokenizer(key, "~"); - while (vulnkeyTokenizer.hasMoreTokens()) { - String token = vulnkeyTokenizer.nextToken(); - map.put(returnFields.get(count), token); - count++; - } - bucketList.add(map); - } - - return bucketList; - } - - private String createPayLoad(String aggString, String searchText, String searchCategory, String resourceType, - boolean includeAllAssets) { - StringBuilder payLoad = new StringBuilder(); - String matchString = ""; - if (AssetConstants.ASSETS.equals(searchCategory)) { - matchString = "{\"match\":{\"_entity\":\"true\"}}"; - } - if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { - matchString = "{\"match\":{\"type.keyword\":\"issue\"}},{\"terms\":{\"issueStatus.keyword\":[ \"open\",\"exempted\"]}}"; - } - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - matchString = "{\"terms\":{\"severitylevel\":[3,4,5]}}"; - if (resourceType != null) { - matchString = matchString + ",{\"match\":{\"_index\":\"aws_" + resourceType + "\"}}"; - } - } - - payLoad.append("{\"size\":0,\"query\":{\"bool\":{\"must\":["); - payLoad.append(matchString); - if (AssetConstants.ASSETS.equals(searchCategory) && !includeAllAssets) { - payLoad.append(",{\"match\":{\"latest\":\"true\"}}"); - } - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - payLoad.append(",{\"match\":{\"latest\":\"true\"}}"); - } - - payLoad.append(",{\"match_phrase_prefix\":{\"_all\":\""); - payLoad.append(searchText); - payLoad.append("\"}}]}}"); - payLoad.append(",\"aggs\":{"); - payLoad.append(aggString); - payLoad.append("}}"); - return payLoad.toString(); - } - - @Override - public Map getFieldMappingsForSearch(String incomingResourceType, boolean flipOrder, - String searchCategory) { - - Map mappingList = new LinkedHashMap<>(); - - String commaSepString = categoryToRefineByMap.get(searchCategory).get(incomingResourceType); - - String commaSepStringForAll = categoryToRefineByMap.get(searchCategory).get("All"); - - String jointStr = commaSepStringForAll + (commaSepString != null ? (",".concat(commaSepString)) : ""); - - String displayName = null; - String esFieldName = null; - - StringTokenizer commaTokens = new StringTokenizer(jointStr, ","); - while (commaTokens.hasMoreTokens()) { - String pipeSeparatedStr = commaTokens.nextToken(); - if (pipeSeparatedStr.contains("|")) { - int posOfPipe = pipeSeparatedStr.indexOf('|'); - esFieldName = pipeSeparatedStr.substring(0, posOfPipe); - displayName = pipeSeparatedStr.substring(posOfPipe, pipeSeparatedStr.length()); - } else { - // Assume display name is same as field name - esFieldName = pipeSeparatedStr; - displayName = pipeSeparatedStr; - } - if (flipOrder) { - mappingList.put(esFieldName, displayName); - } else { - mappingList.put(displayName, esFieldName); - } - } - return mappingList; - } - - @Override - public List getReturnFieldsForSearch(String incomingResourceType, String searchCategory) { - - List returnFieldList = new ArrayList<>(); - - String commaSepString = categoryToReturnFieldsMap.get(searchCategory).get(incomingResourceType); - String commaSepStringForAll = categoryToReturnFieldsMap.get(searchCategory).get("All"); - - String jointStr = commaSepStringForAll + (commaSepString != null ? (",".concat(commaSepString)) : ""); - StringTokenizer commaTokens = new StringTokenizer(jointStr, ","); - - while (commaTokens.hasMoreTokens()) { - returnFieldList.add(commaTokens.nextToken()); - } - - return returnFieldList; - } - - private List> pruneResults(List> results, String targetType, - String searchCategory) { - List returnFields = getReturnFieldsForSearch(targetType, searchCategory); - List> resultsAfterPruning = new ArrayList<>(); - results.forEach(result -> { - Map outgoingMap = new LinkedHashMap<>(); - result.forEach((key, value) -> { - if (returnFields.contains(key) || key.startsWith("tags.")) { - // The first item in the return fields from RDS is to be - // considered as the id - // field - if (key.equals(returnFields.get(0))) { - key = Constants._ID; - } - outgoingMap.put(key, value); - } - }); - - outgoingMap.put("searchCategory", searchCategory); - boolean removeDups = false; - if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { - removeDups = true; - } - if (!removeDups || (removeDups - && !doesResultAlreadyContainId(resultsAfterPruning, outgoingMap.get(Constants._ID)))) { - resultsAfterPruning.add(outgoingMap); - } - }); - return resultsAfterPruning; - } - - private boolean doesResultAlreadyContainId(List> resultsAfterPruning, - Object idValueToBeChecked) { - List matchedObjects = new ArrayList<>(); - resultsAfterPruning.forEach(result -> { - result.forEach((key, value) -> { - if (key.equals(Constants._ID)) { - double lhsLongValue = Double.parseDouble(value.toString()); - double rhsLongValue = Double.parseDouble(idValueToBeChecked.toString()); - if (lhsLongValue == rhsLongValue) { - - LOGGER.debug("Duplicate vuln id found(Won't be adding this..): {}", idValueToBeChecked); - matchedObjects.add(idValueToBeChecked); - } - - } - }); - }); - return !matchedObjects.isEmpty(); - } - - private RestClient getRestClient() { - if (restClient == null) { - - RestClientBuilder builder = RestClient.builder(new HttpHost(esHost, esPort)); - builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { - @Override - public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { - return requestConfigBuilder.setConnectionRequestTimeout(0); - } - }); - restClient = builder.build(); - } - return restClient; - - } - - private String invokeESCall(String method, String endpoint, String payLoad) { - HttpEntity entity = null; - try { - if (payLoad != null) { - entity = new NStringEntity(payLoad, ContentType.APPLICATION_JSON); - } - return EntityUtils.toString(getRestClient() - .performRequest(method, endpoint, Collections.emptyMap(), entity).getEntity()); - } catch (IOException e) { - LOGGER.error("Error in invokeESCall ", e); - } - return null; - } - -} +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.asset.repository; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import joptsimple.internal.Strings; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.entity.ContentType; +import org.apache.http.nio.entity.NStringEntity; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Repository; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.tmobile.pacman.api.asset.AssetConstants; +import com.tmobile.pacman.api.asset.domain.SearchResult; +import com.tmobile.pacman.api.asset.service.AssetService; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; +import com.tmobile.pacman.api.commons.repo.PacmanRdsRepository; +import com.tmobile.pacman.api.commons.utils.PacHttpUtils; + +/** + * Implemented class for SearchRepository and all its method + */ +@Repository +public class SearchRepositoryImpl implements SearchRepository { + + private static final Logger LOGGER = LoggerFactory.getLogger(SearchRepositoryImpl.class); + private static final String PROTOCOL = "http://"; + @Autowired + private PacmanRdsRepository rdsRepository; + + @Value("${elastic-search.host}") + private String esHost; + @Value("${elastic-search.port}") + private int esPort; + @Value("${vulnerability.types}") + private String configuredVulnTargetTypes; + + @Autowired + ElasticSearchRepository esRepository; + + @Autowired + AssetService assetService; + + private static RestClient restClient; + + private static Map> categoryToRefineByMap = new HashMap<>(); + private static Map> categoryToReturnFieldsMap = new HashMap<>(); + + private synchronized void fetchConfigFromDB() { + + if (categoryToRefineByMap.size() > 0 || categoryToReturnFieldsMap.size() > 0) { + return; + } + + String query = "select SEARCH_CATEGORY,RESOURCE_TYPE,REFINE_BY_FIELDS,RETURN_FIELDS FROM OmniSearch_Config"; + List> resultsList = rdsRepository.getDataFromPacman(query); + + Iterator> rowIterator = resultsList.iterator(); + + while (rowIterator.hasNext()) { + Map currentRowMap = rowIterator.next(); + String searchCategory = currentRowMap.get("SEARCH_CATEGORY") != null + ? currentRowMap.get("SEARCH_CATEGORY").toString().trim() : ""; + String resourceType = currentRowMap.get("RESOURCE_TYPE") != null + ? currentRowMap.get("RESOURCE_TYPE").toString().trim() : ""; + String refineByFields = currentRowMap.get("REFINE_BY_FIELDS") != null + ? currentRowMap.get("REFINE_BY_FIELDS").toString().trim() : ""; + String returnFields = currentRowMap.get("RETURN_FIELDS") != null + ? currentRowMap.get("RETURN_FIELDS").toString().trim() : ""; + + Map resourceTypeToRefineByMap = categoryToRefineByMap.get(searchCategory); + if (null == resourceTypeToRefineByMap) { + resourceTypeToRefineByMap = new HashMap<>(); + } + resourceTypeToRefineByMap.put(resourceType, refineByFields); + + Map resourceTypeToReturnFieldMap = categoryToReturnFieldsMap.get(searchCategory); + if (null == resourceTypeToReturnFieldMap) { + resourceTypeToReturnFieldMap = new HashMap<>(); + } + resourceTypeToReturnFieldMap.put(resourceType, returnFields); + + categoryToRefineByMap.put(searchCategory, resourceTypeToRefineByMap); + categoryToReturnFieldsMap.put(searchCategory, resourceTypeToReturnFieldMap); + + } + } + + @Override + public SearchResult fetchSearchResultsAndSetTotal(String ag, String domain, boolean includeAllAssets, + String targetType, String searchText, Map> lowLevelFilters, int from, int size, + SearchResult result, String searchCategory) throws DataException { + + if (categoryToRefineByMap.size() == 0 || categoryToReturnFieldsMap.size() == 0) { + + fetchConfigFromDB(); + + } + + Map mustFilter = new LinkedHashMap<>(); + Map mustTermsFilter = new LinkedHashMap<>(); + + lowLevelFilters.forEach((displayName, valueList) -> { + String esFieldName = getFieldMappingsForSearch(targetType, false, searchCategory).get(displayName) + + ".keyword"; + mustTermsFilter.put(esFieldName, valueList); + }); + + String esType = null; + + if (AssetConstants.ASSETS.equals(searchCategory)) { + if (!includeAllAssets) { + mustFilter.put(Constants.LATEST, Constants.TRUE); + } + mustFilter.put(AssetConstants.UNDERSCORE_ENTITY, Constants.TRUE); + if (null == targetType) { + mustTermsFilter.put(AssetConstants.UNDERSCORE_ENTITY_TYPE_KEYWORD, getTypesForDomain(ag, domain)); + } + esType = targetType; + } + + if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { + mustFilter.put("type.keyword", "issue"); + mustTermsFilter.put("issueStatus.keyword", Arrays.asList("open", "exempted")); + if (null == targetType) { + esType = null; + mustTermsFilter.put("targetType.keyword", getTypesForDomain(ag, domain)); + + } else { + esType = "issue_" + targetType; + } + + } + + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + mustFilter.put(Constants.LATEST, Constants.TRUE); + mustTermsFilter.put(Constants.SEVEITY_LEVEL+".keyword", + Arrays.asList(Constants.THREE, Constants.FOUR, Constants.FIVE)); + + if (null != targetType) { + mustFilter.put("_index", "aws_" + targetType); + } + esType = Constants.VULN_INFO; + } + long start = System.currentTimeMillis(); + + if (!Strings.isNullOrEmpty(searchText)) { + searchText = "\"" + searchText + "\""; + } + List> results = new ArrayList<>(); + if (!AssetConstants.VULNERABILITIES.equals(searchCategory)) { + + List> sortFieldsMapList = new ArrayList<>(); + Map resourceIdSort = new HashMap<>(); + resourceIdSort.put("_resourceid.keyword", "asc"); + sortFieldsMapList.add(resourceIdSort); + + StringBuilder urlToQuery = new StringBuilder(PROTOCOL + esHost + ":" + esPort + "/" + ag); + if (!Strings.isNullOrEmpty(esType)) { + urlToQuery.append("/").append(esType); + } + urlToQuery.append("/").append("_search?from=").append(from).append("&size=").append(size); + + Map query = new HashMap<>(); + query.put("query", esRepository.buildQuery(mustFilter, null, null, searchText, mustTermsFilter, null)); + query.put("_source", getReturnFieldsForSearch(targetType, searchCategory)); + query.put("sort", resourceIdSort); + + String resultJson = invokeESCall("GET", urlToQuery.toString(), new Gson().toJson(query)); + + Gson serializer = new GsonBuilder().create(); + Map response = (Map) serializer.fromJson(resultJson, Object.class); + if (response.containsKey("hits")) { + Map hits = (Map) response.get("hits"); + long total = Double.valueOf(hits.get("total").toString()).longValue(); + result.setTotal(total); + } + esRepository.processResponseAndSendTheScrollBack(resultJson, results); + + } else { + List returnFields = getReturnFieldsForSearch(targetType, searchCategory); + String docQueryString = ""; + docQueryString = new StringBuilder(docQueryString).append("[").toString(); + int count = 0; + for (String returnField : returnFields) { + if (count == 0) { + docQueryString = new StringBuilder(docQueryString).append("doc['").append(returnField) + .append("'].value").toString(); + } else { + docQueryString = new StringBuilder(docQueryString).append("doc['").append(returnField) + .append(".keyword'].value").toString(); + + } + count++; + + if (count < returnFields.size()) { + docQueryString = new StringBuilder(docQueryString).append(" +'~'+").toString(); + } + + } + docQueryString = docQueryString + "]"; + + String url = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.VULN_INFO + "/" + + Constants.SEARCH; + Map query = new HashMap<>(); + query.put("query", esRepository.buildQuery(mustFilter, null, null, searchText, mustTermsFilter, null)); + + String queryString = new Gson().toJson(query); + String payload = queryString.substring(0, queryString.length() - 1) + + ", \"aggs\": {\"qids\": {\"terms\": {\"script\": \"" + docQueryString + "\",\"size\": 10000}}}}"; + String responseJson = ""; + try { + long startAggs = System.currentTimeMillis(); + LOGGER.debug("To get vuln aggs without dups, url is: {} and payload is: {}", url, payload); + responseJson = PacHttpUtils.doHttpPost(url, payload); + LOGGER.debug(AssetConstants.DEBUG_RESPONSEJSON, responseJson); + long endAggs = System.currentTimeMillis(); + LOGGER.debug("Time taken for ES call(vuln aggs sans dups) is: {}", (endAggs - startAggs)); + results = getDistFromVulnAggsResult(responseJson, returnFields); + } catch (Exception e) { + LOGGER.error("Failed to retrieve vuln aggs for omni search ", e); + } + + } + + results = pruneResults(results, targetType, searchCategory); + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + result.setTotal(results.size()); + + int end = from + size; + if (end > (results.size())) { + from = 0; + end = results.size(); + } + results = results.subList(from, end); + } + + result.setResults(results); + long end = System.currentTimeMillis(); + LOGGER.debug("Time taken to perform search for Search Category {} is: {}", searchCategory, (end - start)); + + return result; + + } + + @Override + public List> fetchTargetTypes(String ag, String searchText, String searchCategory, + String domain, boolean includeAllAssets) throws DataException { + + if (categoryToRefineByMap.size() == 0 || categoryToReturnFieldsMap.size() == 0) { + + fetchConfigFromDB(); + + } + + List> resourceTypeBucketList = new ArrayList<>(); + + String aggStringForHighLevelEntities = ""; + if (AssetConstants.ASSETS.equals(searchCategory)) { + aggStringForHighLevelEntities = "\"targetTypes\":{\"terms\":{\"field\":\"_entitytype.keyword\",\"size\":10000}}"; + } + + if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { + aggStringForHighLevelEntities = "\"targetTypes\":{\"terms\":{\"field\":\"targetType.keyword\",\"size\":10000}}"; + } + + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + aggStringForHighLevelEntities = "\"targetTypes\":{\"terms\":{\"field\":\"_index\",\"size\":10000},\"aggs\":{\"unique\":{\"cardinality\":{\"field\":\"" + + getReturnFieldsForSearch(null, searchCategory).get(0) + "\"}}}}"; + } + + String payLoadStr = createPayLoad(aggStringForHighLevelEntities, searchText, searchCategory, null, + includeAllAssets); + + String firstUrl = ""; + + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + firstUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.VULN_INFO + "/" + Constants.SEARCH; + } else { + firstUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.SEARCH; + } + String responseJson = ""; + + try { + long start = System.currentTimeMillis(); + LOGGER.debug("To get targetTypes:URL is: {} and payload is : {}", firstUrl, payLoadStr); + responseJson = PacHttpUtils.doHttpPost(firstUrl, payLoadStr); + LOGGER.debug(AssetConstants.DEBUG_RESPONSEJSON, responseJson); + long end = System.currentTimeMillis(); + LOGGER.debug("Time taken for ES call(targetType) for Search Category {} is: {}", searchCategory, + (end - start)); + + } catch (Exception e) { + LOGGER.error("Failed to retrieve high level entity types for omni search ", e); + return resourceTypeBucketList; + } + + resourceTypeBucketList = getDistributionFromAggResult(responseJson, "targetTypes"); + + // Atleast one refinement should be defined for the entity. If not, kick + // it out + removeResourceTypeIfNoMappingDefined(resourceTypeBucketList, searchCategory); + + removeResourceTypeIfNotAttachedToDomain(ag, resourceTypeBucketList, domain); + + return resourceTypeBucketList; + } + + private List getTypesForDomain(String ag, String domain) { + List> domainData = assetService.getTargetTypesForAssetGroup(ag, domain); + List typesForDomain = new ArrayList<>(); + domainData.forEach(domainMap -> { + domainMap.forEach((key, value) -> { + if (key.equals("type")) { + typesForDomain.add(value.toString()); + } + }); + }); + return typesForDomain; + } + + private synchronized void removeResourceTypeIfNotAttachedToDomain(String ag, + List> resourceTypeBucketList, String domain) { + + List typesForDomain = getTypesForDomain(ag, domain); + + Iterator> resourceIterator = resourceTypeBucketList.iterator(); + while (resourceIterator.hasNext()) { + String resourceType = resourceIterator.next().get(AssetConstants.FIELDNAME).toString(); + if (!typesForDomain.contains(resourceType)) { + resourceIterator.remove(); + } + } + } + + private synchronized void removeResourceTypeIfNoMappingDefined(List> resourceTypeBucketList, + String searchCategory) { + Iterator> resourceIterator = resourceTypeBucketList.iterator(); + while (resourceIterator.hasNext()) { + String resourceType = resourceIterator.next().get(AssetConstants.FIELDNAME).toString(); + Map fieldMapping = getFieldMappingsForSearch(resourceType, false, searchCategory); + if (fieldMapping.isEmpty()) { + resourceIterator.remove(); + } + } + } + + @Override + public Map>> fetchDistributionForTargetType(String ag, String resourceType, + String searchText, String searchCategory, boolean includeAllAssets) { + + Map>> returnBucketMap = new LinkedHashMap<>(); + + // Prepare aggregation string based on what resourceType we are + // dealing with + StringBuilder aggregationStrBuffer = new StringBuilder(); + Map fieldMapping = getFieldMappingsForSearch(resourceType, false, searchCategory); + if (fieldMapping.isEmpty()) { + return returnBucketMap; + } + + fieldMapping.forEach((displayName, esFieldName) -> { + aggregationStrBuffer.append( + "\"" + displayName + "\":{\"terms\":{\"field\":\"" + esFieldName + ".keyword\",\"size\":10000}"); + + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + + aggregationStrBuffer.append(",\"aggs\":{\"unique\":{\"cardinality\":{\"field\":\"" + + getReturnFieldsForSearch(resourceType, searchCategory).get(0) + "\"}}}"); + } + aggregationStrBuffer.append("}"); + + // Trailing comma + aggregationStrBuffer.append(","); + }); + + // Remove the trailing comma, because of the iteration above + String aggStringForLowLevelMenu = aggregationStrBuffer.toString().substring(0, + aggregationStrBuffer.toString().length() - 1); + + String lowLevelPayLoadStr = createPayLoad(aggStringForLowLevelMenu, searchText, searchCategory, resourceType, + includeAllAssets); + + String secondUrl = null; + if (AssetConstants.ASSETS.equals(searchCategory)) { + secondUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + resourceType + "/" + Constants.SEARCH; + } + if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { + secondUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + "issue_" + resourceType + "/" + + Constants.SEARCH; + } + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + secondUrl = PROTOCOL + esHost + ":" + esPort + "/" + ag + "/" + Constants.VULN_INFO + "/" + + Constants.SEARCH; + } + + try { + LOGGER.debug("To get distribution, the URL is: {} and the payload is: {}", secondUrl, lowLevelPayLoadStr); + long start = System.currentTimeMillis(); + final String lowLevelResponseJson = invokeESCall("GET", secondUrl, lowLevelPayLoadStr); + LOGGER.debug(AssetConstants.DEBUG_RESPONSEJSON, lowLevelResponseJson); + long end = System.currentTimeMillis(); + LOGGER.debug("Search Category {}", searchCategory); + LOGGER.debug("Target type {}", resourceType); + LOGGER.debug("Time taken for ES call(refineBy) is: {}", (end - start)); + + fieldMapping.forEach((displayName, esFieldName) -> { + List> detailsBucketList = getDistributionFromAggResult(lowLevelResponseJson, + displayName); + if (!detailsBucketList.isEmpty()) { + returnBucketMap.put(displayName, detailsBucketList); + } + + }); + } catch (Exception e) { + LOGGER.error("Error fetching distributions from ES:", e); + } + + return returnBucketMap; + } + + private List> getDistributionFromAggResult(String responseJson, String aggName) { + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = jsonParser.parse(responseJson).getAsJsonObject(); + JsonArray types = resultJson.get("aggregations").getAsJsonObject().get(aggName).getAsJsonObject().get("buckets") + .getAsJsonArray(); + List> bucketList = new ArrayList<>(); + for (JsonElement type : types) { + JsonObject typeObj = type.getAsJsonObject(); + String fieldName = typeObj.get("key").getAsString(); + + // To handle vulnerabilities type + if (fieldName.startsWith("aws_")) { + fieldName = fieldName.substring(4); + } + + long count = typeObj.get("doc_count").getAsLong(); + JsonElement uniqueNumberElement = typeObj.get("unique"); + if (null != uniqueNumberElement) { + count = uniqueNumberElement.getAsJsonObject().get("value").getAsLong(); + } + Map typeMap = new HashMap<>(); + typeMap.put(AssetConstants.FIELDNAME, fieldName); + typeMap.put("count", count); + bucketList.add(typeMap); + } + + return bucketList; + } + + private List> getDistFromVulnAggsResult(String responseJson, List returnFields) { + + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = jsonParser.parse(responseJson).getAsJsonObject(); + JsonArray types = resultJson.get("aggregations").getAsJsonObject().get("qids").getAsJsonObject().get("buckets") + .getAsJsonArray(); + List> bucketList = new ArrayList<>(); + for (JsonElement type : types) { + int count = 0; + Map map = new HashMap<>(); + JsonObject typeObj = type.getAsJsonObject(); + String key = typeObj.get("key").getAsString(); + StringTokenizer vulnkeyTokenizer = new StringTokenizer(key, "~"); + while (vulnkeyTokenizer.hasMoreTokens()) { + String token = vulnkeyTokenizer.nextToken(); + map.put(returnFields.get(count), token); + count++; + } + bucketList.add(map); + } + + return bucketList; + } + + private String createPayLoad(String aggString, String searchText, String searchCategory, String resourceType, + boolean includeAllAssets) { + StringBuilder payLoad = new StringBuilder(); + String matchString = ""; + if (AssetConstants.ASSETS.equals(searchCategory)) { + matchString = "{\"match\":{\"_entity\":\"true\"}}"; + } + if (AssetConstants.POLICY_VIOLATIONS.equals(searchCategory)) { + matchString = "{\"match\":{\"type.keyword\":\"issue\"}},{\"terms\":{\"issueStatus.keyword\":[ \"open\",\"exempted\"]}}"; + } + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + matchString = "{\"terms\":{\"severitylevel.keyword\":[3,4,5]}}"; + if (resourceType != null) { + matchString = matchString + ",{\"match\":{\"_index\":\"aws_" + resourceType + "\"}}"; + } + } + + payLoad.append("{\"size\":0,\"query\":{\"bool\":{\"must\":["); + payLoad.append(matchString); + if (AssetConstants.ASSETS.equals(searchCategory) && !includeAllAssets) { + payLoad.append(",{\"match\":{\"latest\":\"true\"}}"); + } + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + payLoad.append(",{\"match\":{\"latest\":\"true\"}}"); + } + + payLoad.append(",{\"match_phrase_prefix\":{\"_all\":\""); + payLoad.append(searchText); + payLoad.append("\"}}]}}"); + payLoad.append(",\"aggs\":{"); + payLoad.append(aggString); + payLoad.append("}}"); + return payLoad.toString(); + } + + @Override + public Map getFieldMappingsForSearch(String incomingResourceType, boolean flipOrder, + String searchCategory) { + + Map mappingList = new LinkedHashMap<>(); + + String commaSepString = categoryToRefineByMap.get(searchCategory).get(incomingResourceType); + + String commaSepStringForAll = categoryToRefineByMap.get(searchCategory).get("All"); + + String jointStr = commaSepStringForAll + (commaSepString != null ? (",".concat(commaSepString)) : ""); + + String displayName = null; + String esFieldName = null; + + StringTokenizer commaTokens = new StringTokenizer(jointStr, ","); + while (commaTokens.hasMoreTokens()) { + String pipeSeparatedStr = commaTokens.nextToken(); + if (pipeSeparatedStr.contains("|")) { + int posOfPipe = pipeSeparatedStr.indexOf('|'); + esFieldName = pipeSeparatedStr.substring(0, posOfPipe); + displayName = pipeSeparatedStr.substring(posOfPipe, pipeSeparatedStr.length()); + } else { + // Assume display name is same as field name + esFieldName = pipeSeparatedStr; + displayName = pipeSeparatedStr; + } + if (flipOrder) { + mappingList.put(esFieldName, displayName); + } else { + mappingList.put(displayName, esFieldName); + } + } + return mappingList; + } + + @Override + public List getReturnFieldsForSearch(String incomingResourceType, String searchCategory) { + + List returnFieldList = new ArrayList<>(); + + String commaSepString = categoryToReturnFieldsMap.get(searchCategory).get(incomingResourceType); + String commaSepStringForAll = categoryToReturnFieldsMap.get(searchCategory).get("All"); + + String jointStr = commaSepStringForAll + (commaSepString != null ? (",".concat(commaSepString)) : ""); + StringTokenizer commaTokens = new StringTokenizer(jointStr, ","); + + while (commaTokens.hasMoreTokens()) { + returnFieldList.add(commaTokens.nextToken()); + } + + return returnFieldList; + } + + private List> pruneResults(List> results, String targetType, + String searchCategory) { + List returnFields = getReturnFieldsForSearch(targetType, searchCategory); + List> resultsAfterPruning = new ArrayList<>(); + results.forEach(result -> { + Map outgoingMap = new LinkedHashMap<>(); + result.forEach((key, value) -> { + if (returnFields.contains(key) || key.startsWith("tags.")) { + // The first item in the return fields from RDS is to be + // considered as the id + // field + if (key.equals(returnFields.get(0))) { + key = Constants._ID; + } + outgoingMap.put(key, value); + } + }); + + outgoingMap.put("searchCategory", searchCategory); + boolean removeDups = false; + if (AssetConstants.VULNERABILITIES.equals(searchCategory)) { + removeDups = true; + } + if (!removeDups || (removeDups + && !doesResultAlreadyContainId(resultsAfterPruning, outgoingMap.get(Constants._ID)))) { + resultsAfterPruning.add(outgoingMap); + } + }); + return resultsAfterPruning; + } + + private boolean doesResultAlreadyContainId(List> resultsAfterPruning, + Object idValueToBeChecked) { + List matchedObjects = new ArrayList<>(); + resultsAfterPruning.forEach(result -> { + result.forEach((key, value) -> { + if (key.equals(Constants._ID)) { + double lhsLongValue = Double.parseDouble(value.toString()); + double rhsLongValue = Double.parseDouble(idValueToBeChecked.toString()); + if (lhsLongValue == rhsLongValue) { + + LOGGER.debug("Duplicate vuln id found(Won't be adding this..): {}", idValueToBeChecked); + matchedObjects.add(idValueToBeChecked); + } + + } + }); + }); + return !matchedObjects.isEmpty(); + } + + private RestClient getRestClient() { + if (restClient == null) { + + RestClientBuilder builder = RestClient.builder(new HttpHost(esHost, esPort)); + builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { + @Override + public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { + return requestConfigBuilder.setConnectionRequestTimeout(0); + } + }); + restClient = builder.build(); + } + return restClient; + + } + + private String invokeESCall(String method, String endpoint, String payLoad) { + HttpEntity entity = null; + try { + if (payLoad != null) { + entity = new NStringEntity(payLoad, ContentType.APPLICATION_JSON); + } + return EntityUtils.toString(getRestClient() + .performRequest(method, endpoint, Collections.emptyMap(), entity).getEntity()); + } catch (IOException e) { + LOGGER.error("Error in invokeESCall ", e); + } + return null; + } + +} diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/ComplianceController.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/ComplianceController.java index f3baa0f66..5d36208a4 100644 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/ComplianceController.java +++ b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/ComplianceController.java @@ -1,750 +1,715 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.compliance.controller; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; -import java.util.TimeZone; - -import org.apache.commons.collections.MapUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import com.google.common.base.Strings; -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.ServiceException; -import com.tmobile.pacman.api.commons.utils.ResponseUtils; -import com.tmobile.pacman.api.compliance.domain.DitributionDTO; -import com.tmobile.pacman.api.compliance.domain.IssueAuditLogRequest; -import com.tmobile.pacman.api.compliance.domain.IssueResponse; -import com.tmobile.pacman.api.compliance.domain.IssuesException; -import com.tmobile.pacman.api.compliance.domain.KernelVersion; -import com.tmobile.pacman.api.compliance.domain.OutputDTO; -import com.tmobile.pacman.api.compliance.domain.PolicyDescription; -import com.tmobile.pacman.api.compliance.domain.PolicyViolationDetails; -import com.tmobile.pacman.api.compliance.domain.Request; -import com.tmobile.pacman.api.compliance.domain.ResourceTypeResponse; -import com.tmobile.pacman.api.compliance.domain.ResponseData; -import com.tmobile.pacman.api.compliance.domain.ResponseWithOrder; -import com.tmobile.pacman.api.compliance.domain.RevokeIssuesException; -import com.tmobile.pacman.api.compliance.domain.RuleDetails; -import com.tmobile.pacman.api.compliance.service.ComplianceService; -import com.tmobile.pacman.api.compliance.service.VulnerabilityService; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -/** - * The Class ComplianceController. - */ -@RestController -@PreAuthorize("@securityService.hasPermission(authentication, 'ROLE_USER')") -public class ComplianceController implements Constants { - - /** The compliance service. */ - @Autowired - private ComplianceService complianceService; - - /** The vuln service. */ - @Autowired - private VulnerabilityService vulnService; - - /** - * Gets the issues details.Request expects asssetGroup and domain as - * mandatory, ruleId as optional.If API receives assetGroup and domain as - * request parameter, it gives details of all open issues for all the rules - * associated to that domain. If API receives assetGroup, domain and ruleId - * as request parameter,it gives only open issues of that rule associated to - * that domain. SearchText is used to match any text you are looking - * for.From and size are for the pagination - * - * @param request request body - * @return issues - */ - - @RequestMapping(path = "/v1/issues", method = RequestMethod.POST) - @ResponseBody - public ResponseEntity getIssues(@RequestBody(required = false) Request request) { - String assetGroup = request.getAg(); - Map filters = request.getFilter(); - - if (Strings.isNullOrEmpty(assetGroup) || MapUtils.isEmpty(filters) - || Strings.isNullOrEmpty(filters.get(DOMAIN))) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); - } - ResponseWithOrder response = null; - try { - response = complianceService.getIssues(request); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the issues count. asssetGroup and domain are mandatory & ruleId is - * optional parameter, it gives issues count of all open issues for all the rules - * associated to that domain. If API receives assetGroup,domain and ruleId - * as request parameter,it gives issues count of all open issues for that - * rule associated to that domain. - * - * @param assetGroup name of the asset group - * @param domain the domain - * @param ruleId the rule id - * @return the issues count - */ - - @RequestMapping(path = "/v1/issues/count", method = RequestMethod.GET) - public ResponseEntity getIssuesCount(@RequestParam("ag") String assetGroup, - @RequestParam("domain") String domain, @RequestParam(name = "ruleId", required = false) String ruleId) { - if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(domain)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); - } - Map response = new HashMap<>(); - try { - response.put("total_issues", complianceService.getIssuesCount(assetGroup, ruleId, domain)); - } catch (ServiceException e) { - return ResponseUtils.buildFailureResponse(e); - } - - return ResponseUtils.buildSucessResponse(response); - - } - - /** - * Gets the issue distribution by ruleCategory and severity.asssetGroup - * is mandatory, domain is optional. API return issue distribution rule - * severity & rule Category for given asset group - * - * @param assetGroup name of the asset group - * @param domain the domain - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/issues/distribution", method = RequestMethod.GET) - public ResponseEntity getDistribution(@RequestParam("ag") String assetGroup, - @RequestParam(name = "domain", required = false) String domain) { - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); - } - DitributionDTO distribution = null; - try { - distribution = new DitributionDTO(complianceService.getDistribution(assetGroup, domain)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(distribution); - } - - /** - * Gets the tagging compliance summary.asssetGroup is mandatory and - * targetType is optional If API receives assetGroup as request parameter, - * api returns tagged/un-tagged/asset count of all the target types for that - * asset group. If API receives both assetGroup and targetType as request - * parameter,api returns tagged/un-tagged/asset count of specified target - * type. - * - * @param assetGroup name of the asset group - * @param targetType the target type - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/tagging", method = RequestMethod.GET) - public ResponseEntity getTagging(@RequestParam("ag") String assetGroup, - @RequestParam(name = "targettype", required = false) String targetType) { - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); - } - OutputDTO output = null; - try { - output = new OutputDTO(complianceService.getTagging(assetGroup, targetType)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(output); - } - - /** - * Gets the vulnerabilities.asssetGroup is mandatory. API returns count of - * totalVulnerabilities/totalAssets/totalVulnerabilites Assets - * - * @param assetGroup name of the asset group - * @return ResponseEntity - */ - // @Cacheable("trends") - - @RequestMapping(path = "/v1/vulnerabilites", method = RequestMethod.GET) - public ResponseEntity getVulnerabilities(@RequestParam("ag") String assetGroup) { - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); - } - OutputDTO output = null; - try { - Map vulnerabilities = new HashMap<>(); - Map vulnSummary = vulnService.getVulnerabilitySummary(assetGroup,SEVERITY_LEVELS); - vulnerabilities.put("vulnerabilities", Long.valueOf(vulnSummary.get("vulnerabilities").toString())); - vulnerabilities.put("hosts", Long.valueOf(vulnSummary.get("hosts").toString())); - vulnerabilities.put("totalVulnerableAssets", - Long.valueOf(vulnSummary.get("totalVulnerableAssets").toString())); - vulnSummary.remove("compliantpercent"); - output = new OutputDTO(vulnerabilities); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(output); - } - - /** - * Gets the certificates compliance details.asssetGroup is mandatory. API - * returns count of expiredCertificates with in 60days and totalCertificates - * for given assetGroup - * - * @param assetGroup name of the asset group - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/certificates", method = RequestMethod.GET) - public ResponseEntity getCertificates(@RequestParam("ag") String assetGroup) { - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); - } - OutputDTO output = null; - try { - output = new OutputDTO(complianceService.getCertificates(assetGroup)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(output); - } - - /** - * Gets the patching compliance details.AssetGroup is mandatory. API returns - * count of totalPached/toalUnpatched/TotalInstances for given assetGroup - * - * @param assetGroup name of the asset group - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/patching", method = RequestMethod.GET) - public ResponseEntity getPatching(@RequestParam("ag") String assetGroup) { - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception("Asset group is mandatory")); - } - OutputDTO output = null; - try { - output = new OutputDTO(complianceService.getPatching(assetGroup, null)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(output); - } - - /** - * Gets the recommendations details by policy.asssetGroup is mandatory and - * targetType is optional. If API receives assetGroup as request parameter, - * API returns list of all the issue counts which are related to - * recommendations rules from the ES for the given assetGroup with all the - * targetTypes.If API receives both assetGroup and targetType as request - * parameter,API returns list of all the issue counts which are related to - * recommendations rules from the ES for the given targetType & assetGroup. - * - * @param assetGroup name of the asset group - * @param targetType the target type - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/recommendations", method = RequestMethod.GET) - public ResponseEntity getRecommendations(@RequestParam("ag") String assetGroup, - @RequestParam(name = "targettype", required = false) String targetType) { - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); - } - ResponseData response = null; - try { - response = new ResponseData(complianceService.getRecommendations(assetGroup, targetType)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - - } - - /** - * Gets the issue audit details.This request accepts - * annotationId,targetType,size as mandatory. If API receives - * annotationId,targetType,size as request parameter, API returns list of - * data source, audit date and status of that annotationId. searchText is used - * to match any text you are looking for. from and size are for pagination. - * - * @param request the request - * @return the issue audit - */ - - @RequestMapping(path = "/v1/issueauditlog", method = RequestMethod.POST) - public ResponseEntity getIssueAudit(@RequestBody IssueAuditLogRequest request) { - String issueId = request.getIssueId(); - String targetType = request.getTargetType(); - int from = request.getFrom(); - int size = request.getSize(); - String searchText = request.getSearchText(); - if (Strings.isNullOrEmpty(issueId) || Strings.isNullOrEmpty(targetType) || from < 0 || size <= 0) { - return ResponseUtils.buildFailureResponse(new Exception("IssueId/Targettype/from/size is Mandatory")); - } - ResponseWithOrder response = null; - try { - response = complianceService.getIssueAuditLog(issueId, targetType, from, size, searchText); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - - } - - /** - * Gets the resource details.assetGroup and resourceId are mandatory. API - * returns map details for given resourceId - * - * @param assetGroup name of the asset group - * @param resourceId the resource id - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/resourcedetails", method = RequestMethod.GET) - public ResponseEntity getResourceDetails(@RequestParam("ag") String assetGroup, - @RequestParam("resourceId") String resourceId) { - if (Strings.isNullOrEmpty(resourceId)) { - return ResponseUtils.buildFailureResponse(new Exception("assetGroup/resourceId is mandatory")); - } - ResponseData response = null; - try { - response = new ResponseData(complianceService.getResourceDetails(assetGroup, resourceId)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Close issues.ruleDetails expects ruleId,reason and userId, Api returns - * true if its successfully closes all issues in ES for that ruleId else - * false - * - * @param ruleDetails the rule details - * @return ResponseEntity - */ - @ApiOperation(httpMethod = "PUT", value = "Close Issues by Rule Details") - @RequestMapping(path = "/v1/issues/close-by-rule-id", method = RequestMethod.PUT) - @ResponseBody - - public ResponseEntity closeIssues( - @ApiParam(value = "Provide valid Rule Details ", required = true) @RequestBody(required = true) RuleDetails ruleDetails) { - Map response = complianceService.closeIssuesByRule(ruleDetails); - if (Integer.parseInt(response.get("status").toString()) == TWO_HUNDRED) { - return new ResponseEntity<>(response, HttpStatus.OK); - } else { - return new ResponseEntity<>(response, HttpStatus.FORBIDDEN); - } - } - - /** - * Adds the issue exception.issueException expects - * issueId,exceptionGrantedDate,exceptionEndDate and exceptionReason, API is - * for adding issue exception to the corresponding target type. - * - * @param issueException the issue exception - * @return ResponseEntity - */ - @ApiOperation(httpMethod = "POST", value = "Adding issue exception to the corresponding target type") - @RequestMapping(path = "/v1/issues/add-exception", method = RequestMethod.POST) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Added Issue Exception"), - @ApiResponse(code = 401, message = "You are not authorized to Add Issue Exception"), - @ApiResponse(code = 403, message = "Add Issue Exception is forbidden") }) - @ResponseBody - - public ResponseEntity addIssueException( - @ApiParam(value = "Provide Issue Exception Details", required = true) @RequestBody(required = true) IssueResponse issueException) { - try { - Boolean isExempted = complianceService.addIssueException(issueException); - if (isExempted) { - return ResponseUtils.buildSucessResponse("Successfully Added Issue Exception"); - } else { - return ResponseUtils.buildFailureResponse(new Exception("Failed in Adding Issue Exception")); - } - } catch (ServiceException exception) { - return ResponseUtils.buildFailureResponse(exception); - } - } - - /** - * Revoke issue exception. - * - * @param issueId the issue id - * @return ResponseEntity - */ - @ApiOperation(httpMethod = "POST", value = "Revoking issue exception to the corresponding target type") - @RequestMapping(path = "/v1/issues/revoke-exception", method = RequestMethod.POST) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Revoked Issue Exception"), - @ApiResponse(code = 401, message = "You are not authorized to Revoke Issue Exception"), - @ApiResponse(code = 403, message = "Revoke IssueException is forbidden") }) - @ResponseBody - - public ResponseEntity revokeIssueException( - @ApiParam(value = "Provide Issue Id", required = true) @RequestParam(required = true) String issueId) { - try { - Boolean isIssueExceptionRevoked = complianceService.revokeIssueException(issueId); - if (isIssueExceptionRevoked) { - return ResponseUtils.buildSucessResponse("Successfully Revoked Issue Exception"); - } else { - return ResponseUtils.buildFailureResponse(new Exception("Failed in Revoking Issue Exception")); - } - } catch (ServiceException exception) { - return ResponseUtils.buildFailureResponse(exception); - } - } - - /** - * Gets the non compliance policy by rule.request expects asset group and - * domain as mandatory.Api returns list of all the rules associated to that - * domain with compliance percentage/severity/ruleCategory etc fields. - * - * @param request the request - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/noncompliancepolicy", method = RequestMethod.POST) - // @Cacheable(cacheNames="compliance",unless="#result.status==200") - // commenting to performance after refacoting - // @Cacheable(cacheNames="compliance",key="#request.key") - - public ResponseEntity getNonCompliancePolicyByRule(@RequestBody(required = false) Request request) { - String assetGroup = request.getAg(); - - Map filters = request.getFilter(); - - if (Strings.isNullOrEmpty(assetGroup) || MapUtils.isEmpty(filters) - || Strings.isNullOrEmpty(filters.get(DOMAIN))) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); - } - ResponseWithOrder response = null; - try { - response = (complianceService.getRulecompliance(request)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - - } - - /** - * Gets the policy details by application.asssetGroup and ruleId are - * mandatory. API returns total/application/compliant/compliantPercentage of - * the ruleId for given assetGroup. SearchText is used to match any text you - * are looking for - * - * @param assetGroup name of the asset group - * @param ruleId the rule id - * @param searchText the search text - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/policydetailsbyapplication", method = RequestMethod.GET) - // @Cacheable(cacheNames="compliance",unless="#result.status==200") - - public ResponseEntity getPolicydetailsbyApplication(@RequestParam("ag") String assetGroup, - @RequestParam("ruleId") String ruleId, - @RequestParam(name = "searchText", required = false) String searchText) { - if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(ruleId)) { - return ResponseUtils.buildFailureResponse(new Exception("Assetgroup/ruleId is mandatory")); - } - ResponseData response = null; - try { - - response = new ResponseData(complianceService.getRuleDetailsbyApplication(assetGroup, ruleId, searchText)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the policy details by environment.asssetGroup,application and ruleId - * are mandatory. API returns - * total/environment/compliant/compliantPercentage of the ruleId for given - * assetGroup and application. SearchText is used to match any text you are - * looking for - * - * @param assetGroup name of the asset group - * @param application name of the application - * @param ruleId the rule id - * @param searchText the search text - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/policydetailsbyenvironment", method = RequestMethod.GET) - - public ResponseEntity getpolicydetailsbyEnvironment(@RequestParam("ag") String assetGroup, - @RequestParam("application") String application, @RequestParam("ruleId") String ruleId, - @RequestParam(name = "searchText", required = false) String searchText) { - - if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(application) || Strings.isNullOrEmpty(ruleId)) { - return ResponseUtils.buildFailureResponse(new Exception("assetgroup/application/ruleId is mandatory")); - } - ResponseData response = null; - try { - response = new ResponseData(complianceService.getRuleDetailsbyEnvironment(assetGroup, ruleId, application, - searchText)); - - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * API returns details of the given ruleId. - * - * @param ruleId the rule id - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/policydescription", method = RequestMethod.GET) - - public ResponseEntity getPolicyDescription(@RequestParam("ruleId") String ruleId) { - - if (Strings.isNullOrEmpty(ruleId)) { - return ResponseUtils.buildFailureResponse(new Exception("ruleId Mandatory")); - } - PolicyDescription response = null; - try { - response = new PolicyDescription(complianceService.getRuleDescription(ruleId)); - - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * API returns the kernel version of the given instanceId if it is - * from web service. - * - * @param instanceId the instance id - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/kernelcompliancebyinstanceid", method = RequestMethod.GET) - - public ResponseEntity getKernelComplianceByInstanceId(@RequestParam("instanceId") String instanceId) { - - if (Strings.isNullOrEmpty(instanceId)) { - return ResponseUtils.buildFailureResponse(new Exception("instanceId is mandatory")); - } - PolicyDescription output = null; - try { - output = new PolicyDescription(complianceService.getKernelComplianceByInstanceIdFromDb(instanceId)); - - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(output); - } - - /** - * API returns true if it updates the kernel version for the given - * instanceId successfully. - * - * @param kernelVersion the kernel version - * @return ResponseEntity - */ - - @ApiOperation(httpMethod = "PUT", value = "Update Kernel Version by InstanceId") - @RequestMapping(path = "/v1/update-kernel-version", method = RequestMethod.PUT) - @ResponseBody - - public ResponseEntity updateKernelVersion( - @ApiParam(value = "Provide valid Rule Details ", required = true) @RequestBody(required = true) KernelVersion kernelVersion) { - Map response = complianceService.updateKernelVersion(kernelVersion); - return new ResponseEntity<>(response, HttpStatus.OK); - } - - /** - * API returns overall compliance based on rule category and severity weightages - * for given asset group and domain. - * - * @param assetGroup - String - * @param domain - String - * @return ResponseEntity . - */ - @RequestMapping(path = "/v1/overallcompliance", method = RequestMethod.GET) - - public ResponseEntity getOverallCompliance(@RequestParam("ag") String assetGroup, - @RequestParam(name = "domain") String domain) { - if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(domain)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); - } - DitributionDTO distribution = null; - try { - distribution = new DitributionDTO(complianceService.getOverallComplianceByDomain(assetGroup, domain)); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(distribution); - } - - /** - * API returns targetTypes for given asset group and domain based on - * project target types configurations. - * - * @param assetgroup the assetgroup - * @param domain the domain - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/targetType", method = RequestMethod.GET) - - public ResponseEntity getTargetType(@RequestParam("ag") String assetgroup, - @RequestParam(name = "domain", required = false) String domain) { - - if (Strings.isNullOrEmpty(assetgroup)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); - } - ResourceTypeResponse response; - try { - - response = new ResourceTypeResponse(complianceService.getResourceType(assetgroup, domain)); - } catch (Exception e) { - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * API returns reason for violation along with other details for the - * given asset group and issueId. - * - * @param assetgroup the assetgroup - * @param issueId the issue id - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/policyViolationReason", method = RequestMethod.GET) - public ResponseEntity policyViolationReason(@RequestParam("ag") String assetgroup, - @RequestParam(name = "issueId") String issueId) { - - if (Strings.isNullOrEmpty(assetgroup) && Strings.isNullOrEmpty(issueId)) { - return ResponseUtils.buildFailureResponse(new Exception("AssetGroup/IssueId is Mandatory")); - } - PolicyViolationDetails response = null; - try { - response = complianceService.getPolicyViolationDetailsByIssueId(assetgroup, issueId); - } catch (ServiceException e) { - return complianceService.formatException(e); - } - return ResponseUtils.buildSucessResponse(response); - - } - - - /** - * API returns current kernel versions. - * - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/get-current-kernel-versions", method = RequestMethod.GET) - public ResponseEntity getCurrentKernelVersions() { - return ResponseUtils.buildSucessResponse(complianceService.getCurrentKernelVersions()); - } - - /** - * Adds the issues exception. - * - * @param issuesException the issues exception - * @return the response entity - */ - @ApiOperation(httpMethod = "POST", value = "Adding issue exception to the corresponding target type") - @RequestMapping(path = "/v2/issue/add-exception", method = RequestMethod.POST) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Added Issue Exception"), - @ApiResponse(code = 401, message = "You are not authorized to Add Issue Exception"), - @ApiResponse(code = 403, message = "Add Issue Exception is forbidden") }) - @ResponseBody - - public ResponseEntity addIssuesException( - @ApiParam(value = "Provide Issue Exception Details", required = true) @RequestBody(required = true) IssuesException issuesException) { - try { - - if (issuesException.getExceptionGrantedDate() == null) { - return ResponseUtils.buildFailureResponse(new Exception("Exception Granted Date is mandatory")); - } - if (issuesException.getExceptionEndDate() == null) { - return ResponseUtils.buildFailureResponse(new Exception("Exception End Date is mandatory")); - } - - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - Calendar cal = Calendar.getInstance(); - cal.setTimeZone(TimeZone.getTimeZone("UTC")); - if(sdf.parse(sdf.format(issuesException.getExceptionGrantedDate())).before(sdf.parse(sdf.format(cal.getTime())))) { - return ResponseUtils.buildFailureResponse(new Exception("Exception Granted Date cannot be earlier date than today")); - } - if(sdf.parse(sdf.format(issuesException.getExceptionEndDate())).before(sdf.parse(sdf.format(cal.getTime())))) { - return ResponseUtils.buildFailureResponse(new Exception("Exception End Date cannot be earlier date than today")); - } - if(issuesException.getIssueIds().isEmpty()) { - return ResponseUtils.buildFailureResponse(new Exception("Atleast one issue id is required")); - } - return ResponseUtils.buildSucessResponse(complianceService.addMultipleIssueException(issuesException)); - } catch (ServiceException | ParseException exception) { - return ResponseUtils.buildFailureResponse(exception); - } - } - - /** - * Revoke issue exception. - * - * @param issueIds the issue ids - * @return ResponseEntity - */ - @ApiOperation(httpMethod = "POST", value = "Revoking issue exception to the corresponding target type") - @RequestMapping(path = "/v2/issue/revoke-exception", method = RequestMethod.POST) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Revoked Issue Exception"), - @ApiResponse(code = 401, message = "You are not authorized to Revoke Issue Exception"), - @ApiResponse(code = 403, message = "Revoke IssueException is forbidden") }) - @ResponseBody - - public ResponseEntity revokeIssuesException( - @ApiParam(value = "Provide Issue Id", required = true) @RequestBody(required = true) RevokeIssuesException revokeIssuesException) { - try { - if(revokeIssuesException.getIssueIds().isEmpty()) { - return ResponseUtils.buildFailureResponse(new Exception("Atleast one issue id is required")); - } - return ResponseUtils.buildSucessResponse(complianceService.revokeMultipleIssueException(revokeIssuesException.getIssueIds())); - } catch (ServiceException exception) { - return ResponseUtils.buildFailureResponse(exception); - } - } -} +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.compliance.controller; + +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import java.util.TimeZone; + +import org.apache.commons.collections.MapUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import com.google.common.base.Strings; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.ServiceException; +import com.tmobile.pacman.api.commons.utils.ResponseUtils; +import com.tmobile.pacman.api.compliance.domain.DitributionDTO; +import com.tmobile.pacman.api.compliance.domain.IssueAuditLogRequest; +import com.tmobile.pacman.api.compliance.domain.IssueResponse; +import com.tmobile.pacman.api.compliance.domain.IssuesException; +import com.tmobile.pacman.api.compliance.domain.KernelVersion; +import com.tmobile.pacman.api.compliance.domain.OutputDTO; +import com.tmobile.pacman.api.compliance.domain.PolicyDescription; +import com.tmobile.pacman.api.compliance.domain.PolicyViolationDetails; +import com.tmobile.pacman.api.compliance.domain.Request; +import com.tmobile.pacman.api.compliance.domain.ResourceTypeResponse; +import com.tmobile.pacman.api.compliance.domain.ResponseData; +import com.tmobile.pacman.api.compliance.domain.ResponseWithOrder; +import com.tmobile.pacman.api.compliance.domain.RevokeIssuesException; +import com.tmobile.pacman.api.compliance.domain.RuleDetails; +import com.tmobile.pacman.api.compliance.service.ComplianceService; + +/** + * The Class ComplianceController. + */ +@RestController +@PreAuthorize("@securityService.hasPermission(authentication, 'ROLE_USER')") +public class ComplianceController implements Constants { + + /** The compliance service. */ + @Autowired + private ComplianceService complianceService; + + /** + * Gets the issues details.Request expects asssetGroup and domain as + * mandatory, ruleId as optional.If API receives assetGroup and domain as + * request parameter, it gives details of all open issues for all the rules + * associated to that domain. If API receives assetGroup, domain and ruleId + * as request parameter,it gives only open issues of that rule associated to + * that domain. SearchText is used to match any text you are looking + * for.From and size are for the pagination + * + * @param request request body + * @return issues + */ + + @RequestMapping(path = "/v1/issues", method = RequestMethod.POST) + @ResponseBody + public ResponseEntity getIssues(@RequestBody(required = false) Request request) { + String assetGroup = request.getAg(); + Map filters = request.getFilter(); + + if (Strings.isNullOrEmpty(assetGroup) || MapUtils.isEmpty(filters) + || Strings.isNullOrEmpty(filters.get(DOMAIN))) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); + } + ResponseWithOrder response = null; + try { + response = complianceService.getIssues(request); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the issues count. asssetGroup and domain are mandatory & ruleId is + * optional parameter, it gives issues count of all open issues for all the rules + * associated to that domain. If API receives assetGroup,domain and ruleId + * as request parameter,it gives issues count of all open issues for that + * rule associated to that domain. + * + * @param assetGroup name of the asset group + * @param domain the domain + * @param ruleId the rule id + * @return the issues count + */ + + @RequestMapping(path = "/v1/issues/count", method = RequestMethod.GET) + public ResponseEntity getIssuesCount(@RequestParam("ag") String assetGroup, + @RequestParam("domain") String domain, @RequestParam(name = "ruleId", required = false) String ruleId) { + if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(domain)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); + } + Map response = new HashMap<>(); + try { + response.put("total_issues", complianceService.getIssuesCount(assetGroup, ruleId, domain)); + } catch (ServiceException e) { + return ResponseUtils.buildFailureResponse(e); + } + + return ResponseUtils.buildSucessResponse(response); + + } + + /** + * Gets the issue distribution by ruleCategory and severity.asssetGroup + * is mandatory, domain is optional. API return issue distribution rule + * severity & rule Category for given asset group + * + * @param assetGroup name of the asset group + * @param domain the domain + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/issues/distribution", method = RequestMethod.GET) + public ResponseEntity getDistribution(@RequestParam("ag") String assetGroup, + @RequestParam(name = "domain", required = false) String domain) { + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + DitributionDTO distribution = null; + try { + distribution = new DitributionDTO(complianceService.getDistribution(assetGroup, domain)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(distribution); + } + + /** + * Gets the tagging compliance summary.asssetGroup is mandatory and + * targetType is optional If API receives assetGroup as request parameter, + * api returns tagged/un-tagged/asset count of all the target types for that + * asset group. If API receives both assetGroup and targetType as request + * parameter,api returns tagged/un-tagged/asset count of specified target + * type. + * + * @param assetGroup name of the asset group + * @param targetType the target type + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/tagging", method = RequestMethod.GET) + public ResponseEntity getTagging(@RequestParam("ag") String assetGroup, + @RequestParam(name = "targettype", required = false) String targetType) { + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + OutputDTO output = null; + try { + output = new OutputDTO(complianceService.getTagging(assetGroup, targetType)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(output); + } + + /** + * Gets the certificates compliance details.asssetGroup is mandatory. API + * returns count of expiredCertificates with in 60days and totalCertificates + * for given assetGroup + * + * @param assetGroup name of the asset group + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/certificates", method = RequestMethod.GET) + public ResponseEntity getCertificates(@RequestParam("ag") String assetGroup) { + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + OutputDTO output = null; + try { + output = new OutputDTO(complianceService.getCertificates(assetGroup)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(output); + } + + /** + * Gets the patching compliance details.AssetGroup is mandatory. API returns + * count of totalPached/toalUnpatched/TotalInstances for given assetGroup + * + * @param assetGroup name of the asset group + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/patching", method = RequestMethod.GET) + public ResponseEntity getPatching(@RequestParam("ag") String assetGroup) { + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception("Asset group is mandatory")); + } + OutputDTO output = null; + try { + output = new OutputDTO(complianceService.getPatching(assetGroup, null)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(output); + } + + /** + * Gets the recommendations details by policy.asssetGroup is mandatory and + * targetType is optional. If API receives assetGroup as request parameter, + * API returns list of all the issue counts which are related to + * recommendations rules from the ES for the given assetGroup with all the + * targetTypes.If API receives both assetGroup and targetType as request + * parameter,API returns list of all the issue counts which are related to + * recommendations rules from the ES for the given targetType & assetGroup. + * + * @param assetGroup name of the asset group + * @param targetType the target type + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/recommendations", method = RequestMethod.GET) + public ResponseEntity getRecommendations(@RequestParam("ag") String assetGroup, + @RequestParam(name = "targettype", required = false) String targetType) { + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + ResponseData response = null; + try { + response = new ResponseData(complianceService.getRecommendations(assetGroup, targetType)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + + } + + /** + * Gets the issue audit details.This request accepts + * annotationId,targetType,size as mandatory. If API receives + * annotationId,targetType,size as request parameter, API returns list of + * data source, audit date and status of that annotationId. searchText is used + * to match any text you are looking for. from and size are for pagination. + * + * @param request the request + * @return the issue audit + */ + + @RequestMapping(path = "/v1/issueauditlog", method = RequestMethod.POST) + public ResponseEntity getIssueAudit(@RequestBody IssueAuditLogRequest request) { + String issueId = request.getIssueId(); + String targetType = request.getTargetType(); + int from = request.getFrom(); + int size = request.getSize(); + String searchText = request.getSearchText(); + if (Strings.isNullOrEmpty(issueId) || Strings.isNullOrEmpty(targetType) || from < 0 || size <= 0) { + return ResponseUtils.buildFailureResponse(new Exception("IssueId/Targettype/from/size is Mandatory")); + } + ResponseWithOrder response = null; + try { + response = complianceService.getIssueAuditLog(issueId, targetType, from, size, searchText); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + + } + + /** + * Gets the resource details.assetGroup and resourceId are mandatory. API + * returns map details for given resourceId + * + * @param assetGroup name of the asset group + * @param resourceId the resource id + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/resourcedetails", method = RequestMethod.GET) + public ResponseEntity getResourceDetails(@RequestParam("ag") String assetGroup, + @RequestParam("resourceId") String resourceId) { + if (Strings.isNullOrEmpty(resourceId)) { + return ResponseUtils.buildFailureResponse(new Exception("assetGroup/resourceId is mandatory")); + } + ResponseData response = null; + try { + response = new ResponseData(complianceService.getResourceDetails(assetGroup, resourceId)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Close issues.ruleDetails expects ruleId,reason and userId, Api returns + * true if its successfully closes all issues in ES for that ruleId else + * false + * + * @param ruleDetails the rule details + * @return ResponseEntity + */ + @ApiOperation(httpMethod = "PUT", value = "Close Issues by Rule Details") + @RequestMapping(path = "/v1/issues/close-by-rule-id", method = RequestMethod.PUT) + @ResponseBody + + public ResponseEntity closeIssues( + @ApiParam(value = "Provide valid Rule Details ", required = true) @RequestBody(required = true) RuleDetails ruleDetails) { + Map response = complianceService.closeIssuesByRule(ruleDetails); + if (Integer.parseInt(response.get("status").toString()) == TWO_HUNDRED) { + return new ResponseEntity<>(response, HttpStatus.OK); + } else { + return new ResponseEntity<>(response, HttpStatus.FORBIDDEN); + } + } + + /** + * Adds the issue exception.issueException expects + * issueId,exceptionGrantedDate,exceptionEndDate and exceptionReason, API is + * for adding issue exception to the corresponding target type. + * + * @param issueException the issue exception + * @return ResponseEntity + */ + @ApiOperation(httpMethod = "POST", value = "Adding issue exception to the corresponding target type") + @RequestMapping(path = "/v1/issues/add-exception", method = RequestMethod.POST) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Added Issue Exception"), + @ApiResponse(code = 401, message = "You are not authorized to Add Issue Exception"), + @ApiResponse(code = 403, message = "Add Issue Exception is forbidden") }) + @ResponseBody + + public ResponseEntity addIssueException( + @ApiParam(value = "Provide Issue Exception Details", required = true) @RequestBody(required = true) IssueResponse issueException) { + try { + Boolean isExempted = complianceService.addIssueException(issueException); + if (isExempted) { + return ResponseUtils.buildSucessResponse("Successfully Added Issue Exception"); + } else { + return ResponseUtils.buildFailureResponse(new Exception("Failed in Adding Issue Exception")); + } + } catch (ServiceException exception) { + return ResponseUtils.buildFailureResponse(exception); + } + } + + /** + * Revoke issue exception. + * + * @param issueId the issue id + * @return ResponseEntity + */ + @ApiOperation(httpMethod = "POST", value = "Revoking issue exception to the corresponding target type") + @RequestMapping(path = "/v1/issues/revoke-exception", method = RequestMethod.POST) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Revoked Issue Exception"), + @ApiResponse(code = 401, message = "You are not authorized to Revoke Issue Exception"), + @ApiResponse(code = 403, message = "Revoke IssueException is forbidden") }) + @ResponseBody + + public ResponseEntity revokeIssueException( + @ApiParam(value = "Provide Issue Id", required = true) @RequestParam(required = true) String issueId) { + try { + Boolean isIssueExceptionRevoked = complianceService.revokeIssueException(issueId); + if (isIssueExceptionRevoked) { + return ResponseUtils.buildSucessResponse("Successfully Revoked Issue Exception"); + } else { + return ResponseUtils.buildFailureResponse(new Exception("Failed in Revoking Issue Exception")); + } + } catch (ServiceException exception) { + return ResponseUtils.buildFailureResponse(exception); + } + } + + /** + * Gets the non compliance policy by rule.request expects asset group and + * domain as mandatory.Api returns list of all the rules associated to that + * domain with compliance percentage/severity/ruleCategory etc fields. + * + * @param request the request + * @return ResponseEntity + */ + @RequestMapping(path = "/v1/noncompliancepolicy", method = RequestMethod.POST) + // @Cacheable(cacheNames="compliance",unless="#result.status==200") + // commenting to performance after refacoting + // @Cacheable(cacheNames="compliance",key="#request.key") + + public ResponseEntity getNonCompliancePolicyByRule(@RequestBody(required = false) Request request) { + String assetGroup = request.getAg(); + + Map filters = request.getFilter(); + + if (Strings.isNullOrEmpty(assetGroup) || MapUtils.isEmpty(filters) + || Strings.isNullOrEmpty(filters.get(DOMAIN))) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); + } + ResponseWithOrder response = null; + try { + response = (complianceService.getRulecompliance(request)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + + } + + /** + * Gets the policy details by application.asssetGroup and ruleId are + * mandatory. API returns total/application/compliant/compliantPercentage of + * the ruleId for given assetGroup. SearchText is used to match any text you + * are looking for + * + * @param assetGroup name of the asset group + * @param ruleId the rule id + * @param searchText the search text + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/policydetailsbyapplication", method = RequestMethod.GET) + // @Cacheable(cacheNames="compliance",unless="#result.status==200") + + public ResponseEntity getPolicydetailsbyApplication(@RequestParam("ag") String assetGroup, + @RequestParam("ruleId") String ruleId, + @RequestParam(name = "searchText", required = false) String searchText) { + if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(ruleId)) { + return ResponseUtils.buildFailureResponse(new Exception("Assetgroup/ruleId is mandatory")); + } + ResponseData response = null; + try { + + response = new ResponseData(complianceService.getRuleDetailsbyApplication(assetGroup, ruleId, searchText)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the policy details by environment.asssetGroup,application and ruleId + * are mandatory. API returns + * total/environment/compliant/compliantPercentage of the ruleId for given + * assetGroup and application. SearchText is used to match any text you are + * looking for + * + * @param assetGroup name of the asset group + * @param application name of the application + * @param ruleId the rule id + * @param searchText the search text + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/policydetailsbyenvironment", method = RequestMethod.GET) + + public ResponseEntity getpolicydetailsbyEnvironment(@RequestParam("ag") String assetGroup, + @RequestParam("application") String application, @RequestParam("ruleId") String ruleId, + @RequestParam(name = "searchText", required = false) String searchText) { + + if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(application) || Strings.isNullOrEmpty(ruleId)) { + return ResponseUtils.buildFailureResponse(new Exception("assetgroup/application/ruleId is mandatory")); + } + ResponseData response = null; + try { + response = new ResponseData(complianceService.getRuleDetailsbyEnvironment(assetGroup, ruleId, application, + searchText)); + + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * API returns details of the given ruleId. + * + * @param ruleId the rule id + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/policydescription", method = RequestMethod.GET) + + public ResponseEntity getPolicyDescription(@RequestParam("ruleId") String ruleId) { + + if (Strings.isNullOrEmpty(ruleId)) { + return ResponseUtils.buildFailureResponse(new Exception("ruleId Mandatory")); + } + PolicyDescription response = null; + try { + response = new PolicyDescription(complianceService.getRuleDescription(ruleId)); + + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * API returns the kernel version of the given instanceId if it is + * from web service. + * + * @param instanceId the instance id + * @return ResponseEntity + */ + @RequestMapping(path = "/v1/kernelcompliancebyinstanceid", method = RequestMethod.GET) + + public ResponseEntity getKernelComplianceByInstanceId(@RequestParam("instanceId") String instanceId) { + + if (Strings.isNullOrEmpty(instanceId)) { + return ResponseUtils.buildFailureResponse(new Exception("instanceId is mandatory")); + } + PolicyDescription output = null; + try { + output = new PolicyDescription(complianceService.getKernelComplianceByInstanceIdFromDb(instanceId)); + + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(output); + } + + /** + * API returns true if it updates the kernel version for the given + * instanceId successfully. + * + * @param kernelVersion the kernel version + * @return ResponseEntity + */ + + @ApiOperation(httpMethod = "PUT", value = "Update Kernel Version by InstanceId") + @RequestMapping(path = "/v1/update-kernel-version", method = RequestMethod.PUT) + @ResponseBody + + public ResponseEntity updateKernelVersion( + @ApiParam(value = "Provide valid Rule Details ", required = true) @RequestBody(required = true) KernelVersion kernelVersion) { + Map response = complianceService.updateKernelVersion(kernelVersion); + return new ResponseEntity<>(response, HttpStatus.OK); + } + + /** + * API returns overall compliance based on rule category and severity weightages + * for given asset group and domain. + * + * @param assetGroup - String + * @param domain - String + * @return ResponseEntity . + */ + @RequestMapping(path = "/v1/overallcompliance", method = RequestMethod.GET) + + public ResponseEntity getOverallCompliance(@RequestParam("ag") String assetGroup, + @RequestParam(name = "domain") String domain) { + if (Strings.isNullOrEmpty(assetGroup) || Strings.isNullOrEmpty(domain)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_GROUP_DOMAIN)); + } + DitributionDTO distribution = null; + try { + distribution = new DitributionDTO(complianceService.getOverallComplianceByDomain(assetGroup, domain)); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(distribution); + } + + /** + * API returns targetTypes for given asset group and domain based on + * project target types configurations. + * + * @param assetgroup the assetgroup + * @param domain the domain + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/targetType", method = RequestMethod.GET) + + public ResponseEntity getTargetType(@RequestParam("ag") String assetgroup, + @RequestParam(name = "domain", required = false) String domain) { + + if (Strings.isNullOrEmpty(assetgroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + ResourceTypeResponse response; + try { + + response = new ResourceTypeResponse(complianceService.getResourceType(assetgroup, domain)); + } catch (Exception e) { + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * API returns reason for violation along with other details for the + * given asset group and issueId. + * + * @param assetgroup the assetgroup + * @param issueId the issue id + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/policyViolationReason", method = RequestMethod.GET) + public ResponseEntity policyViolationReason(@RequestParam("ag") String assetgroup, + @RequestParam(name = "issueId") String issueId) { + + if (Strings.isNullOrEmpty(assetgroup) && Strings.isNullOrEmpty(issueId)) { + return ResponseUtils.buildFailureResponse(new Exception("AssetGroup/IssueId is Mandatory")); + } + PolicyViolationDetails response = null; + try { + response = complianceService.getPolicyViolationDetailsByIssueId(assetgroup, issueId); + } catch (ServiceException e) { + return complianceService.formatException(e); + } + return ResponseUtils.buildSucessResponse(response); + + } + + + /** + * API returns current kernel versions. + * + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/get-current-kernel-versions", method = RequestMethod.GET) + public ResponseEntity getCurrentKernelVersions() { + return ResponseUtils.buildSucessResponse(complianceService.getCurrentKernelVersions()); + } + + /** + * Adds the issues exception. + * + * @param issuesException the issues exception + * @return the response entity + */ + @ApiOperation(httpMethod = "POST", value = "Adding issue exception to the corresponding target type") + @RequestMapping(path = "/v2/issue/add-exception", method = RequestMethod.POST) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Added Issue Exception"), + @ApiResponse(code = 401, message = "You are not authorized to Add Issue Exception"), + @ApiResponse(code = 403, message = "Add Issue Exception is forbidden") }) + @ResponseBody + + public ResponseEntity addIssuesException( + @ApiParam(value = "Provide Issue Exception Details", required = true) @RequestBody(required = true) IssuesException issuesException) { + try { + + if (issuesException.getExceptionGrantedDate() == null) { + return ResponseUtils.buildFailureResponse(new Exception("Exception Granted Date is mandatory")); + } + if (issuesException.getExceptionEndDate() == null) { + return ResponseUtils.buildFailureResponse(new Exception("Exception End Date is mandatory")); + } + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + if(sdf.parse(sdf.format(issuesException.getExceptionGrantedDate())).before(sdf.parse(sdf.format(cal.getTime())))) { + return ResponseUtils.buildFailureResponse(new Exception("Exception Granted Date cannot be earlier date than today")); + } + if(sdf.parse(sdf.format(issuesException.getExceptionEndDate())).before(sdf.parse(sdf.format(cal.getTime())))) { + return ResponseUtils.buildFailureResponse(new Exception("Exception End Date cannot be earlier date than today")); + } + if(issuesException.getIssueIds().isEmpty()) { + return ResponseUtils.buildFailureResponse(new Exception("Atleast one issue id is required")); + } + return ResponseUtils.buildSucessResponse(complianceService.addMultipleIssueException(issuesException)); + } catch (ServiceException | ParseException exception) { + return ResponseUtils.buildFailureResponse(exception); + } + } + + /** + * Revoke issue exception. + * + * @param issueIds the issue ids + * @return ResponseEntity + */ + @ApiOperation(httpMethod = "POST", value = "Revoking issue exception to the corresponding target type") + @RequestMapping(path = "/v2/issue/revoke-exception", method = RequestMethod.POST) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully Revoked Issue Exception"), + @ApiResponse(code = 401, message = "You are not authorized to Revoke Issue Exception"), + @ApiResponse(code = 403, message = "Revoke IssueException is forbidden") }) + @ResponseBody + + public ResponseEntity revokeIssuesException( + @ApiParam(value = "Provide Issue Id", required = true) @RequestBody(required = true) RevokeIssuesException revokeIssuesException) { + try { + if(revokeIssuesException.getIssueIds().isEmpty()) { + return ResponseUtils.buildFailureResponse(new Exception("Atleast one issue id is required")); + } + return ResponseUtils.buildSucessResponse(complianceService.revokeMultipleIssueException(revokeIssuesException.getIssueIds())); + } catch (ServiceException exception) { + return ResponseUtils.buildFailureResponse(exception); + } + } +} diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/DownloadController.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/DownloadController.java index eddb772f6..80747d25b 100644 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/DownloadController.java +++ b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/DownloadController.java @@ -97,10 +97,6 @@ public class DownloadController implements Constants { @Autowired(required=false) private CertificateController certificateController; - /** The vulnerability controller. */ - @Autowired(required=false) - private VulnerabilityController vulnerabilityController; - /** The compliance controller. */ @Autowired private ComplianceController complianceController; diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/VulnerabilityController.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/VulnerabilityController.java deleted file mode 100644 index 222dd56c4..000000000 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/controller/VulnerabilityController.java +++ /dev/null @@ -1,786 +0,0 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -/* - * - */ -package com.tmobile.pacman.api.compliance.controller; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cache.annotation.CacheConfig; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.format.annotation.DateTimeFormat; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.common.base.Strings; -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.exception.ServiceException; -import com.tmobile.pacman.api.commons.utils.ResponseUtils; -import com.tmobile.pacman.api.compliance.domain.DitributionDTO; -import com.tmobile.pacman.api.compliance.domain.Request; -import com.tmobile.pacman.api.compliance.domain.ResponseData; -import com.tmobile.pacman.api.compliance.domain.ResponseWithCount; -import com.tmobile.pacman.api.compliance.domain.TrendNote; -import com.tmobile.pacman.api.compliance.domain.TrendRequest; -import com.tmobile.pacman.api.compliance.service.VulnerabilityService; - -/** - * The Class VulnerabilityController. - */ -@RestController -@PreAuthorize("@securityService.hasPermission(authentication, 'ROLE_USER')") -@CacheConfig(cacheNames = { "trends" }) -@ConditionalOnProperty(name="features.vulnerability.enabled") -public class VulnerabilityController implements Constants { - - private static final Logger LOGGER = LoggerFactory.getLogger(VulnerabilityController.class); - - @Autowired - private VulnerabilityService vulnerabilityService; - - /** - * Gets the vulnerabilities details. - * - * @param request the request - * @return ResponseEntity - */ - - @SuppressWarnings("unchecked") - @PostMapping(value = "/v1/vulnerabilities/detail") - public ResponseEntity getVulnerabilitiesDetails( - @RequestBody(required = true) Request request) { - - ResponseWithCount response; - String assetGroup = request.getAg(); - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception( - ASSET_MANDATORY)); - } - - int from = request.getFrom(); - int size = request.getSize(); - if (from < 0) { - return ResponseUtils.buildFailureResponse(new Exception( - "From should not be a negative number")); - - } - - String searchText = request.getSearchtext(); - - Map filter = request.getFilter(); - if (filter == null) { - filter = new HashMap<>(); - } - - try { - - List> masterDetailList = vulnerabilityService - .getVulnerabilitiesDetails(assetGroup, filter); - - masterDetailList = (List>) vulnerabilityService - .filterMatchingCollectionElements(masterDetailList, - searchText, true); - if (masterDetailList.isEmpty()) { - return ResponseUtils.buildSucessResponse(new ResponseWithCount( - new ArrayList>(), 0)); - } - - if (from >= masterDetailList.size()) { - return ResponseUtils.buildFailureResponse(new Exception( - "From exceeds the size of list")); - } - - int endIndex = 0; - - if ((from + size) > masterDetailList.size()) { - endIndex = masterDetailList.size(); - } else { - endIndex = from + size; - } - - if (endIndex == 0) { - endIndex = masterDetailList.size(); - } - - // from - inclusive, endIndex - exclusive - List> subDetailList = masterDetailList.subList( - from, endIndex); - - response = new ResponseWithCount(subDetailList, - masterDetailList.size()); - - } catch (Exception e) { - LOGGER.error(EXE_VULN , e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerability summary. - * - * @param assetGroup the asset group - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/vulnerabilities/summary", method = RequestMethod.GET) - public ResponseEntity getVulnerabilitysummary( - @RequestParam(name = "ag", required = true) String assetGroup, @RequestParam( name="severity",required=false) String severity) { - - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception( - ASSET_MANDATORY)); - } - if(Strings.isNullOrEmpty(severity)){ - severity = SEVERITY_LEVELS; - } - DitributionDTO response; - try { - response = new DitributionDTO( - vulnerabilityService.getVulnerabilitySummary(assetGroup,severity)); - } catch (Exception e) { - LOGGER.error("Exception in getVulnerabilitysummary ", e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerability by applications. - * - * @param assetGroup the asset group - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/vulnerabilities/summarybyapplication", method = RequestMethod.GET) - public ResponseEntity getVulnerabilityByApplications( - @RequestParam("ag") String assetGroup) { - - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception( - ASSET_MANDATORY)); - } - ResponseData response; - try { - response = new ResponseData( - vulnerabilityService.getVulnerabilityByAppAndEnv( - assetGroup, "tags.Application.keyword", "")); - } catch (Exception e) { - LOGGER.error("Exception in vulnerabilitybyapplications ",e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerabilities trend. - * - * @param request the request - * @return ResponseEntity - */ - - @PostMapping(value = "/v1/vulnerabilities/trend") - public ResponseEntity getVulnerabilitiesTrend( - @RequestBody(required = true) TrendRequest request) { - - Map response = new HashMap<>(); - String assetGroup = request.getAg(); - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception( - ASSET_MANDATORY)); - } - Date from = request.getFrom(); - Date to = request.getTo(); - Map filter = request.getFilter(); - try { - if (from == null && to == null) { - Calendar cal = Calendar.getInstance(); - cal.setTimeZone(TimeZone.getTimeZone("UTC")); - to = cal.getTime(); - cal.add(Calendar.DATE, NEG_THIRTY); - from = cal.getTime(); - } - response.put("ag", assetGroup); - List> trendList = vulnerabilityService - .getVulnerabilityTrend(assetGroup, filter, from, to); - response.put("trend", trendList); - } catch (Exception e) { - LOGGER.error(EXE_VULN , e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerability by environment. - * - * @param assetGroup the asset group - * @param application the application - * @return ResponseEntity - */ - - @RequestMapping(path = "/v1/vulnerabilities/summarybyenvironment", method = RequestMethod.GET) - public ResponseEntity getVulnerabilityByEnvironment( - @RequestParam("ag") String assetGroup, - @RequestParam(name = "application", required = false) String application) { - - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception( - ASSET_MANDATORY)); - } - ResponseData response; - try { - response = new ResponseData( - vulnerabilityService - .getVulnerabilityByAppAndEnv(assetGroup, - "tags.Environment.keyword", application)); - } catch (Exception e) { - LOGGER.error("Exception in vulnerabilitybyenvironment ", e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerability distribution. - * - * @param assetGroup the asset group - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/vulnerabilities/distribution", method = RequestMethod.GET) - public ResponseEntity getVulnerabilityDistribution( - @RequestParam("ag") String assetGroup) { - - if (Strings.isNullOrEmpty(assetGroup)) { - return ResponseUtils.buildFailureResponse(new Exception( - ASSET_MANDATORY)); - } - ResponseData response; - try { - response = new ResponseData( - vulnerabilityService - .getVulnerabilitiesDistribution(assetGroup)); - } catch (Exception e) { - LOGGER.error("Exception in getVulnerabilityDistribution ", e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerabilitysummary by resource id. - * - * @param resourceId the resource id - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/vulnerabilities/summary/{resourceId}", method = RequestMethod.GET) - public ResponseEntity getVulnerabilitysummaryByResourceId( - @PathVariable(name = "resourceId", required = true) String resourceId) { - - DitributionDTO response; - try { - response = new DitributionDTO( - vulnerabilityService - .getVulnerabilitysummaryByResourceId(resourceId)); - } catch (Exception e) { - LOGGER.error("Exception in getVulnerabilitysummary ", e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerability details by resource id. - * - * @param resourceId the resource id - * @param searchtext the searchtext - * @param from the from - * @param size the size - * @return ResponseEntity - */ - @SuppressWarnings("unchecked") - @RequestMapping(path = "/v1/vulnerabilities/detail/{resourceId}", method = RequestMethod.GET) - public ResponseEntity getVulnerabilityDetailsByResourceId( - @PathVariable(name = "resourceId", required = true) String resourceId, - @RequestParam(name = "searchtext", required = false) String searchtext, - @RequestParam(name = "from", required = false) Integer from, - @RequestParam(name = "size", required = false) Integer size) { - - Integer iFrom = from == null ? 0 : from; - Integer iSize = size == null ? 0 : size; - - ResponseWithCount response; - try { - List> masterDetailList = vulnerabilityService - .getVulnerabilityDetailsByResourceId(resourceId); - masterDetailList = (List>) vulnerabilityService - .filterMatchingCollectionElements(masterDetailList, - searchtext, true); - if (masterDetailList.isEmpty()) { - return ResponseUtils.buildSucessResponse(new ResponseWithCount( - new ArrayList>(), 0)); - } - - if (iFrom >= masterDetailList.size()) { - return ResponseUtils.buildFailureResponse(new Exception( - "From exceeds the size of list")); - } - - int endIndex = 0; - - if (iSize == 0) { - iSize = masterDetailList.size(); - } - - if ((iFrom + iSize) > masterDetailList.size()) { - endIndex = masterDetailList.size(); - } else { - endIndex = iFrom + iSize; - } - - List> subDetailList = masterDetailList.subList( - iFrom, endIndex); - - response = new ResponseWithCount(subDetailList, - masterDetailList.size()); - - } catch (Exception e) { - LOGGER.error(EXE_VULN , e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the vulnerability distribution summary. - * - * @param assetGroup the asset group - * @param severity the severity - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/vulnerabilities/distributionsummary", method = RequestMethod.GET) - public ResponseEntity getVulnerabilityDistributionSummary( - @RequestParam("ag") String assetGroup, - @RequestParam(name = "severity", required = false) String severity) { - - return ResponseUtils.buildSucessResponse(vulnerabilityService - .getVulnerabilityDistributionSummary(assetGroup, severity)); - } - - /** - * Gets the aging distribution summary. - * - * @param assetGroup the asset group - * @param severity the severity - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/vulnerabilities/aging/distributionsummary", method = RequestMethod.GET) - public ResponseEntity getAgingDistributionSummary( - @RequestParam("ag") String assetGroup, - @RequestParam(name = "severity", required = false) String severity) { - return ResponseUtils.buildSucessResponse(vulnerabilityService - .getAgingDistributionSummary(assetGroup, severity)); - } - - /** - * Gets the aging summary. - * - * @param assetGroup the asset group - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/vulnerabilities/aging/summary", method = RequestMethod.GET) - public ResponseEntity getAgingSummary( - @RequestParam("ag") String assetGroup) { - return ResponseUtils.buildSucessResponse(vulnerabilityService - .getAgingSummary(assetGroup)); - } - - /** - * Gets the vulnerability by qid. - * - * @param qid the qid - * @return ResponseEntity - */ - @RequestMapping(path = "/v1/vulnerabilities/qids", method = RequestMethod.GET) - public ResponseEntity getVulnerabilityByQid( - @RequestParam("qid") String qid) { - return ResponseUtils.buildSucessResponse(vulnerabilityService - .getVulnerabilityByQid(qid)); - } - - /** - * Gets the distribution summary by vuln type. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary by vuln type - */ - @RequestMapping(path = "/v1/vulnerabilities/distribution-vulntype", method = RequestMethod.GET) - public ResponseEntity getDistributionSummaryByVulnType( - @RequestParam("ag") String assetGroup, @RequestParam( name="severity",required=false) String severity) { - - Map response = new HashMap<>(); - - List> distributionList = new ArrayList<>(); - try { - distributionList = vulnerabilityService.getDistributionSummaryByVulnType(assetGroup, severity); - } catch (DataException e) { - LOGGER.error("Error in getDistributionSummaryByVulnType",e); - return ResponseUtils.buildFailureResponse(e); - } - - response.put(DISTRIBUTION, distributionList); - return ResponseUtils.buildSucessResponse(response); - - } - - /** - * Gets the distribution summary by infra type. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary by infra type - */ - @RequestMapping(path = "/v1/vulnerabilities/distribution-infra", method = RequestMethod.GET) - public ResponseEntity getDistributionSummaryByInfraType( - @RequestParam("ag") String assetGroup, @RequestParam( name="severity",required=false) String severity) { - Map response = new HashMap<>(); - - List> distributionList = new ArrayList<>(); - try { - distributionList = vulnerabilityService.getDistributionSummaryByInfraType(assetGroup, severity); - } catch (ServiceException e) { - LOGGER.error("Error in getDistributionSummaryByInfraType",e); - return ResponseUtils.buildFailureResponse(e); - } - response.put(DISTRIBUTION, distributionList); - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the distribution summary by env. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary by env - */ - @RequestMapping(path = "/v1/vulnerabilities/distribution-env", method = RequestMethod.GET) - public ResponseEntity getDistributionSummaryByEnv( - @RequestParam("ag") String assetGroup, @RequestParam( name="severity",required=false) String severity) { - Map response = new HashMap<>(); - - List> distributionList = new ArrayList<>(); - try { - distributionList = vulnerabilityService.getDistributionSummaryByEnv(assetGroup, severity); - } catch (ServiceException e) { - LOGGER.error("Error in getDistributionSummaryByEnv",e); - return ResponseUtils.buildFailureResponse(e); - } - response.put(DISTRIBUTION, distributionList); - return ResponseUtils.buildSucessResponse(response); - } - - - /** - * Gets the remediation actions summary. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the remediation actions summary - */ - @RequestMapping(path = "/v1/vulnerabilities/remediations/summary", method = RequestMethod.GET) - public ResponseEntity getRemediationActionsSummary( - @RequestParam("ag") String assetGroup, @RequestParam( name="severity",required=false) String severity) { - Map response = new HashMap<>(); - - List> remediationList = new ArrayList<>(); - try { - remediationList = vulnerabilityService.getRemediationActionsSummary(assetGroup, severity); - } catch (DataException e) { - LOGGER.error("Error in getRemediationActionsSummary",e); - return ResponseUtils.buildFailureResponse(e); - } - - response.put("actions", remediationList); - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the highest lowest performers. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the highest lowest performers - */ - @RequestMapping(path = "/v1/vulnerabilities/performers", method = RequestMethod.GET) - public ResponseEntity getHighestLowestPerformers( - @RequestParam("ag") String assetGroup, @RequestParam( name="severity",required=false) String severity) { - Map response = new HashMap<>(); - - List> responseList = new ArrayList<>(); - Map directorData = vulnerabilityService.getHighestLowestPerformers(assetGroup, severity,"org"); - Set keys = directorData.keySet(); - String[] keysArray = keys.toArray(new String[keys.size()]); - - if(keysArray.length >= 10 ) { - - Map info = new HashMap<>(); - info.put(CATEGORY, HIGHEST); - List< Map> directorList = new ArrayList<>(); - - for(int i=0; i director = new HashMap<>(); - director.put(keysArray[i], directorData.get(keysArray[i])); - directorList.add(director); - } - info.put(DIRECTORS, directorList); - responseList.add(info); - - info = new HashMap<>(); - info.put(CATEGORY, "Lowest"); - directorList = new ArrayList<>(); - - for(int i=keysArray.length-Constants.ONE; i>keysArray.length-Constants.SIX && i>=0;i--) { - Map director = new HashMap<>(); - director.put(keysArray[i], directorData.get(keysArray[i])); - directorList.add(director); - } - info.put(DIRECTORS, directorList); - responseList.add(info); - } else { - - if(keysArray.length % 2 == 0) { - Map info = new HashMap<>(); - info.put(CATEGORY, HIGHEST); - List< Map> directorList = new ArrayList<>(); - - for(int i=0; i director = new HashMap<>(); - director.put(keysArray[i], directorData.get(keysArray[i])); - directorList.add(director); - } - info.put(DIRECTORS, directorList); - responseList.add(info); - - } else { - - Map info = new HashMap<>(); - info.put(CATEGORY, HIGHEST); - List< Map> directorList = new ArrayList<>(); - - for(int i=0; i<(keysArray.length/2)+1;i++) { - Map director = new HashMap<>(); - director.put(keysArray[i], directorData.get(keysArray[i])); - directorList.add(director); - } - info.put(DIRECTORS, directorList); - responseList.add(info); - } - - Mapinfo = new HashMap<>(); - info.put(CATEGORY, "Lowest"); - List< Map> directorList = new ArrayList<>(); - - for(int i=keysArray.length-Constants.ONE; i>keysArray.length/2 && i>=0;i--) { - Map director = new HashMap<>(); - director.put(keysArray[i], directorData.get(keysArray[i])); - directorList.add(director); - } - info.put(DIRECTORS, directorList); - responseList.add(info); - } - response.put("response", responseList); - return ResponseUtils.buildSucessResponse(response); - } - - /** - * Gets the highest lowest performers. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the highest lowest performers - */ - @RequestMapping(path = "/v2/vulnerabilities/performers", method = RequestMethod.GET) - public ResponseEntity getHighestLowestPerformers( - @RequestParam("ag") String assetGroup, @RequestParam( name="severity",required=false) String severity,@RequestParam( name="type") PerfType type) { - Map response = new HashMap<>(); - - Map perfData = vulnerabilityService.getHighestLowestPerformers(assetGroup, severity,type.name()); - List< Map> perfList = new ArrayList<>(); - Map info = new HashMap<>(); - String typeName = type.name(); - switch(typeName){ - case "org": - info.put(CATEGORY, "Director"); - break; - case "application": - info.put(CATEGORY, "Application"); - break; - case "environment": - info.put(CATEGORY, "Environment"); - break; - } - - if(perfData.size() > 1) { - Set keys = perfData.keySet(); - String[] keysArray = keys.toArray(new String[keys.size()]); - - for(int i=0; i director = new HashMap<>(); - director.put(keysArray[i], perfData.get(keysArray[i])); - perfList.add(director); - } - } - - info.put("data", perfList); - - response.put("response", info); - return ResponseUtils.buildSucessResponse(response); - } - - - /** - * Gets the vulnerability trend. - * - * @param request the request - * @return the vulnerability trend - */ - @Cacheable(cacheNames = "trends", key = "#request.vulnCacheKey" ,unless="#result.statusCodeValue!=200" ) - @RequestMapping(path = "/v1/vulnerabilities/trend/open-new", method = RequestMethod.POST) - public ResponseEntity getVulnerabilityTrend( - @RequestBody(required = true) TrendRequest request) { - - String ag = request.getAg(); - if (Strings.isNullOrEmpty(ag)) { - return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); - } - Date from = request.getFrom(); - if(from == null){ - Calendar cal = Calendar.getInstance(); - cal.setTimeZone(TimeZone.getTimeZone("UTC")); - cal.add(Calendar.DATE, NEG_THIRTY); - from = cal.getTime(); - } - - Map filter = request.getFilter(); - String severity = SEVERITY_LEVELS; - if(filter!=null){ - severity = filter.get("severity"); - if(severity==null){ - severity =SEVERITY_LEVELS; - } - } - - Map response = new HashMap<>(); - try { - List< Map> trendList = vulnerabilityService.getVulnerabilityNewOpenTrend(ag,severity,from); - response.put("trend",trendList); - return ResponseUtils.buildSucessResponse(response); - } catch (Exception e) { - return ResponseUtils.buildFailureResponse(e); - } - - } - - /** - * Creates the trend annotation. - * - * @param request the request - * @return the response entity - */ - @RequestMapping(path = "/v1/vulnerabilities/trend/notes", method = RequestMethod.POST) - public ResponseEntity createTrendAnnotation( @RequestBody(required = true) TrendNote request) { - - try { - if(vulnerabilityService.createTrendAnnotation(request)) { - return ResponseUtils.buildSucessResponse("Annotation created"); - } else { - return ResponseUtils.buildFailureResponse(new Exception("Annotation creation failed")); - } - } catch (JsonProcessingException e) { - LOGGER.error("Error in createTrendAnnotation ",e); - return ResponseUtils.buildFailureResponse(e); - } - } - - /** - * Gets the trend annotations. - * - * @param assetGroup the asset group - * @param from the from - * @return the trend annotations - */ - @RequestMapping(path = "/v1/vulnerabilities/trend/notes", method = RequestMethod.GET) - public ResponseEntity getTrendAnnotations(@RequestParam("ag") String assetGroup, @RequestParam( name="from",required=false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date from) { - - if(from == null){ - Calendar cal = Calendar.getInstance(); - cal.setTimeZone(TimeZone.getTimeZone("UTC")); - cal.add(Calendar.DATE, NEG_THIRTY); - from = cal.getTime(); - } - Map notes = new HashMap<>(); - try { - notes .put("notes", vulnerabilityService.getTrendAnnotations(assetGroup, from)); - } catch (DataException e) { - LOGGER.error("Error in getTrendAnnotations ",e); - return ResponseUtils.buildFailureResponse(e); - } - return ResponseUtils.buildSucessResponse(notes); - - } - - /** - * Delete trend annotation. - * - * @param noteId the note id - * @return the response entity - */ - @RequestMapping(path = "/v1/vulnerabilities/trend/notes/{noteId}", method = RequestMethod.DELETE) - public ResponseEntity deleteTrendAnnotation(@PathVariable(name="noteId", required = true) String noteId) { - - if(vulnerabilityService.deleteTrendAnnotation(noteId)) { - return ResponseUtils.buildSucessResponse("Annotation Deleted"); - } else { - return ResponseUtils.buildFailureResponse(new Exception("Annotation deletion failed")); - } - } -} - -enum PerfType { - org,application,environment -} diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImpl.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImpl.java index 422df80a8..c9deeffa9 100644 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImpl.java +++ b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImpl.java @@ -132,10 +132,6 @@ public class ComplianceRepositoryImpl implements ComplianceRepository, Constants @Autowired private AssetServiceClient assetServiceClient; - /** The vulnerability repository. */ - @Autowired - private VulnerabilityRepository vulnerabilityRepository; - /** The filter repository. */ @Autowired private FilterRepository filterRepository; @@ -1308,7 +1304,7 @@ public JsonArray getRuleDetailsByEnvironmentFromES(String assetGroup, String rul body = body + "]"; body = body + ",\"minimum_should_match\":1"; } - body = body + "}},\"aggs\":{\"NAME\":{\"terms\":{\"field\":\"tags.Environment.keyword.keyword\",\"size\":1000000}}}}"; + body = body + "}},\"aggs\":{\"NAME\":{\"terms\":{\"field\":\"tags.Environment.keyword\",\"size\":1000000}}}}"; requestBody = new StringBuilder(body); }else{ diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityRepository.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityRepository.java deleted file mode 100644 index 4f5033886..000000000 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityRepository.java +++ /dev/null @@ -1,1651 +0,0 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.compliance.repository; - -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.PostConstruct; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.entity.ContentType; -import org.apache.http.nio.entity.NStringEntity; -import org.apache.http.util.EntityUtils; -import org.elasticsearch.client.Response; -import org.elasticsearch.client.RestClient; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Repository; -import org.springframework.util.CollectionUtils; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Strings; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; -import com.tmobile.pacman.api.commons.repo.PacmanRdsRepository; -import com.tmobile.pacman.api.commons.utils.CommonUtils; -import com.tmobile.pacman.api.commons.utils.PacHttpUtils; -import com.tmobile.pacman.api.compliance.domain.TrendNote; - -/** - * This is the Repository layer which makes call to ElasticSearch. - */ -@Repository -public class VulnerabilityRepository implements Constants { - - @Value("${elastic-search.host}") - private String esHost; - @Value("${elastic-search.port}") - private int esPort; - @Value("${elastic-search.update-host}") - private String updateESHost; - @Value("${elastic-search.update-port}") - private int updateESPort; - - private static final String PROTOCOL = "http"; - - private String esUrl; - - @Autowired - private ElasticSearchRepository elasticSearchRepository; - - @Autowired - private PacmanRdsRepository rdsRepository; - - private static final Log LOGGER = LogFactory.getLog(VulnerabilityRepository.class); - - private RestClient restClient; - - /** - * Initializes the esUrl. - */ - @PostConstruct - void init() { - esUrl = PROTOCOL + "://" + esHost + ":" + esPort; - } - - /** - * Gets the all vulnerabilities. - * - * @param vulnAssetsAffectedQids the vuln assets affected qids - * @return the all vulnerabilities - * @throws DataException the DataException - */ - public List> getAllVulnerabilities( - List vulnAssetsAffectedQids) throws DataException { - - List> results = new ArrayList<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl) - .append("/qualys-kb/kb/_search"); - String responseJson = ""; - try { - for (int index = 0; index <= (vulnAssetsAffectedQids.size() / THOUSAND_TWENTY_FOUR); index++) { - int from = index * THOUSAND_TWENTY_FOUR; - int to = from + THOUSAND_TWENTY_FOUR; - if (vulnAssetsAffectedQids.size() < to) { - to = vulnAssetsAffectedQids.size(); - } - StringBuilder requestBody = new StringBuilder( - "{\"size\":10000,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"qid\":"); - requestBody.append(vulnAssetsAffectedQids.subList(from, to)); - requestBody.append("}}"); - requestBody.append("]}}}"); - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - elasticSearchRepository.processResponseAndSendTheScrollBack( - responseJson, results); - } - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilityData", e); - throw new DataException(); - } - return results; - } - - /** - * Gets the assets affected count. - * - * @param assetGroup the asset group - * @param filter the filter - * @param parentType the parent type - * @return the assets affected count - */ - public Map getAssetsAffectedCount(String assetGroup, - Map filter, String parentType) { - - Map assetsAffectedCount = new HashMap<>(); - Map filterForQuery = new HashMap<>(); - if (!CollectionUtils.isEmpty(filter)) { - filterForQuery = new HashMap<>(filter); - } - - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(VULN_INFO); - urlToQuery.append("/").append(SEARCH); - String responseJson = ""; - try { - String severity = SEVERITY_LEVELS; - if (filterForQuery.containsKey(SEVEITY_LEVEL)) { - severity = filterForQuery.get(SEVEITY_LEVEL); - filterForQuery.remove(SEVEITY_LEVEL); - } - - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel\":["); - requestBody.append(severity + "]}},"); - requestBody - .append("{\"has_parent\":{\"parent_type\":\"" - + parentType - + "\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}"); - - if (!filterForQuery.isEmpty()) { - requestBody.append(",{\"match\":"); - requestBody.append(new GsonBuilder().create().toJson( - filterForQuery)); - requestBody.append("}"); - } - requestBody - .append("]}}}}]}},\"aggs\":{\"qid\":{\"terms\":{\"field\":\"qid\",\"size\":"); - requestBody.append(ES_PAGE_SIZE); - requestBody.append("}}}}"); - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getAssetsAffectedCount from ES", e); - } - JsonParser jsonParser = new JsonParser(); - if (StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray outerBuckets = aggsJson.getAsJsonObject("qid") - .getAsJsonArray(BUCKETS); - if (outerBuckets.size() > 0) { - for (int i = 0; i < outerBuckets.size(); i++) { - assetsAffectedCount.put( - String.valueOf(outerBuckets.get(i) - .getAsJsonObject().get("key").getAsLong()), - outerBuckets.get(i).getAsJsonObject() - .get(DOC_COUNT).getAsLong()); - } - } - } - return assetsAffectedCount; - } - - /** - * Gets the vulnerabily across app and env. - * - * @param assetGroup the asset group - * @param filter the filter - * @param application the application - * @param parentType the parent type - * @param severity the severity - * @return the vulnerabily across app and env - * @throws Exception the exception - */ - public List> getVulnerabilyAcrossAppAndEnv( - String assetGroup, String filter, String application, - String parentType, String severity) throws Exception { - - List> vulnApplications = new ArrayList<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(parentType); - urlToQuery.append("/").append(SEARCH); - - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}"); - if (StringUtils.isNotEmpty(application)) { - requestBody.append(",{\"match\":{\"tags.Application.keyword\":\""); - requestBody.append(application); - requestBody.append("\"}}"); - } - requestBody.append("]}},\"aggs\":{\"apps\":{\"terms\":{\"field\":\""); - requestBody.append(filter); - requestBody - .append("\",\"size\":10000},\"aggs\":{\"vulns\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\""); - if (StringUtils.isNotEmpty(severity)) { - requestBody.append("S").append(severity); - requestBody.append("\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"term\":{\"severitylevel\":") - .append(severity).append("}}]}}"); - } else { - requestBody - .append("S3\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":3}},{\"match\":{\"latest\":true}}]}},\"S4\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":4}},{\"match\":{\"latest\":true}}]}},\"S5\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":5}},{\"match\":{\"latest\":true}}]}}"); - } - requestBody.append("}}}}}}}}}"); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilyAcrossAppAndEnv from ES", e); - throw e; - } - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray outerBuckets = aggsJson.getAsJsonObject("apps") - .getAsJsonArray(BUCKETS); - if (outerBuckets.size() > 0) { - for (int i = 0; i < outerBuckets.size(); i++) { - String appName = outerBuckets.get(i).getAsJsonObject() - .get("key").getAsString(); - List> severityInfo = getSeverityInfo( - outerBuckets.get(i).getAsJsonObject() - .getAsJsonObject(VULN) - .getAsJsonObject("NAME") - .getAsJsonObject(BUCKETS), severity); - Map applicationInfo = new HashMap<>(); - if (filter.equals(TAGS_APPS)) { - applicationInfo.put(APPS, appName); - } else { - applicationInfo.put("environment", appName); - } - applicationInfo.put("severityinfo", severityInfo); - if (StringUtils.isEmpty(severity)) { - applicationInfo.put( - VULNEREBILITIES, - Integer.valueOf(severityInfo.get(0).get(COUNT) - .toString()) - + Integer.valueOf(severityInfo.get(1) - .get(COUNT).toString()) - + Integer.valueOf(severityInfo.get(2) - .get(COUNT).toString())); - } else { - applicationInfo.put( - VULNEREBILITIES, - Integer.valueOf(severityInfo.get(0).get(COUNT) - .toString())); - } - vulnApplications.add(applicationInfo); - } - } - return vulnApplications; - } - - /** - * Gets the vulnerability trend. - * - * @param assetGroup the asset group - * @param filter the filter - * @param from the from - * @param to the to - * @return the vulnerability trend - * @throws Exception the exception - */ - public List> getVulnerabilityTrend(String assetGroup, - Map filter, Date from, Date to) throws Exception { - List> vulnTrendList = new ArrayList<>(); - try { - - StringBuilder urlToQuery = new StringBuilder(esUrl) - .append("/assetgroup_stats/count_vuln/_search"); - StringBuilder request = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"ag.keyword\":" - + "\"" + assetGroup + "\"}}"); - - if (filter != null) { - Set filterkeys = filter.keySet(); - if (filterkeys.contains(TAGS_APPS)) { - request.append(",{ \"match\": {\"tags.Application.keyword\": " - + "\"" - + filter.get(TAGS_APPS) - + "\"}}"); - } - if (filterkeys.contains("tags.Environment.keyword")) { - request.append(",{ \"match\": {\"tags.Environment.keyword\": " - + "\"" - + filter.get("tags.Environment.keyword") - + "\"}}"); - } - } - String gte = null; - String lte = null; - - if (from != null) { - gte = "\"gte\": \"" - + new SimpleDateFormat("yyyy-MM-dd").format(from) - + "\""; - } - if (to != null) { - lte = "\"lte\": \"" - + new SimpleDateFormat("yyyy-MM-dd").format(to) + "\""; - } - - if (gte != null && lte != null) { - request.append(",{ \"range\": {\"date\": {" + gte + "," + lte - + "}}}"); - } else if (gte != null) { - request.append(",{ \"range\": {\"date\": {" + gte + "}}}"); - } else { - request.append(",{ \"range\": {\"date\": {" + lte + "}}}"); - } - - request.append("]}},\"aggs\": {\"date\": {\"date_histogram\": {\"field\": \"date\",\"interval\": \"day\",\"format\": \"yyyy-MM-dd\"},\"aggs\": {\"vulns\": {\"sum\": {\"field\": \"count\"}}}}}}"); - - String responseJson = PacHttpUtils.doHttpPost( - urlToQuery.toString(), request.toString()); - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonArray buckets = resultJson.get(AGGREGATIONS) - .getAsJsonObject().get("date").getAsJsonObject() - .get(BUCKETS).getAsJsonArray(); - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - Map trend = new HashMap<>(); - JsonObject bucket = (JsonObject) buckets.get(i); - String date = bucket.get("key_as_string").getAsString(); - Long count = bucket.get(VULN).getAsJsonObject() - .get(VALUE).getAsLong(); - trend.put("date", date); - trend.put(COUNT, count); - vulnTrendList.add(trend); - } - } - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilityTrend from ES", e); - throw e; - } - - return vulnTrendList; - } - - /** - * Gets the vulnerabilities distribution. - * - * @param assetGroup the asset group - * @param parentType the parent type - * @return the vulnerabilities distribution - * @throws Exception the exception - */ - public List> getVulnerabilitiesDistribution( - String assetGroup, String parentType) throws Exception { - List> vulnDistributions = new ArrayList<>(); - - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(parentType).append("/_search"); - String requestBody = "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}]}},\"aggs\":{\"apps\":{\"terms\":{\"field\":\"tags.Application.keyword\",\"size\":1000}," - + "\"aggs\":{\"envs\":{\"terms\":{\"field\":\"tags.Environment.keyword\",\"size\":1000},\"aggs\":{\"vulns\":{\"children\":{\"type\":\"vulninfo\"}," - + "\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\"S3\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":3}},{\"match\":{\"latest\":true}}]}},\"S4\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":4}},{\"match\":{\"latest\":true}}]}},\"S5\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":5}},{\"match\":{\"latest\":true}}]}}}}}}}}}}}}}"; - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody); - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilitiesDistribution from ES", e); - throw e; - } - - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray outerBuckets = aggsJson.getAsJsonObject("apps") - .getAsJsonArray(BUCKETS); - if (outerBuckets.size() > 0) { - for (int i = 0; i < outerBuckets.size(); i++) { - Map applist = new HashMap<>(); - String appName = outerBuckets.get(i).getAsJsonObject() - .get("key").getAsString(); - JsonArray envs = outerBuckets.get(i).getAsJsonObject() - .getAsJsonObject("envs").getAsJsonArray(BUCKETS); - List> envDetails = new ArrayList<>(); - if (envs.size() > 0) { - for (int j = 0; j < envs.size(); j++) { - String envName = envs.get(j).getAsJsonObject() - .get("key").getAsString(); - List> severityInfo = getSeverityInfo( - envs.get(j).getAsJsonObject() - .getAsJsonObject(VULN) - .getAsJsonObject("NAME") - .getAsJsonObject(BUCKETS), null); - Map envSeverity = new HashMap<>(); - envSeverity.put("environment", envName); - envSeverity.put(SEVERITY_INFO, severityInfo); - envSeverity.put( - VULNEREBILITIES, - Integer.valueOf(severityInfo.get(0) - .get(COUNT).toString()) - + Integer.valueOf(severityInfo.get(ONE) - .get(COUNT).toString()) - + Integer.valueOf(severityInfo.get(TWO) - .get(COUNT).toString())); - envDetails.add(envSeverity); - } - } - applist.put(APPS, appName); - applist.put("applicationInfo", envDetails); - vulnDistributions.add(applist); - } - } - return vulnDistributions; - } - - /** - * Gets the vulnerabilitysummary by resource id. - * - * @param resourceId the resource id - * @return the vulnerabilitysummary by resource id - */ - public Map getVulnerabilitysummaryByResourceId( - String resourceId) { - - String index = "aws_onpremserver,aws_ec2"; - Map vulnSummary = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - index); - urlToQuery.append("/").append(VULN_INFO); - urlToQuery.append("/").append(SEARCH); - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"_resourceid.keyword\":\""); - requestBody.append(resourceId); - requestBody - .append("\"}},{\"terms\": {\"severitylevel\": [3,4,5]}}]}},\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\"S3\":{\"term\":{\"severitylevel\":\"3\"}},\"S4\":{\"term\":{\"severitylevel\":\"4\"}},\"S5\":{\"term\":{\"severitylevel\":\"5\"}}}}}}}"); - - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error( - "Error in getVulnerabilitysummaryByResourceId from ES", e); - } - JsonParser jsonParser = new JsonParser(); - if (StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get( - "hits").toString()); - vulnSummary.put(TOTAL, hitsJson.get(TOTAL).getAsLong()); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - try { - vulnSummary.put( - SEVERITY_INFO, - getSeverityInfo(aggsJson.getAsJsonObject("NAME") - .getAsJsonObject(BUCKETS), null)); - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilitysummaryByResourceId ", e); - } - } - return vulnSummary; - - } - - /** - * Gets the vulnerability details by resource id. - * - * @param resourceId the resource id - * @return the vulnerability details by resource id - */ - public List> getVulnerabilityDetailsByResourceId( - String resourceId) { - - List> results = new ArrayList<>(); - Long totalDocs = (Long) getVulnerabilitysummaryByResourceId(resourceId) - .get(TOTAL); - StringBuilder urlToQueryBuffer = new StringBuilder(esUrl).append("/") - .append("aws_ec2,aws_onpremserver"); - urlToQueryBuffer.append("/").append(VULN_INFO); - urlToQueryBuffer.append("/").append(SEARCH).append(SCROLL) - .append(ES_PAGE_SCROLL_TTL); - - String urlToQuery = urlToQueryBuffer.toString(); - String urlToScroll = new StringBuilder(esUrl).append("/") - .append(SEARCH).append(SLASH_SCROLL).toString(); - - StringBuilder requestBody = new StringBuilder( - "{\"size\":10000,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel\":[3,4,5]}},{\"match\":{\"_resourceid.keyword\":\""); - requestBody.append(resourceId); - requestBody.append("\"}}]}}}"); - String request = requestBody.toString(); - String scrollId = null; - for (int index = 0; index <= (totalDocs / ES_PAGE_SIZE); index++) { - try { - if (!Strings.isNullOrEmpty(scrollId)) { - request = elasticSearchRepository.buildScrollRequest( - scrollId, ES_PAGE_SCROLL_TTL); - urlToQuery = urlToScroll; - } - String responseDetails = PacHttpUtils.doHttpPost(urlToQuery, - request); - scrollId = elasticSearchRepository - .processResponseAndSendTheScrollBack(responseDetails, - results); - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilityDetailsByResourceId", e); - } - } - return results; - } - - /** - * Gets the severity info. - * - * @param countBucket the count bucket - * @param severity the severity - * @return the severity info - * @throws DataException the data exception - */ - private List> getSeverityInfo(JsonObject countBucket, - String severity){ - - List> severityInfo = new ArrayList<>(); - if (StringUtils.isEmpty(severity)) { - Map severity3 = new HashMap<>(); - severity3.put(SEVEITY_LEVEL, THREE); - severity3.put(SEVERITY, "S3"); - severity3.put(COUNT, - countBucket.getAsJsonObject("S3").get(DOC_COUNT) - .getAsLong()); - severity3.put(VULN_COUNT, countBucket - .getAsJsonObject("S3").get(DOC_COUNT).getAsLong()); - Map severity4 = new HashMap<>(); - severity4.put(SEVEITY_LEVEL, FOUR); - severity4.put(SEVERITY, "S4"); - severity4.put(COUNT, - countBucket.getAsJsonObject("S4").get(DOC_COUNT) - .getAsLong()); - severity4.put(VULN_COUNT, countBucket - .getAsJsonObject("S4").get(DOC_COUNT).getAsLong()); - Map severity5 = new HashMap<>(); - severity5.put(SEVEITY_LEVEL, FIVE); - severity5.put(COUNT, - countBucket.getAsJsonObject("S5").get(DOC_COUNT) - .getAsLong()); - severity5.put(SEVERITY, "S5"); - severity5.put(VULN_COUNT, countBucket - .getAsJsonObject("S5").get(DOC_COUNT).getAsLong()); - severityInfo.add(severity3); - severityInfo.add(severity4); - severityInfo.add(severity5); - } else { - Map severityMap = new HashMap<>(); - severityMap.put(SEVEITY_LEVEL, Integer.valueOf(severity)); - severityMap.put(COUNT, countBucket - .getAsJsonObject("S" + severity).get(DOC_COUNT) - .getAsLong()); - severityMap.put(SEVERITY, "S" + severity); - severityMap.put(VULN_COUNT, - countBucket.getAsJsonObject("S" + severity) - .get(DOC_COUNT).getAsLong()); - severityInfo.add(severityMap); - } - - return severityInfo; - } - - /** - * Fetch exec director apps. - * - * @return the list - * @throws Exception the exception - */ - public List> fetchExecDirectorApps() throws Exception { - Map mustFilter = new HashMap<>(); - mustFilter.put(Constants.LATEST, Constants.TRUE); - return elasticSearchRepository.getDataFromES("aws_apps", "apps", mustFilter, - null, null,Arrays.asList("appTag", "director", "executiveSponsor"), null); - - } - - /** - * Gets the unique host. - * - * @param assetGroup the asset group - * @return the unique host - */ - public Map getUniqueHost(String assetGroup,String severity) { - - Map uniqueHost = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(SEARCH); - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":["+severity+"]}}]}}}}]}},\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"}," - + "\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":["+severity+"]}}]}}," - + "\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel\",\"size\":5}," - + "\"aggs\":{\"unique-host\":{\"cardinality\":{\"field\":\"_resourceid.keyword\",\"precision_threshold\":40000}}}}}}}}}}"); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error(Constants.ERROR_UNIQUEHOST, e); - } - - JsonParser jsonParser = new JsonParser(); - if (StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - - JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get( - HITS).toString()); - long total = hitsJson.get(TOTAL).getAsLong(); - uniqueHost.put(TOTAL,total); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter").getAsJsonObject(SEVERITY) - .getAsJsonArray(BUCKETS); - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - uniqueHost.put(buckets.get(i).getAsJsonObject().get("key") - .toString(), - buckets.get(i).getAsJsonObject().get("unique-host") - .getAsJsonObject().get(VALUE).getAsLong()); - } - } - } - return uniqueHost; - } - - /** - * Gets the unique vuln. - * - * @param assetGroup the asset group - * @return the unique vuln - */ - public Map getVulnInfo(String assetGroup,String severity) { - - Map vulnInfo = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(SEARCH); - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":["+severity+"]}}]}}}}]}},\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"}," - + "\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":["+severity+"]}}]}}," - + "\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel\",\"size\":5}," - + "\"aggs\":{\"unique-qid\":{\"cardinality\":{\"script\":\"doc['qid'].toString().replace('.0','')\",\"precision_threshold\": 40000}}}}}}}}}}"); - - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error(Constants.ERROR_UNIQUEHOST, e); - } - - JsonParser jsonParser = new JsonParser(); - if (StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - long total = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter").get(DOC_COUNT).getAsLong(); - vulnInfo.put(TOTAL, total) ; - JsonArray buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter").getAsJsonObject(SEVERITY) - .getAsJsonArray(BUCKETS); - - Map sevInfo; - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - String sevKey = buckets.get(i).getAsJsonObject().get("key") - .toString(); - sevInfo = new HashMap<>(); - sevInfo.put(SEVERITY, sevKey); - sevInfo.put(UNIQUE_VULN_COUNT,buckets.get(i).getAsJsonObject().get(UNIQUE_QID) - .getAsJsonObject().get(VALUE).getAsLong()); - sevInfo.put(VULN_COUNT,buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); - vulnInfo.put(sevKey,sevInfo); - } - } - } - return vulnInfo; - } - - /** - * Gets the unique app. - * - * @param assetGroup the asset group - * @return the unique app - */ - public Map getUniqueApp(String assetGroup) { - - Map uniqueApp = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append("_search?filter_path=aggregations"); - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"_entity\":true}}]}}," - + "\"aggs\":{\"severity\":{\"filters\":{\"filters\":{" - + "\"S3\":{\"has_child\":{\"type\":\"vulninfo\",\"query\":{ \"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"severitylevel\":3}}]}}}}," - + "\"S4\":{\"has_child\":{\"type\":\"vulninfo\",\"query\":{ \"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"severitylevel\":4}}]}}}}," - + "\"S5\":{\"has_child\":{\"type\":\"vulninfo\",\"query\":{ \"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"severitylevel\":5}}]}}}}}}," - + "\"aggs\":{\"NAME\":{\"cardinality\":{\"field\":\"tags.Application.keyword\",\"precision_threshold\": 40000}}}}}}"); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error(Constants.ERROR_UNIQUEHOST, e); - } - JsonParser jsonParser = new JsonParser(); - if (StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonObject buckets = aggsJson.getAsJsonObject(SEVERITY) - .getAsJsonObject(BUCKETS); - for (int i = 3; i <= 5; i++) { - uniqueApp.put( - String.valueOf(i), - buckets.get("S"+i).getAsJsonObject() - .get("NAME").getAsJsonObject().get(VALUE) - .getAsLong()); - } - } - return uniqueApp; - } - - /** - * Gets the aging summary. - * - * @param assetGroup the asset group - * @return the aging summary - */ - public List> getAgingSummary(String assetGroup) { - - List> agingSummary = new ArrayList<>(); - Map avgAgingMap = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(VULN_INFO); - urlToQuery.append("/").append(SEARCH); - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel\":[3,4,5]}}]}}," - + "\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel\",\"size\":10},\"aggs\":{\"aging\":{\"avg\":{\"field\":\"_vulnage\"}}}}}}"); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getAgingSummary from ES", e); - } - JsonParser jsonParser = new JsonParser(); - if (StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray buckets = aggsJson.getAsJsonObject(SEVERITY) - .getAsJsonArray(BUCKETS); - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - avgAgingMap.put( - buckets.get(i).getAsJsonObject().get("key").toString(), - Math.floor(buckets.get(i).getAsJsonObject() - .get(AGING).getAsJsonObject().get(VALUE) - .getAsDouble())); - } - } - - avgAgingMap.forEach((severity, avg) -> { - Map sevInfo = new HashMap<>(); - sevInfo.put(SEVERITY, "S" + severity); - sevInfo.put("days", avg); - agingSummary.add(sevInfo); - }); - } - return agingSummary; - } - - /** - * Gets the aging by application. - * - * @param assetGroup the asset group - * @param parentType the parent type - * @param severity the severity - * @return the aging by application - * @throws Exception the exception - */ - public List> getAgingByApplication(String assetGroup, - String parentType, String severity) throws Exception { - - List> vulnApplications = new ArrayList<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(parentType); - urlToQuery.append("/").append(SEARCH); - - StringBuilder requestBody = new StringBuilder( - "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}]}},\"aggs\":{\"apps\":{\"terms\":{\"field\":\"tags.Application.keyword\",\"size\":10000}," - + "\"aggs\":{\"vulns\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\""); - if (StringUtils.isNotEmpty(severity)) { - requestBody.append("S").append(severity); - requestBody.append("\":{\"bool\":{\"must\":[ {\"match\":{\"latest\":true}},{\"term\":{\"severitylevel\":") - .append(severity).append("}}]}}"); - } else { - requestBody - .append("S3\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":3}},{\"match\":{\"latest\":true}}]}},\"S4\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":4}},{\"match\":{\"latest\":true}}]}},\"S5\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel\":5}},{\"match\":{\"latest\":true}}]}}"); - } - requestBody - .append("}},\"aggs\":{\"aging\":{\"sum\":{\"field\":\"_vulnage\"}}}}}}}}}}"); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getAgingByApplication from ES", e); - throw e; - } - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray outerBuckets = aggsJson.getAsJsonObject("apps") - .getAsJsonArray(BUCKETS); - if (outerBuckets.size() > 0) { - for (int i = 0; i < outerBuckets.size(); i++) { - String appName = outerBuckets.get(i).getAsJsonObject() - .get("key").getAsString(); - List> agingInfo = getAgingInfo(outerBuckets - .get(i).getAsJsonObject().getAsJsonObject(VULN) - .getAsJsonObject("NAME").getAsJsonObject(BUCKETS), - severity); - Map applicationInfo = new HashMap<>(); - applicationInfo.put(APPS, appName); - applicationInfo.put("severityinfo", agingInfo); - vulnApplications.add(applicationInfo); - } - } - return vulnApplications; - } - - /** - * Gets the aging info. - * - * @param countBucket the count bucket - * @param severity the severity - * @return the aging info - * @throws DataException the data exception - */ - private List> getAgingInfo(JsonObject countBucket, - String severity) throws DataException { - - List> severityInfo = new ArrayList<>(); - if (StringUtils.isEmpty(severity)) { - Map severity3 = new HashMap<>(); - severity3.put(SEVEITY_LEVEL, 3); - severity3.put(SEVERITY, "S3"); - if (countBucket.getAsJsonObject("S3").get(DOC_COUNT).toString() - .equals(ZERO)) { - severity3.put("days", 0); - severity3.put(COUNT, 0); - } else { - severity3.put(COUNT, - countBucket.getAsJsonObject("S3").get(DOC_COUNT) - .getAsDouble()); - severity3.put( - "days", - Math.floor(countBucket.getAsJsonObject("S3") - .get(AGING).getAsJsonObject().get(VALUE) - .getAsDouble())); - } - Map severity4 = new HashMap<>(); - severity4.put(SEVEITY_LEVEL, 4); - severity4.put(SEVERITY, "S4"); - if (countBucket.getAsJsonObject("S4").get(DOC_COUNT).toString() - .equals(ZERO)) { - severity4.put("days", 0); - severity4.put(COUNT, 0); - } else { - severity4.put(COUNT, - countBucket.getAsJsonObject("S4").get(DOC_COUNT) - .getAsDouble()); - severity4.put("days", - countBucket.getAsJsonObject("S4").get(AGING) - .getAsJsonObject().get(VALUE).getAsDouble()); - } - Map severity5 = new HashMap<>(); - severity5.put(SEVEITY_LEVEL, 5); - severity5.put(SEVERITY, "S5"); - if (countBucket.getAsJsonObject("S5").get(DOC_COUNT).toString() - .equals(ZERO)) { - severity5.put(COUNT, 0); - severity5.put("days", 0); - } else { - severity5.put(COUNT, - countBucket.getAsJsonObject("S5").get(DOC_COUNT) - .getAsDouble()); - severity5.put("days", - countBucket.getAsJsonObject("S5").get(AGING) - .getAsJsonObject().get(VALUE).getAsDouble()); - } - severityInfo.add(severity3); - severityInfo.add(severity4); - severityInfo.add(severity5); - } else { - Map severityMap = new HashMap<>(); - severityMap.put(SEVEITY_LEVEL, Integer.valueOf(severity)); - severityMap.put(SEVERITY, "S" + severity); - if (countBucket.getAsJsonObject("S" + severity).get(DOC_COUNT) - .toString().equals(ZERO)) { - severityMap.put("days", 0); - severityMap.put(COUNT, 0); - } else { - severityMap.put( - COUNT, - countBucket.getAsJsonObject("S" + severity) - .get(DOC_COUNT).getAsDouble()); - severityMap.put("days", - countBucket.getAsJsonObject("S" + severity) - .get(AGING).getAsJsonObject().get(VALUE) - .getAsDouble()); - } - severityInfo.add(severityMap); - } - - return severityInfo; - } - - /** - * Gets the total qualys host count. - * - * @param index the index - * @param vulnType the vuln type - * @return the total qualys host count - * @throws DataException the data exception - */ - public long getTotalQualysHostCount(String index, String vulnType) - throws DataException { - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/") - .append(index).append("/").append(vulnType).append("/") - .append(UNDERSCORE_COUNT); - StringBuilder requestBody = new StringBuilder("{\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"qualysinfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}}]}}}}]}}}"); - try { - String responseDetails = PacHttpUtils.doHttpPost( - urlToQuery.toString(), requestBody.toString()); - JsonObject responseObj = (JsonObject) new JsonParser().parse(responseDetails); - return (long) responseObj.get("count").getAsLong(); - } catch (Exception e) { - LOGGER.error("Error in getTotalQualysAssetCount", e); - throw new DataException(e); - } - } - - /** - * Gets the vulnerability by qid. - * - * @param qid the qid - * @return the vulnerability by qid - */ - public Map getVulnerabilityByQid(String qid) { - - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - "qualys-kb/kb/_search"); - StringBuilder requestBody = new StringBuilder( - "{\"query\":{\"bool\":{\"must\":[{\"term\":{\"latest\":\"true\"}},{\"term\":{\"qid\":\""); - requestBody.append(qid); - requestBody.append("\"}}]}}}"); - - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilityByQid from ES", e); - } - JsonParser jsonParser = new JsonParser(); - Map vuln = new HashMap<>(); - if(StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonArray hits = resultJson.get("hits").getAsJsonObject().get("hits") - .getAsJsonArray(); - if (hits.size() > 0) { - for (int i = 0; i < hits.size(); i++) { - JsonObject obj = (JsonObject) hits.get(i); - JsonObject sourceJson = (JsonObject) obj.get("_source"); - if (sourceJson != null) { - vuln = new Gson().fromJson(sourceJson, - new TypeToken>() { - }.getType()); - vuln.remove("latest"); - vuln.remove("_loadDate"); - } - } - } - } - return vuln; - } - - /** - * Gets the unique vuln with parent. - * - * @param assetGroup the asset group - * @param severitylevel the severitylevel - * @param parentType the parent type - * @return the vulnerability by qid - * @throws DataException the data exception - */ - public Map getDistributionSummaryByInfraType(String assetGroup, String severitylevel, String parentType) throws DataException { - - Map infraInfo = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(parentType); - urlToQuery.append("/").append(SEARCH); - StringBuilder requestBody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}}," - + "{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}}," - + "{\"terms\":{\"severitylevel\":[%s]}}]}}}}]}},\"aggs\":{\"NAME\":{\"children\":{\"type\":\"vulninfo\"}," - + "\"aggs\":{\"NAME\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}}," - + "\"aggs\":{\"NAME\":{\"cardinality\":{\"script\":\"doc['qid'].toString().replace('.0','')\",\"precision_threshold\":40000}}}}}}}}"); - String requestJson = String.format(requestBody.toString(), severitylevel,severitylevel); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestJson); - } catch (Exception e) { - LOGGER.error("Error in getDistributionSummaryByInfraType", e); - throw new DataException(e); - } - JsonParser jsonParser = new JsonParser(); - if(StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get( - HITS).toString()); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - long totalVulnerableAssets = hitsJson.get(TOTAL).getAsLong(); - long vulnerabilities = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).get(DOC_COUNT).getAsLong(); - long uniqueVulnCount = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).get(VALUE).getAsLong(); - - infraInfo.put(TOTAL_VULN_ASSETS,totalVulnerableAssets); - infraInfo.put(VULNEREBILITIES,vulnerabilities); - infraInfo.put(UNIQUE_VULN_COUNT,uniqueVulnCount); - } - return infraInfo; - } - - /** - * Gets the prod info by env. - * - * @param assetGroup the asset group - * @param severitylevel the severitylevel - * @return the prod info by env - */ - public Map getProdInfoByEnv(String assetGroup, String severitylevel) { - - Map prodInfo = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(SEARCH); - - StringBuilder requestbody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},"); - requestbody.append("{\"terms\":{\"severitylevel\":[%s]}}]}}}}],") - .append("\"should\":[{\"prefix\":{\"tags.Environment.keyword\":\"Production\"}},") - .append( "{\"prefix\":{\"tags.Environment.keyword\":\"production\"}},") - .append( "{\"prefix\":{\"tags.Environment.keyword\":\"Prd\"}},") - .append( "{\"prefix\":{\"tags.Environment.keyword\":\"prd\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"PRD\"}},") - .append( "{\"prefix\":{\"tags.Environment.keyword\":\"Prod\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"PROD\"}}],") - .append("\"minimum_should_match\":1}},") - .append( "\"aggs\":{\"NAME\":{\"children\":{\"type\":\"vulninfo\"},") - .append( "\"aggs\":{\"NAME\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}},") - .append( "\"aggs\":{\"NAME\":{\"cardinality\":{\"script\":\"doc['qid'].toString().replace('.0','')\",\"precision_threshold\": 40000}}}}}}}}"); - String requestJson = String.format(requestbody.toString(), severitylevel,severitylevel); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestJson); - } catch (Exception e) { - LOGGER.error("Error in getProdInfoByEnv", e); - } - - JsonParser jsonParser = new JsonParser(); - if(StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get( - HITS).toString()); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - long totalVulnerableAssets = hitsJson.get(TOTAL).getAsLong(); - long vulnerabilities = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).get(DOC_COUNT).getAsLong(); - long uniqueVulnCount = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).get(VALUE).getAsLong(); - - prodInfo.put(TOTAL_VULN_ASSETS,totalVulnerableAssets); - prodInfo.put(VULNEREBILITIES,vulnerabilities); - prodInfo.put(UNIQUE_VULN_COUNT,uniqueVulnCount); - } - - return prodInfo; - - } - - /** - * Gets the non prod info by env. - * - * @param assetGroup the asset group - * @param severitylevel the severitylevel - * @return the non prod info by env - */ - public Map getNonProdInfoByEnv(String assetGroup, String severitylevel) { - - Map nonProdInfo = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(SEARCH); - - StringBuilder requestBody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},"); - requestBody.append("{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}}}}],") - .append("\"must_not\":[") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"Production\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"production\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"Prd\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"prd\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"PRD\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"Prod\"}},") - .append("{\"prefix\":{\"tags.Environment.keyword\":\"PROD\"}}]}},") - .append("\"aggs\":{\"NAME\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"NAME\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}},") - .append("\"aggs\":{\"NAME\":{\"cardinality\":{\"script\":\"doc['qid'].toString().replace('.0','')\",\"precision_threshold\": 40000}}}}}}}}"); - String requestJson = String.format(requestBody.toString(), severitylevel,severitylevel); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestJson); - } catch (Exception e) { - LOGGER.error("Error in getNonProdInfoByEnv", e); - } - - JsonParser jsonParser = new JsonParser(); - if(StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get( - HITS).toString()); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - long totalVulnerableAssets = hitsJson.get(TOTAL).getAsLong(); - long vulnerabilities = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).get(DOC_COUNT).getAsLong(); - long uniqueVulnCount = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()).get(VALUE).getAsLong(); - - nonProdInfo.put(TOTAL_VULN_ASSETS,totalVulnerableAssets); - nonProdInfo.put(VULNEREBILITIES,vulnerabilities); - nonProdInfo.put(UNIQUE_VULN_COUNT,uniqueVulnCount); - } - return nonProdInfo; - - } - - /** - * Gets the distribution summary by vuln type. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary by vuln type - * @throws DataException the data exception - */ - public List> getDistributionSummaryByVulnType(String assetGroup, String severity) throws DataException { - - List> distributionList = new ArrayList<>(); - long totalVulnCount = 0; - Map infoOS = new HashMap<>(); - infoOS.put("category", "OS"); - infoOS.put(TOTAL_VULN_ASSETS, 0); - infoOS.put(VULNEREBILITIES, 0); - infoOS.put(UNIQUE_VULN_COUNT,0); - - Map infoApp = new HashMap<>(); - infoApp.put("category", "Application"); - infoApp.put(TOTAL_VULN_ASSETS, 0); - infoApp.put(VULNEREBILITIES, 0); - infoApp.put(UNIQUE_VULN_COUNT,0); - - - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(SEARCH); - StringBuilder requestBody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},") - .append( "{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}}}}]}},") - .append("\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}},") - .append("\"aggs\":{\"classification\":{\"terms\":{\"field\":\"classification.keyword\",\"size\":10},\"aggs\":{\"resources\":{\"cardinality\":{\"field\":\"_resourceid.keyword\",\"precision_threshold\":40000}}}}}}}}}}"); - - - String requestJson = String.format(requestBody.toString(), severity,severity); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestJson); - } catch (Exception e) { - LOGGER.error("Error in getVulnerabilitySummaryByClassification from ES", e); - throw new DataException(e); - } - - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter").getAsJsonObject("classification") - .getAsJsonArray(BUCKETS); - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - totalVulnCount += buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong(); - if(buckets.get(i).getAsJsonObject().get("key") - .toString().replace("\"", "").equals("OS")) { - infoOS.put(TOTAL_VULN_ASSETS, buckets.get(i).getAsJsonObject().get("resources").getAsJsonObject().get(VALUE).getAsLong()); - infoOS.put(VULNEREBILITIES, buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); - } else { - infoApp.put(TOTAL_VULN_ASSETS, buckets.get(i).getAsJsonObject().get("resources").getAsJsonObject().get(VALUE).getAsLong()); - infoApp.put(VULNEREBILITIES, buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); - } - } - } - - requestBody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},") - .append( "{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}}}}]}},") - .append("\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":[%s]}}]}},") - .append("\"aggs\":{\"classification\":{\"terms\":{\"field\":\"classification.keyword\",\"size\":10},\"aggs\":{\"unique-qid\":{\"cardinality\":{\"script\":\"doc['qid'].toString().replace('.0','')\",\"precision_threshold\":40000}}}}}}}}}}"); - - requestJson = String.format(requestBody.toString(), severity,severity); - responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestJson); - } catch (Exception e) { - LOGGER.error(Constants.ERROR_UNIQUEHOST, e); - throw new DataException(e); - } - - resultJson = (JsonObject) jsonParser.parse(responseJson); - aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter").getAsJsonObject("classification") - .getAsJsonArray(BUCKETS); - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - if(buckets.get(i).getAsJsonObject().get("key") - .toString().replace("\"", "").equals("OS")) { - infoOS.put(UNIQUE_VULN_COUNT, buckets.get(i).getAsJsonObject().get(UNIQUE_QID) - .getAsJsonObject().get(VALUE).getAsLong()); - } else { - infoApp.put(UNIQUE_VULN_COUNT, buckets.get(i).getAsJsonObject().get(UNIQUE_QID) - .getAsJsonObject().get(VALUE).getAsLong()); - } - } - } - - if(totalVulnCount > 0){ - distributionList.add(infoOS); - distributionList.add(infoApp); - } - double contribution = HUNDRED; - for(int i=0;i info = distributionList.get(i); - if(totalVulnCount > 0){ - double contributionPercent = Math.floor((Double.valueOf(info.get(VULNEREBILITIES).toString())/totalVulnCount)*HUNDRED); - if(i== distributionList.size()-1){ - info.put("contribution", contribution); - }else{ - info.put("contribution", contributionPercent); - contribution = contribution-contributionPercent; - } - } - } - return distributionList; - } - - /** - * Gets the all qid by AG. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the all qid by AG - * @throws DataException the data exception - */ - public Map getAllQidByAG(String assetGroup, String severity) throws DataException { - - Map qids = new HashMap<>(); - - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(VULN_INFO); - urlToQuery.append("/").append(SEARCH); - StringBuilder requestBody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel\":["); - requestBody.append(severity); - requestBody.append("]}}]}},\"aggs\":{\"qid\":{\"terms\":{\"script\":\"(doc['qid'].value+'~').replace('.0','')+doc['title.keyword'].value.toLowerCase()+'~'+doc['classification.keyword'].value\",\"size\":100000}}}}"); - - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getAllQidByAG from ES", e); - throw new DataException(e); - } - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray buckets = aggsJson.getAsJsonObject("qid") - .getAsJsonArray(BUCKETS); - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - qids.put(buckets.get(i).getAsJsonObject().get("key") - .toString().replace("\"", ""), buckets.get(i).getAsJsonObject().get(DOC_COUNT)); - } - } - return qids; - } - - /** - * Gets the apps by severity. - * - * @param assetGroup the asset group - * @param parentType the parent type - * @param severity the severity - * @return the apps by severity - * @throws Exception the exception - */ - public Map getAppsBySeverity(String assetGroup, - String parentType, String severity) throws Exception { - - Map appDetails = new HashMap<>(); - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - assetGroup); - urlToQuery.append("/").append(parentType); - urlToQuery.append("/").append(SEARCH); - - StringBuilder requestBody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}]}}," - + "\"aggs\":{\"apps\":{\"terms\":{\"field\":\"tags.Application.keyword\",\"size\":10000}," - + "\"aggs\":{\"vulns\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\"severity\":{\"terms\":{\"severitylevel\":["); - requestBody.append(severity); - requestBody.append("]}}}}}}}}}}}"); - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getAppsBySeverity from ES", e); - throw e; - } - JsonParser jsonParser = new JsonParser(); - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get( - AGGREGATIONS).toString()); - JsonArray buckets = aggsJson.getAsJsonObject("apps") - .getAsJsonArray(BUCKETS); - if (buckets.size() > 0) { - for (int i = 0; i < buckets.size(); i++) { - appDetails.put(buckets.get(i).getAsJsonObject() - .get("key").getAsString(),buckets.get(i).getAsJsonObject().getAsJsonObject("vulns") - .getAsJsonObject("NAME").getAsJsonObject("buckets").getAsJsonObject("severity").get(DOC_COUNT).getAsLong()); - } - } - return appDetails; - } - - /** - * Creates the trend annotation. - * - * @param request the request - * @return true, if successful - * @throws JsonProcessingException the json processing exception - */ - public boolean createTrendAnnotation(TrendNote request) throws JsonProcessingException { - - SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd"); - SimpleDateFormat dateformatId = new SimpleDateFormat("yyyyMMdd"); - String assetGroup; - if(StringUtils.isBlank(request.getAg())) { - assetGroup = ""; - } else { - assetGroup = request.getAg(); - } - Date date = request.getDate(); - Map payLoad = new HashMap<>(); - payLoad.put("ag", assetGroup); - payLoad.put("note", request.getNote()); - payLoad.put("date", dateformat.format(date)); - if(StringUtils.isEmpty(assetGroup)) { - payLoad.put(NOTE_ID, dateformatId.format(date)); - } else { - payLoad.put(NOTE_ID, assetGroup+"_"+dateformatId.format(date)); - } - - - List> docs = new ArrayList<>(); - docs.add(payLoad); - createIndex("assetgroup_annotations"); - return uploadData("assetgroup_annotations", "annotations", docs, NOTE_ID); - } - - /** - * Creates the index. - * - * @param indexName the index name - */ - public void createIndex(String indexName){ - if(!indexExists(indexName)){ - String payLoad = "{\"settings\": { \"index.mapping.ignore_malformed\": true }}"; - invokeAPI("PUT",indexName,payLoad); - } - } - - private boolean indexExists(String indexName){ - Response response = invokeAPI("HEAD",indexName,null); - if(response!=null){ - return response.getStatusLine().getStatusCode() == 200?true:false; - } - return false; - } - - private boolean uploadData(String index, String type, List> docs, String idKey) { - String actionTemplate = "{ \"index\" : { \"_index\" : \"%s\", \"_type\" : \"%s\", \"_id\" : \"%s\"} }%n"; - - LOGGER.info("*********UPLOADING*** " + type); - if (null != docs && !docs.isEmpty()) { - StringBuilder bulkRequest = new StringBuilder(); - int i = 0; - for (Map doc : docs) { - if (doc != null) { - String id = doc.get(idKey).toString(); - StringBuilder docStrBuilder = new StringBuilder(createESDoc(doc)); - - if (docStrBuilder != null) { - bulkRequest.append(String.format(actionTemplate, index, type, id)); - bulkRequest.append(docStrBuilder + "\n"); - } - i++; - if (i % Constants.THOUSAND == 0 - || bulkRequest.toString().getBytes().length - / (Constants.THOUSAND_TWENTY_FOUR * Constants.THOUSAND_TWENTY_FOUR) > Constants.FIVE) { - LOGGER.info("Uploaded" + i); - Response resp = invokeAPI("POST", "/_bulk?refresh=true", bulkRequest.toString()); - try { - String responseStr = ""; - if(null != resp) { - responseStr = EntityUtils.toString(resp.getEntity()); - } - if (responseStr.contains("\"errors\":true")) { - Response retryResp = invokeAPI("POST", "/_bulk?refresh=true", - bulkRequest.toString()); - String retryResponse = ""; - if(null != retryResp) { - retryResponse = EntityUtils.toString(retryResp.getEntity()); - } - if (retryResponse.contains("\"errors\":true")) { - LOGGER.error(retryResponse); - } - } - } catch (Exception e) { - LOGGER.error("Bulk upload failed",e); - return false; - } - bulkRequest = new StringBuilder(); - } - } - } - if (bulkRequest.length() > 0) { - LOGGER.info("Uploaded" + i); - Response resp = invokeAPI("POST", "/_bulk?refresh=true", bulkRequest.toString()); - try { - String responseStr = ""; - if(null != resp) { - responseStr = EntityUtils.toString(resp.getEntity()); - } - if (responseStr.contains("\"errors\":true")) { - Response retryResp = invokeAPI("POST", "/_bulk?refresh=true", - bulkRequest.toString()); - String retryResponse = ""; - if(null != retryResp) { - retryResponse = EntityUtils.toString(retryResp.getEntity()); - } - - if (retryResponse.contains("\"errors\":true")) { - LOGGER.error(retryResponse); - } - } - if(null != resp) { - return resp.getStatusLine().getStatusCode() == 200 ? true : false; - } else { - return false; - } - } catch (Exception e) { - LOGGER.error("Bulk upload failed",e); - return false; - } - } - } - return true; - } - - private String createESDoc(Map doc) { - ObjectMapper objMapper = new ObjectMapper(); - String docJson = "{}"; - try { - docJson = objMapper.writeValueAsString(doc); - } catch (JsonProcessingException e) { - LOGGER.error("Error in createESDoc" , e); - } - return docJson; - } - - private Response invokeAPI(String method, String endpoint, String payLoad) { - HttpEntity entity = null; - try { - if (payLoad != null) { - entity = new NStringEntity(payLoad, ContentType.APPLICATION_JSON); - } - return getRestClient().performRequest(method, endpoint, Collections.emptyMap(), entity); - } catch (IOException e) { - LOGGER.error("Error in invokeAPI" , e); - } - return null; - } - - private RestClient getRestClient() { - if (restClient == null) { - restClient = RestClient.builder(new HttpHost(updateESHost, updateESPort)).build(); - } - return restClient; - } - - /** - * Gets the trend annotations. - * - * @param ag the ag - * @param from the from - * @return the trend annotations - */ - public List> getTrendAnnotations(String ag,Date from) { - - List> notes = new ArrayList<>(); - SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd"); - - StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append( - "assetgroup_annotations/annotations/_search"); - StringBuilder requestBody = new StringBuilder("{\"size\":10000,\"query\":{\"bool\":{\"must\":[{\"range\":{\"date\":{\"gte\":\""); - requestBody.append(dateformat.format(from)); - requestBody.append("\",\"lte\":\""); - requestBody.append(dateformat.format(new Date())); - requestBody.append("\",\"format\":\"yyyy-MM-dd\"}}}"); - requestBody.append(",{\"terms\":{\"ag.keyword\":[\"\",\""); - requestBody.append(ag).append("\"]}}]}}}"); - - String responseJson = ""; - try { - responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), - requestBody.toString()); - } catch (Exception e) { - LOGGER.error("Error in getTrendAnnotations from ES", e); - } - JsonParser jsonParser = new JsonParser(); - if (StringUtils.isNotEmpty(responseJson)) { - JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); - JsonArray hits = resultJson.get("hits").getAsJsonObject().get("hits") - .getAsJsonArray(); - Map note ; - if (hits.size() > 0) { - for (int i = 0; i < hits.size(); i++) { - JsonObject obj = (JsonObject) hits.get(i); - JsonObject sourceJson = (JsonObject) obj.get("_source"); - if (sourceJson != null) { - note = new Gson().fromJson(sourceJson, - new TypeToken>() { - }.getType()); - notes.add(note); - } - } - } - } - return notes; - } - - /** - * Delete trend annotation. - * - * @param noteId the note id - * @return true, if successful - */ - public boolean deleteTrendAnnotation(String noteId) { - boolean result = false; - try { - result = invokeAPI("POST", "assetgroup_annotations/annotations/_delete_by_query?refresh&q=_id:"+noteId, null).getStatusLine().getStatusCode() == 200 ; - } catch(Exception e) { - LOGGER.error("Error in deleteTrendAnnotation ",e); - } - return result; - } - - /** - * Gets the data from pacman RDS. - * - * @param query the query - * @return the data from pacman RDS - */ - public List> getDataFromPacmanRDS(String query) { - return rdsRepository.getDataFromPacman(query); - } -} diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityTrendGenerator.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityTrendGenerator.java deleted file mode 100644 index ac8b7ff93..000000000 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityTrendGenerator.java +++ /dev/null @@ -1,293 +0,0 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -/** - Copyright (C) 2017 T Mobile Inc - All Rights Reserve - Purpose: - Author :kkumar - Modified Date: Oct 20, 2017 - - **/ -package com.tmobile.pacman.api.compliance.repository; - -import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Repository; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.utils.PacHttpUtils; - - -/** - * The Class VulnerabilityTrendGenerator. - */ -@Repository -public class VulnerabilityTrendGenerator implements Constants { - - /** The es host. */ - @Value("${elastic-search.host}") - private String esHost; - - /** The es port. */ - @Value("${elastic-search.port}") - private int esPort; - - /** The es cluster name. */ - @Value("${elastic-search.clusterName}") - private String esClusterName; - - /** The date format. */ - @Value("${formats.date}") - private String dateFormat; - - /** The Constant LOGGER. */ - private static final Logger LOGGER = LoggerFactory - .getLogger(VulnerabilityTrendGenerator.class); - - /** - * Generate trend. - * - * @param ag the ag - * @param severity the severity - * @param fromDate the from date - * @return the list - * @throws Exception the exception - */ - - public List> generateTrend(String ag,String severity, Date fromDate) throws Exception { - List> dateList = new ArrayList<>(); - LocalDate from = LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(fromDate)); - - StringBuilder queryBody = new StringBuilder(); - queryBody.append("\"query\":{\"bool\":{\"must\":["). - append("{\"terms\":{\"severitylevel\":["+severity+"]}}"). - append("]}}"); - - - long totalCount = getTotalDocCount(ag,queryBody); - - if (totalCount > 0) { - - - List issueOpenDates = new ArrayList<>(); - ExecutorService executionService = Executors.newFixedThreadPool(2); - Map newFoundMap = new HashMap<>(); - Map openCountMap = new HashMap<>(); - executionService.execute(()-> { - newFoundMap.putAll(fetchNewlyFoundVulnByDay(ag,severity,from)); - }); - - executionService.execute( () -> { - - // ES needs minimum 2 slices, if records are less , we need to slice - // accordingly - final int scrollSize = totalCount > 10000 ? 10000 - : (int) (totalCount / 2) + 1; - - final int slices = totalCount > scrollSize ? (int) totalCount - / scrollSize + 1 : 2; - - IntStream.range(0, slices) - .parallel() - .forEach(i -> { - List issueOpenDatesList = fetchVulnInfoDateRanges(ag,scrollSize,slices,i,queryBody,from); - synchronized(issueOpenDates){ - issueOpenDates.addAll(issueOpenDatesList); - } - }); - - openCountMap.putAll(issueOpenDates.parallelStream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))); - - }); - - executionService.shutdown(); - while(!executionService.isTerminated()){} - - - - openCountMap.entrySet().forEach(entry->{ - Map dateObj = new HashMap<>(); - String date = entry.getKey(); - Long open = entry.getValue(); - Long newlyFound = newFoundMap.get(date); - - dateObj.put("date",date); - dateObj.put("open",open); - dateObj.put("new",newlyFound==null?0l:newlyFound); - dateList.add(dateObj); - - }); - return dateList ; - } else { - - throw new DataException(NO_DATA_FOUND); - } - } - - /** - * Fetch newly found vuln by day. - * - * @param ag the ag - * @param severity the severity - * @param from the from - * @return the map - */ - private Map fetchNewlyFoundVulnByDay(String ag,String severity,LocalDate from ){ - - StringBuilder queryBody = new StringBuilder(); - queryBody.append("\"query\":{\"bool\":{\"must\":["). - append("{\"terms\":{\"severitylevel\":["+severity+"]}}"). - append(",{\"range\":{\"_firstFound\":{\"gte\":\""). - append(from.toString()). - append("\"}}}]}}"); - - String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_search?size=0"; - StringBuilder request = new StringBuilder(); - request.append("{"). - append("\"aggs\":{\"dates\":{\"date_histogram\":{\"field\":\"_firstFound\",\"interval\":\"day\",\"format\":\"yyyy-MM-dd\"}}}"). - append(",").append(queryBody).append("}"); - - Map newFoundMap = new HashMap<>(); - try { - String searchResponse = PacHttpUtils.doHttpPost(searchUrl, request.toString()); - JsonParser parser = new JsonParser(); - JsonObject responeObj = parser.parse(searchResponse).getAsJsonObject(); - JsonArray dateBuckets = responeObj.getAsJsonObject("aggregations").getAsJsonObject("dates").getAsJsonArray("buckets"); - for(JsonElement jsonElement:dateBuckets){ - JsonObject dateObj = jsonElement.getAsJsonObject(); - newFoundMap.put(dateObj.get("key_as_string").getAsString(),dateObj.get("doc_count").getAsLong()); - - } - } catch (Exception e) { - LOGGER.error("error",e); - } - - return newFoundMap; - - } - - /** - * Fetch vuln info date ranges. - * - * @param ag the ag - * @param scrollSize the scroll size - * @param slices the slices - * @param sliceNo the slice no - * @param queryBody the query body - * @param from the from - * @return the list - */ - @SuppressWarnings("unchecked") - private List fetchVulnInfoDateRanges(String ag,int scrollSize,int slices,int sliceNo,StringBuilder queryBody,LocalDate from){ - String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_search?scroll=1m"; - StringBuilder request = new StringBuilder(); - request.append("{\"size\":"). - append(scrollSize). - append(",\"_source\":[\"_firstFound\",\"_closedate\"],"). - append("\"slice\": {\"id\":"). - append(sliceNo).append(",\"max\":").append(slices).append("},"). - append(queryBody).append("}"); - try{ - String searchResponse = PacHttpUtils.doHttpPost(searchUrl, request.toString()); - JsonParser parser = new JsonParser(); - JsonObject responeObj = parser.parse(searchResponse).getAsJsonObject(); - JsonArray hits = responeObj.getAsJsonObject("hits").getAsJsonArray("hits"); - List> hitsList = new Gson().fromJson(hits,new TypeToken>>(){}.getType()); - return hitsList.parallelStream().map(obj-> (Map)obj.get("_source")).flatMap( obj-> getDateRange(obj.get("_firstFound"),obj.get("_closedate"),from).stream()).collect(Collectors.toList()); - - }catch(Exception e){ - LOGGER.error("error",e); - } - return new ArrayList<>(); - - } - - /** - * Gets the total doc count. - * - * @param ag the ag - * @param queryBody the query body - * @return the total doc count - * @throws Exception the exception - */ - private long getTotalDocCount(String ag, StringBuilder queryBody) throws Exception{ - String countUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_count"; - StringBuilder requestBody = new StringBuilder(); - requestBody.append("{").append(queryBody).append("}"); - String countResponse = PacHttpUtils.doHttpPost(countUrl, requestBody.toString()); - JsonParser jsonParser = new JsonParser(); - JsonObject response = jsonParser.parse(countResponse).getAsJsonObject(); - return Double.valueOf(response.get("count").getAsString()).longValue(); - - } - - /** - * Gets the date range. - * - * @param from the from - * @param to the to - * @param excludeBefore the exclude before - * @return the date range - */ - private List getDateRange(Object from, Object to, LocalDate excludeBefore){ - - LocalDate fromDt; - LocalDate toDt; - List dateRage = new ArrayList<>(); - DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[Z]['Z']"); - if(from!=null){ - fromDt = LocalDateTime.parse(from.toString(),inputFormatter).toLocalDate(); - if(to==null){ - toDt = LocalDate.now(); - }else{ - toDt = LocalDateTime.parse(to.toString(),inputFormatter).toLocalDate(); - } - DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; - while(fromDt.isBefore(toDt)){ - if(!fromDt.isBefore(excludeBefore)){ - dateRage.add(formatter.format(fromDt)); - } - fromDt = fromDt.plusDays(1); - } - } - - return dateRage; - } - - -} diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImpl.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImpl.java index d3c44a4c3..021a00359 100644 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImpl.java +++ b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImpl.java @@ -1,854 +1,830 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.compliance.service; - -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; - -import com.google.common.base.Strings; -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.exception.ServiceException; -import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; -import com.tmobile.pacman.api.compliance.client.AuthServiceClient; -import com.tmobile.pacman.api.compliance.domain.Asset; -import com.tmobile.pacman.api.compliance.domain.Request; -import com.tmobile.pacman.api.compliance.domain.ResponseWithOrder; -import com.tmobile.pacman.api.compliance.repository.ComplianceRepository; -import com.tmobile.pacman.api.compliance.repository.TrendRepository; -/** - * The Class IssueTrendServiceImpl. - */ -@Service -public class IssueTrendServiceImpl implements IssueTrendService, Constants { - - /** The es host. */ - @Value("${elastic-search.host}") - private String esHost; - - /** The es port. */ - @Value("${elastic-search.port}") - private int esPort; - - /** The es cluster name. */ - @Value("${elastic-search.clusterName}") - private String esClusterName; - - /** The date format. */ - @Value("${formats.date}") - private String dateFormat; - - /** The logger. */ - private final Logger logger = LoggerFactory.getLogger(getClass()); - - /** The statistics client. */ - - /** The auth client. */ - @Autowired - private AuthServiceClient authClient; - - /** The repository. */ - @Autowired - private TrendRepository repository; - - /** The compliance service. */ - @Autowired - private ComplianceService complianceService; - - /** The elastic search repository. */ - @Autowired - private ElasticSearchRepository elasticSearchRepository; - - /** The compliance repository. */ - @Autowired - private ComplianceRepository complianceRepository; - - /** The vuln service. */ - @Autowired - private VulnerabilityService vulnService; - - /** - * {@inheritDoc} - */ - public Asset finfindByName(String accountName) { - Assert.hasLength(accountName, "accountName cannot be null or empty"); - return null; - } - - /* (non-Javadoc) - * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getTrendForIssues(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) - */ - @Override - public Map getTrendForIssues(String assetGroup, - String fromDate, String toDate, String severity, String ruleId, - String policyId, String app, String env) throws ServiceException { - Assert.hasLength(assetGroup, "assetGroup cannot be null or empty"); - - RangeGenerator generator = new RangeGenerator(); - Map mustNotFilter = new HashMap<>(); - Map mustFilter = new HashMap<>(); - if (!Strings.isNullOrEmpty(severity)) { - mustFilter.put("severity.keyword", severity); - } - - if (!Strings.isNullOrEmpty(policyId)) { - mustFilter.put("policyId.keyword", policyId); - } - - if (!Strings.isNullOrEmpty(ruleId)) { - mustFilter.put("ruleId.keyword", ruleId); - } - if (!Strings.isNullOrEmpty(app)) { - mustFilter.put("tags.Application.keyword", app); - } - - if (!Strings.isNullOrEmpty(env)) { - mustFilter.put("tags.Environment.keyword", env); - } - - List hosts = Arrays.asList(esHost, - ""); - // this has to move to config, this is just an additional end point, - // even if not provided default end point from config will work - - try { - return generator.generateTrend(esClusterName, hosts, - NINE_THOUSAND_THREE_HUNDRED, assetGroup, "issue", - "createdDate", "modifiedDate", mustNotFilter, mustFilter, - "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); - } catch (DataException e) { - - throw new ServiceException(e); - } - - } - - /* (non-Javadoc) - * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getComplianceTrendProgress(java.lang.String, java.time.LocalDate, java.lang.String) - */ - @Override - public Map getComplianceTrendProgress(String assetGroup, - LocalDate fromDate, String domain) throws ServiceException { - Map parentMap = new HashMap<>(); - parentMap.put("ag", assetGroup); - // get list of targetypes mapped - String ttypes = complianceRepository.getTargetTypeForAG(assetGroup, - domain); - List> ruleDetails = null; - List> inputList; - List> complianceInfoList; - - if (!Strings.isNullOrEmpty(ttypes)) { - try { - ruleDetails = complianceRepository - .getRuleIdWithDisplayNameQuery(ttypes); - } catch (DataException e) { - throw new ServiceException(e); - } - } - // Make map of rule severity,category - Set ruleCat = new HashSet<>(); - List> ruleSevCatDetails; - - ruleSevCatDetails = complianceService - .getRuleSevCatDetails(ruleDetails); - - - - Map ruleCatDetails = ruleSevCatDetails.parallelStream() - .collect( - Collectors.toMap(c -> c.get(RULEID).toString(), - c -> c.get(RULE_CATEGORY), - (oldvalue, newValue) -> newValue)); - ruleCatDetails.entrySet().parallelStream() - .forEach(entry -> ruleCat.add(entry.getValue().toString())); - complianceInfoList = new ArrayList<>(); - - try { - inputList = repository - .getComplianceTrendProgress(assetGroup, fromDate, domain, - ruleCat); - } catch (DataException e) { - throw new ServiceException(e); - } - - if (!inputList.isEmpty()) { - // Sort the list by the date in ascending order - Comparator> comp = (m1, m2) -> LocalDate.parse( - m1.get("date").toString(), DateTimeFormatter.ISO_DATE) - .compareTo( - LocalDate.parse(m2.get("date").toString(), - DateTimeFormatter.ISO_DATE)); - - Collections.sort(inputList, comp); - useRealTimeDataForLatestDate(inputList, assetGroup, - COMPLIANCE_PERCENTAGE, null, domain); - inputList.forEach(inputMap -> { - Map outputMap = new HashMap<>(); - inputMap.forEach((key, value) -> { - // Other than the specified keys, ignore all other kv pairs - if ((!Strings.isNullOrEmpty(key)) - && !("_id".equalsIgnoreCase(key))) { - - outputMap.put(key, value); - } - }); - - complianceInfoList.add(outputMap); - }); - - Collections.sort(complianceInfoList, comp); - } - parentMap.put("compliance_info", complianceInfoList); - return parentMap; - } - - /* (non-Javadoc) - * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getTrendProgress(java.lang.String, java.lang.String, java.time.LocalDate, java.time.LocalDate, java.lang.String) - */ - @Override - public Map getTrendProgress(String assetGroup, - String ruleId, LocalDate startDate, LocalDate endDate, - String trendCategory) throws ServiceException { - - List> trendList; - try{ - trendList = repository.getTrendProgress( - assetGroup, ruleId, startDate, endDate, trendCategory); - }catch(DataException e){ - throw new ServiceException(e); - } - if (!trendList.isEmpty()) { - - // Sort the list by the date in ascending order - Comparator> comp = (m1, m2) -> LocalDate.parse( - m1.get("date").toString(), DateTimeFormatter.ISO_DATE) - .compareTo( - LocalDate.parse(m2.get("date").toString(), - DateTimeFormatter.ISO_DATE)); - Collections.sort(trendList, comp); - LocalDate trendStartDate = LocalDate.parse(trendList.get(0) - .get("date").toString()); - - // Elastic Search might not have data for some dates. But we want to - // send consistent data to the consumers of this service, so we will - // populate previous where data is unavailable - fillNoDataDatesWithPrevious(trendList, trendStartDate, endDate); - - useRealTimeDataForLatestDate(trendList, assetGroup, trendCategory, - ruleId, null); - - // ADD compliance_percent if not available . This is done - // temporarily.Will update with compliance_percent at source - - appendWithCompliancePercent(trendList); - - return segregateTrendProgressByWeek(assetGroup, trendList, - trendStartDate, endDate); - } else { - return new HashMap<>(); - } - } - - /* (non-Javadoc) - * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#useRealTimeDataForLatestDate(java.util.List, java.lang.String, java.lang.String, java.lang.String, java.lang.String) - */ - @Override - public void useRealTimeDataForLatestDate( - List> trendList, String ag, - String trendCategory, String ruleId, String domain) - throws ServiceException { - Map latestDaysTrendData = new HashMap<>( - trendList.get(trendList.size() - 1)); - Map baseApiReturnMap = new HashMap<>(); - Map overallCompliance = new HashMap<>(); - long compliantQuantity = 0; - long noncompliantQuantity = 0; - long total = 0; - double compliance; - LocalDate today; - try { - switch (trendCategory) { - case "tagcompliance": - baseApiReturnMap = complianceService.getTagging(ag, null); - compliantQuantity = baseApiReturnMap.get("tagged"); - noncompliantQuantity = baseApiReturnMap.get("untagged"); - total = baseApiReturnMap.get("assets"); - compliance = baseApiReturnMap.get(COMPLIANCE_PERCENTAGE); - - latestDaysTrendData.put(COMPLAINT, compliantQuantity); - latestDaysTrendData.put(NON_COMPLIANT, noncompliantQuantity); - latestDaysTrendData.put(TOTAL, total); - latestDaysTrendData.put(COMPLIANCE_PERCENT, compliance); - break; - - case "certcompliance": - - baseApiReturnMap = complianceService.getCertificates(ag); - total = baseApiReturnMap.get("certificates"); - noncompliantQuantity = baseApiReturnMap - .get("certificates_expiring"); - compliantQuantity = total - noncompliantQuantity; - - latestDaysTrendData.put(COMPLAINT, compliantQuantity); - latestDaysTrendData.put(NON_COMPLIANT, noncompliantQuantity); - latestDaysTrendData.put(TOTAL, total); - if (total > 0) { - compliance = Math - .floor(compliantQuantity * HUNDRED / total); - } else { - compliance = INT_HUNDRED; - } - latestDaysTrendData.put(COMPLIANCE_PERCENT, compliance); - break; - - case "vulncompliance": - Map vulnSummary = vulnService - .getVulnerabilitySummary(ag,SEVERITY_LEVELS); - total = Long.valueOf(vulnSummary.get("hosts").toString()); - noncompliantQuantity = Long.valueOf(vulnSummary.get( - "totalVulnerableAssets").toString()); - compliantQuantity = total - noncompliantQuantity; - - latestDaysTrendData.put(COMPLAINT, compliantQuantity); - latestDaysTrendData.put(NON_COMPLIANT, noncompliantQuantity); - latestDaysTrendData.put(TOTAL, total); - if (total > 0) { - compliance = Math - .floor(compliantQuantity * HUNDRED / total); - } else { - compliance = INT_HUNDRED; - } - latestDaysTrendData.put(COMPLIANCE_PERCENT, compliance); - break; - - case "issuecompliance": - Request request = new Request(); - request.setAg(ag); - Map filters = new HashMap<>(); - filters.put("ruleId.keyword", ruleId); - filters.put("domain", domain); - request.setFilter(filters); - ResponseWithOrder responseWithOrder = complianceService - .getRulecompliance(request); - latestDaysTrendData.put(COMPLAINT, responseWithOrder - .getResponse().get(0).get("passed")); - latestDaysTrendData.put(NON_COMPLIANT, responseWithOrder - .getResponse().get(0).get("failed")); - latestDaysTrendData.put(TOTAL, responseWithOrder.getResponse() - .get(0).get("assetsScanned")); - latestDaysTrendData.put(COMPLIANCE_PERCENT, responseWithOrder - .getResponse().get(0).get(COMPLIANCE_PERCENT)); - - break; - - case "patching": - baseApiReturnMap = complianceService.getPatching(ag, null); - compliantQuantity = baseApiReturnMap.get("patched_instances"); - noncompliantQuantity = baseApiReturnMap - .get("unpatched_instances"); - total = baseApiReturnMap.get("total_instances"); - compliance = baseApiReturnMap.get("patching_percentage"); - latestDaysTrendData.put("patched_instances", compliantQuantity); - latestDaysTrendData.put("unpatched_instances", - noncompliantQuantity); - latestDaysTrendData.put("total_instances", total); - latestDaysTrendData.put("patching_percentage", compliance); - break; - - case COMPLIANCE_PERCENTAGE: - overallCompliance = complianceService - .getOverallComplianceByDomain(ag, domain); - if(!overallCompliance.isEmpty()){ - for (Map.Entry entry : overallCompliance.entrySet()) { - latestDaysTrendData.put(entry.getKey(),entry.getValue()); - } - } - break; - - case "issues": - Map distroMap = complianceService - .getDistribution(ag, domain); - Map distroBySev = (Map) distroMap - .get("distribution_by_severity"); - latestDaysTrendData.put(TOTAL, distroMap.get("total_issues")); - - for (Map.Entry severity : distroBySev - .entrySet()) { - latestDaysTrendData.put(severity.getKey(), - severity.getValue()); - } - break; - default: - //nothings - } - - // Check if the trend already has todays data (Compare dates) - // If yes, overwrite. If not, add at the end. - LocalDate date = null; - today = LocalDate.now(); - date = LocalDate.parse(latestDaysTrendData.get("date").toString(), - DateTimeFormatter.ISO_LOCAL_DATE); - - if (date.isEqual(today)) { - logger.info("Latest days data available in trend data, so overwriting"); - trendList.set(trendList.size() - 1, latestDaysTrendData); - } else if (date.isEqual(today.minusDays(1))) { - // Ideally we need to consider this case only else, we may - // unnecessarily append wrong data. FOr eg. In case of patching - // if any previous/ progress is requested. - logger.info("Latest days data is NOT available in trend data, so adding at the end"); - latestDaysTrendData.put("date", - today.format(DateTimeFormatter.ISO_LOCAL_DATE)); - trendList.add(latestDaysTrendData); - } - - } catch (ServiceException e) { - logger.error("Call to Base API to get todays data failed" , e); - return; - } - - } - - /** - * Append with compliance percent. - * - * @param trendList the trend list - */ - private void appendWithCompliancePercent(List> trendList) { - - trendList.parallelStream().forEach( - trend -> { - if (trend.get(COMPLIANCE_PERCENT) == null) { - double total = Double.parseDouble(trend.get(TOTAL) - .toString()); - double compliant = Double.parseDouble(trend.get(COMPLAINT) - .toString()); - double compliancePercent = HUNDRED; - if (total > 0) { - compliancePercent = Math.floor(compliant * HUNDRED - / total); - } - trend.put(COMPLIANCE_PERCENT, compliancePercent); - } - }); - } - - /** - * Fill no data dates with previous. - * - * @param trendList the trend list - * @param firstDay the first day - * @param lastDay the last day - */ - private void fillNoDataDatesWithPrevious( - List> trendList, LocalDate firstDay, - LocalDate lastDay) { - - // We don't want data for future weeks. If the quarter being - // requested is the ongoing quarter, the max we we are interested - // is data up to and including the ongoing day in the ongoing week. - if (lastDay.isAfter(LocalDate.now())) { - lastDay = LocalDate.now(); - } - - List listOfAllDates = new ArrayList<>(); - - LocalDate iterationDate = firstDay; - - // Have a temp variable called iterationDate. Keep incrementing it by 1, - // until we reach the end date. In each such iteration, add each date to - // our list of dates - while (!iterationDate.isAfter(lastDay)) { - listOfAllDates.add(iterationDate); - iterationDate = iterationDate.plusDays(1); - } - - // Iterate through each date. If the data from ES is missing for any - // such - // date, add a dummy map with zero values - Map currentData = new LinkedHashMap<>(); - currentData.put(TOTAL, 0); - currentData.put(COMPLAINT, 0); - currentData.put(NON_COMPLIANT, 0); - currentData.put(COMPLIANCE_PERCENT, HUNDRED); - - for (int i = 0; i < listOfAllDates.size(); i++) { - LocalDate date = listOfAllDates.get(i); - Map trendInfo = getTrendDataForDate(trendList, date); - if (trendInfo == null) { - trendInfo = new LinkedHashMap<>(); - trendInfo.put("date", date.format(DateTimeFormatter.ISO_DATE)); - trendInfo.put(NON_COMPLIANT, currentData.get(NON_COMPLIANT)); - trendInfo.put(TOTAL, currentData.get(TOTAL)); - trendInfo.put(COMPLAINT, currentData.get(COMPLAINT)); - if (currentData.get(COMPLIANCE_PERCENT) != null) { - trendInfo.put(COMPLIANCE_PERCENT, - currentData.get(COMPLIANCE_PERCENT)); - } - trendList.add(i, trendInfo); - } else { - currentData = trendInfo; - } - } - - } - - /** - * Gets the trend data for date. - * - * @param trendList the trend list - * @param date the date - * @return the trend data for date - */ - private Map getTrendDataForDate( - List> trendList, LocalDate date) { - - List> match = trendList - .stream() - .filter(trendMap -> { - LocalDate dateInThisIteration = LocalDate - .parse(trendMap.get("date").toString(), - DateTimeFormatter.ISO_DATE); - return dateInThisIteration.isEqual(date); - }).collect(Collectors.toList()); - if (match != null && !match.isEmpty()) { - return match.get(0); - } - return null; - } - - /** - * Segregate trend progress by week. - * - * @param assetGroup the asset group - * @param trendProgressList the trend progress list - * @param startDate the start date - * @param endDate the end date - * @return the map - */ - private Map segregateTrendProgressByWeek(String assetGroup, - List> trendProgressList, LocalDate startDate, - LocalDate endDate) { - - long maxInstancesForTheCompleteDateRange = 0; - - long totalNumberRunningValue = 0; - long compliantRunningValue = 0; - long noncompliantRunningValue = 0; - double complianceRunningValue = 0; - - List> allWeeksDataList = new ArrayList<>(); - - // The first day of date range is taken as the first day of week 1 of - // the - // quarter. This - // could be a Monday, Thursday or ANY day. - LocalDate startingDayOfWeek = startDate; - - // Add 6 days to get the end date. If we start on a Thursday, the week - // ends on next Wednesday - LocalDate endingDayOfWeek = startingDayOfWeek.plusDays(SIX); - - List> trendListForTheWeek = new ArrayList<>(); - - // We will send 100 weeks at most. Start with week 1(There - // is no week zero!) - for (int weekNumber = 1; weekNumber <= HUNDRED; weekNumber++) { - - LocalDate startingDayOfWeekLocalCopy = startingDayOfWeek; - LocalDate endingDayOfWeekLocalCopy = endingDayOfWeek; - - trendProgressList - .forEach(ruleTrendProgressMap -> ruleTrendProgressMap.forEach(( - key, value) -> { - - if ("date".equals(key)) { - - // Check if this date falls in the week that we are - // currently interested in - LocalDate dateInThisIteration = LocalDate.parse( - value.toString(), - DateTimeFormatter.ISO_DATE); - if (dateInThisIteration - .isAfter(startingDayOfWeekLocalCopy - .minusDays(1)) - && (dateInThisIteration - .isBefore(endingDayOfWeekLocalCopy - .plusDays(1)))) { - // If the date matches, lets pick the map which - // represents this date's patching data and add - // it to - // the weeks list - trendListForTheWeek.add(ruleTrendProgressMap); - } - - } - - })); - - Map mapForTheWeek = new LinkedHashMap<>(); - - // First some k-v pairs for week number,week start date, week end - // date - mapForTheWeek.put("week", weekNumber); - mapForTheWeek.put("start_date", - startingDayOfWeek.format(DateTimeFormatter.ISO_DATE)); - mapForTheWeek.put("end_date", - endingDayOfWeek.format(DateTimeFormatter.ISO_DATE)); - - // Lets calculate the compliance for the week. We simply get the - // compliance for the last day of the week - - complianceRunningValue = calculateWeeklyCompliance(trendListForTheWeek); - mapForTheWeek.put(COMPLIANCE_PERCENTAGE, complianceRunningValue); - trendListForTheWeek.forEach(ruleTrendProgressMap -> { - // We don't need _id in the response - ruleTrendProgressMap.remove("_id"); - }); - - // Store a 'copy' of the weeks array list instead of the original, - // as we will clear the original and reuse it for the next - // iteration. Lets call this by the key 'compliance_info' - mapForTheWeek.put("compliance_info", - new ArrayList>(trendListForTheWeek)); - - if (!trendListForTheWeek.isEmpty()) { - allWeeksDataList.add(mapForTheWeek); - - totalNumberRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList( - TOTAL, trendListForTheWeek); - compliantRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList( - COMPLAINT, trendListForTheWeek); - noncompliantRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList( - NON_COMPLIANT, trendListForTheWeek); - - // Maintain a max instance number for the quarter that is being - // processed. - long maxInstancesRunningValue = (long) getMaxValueNumericDataFromAWeeklyDataList( - TOTAL, trendListForTheWeek); - if (maxInstancesRunningValue > maxInstancesForTheCompleteDateRange) { - maxInstancesForTheCompleteDateRange = maxInstancesRunningValue; - } - - } - - // Now, lets get ready for the iteration for next week - trendListForTheWeek.clear(); - startingDayOfWeek = startingDayOfWeek.plusDays(7); - endingDayOfWeek = endingDayOfWeek.plusDays(7); - - // If week ending date bypasses the quarter end date, lets rewind - // back to quarter end date. The quarter end date will be set as the - // week ending date. - } - - Map quarterlyDataMap = new LinkedHashMap<>(); - quarterlyDataMap.put("ag", assetGroup); - quarterlyDataMap.put("start_date", - startDate.format(DateTimeFormatter.ISO_DATE)); - quarterlyDataMap.put("end_date", - endDate.format(DateTimeFormatter.ISO_DATE)); - quarterlyDataMap.put("max", maxInstancesForTheCompleteDateRange); - quarterlyDataMap.put(TOTAL, totalNumberRunningValue); - quarterlyDataMap.put(COMPLAINT, compliantRunningValue); - quarterlyDataMap.put(NON_COMPLIANT, noncompliantRunningValue); - quarterlyDataMap.put(COMPLIANCE_PERCENTAGE, complianceRunningValue); - - quarterlyDataMap.put("compliance_trend", allWeeksDataList); - - return quarterlyDataMap; - - } - - /** - * Gets the latest days numeric data from A weekly data list. - * - * @param dataKeyName the data key name - * @param ruleTrendProgressListForTheWeek the rule trend progress list for the week - * @return the latest days numeric data from A weekly data list - */ - private double getLatestDaysNumericDataFromAWeeklyDataList( - String dataKeyName, - List> ruleTrendProgressListForTheWeek) { - - int index = ruleTrendProgressListForTheWeek.size() - 1; - - // We take the latest days data, provided its a non-zero value - while (index >= 0) { - Object obj = ruleTrendProgressListForTheWeek.get(index).get( - dataKeyName); - if (null != obj && Double.valueOf(obj.toString()) != 0) { - return Double.valueOf(obj.toString()); - } - index--; - } - - return 0; - } - - /** - * Gets the max value numeric data from A weekly data list. - * - * @param dataKeyName the data key name - * @param trendProgressListForTheWeek the trend progress list for the week - * @return the max value numeric data from A weekly data list - */ - private double getMaxValueNumericDataFromAWeeklyDataList( - String dataKeyName, - List> trendProgressListForTheWeek) { - - double maxValue = 0; - int index = trendProgressListForTheWeek.size() - 1; - - while (index >= 0) { - Object obj = trendProgressListForTheWeek.get(index) - .get(dataKeyName); - if (null != obj && Double.valueOf(obj.toString()) != 0 - && (Double.valueOf(obj.toString()) > maxValue)) { - maxValue = Double.valueOf(obj.toString()); - } - index--; - } - - return maxValue; - } - - /** - * Calculate weekly compliance. - * - * @param trendProgressListForTheWeek the trend progress list for the week - * @return the double - */ - private double calculateWeeklyCompliance( - List> trendProgressListForTheWeek) { - - int index = trendProgressListForTheWeek.size() - 1; - while (index >= 0) { - Object percentObj = trendProgressListForTheWeek.get(index).get( - COMPLIANCE_PERCENT); - if (null != percentObj - && Double.valueOf(percentObj.toString()) != 0) { - return Double.valueOf(percentObj.toString()); - } - index--; - } - return HUNDRED; - - } - - /* (non-Javadoc) - * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getTrendIssues(java.lang.String, java.time.LocalDate, java.time.LocalDate, java.util.Map, java.lang.String) - */ - @Override - public Map getTrendIssues(String assetGroup, - LocalDate from, LocalDate to, Map filter, - String domain) throws ServiceException { - - Map parentMap = new HashMap<>(); - parentMap.put("ag", assetGroup); - - String ttypes = complianceRepository.getTargetTypeForAG(assetGroup, - filter.get(DOMAIN)); - List> ruleDetails = null; - if (!Strings.isNullOrEmpty(ttypes)) { - try{ - ruleDetails = complianceRepository - .getRuleIdWithDisplayNameQuery(ttypes); - }catch(DataException e){ - throw new ServiceException(e); - } - } - - Set ruleSev = new HashSet<>(); - List> ruleSevCatDetails; - ruleSevCatDetails = complianceService - .getRuleSevCatDetails(ruleDetails); - - Map ruleSevDetails = ruleSevCatDetails.parallelStream() - .collect( - Collectors.toMap(r -> r.get(RULEID).toString(), - r -> r.get(SEVERITY), - (oldvalue, newValue) -> newValue)); - ruleSevDetails.entrySet().parallelStream() - .forEach(entry -> ruleSev.add(entry.getValue().toString())); - - List> issueInfoList; - try { - issueInfoList = repository.getTrendIssues( - assetGroup, from, to, filter, ruleSev); - } catch (DataException e) { - throw new ServiceException(e); - } - if (!issueInfoList.isEmpty()) { - issueInfoList.parallelStream().forEach( - issuemap -> { - issuemap.remove("_id"); - double total = Double.parseDouble(issuemap.get(TOTAL) - .toString()); - if (total == 0) { - for (Map.Entry issue : issuemap - .entrySet()) { - if (!"date".equals(issue.getKey())) { - issuemap.put(issue.getKey(), 0); - } - } - } else { - - for (Map.Entry issue : issuemap - .entrySet()) { - if (issuemap.get(issue.getKey()) == null) - issuemap.put(issue.getKey(), 0); - } - } - - }); - // Sort the list by the date in ascending order - Comparator> comp = (m1, m2) -> LocalDate.parse( - m1.get("date").toString(), DateTimeFormatter.ISO_DATE) - .compareTo( - LocalDate.parse(m2.get("date").toString(), - DateTimeFormatter.ISO_DATE)); - - Collections.sort(issueInfoList, comp); - - useRealTimeDataForLatestDate(issueInfoList, assetGroup, "issues", - null, domain); - - parentMap.put("issues_info", issueInfoList); - } - return parentMap; - } - -} +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.compliance.service; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +import com.google.common.base.Strings; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.exception.ServiceException; +import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; +import com.tmobile.pacman.api.compliance.client.AuthServiceClient; +import com.tmobile.pacman.api.compliance.domain.Asset; +import com.tmobile.pacman.api.compliance.domain.Request; +import com.tmobile.pacman.api.compliance.domain.ResponseWithOrder; +import com.tmobile.pacman.api.compliance.repository.ComplianceRepository; +import com.tmobile.pacman.api.compliance.repository.TrendRepository; +/** + * The Class IssueTrendServiceImpl. + */ +@Service +public class IssueTrendServiceImpl implements IssueTrendService, Constants { + + /** The es host. */ + @Value("${elastic-search.host}") + private String esHost; + + /** The es port. */ + @Value("${elastic-search.port}") + private int esPort; + + /** The es cluster name. */ + @Value("${elastic-search.clusterName}") + private String esClusterName; + + /** The date format. */ + @Value("${formats.date}") + private String dateFormat; + + /** The logger. */ + private final Logger logger = LoggerFactory.getLogger(getClass()); + + /** The statistics client. */ + + /** The auth client. */ + @Autowired + private AuthServiceClient authClient; + + /** The repository. */ + @Autowired + private TrendRepository repository; + + /** The compliance service. */ + @Autowired + private ComplianceService complianceService; + + /** The elastic search repository. */ + @Autowired + private ElasticSearchRepository elasticSearchRepository; + + /** The compliance repository. */ + @Autowired + private ComplianceRepository complianceRepository; + + /** + * {@inheritDoc} + */ + public Asset finfindByName(String accountName) { + Assert.hasLength(accountName, "accountName cannot be null or empty"); + return null; + } + + /* (non-Javadoc) + * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getTrendForIssues(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public Map getTrendForIssues(String assetGroup, + String fromDate, String toDate, String severity, String ruleId, + String policyId, String app, String env) throws ServiceException { + Assert.hasLength(assetGroup, "assetGroup cannot be null or empty"); + + RangeGenerator generator = new RangeGenerator(); + Map mustNotFilter = new HashMap<>(); + Map mustFilter = new HashMap<>(); + if (!Strings.isNullOrEmpty(severity)) { + mustFilter.put("severity.keyword", severity); + } + + if (!Strings.isNullOrEmpty(policyId)) { + mustFilter.put("policyId.keyword", policyId); + } + + if (!Strings.isNullOrEmpty(ruleId)) { + mustFilter.put("ruleId.keyword", ruleId); + } + if (!Strings.isNullOrEmpty(app)) { + mustFilter.put("tags.Application.keyword", app); + } + + if (!Strings.isNullOrEmpty(env)) { + mustFilter.put("tags.Environment.keyword", env); + } + + List hosts = Arrays.asList(esHost, + ""); + // this has to move to config, this is just an additional end point, + // even if not provided default end point from config will work + + try { + return generator.generateTrend(esClusterName, hosts, + NINE_THOUSAND_THREE_HUNDRED, assetGroup, "issue", + "createdDate", "modifiedDate", mustNotFilter, mustFilter, + "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + } catch (DataException e) { + + throw new ServiceException(e); + } + + } + + /* (non-Javadoc) + * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getComplianceTrendProgress(java.lang.String, java.time.LocalDate, java.lang.String) + */ + @Override + public Map getComplianceTrendProgress(String assetGroup, + LocalDate fromDate, String domain) throws ServiceException { + Map parentMap = new HashMap<>(); + parentMap.put("ag", assetGroup); + // get list of targetypes mapped + String ttypes = complianceRepository.getTargetTypeForAG(assetGroup, + domain); + List> ruleDetails = null; + List> inputList; + List> complianceInfoList; + + if (!Strings.isNullOrEmpty(ttypes)) { + try { + ruleDetails = complianceRepository + .getRuleIdWithDisplayNameQuery(ttypes); + } catch (DataException e) { + throw new ServiceException(e); + } + } + // Make map of rule severity,category + Set ruleCat = new HashSet<>(); + List> ruleSevCatDetails; + + ruleSevCatDetails = complianceService + .getRuleSevCatDetails(ruleDetails); + + + + Map ruleCatDetails = ruleSevCatDetails.parallelStream() + .collect( + Collectors.toMap(c -> c.get(RULEID).toString(), + c -> c.get(RULE_CATEGORY), + (oldvalue, newValue) -> newValue)); + ruleCatDetails.entrySet().parallelStream() + .forEach(entry -> ruleCat.add(entry.getValue().toString())); + complianceInfoList = new ArrayList<>(); + + try { + inputList = repository + .getComplianceTrendProgress(assetGroup, fromDate, domain, + ruleCat); + } catch (DataException e) { + throw new ServiceException(e); + } + + if (!inputList.isEmpty()) { + // Sort the list by the date in ascending order + Comparator> comp = (m1, m2) -> LocalDate.parse( + m1.get("date").toString(), DateTimeFormatter.ISO_DATE) + .compareTo( + LocalDate.parse(m2.get("date").toString(), + DateTimeFormatter.ISO_DATE)); + + Collections.sort(inputList, comp); + useRealTimeDataForLatestDate(inputList, assetGroup, + COMPLIANCE_PERCENTAGE, null, domain); + inputList.forEach(inputMap -> { + Map outputMap = new HashMap<>(); + inputMap.forEach((key, value) -> { + // Other than the specified keys, ignore all other kv pairs + if ((!Strings.isNullOrEmpty(key)) + && !("_id".equalsIgnoreCase(key))) { + + outputMap.put(key, value); + } + }); + + complianceInfoList.add(outputMap); + }); + + Collections.sort(complianceInfoList, comp); + } + parentMap.put("compliance_info", complianceInfoList); + return parentMap; + } + + /* (non-Javadoc) + * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getTrendProgress(java.lang.String, java.lang.String, java.time.LocalDate, java.time.LocalDate, java.lang.String) + */ + @Override + public Map getTrendProgress(String assetGroup, + String ruleId, LocalDate startDate, LocalDate endDate, + String trendCategory) throws ServiceException { + + List> trendList; + try{ + trendList = repository.getTrendProgress( + assetGroup, ruleId, startDate, endDate, trendCategory); + }catch(DataException e){ + throw new ServiceException(e); + } + if (!trendList.isEmpty()) { + + // Sort the list by the date in ascending order + Comparator> comp = (m1, m2) -> LocalDate.parse( + m1.get("date").toString(), DateTimeFormatter.ISO_DATE) + .compareTo( + LocalDate.parse(m2.get("date").toString(), + DateTimeFormatter.ISO_DATE)); + Collections.sort(trendList, comp); + LocalDate trendStartDate = LocalDate.parse(trendList.get(0) + .get("date").toString()); + + // Elastic Search might not have data for some dates. But we want to + // send consistent data to the consumers of this service, so we will + // populate previous where data is unavailable + fillNoDataDatesWithPrevious(trendList, trendStartDate, endDate); + + useRealTimeDataForLatestDate(trendList, assetGroup, trendCategory, + ruleId, null); + + // ADD compliance_percent if not available . This is done + // temporarily.Will update with compliance_percent at source + + appendWithCompliancePercent(trendList); + + return segregateTrendProgressByWeek(assetGroup, trendList, + trendStartDate, endDate); + } else { + return new HashMap<>(); + } + } + + /* (non-Javadoc) + * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#useRealTimeDataForLatestDate(java.util.List, java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public void useRealTimeDataForLatestDate( + List> trendList, String ag, + String trendCategory, String ruleId, String domain) + throws ServiceException { + Map latestDaysTrendData = new HashMap<>( + trendList.get(trendList.size() - 1)); + Map baseApiReturnMap = new HashMap<>(); + Map overallCompliance = new HashMap<>(); + long compliantQuantity = 0; + long noncompliantQuantity = 0; + long total = 0; + double compliance; + LocalDate today; + try { + switch (trendCategory) { + case "tagcompliance": + baseApiReturnMap = complianceService.getTagging(ag, null); + compliantQuantity = baseApiReturnMap.get("tagged"); + noncompliantQuantity = baseApiReturnMap.get("untagged"); + total = baseApiReturnMap.get("assets"); + compliance = baseApiReturnMap.get(COMPLIANCE_PERCENTAGE); + + latestDaysTrendData.put(COMPLAINT, compliantQuantity); + latestDaysTrendData.put(NON_COMPLIANT, noncompliantQuantity); + latestDaysTrendData.put(TOTAL, total); + latestDaysTrendData.put(COMPLIANCE_PERCENT, compliance); + break; + + case "certcompliance": + + baseApiReturnMap = complianceService.getCertificates(ag); + total = baseApiReturnMap.get("certificates"); + noncompliantQuantity = baseApiReturnMap + .get("certificates_expiring"); + compliantQuantity = total - noncompliantQuantity; + + latestDaysTrendData.put(COMPLAINT, compliantQuantity); + latestDaysTrendData.put(NON_COMPLIANT, noncompliantQuantity); + latestDaysTrendData.put(TOTAL, total); + if (total > 0) { + compliance = Math + .floor(compliantQuantity * HUNDRED / total); + } else { + compliance = INT_HUNDRED; + } + latestDaysTrendData.put(COMPLIANCE_PERCENT, compliance); + break; + + case "issuecompliance": + Request request = new Request(); + request.setAg(ag); + Map filters = new HashMap<>(); + filters.put("ruleId.keyword", ruleId); + filters.put("domain", domain); + request.setFilter(filters); + ResponseWithOrder responseWithOrder = complianceService + .getRulecompliance(request); + latestDaysTrendData.put(COMPLAINT, responseWithOrder + .getResponse().get(0).get("passed")); + latestDaysTrendData.put(NON_COMPLIANT, responseWithOrder + .getResponse().get(0).get("failed")); + latestDaysTrendData.put(TOTAL, responseWithOrder.getResponse() + .get(0).get("assetsScanned")); + latestDaysTrendData.put(COMPLIANCE_PERCENT, responseWithOrder + .getResponse().get(0).get(COMPLIANCE_PERCENT)); + + break; + + case "patching": + baseApiReturnMap = complianceService.getPatching(ag, null); + compliantQuantity = baseApiReturnMap.get("patched_instances"); + noncompliantQuantity = baseApiReturnMap + .get("unpatched_instances"); + total = baseApiReturnMap.get("total_instances"); + compliance = baseApiReturnMap.get("patching_percentage"); + latestDaysTrendData.put("patched_instances", compliantQuantity); + latestDaysTrendData.put("unpatched_instances", + noncompliantQuantity); + latestDaysTrendData.put("total_instances", total); + latestDaysTrendData.put("patching_percentage", compliance); + break; + + case COMPLIANCE_PERCENTAGE: + overallCompliance = complianceService + .getOverallComplianceByDomain(ag, domain); + if(!overallCompliance.isEmpty()){ + for (Map.Entry entry : overallCompliance.entrySet()) { + latestDaysTrendData.put(entry.getKey(),entry.getValue()); + } + } + break; + + case "issues": + Map distroMap = complianceService + .getDistribution(ag, domain); + Map distroBySev = (Map) distroMap + .get("distribution_by_severity"); + latestDaysTrendData.put(TOTAL, distroMap.get("total_issues")); + + for (Map.Entry severity : distroBySev + .entrySet()) { + latestDaysTrendData.put(severity.getKey(), + severity.getValue()); + } + break; + default: + //nothings + } + + // Check if the trend already has todays data (Compare dates) + // If yes, overwrite. If not, add at the end. + LocalDate date = null; + today = LocalDate.now(); + date = LocalDate.parse(latestDaysTrendData.get("date").toString(), + DateTimeFormatter.ISO_LOCAL_DATE); + + if (date.isEqual(today)) { + logger.info("Latest days data available in trend data, so overwriting"); + trendList.set(trendList.size() - 1, latestDaysTrendData); + } else if (date.isEqual(today.minusDays(1))) { + // Ideally we need to consider this case only else, we may + // unnecessarily append wrong data. FOr eg. In case of patching + // if any previous/ progress is requested. + logger.info("Latest days data is NOT available in trend data, so adding at the end"); + latestDaysTrendData.put("date", + today.format(DateTimeFormatter.ISO_LOCAL_DATE)); + trendList.add(latestDaysTrendData); + } + + } catch (ServiceException e) { + logger.error("Call to Base API to get todays data failed" , e); + return; + } + + } + + /** + * Append with compliance percent. + * + * @param trendList the trend list + */ + private void appendWithCompliancePercent(List> trendList) { + + trendList.parallelStream().forEach( + trend -> { + if (trend.get(COMPLIANCE_PERCENT) == null) { + double total = Double.parseDouble(trend.get(TOTAL) + .toString()); + double compliant = Double.parseDouble(trend.get(COMPLAINT) + .toString()); + double compliancePercent = HUNDRED; + if (total > 0) { + compliancePercent = Math.floor(compliant * HUNDRED + / total); + } + trend.put(COMPLIANCE_PERCENT, compliancePercent); + } + }); + } + + /** + * Fill no data dates with previous. + * + * @param trendList the trend list + * @param firstDay the first day + * @param lastDay the last day + */ + private void fillNoDataDatesWithPrevious( + List> trendList, LocalDate firstDay, + LocalDate lastDay) { + + // We don't want data for future weeks. If the quarter being + // requested is the ongoing quarter, the max we we are interested + // is data up to and including the ongoing day in the ongoing week. + if (lastDay.isAfter(LocalDate.now())) { + lastDay = LocalDate.now(); + } + + List listOfAllDates = new ArrayList<>(); + + LocalDate iterationDate = firstDay; + + // Have a temp variable called iterationDate. Keep incrementing it by 1, + // until we reach the end date. In each such iteration, add each date to + // our list of dates + while (!iterationDate.isAfter(lastDay)) { + listOfAllDates.add(iterationDate); + iterationDate = iterationDate.plusDays(1); + } + + // Iterate through each date. If the data from ES is missing for any + // such + // date, add a dummy map with zero values + Map currentData = new LinkedHashMap<>(); + currentData.put(TOTAL, 0); + currentData.put(COMPLAINT, 0); + currentData.put(NON_COMPLIANT, 0); + currentData.put(COMPLIANCE_PERCENT, HUNDRED); + + for (int i = 0; i < listOfAllDates.size(); i++) { + LocalDate date = listOfAllDates.get(i); + Map trendInfo = getTrendDataForDate(trendList, date); + if (trendInfo == null) { + trendInfo = new LinkedHashMap<>(); + trendInfo.put("date", date.format(DateTimeFormatter.ISO_DATE)); + trendInfo.put(NON_COMPLIANT, currentData.get(NON_COMPLIANT)); + trendInfo.put(TOTAL, currentData.get(TOTAL)); + trendInfo.put(COMPLAINT, currentData.get(COMPLAINT)); + if (currentData.get(COMPLIANCE_PERCENT) != null) { + trendInfo.put(COMPLIANCE_PERCENT, + currentData.get(COMPLIANCE_PERCENT)); + } + trendList.add(i, trendInfo); + } else { + currentData = trendInfo; + } + } + + } + + /** + * Gets the trend data for date. + * + * @param trendList the trend list + * @param date the date + * @return the trend data for date + */ + private Map getTrendDataForDate( + List> trendList, LocalDate date) { + + List> match = trendList + .stream() + .filter(trendMap -> { + LocalDate dateInThisIteration = LocalDate + .parse(trendMap.get("date").toString(), + DateTimeFormatter.ISO_DATE); + return dateInThisIteration.isEqual(date); + }).collect(Collectors.toList()); + if (match != null && !match.isEmpty()) { + return match.get(0); + } + return null; + } + + /** + * Segregate trend progress by week. + * + * @param assetGroup the asset group + * @param trendProgressList the trend progress list + * @param startDate the start date + * @param endDate the end date + * @return the map + */ + private Map segregateTrendProgressByWeek(String assetGroup, + List> trendProgressList, LocalDate startDate, + LocalDate endDate) { + + long maxInstancesForTheCompleteDateRange = 0; + + long totalNumberRunningValue = 0; + long compliantRunningValue = 0; + long noncompliantRunningValue = 0; + double complianceRunningValue = 0; + + List> allWeeksDataList = new ArrayList<>(); + + // The first day of date range is taken as the first day of week 1 of + // the + // quarter. This + // could be a Monday, Thursday or ANY day. + LocalDate startingDayOfWeek = startDate; + + // Add 6 days to get the end date. If we start on a Thursday, the week + // ends on next Wednesday + LocalDate endingDayOfWeek = startingDayOfWeek.plusDays(SIX); + + List> trendListForTheWeek = new ArrayList<>(); + + // We will send 100 weeks at most. Start with week 1(There + // is no week zero!) + for (int weekNumber = 1; weekNumber <= HUNDRED; weekNumber++) { + + LocalDate startingDayOfWeekLocalCopy = startingDayOfWeek; + LocalDate endingDayOfWeekLocalCopy = endingDayOfWeek; + + trendProgressList + .forEach(ruleTrendProgressMap -> ruleTrendProgressMap.forEach(( + key, value) -> { + + if ("date".equals(key)) { + + // Check if this date falls in the week that we are + // currently interested in + LocalDate dateInThisIteration = LocalDate.parse( + value.toString(), + DateTimeFormatter.ISO_DATE); + if (dateInThisIteration + .isAfter(startingDayOfWeekLocalCopy + .minusDays(1)) + && (dateInThisIteration + .isBefore(endingDayOfWeekLocalCopy + .plusDays(1)))) { + // If the date matches, lets pick the map which + // represents this date's patching data and add + // it to + // the weeks list + trendListForTheWeek.add(ruleTrendProgressMap); + } + + } + + })); + + Map mapForTheWeek = new LinkedHashMap<>(); + + // First some k-v pairs for week number,week start date, week end + // date + mapForTheWeek.put("week", weekNumber); + mapForTheWeek.put("start_date", + startingDayOfWeek.format(DateTimeFormatter.ISO_DATE)); + mapForTheWeek.put("end_date", + endingDayOfWeek.format(DateTimeFormatter.ISO_DATE)); + + // Lets calculate the compliance for the week. We simply get the + // compliance for the last day of the week + + complianceRunningValue = calculateWeeklyCompliance(trendListForTheWeek); + mapForTheWeek.put(COMPLIANCE_PERCENTAGE, complianceRunningValue); + trendListForTheWeek.forEach(ruleTrendProgressMap -> { + // We don't need _id in the response + ruleTrendProgressMap.remove("_id"); + }); + + // Store a 'copy' of the weeks array list instead of the original, + // as we will clear the original and reuse it for the next + // iteration. Lets call this by the key 'compliance_info' + mapForTheWeek.put("compliance_info", + new ArrayList>(trendListForTheWeek)); + + if (!trendListForTheWeek.isEmpty()) { + allWeeksDataList.add(mapForTheWeek); + + totalNumberRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList( + TOTAL, trendListForTheWeek); + compliantRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList( + COMPLAINT, trendListForTheWeek); + noncompliantRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList( + NON_COMPLIANT, trendListForTheWeek); + + // Maintain a max instance number for the quarter that is being + // processed. + long maxInstancesRunningValue = (long) getMaxValueNumericDataFromAWeeklyDataList( + TOTAL, trendListForTheWeek); + if (maxInstancesRunningValue > maxInstancesForTheCompleteDateRange) { + maxInstancesForTheCompleteDateRange = maxInstancesRunningValue; + } + + } + + // Now, lets get ready for the iteration for next week + trendListForTheWeek.clear(); + startingDayOfWeek = startingDayOfWeek.plusDays(7); + endingDayOfWeek = endingDayOfWeek.plusDays(7); + + // If week ending date bypasses the quarter end date, lets rewind + // back to quarter end date. The quarter end date will be set as the + // week ending date. + } + + Map quarterlyDataMap = new LinkedHashMap<>(); + quarterlyDataMap.put("ag", assetGroup); + quarterlyDataMap.put("start_date", + startDate.format(DateTimeFormatter.ISO_DATE)); + quarterlyDataMap.put("end_date", + endDate.format(DateTimeFormatter.ISO_DATE)); + quarterlyDataMap.put("max", maxInstancesForTheCompleteDateRange); + quarterlyDataMap.put(TOTAL, totalNumberRunningValue); + quarterlyDataMap.put(COMPLAINT, compliantRunningValue); + quarterlyDataMap.put(NON_COMPLIANT, noncompliantRunningValue); + quarterlyDataMap.put(COMPLIANCE_PERCENTAGE, complianceRunningValue); + + quarterlyDataMap.put("compliance_trend", allWeeksDataList); + + return quarterlyDataMap; + + } + + /** + * Gets the latest days numeric data from A weekly data list. + * + * @param dataKeyName the data key name + * @param ruleTrendProgressListForTheWeek the rule trend progress list for the week + * @return the latest days numeric data from A weekly data list + */ + private double getLatestDaysNumericDataFromAWeeklyDataList( + String dataKeyName, + List> ruleTrendProgressListForTheWeek) { + + int index = ruleTrendProgressListForTheWeek.size() - 1; + + // We take the latest days data, provided its a non-zero value + while (index >= 0) { + Object obj = ruleTrendProgressListForTheWeek.get(index).get( + dataKeyName); + if (null != obj && Double.valueOf(obj.toString()) != 0) { + return Double.valueOf(obj.toString()); + } + index--; + } + + return 0; + } + + /** + * Gets the max value numeric data from A weekly data list. + * + * @param dataKeyName the data key name + * @param trendProgressListForTheWeek the trend progress list for the week + * @return the max value numeric data from A weekly data list + */ + private double getMaxValueNumericDataFromAWeeklyDataList( + String dataKeyName, + List> trendProgressListForTheWeek) { + + double maxValue = 0; + int index = trendProgressListForTheWeek.size() - 1; + + while (index >= 0) { + Object obj = trendProgressListForTheWeek.get(index) + .get(dataKeyName); + if (null != obj && Double.valueOf(obj.toString()) != 0 + && (Double.valueOf(obj.toString()) > maxValue)) { + maxValue = Double.valueOf(obj.toString()); + } + index--; + } + + return maxValue; + } + + /** + * Calculate weekly compliance. + * + * @param trendProgressListForTheWeek the trend progress list for the week + * @return the double + */ + private double calculateWeeklyCompliance( + List> trendProgressListForTheWeek) { + + int index = trendProgressListForTheWeek.size() - 1; + while (index >= 0) { + Object percentObj = trendProgressListForTheWeek.get(index).get( + COMPLIANCE_PERCENT); + if (null != percentObj + && Double.valueOf(percentObj.toString()) != 0) { + return Double.valueOf(percentObj.toString()); + } + index--; + } + return HUNDRED; + + } + + /* (non-Javadoc) + * @see com.tmobile.pacman.api.compliance.service.IssueTrendService#getTrendIssues(java.lang.String, java.time.LocalDate, java.time.LocalDate, java.util.Map, java.lang.String) + */ + @Override + public Map getTrendIssues(String assetGroup, + LocalDate from, LocalDate to, Map filter, + String domain) throws ServiceException { + + Map parentMap = new HashMap<>(); + parentMap.put("ag", assetGroup); + + String ttypes = complianceRepository.getTargetTypeForAG(assetGroup, + filter.get(DOMAIN)); + List> ruleDetails = null; + if (!Strings.isNullOrEmpty(ttypes)) { + try{ + ruleDetails = complianceRepository + .getRuleIdWithDisplayNameQuery(ttypes); + }catch(DataException e){ + throw new ServiceException(e); + } + } + + Set ruleSev = new HashSet<>(); + List> ruleSevCatDetails; + ruleSevCatDetails = complianceService + .getRuleSevCatDetails(ruleDetails); + + Map ruleSevDetails = ruleSevCatDetails.parallelStream() + .collect( + Collectors.toMap(r -> r.get(RULEID).toString(), + r -> r.get(SEVERITY), + (oldvalue, newValue) -> newValue)); + ruleSevDetails.entrySet().parallelStream() + .forEach(entry -> ruleSev.add(entry.getValue().toString())); + + List> issueInfoList; + try { + issueInfoList = repository.getTrendIssues( + assetGroup, from, to, filter, ruleSev); + } catch (DataException e) { + throw new ServiceException(e); + } + if (!issueInfoList.isEmpty()) { + issueInfoList.parallelStream().forEach( + issuemap -> { + issuemap.remove("_id"); + double total = Double.parseDouble(issuemap.get(TOTAL) + .toString()); + if (total == 0) { + for (Map.Entry issue : issuemap + .entrySet()) { + if (!"date".equals(issue.getKey())) { + issuemap.put(issue.getKey(), 0); + } + } + } else { + + for (Map.Entry issue : issuemap + .entrySet()) { + if (issuemap.get(issue.getKey()) == null) + issuemap.put(issue.getKey(), 0); + } + } + + }); + // Sort the list by the date in ascending order + Comparator> comp = (m1, m2) -> LocalDate.parse( + m1.get("date").toString(), DateTimeFormatter.ISO_DATE) + .compareTo( + LocalDate.parse(m2.get("date").toString(), + DateTimeFormatter.ISO_DATE)); + + Collections.sort(issueInfoList, comp); + + useRealTimeDataForLatestDate(issueInfoList, assetGroup, "issues", + null, domain); + + parentMap.put("issues_info", issueInfoList); + } + return parentMap; + } + +} diff --git a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/service/VulnerabilityService.java b/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/service/VulnerabilityService.java deleted file mode 100644 index 4dd80dfc1..000000000 --- a/api/pacman-api-compliance/src/main/java/com/tmobile/pacman/api/compliance/service/VulnerabilityService.java +++ /dev/null @@ -1,1895 +0,0 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.compliance.service; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.stream.Collectors; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Strings; -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.exception.ServiceException; -import com.tmobile.pacman.api.commons.utils.CommonUtils; -import com.tmobile.pacman.api.compliance.client.AssetServiceClient; -import com.tmobile.pacman.api.compliance.domain.AssetApi; -import com.tmobile.pacman.api.compliance.domain.AssetApiData; -import com.tmobile.pacman.api.compliance.domain.AssetCount; -import com.tmobile.pacman.api.compliance.domain.AssetCountByAppEnvDTO; -import com.tmobile.pacman.api.compliance.domain.AssetCountDTO; -import com.tmobile.pacman.api.compliance.domain.AssetCountData; -import com.tmobile.pacman.api.compliance.domain.Request; -import com.tmobile.pacman.api.compliance.domain.TrendNote; -import com.tmobile.pacman.api.compliance.repository.VulnerabilityRepository; -import com.tmobile.pacman.api.compliance.repository.VulnerabilityTrendGenerator; - -/** - * The Class VulnerabilityService. - */ -@Service -public class VulnerabilityService implements Constants { - - /** The vulnerability repository. */ - @Autowired - private VulnerabilityRepository vulnerabilityRepository; - - /** The vuln trend generator. */ - @Autowired - VulnerabilityTrendGenerator vulnTrendGenerator; - - @Autowired - ComplianceService complianceService; - - /** The vuln types. */ - @Value("${vulnerability.types}") - private String vulnTypes; - - /** The vuln summary severity. */ - @Value("${vulnerability.summary.severity}") - private String vulnSummarySeverity; - - /** The asset service client. */ - @Autowired - private AssetServiceClient assetServiceClient; - - /** The Constant logger. */ - private static final Log logger = LogFactory.getLog(VulnerabilityService.class); - - - - /** - * Gets the vulnerabilities details. - * - * @param assetGroup the asset group - * @param filter the filter - * @return the vulnerabilities details - * @throws Exception the exception - */ - public List> getVulnerabilitiesDetails( - String assetGroup, Map filter) throws Exception { - List> vulnerabilitiesDetails = new ArrayList<>(); - try { - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - if (!vulnTargetTypes.isEmpty()) { - for (String parentType : vulnTargetTypes) { - Map vulnAssetsAffected = vulnerabilityRepository - .getAssetsAffectedCount(assetGroup, filter, - parentType); - List> vulnerabilitiesData = formVulnerabilitiesData( - vulnerabilityRepository.getAllVulnerabilities(new ArrayList( - vulnAssetsAffected.keySet())), vulnAssetsAffected); - List> vulnerabilitiesDetailsTemp = new ArrayList<>(); - if(vulnerabilitiesDetails.isEmpty()) { - vulnerabilitiesDetails = new ArrayList<>(vulnerabilitiesData); - } else { - for(Map vulnData : vulnerabilitiesData) { - boolean qidMatched = false; - for(Map vulnDetail : vulnerabilitiesDetails) { - if(vulnData.get("qid").equals(vulnDetail.get("qid"))) { - vulnDetail.put(ASSETS_AFFECTED, Long.valueOf(vulnDetail.get(ASSETS_AFFECTED).toString()) - + Long.valueOf(vulnData.get(ASSETS_AFFECTED).toString())); - qidMatched = true; - break; - } - } - if(!qidMatched) { - vulnerabilitiesDetailsTemp.add(vulnData); - } - } - vulnerabilitiesDetails.addAll(vulnerabilitiesDetailsTemp); - } - } - } - - } catch (Exception e) { - logger.error("Error in getVulnerabilitiesDetails ", e); - throw e; - } - - return vulnerabilitiesDetails; - } - - /** - * Gets the vulnerability summary. - * - * @param assetGroup the asset group - * @return the vulnerability summary - * @throws ServiceException the service exception - */ - @SuppressWarnings({ "unchecked" }) - public Map getVulnerabilitySummary(String assetGroup,String reqSeverity) - throws ServiceException { - - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - - Map vulnerabilitySummary = new HashMap<>(); - List> severityInfo = new ArrayList<>(); - if (vulnTargetTypes.isEmpty()) { - for (int i = 3; i <= 5; i++) { - Map sevInfo = new HashMap<>(); - sevInfo.put(SEVERITY, "S" + i); - sevInfo.put(SEVEITY_LEVEL, i); - sevInfo.put(COUNT, 0); - sevInfo.put("appCount", 0); - sevInfo.put("hostCount", 0); - sevInfo.put(UNIQUE_VULN_COUNT, 0); - sevInfo.put(VULN_COUNT, 0); - severityInfo.add(sevInfo); - } - vulnerabilitySummary.put(SEV_INFO, severityInfo); - vulnerabilitySummary.put(VULNEREBILITIES, 0); - vulnerabilitySummary.put("hosts", 0); - vulnerabilitySummary.put(TOTAL_VULN_ASSETS, 0); - vulnerabilitySummary.put("compliantpercent", 100); - vulnerabilitySummary.put("assetsWithVulns", 0); - return vulnerabilitySummary; - - } else { - - Map> queryResults = new HashMap<>(); - - long totalQualysCount = 0; - long vulnerableAssetCount = 0; - long totalAssetCount = 0; - - ExecutorService executor = Executors.newFixedThreadPool(3); - executor.execute(() -> { - queryResults.put("uniqueHost",vulnerabilityRepository.getUniqueHost(assetGroup,reqSeverity)); - }); - executor.execute(() -> { - queryResults.put("VulnInfo",vulnerabilityRepository.getVulnInfo(assetGroup,reqSeverity)); - - }); - executor.execute(() -> { - queryResults.put("uniqueApp",vulnerabilityRepository.getUniqueApp(assetGroup)); - }); - executor.shutdown(); - while (!executor.isTerminated()) { - } - - Map uniqueHost = queryResults.get("uniqueHost"); - Map vulnInfo = queryResults.get("VulnInfo"); - Map uniqueApp = queryResults.get("uniqueApp"); - - List sevList = Arrays.asList(reqSeverity.split(",")); - List summarySevList = Arrays.asList(vulnSummarySeverity.split(",")); - Map sevVulnInfo ; - Map vulnInfoMap ; - - List> sevVulnfoList = new ArrayList<>(); - vulnerabilitySummary.put(SEV_INFO, sevVulnfoList); - - for(String sev : sevList){ - sevVulnInfo = new HashMap<>(); - sevVulnInfo.put(SEVEITY_LEVEL, Integer.valueOf(sev)); - sevVulnInfo.put(SEVERITY, "S"+sev); - sevVulnInfo.put("hostCount", uniqueHost.get(sev)==null?0:uniqueHost.get(sev)); - if(summarySevList.contains(sev)){ - vulnerableAssetCount += Long.valueOf(sevVulnInfo.get("hostCount").toString()); - } - vulnInfoMap = (Map) vulnInfo.get(sev); - if(vulnInfoMap!=null){ - sevVulnInfo.put(COUNT,vulnInfoMap.get(VULN_COUNT)); - sevVulnInfo.put(VULN_COUNT,vulnInfoMap.get(VULN_COUNT)); - sevVulnInfo.put(UNIQUE_VULN_COUNT,vulnInfoMap.get(UNIQUE_VULN_COUNT)); - }else{ - sevVulnInfo.put(COUNT,0); - sevVulnInfo.put(VULN_COUNT,0); - sevVulnInfo.put(UNIQUE_VULN_COUNT,0); - } - sevVulnInfo.put("appCount", uniqueApp.get(sev)==null?0:uniqueApp.get(sev)); - sevVulnfoList.add(sevVulnInfo); - } - vulnerabilitySummary.put(UNIQUE_VULN_COUNT, sevVulnfoList.stream().mapToLong(sevData-> Long.valueOf(sevData.get(UNIQUE_VULN_COUNT).toString())).sum()); - vulnerabilitySummary.put("assetsWithVulns", uniqueHost.get(TOTAL)==null?0:uniqueHost.get(TOTAL)); - vulnerabilitySummary.put( VULNEREBILITIES,vulnInfo.get(TOTAL)==null?0:vulnInfo.get(TOTAL)); - - if(sevList.stream().filter(summarySevList::contains).count() != summarySevList.size()){ - vulnerableAssetCount = Long.valueOf(vulnerabilityRepository.getUniqueHost(assetGroup,vulnSummarySeverity).get(TOTAL).toString()); - } - - for (String vulnType : vulnTargetTypes) { - try{ - if(vulnType.equals(EC2)) { - Request request = new Request(); - request.setAg(assetGroup); - Map filter = new HashMap<>(); - filter.put("domain", "Infra & Platforms"); - filter.put("ruleId.keyword","PacMan_Ec2InstanceScannedByQualys_version-1_Ec2-instance-scanned-by-qualys-API_ec2"); - request.setFilter(filter ); - Map response = complianceService.getRulecompliance(request).getResponse().get(0); - totalAssetCount += Long.valueOf(response.get("assetsScanned").toString()); - totalQualysCount += Long.valueOf(response.get("passed").toString()); - } else { - AssetCount totalAssets = assetServiceClient - .getTotalAssetsCount(assetGroup, vulnType, null); - AssetCountData data = totalAssets.getData(); - AssetCountByAppEnvDTO[] assetcount = data.getAssetcount(); - Long totalAssetsCount = 0l; - for (AssetCountByAppEnvDTO assetCount_Count : assetcount) { - if (assetCount_Count.getType().equalsIgnoreCase(vulnType)) { - totalAssetsCount = Long.parseLong(assetCount_Count - .getCount()); - } - } - totalAssetCount += totalAssetsCount; - totalQualysCount += vulnerabilityRepository.getTotalQualysHostCount(assetGroup, vulnType); - } - }catch(ServiceException | DataException e){ - throw new ServiceException(); - } - } - - try { - - vulnerabilitySummary.put("hosts", totalAssetCount); - if (totalQualysCount > totalAssetCount) { - totalQualysCount = totalAssetCount; - } - - long totalVulnerableAssets = totalAssetCount - totalQualysCount - + vulnerableAssetCount; - if (totalVulnerableAssets > totalAssetCount) { - totalVulnerableAssets = totalAssetCount; - } - vulnerabilitySummary.put(TOTAL_VULN_ASSETS, - totalVulnerableAssets); - - float compliantCount = (float)totalAssetCount - totalVulnerableAssets; - float compliantpercent = 100; - if (totalAssetCount > 0) { - compliantpercent = (compliantCount / totalAssetCount) * 100; - } - DecimalFormat df = new DecimalFormat("#.00"); - vulnerabilitySummary.put("compliantpercent", - Math.floor(Float.valueOf(df.format(compliantpercent)))); - vulnerabilitySummary.put("hostsScanned", totalQualysCount); - vulnerabilitySummary.put("hostsNotScanned", totalAssetCount-totalQualysCount); - if(totalAssetCount > 0) { - vulnerabilitySummary.put("hostsScanCoverage", Math.floor( (1.0*totalQualysCount/totalAssetCount)*100)); - } else { - vulnerabilitySummary.put("hostsScanCoverage", 0); - } - } catch (Exception e) { - logger.error(e); - throw new ServiceException(e); - } - if(vulnerabilitySummary.isEmpty()){ - throw new ServiceException(NO_DATA_FOUND); - } - return vulnerabilitySummary; - } - - } - - /** - * Gets the vulnerability by app and env. - * - * @param assetGroup the asset group - * @param filter the filter - * @param application the application - * @return the vulnerability by app and env - * @throws Exception the exception - */ - public List> getVulnerabilityByAppAndEnv( - String assetGroup, String filter, String application) - throws Exception { - - List> vulnApplications = new ArrayList<>(); - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - - if (!vulnTargetTypes.isEmpty()) { - for (String parentType : vulnTargetTypes) { - vulnApplications.addAll(vulnerabilityRepository - .getVulnerabilyAcrossAppAndEnv(assetGroup, filter, - application, parentType, null)); - } - } - - return vulnApplications; - } - - /** - * Gets the vulnerability trend. - * - * @param assetGroup the asset group - * @param filter the filter - * @param from the from - * @param to the to - * @return the vulnerability trend - * @throws Exception the exception - */ - public List> getVulnerabilityTrend(String assetGroup, - Map filter, Date from, Date to) throws Exception { - return vulnerabilityRepository.getVulnerabilityTrend(assetGroup, - filter, from, to); - } - - /** - * Gets the vulnerability trend. - * - * @param assetGroup the asset group - * @param severity the severity - * @param from the from - * @return the vulnerability trend with open new count - * @throws Exception the exception - */ - public List> getVulnerabilityNewOpenTrend(String assetGroup, - String severity, Date from) throws Exception { - return vulnTrendGenerator.generateTrend(assetGroup, - severity,from); - } - - - /** - * Gets the vulnerabilities distribution. - * - * @param assetGroup the asset group - * @return the vulnerabilities distribution - * @throws Exception the exception - */ - public List> getVulnerabilitiesDistribution( - String assetGroup) throws Exception { - - List> vulnDistributions = new ArrayList<>(); - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - if (!vulnTargetTypes.isEmpty()) { - for (String parentType : vulnTargetTypes) { - vulnDistributions - .addAll(vulnerabilityRepository - .getVulnerabilitiesDistribution(assetGroup, - parentType)); - } - } - return vulnDistributions; - } - - /** - * Filter matching collection elements. - * - * @param masterDetailList the master detail list - * @param searchText the search text - * @param b the b - * @return the object - * @throws ServiceException the ServiceException - */ - public Object filterMatchingCollectionElements( - List> masterDetailList, String searchText, - boolean b) throws ServiceException { - return CommonUtils.filterMatchingCollectionElements(masterDetailList, - searchText, true); - } - - /** - * Gets the vulnerabilitysummary by resource id. - * - * @param instanceId the instance id - * @return the vulnerabilitysummary by resource id - */ - public Map getVulnerabilitysummaryByResourceId( - String instanceId) { - return vulnerabilityRepository - .getVulnerabilitysummaryByResourceId(instanceId); - } - - /** - * Gets the vulnerability details by resource id. - * - * @param instanceId the instance id - * @return the vulnerability details by resource id - */ - public List> getVulnerabilityDetailsByResourceId( - String instanceId) { - - List> vulnerabilitiesDetails = new ArrayList<>(); - try { - List> vulnerabilitiesDetailsList = vulnerabilityRepository - .getVulnerabilityDetailsByResourceId(instanceId); - vulnerabilitiesDetails = formVulnerabilitiesData( - vulnerabilitiesDetailsList, new HashMap()); - } catch (Exception e) { - logger.error("Error in getVulnerabilitiesDetails ", e); - throw e; - } - - return vulnerabilitiesDetails; - } - - /** - * Form vulnerabilities data. - * - * @param vulnerabilitiesDetails the vulnerabilities details - * @param vulnAssetsAffected the vuln assets affected - * @return the list - */ - private List> formVulnerabilitiesData( - List> vulnerabilitiesDetails, - Map vulnAssetsAffected) { - - List> vulnerabilitiesDetailsList = new ArrayList<>(); - - vulnerabilitiesDetails - .parallelStream() - .forEach( - vulnObject -> { - Map vulnObj = new LinkedHashMap<>(); - vulnObj.put(TITLE, vulnObject.get(TITLE).toString()); - vulnObj.put( - SEVERITY, - "S" - + Double.valueOf( - vulnObject.get( - SEVEITY_LEVEL) - .toString()) - .intValue()); - if (!CollectionUtils.isEmpty(vulnAssetsAffected)) { - vulnObj.put(ASSETS_AFFECTED, vulnAssetsAffected - .get(String.valueOf(vulnObject.get( - "qid").toString()))); - } - vulnObj.put( - "qid", - Double.valueOf( - vulnObject.get("qid").toString()) - .longValue()); - vulnObj.put(CATEGORY, vulnObject.get(CATEGORY) - .toString()); - vulnObj.put(VULN_TYPE, vulnObject.get(VULN_TYPE) - .toString()); - if (vulnObject.containsKey(PATCHABLE)) { - vulnObj.put(PATCHABLE, "1".equals(vulnObject - .get(PATCHABLE).toString()) ? true - : false); - } - vulnObj.put( - SEVEITY_LEVEL, - Double.valueOf( - vulnObject.get(SEVEITY_LEVEL) - .toString()).intValue()); - synchronized (vulnerabilitiesDetailsList) { - vulnerabilitiesDetailsList.add(vulnObj); - } - }); - - if (!CollectionUtils.isEmpty(vulnAssetsAffected)) { - return vulnerabilitiesDetailsList - .stream() - .sorted((h1, h2) -> (int) (Double.parseDouble(h2.get( - ASSETS_AFFECTED).toString()) - (Double - .parseDouble(h1.get(ASSETS_AFFECTED).toString())))) - .sorted((h1, h2) -> (int) (Double.parseDouble(h2.get( - SEVEITY_LEVEL).toString()) - (Double.parseDouble(h1 - .get(SEVEITY_LEVEL).toString())))) - .collect(Collectors.toList()); - } else { - return vulnerabilitiesDetailsList - .stream() - .sorted((h1, h2) -> (int) (Double.parseDouble(h2.get( - SEVEITY_LEVEL).toString()) - (Double.parseDouble(h1 - .get(SEVEITY_LEVEL).toString())))) - .collect(Collectors.toList()); - } - - } - - /** - * Gets the target types. - * - * @param assetGroup the asset group - * @return the target types - */ - private String getTargetTypes(String assetGroup) { - String tTypesTemp; - String ttypes = null; - AssetApi assetApi = assetServiceClient.getTargetTypeList(assetGroup, - null); - AssetApiData data = assetApi.getData(); - AssetCountDTO[] targetTypes = data.getTargettypes(); - for (AssetCountDTO name : targetTypes) { - if (!Strings.isNullOrEmpty(name.getType())) { - tTypesTemp = new StringBuilder().append('\'') - .append(name.getType()).append('\'').toString(); - if (Strings.isNullOrEmpty(ttypes)) { - ttypes = tTypesTemp; - } else { - ttypes = new StringBuilder(ttypes).append(",").append(tTypesTemp).toString(); - } - } - } - return ttypes; - } - - /** - * Gets the vulnerability distribution summary. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the vulnerability distribution summary - */ - public List> getVulnerabilityDistributionSummary( - String assetGroup, String severity) { - - List> distributionSummary = new ArrayList<>(); - - Map> appDetails = getDistributionSummary(assetGroup, severity); - - Map directApp = new ConcurrentHashMap<>(); - Map vpApp = new ConcurrentHashMap<>(); - formDirectorAndVPByApp(directApp, vpApp); - - if (StringUtils.isEmpty(severity)) { - for (int i = 3; i <= 5; i++) { - distributionSummary.add(formDistributionSummary(appDetails, - directApp, vpApp, String.valueOf(i))); - } - } else - distributionSummary.add(formDistributionSummary(appDetails, - directApp, vpApp, severity)); - - return distributionSummary; - } - - /** - * Form distribution summary. - * - * @param appDetails the app details - * @param directApp the direct app - * @param vpApp the vp app - * @param severity the severity - * @return the map - */ - private Map formDistributionSummary( - Map> appDetails, - Map directApp, Map vpApp, - String severity) { - - List> vpData = new ArrayList<>(); - List> directorData = new ArrayList<>(); - List> appData = new ArrayList<>(); - - int total = 0; - - for (Entry> entry : appDetails.entrySet()) { - String appName = entry.getKey(); - Map sev = entry.getValue(); - - Map appTemp = new HashMap<>(); - appTemp.put("name", appName); - appTemp.put(COUNT, sev.get("S" + severity)); - total += Integer.valueOf(sev.get("S" + severity).toString()); - appData.add(appTemp); - if (!directorData.isEmpty()) { - String director; - if (StringUtils.isEmpty(directApp.get(appName))) - director = UNKNOWN; - else - director = directApp.get(appName); - - boolean directorExists = false; - for (Map existingDirectorData : directorData) { - if (director.equals(existingDirectorData.get("name"))) { - existingDirectorData.put( - COUNT, - Integer.valueOf(existingDirectorData.get(COUNT) - .toString()) - + Integer.valueOf(sev.get( - "S" + severity).toString())); - directorExists = true; - break; - } - } - if (!directorExists) { - Map directorTemp = new HashMap<>(); - directorTemp.put("name", director); - directorTemp.put(COUNT, sev.get("S" + severity)); - directorData.add(directorTemp); - } - } else { - Map directorTemp = new HashMap<>(); - if (StringUtils.isEmpty(directApp.get(appName))) { - directorTemp.put("name", UNKNOWN); - } else - directorTemp.put("name", directApp.get(appName)); - directorTemp.put(COUNT, sev.get("S" + severity)); - directorData.add(directorTemp); - } - - if (!vpData.isEmpty()) { - String vp; - if (StringUtils.isEmpty(vpApp.get(appName))) - vp = UNKNOWN; - else - vp = vpApp.get(appName); - - boolean vpExists = false; - for (Map existingVpData : vpData) { - if (vp.equals(existingVpData.get("name"))) { - existingVpData.put( - COUNT, - Integer.valueOf(existingVpData.get(COUNT) - .toString()) - + Integer.valueOf(sev.get( - "S" + severity).toString())); - vpExists = true; - break; - } - } - if (!vpExists) { - Map vpTemp = new HashMap<>(); - vpTemp.put("name", vp); - vpTemp.put(COUNT, sev.get("S" + severity)); - vpData.add(vpTemp); - } - } else { - Map vpTemp = new HashMap<>(); - if (StringUtils.isEmpty(vpApp.get(appName))) { - vpTemp.put("name", UNKNOWN); - } else - vpTemp.put("name", vpApp.get(appName)); - vpTemp.put(COUNT, sev.get("S" + severity)); - vpData.add(vpTemp); - } - } - - Map vpInfo = new LinkedHashMap<>(); - vpInfo.put("type", "VP"); - vpInfo.put("data", vpData); - Map directorInfo = new LinkedHashMap<>(); - directorInfo.put("type", "Director"); - directorInfo.put("data", directorData); - Map appInfo = new LinkedHashMap<>(); - appInfo.put("type", "Application"); - appInfo.put("data", appData); - - List> distributionList = new ArrayList<>(); - distributionList.add(vpInfo); - distributionList.add(directorInfo); - distributionList.add(appInfo); - - Map severityMap = new HashMap<>(); - severityMap.put(SEVERITY, Integer.valueOf(severity)); - severityMap.put("distribution", distributionList); - severityMap.put("total", total); - return severityMap; - } - - /** - * Gets the aging summary. - * - * @param assetGroup the asset group - * @return the aging summary - */ - public List> getAgingSummary(String assetGroup) { - return vulnerabilityRepository.getAgingSummary(assetGroup); - } - - /** - * Gets the aging distribution summary. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the aging distribution summary - */ - @SuppressWarnings("unchecked") - public List> getAgingDistributionSummary( - String assetGroup, String severity) { - - List> distributionSummary = new ArrayList<>(); - List> vulnApplications = new ArrayList<>(); - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - if (!vulnTargetTypes.isEmpty()) { - for (String parentType : vulnTargetTypes) { - try { - vulnApplications.addAll(vulnerabilityRepository - .getAgingByApplication(assetGroup, parentType, - severity)); - } catch (Exception e) { - logger.error(e); - } - } - } - /* Parallel Stream and so concurrent hashmap */ - Map directApp = new ConcurrentHashMap<>(); - Map vpApp = new ConcurrentHashMap<>(); - try { - vulnerabilityRepository - .fetchExecDirectorApps() - .parallelStream() - .forEach( - app -> { - directApp.put(app.get(APP_TAG).toString(), app - .get("director").toString()); - vpApp.put(app.get(APP_TAG).toString(), - app.get("executiveSponsor").toString()); - }); - - } catch (Exception e) { - logger.error(e); - } - - Map appDetails = new ConcurrentHashMap<>(); - vulnApplications - .parallelStream() - .forEach( - vulnApps -> { - List> severityInfo = (List>) vulnApps - .get(SEV_INFO); - Map> sevDetails = new HashMap<>(); - for (Map sevInfo : severityInfo) { - Map days = new HashMap<>(); - days.put("days", sevInfo.get("days")); - days.put(COUNT, sevInfo.get(COUNT)); - sevDetails.put( - sevInfo.get(SEVERITY).toString(), days); - } - appDetails.put(vulnApps.get("application") - .toString(), sevDetails); - }); - if (StringUtils.isEmpty(severity)) { - for (int i = 3; i <= 5; i++) { - distributionSummary.add(formAgingDistributionSummary( - appDetails, directApp, vpApp, String.valueOf(i))); - } - } else - distributionSummary.add(formAgingDistributionSummary(appDetails, - directApp, vpApp, severity)); - - return distributionSummary; - } - - /** - * Form aging distribution summary. - * - * @param appDetails the app details - * @param directApp the direct app - * @param vpApp the vp app - * @param severity the severity - * @return the map - */ - @SuppressWarnings("unchecked") - private Map formAgingDistributionSummary( - Map appDetails, Map directApp, - Map vpApp, String severity) { - - List> vpData = new ArrayList<>(); - List> directorData = new ArrayList<>(); - List> appData = new ArrayList<>(); - - ObjectMapper oMapper = new ObjectMapper(); - - for (Entry entry : appDetails.entrySet()) { - String appName = entry.getKey(); - Map sev = oMapper.convertValue(entry.getValue(), - Map.class); - Map appTemp = new HashMap<>(); - appTemp.put("name", appName); - Map sevInfo = oMapper.convertValue( - sev.get("S" + severity), Map.class); - if (sevInfo.get(COUNT).toString().equals(ZERO) - || sevInfo.get(COUNT).toString().equals(DOUBLE_ZERO)) { - appTemp.put("days", 0); - } else { - appTemp.put("days", Math.floor(Double.valueOf(sevInfo.get( - "days").toString()) - / Double.valueOf(sevInfo.get(COUNT).toString()))); - } - - appData.add(appTemp); - if (!directorData.isEmpty()) { - String director; - if (StringUtils.isEmpty(directApp.get(appName))) - director = UNKNOWN; - else - director = directApp.get(appName); - - boolean directorExists = false; - for (Map existingDirectorData : directorData) { - if (director.equals(existingDirectorData.get("name"))) { - existingDirectorData.put( - "days", - Double.valueOf(existingDirectorData.get("days") - .toString()) - + Double.valueOf(sevInfo.get("days") - .toString())); - existingDirectorData.put( - COUNT, - Double.valueOf(existingDirectorData.get(COUNT) - .toString()) - + Double.valueOf(sevInfo.get(COUNT) - .toString())); - directorExists = true; - break; - } - } - if (!directorExists) { - Map directorTemp = new HashMap<>(); - directorTemp.put("name", director); - directorTemp.put("days", sevInfo.get("days")); - directorTemp.put(COUNT, sevInfo.get(COUNT)); - directorData.add(directorTemp); - } - } else { - Map directorTemp = new HashMap<>(); - if (StringUtils.isEmpty(directApp.get(appName))) { - directorTemp.put("name", UNKNOWN); - } else - directorTemp.put("name", directApp.get(appName)); - directorTemp.put("days", sevInfo.get("days")); - directorTemp.put(COUNT, sevInfo.get(COUNT)); - directorData.add(directorTemp); - } - - if (!vpData.isEmpty()) { - String vp; - if (StringUtils.isEmpty(vpApp.get(appName))) - vp = UNKNOWN; - else - vp = vpApp.get(appName); - - boolean vpExists = false; - for (Map existingVpData : vpData) { - if (vp.equals(existingVpData.get("name"))) { - existingVpData.put( - "days", - Double.valueOf(existingVpData.get("days") - .toString()) - + Double.valueOf(sevInfo.get("days") - .toString())); - existingVpData.put( - COUNT, - Double.valueOf(existingVpData.get(COUNT) - .toString()) - + Double.valueOf(sevInfo.get(COUNT) - .toString())); - vpExists = true; - break; - } - } - if (!vpExists) { - Map vpTemp = new HashMap<>(); - vpTemp.put("name", vp); - vpTemp.put("days", sevInfo.get("days")); - vpTemp.put(COUNT, sevInfo.get(COUNT)); - vpData.add(vpTemp); - } - } else { - Map vpTemp = new HashMap<>(); - if (StringUtils.isEmpty(vpApp.get(appName))) { - vpTemp.put("name", UNKNOWN); - } else - vpTemp.put("name", vpApp.get(appName)); - vpTemp.put("days", sevInfo.get("days")); - vpTemp.put(COUNT, sevInfo.get(COUNT)); - vpData.add(vpTemp); - } - } - - directorData.parallelStream().forEach( - director -> { - if (director.get(COUNT).toString().equals(ZERO) - || director.get(COUNT).toString() - .equals(DOUBLE_ZERO)) { - director.put("days", 0); - } else { - director.put("days", - Math.floor(Double.valueOf(director.get("days") - .toString()) - / Double.valueOf(director.get(COUNT) - .toString()))); - } - director.remove(COUNT); - }); - vpData.parallelStream().forEach( - vp -> { - if (vp.get(COUNT).toString().equals(ZERO) - || vp.get(COUNT).toString().equals(DOUBLE_ZERO)) { - vp.put("days", 0); - } else { - vp.put("days", Math.floor(Double.valueOf(vp.get("days") - .toString()) - / Double.valueOf(vp.get(COUNT).toString()))); - } - vp.remove(COUNT); - }); - - Map vpInfo = new LinkedHashMap<>(); - vpInfo.put("type", "VP"); - vpInfo.put("data", vpData); - Map directorInfo = new LinkedHashMap<>(); - directorInfo.put("type", "Director"); - directorInfo.put("data", directorData); - Map appInfo = new LinkedHashMap<>(); - appInfo.put("type", "Application"); - appInfo.put("data", appData); - - List> distributionList = new ArrayList<>(); - distributionList.add(vpInfo); - distributionList.add(directorInfo); - distributionList.add(appInfo); - - Map severityMap = new HashMap<>(); - severityMap.put(SEVERITY, Integer.valueOf(severity)); - severityMap.put("distribution", distributionList); - return severityMap; - } - - /** - * Gets the vulnerability by qid. - * - * @param qid the qid - * @return the vulnerability by qid - */ - public List> getVulnerabilityByQid(String qid) { - - List> vulnByCategories = new ArrayList<>(); - Map vulnKbData = vulnerabilityRepository - .getVulnerabilityByQid(qid); - vulnByCategories.add(formGeneralCategory(vulnKbData)); - vulnByCategories.add(formDetailsCategory(vulnKbData)); - vulnByCategories.add(formSoftwareCategory(vulnKbData)); - vulnByCategories.add(formImpactCategory(vulnKbData)); - vulnByCategories.add(formThreatCategory(vulnKbData)); - vulnByCategories.add(formSolutionCategory(vulnKbData)); - vulnByCategories.add(formExploitabilityCategory(vulnKbData)); - vulnByCategories.add(formAssociatedMalware(vulnKbData)); - return vulnByCategories; - } - - /** - * Form general category. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - @SuppressWarnings("unchecked") - private Map formGeneralCategory( - Map vulnKbData) { - - ObjectMapper oMapper = new ObjectMapper(); - - Map category = new LinkedHashMap<>(); - category.put("name", "General Information"); - Map attributes = new LinkedHashMap<>(); - attributes.put("QID", - null == vulnKbData.get("qid") ? "" : vulnKbData.get("qid")); - attributes.put("Title", - null == vulnKbData.get(TITLE) ? "" : vulnKbData.get(TITLE)); - attributes.put( - "Severity Level", - null == vulnKbData.get(SEVEITY_LEVEL) ? "" : vulnKbData - .get(SEVEITY_LEVEL)); - attributes.put( - "Vulnerability Type", - null == vulnKbData.get(VULN_TYPE) ? "" : vulnKbData - .get(VULN_TYPE)); - attributes.put("Category", null == vulnKbData.get(CATEGORY) ? "" - : vulnKbData.get(CATEGORY)); - - Map discovery = oMapper.convertValue( - vulnKbData.get("discovery"), Map.class); - - if (discovery != null) { - attributes - .put("Authentication", - fetchAttributes(discovery, "authtypelist", - "authtype", true)); - } - - attributes.put("Service Modified", - null == vulnKbData.get("lastservicemodificationdatetime") ? "" - : vulnKbData.get("lastservicemodificationdatetime")); - attributes.put( - "Published", - null == vulnKbData.get("publisheddatetime") ? "" : vulnKbData - .get("publisheddatetime")); - - category.put(ATTRIBUTES, attributes); - return category; - } - - /** - * Form details category. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - @SuppressWarnings("unchecked") - private Map formDetailsCategory( - Map vulnKbData) { - ObjectMapper oMapper = new ObjectMapper(); - Map category = new HashMap<>(); - category.put("name", "Details"); - Map attributes = new LinkedHashMap<>(); - if (Arrays.asList( - fetchAttributes(vulnKbData, "discovery", "additionalinfo", - false).toString().split("\\s*,\\s*")).contains( - "Patch Available")) { - attributes.put("Patch Availble", "Yes"); - } else - attributes.put("Patch Availble", "No"); - - attributes.put("CVE ID", - fetchAttributes(vulnKbData, "cvelist", "cve", true)); - attributes.put( - "Vendor Reference", - fetchAttributes(vulnKbData, "vendorreferencelist", - "vendorreference", true)); - attributes.put("Bugtraq ID", - fetchAttributes(vulnKbData, "bugtraqlist", "bugtraq", true)); - - if (null != vulnKbData.get("pciflag")) { - attributes.put("PCI Flag", Double.valueOf(vulnKbData.get("pciflag") - .toString()) == 0 ? false : true); - } - - attributes.put("PCI Reasons", - fetchAttributes(vulnKbData, "pcireasons", "pcireason", true)); - if (null != vulnKbData.get("supportedmodules")) { - attributes.put("Supported Modules", - vulnKbData.get("supportedmodules")); - } - - Map cvss = oMapper.convertValue(vulnKbData.get("cvss"), - Map.class); - Map cvss3 = oMapper.convertValue( - vulnKbData.get("cvssv3"), Map.class); - if (cvss != null) { - attributes.put("CVSS Base", cvss.get("base")); - attributes.put("CVSS Temporal", cvss.get("temporal")); - attributes.put("CVSS Access Vector", - fetchAttributes(cvss, "access", "vector", false)); - } - if (cvss3 != null) { - attributes.put("CVSS3 Base", cvss3.get("base")); - attributes.put("CVSS3 Temporal", cvss3.get("temporal")); - } - - category.put(ATTRIBUTES, attributes); - return category; - } - - /** - * Form software category. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - private Map formSoftwareCategory( - Map vulnKbData) { - - Map category = new HashMap<>(); - category.put("name", "Software"); - category.put(ATTRIBUTES, - fetchAttributes(vulnKbData, "softwarelist", "software", true)); - return category; - } - - /** - * Form threat category. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - private Map formThreatCategory( - Map vulnKbData) { - - Map category = new HashMap<>(); - category.put("name", "Threat"); - category.put(ATTRIBUTES, null == vulnKbData.get("diagnosis") ? "" - : vulnKbData.get("diagnosis")); - return category; - } - - /** - * Form impact category. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - private Map formImpactCategory( - Map vulnKbData) { - - Map category = new HashMap<>(); - category.put("name", "Impact"); - category.put(ATTRIBUTES, null == vulnKbData.get("consequence") ? "" - : vulnKbData.get("consequence")); - return category; - } - - /** - * Form solution category. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - private Map formSolutionCategory( - Map vulnKbData) { - - Map category = new HashMap<>(); - category.put("name", "Solution"); - category.put(ATTRIBUTES, null == vulnKbData.get("solution") ? "" - : vulnKbData.get("solution")); - return category; - } - - /** - * Form exploitability category. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - @SuppressWarnings("unchecked") - private Map formExploitabilityCategory( - Map vulnKbData) { - - ObjectMapper oMapper = new ObjectMapper(); - List> attributes = new ArrayList<>(); - Map category = new HashMap<>(); - category.put("name", "Exploitability"); - - Map correlation = oMapper.convertValue( - vulnKbData.get("correlation"), Map.class); - if (correlation != null && !correlation.isEmpty()) { - List> exploits = (List>) fetchAttributes( - correlation, "exploits", "expltsrc", true); - for (Map exploitTemp : exploits) { - Map exploit = new HashMap<>(); - exploit.put(SRC_NAME, exploitTemp.get(SRC_NAME)); - exploit.put( - "exploits", - fetchAttributes(exploitTemp, "expltlist", "explt", true)); - attributes.add(exploit); - } - } - category.put(ATTRIBUTES, attributes); - return category; - } - - /** - * Form associated malware. - * - * @param vulnKbData the vuln kb data - * @return the map - */ - @SuppressWarnings("unchecked") - private Map formAssociatedMalware( - Map vulnKbData) { - ObjectMapper oMapper = new ObjectMapper(); - List> attributes = new ArrayList<>(); - Map category = new HashMap<>(); - category.put("name", "Malware"); - - Map correlation = oMapper.convertValue( - vulnKbData.get("correlation"), Map.class); - if (correlation != null && !correlation.isEmpty()) { - List> exploits = (List>) fetchAttributes( - correlation, "malware", "mwsrc", true); - for (Map exploitTemp : exploits) { - Map exploit = new HashMap<>(); - exploit.put(SRC_NAME, exploitTemp.get(SRC_NAME)); - exploit.put("malwares", - fetchAttributes(exploitTemp, "mwlist", "mwinfo", true)); - attributes.add(exploit); - } - } - category.put(ATTRIBUTES, attributes); - return category; - } - - /** - * Fetch attributes. - * - * @param vulnKbData the vuln kb data - * @param parent the parent - * @param child the child - * @param isList the is list - * @return the object - */ - @SuppressWarnings("unchecked") - private Object fetchAttributes(Map vulnKbData, - String parent, String child, boolean isList) { - Map parentMap = new ObjectMapper().convertValue( - vulnKbData.get(parent), Map.class); - Object childObj; - if (parentMap != null) { - childObj = parentMap.get(child); - if (childObj != null) - return childObj; - } - - if (isList) { - return new ArrayList<>(); - } else { - return ""; - } - } - - /** - * Gets the distribution summary. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary - */ - @SuppressWarnings("unchecked") - private Map> getDistributionSummary(String assetGroup, String severity) { - - List> vulnApplications = new ArrayList<>(); - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - if (!vulnTargetTypes.isEmpty()) { - for (String parentType : vulnTargetTypes) { - try { - vulnApplications.addAll(vulnerabilityRepository - .getVulnerabilyAcrossAppAndEnv(assetGroup, - "tags.Application.keyword", "", parentType, - severity)); - } catch (Exception e) { - logger.error("Exception in getting getDistributionSummary ",e); - } - } - } - - Map> appDetails = new ConcurrentHashMap<>(); - vulnApplications - .parallelStream() - .forEach( - vulnApps -> { - List> severityInfo = (List>) vulnApps - .get(SEV_INFO); - Map sevDetails = new HashMap<>(); - severityInfo.forEach(sevInfo -> { - sevDetails.put( - sevInfo.get(SEVERITY).toString(), - sevInfo.get(COUNT)); - }); - appDetails.put(vulnApps.get("application") - .toString(), sevDetails); - }); - return appDetails; - } - - /** - * Form director and VP by app. - * - * @param directApp the direct app - * @param vpApp the vp app - */ - private void formDirectorAndVPByApp(Map directApp, Map vpApp) { - try { - vulnerabilityRepository - .fetchExecDirectorApps() - .parallelStream() - .forEach( - app -> { - if(null != directApp) { - directApp.put(app.get(APP_TAG).toString(), app - .get("director").toString()); - } - if(null != vpApp) { - vpApp.put(app.get(APP_TAG).toString(), - app.get("executiveSponsor").toString()); - } - }); - - } catch (Exception e) { - logger.error(e); - } - } - - /** - * Gets the highest lowest performers. - * - * @param assetGroup the asset group - * @param severity the severity - * @param type the type - * @return the highest lowest performers - */ - @SuppressWarnings("unchecked") - public Map getHighestLowestPerformers(String assetGroup, String severity,String type) { - - Map appDetails = new HashMap<>(); - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - - if(StringUtils.isBlank(severity)) { - severity=SEVERITY_LEVELS; - } - Map perfData = new HashMap<>(); - - if("org".equalsIgnoreCase(type)){ - if (!vulnTargetTypes.isEmpty()) { - for (String parentType : vulnTargetTypes) { - try { - Map appDetailsTemp = vulnerabilityRepository.getAppsBySeverity(assetGroup, parentType, severity); - if(appDetails.isEmpty()) { - appDetails = new HashMap<>(appDetailsTemp); - } else { - for(Entry appDetailTemp : appDetailsTemp.entrySet()) { - boolean appExists = false; - for(Entry appDetail : appDetails.entrySet()) { - if(appDetail.getKey().equals(appDetailTemp.getKey())){ - appDetails.put(appDetail.getKey(),appDetail.getValue()+appDetailTemp.getValue()); - appExists = true; - break; - } - } - if(!appExists) { - appDetails.put(appDetailTemp.getKey(),appDetailTemp.getValue()); - } - } - } - } catch (Exception e) { - logger.error("Exception in getHighestLowestPeformers ",e); - } - } - } - - Map directApp = new ConcurrentHashMap<>(); - formDirectorAndVPByApp(directApp, null); - - - for (Entry entry : appDetails.entrySet()) { - - String appName = entry.getKey(); - - if (!perfData.isEmpty()) { - String director; - if (StringUtils.isEmpty(directApp.get(appName))) - director = UNKNOWN; - else - director = directApp.get(appName).trim(); - - boolean directorExists = false; - for (Entry existingDirectorData : perfData.entrySet()) { - if (director.equals(existingDirectorData.getKey())) { - perfData.put( - director,existingDirectorData.getValue()+ Integer.valueOf(entry.getValue().toString())); - directorExists = true; - break; - } - } - if (!directorExists) { - perfData.put(director, Integer.valueOf(entry.getValue().toString())); - } - } else { - if(StringUtils.isEmpty(directApp.get(appName))) { - perfData.put(UNKNOWN, Integer.valueOf(entry.getValue().toString())); - } else - perfData.put(directApp.get(appName),Integer.valueOf(entry.getValue().toString())); - } - } - - }else if(APPLICATION.equalsIgnoreCase(type)){ - try{ - List> vulnApplications = getVulnerabilityByAppAndEnv( - assetGroup, TAGS_APPS, ""); - for(Map appInfo:vulnApplications) { - String app = appInfo.get(APPS).toString(); - List> sevInfo = (List>)appInfo.get(SEV_INFO); - perfData.put(app, getVulnInstanceCount(sevInfo,severity)); - } - }catch(Exception e){ - - } - - }else if(ENVIRONMENT.equalsIgnoreCase(type)){ - - try{ - List> vulnEnvmnts = getVulnerabilityByAppAndEnv( - assetGroup, TAGS_ENV, ""); - for(Map envInfo:vulnEnvmnts) { - String env = envInfo.get(ENV).toString(); - List> sevInfo = (List>)envInfo.get(SEV_INFO); - perfData.put(env, getVulnInstanceCount(sevInfo,severity)); - } - }catch(Exception e){ - - } - } - - return perfData.entrySet().stream() - .sorted(Map.Entry.comparingByValue()) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, - (oldValue, newValue) -> oldValue, LinkedHashMap::new)); - } - - /** - * Gets the vuln instance count. - * - * @param sevInfoList the sev info list - * @param severity the severity - * @return the vuln instance count - */ - private int getVulnInstanceCount(List> sevInfoList, String severity){ - List sevList = Arrays.asList(severity.split(",")); - return sevInfoList.stream().filter(sevInfo-> sevList.contains(sevInfo.get("severitylevel").toString())).mapToInt(sevInfo-> Double.valueOf(sevInfo.get("vulnInstanceCount").toString()).intValue()).sum(); - } - - /** - * Gets the vuln target types. - * - * @param assetGroup the asset group - * @return the vuln target types - */ - private List getVulnTargetTypes(String assetGroup) { - - String validTargetTypes = getTargetTypes(assetGroup); - List vulnTargetTypes = new ArrayList<>(); - for (String vulnType : vulnTypes.split(",")) { - if (!StringUtils.isEmpty(validTargetTypes) - && validTargetTypes.contains(vulnType.trim())) { - vulnTargetTypes.add(vulnType); - } - } - return vulnTargetTypes; - } - - /** - * Gets the distribution summary by infra type. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary by infra type - * @throws ServiceException the service exception - */ - public List> getDistributionSummaryByInfraType(String assetGroup, String severity) throws ServiceException { - - List> distributionList = new ArrayList<>(); - - List vulnTargetTypes = getVulnTargetTypes(assetGroup); - if(StringUtils.isBlank(severity)) { - severity=SEVERITY_LEVELS; - } - long totalVulnCount = 0; - for (String vulnType : vulnTargetTypes) { - Map info = new HashMap<>(); - try{ - info = vulnerabilityRepository. - getDistributionSummaryByInfraType(assetGroup, severity, vulnType); - }catch(Exception e){ - logger.error("Error in getDistributionSummaryByInfraType ", e); - throw new ServiceException(); - } - - totalVulnCount += Long.valueOf(info.get(VULNEREBILITIES).toString()); - - if(vulnType.equals(EC2)) { - info.put(CATEGORY, "Cloud"); - } else { - info.put(CATEGORY, "On-Prem"); - } - distributionList.add(info); - } - - double contribution = HUNDRED; - for(int i=0;i info = distributionList.get(i); - double contributionPercent = Math.floor((Double.valueOf(info.get(VULNEREBILITIES).toString())/totalVulnCount)*HUNDRED); - if(i== distributionList.size()-1){ - info.put(CONTRIBUTION, contribution); - }else{ - info.put(CONTRIBUTION, contributionPercent); - contribution = contribution-contributionPercent; - } - } - return distributionList; - } - - /** - * Gets the distribution summary by env. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary by env - * @throws ServiceException the service exception - */ - public List> getDistributionSummaryByEnv(String assetGroup, String severity) throws ServiceException { - - List> distributionList = new ArrayList<>(); - if(StringUtils.isBlank(severity)) { - severity=SEVERITY_LEVELS; - } - - long totalVulnCount = 0; - - Map prodInfo = new HashMap<>(); - prodInfo.put(TOTAL_VULN_ASSETS, 0); - prodInfo.put(VULNEREBILITIES, 0); - prodInfo.put(UNIQUE_VULN_COUNT, 0); - - Map nonProdInfo = new HashMap<>(); - nonProdInfo.put(TOTAL_VULN_ASSETS, 0); - nonProdInfo.put(VULNEREBILITIES, 0); - nonProdInfo.put(UNIQUE_VULN_COUNT, 0); - try { - Map prodInfoTemp = vulnerabilityRepository.getProdInfoByEnv(assetGroup, severity); - Map nonProdInfoTemp = vulnerabilityRepository.getNonProdInfoByEnv(assetGroup, severity); - - totalVulnCount += prodInfoTemp.get(VULNEREBILITIES)+nonProdInfoTemp.get(VULNEREBILITIES); - - for (Entry entry : prodInfo.entrySet()) { - prodInfo.put(entry.getKey(), Long.valueOf(entry.getValue().toString())+prodInfoTemp.get(entry.getKey())); - } - - for (Entry entry : nonProdInfo.entrySet()) { - nonProdInfo.put(entry.getKey(), Long.valueOf(entry.getValue().toString())+nonProdInfoTemp.get(entry.getKey())); - } - } catch (Exception e) { - throw new ServiceException(e); - } - prodInfo.put(CATEGORY,"Prod"); - distributionList.add(prodInfo); - nonProdInfo.put(CATEGORY,"Non-Prod"); - distributionList.add(nonProdInfo); - - double contribution = HUNDRED; - for(int i=0;i info = distributionList.get(i); - if(totalVulnCount > 0) { - double contributionPercent = Math.floor((Double.valueOf(info.get(VULNEREBILITIES).toString())/totalVulnCount)*HUNDRED); - if(i== distributionList.size()-1){ - info.put(CONTRIBUTION, contribution); - }else{ - info.put(CONTRIBUTION, contributionPercent); - contribution = contribution-contributionPercent; - } - } else { - info.put(CONTRIBUTION, 0); - } - } - return distributionList; - } - - /** - * Gets the distribution summary by vuln type. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the distribution summary by vuln type - * @throws DataException the data exception - */ - public List> getDistributionSummaryByVulnType(String assetGroup, String severity) throws DataException { - if(StringUtils.isBlank(severity)) { - severity=SEVERITY_LEVELS; - } - return vulnerabilityRepository.getDistributionSummaryByVulnType(assetGroup, severity); - } - - /** - * Gets the remediation actions summary. - * - * @param assetGroup the asset group - * @param severity the severity - * @return the remediation actions summary - * @throws DataException the data exception - */ - public List> getRemediationActionsSummary(String assetGroup, String severity) throws DataException { - - List> remediationList = new ArrayList<>(); - if(StringUtils.isBlank(severity)) { - severity=SEVERITY_LEVELS; - } - - List> eolActions = vulnerabilityRepository.getDataFromPacmanRDS("SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " - + "action='Remove/Replace EOL Software'"); - List> stopRemoveActions = vulnerabilityRepository.getDataFromPacmanRDS("SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " - + "action='Stop Service/Remove Software'"); - List> swConfigChangeActions = vulnerabilityRepository.getDataFromPacmanRDS("SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " - + "action='Software Configuration Change'"); - List> swUpdateActions = vulnerabilityRepository.getDataFromPacmanRDS("SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " - + "action='Software Update'"); - - String softwareConfig = getAllMatchingString(swConfigChangeActions); - String softwareUpdate = getAllMatchingString(swUpdateActions); - - Map osPatching = new HashMap<>(); - osPatching.put(ACTION, "OS Patching"); - osPatching.put(DESCRIPTION, "Apply the patches released by the operating system provider"); - osPatching.put(CONTRIBUTION, 0); - Map eolSoftware = new HashMap<>(); - eolSoftware.put(ACTION, "Remove/Replace EOL Software"); - eolSoftware.put(CONTRIBUTION, 0); - eolSoftware.put(DESCRIPTION, "Remove or replace below listed End of Life Software versions"); - Map noSolution = new HashMap<>(); - noSolution.put(ACTION, "No Solution Available"); - noSolution.put(CONTRIBUTION, 0); - noSolution.put(DESCRIPTION, "Vulnerabilities with no published solution yet"); - Map stopRemove = new HashMap<>(); - stopRemove.put(ACTION, "Stop Service/Remove Software"); - stopRemove.put(CONTRIBUTION, 0); - stopRemove.put(DESCRIPTION, "Stop unimportant vulnerable services, remove malicious softwares from the hosts"); - Map swConfigChange = new HashMap<>(); - swConfigChange.put(ACTION, "Software Configuration Change"); - swConfigChange.put(CONTRIBUTION, 0); - swConfigChange.put(DESCRIPTION, "Fix the configurations of the below listed softwares. Some default configurations like default admin username and password should be replaced with a stronger one"); - Map swUpdate = new HashMap<>(); - swUpdate.put(ACTION, "Software Update"); - swUpdate.put(CONTRIBUTION, 0); - swUpdate.put(DESCRIPTION, "Update the below listed softwares to their latest version or apply patches released by the software provider "); - - List> eolSubActions = new ArrayList<>(); - List> stopRemoveSubActions = new ArrayList<>(); - List> swConfigChangeSubActions = new ArrayList<>(); - List> swUpdateSubActions = new ArrayList<>(); - - Map unclassified = new HashMap<>(); - unclassified.put(ACTION, "Unclassified"); - unclassified.put(DESCRIPTION, "These vulnerabilities are not classified yet. Refer the vulnerability description to fix the vulnerability"); - unclassified.put(CONTRIBUTION, 0); - - Map qids = vulnerabilityRepository.getAllQidByAG(assetGroup, severity); - Long total = qids.entrySet().stream().mapToLong(entry-> Long.valueOf(entry.getValue().toString())).sum(); - for (String qidTitleClass: qids.keySet()) { - String qid = qidTitleClass.split("~")[0]; - String vulnTitle = qidTitleClass.split("~")[1].toLowerCase(); - String classification = qidTitleClass.split("~")[2]; - if("OS".equalsIgnoreCase(classification)){ - osPatching.put(CONTRIBUTION, Long.valueOf(osPatching.get(CONTRIBUTION).toString())+Long.valueOf(qids.get(qidTitleClass).toString())); - }else if(vulnTitle.contains("EOL/Obsolete".toLowerCase())) { - eolSoftware.put(CONTRIBUTION, Long.valueOf(eolSoftware.get(CONTRIBUTION).toString())+Long.valueOf(qids.get(qidTitleClass).toString())); - formSubActionList(eolActions,eolSubActions,vulnTitle,Long.valueOf(qids.get(qidTitleClass).toString())); - } else if("11925".equals(qid) || "370914".equals(qid)) { - noSolution.put(CONTRIBUTION, Long.valueOf(noSolution.get(CONTRIBUTION).toString())+Long.valueOf(qids.get(qidTitleClass).toString())); - } else if(vulnTitle.contains("Java Debug Wire Protocol".toLowerCase())) { - stopRemove.put(CONTRIBUTION, Long.valueOf(stopRemove.get(CONTRIBUTION).toString())+Long.valueOf(qids.get(qidTitleClass).toString())); - formSubActionList(stopRemoveActions,stopRemoveSubActions,vulnTitle,Long.valueOf(qids.get(qidTitleClass).toString())); - } else if(checkVulnTitle(vulnTitle,softwareConfig)) { - swConfigChange.put(CONTRIBUTION, Long.valueOf(swConfigChange.get(CONTRIBUTION).toString())+Long.valueOf(qids.get(qidTitleClass).toString())); - formSubActionList(swConfigChangeActions,swConfigChangeSubActions,vulnTitle,Long.valueOf(qids.get(qidTitleClass).toString())); - } else if(checkVulnTitle(vulnTitle,softwareUpdate)) { - swUpdate.put(CONTRIBUTION, Long.valueOf(swUpdate.get(CONTRIBUTION).toString())+Long.valueOf(qids.get(qidTitleClass).toString())); - formSubActionList(swUpdateActions,swUpdateSubActions,vulnTitle,Long.valueOf(qids.get(qidTitleClass).toString())); - } else { - unclassified.put(CONTRIBUTION, Long.valueOf(unclassified.get(CONTRIBUTION).toString())+Long.valueOf(qids.get(qidTitleClass).toString())); - } - } - - calculateContributionPercentage(eolSubActions,Long.valueOf(eolSoftware.get(CONTRIBUTION).toString())); - calculateContributionPercentage(stopRemoveSubActions,Long.valueOf(stopRemove.get(CONTRIBUTION).toString())); - calculateContributionPercentage(swConfigChangeSubActions,Long.valueOf(swConfigChange.get(CONTRIBUTION).toString())); - calculateContributionPercentage(swUpdateSubActions,Long.valueOf(swUpdate.get(CONTRIBUTION).toString())); - - eolSoftware.put(SUB_ACTIONS, eolSubActions); - stopRemove.put(SUB_ACTIONS, stopRemoveSubActions); - swConfigChange.put(SUB_ACTIONS, swConfigChangeSubActions); - swUpdate.put(SUB_ACTIONS, swUpdateSubActions); - - remediationList.add(osPatching); - remediationList.add(eolSoftware); - remediationList.add(noSolution); - remediationList.add(stopRemove); - remediationList.add(swConfigChange); - remediationList.add(swUpdate); - remediationList.add(unclassified); - - calculateContributionPercentage(remediationList,total); - return remediationList; - } - - /** - * Check vuln title. - * - * @param vulnTitle the vuln title - * @param values the values - * @return true, if successful - */ - private boolean checkVulnTitle(String vulnTitle, String values) { - for(String value : values.split(",")) { - if(vulnTitle.contains(value)) { - return true; - } - } - return false; - } - - /** - * Form sub action list. - * - * @param actions the actions - * @param subActions the sub actions - * @param vulnTitle the vuln title - * @param contribution the contribution - */ - private void formSubActionList(List> actions, List> subActions,String vulnTitle, long contribution) { - boolean titleMatched = false; - for(Map action : actions) { - if(vulnTitle.contains(action.get(MATCHING_STRING).toString().toLowerCase())) { - titleMatched = true; - formSubAction(subActions, action.get("subAction").toString(), action.get(MATCHING_STRING).toString(), contribution); - break; - } - } - if(!titleMatched) { - formSubAction(subActions, "Others", "Others", contribution); - } - } - - /** - * Form sub action. - * - * @param subActions the sub actions - * @param subActionTitle the sub action title - * @param subActiondescr the sub actiondescr - * @param contribution the contribution - */ - private void formSubAction(List> subActions, String subActionTitle, String subActiondescr, Long contribution) { - if(subActions.isEmpty()) { - Map subAction = new HashMap<>(); - subAction.put(ACTION, subActionTitle); - subAction.put(DESCRIPTION, subActiondescr); - subAction.put(CONTRIBUTION, contribution); - subActions.add(subAction); - } else { - boolean subActionExists = false; - for(Map subAction : subActions) { - if(subActionTitle.equals(subAction.get(ACTION).toString())) { - subActionExists = true; - subAction.put(CONTRIBUTION, Long.valueOf(subAction.get(CONTRIBUTION).toString())+contribution); - break; - } - } - if(!subActionExists) { - Map subAction = new HashMap<>(); - subAction.put(ACTION, subActionTitle); - subAction.put(DESCRIPTION, subActiondescr); - subAction.put(CONTRIBUTION, contribution); - subActions.add(subAction); - } - } - } - - /** - * Gets the all matching string. - * - * @param actions the actions - * @return the all matching string - */ - private String getAllMatchingString(List> actions) { - List matchingStrings = new ArrayList<>(); - for(Map action : actions) { - matchingStrings.add(action.get(MATCHING_STRING).toString().toLowerCase()); - } - return StringUtils.join(matchingStrings, ","); - } - - /** - * Calculate contribution percentage. - * - * @param contributionList the contribution list - * @param total the total - */ - private void calculateContributionPercentage(List> contributionList, long total) { - DecimalFormat df = new DecimalFormat("###.##"); - ListIterator> it = contributionList.listIterator(); - String contributionPercent; - while(it.hasNext()){ - Map bucket = it.next(); - Long contribution = Long.valueOf(bucket.get(CONTRIBUTION).toString()); - if(contribution==0){ - it.remove(); - }else{ - contributionPercent = df.format((contribution*HUNDRED)/total); - if("0".equals(contributionPercent)){ - it.remove(); - }else{ - bucket.put(CONTRIBUTION, Float.valueOf(contributionPercent)); - } - } - } - } - - /** - * Creates the trend annotation. - * - * @param request the request - * @return true, if successful - * @throws JsonProcessingException the json processing exception - */ - public boolean createTrendAnnotation(TrendNote request) throws JsonProcessingException { - return vulnerabilityRepository.createTrendAnnotation(request); - } - - /** - * Gets the trend annotations. - * - * @param assetGroup the asset group - * @param from the from - * @return the trend annotations - * @throws DataException the data exception - */ - public List> getTrendAnnotations(String assetGroup, Date from) throws DataException { - - List> globalAnnotations = new ArrayList<>(); - List> assetGroupAnnotations = new ArrayList<>(); - List> annotations = vulnerabilityRepository.getTrendAnnotations(assetGroup,from); - - annotations.parallelStream().forEach(annotation -> { - if(StringUtils.isEmpty(annotation.get("ag").toString())) { - synchronized (globalAnnotations) { - globalAnnotations.add(annotation); - } - } else { - synchronized (assetGroupAnnotations) { - assetGroupAnnotations.add(annotation); - } - } - }); - - Map gloablMap = new HashMap<>(); - gloablMap.put("type", "Global"); - gloablMap.put("data", globalAnnotations); - - Map agMap = new HashMap<>(); - agMap.put("type", "AssetGroup"); - agMap.put("data", assetGroupAnnotations); - - List> noteList = new ArrayList<>(); - noteList.add(agMap); - noteList.add(gloablMap); - - return noteList; - } - - /** - * Delete trend annotation. - * - * @param noteId the note id - * @return true, if successful - */ - public boolean deleteTrendAnnotation(String noteId) { - return vulnerabilityRepository.deleteTrendAnnotation(noteId); - } -} diff --git a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/controller/ComplianceControllerTest.java b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/controller/ComplianceControllerTest.java index a0d66062e..f5a0d0fc6 100644 --- a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/controller/ComplianceControllerTest.java +++ b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/controller/ComplianceControllerTest.java @@ -43,7 +43,6 @@ import com.tmobile.pacman.api.compliance.domain.PolicyViolationDetails; import com.tmobile.pacman.api.compliance.domain.RevokeIssuesException; import com.tmobile.pacman.api.compliance.service.ComplianceService; -import com.tmobile.pacman.api.compliance.service.VulnerabilityService; import com.tmobile.pacman.api.compliance.util.CommonTestUtil; @RunWith(MockitoJUnitRunner.class) @@ -55,9 +54,6 @@ public class ComplianceControllerTest { @Mock ComplianceService complianceService; - @Mock - VulnerabilityService vulnerabilityService; - @Test public void getIssuesTest() throws Exception { when(complianceService.getIssues(anyObject())).thenReturn(CommonTestUtil.getResponseWithOrder()); @@ -111,18 +107,6 @@ public void getTaggingTest() throws Exception { assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); } - @Test - public void getVulnerabilitiesTest() throws Exception { - when(vulnerabilityService.getVulnerabilitySummary(anyString(),anyString())).thenReturn(CommonTestUtil.getMapObject()); - assertThat(complianceController.getVulnerabilities("ag"), is(notNullValue())); - assertThat(complianceController.getVulnerabilities(""), is(notNullValue())); - - when(vulnerabilityService.getVulnerabilitySummary(anyString(),anyString())).thenThrow(new ServiceException()); - when(complianceService.formatException(anyObject())).thenReturn(ResponseUtils.buildFailureResponse(new ServiceException())); - ResponseEntity responseObj = complianceController.getVulnerabilities("ag"); - assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - @Test public void getCertificatesTest() throws Exception { when(complianceService.getCertificates(anyString())).thenReturn(CommonTestUtil.getMapLong()); diff --git a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/controller/VulnerabilityControllerTest.java b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/controller/VulnerabilityControllerTest.java deleted file mode 100644 index 53c151c0c..000000000 --- a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/controller/VulnerabilityControllerTest.java +++ /dev/null @@ -1,428 +0,0 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.compliance.controller; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.powermock.api.mockito.PowerMockito.when; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.powermock.modules.junit4.PowerMockRunner; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.exception.ServiceException; -import com.tmobile.pacman.api.compliance.domain.Request; -import com.tmobile.pacman.api.compliance.domain.TrendRequest; -import com.tmobile.pacman.api.compliance.service.VulnerabilityService; - -@RunWith(PowerMockRunner.class) -public class VulnerabilityControllerTest { - - @InjectMocks - VulnerabilityController vulnerabilityController; - - @Mock - VulnerabilityService vulnerabilityService; - - @Test - public void getVulnerabilitiesDetailsTest() throws Exception { - - List> vulnDetails = new ArrayList<>(); - - Request request = new Request(); - request.setAg("ag"); - request.setFrom(0); - - when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(new ArrayList<>()); - - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); - - request.setFilter(new HashMap<>()); - vulnDetails.add(new HashMap<>()); - vulnDetails.add(new HashMap<>()); - - when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(vulnDetails); - - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); - - request.setSize(1); - when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(vulnDetails); - - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); - - request.setSize(3); - when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(vulnDetails); - - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilitiesDetailsTest_Failure() throws Exception { - - Request request = new Request(); - - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - request.setAg("ag"); - request.setFrom(-1); - - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - request.setFrom(2); - List> vulnDetails = new ArrayList>(); - vulnDetails.add(new HashMap<>()); - - when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(vulnDetails); - - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getCertificatesDetailsTest_Exception() throws Exception { - - Request request = new Request(); - request.setAg("ag"); - request.setFrom(0); - - when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenThrow(new ServiceException()); - assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getVulnerabilitysummaryTest() throws Exception { - - when(vulnerabilityService.getVulnerabilitySummary(anyString(),anyString())).thenReturn(new HashMap<>()); - assertTrue(vulnerabilityController.getVulnerabilitysummary("ag","3,4,5").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilitysummaryTest_Exception() throws Exception { - - assertTrue(vulnerabilityController.getVulnerabilitysummary("","3,4,5").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - when(vulnerabilityService.getVulnerabilitySummary(anyString(),anyString())).thenThrow(new ServiceException()); - assertTrue(vulnerabilityController.getVulnerabilitysummary("ag","3,4,5").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getVulnerabilityByApplicationsTest() throws Exception { - - when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilityByApplications("ag").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilityByApplicationsTest_Exception() throws Exception { - - assertTrue(vulnerabilityController.getVulnerabilityByApplications("").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())).thenThrow(new Exception()); - assertTrue(vulnerabilityController.getVulnerabilityByApplications("ag").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getVulnerabilitiesTrendTest() throws Exception { - - TrendRequest request = new TrendRequest(); - request.setAg("ag"); - - when(vulnerabilityService.getVulnerabilityTrend(anyString(),anyObject(),anyObject(),anyObject())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); - - request.setFrom(new Date()); - when(vulnerabilityService.getVulnerabilityTrend(anyString(),anyObject(),anyObject(),anyObject())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); - - request.setTo(new Date()); - when(vulnerabilityService.getVulnerabilityTrend(anyString(),anyObject(),anyObject(),anyObject())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); - - request = new TrendRequest(); - request.setAg("ag"); - request.setTo(new Date()); - when(vulnerabilityService.getVulnerabilityTrend(anyString(),anyObject(),anyObject(),anyObject())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilitiesTrendTest_Exception() throws Exception { - - TrendRequest request = new TrendRequest(); - assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - request.setAg("ag"); - when(vulnerabilityService.getVulnerabilityTrend(anyString(),anyObject(),anyObject(),anyObject())).thenThrow(new ServiceException()); - assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getVulnerabilityByEnvironmentTest() throws Exception { - - when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilityByEnvironment("ag","app").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilityByEnvironmentTest_Exception() throws Exception { - - assertTrue(vulnerabilityController.getVulnerabilityByEnvironment("",null).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())).thenThrow(new Exception()); - assertTrue(vulnerabilityController.getVulnerabilityByEnvironment("ag","app").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getVulnerabilityDistributionTest() throws Exception { - - when(vulnerabilityService.getVulnerabilitiesDistribution(anyString())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilityDistribution("ag").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilityDistributionTest_Exception() throws Exception { - - assertTrue(vulnerabilityController.getVulnerabilityDistribution("").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - when(vulnerabilityService.getVulnerabilitiesDistribution(anyString())).thenThrow(new ServiceException()); - assertTrue(vulnerabilityController.getVulnerabilityDistribution("ag").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getVulnerabilitysummaryByResourceIdTest() throws Exception { - - when(vulnerabilityService.getVulnerabilitysummaryByResourceId(anyString())).thenReturn(new HashMap<>()); - assertTrue(vulnerabilityController.getVulnerabilitysummaryByResourceId("ag").getStatusCode() == HttpStatus.OK); - } - - /* @Test - public void getVulnerabilitysummaryByResourceIdTest_Exception() throws Exception { - - when(vulnerabilityService.getVulnerabilitysummaryByResourceId(anyString())).thenThrow(new Exception()); - assertTrue(vulnerabilityController.getVulnerabilitysummaryByResourceId("ag").getStatusCode() == HttpStatus.EXPECTATION_FAILED); - }*/ - - @Test - public void getVulnerabilityDetailsByResourceIdTest() throws Exception { - - when(vulnerabilityService.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(new ArrayList<>()); - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(new ArrayList<>()); - - assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id","search",0,0).getStatusCode() == HttpStatus.OK); - assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id","search",null,null).getStatusCode() == HttpStatus.OK); - - List> resourceDetails = new ArrayList<>(); - resourceDetails.add(new HashMap<>()); - resourceDetails.add(new HashMap<>()); - - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(resourceDetails); - assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id","search",0,0).getStatusCode() == HttpStatus.OK); - - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(resourceDetails); - assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id","search",0,1).getStatusCode() == HttpStatus.OK); - - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(resourceDetails); - assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id","search",0,3).getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilityDetailsByResourceIdTest_Exception() throws Exception { - - List> resourceDetails = new ArrayList<>(); - resourceDetails.add(new HashMap<>()); - - when(vulnerabilityService.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(new ArrayList<>()); - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenReturn(resourceDetails); - assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id","search",2,3).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - when(vulnerabilityService.filterMatchingCollectionElements(anyObject(),anyString(),anyBoolean())).thenThrow(new ServiceException()); - assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id","search",0,1).getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getVulnerabilityDistributionSummaryTest() throws Exception { - - when(vulnerabilityService.getVulnerabilityDistributionSummary(anyString(),anyString())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilityDistributionSummary("ag","sev").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getAgingDistributionSummaryTest() throws Exception { - - when(vulnerabilityService.getAgingDistributionSummary(anyString(),anyString())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getAgingDistributionSummary("ag","sev").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getAgingSummaryTest() throws Exception { - - when(vulnerabilityService.getAgingSummary(anyString())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getAgingSummary("ag").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulnerabilityByQidTest() throws Exception { - - when(vulnerabilityService.getVulnerabilityByQid(anyString())).thenReturn(new ArrayList<>()); - assertTrue(vulnerabilityController.getVulnerabilityByQid("qid").getStatusCode() == HttpStatus.OK); - } - - @Test - public void getDistributionSummaryByVulnTypeTest() throws Exception { - - when(vulnerabilityService.getDistributionSummaryByVulnType(anyString(), anyString())).thenReturn(new ArrayList<>()); - - ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByVulnType("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.OK); - } - - @Test - public void getDistributionSummaryByVulnTypeTest_Exception() throws Exception { - - when(vulnerabilityService.getDistributionSummaryByVulnType(anyString(), anyString())).thenThrow(new DataException()); - - ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByVulnType("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getDistributionSummaryByInfraTypeTest() throws Exception { - - when(vulnerabilityService.getDistributionSummaryByInfraType(anyString(), anyString())).thenReturn(new ArrayList<>()); - - ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByInfraType("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.OK); - } - - @Test - public void getDistributionSummaryByInfraTypeTest_Exception() throws Exception { - - when(vulnerabilityService.getDistributionSummaryByInfraType(anyString(), anyString())).thenThrow(new ServiceException()); - - ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByInfraType("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getDistributionSummaryByEnvTest() throws Exception { - - when(vulnerabilityService.getDistributionSummaryByEnv(anyString(), anyString())).thenReturn(new ArrayList<>()); - - ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByEnv("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.OK); - } - - @Test - public void getDistributionSummaryByEnvTest_Exception() throws Exception { - - when(vulnerabilityService.getDistributionSummaryByEnv(anyString(), anyString())).thenThrow(new ServiceException()); - - ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByEnv("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getRemediationActionsSummaryTest() throws Exception { - - when(vulnerabilityService.getRemediationActionsSummary(anyString(), anyString())).thenReturn(new ArrayList<>()); - - ResponseEntity responseObj = vulnerabilityController.getRemediationActionsSummary("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.OK); - } - - @Test - public void getRemediationActionsSummaryTest_Exception() throws Exception { - - when(vulnerabilityService.getRemediationActionsSummary(anyString(), anyString())).thenThrow(new DataException()); - - ResponseEntity responseObj = vulnerabilityController.getRemediationActionsSummary("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } - - @Test - public void getHighestLowestPeformersTest() throws Exception { - - Map directorData = new HashMap<>(); - directorData.put("dir1", 1); - directorData.put("dir2", 2); - - when(vulnerabilityService.getHighestLowestPerformers(anyString(), anyString(),anyString())).thenReturn(directorData); - - ResponseEntity responseObj = vulnerabilityController.getHighestLowestPerformers("ag","3"); - assertTrue(responseObj.getStatusCode() == HttpStatus.OK); - - } - - @Test - public void getVulerabilityTrendTest() throws Exception { - - TrendRequest request = new TrendRequest(); - request.setAg("ag"); - - when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(),anyString(),anyObject())).thenReturn(new ArrayList<>()); - - ResponseEntity responseObj = vulnerabilityController.getVulnerabilityTrend(request); - assertTrue(responseObj.getStatusCode() == HttpStatus.OK); - - request.setFrom(new Date()); - request.setFilter(new HashMap<>()); - - when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(),anyString(),anyObject())).thenReturn(new ArrayList<>()); - - ResponseEntity response1Obj = vulnerabilityController.getVulnerabilityTrend(request); - assertTrue(response1Obj.getStatusCode() == HttpStatus.OK); - - Map filter = new HashMap<>(); - filter.put("severity","3"); - request.setFilter(filter); - when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(),anyString(),anyObject())).thenReturn(new ArrayList<>()); - - ResponseEntity response2Obj = vulnerabilityController.getVulnerabilityTrend(request); - assertTrue(response2Obj.getStatusCode() == HttpStatus.OK); - } - - @Test - public void getVulerabilityTrendTest_Failure() throws Exception { - - TrendRequest request = new TrendRequest(); - - ResponseEntity responseObj = vulnerabilityController.getVulnerabilityTrend(request); - assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - - request.setAg("ag"); - when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(),anyString(),anyObject())).thenThrow(new Exception()); - - ResponseEntity response1 = vulnerabilityController.getVulnerabilityTrend(request); - assertTrue(response1.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - } -} diff --git a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImplTest.java b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImplTest.java index 9e6c4f766..3d4d6e759 100644 --- a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImplTest.java +++ b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/repository/ComplianceRepositoryImplTest.java @@ -74,8 +74,6 @@ public class ComplianceRepositoryImplTest implements Constants { @Mock AssetServiceClient assetServiceClient; - @Mock - VulnerabilityRepository vulnerabilityRepository; @Mock FilterRepository filterRepository; diff --git a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityRepositoryTest.java b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityRepositoryTest.java deleted file mode 100644 index 5ff3d1748..000000000 --- a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/repository/VulnerabilityRepositoryTest.java +++ /dev/null @@ -1,551 +0,0 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.compliance.repository; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.springframework.test.util.ReflectionTestUtils; - -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; -import com.tmobile.pacman.api.commons.repo.PacmanRdsRepository; -import com.tmobile.pacman.api.commons.utils.PacHttpUtils; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({PacHttpUtils.class}) -public class VulnerabilityRepositoryTest { - - @InjectMocks - private VulnerabilityRepository vulnerabilityRepository; - - @Mock - private ElasticSearchRepository elasticSearchRepository; - - @Mock - private PacmanRdsRepository rdsRepository; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void getAllVulnerabilitiesTest() throws Exception { - - String response = "{\"hits\":{\"total\":68,\"hits\":[{\"_index\":\"qualys-kb\",\"_type\":\"kb\",\"_id\":\"236591\",\"_score\":8.899231," - + "\"_source\":{\"qid\":\"236591\",\"vulntype\":\"Vulnerability\",\"severitylevel\":4,\"title\":\"Red Hat Update for kernel\"," - + "\"category\":\"RedHat\",\"lastservicemodificationdatetime\":\"2018-05-29T20:32:16z\",\"publisheddatetime\":\"2018-01-04T04:02:43z\"," - + "\"_loadDate\":\"2018-07-09T14:23:27z\",\"latest\":true,\"classification\":\"OS\"}}]}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - when(elasticSearchRepository.processResponseAndSendTheScrollBack(anyString(), anyObject())).thenCallRealMethod(); - - List> vulnerabilities = vulnerabilityRepository.getAllVulnerabilities(new ArrayList<>()); - assertTrue(vulnerabilities.size() == 1); - } - - @Test - public void getAllVulnerabilitiesTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getAllVulnerabilities(new ArrayList<>())) - .isInstanceOf(DataException.class); - } - - @Test - public void getAssetsAffectedCountTest() throws Exception { - - String response = "{\"aggregations\":{\"qid\":{\"buckets\":[{\"key\":105130,\"doc_count\":871}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - Map filter = new HashMap<>(); - filter.put("tags.Application.keyword", "app"); - filter.put(Constants.SEVEITY_LEVEL, "3"); - - Map assetsAffected = vulnerabilityRepository.getAssetsAffectedCount("ag", filter, "parent"); - assertTrue(assetsAffected.size() == 1); - } - - @Test - public void getAssetsAffectedCountTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - Map assetsAffected = vulnerabilityRepository.getAssetsAffectedCount("ag", null, "parent"); - assertTrue(assetsAffected.size() == 0); - } - - @Test - public void getVulnerabilyAcrossAppAndEnvTest() throws Exception { - - String response = "{\"hits\":{\"total\":905},\"aggregations\":{\"apps\":{\"buckets\":[{\"key\":\"APP1\",\"doc_count\":905," - + "\"vulns\":{\"doc_count\":5522,\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":556},\"S4\":{\"doc_count\":469},\"S5\":{\"doc_count\":86}}}}}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv("ag","tags.Application.keyword", "","parent", "3").size() == 1); - assertTrue(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv("ag","tags.Environment.keyword", "app","parent", "").size() == 1); - } - - @Test - public void getVulnerabilyAcrossAppAndEnvTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv("ag","tags.Application.keyword", "","parent", "3")) - .isInstanceOf(Exception.class); - } - - @Test - public void getVulnerabilityTrendTest() throws Exception { - - String response = "{\"aggregations\":{\"date\":{\"buckets\":[{\"key_as_string\":\"2018-07-25\",\"key\":1532476800000," - + "\"doc_count\":51,\"vulns\":{\"value\":11126}}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - Map filter = new HashMap<>(); - filter.put("tags.Application.keyword", "app"); - filter.put("tags.Environment.keyword", "env"); - assertTrue(vulnerabilityRepository.getVulnerabilityTrend("ag",filter,new Date(),new Date()).size() == 1); - } - - @Test - public void getVulnerabilityTrendTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilityTrend("ag",null,null,null)) - .isInstanceOf(Exception.class); - - Map filter = new HashMap<>(); - filter.put("test", "test"); - assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilityTrend("ag",filter,new Date(),null)) - .isInstanceOf(Exception.class); - } - - @Test - public void getVulnerabilitiesDistributionTest() throws Exception { - - String response = "{\"aggregations\":{\"apps\":{\"doc_count_error_upper_bound\":0,\"sum_other_doc_count\":0," - + "\"buckets\":[{\"key\":\"APP1\",\"doc_count\":90,\"envs\":{\"doc_count_error_upper_bound\":0,\"sum_other_doc_count\":0," - + "\"buckets\":[{\"key\":\"Production::prd\",\"doc_count\":32,\"vulns\":{\"doc_count\":2002," - + "\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":197},\"S4\":{\"doc_count\":164},\"S5\":{\"doc_count\":30}}}}}]}}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getVulnerabilitiesDistribution("ag","parent").size() == 1); - } - - @Test - public void getVulnerabilitiesDistributionTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilitiesDistribution("ag","parent")) - .isInstanceOf(Exception.class); - } - - @Test - public void getVulnerabilitysummaryByResourceIdTest() throws Exception { - - String response = "{\"hits\":{\"total\":518},\"aggregations\":{\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":556},\"S4\":{\"doc_count\":469},\"S5\":{\"doc_count\":86}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - assertTrue(vulnerabilityRepository.getVulnerabilitysummaryByResourceId("resource").size() == 2); - } - - @Test - public void getVulnerabilitysummaryByResourceIdTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - assertTrue(vulnerabilityRepository.getVulnerabilitysummaryByResourceId("resource").size() == 0); - } - - @Test - public void fetchExecDirectorAppsTest() throws Exception { - - when(elasticSearchRepository.getDataFromES(anyString(), anyString(), anyObject(), anyObject(), anyObject(), anyObject(), anyObject())). - thenReturn(new ArrayList<>()); - assertThat(vulnerabilityRepository.fetchExecDirectorApps(),is(notNullValue())); - } - - @Test - public void getUniqueHostTest() throws Exception { - - String response = "{\"hits\":{\"total\":30056},\"aggregations\":{\"vulninfo\":{\"sev-filter\":{\"severity\":{\"buckets\":[" - + "{\"key\":4,\"unique-host\":{\"value\":25071}},{\"key\":3,\"unique-host\":{\"value\":23776}}," - + "{\"key\":5,\"unique-host\":{\"value\":19250}}]}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getUniqueHost("ag","3,4,5").size() == 4); - } - - @Test - public void getUniqueHostTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getUniqueHost("ag","3,4,5").size() == 0); - } - - @Test - public void getUniqueVulnTest() throws Exception { - - String response = "{\"aggregations\":{\"vulninfo\":{\"sev-filter\":{\"doc_count\":668732,\"severity\":{\"buckets\":[" - + "{\"key\":4,\"doc_count\":354352,\"unique-qid\":{\"value\":1377}},{\"key\":3,\"doc_count\":203380,\"unique-qid\":{\"value\":1868}}," - + "{\"key\":5,\"doc_count\":111000,\"unique-qid\":{\"value\":555}}]}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getVulnInfo("ag","3,4,5").size() == 4); - } - - @Test - public void getUniqueVulnTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getVulnInfo("ag","3,4,5").size() == 0); - } - - @Test - public void getUniqueAppTest() throws Exception { - - String response = "{\"aggregations\":{\"severity\":{\"buckets\":{\"S3\":{\"doc_count\":871,\"NAME\":{\"value\":1}}," - + "\"S4\":{\"doc_count\":871,\"NAME\":{\"value\":1}},\"S5\":{\"doc_count\":844,\"NAME\":{\"value\":1}}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getUniqueApp("ag").size() == 3); - } - - @Test - public void getUniqueAppTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - assertTrue(vulnerabilityRepository.getUniqueApp("ag").size() == 0); - } - - @Test - public void getAgingSummaryTest() throws Exception { - - String response = "{\"aggregations\":{\"severity\":{\"buckets\":[{\"key\":3,\"doc_count\":5581,\"aging\":{\"value\":53.36391327719047}}," - + "{\"key\":4,\"doc_count\":4704,\"aging\":{\"value\":41.863945578231295}},{\"key\":5,\"doc_count\":865,\"aging\":{\"value\":38.522543352601154}}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getAgingSummary("ag").size() == 3); - } - - @Test - public void getAgingSummaryTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - assertTrue(vulnerabilityRepository.getAgingSummary("ag").size() == 0); - } - - @Test - public void getAgingByApplicationTest() throws Exception { - - String response = "{\"aggregations\":{\"apps\":{\"buckets\":[{\"key\":\"APP1\",\"doc_count\":905,\"vulns\":{\"doc_count\":55225," - + "\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":5569,\"aging\":{\"value\":297099}},\"S4\":{\"doc_count\":4694,\"aging\":" - + "{\"value\":196471}},\"S5\":{\"doc_count\":863,\"aging\":{\"value\":33216}}}}}}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getAgingByApplication("ag","parent","").size() == 1); - assertTrue(vulnerabilityRepository.getAgingByApplication("ag","parent","3").size() == 1); - - response = "{\"aggregations\":{\"apps\":{\"buckets\":[{\"key\":\"APP1\",\"doc_count\":905,\"vulns\":{\"doc_count\":55225," - + "\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":0,\"aging\":{\"value\":297099}},\"S4\":{\"doc_count\":0,\"aging\":" - + "{\"value\":196471}},\"S5\":{\"doc_count\":0,\"aging\":{\"value\":33216}}}}}}]}}}"; - assertTrue(vulnerabilityRepository.getAgingByApplication("ag","parent","").size() == 1); - assertTrue(vulnerabilityRepository.getAgingByApplication("ag","parent","3").size() == 1); - } - - @Test - public void getAgingByApplicationTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - assertThatThrownBy(() -> vulnerabilityRepository.getAgingByApplication("ag","parent","3")) - .isInstanceOf(Exception.class); - } - - @Test - public void getTotalQualysHostCountTest() throws Exception { - - String response = "{\"count\":3}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getTotalQualysHostCount("ag","parent") == 3); - } - - @Test - public void getTotalQualysHostCountTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getTotalQualysHostCount("ag","parent")) - .isInstanceOf(DataException.class); - } - - @Test - public void getVulnerabilityByQidTest() throws Exception { - - String response = "{\"hits\":{\"total\":68,\"hits\":[{\"_index\":\"qualys-kb\",\"_type\":\"kb\",\"_id\":\"236591\",\"_score\":8.899231," - + "\"_source\":{\"qid\":\"236591\",\"vulntype\":\"Vulnerability\",\"severitylevel\":4,\"title\":\"Red Hat Update for kernel\"," - + "\"category\":\"RedHat\",\"lastservicemodificationdatetime\":\"2018-05-29T20:32:16z\",\"publisheddatetime\":\"2018-01-04T04:02:43z\"," - + "\"_loadDate\":\"2018-07-09T14:23:27z\",\"latest\":true,\"classification\":\"OS\"}}]}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThat(vulnerabilityRepository.getVulnerabilityByQid("qid"),is(notNullValue())); - } - - @Test - public void getVulnerabilityByQidTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getVulnerabilityByQid("ag").size() ==0); - } - - @Test - public void getDistributionSummaryByInfraTypeTest() throws Exception { - - String response = "{\"hits\":{\"total\":515,\"max_score\":0,\"hits\":[]},\"aggregations\":{\"NAME\":{\"doc_count\":32252," - + "\"NAME\":{\"doc_count\":6361,\"NAME\":{\"value\":37}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getDistributionSummaryByInfraType("ag","","parent").size() == 3); - } - - @Test - public void getDistributionSummaryByInfraTypeTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getDistributionSummaryByInfraType("ag","3","parent")) - .isInstanceOf(DataException.class); - } - - @Test - public void getProdInfoByEnvTest() throws Exception { - - String response = "{\"hits\":{\"total\":515,\"max_score\":0,\"hits\":[]},\"aggregations\":{\"NAME\":{\"doc_count\":32252," - + "\"NAME\":{\"doc_count\":6361,\"NAME\":{\"value\":37}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getProdInfoByEnv("ag","").size() == 3); - } - - @Test - public void getProdInfoByEnvTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getProdInfoByEnv("ag","3").size() == 0); - } - - @Test - public void getNonProdInfoByEnvTest() throws Exception { - - String response = "{\"hits\":{\"total\":515,\"max_score\":0,\"hits\":[]},\"aggregations\":{\"NAME\":{\"doc_count\":32252," - + "\"NAME\":{\"doc_count\":6361,\"NAME\":{\"value\":37}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getNonProdInfoByEnv("ag","").size() == 3); - } - - @Test - public void getNonProdInfoByEnvTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getNonProdInfoByEnv("ag","3").size() == 0); - } - - @Test - public void getDistributionSummaryByVulnTypeTest() throws Exception { - - String response1 = "{\"aggregations\":{\"vulninfo\":{\"doc_count\":126339,\"sev-filter\":" - + "{\"doc_count\":104821,\"classification\":{\"buckets\":[{\"key\":\"OS\",\"doc_count\":94207,\"resources\":{\"value\":4219}}," - + "{\"key\":\"Application\",\"doc_count\":10614,\"resources\":{\"value\":1869}}]}}}}}"; - - String response2 = "{\"aggregations\":{\"vulninfo\":{\"doc_count\":126339,\"sev-filter\":" - + "{\"doc_count\":104821,\"classification\":{\"buckets\":[{\"key\":\"OS\",\"doc_count\":94207,\"unique-qid\":{\"value\":1156}}," - + "{\"key\":\"Application\",\"doc_count\":10614,\"unique-qid\":{\"value\":428}}]}}}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response1,response2); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getDistributionSummaryByVulnType("ag","").size() == 2); - } - - @Test - public void getDistributionSummaryByVulnTypeTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getDistributionSummaryByVulnType("ag","3")) - .isInstanceOf(DataException.class); - } - - @Test - public void getAllQidByAGTest() throws Exception { - - String response = "{\"aggregations\":{\"qid\":{\"buckets\":[{\"key\":\"105130~unix group list~OS\",\"doc_count\":873}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getAllQidByAG("ag","").size() == 1); - } - - @Test - public void getAllQidByAGTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getAllQidByAG("ag","3")) - .isInstanceOf(DataException.class); - } - - @Test - public void getAppsBySeverityTest() throws Exception { - - String response = "{\"aggregations\":{\"apps\":{\"buckets\":[{\"key\":\"APP1\",\"doc_count\":905," - + "\"vulns\":{\"doc_count\":55283,\"NAME\":{\"buckets\":{\"severity\":{\"doc_count\":12242}}}}}]}}}"; - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertTrue(vulnerabilityRepository.getAppsBySeverity("ag","parent","").size() == 1); - } - - @Test - public void getAppsBySeverityTest_Exception() throws Exception { - - mockStatic(PacHttpUtils.class); - when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); - ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); - - assertThatThrownBy(() -> vulnerabilityRepository.getAppsBySeverity("ag","parent","3")) - .isInstanceOf(Exception.class); - } -} diff --git a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImplTest.java b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImplTest.java index b396303dc..e3a721a5c 100644 --- a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImplTest.java +++ b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/service/IssueTrendServiceImplTest.java @@ -56,9 +56,6 @@ public class IssueTrendServiceImplTest { @Mock private ComplianceService complianceService; - @Mock - private VulnerabilityService vulnService; - Request request = new Request(); UntaggedTargetTypeRequest untaggedTargetTypeRequest = new UntaggedTargetTypeRequest(); @@ -99,11 +96,6 @@ public void getTrendProgressTest() throws Exception { when(complianceService.getCertificates(anyString())) .thenReturn(taggingInfoMap); - when(vulnService.getVulnerabilitySummary(anyString(),anyString())) - .thenReturn(vulnInfoMap); - complianceService - .getRulecompliance(request); - when(complianceService.getRulecompliance(anyObject())) .thenReturn(CommonTestUtil.getResponseWithOrder()); diff --git a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/service/VulnerabilityServiceTest.java b/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/service/VulnerabilityServiceTest.java deleted file mode 100644 index 5dbe6ce1a..000000000 --- a/api/pacman-api-compliance/src/test/java/com/tmobile/pacman/api/compliance/service/VulnerabilityServiceTest.java +++ /dev/null @@ -1,713 +0,0 @@ -/******************************************************************************* - * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package com.tmobile.pacman.api.compliance.service; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.powermock.api.mockito.PowerMockito.when; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.powermock.modules.junit4.PowerMockRunner; -import org.springframework.test.util.ReflectionTestUtils; - -import com.tmobile.pacman.api.commons.Constants; -import com.tmobile.pacman.api.commons.exception.DataException; -import com.tmobile.pacman.api.commons.exception.ServiceException; -import com.tmobile.pacman.api.commons.utils.CommonUtils; -import com.tmobile.pacman.api.compliance.client.AssetServiceClient; -import com.tmobile.pacman.api.compliance.domain.AssetApi; -import com.tmobile.pacman.api.compliance.domain.AssetApiData; -import com.tmobile.pacman.api.compliance.domain.AssetCount; -import com.tmobile.pacman.api.compliance.domain.AssetCountByAppEnvDTO; -import com.tmobile.pacman.api.compliance.domain.AssetCountDTO; -import com.tmobile.pacman.api.compliance.domain.AssetCountData; -import com.tmobile.pacman.api.compliance.domain.Request; -import com.tmobile.pacman.api.compliance.domain.ResponseWithOrder; -import com.tmobile.pacman.api.compliance.repository.VulnerabilityRepository; -import com.tmobile.pacman.api.compliance.repository.VulnerabilityTrendGenerator; - -@RunWith(PowerMockRunner.class) -public class VulnerabilityServiceTest { - - @InjectMocks - VulnerabilityService vulnerabilityService; - - @Mock - VulnerabilityRepository vulnerabilityRepository; - - @Mock - AssetServiceClient assetServiceClient; - - @Mock - VulnerabilityTrendGenerator vulnTrendGenerator; - - @Mock - ComplianceService complianceService; - - @Mock - CommonUtils commonUtils; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - AssetApi assetApi = new AssetApi(); - AssetApiData data = new AssetApiData(); - - List ttypes = new ArrayList<>(); - AssetCountDTO tt = new AssetCountDTO(); - tt.setType("ec2"); - ttypes.add(tt); - tt = new AssetCountDTO(); - tt.setType("onpremserver"); - ttypes.add(tt); - - data.setTargettypes(ttypes.toArray(new AssetCountDTO[ttypes.size()])); - assetApi.setData(data); - - when(assetServiceClient.getTargetTypeList(anyString(),anyObject())).thenReturn(assetApi); - } - - @Test - public void getVulnerabilitiesDetailsTest() throws Exception { - - List> vulnerabilitiesData = new ArrayList<>(); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getAssetsAffectedCount(anyString(), - anyObject(), anyString())).thenReturn(new HashMap<>()); - when (vulnerabilityRepository.getAllVulnerabilities(anyObject())).thenReturn(vulnerabilitiesData); - assertThat(vulnerabilityService.getVulnerabilitiesDetails("ag", null), - is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); - assertThat(vulnerabilityService.getVulnerabilitiesDetails("ag", null), - is(notNullValue())); - - Map vuln = new HashMap<>(); - vuln.put("qid", "123"); - vuln.put("assetsAffected", 1); - vuln.put(Constants.TITLE, "test"); - vuln.put(Constants.SEVEITY_LEVEL, "3"); - vuln.put(Constants.CATEGORY, "test"); - vuln.put(Constants.VULN_TYPE, "type"); - vuln.put(Constants.PATCHABLE, "1"); - vulnerabilitiesData.add(vuln); - - vuln = new HashMap<>(); - vuln.put("qid", "456"); - vuln.put("assetsAffected", 2); - vuln.put(Constants.TITLE, "test"); - vuln.put(Constants.SEVEITY_LEVEL, "5"); - vuln.put(Constants.CATEGORY, "test"); - vuln.put(Constants.VULN_TYPE, "type"); - vuln.put(Constants.PATCHABLE, "0"); - vulnerabilitiesData.add(vuln); - - vuln = new HashMap<>(); - vuln.put("qid", "789"); - vuln.put("assetsAffected", 2); - vuln.put(Constants.TITLE, "test"); - vuln.put(Constants.SEVEITY_LEVEL, "5"); - vuln.put(Constants.CATEGORY, "test"); - vuln.put(Constants.VULN_TYPE, "type"); - vulnerabilitiesData.add(vuln); - - Map assetsAffected = new HashMap(); - assetsAffected.put("123", 10L); - assetsAffected.put("456", 10L); - assetsAffected.put("789", 10L); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); - when(vulnerabilityRepository.getAssetsAffectedCount(anyString(), - anyObject(), anyString())).thenReturn(assetsAffected); - when (vulnerabilityRepository.getAllVulnerabilities(anyObject())).thenReturn(vulnerabilitiesData); - assertThat(vulnerabilityService.getVulnerabilitiesDetails("ag", null), - is(notNullValue())); - } - - @Test - public void getVulnerabilitiesDetailsTest_Exception() throws Exception { - - when(vulnerabilityRepository.getAssetsAffectedCount(anyString(), - anyObject(), anyString())).thenReturn(new HashMap<>()); - when (vulnerabilityRepository.getAllVulnerabilities(anyObject())).thenThrow(new DataException()); - assertThatThrownBy( - () -> vulnerabilityService.getVulnerabilitiesDetails("ag", null)).isInstanceOf(Exception.class); - } - - @Test - public void getVulnerabilitySummaryTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); - assertThat(vulnerabilityService.getVulnerabilitySummary("ag","3,4,5"), - is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getUniqueHost(anyString(),anyString())).thenReturn(new HashMap()); - when(vulnerabilityRepository.getVulnInfo(anyString(),anyString())).thenReturn(new HashMap()); - when(vulnerabilityRepository.getUniqueApp(anyString())).thenReturn(new HashMap()); - - AssetCount totalAssets = new AssetCount(); - AssetCountData data = new AssetCountData(); - - AssetCountByAppEnvDTO assetCount_Count = new AssetCountByAppEnvDTO(); - assetCount_Count.setType("onpremserver"); - assetCount_Count.setCount("1"); - - List assetAppEnvDTOs = new ArrayList(); - assetAppEnvDTOs.add(assetCount_Count); - data.setAssetcount(assetAppEnvDTOs.toArray(new AssetCountByAppEnvDTO[assetAppEnvDTOs.size()])); - totalAssets.setData(data); - - ResponseWithOrder responseWithOrder = new ResponseWithOrder(); - List> response = new ArrayList<>(); - LinkedHashMap obj = new LinkedHashMap<>(); - obj.put("assetsScanned", 1); - obj.put("passed", 1); - response.add(obj); - responseWithOrder.setResponse(response ); - when(complianceService.getRulecompliance(any(Request.class))).thenReturn(responseWithOrder); - when(vulnerabilityRepository.getTotalQualysHostCount(anyString(), anyString())).thenReturn(1L); - ReflectionTestUtils.setField(vulnerabilityService, "vulnSummarySeverity", "3"); - - Map vulnSummary = new HashMap<>(); - List> severityInfo = new ArrayList<>(); - Map severity = new HashMap<>(); - severity.put(Constants.SEVEITY_LEVEL, 3); - severity.put(Constants.COUNT, 2); - severity.put(Constants.VULN_COUNT, 2); - severityInfo.add(severity); - severity = new HashMap<>(); - severity.put(Constants.SEVEITY_LEVEL, 4); - severity.put(Constants.COUNT, 2); - severity.put(Constants.VULN_COUNT, 2); - severityInfo.add(severity); - severity = new HashMap<>(); - severity.put(Constants.SEVEITY_LEVEL, 5); - severity.put(Constants.COUNT, 2); - severity.put(Constants.VULN_COUNT, 2); - severityInfo.add(severity); - - vulnSummary.put("severityInfo", severityInfo); - assertThat(vulnerabilityService.getVulnerabilitySummary("ag","3,4,5"),is(notNullValue())); - - - Map uniqueHost = new HashMap<>(); - uniqueHost.put("total", 10); - uniqueHost.put("3", 1); - Map vulnInfo = new HashMap<>(); - Map vulnInfoMap = new HashMap<>(); - vulnInfoMap.put(Constants.VULN_COUNT,2); - vulnInfoMap.put(Constants.UNIQUE_VULN_COUNT,2); - vulnInfo.put("total", 10); - vulnInfo.put("3", vulnInfoMap); - Map uniqueApp = new HashMap<>(); - uniqueApp.put("3", 1); - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); - when(vulnerabilityRepository.getUniqueHost(anyString(),anyString())).thenReturn(uniqueHost); - when(vulnerabilityRepository.getVulnInfo(anyString(),anyString())).thenReturn(vulnInfo); - when(vulnerabilityRepository.getUniqueApp(anyString())).thenReturn(uniqueApp); - - when(complianceService.getRulecompliance(any(Request.class))).thenReturn(responseWithOrder); - when(assetServiceClient.getTotalAssetsCount(anyString(), anyString(), anyString())).thenReturn(totalAssets); - when(vulnerabilityRepository.getTotalQualysHostCount(anyString(), anyString())).thenReturn(1L); - ReflectionTestUtils.setField(vulnerabilityService, "vulnSummarySeverity", "3"); - - vulnSummary.put("severityInfo", severityInfo); - - assertThat(vulnerabilityService.getVulnerabilitySummary("ag","3"),is(notNullValue())); - - } - - @Test - public void getVulnerabilitySummaryTest_Exception() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getUniqueHost(anyString(),anyString())).thenReturn(new HashMap()); - when(vulnerabilityRepository.getVulnInfo(anyString(),anyString())).thenReturn(new HashMap()); - when(vulnerabilityRepository.getUniqueApp(anyString())).thenReturn(new HashMap()); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnSummarySeverity", "3"); - when(complianceService.getRulecompliance(any(Request.class))).thenThrow(new ServiceException()); - assertThatThrownBy( - () -> vulnerabilityService.getVulnerabilitySummary("ag","3,4,5")).isInstanceOf(ServiceException.class); - } - - @Test - public void getVulnerabilityByAppAndEnvTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv(anyString(), anyObject(), - anyString(), anyString(), anyString())).thenReturn(new ArrayList<>()); - assertThat(vulnerabilityService.getVulnerabilityByAppAndEnv("ag","filter","app"), - is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); - assertThat(vulnerabilityService.getVulnerabilityByAppAndEnv("ag","filter","app").size(), - is(0)); - } - - @Test - public void getVulnerabilityTrendTest() throws Exception { - - when(vulnerabilityRepository.getVulnerabilityTrend(anyString(), - anyObject(), anyObject(), anyObject())).thenReturn(new ArrayList<>()); - assertThat(vulnerabilityService.getVulnerabilityTrend("ag",null,new Date(),new Date()), - is(notNullValue())); - } - - @Test - public void getVulnerabilityNewOpenTrendTest() throws Exception { - - when(vulnTrendGenerator.generateTrend(anyString(), - anyString(), anyObject())).thenReturn(new ArrayList<>()); - assertThat(vulnerabilityService.getVulnerabilityNewOpenTrend("ag","sev",new Date()), - is(notNullValue())); - } - - @Test - public void getVulnerabilitiesDistributionTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getVulnerabilitiesDistribution(anyString(),anyString())).thenReturn(new ArrayList<>()); - assertThat(vulnerabilityService.getVulnerabilitiesDistribution("ag"), - is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); - assertThat(vulnerabilityService.getVulnerabilitiesDistribution("ag").size(), - is(0)); - } - - /*@SuppressWarnings("static-access") - @Test - public void filterMatchingCollectionElementsTest() throws Exception { - - when(commonUtils.filterMatchingCollectionElements(anyObject(), - anyObject(), anyObject())).thenReturn(new Object()); - assertThat(vulnerabilityService.filterMatchingCollectionElements(new ArrayList<>(),"sev",true), - is(notNullValue())); - }*/ - - @Test - public void getVulnerabilitysummaryByResourceIdTest() throws Exception { - - when(vulnerabilityRepository.getVulnerabilitysummaryByResourceId(anyString())).thenReturn(new HashMap<>()); - assertThat(vulnerabilityService.getVulnerabilitysummaryByResourceId("id"), - is(notNullValue())); - } - - @Test - public void getVulnerabilityDetailsByResourceIdTest() throws Exception { - - List> vulnerabilitiesData = new ArrayList<>(); - - Map vuln = new HashMap<>(); - vuln.put("qid", "123"); - vuln.put("assetsAffected", 1); - vuln.put(Constants.TITLE, "test"); - vuln.put(Constants.SEVEITY_LEVEL, "3"); - vuln.put(Constants.CATEGORY, "test"); - vuln.put(Constants.VULN_TYPE, "type"); - vuln.put(Constants.PATCHABLE, "1"); - vulnerabilitiesData.add(vuln); - - when(vulnerabilityRepository.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(vulnerabilitiesData); - assertThat(vulnerabilityService.getVulnerabilityDetailsByResourceId("id"), - is(notNullValue())); - - vuln = new HashMap<>(); - vuln.put("qid", "123"); - vuln.put("assetsAffected", 1); - vulnerabilitiesData.add(vuln); - - when(vulnerabilityRepository.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(vulnerabilitiesData); - assertThatThrownBy( - () -> vulnerabilityService.getVulnerabilityDetailsByResourceId("id")).isInstanceOf(Exception.class); - } - - @Test - public void getVulnerabilityDistributionSummaryTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv(anyString(), - anyString(), anyString(), anyString(),anyString())).thenReturn(getApps()); - when(vulnerabilityRepository.fetchExecDirectorApps()).thenReturn(fetchExecDirectorApps()); - - assertThat(vulnerabilityService.getVulnerabilityDistributionSummary("ag","3"), - is(notNullValue())); - assertThat(vulnerabilityService.getVulnerabilityDistributionSummary("ag",null), - is(notNullValue())); - } - - @Test - public void getAgingSummaryTest() throws Exception { - - when(vulnerabilityRepository.getAgingSummary(anyString())).thenReturn(new ArrayList<>()); - assertThat(vulnerabilityService.getAgingSummary("ag"), - is(notNullValue())); - } - - @Test - public void getAgingDistributionSummaryTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getAgingByApplication(anyString(),anyString(),anyString())).thenReturn(getApps()); - when(vulnerabilityRepository.fetchExecDirectorApps()).thenReturn(fetchExecDirectorApps()); - - assertThat(vulnerabilityService.getAgingDistributionSummary("ag","3"), - is(notNullValue())); - assertThat(vulnerabilityService.getAgingDistributionSummary("ag",null), - is(notNullValue())); - } - - @Test - public void getAgingDistributionSummaryTest_Exception() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); - when(vulnerabilityRepository.getAgingByApplication(anyString(),anyString(),anyString())).thenReturn(getApps()); - when(vulnerabilityRepository.fetchExecDirectorApps()).thenReturn(fetchExecDirectorApps()); - assertThat(vulnerabilityService.getAgingDistributionSummary("ag","3"), - is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getAgingByApplication(anyString(),anyString(),anyString())).thenThrow(new Exception()); - assertThat(vulnerabilityService.getAgingDistributionSummary("ag","3"), - is(notNullValue())); - } - - @Test - public void getVulnerabilityByQidTest() throws Exception { - - Map vuln = new HashMap<>(); - vuln.put("qid", "123"); - vuln.put("vulntype", "type"); - vuln.put("severitylevel", "3"); - vuln.put("title", "test"); - vuln.put("category", ""); - vuln.put("lastservicemodificationdatetime", "1234"); - vuln.put("publisheddatetime", "123"); - vuln.put("patchable", "1"); - Map softwarelist = new HashMap<>(); - List> softwares = new ArrayList<>(); - Map innerMap = new HashMap<>(); - innerMap.put("test","test"); - innerMap.put("test", "test"); - softwares.add(innerMap); - softwarelist.put("software", softwares); - vuln.put("softwarelist", softwarelist); - Map vendorreferencelist = new HashMap<>(); - List> vendorreference = new ArrayList<>(); - vendorreference.add(innerMap); - vendorreferencelist.put("vendorreference", vendorreference); - vuln.put("vendorreferencelist", vendorreferencelist); - vuln.put("diagnosis", "test"); - vuln.put("consequence", "test"); - vuln.put("solution", "test"); - Map bugtraqlist = new HashMap<>(); - List> bugtraq = new ArrayList<>(); - bugtraq.add(innerMap); - bugtraqlist.put("vendorreference", bugtraq); - vuln.put("bugtraqlist", bugtraqlist); - vuln.put("pciflag", 0); - Map pcireasons = new HashMap<>(); - List> pcireason = new ArrayList<>(); - pcireason.add(innerMap); - pcireasons.put("pcireason", pcireason); - vuln.put("pcireasons", pcireasons); - Map authtypelist = new HashMap<>(); - List> authtype = new ArrayList<>(); - authtype.add(innerMap); - authtypelist.put("authtype", authtype); - Map discovery = new HashMap<>(); - discovery.put("authtypelist", authtypelist); - discovery.put("additionalinfo", "Patch Available"); - vuln.put("discovery", discovery); - vuln.put("supportedmodules", "test"); - Map cvelist = new HashMap<>(); - List> cve = new ArrayList<>(); - cve.add(innerMap); - cvelist.put("cve", cve); - vuln.put("cvelist", cvelist); - Map cvss = new HashMap<>(); - cvss.put("base", 1); - cvss.put("temporal", 1); - vuln.put("cvssv3", cvss); - Map access = new HashMap<>(); - access.put("vector", 1); - cvss.put("access", access); - vuln.put("cvss", cvss); - - when(vulnerabilityRepository.getVulnerabilityByQid(anyString())).thenReturn(vuln); - assertThat(vulnerabilityService.getVulnerabilityByQid("id"), - is(notNullValue())); - - vuln = new HashMap<>(); - discovery = new HashMap<>(); - discovery.put("additionalinfo", "test"); - vuln.put("discovery", discovery); - vuln.put("pciflag", 1); - - when(vulnerabilityRepository.getVulnerabilityByQid(anyString())).thenReturn(vuln); - assertThat(vulnerabilityService.getVulnerabilityByQid("id"), - is(notNullValue())); - - when(vulnerabilityRepository.getVulnerabilityByQid(anyString())).thenReturn(new HashMap<>()); - assertThat(vulnerabilityService.getVulnerabilityByQid("id"), - is(notNullValue())); - } - - @Test - public void getHighestLowestPerformersTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); - when(vulnerabilityRepository.fetchExecDirectorApps()).thenReturn(fetchExecDirectorApps()); - assertThat(vulnerabilityService.getHighestLowestPerformers("ag", null,"org"),is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getAppsBySeverity(anyString(),anyString(),anyString())).thenReturn(new HashMap<>()); - when(vulnerabilityRepository.fetchExecDirectorApps()).thenReturn(fetchExecDirectorApps()); - assertThat(vulnerabilityService.getHighestLowestPerformers("ag", null,"org"),is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); - Map apps = new HashMap<>(); - apps.put("app1", 1L); - apps.put("app2", 2L); - apps.put("app3", 3L); - when(vulnerabilityRepository.getAppsBySeverity(anyString(),anyString(),anyString())).thenReturn(apps); - when(vulnerabilityRepository.fetchExecDirectorApps()).thenReturn(fetchExecDirectorApps()); - assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3","org"),is(notNullValue())); - - } - - @Test - public void getHighestLowestPerformersTest_Exception() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getAppsBySeverity(anyString(),anyString(),anyString())).thenThrow(new Exception()); - assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3","org"),is(notNullValue())); - } - - @Test - public void getDistributionSummaryByInfraTypeTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); - Map infraInfo = new HashMap<>(); - infraInfo.put(Constants.TOTAL_VULN_ASSETS,1); - infraInfo.put(Constants.VULNEREBILITIES,1); - infraInfo.put(Constants.UNIQUE_VULN_COUNT,1); - when(vulnerabilityRepository.getDistributionSummaryByInfraType(anyString(),anyString(),anyString())).thenReturn(infraInfo); - assertThat(vulnerabilityService.getDistributionSummaryByInfraType("ag",null),is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getDistributionSummaryByInfraType(anyString(),anyString(),anyString())).thenReturn(infraInfo); - assertThat(vulnerabilityService.getDistributionSummaryByInfraType("ag","3"),is(notNullValue())); - } - - @Test - public void getDistributionSummaryByInfraTypeTest_Exception() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - when(vulnerabilityRepository.getDistributionSummaryByInfraType(anyString(),anyString(),anyString())).thenThrow(new DataException()); - assertThatThrownBy( - () -> vulnerabilityService.getDistributionSummaryByInfraType("ag","3")).isInstanceOf(ServiceException.class); - } - - @Test - public void getDistributionSummaryByEnvTest() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); - - Map prodInfo = new HashMap<>(); - prodInfo.put("totalVulnerableAssets", 1L); - prodInfo.put(Constants.VULNEREBILITIES, 1L); - prodInfo.put("uniqueVulnCount", 1L); - - Map nonProdInfo = new HashMap<>(); - nonProdInfo.put("totalVulnerableAssets", 1L); - nonProdInfo.put(Constants.VULNEREBILITIES, 1L); - nonProdInfo.put("uniqueVulnCount", 1L); - - when(vulnerabilityRepository.getProdInfoByEnv(anyString(), anyString())).thenReturn(prodInfo); - when(vulnerabilityRepository.getNonProdInfoByEnv(anyString(), anyString())).thenReturn(nonProdInfo); - assertThat(vulnerabilityService.getDistributionSummaryByEnv("ag","3"),is(notNullValue())); - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - - prodInfo = new HashMap<>(); - prodInfo.put("totalVulnerableAssets", 0L); - prodInfo.put(Constants.VULNEREBILITIES, 0L); - prodInfo.put("uniqueVulnCount", 0L); - - nonProdInfo = new HashMap<>(); - nonProdInfo.put("totalVulnerableAssets", 0L); - nonProdInfo.put(Constants.VULNEREBILITIES, 0L); - nonProdInfo.put("uniqueVulnCount", 0L); - - when(vulnerabilityRepository.getProdInfoByEnv(anyString(), anyString())).thenReturn(prodInfo); - when(vulnerabilityRepository.getNonProdInfoByEnv(anyString(), anyString())).thenReturn(nonProdInfo); - assertThat(vulnerabilityService.getDistributionSummaryByEnv("ag",""),is(notNullValue())); - } - - @Test - public void getDistributionSummaryByEnvTest_Exception() throws Exception { - - ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); - Map prodInfo = new HashMap<>(); - prodInfo.put("totalVulnerableAssets", 1L); - prodInfo.put("uniqueVulnCount", 1L); - - Map nonProdInfo = new HashMap<>(); - nonProdInfo.put("totalVulnerableAssets", 1L); - nonProdInfo.put(Constants.VULNEREBILITIES, 1L); - nonProdInfo.put("uniqueVulnCount", 1L); - - when(vulnerabilityRepository.getProdInfoByEnv(anyString(), anyString())).thenReturn(prodInfo); - when(vulnerabilityRepository.getNonProdInfoByEnv(anyString(), anyString())).thenReturn(nonProdInfo); - assertThatThrownBy( - () -> vulnerabilityService.getDistributionSummaryByEnv("ag","3")).isInstanceOf(ServiceException.class); - } - - @Test - public void getDistributionSummaryByVulnTypeTest() throws Exception { - - when(vulnerabilityRepository.getDistributionSummaryByVulnType(anyString(), anyString())).thenReturn(new ArrayList<>()); - assertThat(vulnerabilityService.getDistributionSummaryByVulnType("ag","3"),is(notNullValue())); - - when(vulnerabilityRepository.getDistributionSummaryByVulnType(anyString(), anyString())).thenReturn(new ArrayList<>()); - assertThat(vulnerabilityService.getDistributionSummaryByVulnType("ag",null),is(notNullValue())); - } - - @Test - public void getRemediationActionsSummaryTest() throws Exception { - - Map qids = new HashMap<>(); - qids.put("123~title~OS", 2); - qids.put("123~EOL/Obsolete~Infra", 2); - qids.put("11925~title~Infra", 2); - qids.put("370914~title~Infra", 2); - qids.put("123~Java Debug Wire Protocol~Infra", 0); - qids.put("123~Java JMX Server Insecure Configuration~Infra", 2); - qids.put("123~Java~Infra", 2); - qids.put("123~title~Infra", 2); - when(vulnerabilityRepository.getAllQidByAG(anyString(),anyString())).thenReturn(qids); - assertThat(vulnerabilityService.getRemediationActionsSummary("ag",null),is(notNullValue())); - } - - private List> getApps() { - - List> vulnApplications = new ArrayList<>(); - List> severityInfo = new ArrayList<>(); - - Map severity = new HashMap<>(); - severity.put(Constants.SEVERITY, "S3"); - severity.put(Constants.COUNT, 3); - severity.put("days", 3); - severityInfo.add(severity); - severity = new HashMap<>(); - severity.put(Constants.SEVERITY, "S4"); - severity.put(Constants.COUNT, 4); - severity.put("days", 4); - severityInfo.add(severity); - severity = new HashMap<>(); - severity.put(Constants.SEVERITY, "S5"); - severity.put(Constants.COUNT, 5); - severity.put("days", 5); - severityInfo.add(severity); - - Map vulnApp = new HashMap<>(); - vulnApp.put("application", "app1"); - vulnApp.put(Constants.SEV_INFO, severityInfo); - vulnApplications.add(vulnApp); - - vulnApp = new HashMap<>(); - vulnApp.put("application", "app2"); - vulnApp.put(Constants.SEV_INFO, severityInfo); - vulnApplications.add(vulnApp); - - vulnApp = new HashMap<>(); - vulnApp.put("application", "app3"); - vulnApp.put(Constants.SEV_INFO, severityInfo); - vulnApplications.add(vulnApp); - return vulnApplications; - } - - private List> fetchExecDirectorApps() { - - List> apps = new ArrayList<>(); - Map app = new HashMap<>(); - app.put("appTag", "app1"); - app.put("director", "director1"); - app.put("executiveSponsor", "executiveSponsor1"); - apps.add(app); - - app = new HashMap<>(); - app.put("appTag", "app1"); - app.put("director", "director3"); - app.put("executiveSponsor", "executiveSponsor3"); - apps.add(app); - - app = new HashMap<>(); - app.put("appTag", "app2"); - app.put("director", "director2"); - app.put("executiveSponsor", "executiveSponsor2"); - apps.add(app); - - app = new HashMap<>(); - app.put("appTag", "app2"); - app.put("director", ""); - app.put("executiveSponsor", ""); - apps.add(app); - - app = new HashMap<>(); - app.put("appTag", "app3"); - app.put("director", "director3"); - app.put("executiveSponsor", "executiveSponsor3"); - apps.add(app); - - app = new HashMap<>(); - app.put("appTag", "app3"); - app.put("director", "director1"); - app.put("executiveSponsor", "executiveSponsor1"); - apps.add(app); - - app = new HashMap<>(); - app.put("appTag", "app3"); - app.put("director", null); - app.put("executiveSponsor", null); - apps.add(app); - - return apps; - } - -} diff --git a/api/pacman-api-config/src/main/resources/shared/api.yml b/api/pacman-api-config/src/main/resources/shared/api.yml index c1f8cfa87..e8ba71d86 100644 --- a/api/pacman-api-config/src/main/resources/shared/api.yml +++ b/api/pacman-api-config/src/main/resources/shared/api.yml @@ -8,6 +8,8 @@ service: devstandards: ${PACMAN_HOST_NAME}/api/devstandards auth: ${PACMAN_HOST_NAME}/api/auth admin: ${PACMAN_HOST_NAME}/api/admin + notifications: ${PACMAN_HOST_NAME}/api/notifications + vulnerability: ${PACMAN_HOST_NAME}/api/vulnerability endpoints: refresh: @@ -27,7 +29,7 @@ application: domains: all monitoring: - contextRootNames: asset,compliance,statistics,auth,admin + contextRootNames: asset,compliance,statistics,auth,admin,notifications,vulnerability auth: active: db @@ -66,6 +68,9 @@ api: - name: Notification Service url: ${PACMAN_HOST_NAME:http://localhost:8080}/api/notifications/v2/api-docs version: 2.0 + - name: Vulnerability Service + url: ${PACMAN_HOST_NAME:http://localhost:8080}/api/vulnerability/v2/api-docs + version: 2.0 tagging: mandatoryTags: Application,Environment diff --git a/api/pacman-api-config/src/main/resources/shared/vulnerability-service.yml b/api/pacman-api-config/src/main/resources/shared/vulnerability-service.yml new file mode 100644 index 000000000..9a4ea45fb --- /dev/null +++ b/api/pacman-api-config/src/main/resources/shared/vulnerability-service.yml @@ -0,0 +1,3 @@ +server: + servlet: + context-path: /api/vulnerability \ No newline at end of file diff --git a/api/pacman-api-vulnerability/pom.xml b/api/pacman-api-vulnerability/pom.xml new file mode 100644 index 000000000..22908d37f --- /dev/null +++ b/api/pacman-api-vulnerability/pom.xml @@ -0,0 +1,278 @@ + + + 4.0.0 + + com.tmobile.pacman + vulnerability-service + 1.0-SNAPSHOT + jar + vulnerability-service + + + org.springframework.boot + spring-boot-starter-parent + 2.0.4.RELEASE + + + + + 2.0.2 + UTF-8 + UTF-8 + 1.8 + 1.8 + 1.8 + 1.6.4 + -Xdoclint:none + + + + + + org.springframework.cloud + spring-cloud-dependencies + Finchley.RELEASE + pom + import + + + de.codecentric + spring-boot-admin-dependencies + ${spring-boot-admin.version} + pom + import + + + + + + + com.tmobile.cloud + api-commons + 1.0.1-SNAPSHOT + + + + io.springfox + springfox-swagger2 + 2.7.0 + + + + io.springfox + springfox-swagger-ui + 2.7.0 + + + + io.springfox + springfox-bean-validators + 2.7.0 + + + + de.codecentric + spring-boot-admin-starter-client + + + + org.springframework.cloud + spring-cloud-starter-security + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + org.springframework.cloud + spring-cloud-openfeign-core + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.jayway.jsonpath + json-path + 2.2.0 + test + + + + org.elasticsearch.client + rest + 5.5.3 + + + + com.google.code.gson + gson + 2.8.1 + + + + com.google.guava + guava + 19.0 + + + + org.elasticsearch + elasticsearch + 5.6.2 + + + + org.elasticsearch.client + transport + 5.6.2 + + + + org.apache.logging.log4j + log4j-api + 2.9.0 + + + org.apache.logging.log4j + log4j-core + 2.9.0 + + + + org.springframework.boot + spring-boot-starter-cache + + + + com.github.ben-manes.caffeine + caffeine + + + + org.springframework.boot + spring-boot-devtools + true + + + + org.javassist + javassist + 3.18.1-GA + + + + commons-validator + commons-validator + 1.4.0 + + + + org.powermock + powermock-api-mockito + ${powermock.version} + test + + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + + org.mockito + mockito-core + 1.10.19 + test + + + + ch.qos.logback.contrib + logback-jackson + 0.1.5 + + + + ch.qos.logback.contrib + logback-json-classic + 0.1.5 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + build-info + + + + + pacman-api-vulnerability + true + + + + org.jacoco + jacoco-maven-plugin + 0.7.6.201602180812 + + + + prepare-agent + + + + report + test + + report + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + install + + + + + + + run + + + + + + + + diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/RefreshScopeConfig.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/RefreshScopeConfig.java new file mode 100644 index 000000000..37b8b4725 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/RefreshScopeConfig.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/* + * + */ +package com.tmobile.pacman.api.vulnerability; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.annotation.Configuration; + + +/** + * The Class RefreshScopeConfig. + */ +@Configuration +public class RefreshScopeConfig implements BeanFactoryPostProcessor { + + /* (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) + */ + + /** + * Overriding to update the test scope. + * + */ + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) { + for (String beanName : factory.getBeanDefinitionNames()) { + BeanDefinition beanDef = factory.getBeanDefinition(beanName); + if (beanDef.getBeanClassName() != null && beanDef.getBeanClassName().startsWith("com.tmobile.pacman")) { + beanDef.setScope("refresh"); + } + } + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/VulnerabilityApplication.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/VulnerabilityApplication.java new file mode 100644 index 000000000..6f54d6446 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/VulnerabilityApplication.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/* + * + */ +package com.tmobile.pacman.api.vulnerability; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; + + +/** + * The Class VulnerabilityApplication. + */ +@SpringBootApplication +@EnableFeignClients +@Configuration +@EnableResourceServer +@ComponentScan(basePackages = "com.tmobile.pacman") +public class VulnerabilityApplication { + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + SpringApplication.run(VulnerabilityApplication.class, args); + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/client/AssetServiceClient.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/client/AssetServiceClient.java new file mode 100644 index 000000000..174dec0b4 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/client/AssetServiceClient.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Oct 26, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.tmobile.pacman.api.vulnerability.domain.AssetApi; +import com.tmobile.pacman.api.vulnerability.domain.AssetCount; + +/** + * The Interface AssetServiceClient. + */ +@FeignClient(name = "assetclient", url = "${service.url.asset}") +public interface AssetServiceClient { + + /** + * Gets the total assets count. + * + * @param assetGroup the asset group + * @param targetType the target type + * @param domain the domain + * @return AssetCount + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/count") + AssetCount getTotalAssetsCount(@RequestParam("ag") String assetGroup, + @RequestParam("type") String targetType, + @RequestParam("domain") String domain); + + /** + * Gets the applications list. + * + * @param assetGroup the asset group + * @param domain the domain + * @return AssetApi + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/list/application") + AssetApi getApplicationsList(@RequestParam("ag") String assetGroup, + @RequestParam("domain") String domain); + + /** + * Gets the environment list. + * + * @param assetGroup the asset group + * @param application the application + * @param domain the domain + * @return AssetApi + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/list/environment") + AssetApi getEnvironmentList(@RequestParam("ag") String assetGroup, + @RequestParam("application") String application, + @RequestParam("domain") String domain); + + /** + * Gets the target type list. + * + * @param assetGroup the asset group + * @param domain the domain + * @return AssetApi + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/list/targettype") + AssetApi getTargetTypeList(@RequestParam("ag") String assetGroup, + @RequestParam("domain") String domain); + + /** + * Gets the total assets count by application. + * + * @param assetGroup the asset group + * @param targetType the target type + * @return AssetCount + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/count/byapplication") + AssetCount getTotalAssetsCountByApplication( + @RequestParam("ag") String assetGroup, + @RequestParam("type") String targetType); + + /** + * Gets the total assets count by environment. + * + * @param assetGroup the asset group + * @param application the application + * @param targetType the target type + * @return AssetCount + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/count/byenvironment") + AssetCount getTotalAssetsCountByEnvironment( + @RequestParam("ag") String assetGroup, + @RequestParam("application") String application, + @RequestParam("type") String targetType); + + /** + * Gets the asset group info. + * + * @param assetGroup the asset group + * @return AssetApi + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/assetgroup") + AssetApi getAssetGroupInfo(@RequestParam("ag") String assetGroup); + + /** + * Gets the target type list by domain. + * + * @param assetGroup the asset group + * @param domain the domain + * @return AssetApi + */ + @RequestMapping(method = RequestMethod.GET, value = "/v1/list/targettype") + AssetApi getTargetTypeListByDomain(@RequestParam("ag") String assetGroup, + @RequestParam("domain") String domain); +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/client/ComplianceServiceClient.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/client/ComplianceServiceClient.java new file mode 100644 index 000000000..cec423871 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/client/ComplianceServiceClient.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.tmobile.pacman.api.vulnerability.domain.Request; + +//import com.tmobile.pacman.api.compliance.domain.Request; + +/** + * The Interface ComplianceServiceClient. + */ +@FeignClient(name = "compliance", url = "${service.url.compliance}") +public interface ComplianceServiceClient { + + /** + * Gets the total issues. + * + * @param assetGroup the asset group + * @return the total issues + */ + @RequestMapping(path = "/v1/noncompliancepolicy", method = RequestMethod.POST) + public ResponseEntity getNonCompliancePolicyByRule(@RequestBody(required = false) Request request); + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/config/CrossOriginFilter.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/config/CrossOriginFilter.java new file mode 100644 index 000000000..9d212a292 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/config/CrossOriginFilter.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.config; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Component; + +/** + * Allows cross origin for testing swagger docs using swagger-ui from local file + * system + */ +@Component +public class CrossOriginFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + // Called by the web container to indicate to a filter that it is being + // placed into service. + // We do not want to do anything here. + } + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, + FilterChain chain) throws IOException, ServletException { + HttpServletResponse response = (HttpServletResponse) resp; + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setHeader("Access-Control-Allow-Methods", + "GET, POST, PATCH, PUT, DELETE, OPTIONS"); + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader( + "Access-Control-Allow-Headers", + "Origin, Authorization, X-Requested-With, Content-Type, Accept, X-Auth-Token, X-CSRF-TOKEN"); + chain.doFilter(req, resp); + } + + @Override + public void destroy() { + + // Called by the web container to indicate to a filter that it is being + // taken out of service. + // We do not want to do anything here. + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/config/SpringSecurityConfig.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/config/SpringSecurityConfig.java new file mode 100644 index 000000000..5e153e3c3 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/config/SpringSecurityConfig.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; +import org.springframework.security.web.firewall.DefaultHttpFirewall; +import org.springframework.security.web.firewall.HttpFirewall; + +import feign.RequestInterceptor; +import feign.RequestTemplate; + +/** + * Sample SpringSecurty Config to Support / in "@pathparam". Http security is + * overriden to permit AL. + * + * @author U11087 + * + */ +@Configuration("WebSecurityConfig") +@EnableWebSecurity +public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + /** + * Constructor disables the default security settings + **/ + public SpringSecurityConfig() { + super(true); + } + + @Bean + public RequestInterceptor requestTokenBearerInterceptor() { + return new RequestInterceptor() { + @Override + public void apply(RequestTemplate requestTemplate) { + log.info("Is SecurityContextHolder.getContext() null ===========>"+(SecurityContextHolder.getContext() != null)); + if(SecurityContextHolder.getContext() != null) { + OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails(); + log.info("Token Value===========>"+details.getTokenValue()); + requestTemplate.header("Authorization", "bearer " + details.getTokenValue()); + } + } + }; + } + + /** + * Allow url encoded slash http firewall. + * + * @return the http firewall + */ + @Bean + public HttpFirewall allowUrlEncodedSlashHttpFirewall() { + DefaultHttpFirewall firewall = new DefaultHttpFirewall(); + firewall.setAllowUrlEncodedSlash(true); + return firewall; + } + + /* (non-Javadoc) + * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.WebSecurity) + */ + @Override + public void configure(WebSecurity web) throws Exception { + web.httpFirewall(allowUrlEncodedSlashHttpFirewall()); + web.ignoring().antMatchers("/public/**", "/swagger-ui.html", "/api.html", "/js/swagger-oauth.js", "/images/pacman_logo.svg", "/js/swagger.js", "/js/swagger-ui.js", "/images/favicon-32x32.png", "/images/favicon-16x16.png", "/images/favicon.ico", "/swagger-resources/**", "/v2/api-docs/**", "/webjars/**", + "/v1/auth/**", "/client-auth/**", "/user/login/**", "/auth/refresh/**", "/user/authorize/**"); + web.ignoring().antMatchers("/imgs/**"); + web.ignoring().antMatchers("/css/**"); + web.ignoring().antMatchers("/css/font/**"); + web.ignoring().antMatchers("/proxy*/**"); + web.ignoring().antMatchers("/hystrix/monitor/**"); + web.ignoring().antMatchers("/hystrix/**"); + web.ignoring().antMatchers("/actuator/**"); + web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**"); + } + + /* (non-Javadoc) + * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity) + */ + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + http.anonymous().and().antMatcher("/user").authorizeRequests().antMatchers("/public/**").permitAll() + .antMatchers("/secure/**").authenticated(); + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/controller/VulnerabilityController.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/controller/VulnerabilityController.java new file mode 100644 index 000000000..5eb5c7d28 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/controller/VulnerabilityController.java @@ -0,0 +1,992 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/* + * + */ +package com.tmobile.pacman.api.vulnerability.controller; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TimeZone; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.base.Strings; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.exception.ServiceException; +import com.tmobile.pacman.api.commons.utils.ResponseUtils; +import com.tmobile.pacman.api.vulnerability.domain.CompliantTrendRequest; +import com.tmobile.pacman.api.vulnerability.domain.DitributionDTO; +import com.tmobile.pacman.api.vulnerability.domain.OutputDTO; +import com.tmobile.pacman.api.vulnerability.domain.Request; +import com.tmobile.pacman.api.vulnerability.domain.ResponseData; +import com.tmobile.pacman.api.vulnerability.domain.ResponseWithCount; +import com.tmobile.pacman.api.vulnerability.domain.TrendNote; +import com.tmobile.pacman.api.vulnerability.domain.TrendRequest; +import com.tmobile.pacman.api.vulnerability.domain.VulnerabilityRequest; +import com.tmobile.pacman.api.vulnerability.service.VulnerabilityService; + +import io.swagger.annotations.ApiOperation; + +/** + * The Class VulnerabilityController. + */ +/** + * @author U95007 + * + */ + +@RestController +@PreAuthorize("@securityService.hasPermission(authentication, 'ROLE_USER')") +@CacheConfig(cacheNames = { "trends", "trendsvuln" }) +@ConditionalOnProperty(name = "features.vulnerability.enabled") +public class VulnerabilityController implements Constants { + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory.getLogger(VulnerabilityController.class); + + /** The vulnerability service. */ + @Autowired + private VulnerabilityService vulnerabilityService; + + /** + * Gets the vulnerabilities details. + * + * @param request + * the request + * @return ResponseEntity + */ + + @SuppressWarnings("unchecked") + @PostMapping(value = "/v1/vulnerabilities/detail") + public ResponseEntity getVulnerabilitiesDetails(@RequestBody(required = true) Request request) { + + ResponseWithCount response; + String assetGroup = request.getAg(); + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + + int from = request.getFrom(); + int size = request.getSize(); + if (from < 0) { + return ResponseUtils.buildFailureResponse(new Exception("From should not be a negative number")); + + } + + String searchText = request.getSearchtext(); + + Map filter = request.getFilter(); + if (filter == null) { + filter = new HashMap<>(); + } + + try { + + List> masterDetailList = vulnerabilityService.getVulnerabilitiesDetails(assetGroup, + filter); + + masterDetailList = (List>) vulnerabilityService + .filterMatchingCollectionElements(masterDetailList, searchText, true); + if (masterDetailList.isEmpty()) { + return ResponseUtils + .buildSucessResponse(new ResponseWithCount(new ArrayList>(), 0)); + } + + if (from >= masterDetailList.size()) { + return ResponseUtils.buildFailureResponse(new Exception("From exceeds the size of list")); + } + + int endIndex = 0; + + if ((from + size) > masterDetailList.size()) { + endIndex = masterDetailList.size(); + } else { + endIndex = from + size; + } + + if (endIndex == 0) { + endIndex = masterDetailList.size(); + } + + // from - inclusive, endIndex - exclusive + List> subDetailList = masterDetailList.subList(from, endIndex); + + response = new ResponseWithCount(subDetailList, masterDetailList.size()); + + } catch (Exception e) { + LOGGER.error(EXE_VULN, e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + + + + /** + * Gets the vulnerabilities details by application. + * + * @param request + * the request + * @return ResponseEntity + */ + + @ApiOperation(httpMethod = "POST", value = "Get the cartesian product of vulnerability occureneces of asset and details of assets in an asset group. Filter can receive 'severitylevel' as comma seperated." + + "'searchtext' can be used to get the sorted result based on the search text provided.Sample request: {\"ag\":\"pacman\",\"filter\":{\"severitylevel\":\"3,5\"},\"from\":0,\"searchtext\":\"\",\"size\":25}") + @PostMapping(value = "/v1/vulnerabilities/occurrences") + public ResponseEntity getVulnerabilitiesOccurrences(@RequestBody(required = true) Request request) { + + ResponseWithCount response = null; + String assetGroup = request.getAg(); + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + String searchText = request.getSearchtext(); + int from = request.getFrom(); + int size = request.getSize(); + List severitiesList = new ArrayList<>(); + List severities = new ArrayList<>(); + boolean allMatch = false; + severitiesList.add("3"); + severitiesList.add("4"); + severitiesList.add("5"); + + if (from < 0) { + return ResponseUtils.buildFailureResponse(new Exception("From should not be a negative number")); + } + Map filter = request.getFilter(); + Map severityfilter = new HashMap<>(); + String applicationFilter = null; + String environmentFilter = null; + for (Map.Entry entry : filter.entrySet()) { + if (entry.getKey().equals("severitylevel")) { + severityfilter.put(entry.getKey(), entry.getValue()); + } else if (entry.getKey().equals("tags.Application.keyword")) { + applicationFilter = entry.getValue(); + } else if (entry.getKey().equals("tags.Environment.keyword")) { + environmentFilter = entry.getValue(); + } + } + + if (severityfilter.size() > 0) { + + for (Map.Entry entry : severityfilter.entrySet()) { + severities = Arrays.asList(entry.getValue().split(",")); + } + allMatch = severities.stream().allMatch(severitiesList::contains); + if (allMatch != true) { + return ResponseUtils.buildFailureResponse(new Exception("Severity level can only be 3,4 or 5")); + } + + } + if (!(Optional.ofNullable(size).isPresent()) && size != 0) { + from = 0; + size = 0; + } + + try { + int vulnerabilityOccuranceListCount = vulnerabilityService.vulnerabilityAssetCount(assetGroup, + severityfilter, applicationFilter, environmentFilter, from, size); + List> vulnerabilityOccuranceList = vulnerabilityService + .getAllVulnerabilitiesDetailsByAssetGroup(assetGroup, severityfilter,applicationFilter, environmentFilter, searchText, from, size); + + if (vulnerabilityOccuranceList.isEmpty()) { + return ResponseUtils + .buildSucessResponse(new ResponseWithCount(new ArrayList>(), 0)); + } + + response = new ResponseWithCount(vulnerabilityOccuranceList, vulnerabilityOccuranceListCount); + + } catch (Exception e) { + LOGGER.error(EXE_VULN, e); + return ResponseUtils.buildFailureResponse(e); + } + + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerability summary. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/vulnerabilities/summary", method = RequestMethod.GET) + public ResponseEntity getVulnerabilitysummary(@RequestParam(name = "ag", required = true) String assetGroup, + @RequestParam(name = "severity", required = false) String severity) { + + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + if (Strings.isNullOrEmpty(severity)) { + severity = SEVERITY_LEVELS; + } + DitributionDTO response; + try { + response = new DitributionDTO(vulnerabilityService.getVulnerabilitySummary(assetGroup, severity)); + } catch (Exception e) { + LOGGER.error("Exception in getVulnerabilitysummary ", e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerability by applications. + * + * @param assetGroup + * the asset group + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/vulnerabilities/summarybyapplication", method = RequestMethod.GET) + public ResponseEntity getVulnerabilityByApplications(@RequestParam("ag") String assetGroup) { + + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + ResponseData response; + try { + response = new ResponseData( + vulnerabilityService.getVulnerabilityByAppAndEnv(assetGroup, "tags.Application.keyword", "")); + } catch (Exception e) { + LOGGER.error("Exception in vulnerabilitybyapplications ", e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerabilities trend. + * + * @param request + * the request + * @return ResponseEntity + */ + + @PostMapping(value = "/v1/vulnerabilities/trend") + public ResponseEntity getVulnerabilitiesTrend(@RequestBody(required = true) TrendRequest request) { + + Map response = new HashMap<>(); + String assetGroup = request.getAg(); + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + Date from = request.getFrom(); + Date to = request.getTo(); + Map filter = request.getFilter(); + try { + if (from == null && to == null) { + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + to = cal.getTime(); + cal.add(Calendar.DATE, NEG_THIRTY); + from = cal.getTime(); + } + response.put("ag", assetGroup); + List> trendList = vulnerabilityService.getVulnerabilityTrend(assetGroup, filter, from, + to); + response.put("trend", trendList); + } catch (Exception e) { + LOGGER.error(EXE_VULN, e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerability by environment. + * + * @param assetGroup + * the asset group + * @param application + * the application + * @return ResponseEntity + */ + + @RequestMapping(path = "/v1/vulnerabilities/summarybyenvironment", method = RequestMethod.GET) + public ResponseEntity getVulnerabilityByEnvironment(@RequestParam("ag") String assetGroup, + @RequestParam(name = "application", required = false) String application) { + + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + ResponseData response; + try { + response = new ResponseData(vulnerabilityService.getVulnerabilityByAppAndEnv(assetGroup, + "tags.Environment.keyword", application)); + } catch (Exception e) { + LOGGER.error("Exception in vulnerabilitybyenvironment ", e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerability distribution. + * + * @param assetGroup + * the asset group + * @return ResponseEntity + */ + @RequestMapping(path = "/v1/vulnerabilities/distribution", method = RequestMethod.GET) + public ResponseEntity getVulnerabilityDistribution(@RequestParam("ag") String assetGroup) { + + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + ResponseData response; + try { + response = new ResponseData(vulnerabilityService.getVulnerabilitiesDistribution(assetGroup)); + } catch (Exception e) { + LOGGER.error("Exception in getVulnerabilityDistribution ", e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerabilitysummary by resource id. + * + * @param resourceId + * the resource id + * @return ResponseEntity + */ + @RequestMapping(path = "/v1/vulnerabilities/summary/{resourceId}", method = RequestMethod.GET) + public ResponseEntity getVulnerabilitysummaryByResourceId( + @PathVariable(name = "resourceId", required = true) String resourceId) { + + DitributionDTO response; + try { + response = new DitributionDTO(vulnerabilityService.getVulnerabilitysummaryByResourceId(resourceId)); + } catch (Exception e) { + LOGGER.error("Exception in getVulnerabilitysummary ", e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerability details by resource id. + * + * @param resourceId + * the resource id + * @param searchtext + * the searchtext + * @param from + * the from + * @param size + * the size + * @return ResponseEntity + */ + @SuppressWarnings("unchecked") + @RequestMapping(path = "/v1/vulnerabilities/detail/{resourceId}", method = RequestMethod.GET) + public ResponseEntity getVulnerabilityDetailsByResourceId( + @PathVariable(name = "resourceId", required = true) String resourceId, + @RequestParam(name = "searchtext", required = false) String searchtext, + @RequestParam(name = "from", required = false) Integer from, + @RequestParam(name = "size", required = false) Integer size) { + + Integer iFrom = from == null ? 0 : from; + Integer iSize = size == null ? 0 : size; + + ResponseWithCount response; + try { + List> masterDetailList = vulnerabilityService + .getVulnerabilityDetailsByResourceId(resourceId); + masterDetailList = (List>) vulnerabilityService + .filterMatchingCollectionElements(masterDetailList, searchtext, true); + if (masterDetailList.isEmpty()) { + return ResponseUtils + .buildSucessResponse(new ResponseWithCount(new ArrayList>(), 0)); + } + + if (iFrom >= masterDetailList.size()) { + return ResponseUtils.buildFailureResponse(new Exception("From exceeds the size of list")); + } + + int endIndex = 0; + + if (iSize == 0) { + iSize = masterDetailList.size(); + } + + if ((iFrom + iSize) > masterDetailList.size()) { + endIndex = masterDetailList.size(); + } else { + endIndex = iFrom + iSize; + } + + List> subDetailList = masterDetailList.subList(iFrom, endIndex); + + response = new ResponseWithCount(subDetailList, masterDetailList.size()); + + } catch (Exception e) { + LOGGER.error(EXE_VULN, e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the aging summary. + * + * @param assetGroup + * the asset group + * @return ResponseEntity + */ + @RequestMapping(path = "/v1/vulnerabilities/aging/summary", method = RequestMethod.GET) + public ResponseEntity getAgingSummary(@RequestParam("ag") String assetGroup) { + return ResponseUtils.buildSucessResponse(vulnerabilityService.getAgingSummary(assetGroup)); + } + + /** + * Gets the vulnerability by qid. + * + * @param qid + * the qid + * @return ResponseEntity + */ + @RequestMapping(path = "/v1/vulnerabilities/qids", method = RequestMethod.GET) + public ResponseEntity getVulnerabilityByQid(@RequestParam("qid") String qid) { + return ResponseUtils.buildSucessResponse(vulnerabilityService.getVulnerabilityByQid(qid)); + } + + /** + * Gets the distribution summary by vuln type. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the distribution summary by vuln type + */ + @RequestMapping(path = "/v1/vulnerabilities/distribution-vulntype", method = RequestMethod.GET) + public ResponseEntity getDistributionSummaryByVulnType(@RequestParam("ag") String assetGroup, + @RequestParam(name = "severity", required = false) String severity) { + + Map response = new HashMap<>(); + + List> distributionList = new ArrayList<>(); + try { + distributionList = vulnerabilityService.getDistributionSummaryByVulnType(assetGroup, severity); + } catch (DataException e) { + LOGGER.error("Error in getDistributionSummaryByVulnType", e); + return ResponseUtils.buildFailureResponse(e); + } + + response.put(DISTRIBUTION, distributionList); + return ResponseUtils.buildSucessResponse(response); + + } + + /** + * Gets the distribution summary by infra type. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the distribution summary by infra type + */ + @RequestMapping(path = "/v1/vulnerabilities/distribution-infra", method = RequestMethod.GET) + public ResponseEntity getDistributionSummaryByInfraType(@RequestParam("ag") String assetGroup, + @RequestParam(name = "severity", required = false) String severity) { + Map response = new HashMap<>(); + + List> distributionList = new ArrayList<>(); + try { + distributionList = vulnerabilityService.getDistributionSummaryByInfraType(assetGroup, severity); + } catch (ServiceException e) { + LOGGER.error("Error in getDistributionSummaryByInfraType", e); + return ResponseUtils.buildFailureResponse(e); + } + response.put(DISTRIBUTION, distributionList); + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the distribution summary by env. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the distribution summary by env + */ + @RequestMapping(path = "/v1/vulnerabilities/distribution-env", method = RequestMethod.GET) + public ResponseEntity getDistributionSummaryByEnv(@RequestParam("ag") String assetGroup, + @RequestParam(name = "severity", required = false) String severity) { + Map response = new HashMap<>(); + + List> distributionList = new ArrayList<>(); + try { + distributionList = vulnerabilityService.getDistributionSummaryByEnv(assetGroup, severity); + } catch (ServiceException e) { + LOGGER.error("Error in getDistributionSummaryByEnv", e); + return ResponseUtils.buildFailureResponse(e); + } + response.put(DISTRIBUTION, distributionList); + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the remediation actions summary. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the remediation actions summary + */ + @RequestMapping(path = "/v1/vulnerabilities/remediations/summary", method = RequestMethod.GET) + public ResponseEntity getRemediationActionsSummary(@RequestParam("ag") String assetGroup, + @RequestParam(name = "severity", required = false) String severity) { + Map response = new HashMap<>(); + + List> remediationList = new ArrayList<>(); + try { + remediationList = vulnerabilityService.getRemediationActionsSummary(assetGroup, severity); + } catch (DataException e) { + LOGGER.error("Error in getRemediationActionsSummary", e); + return ResponseUtils.buildFailureResponse(e); + } + + response.put("actions", remediationList); + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the highest lowest performers. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the highest lowest performers + */ + @RequestMapping(path = "/v1/vulnerabilities/performers", method = RequestMethod.GET) + public ResponseEntity getHighestLowestPerformers(@RequestParam("ag") String assetGroup, + @RequestParam(name = "severity", required = false) String severity) { + Map response = new HashMap<>(); + + List> responseList = new ArrayList<>(); + Map directorData = vulnerabilityService.getHighestLowestPerformers(assetGroup, severity, + "org"); + Set keys = directorData.keySet(); + String[] keysArray = keys.toArray(new String[keys.size()]); + + if (keysArray.length >= 10) { + + Map info = new HashMap<>(); + info.put(CATEGORY, HIGHEST); + List> directorList = new ArrayList<>(); + + for (int i = 0; i < keysArray.length && i < Constants.FIVE; i++) { + Map director = new HashMap<>(); + director.put(keysArray[i], directorData.get(keysArray[i])); + directorList.add(director); + } + info.put(DIRECTORS, directorList); + responseList.add(info); + + info = new HashMap<>(); + info.put(CATEGORY, "Lowest"); + directorList = new ArrayList<>(); + + for (int i = keysArray.length - Constants.ONE; i > keysArray.length - Constants.SIX && i >= 0; i--) { + Map director = new HashMap<>(); + director.put(keysArray[i], directorData.get(keysArray[i])); + directorList.add(director); + } + info.put(DIRECTORS, directorList); + responseList.add(info); + } else { + + if (keysArray.length % 2 == 0) { + Map info = new HashMap<>(); + info.put(CATEGORY, HIGHEST); + List> directorList = new ArrayList<>(); + + for (int i = 0; i < keysArray.length / 2; i++) { + Map director = new HashMap<>(); + director.put(keysArray[i], directorData.get(keysArray[i])); + directorList.add(director); + } + info.put(DIRECTORS, directorList); + responseList.add(info); + + } else { + + Map info = new HashMap<>(); + info.put(CATEGORY, HIGHEST); + List> directorList = new ArrayList<>(); + + for (int i = 0; i < (keysArray.length / 2) + 1; i++) { + Map director = new HashMap<>(); + director.put(keysArray[i], directorData.get(keysArray[i])); + directorList.add(director); + } + info.put(DIRECTORS, directorList); + responseList.add(info); + } + + Map info = new HashMap<>(); + info.put(CATEGORY, "Lowest"); + List> directorList = new ArrayList<>(); + + for (int i = keysArray.length - Constants.ONE; i > keysArray.length / 2 && i >= 0; i--) { + Map director = new HashMap<>(); + director.put(keysArray[i], directorData.get(keysArray[i])); + directorList.add(director); + } + info.put(DIRECTORS, directorList); + responseList.add(info); + } + response.put("response", responseList); + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the highest lowest performers. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @param type + * the type + * @return the highest lowest performers + */ + @RequestMapping(path = "/v2/vulnerabilities/performers", method = RequestMethod.GET) + public ResponseEntity getHighestLowestPerformers(@RequestParam("ag") String assetGroup, + @RequestParam(name = "severity", required = false) String severity, + @RequestParam(name = "type") PerfType type) { + Map response = new HashMap<>(); + + Map perfData = vulnerabilityService.getHighestLowestPerformers(assetGroup, severity, + type.name()); + List> perfList = new ArrayList<>(); + Map info = new HashMap<>(); + String typeName = type.name(); + switch (typeName) { + case "org": + info.put(CATEGORY, "Director"); + break; + case "application": + info.put(CATEGORY, "Application"); + break; + case "environment": + info.put(CATEGORY, "Environment"); + break; + } + + if (perfData.size() > 1) { + Set keys = perfData.keySet(); + String[] keysArray = keys.toArray(new String[keys.size()]); + + for (int i = 0; i < keysArray.length; i++) { + Map director = new HashMap<>(); + director.put(keysArray[i], perfData.get(keysArray[i])); + perfList.add(director); + } + } + info.put("data", perfList); + + response.put("response", info); + return ResponseUtils.buildSucessResponse(response); + } + + /** + * Gets the vulnerability trend. + * + * @param header + * the header + * @param request + * the request + * @return the vulnerability trend + */ + @Cacheable(cacheNames = "trends", key = "#request.vulnCacheKey", unless = "#result.statusCodeValue!=200") + @RequestMapping(path = "/v1/vulnerabilities/trend/open-new", method = RequestMethod.POST) + public ResponseEntity getVulnerabilityTrend(@RequestBody(required = true) TrendRequest request) { + + String ag = request.getAg(); + if (Strings.isNullOrEmpty(ag)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + Date from = request.getFrom(); + if (from == null) { + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + cal.add(Calendar.DATE, NEG_THIRTY); + from = cal.getTime(); + } + + Map filter = request.getFilter(); + String severity = SEVERITY_LEVELS; + if (filter != null) { + severity = filter.get("severity"); + if (severity == null) { + severity = SEVERITY_LEVELS; + } + } + + Map response = new HashMap<>(); + try { + List> trendList = vulnerabilityService.getVulnerabilityNewOpenTrend(ag, severity, from); + response.put("trend", trendList); + return ResponseUtils.buildSucessResponse(response); + } catch (Exception e) { + return ResponseUtils.buildFailureResponse(e); + } + + } + + /** + * Creates the trend annotation. + * + * @param request + * the request + * @return the response entity + */ + @RequestMapping(path = "/v1/vulnerabilities/trend/notes", method = RequestMethod.POST) + public ResponseEntity createTrendAnnotation(@RequestBody(required = true) TrendNote request) { + + try { + if (vulnerabilityService.createTrendAnnotation(request)) { + return ResponseUtils.buildSucessResponse("Annotation created"); + } else { + return ResponseUtils.buildFailureResponse(new Exception("Annotation creation failed")); + } + } catch (JsonProcessingException e) { + LOGGER.error("Error in createTrendAnnotation ", e); + return ResponseUtils.buildFailureResponse(e); + } + } + + /** + * Gets the trend annotations. + * + * @param assetGroup + * the asset group + * @param from + * the from + * @return the trend annotations + */ + @RequestMapping(path = "/v1/vulnerabilities/trend/notes", method = RequestMethod.GET) + public ResponseEntity getTrendAnnotations(@RequestParam("ag") String assetGroup, + @RequestParam(name = "from", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date from) { + + if (from == null) { + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + cal.add(Calendar.DATE, NEG_THIRTY); + from = cal.getTime(); + } + Map notes = new HashMap<>(); + try { + notes.put("notes", vulnerabilityService.getTrendAnnotations(assetGroup, from)); + } catch (DataException e) { + LOGGER.error("Error in getTrendAnnotations ", e); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(notes); + + } + + /** + * Delete trend annotation. + * + * @param noteId + * the note id + * @return the response entity + */ + @RequestMapping(path = "/v1/vulnerabilities/trend/notes/{noteId}", method = RequestMethod.DELETE) + public ResponseEntity deleteTrendAnnotation(@PathVariable(name = "noteId", required = true) String noteId) { + + if (vulnerabilityService.deleteTrendAnnotation(noteId)) { + return ResponseUtils.buildSucessResponse("Annotation Deleted"); + } else { + return ResponseUtils.buildFailureResponse(new Exception("Annotation deletion failed")); + } + } + + /** + * Gets the vulnerability assets trend. + * + * @param request + * the request + * @return the vulnerability assets trend + */ + @Cacheable(cacheNames = "trendsvuln", key = "#request.vulnCacheKey", unless = "#result.statusCodeValue!=200") + @RequestMapping(path = "/v1/vulnerabilities/trend/total-affected", method = RequestMethod.POST) + public ResponseEntity getVulnerabilityAssetsTrend(@RequestBody(required = true) TrendRequest request) { + + String ag = request.getAg(); + if (Strings.isNullOrEmpty(ag)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + Date from = request.getFrom(); + if (from == null) { + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + cal.add(Calendar.DATE, NEG_THIRTY); + from = cal.getTime(); + } + + Map filter = request.getFilter(); + String severity = SEVERITY_LEVELS; + if (filter != null) { + severity = filter.get("severity"); + if (severity == null) { + severity = SEVERITY_LEVELS; + } + } + + Map response = new HashMap<>(); + try { + response.put("trend", vulnerabilityService.getVulnerabilityAssetsTrend(ag, severity, from)); + } catch (DataException e) { + LOGGER.error("Error in getVulnerabilityAssetsTrend ", e); + return ResponseUtils.buildFailureResponse(e); + } + + return ResponseUtils.buildSucessResponse(response); + + } + + /** + * Gets the vulnerability summary by assets. + * + * @param assetGroup + * the asset group + * @return the vulnerability summary by assets + */ + @RequestMapping(path = "/v1/vulnerabilities/summarybyassets", method = RequestMethod.GET) + public ResponseEntity getVulnerabilitySummaryByAssets( + @RequestParam(name = "ag", required = true) String assetGroup) { + try { + return ResponseUtils.buildSucessResponse(vulnerabilityService.getVulnerabilitySummaryByAssets(assetGroup)); + } catch (ServiceException | DataException e) { + LOGGER.error("Error in getVulnerabilitySummaryByAssets ", e); + return ResponseUtils.buildFailureResponse(e); + } + } + + /** + * Gets the vulnerabilities.asssetGroup is mandatory. API returns count of + * totalVulnerabilities/totalAssets/totalVulnerabilites Assets + * + * @param assetGroup + * name of the asset group + * @return ResponseEntity + */ + // @Cacheable("trends") + @RequestMapping(path = "/v1/vulnerabilites", method = RequestMethod.GET) + public ResponseEntity getVulnerabilities(@RequestParam("ag") String assetGroup) { + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + OutputDTO output = null; + try { + Map vulnerabilities = new HashMap<>(); + Map vulnSummary = vulnerabilityService.getVulnerabilitySummary(assetGroup, SEVERITY_LEVELS); + vulnerabilities.put("vulnerabilities", Long.valueOf(vulnSummary.get("vulnerabilities").toString())); + vulnerabilities.put("hosts", Long.valueOf(vulnSummary.get("hosts").toString())); + vulnerabilities.put("totalVulnerableAssets", + Long.valueOf(vulnSummary.get("totalVulnerableAssets").toString())); + vulnSummary.remove("compliantpercent"); + output = new OutputDTO(vulnerabilities); + } catch (ServiceException e) { + return vulnerabilityService.formatException(e); + } + return ResponseUtils.buildSucessResponse(output); + } + + @RequestMapping(path = "/v1/trend/compliance/vulnerabilities", method = RequestMethod.POST) + public ResponseEntity getVulnTrend(@RequestBody(required = true) CompliantTrendRequest request) { + + Map response = new HashMap<>(); + String assetGroup = request.getAg(); + + Date input = request.getFrom(); + + if (input == null) { + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + cal.add(Calendar.DATE, NEG_THIRTY); + input = cal.getTime(); + } + + Instant instant = input.toInstant(); + ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault()); + LocalDate fromDate = zdt.toLocalDate(); + LocalDate toDate = LocalDate.now(); + + if (Strings.isNullOrEmpty(assetGroup)) { + return ResponseUtils.buildFailureResponse(new Exception(ASSET_MANDATORY)); + } + + try { + Map ruleTrendProgressList = vulnerabilityService.getTrendProgress(assetGroup, null, + fromDate, toDate, "vulncompliance"); + response.put(RESPONSE, ruleTrendProgressList); + } catch (ServiceException e) { + LOGGER.error("Exception in getVulnTrend", e.getMessage()); + return ResponseUtils.buildFailureResponse(e); + } + return ResponseUtils.buildSucessResponse(response); + } + +} + +enum PerfType { + org, application, environment +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetApi.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetApi.java new file mode 100644 index 000000000..b3da1ed07 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetApi.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Oct 26, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; +/** + * The Class AssetApi. + */ +public class AssetApi { + private String message; + + private AssetApiData data; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public AssetApiData getData() { + return data; + } + + public void setData(AssetApiData data) { + this.data = data; + } + + @Override + public String toString() { + return "ClassPojo [message = " + message + ", data = " + data + "]"; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetApiData.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetApiData.java new file mode 100644 index 000000000..c9e36ab42 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetApiData.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Oct 26, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; +/** + * The Class AssetApiData. + */ +public class AssetApiData { + private String ag; + + private String datasource; + + private AssetCountDTO[] applications; + + private AssetCountDTO[] environments; + + private AssetCountDTO[] targettypes; + + public String getDatasource() { + return datasource; + } + + public void setDatasource(String datasource) { + this.datasource = datasource; + } + + public AssetCountDTO[] getTargettypes() { + return targettypes; + } + + public void setTargettypes(AssetCountDTO[] targettypes) { + this.targettypes = targettypes; + } + + public AssetCountDTO[] getEnvironments() { + return environments; + } + + public void setEnvironments(AssetCountDTO[] environments) { + this.environments = environments; + } + + public String getAg() { + return ag; + } + + public void setAg(String ag) { + this.ag = ag; + } + + public AssetCountDTO[] getApplications() { + return applications; + } + + public void setApplications(AssetCountDTO[] applications) { + this.applications = applications; + } + + @Override + public String toString() { + return "ClassPojo [applications = " + applications + ", ag = " + ag + + ", environments = " + environments + ", targettypes = " + + targettypes + ",datasource = " + datasource + "]"; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCount.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCount.java new file mode 100644 index 000000000..f08f7c151 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCount.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Oct 26, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; +/** + * The Class AssetCount. + */ +public class AssetCount { + private String message; + + private AssetCountData data; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public AssetCountData getData() { + return data; + } + + public void setData(AssetCountData data) { + this.data = data; + } + + @Override + public String toString() { + return "ClassPojo [message = " + message + ", data = " + data + "]"; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountByAppEnvDTO.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountByAppEnvDTO.java new file mode 100644 index 000000000..50b73cb91 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountByAppEnvDTO.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Nov 5, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; +/** + * The Class AssetCountByAppEnvDTO. + */ +public class AssetCountByAppEnvDTO { + private String count; + + private String type; + + private AssetCountEnvCount[] environments; + + private String application; + + public AssetCountEnvCount[] getEnvironments() { + return environments; + } + + public void setEnvironments(AssetCountEnvCount[] environments) { + this.environments = environments; + } + + public String getApplication() { + return application; + } + + public void setApplication(String application) { + this.application = application; + } + + public String getCount() { + return count; + } + + public void setCount(String count) { + this.count = count; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return "ClassPojo [count = " + count + ", type = " + type + + ", application = " + application + ",environments = " + + environments + "]"; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountDTO.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountDTO.java new file mode 100644 index 000000000..de757ec5a --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountDTO.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Nov 5, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; +/** + * The Class AssetCountDTO. + */ +public class AssetCountDTO { + + /** The name. */ + private String name; + + /** The type. */ + private String type; + + /** + * Gets the type. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * Sets the type. + * + * @param type the new type + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets the name. + * + * @param name the new name + */ + public void setName(String name) { + this.name = name; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "ClassPojo [name = " + name + ",type = " + type + "]"; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountData.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountData.java new file mode 100644 index 000000000..f5d069c43 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountData.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Oct 26, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; +/** + * The Class AssetCountData. + */ +public class AssetCountData { + + /** The assetcount. */ + private AssetCountByAppEnvDTO[] assetcount; + + /** The ag. */ + private String ag; + + /** The type. */ + private String type; + + /** + * Gets the type. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * Sets the type. + * + * @param type the new type + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the assetcount. + * + * @return the assetcount + */ + public AssetCountByAppEnvDTO[] getAssetcount() { + return assetcount; + } + + /** + * Sets the assetcount. + * + * @param assetcount the new assetcount + */ + public void setAssetcount(AssetCountByAppEnvDTO[] assetcount) { + this.assetcount = assetcount; + } + + /** + * Gets the ag. + * + * @return the ag + */ + public String getAg() { + return ag; + } + + /** + * Sets the ag. + * + * @param ag the new ag + */ + public void setAg(String ag) { + this.ag = ag; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "ClassPojo [assetcount = " + assetcount + ", ag = " + ag + + ", type = " + type + "]"; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountEnvCount.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountEnvCount.java new file mode 100644 index 000000000..5600dd7d3 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/AssetCountEnvCount.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.domain; + +/** + * The Class AssetCountEnvCount. + */ +public class AssetCountEnvCount { + + /** The environment. */ + private String environment; + + /** The count. */ + private String count; + + /** + * Gets the environment. + * + * @return the environment + */ + public String getEnvironment() { + return environment; + } + + /** + * Sets the environment. + * + * @param environment the new environment + */ + public void setEnvironment(String environment) { + this.environment = environment; + } + + /** + * Gets the count. + * + * @return the count + */ + public String getCount() { + return count; + } + + /** + * Sets the count. + * + * @param count the new count + */ + public void setCount(String count) { + this.count = count; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "ClassPojo [count = " + count + ",environment = " + environment + + "]"; + } + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/CompliantTrendRequest.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/CompliantTrendRequest.java new file mode 100644 index 000000000..30cb64576 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/CompliantTrendRequest.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.Date; +import java.util.Map; +/** + * The Class CompliantTrendRequest. + */ +public class CompliantTrendRequest { + + /** The ag. */ + private String ag; + + /** The from. */ + private Date from; + + /** The filters. */ + private Map filters; + + /** + * Gets the filters. + * + * @return the filters + */ + public Map getFilters() { + return filters; + } + + /** + * Sets the filters. + * + * @param filters the filters + */ + public void setFilters(Map filters) { + this.filters = filters; + } + + /** + * Gets the ag. + * + * @return the ag + */ + public String getAg() { + return ag; + } + + /** + * Sets the ag. + * + * @param ag the new ag + */ + public void setAg(String ag) { + this.ag = ag; + } + + /** + * Gets the from. + * + * @return the from + */ + public Date getFrom() { + return from; + } + + /** + * Sets the from. + * + * @param from the new from + */ + public void setFrom(Date from) { + this.from = from; + } + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/DitributionDTO.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/DitributionDTO.java new file mode 100644 index 000000000..ab25e4644 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/DitributionDTO.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Oct 23, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.Map; +/** + * The Class DitributionDTO. + */ +public class DitributionDTO { + + /** The response. */ + Map response; + + /** + * Instantiates a new ditribution DTO. + */ + public DitributionDTO() { + super(); + } + + /** + * Instantiates a new ditribution DTO. + * + * @param distribution the distribution + */ + public DitributionDTO(Map distribution) { + super(); + this.response = distribution; + } + + /** + * Gets the distribution. + * + * @return the distribution + */ + public Map getDistribution() { + return response; + } + + /** + * Sets the distribution. + * + * @param distribution the distribution + */ + public void setDistribution(Map distribution) { + this.response = distribution; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/OutputDTO.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/OutputDTO.java new file mode 100644 index 000000000..8445414ba --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/OutputDTO.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Oct 24, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.Map; +/** + * The Class OutputDTO. + */ +public class OutputDTO { + + /** The response. */ + Map response; + + /** + * Instantiates a new output DTO. + * + * @param output the output + */ + public OutputDTO(Map output) { + super(); + this.response = output; + } + + /** + * Instantiates a new output DTO. + */ + public OutputDTO() { + super(); + } + + /** + * Gets the output. + * + * @return the output + */ + public Map getOutput() { + return response; + } + + /** + * Sets the output. + * + * @param output the output + */ + public void setOutput(Map output) { + this.response = output; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/Request.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/Request.java new file mode 100644 index 000000000..18aefb327 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/Request.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Nov 17, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.base.Joiner; + + +/** + * The Class Request. + */ +public class Request { + + /** The searchtext. */ + private String searchtext = null; + + /** The from. */ + private int from; + + /** The size. */ + private int size; + + /** The filter. */ + private Map filter; + + /** The ag. */ + private String ag; + + /** + * Instantiates a new request. + * + * @param searchtext the searchtext + * @param from the from + * @param size the size + * @param filter the filter + * @param ag the ag + */ + public Request(String searchtext, int from, int size, + Map filter, String ag) { + super(); + this.searchtext = searchtext; + this.from = from; + this.size = size; + this.filter = filter; + this.ag = ag; + } + + /** + * Instantiates a new request. + */ + public Request() { + super(); + } + + /** + * this is used to cache the response. + * + * @return the key + */ + public String getKey() { + return ag + + searchtext + + Joiner.on("_") + .withKeyValueSeparator("-") + .join(filter == null ? new HashMap() + : filter) + from + "" + size; + } + + /** + * Gets the ag. + * + * @return the ag + */ + public String getAg() { + return ag; + } + + /** + * Sets the ag. + * + * @param ag the new ag + */ + public void setAg(String ag) { + this.ag = ag; + } + + /** + * Gets the searchtext. + * + * @return the searchtext + */ + public String getSearchtext() { + return searchtext; + } + + /** + * Sets the searchtext. + * + * @param searchtext the new searchtext + */ + public void setSearchtext(String searchtext) { + this.searchtext = searchtext; + } + + /** + * Gets the from. + * + * @return the from + */ + public int getFrom() { + return from; + } + + /** + * Sets the from. + * + * @param from the new from + */ + public void setFrom(int from) { + this.from = from; + } + + /** + * Gets the size. + * + * @return the size + */ + public int getSize() { + return size; + } + + /** + * Sets the size. + * + * @param size the new size + */ + public void setSize(int size) { + this.size = size; + } + + /** + * Gets the filter. + * + * @return the filter + */ + public Map getFilter() { + return filter; + } + + /** + * Sets the filter. + * + * @param filter the filter + */ + public void setFilter(Map filter) { + this.filter = filter; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "ClassPojo [ag=" + ag + ", searchtext = " + searchtext + + ", from = " + from + ", filter = " + filter + ", size = " + + size + "]"; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseDTO.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseDTO.java new file mode 100644 index 000000000..c043ec4e7 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseDTO.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Nov 15, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.Map; +/** + * The Class ResponseDTO. + */ +public class ResponseDTO { + + /** The response. */ + Map response; + + /** + * Instantiates a new response DTO. + */ + public ResponseDTO() { + super(); + } + + /** + * Instantiates a new response DTO. + * + * @param response the response + */ + public ResponseDTO(Map response) { + super(); + this.response = response; + } + + /** + * Gets the response. + * + * @return the response + */ + public Map getResponse() { + return response; + } + + /** + * Sets the response. + * + * @param response the response + */ + public void setResponse(Map response) { + this.response = response; + } + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseData.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseData.java new file mode 100644 index 000000000..2699d7c1f --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseData.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Nov 15, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.List; +import java.util.Map; + +/** + * The Class Response. + */ +public class ResponseData { + + /** The response. */ + List> response; + + /** + * Instantiates a new response. + */ + public ResponseData() { + super(); + } + + /** + * Instantiates a new response. + * + * @param response the response + */ + public ResponseData(List> response) { + super(); + this.response = response; + } + + /** + * Gets the response. + * + * @return the response + */ + public List> getResponse() { + return response; + } + + /** + * Sets the response. + * + * @param response the response + */ + public void setResponse(List> response) { + this.response = response; + } + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseWithCount.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseWithCount.java new file mode 100644 index 000000000..c9d49f949 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseWithCount.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Nov 15, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.List; +import java.util.Map; + + +/** + * The Class ResponseWithCount. + */ +public class ResponseWithCount { + + /** The response. */ + List> response; + + /** The total. */ + long total; + + /** + * Instantiates a new response with count. + * + * @param response the response + * @param total the total + */ + public ResponseWithCount(List> response, long total) { + super(); + this.response = response; + this.total = total; + } + + /** + * Gets the total. + * + * @return the total + */ + public long getTotal() { + return total; + } + + /** + * Sets the total. + * + * @param total the new total + */ + public void setTotal(long total) { + this.total = total; + } + + /** + * Gets the response. + * + * @return the response + */ + public List> getResponse() { + return response; + } + + /** + * Sets the response. + * + * @param response the response + */ + public void setResponse(List> response) { + this.response = response; + } + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseWithOrder.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseWithOrder.java new file mode 100644 index 000000000..5a70aa5d3 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/ResponseWithOrder.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :SGorle + Modified Date: Dec 9, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.LinkedHashMap; +import java.util.List; + +/** + * The DTO Class ResponseWithOrder for API response. + */ +public class ResponseWithOrder { + + /** The response. */ + List> response; + + /** The total. */ + long total; + + /** + * Instantiates a new response with order. + */ + public ResponseWithOrder() { + super(); + } + + /** + * Instantiates a new response with order. + * + * @param response the response + * @param total the total + */ + public ResponseWithOrder(List> response, + long total) { + super(); + this.response = response; + this.total = total; + } + + /** + * Gets the response. + * + * @return the response + */ + public List> getResponse() { + return response; + } + + /** + * Sets the response. + * + * @param response the response + */ + public void setResponse(List> response) { + this.response = response; + } + + /** + * Gets the total. + * + * @return the total + */ + public long getTotal() { + return total; + } + + /** + * Sets the total. + * + * @param total the new total + */ + public void setTotal(long total) { + this.total = total; + } + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/TrendNote.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/TrendNote.java new file mode 100644 index 000000000..4adb8eba4 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/TrendNote.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.Date; +/** + * The Class TrendNote. + */ +public class TrendNote { + + /** The ag. */ + private String ag; + + /** The note. */ + private String note; + + /** The date. */ + private Date date; + + /** + * Gets the ag. + * + * @return the ag + */ + public String getAg() { + return ag; + } + + /** + * Sets the ag. + * + * @param ag the new ag + */ + public void setAg(String ag) { + this.ag = ag; + } + + /** + * Gets the note. + * + * @return the note + */ + public String getNote() { + return note; + } + + /** + * Sets the note. + * + * @param note the new note + */ + public void setNote(String note) { + this.note = note; + } + + /** + * Gets the date. + * + * @return the date + */ + public Date getDate() { + return date; + } + + /** + * Sets the date. + * + * @param date the new date + */ + public void setDate(Date date) { + this.date = date; + } + + +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/TrendRequest.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/TrendRequest.java new file mode 100644 index 000000000..aecce9091 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/TrendRequest.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +/** + * The Class TrendRequest. + */ +public class TrendRequest { + + /** The from. */ + private Date from; + + /** The to. */ + private Date to; + + /** The filter. */ + private Map filter; + + /** The ag. */ + private String ag; + + /** + * Gets the from. + * + * @return the from + */ + public Date getFrom() { + return from; + } + + /** + * Sets the from. + * + * @param from the new from + */ + public void setFrom(Date from) { + this.from = from; + } + + /** + * Gets the to. + * + * @return the to + */ + public Date getTo() { + return to; + } + + /** + * Sets the to. + * + * @param to the new to + */ + public void setTo(Date to) { + this.to = to; + } + + /** + * Gets the filter. + * + * @return the filter + */ + public Map getFilter() { + return filter; + } + + /** + * Sets the filter. + * + * @param filter the filter + */ + public void setFilter(Map filter) { + this.filter = filter; + } + + /** + * Gets the ag. + * + * @return the ag + */ + public String getAg() { + return ag; + } + + /** + * Sets the ag. + * + * @param ag the new ag + */ + public void setAg(String ag) { + this.ag = ag; + } + + /** + * Gets the vuln cache key. + * + * @return the vuln cache key + */ + public String getVulnCacheKey(){ + String severity = "3,4,5"; + if(filter!=null&& + (filter.get("severity")!=null)){ + severity =filter.get("severity"); + } + + return ag+ new SimpleDateFormat("yyyy-MM-dd").format(from)+severity; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/VulnerabilityRequest.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/VulnerabilityRequest.java new file mode 100644 index 000000000..f62f60766 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/domain/VulnerabilityRequest.java @@ -0,0 +1,212 @@ +package com.tmobile.pacman.api.vulnerability.domain; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.base.Joiner; + +public class VulnerabilityRequest { + /** The searchtext. */ + private String searchtext = null; + + /** The from. */ + private int from; + + /** The size. */ + private int size; + + /** The severity filter. */ + private Map severityFilter; + /** The application filter. */ + String applicationFilter; + /** The environment filter. */ + String environmentFilter; + + /** The ag. */ + private String ag; + + /** + * Instantiates a new request. + * + * @param searchtext + * the searchtext + * @param from + * the from + * @param size + * the size + * @param filter + * the filter + * @param ag + * the ag + */ + public VulnerabilityRequest(String searchtext, int from, int size, Map severityFilter, + String environmentFilter, String applicationFilter, String ag) { + super(); + this.searchtext = searchtext; + this.from = from; + this.size = size; + this.severityFilter = severityFilter; + this.applicationFilter = applicationFilter; + this.environmentFilter = environmentFilter; + this.ag = ag; + } + + /** + * Instantiates a new request. + */ + public VulnerabilityRequest() { + super(); + } + + /** + * this is used to cache the response. + * + * @return the key + */ + public String getKey() { + return ag + searchtext + Joiner.on("_").withKeyValueSeparator("-") + .join(severityFilter == null ? new HashMap() : severityFilter) + from + "" + size; + } + + /** + * Gets the ag. + * + * @return the ag + */ + public String getAg() { + return ag; + } + + /** + * Sets the ag. + * + * @param ag + * the new ag + */ + public void setAg(String ag) { + this.ag = ag; + } + + /** + * Gets the searchtext. + * + * @return the searchtext + */ + public String getSearchtext() { + return searchtext; + } + + /** + * Sets the searchtext. + * + * @param searchtext + * the new searchtext + */ + public void setSearchtext(String searchtext) { + this.searchtext = searchtext; + } + + /** + * Gets the from. + * + * @return the from + */ + public int getFrom() { + return from; + } + + /** + * Sets the from. + * + * @param from + * the new from + */ + public void setFrom(int from) { + this.from = from; + } + + /** + * Gets the size. + * + * @return the size + */ + public int getSize() { + return size; + } + + /** + * Sets the size. + * + * @param size + * the new size + */ + public void setSize(int size) { + this.size = size; + } + + /** + * Gets the filter. + * + * @return the filter + */ + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + + /** + * @return the severityFilter + */ + + /** + * @return the applicationFilter + */ + public String getApplicationFilter() { + return applicationFilter; + } + + /** + * @return the severityFilter + */ + public Map getSeverityFilter() { + return severityFilter; + } + + /** + * @param severityFilter + * the severityFilter to set + */ + public void setSeverityFilter(Map severityFilter) { + this.severityFilter = severityFilter; + } + + /** + * @return the environmentFilter + */ + public String getEnvironmentFilter() { + return environmentFilter; + } + + /** + * @param severityFilter + * the severityFilter to set + */ + + /** + * @param applicationFilter + * the applicationFilter to set + */ + public void setApplicationFilter(String applicationFilter) { + this.applicationFilter = applicationFilter; + } + + /** + * @param environmentFilter + * the environmentFilter to set + */ + public void setEnvironmentFilter(String environmentFilter) { + this.environmentFilter = environmentFilter; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityRepository.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityRepository.java new file mode 100644 index 000000000..64a750e32 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityRepository.java @@ -0,0 +1,1786 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.repository; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.entity.ContentType; +import org.apache.http.nio.entity.NStringEntity; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.RestClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; +import com.tmobile.pacman.api.commons.repo.PacmanRdsRepository; +import com.tmobile.pacman.api.commons.utils.CommonUtils; +import com.tmobile.pacman.api.commons.utils.PacHttpUtils; +import com.tmobile.pacman.api.vulnerability.domain.TrendNote; + +/** + * This is the Repository layer which makes call to ElasticSearch. + */ +@Repository +public class VulnerabilityRepository implements Constants { + + /** The es host. */ + @Value("${elastic-search.host}") + private String esHost; + + /** The es port. */ + @Value("${elastic-search.port}") + private int esPort; + + /** The update ES host. */ + @Value("${elastic-search.update-host}") + private String updateESHost; + + /** The update ES port. */ + @Value("${elastic-search.update-port}") + private int updateESPort; + + /** The Constant PROTOCOL. */ + private static final String PROTOCOL = "http"; + + /** The es url. */ + private String esUrl; + + /** The elastic search repository. */ + @Autowired + private ElasticSearchRepository elasticSearchRepository; + + /** The rds repository. */ + @Autowired + private PacmanRdsRepository rdsRepository; + + /** The Constant LOGGER. */ + private static final Log LOGGER = LogFactory.getLog(VulnerabilityRepository.class); + + /** The rest client. */ + private RestClient restClient; + + /** + * Initializes the esUrl. + */ + @PostConstruct + void init() { + esUrl = PROTOCOL + "://" + esHost + ":" + esPort; + } + + /** + * Gets the all vulnerabilities. + * + * @param vulnAssetsAffectedQids + * the vuln assets affected qids + * @return the all vulnerabilities + * @throws DataException + * the DataException + */ + public List> getAllVulnerabilities(List vulnAssetsAffectedQids) throws DataException { + + List> results = new ArrayList<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/qualys-kb/kb/_search"); + String responseJson = ""; + try { + for (int index = 0; index <= (vulnAssetsAffectedQids.size() / THOUSAND_TWENTY_FOUR); index++) { + int from = index * THOUSAND_TWENTY_FOUR; + int to = from + THOUSAND_TWENTY_FOUR; + if (vulnAssetsAffectedQids.size() < to) { + to = vulnAssetsAffectedQids.size(); + } + StringBuilder requestBody = new StringBuilder( + "{\"size\":10000,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"qid.keyword\":"); + requestBody.append(vulnAssetsAffectedQids.subList(from, to)); + requestBody.append("}}"); + requestBody.append("]}}}"); + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + elasticSearchRepository.processResponseAndSendTheScrollBack(responseJson, results); + } + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilityData", e); + throw new DataException(); + } + return results; + } + + public List> getAllVulnerabilitiesByAssetGroup(String assetGroup, String targetType, + Map mustFilter, List occurrenceFieldList, int from, int size, + Map mustTermsFilter) throws DataException { + List> results = new ArrayList<>(); + if (size != 0) { + try { + results = elasticSearchRepository.getSortedDataFromESBySize(assetGroup, targetType, mustFilter, null, + null, occurrenceFieldList, from, size, null, mustTermsFilter, null); + } catch (Exception e) { + LOGGER.error("Error in getAllVulnerabilitiesByAssetGroup", e); + throw new DataException(); + } + } else { + try { + /* + * results = vulnerabilityAssetsCount(assetGroup, targetType, mustFilter, + * occurrenceFieldList, from, size); + */ + results = elasticSearchRepository.getSortedDataFromES(assetGroup, targetType, mustFilter, null, null, + occurrenceFieldList, mustTermsFilter, null); + } catch (Exception e) { + LOGGER.error("Error in getAllVulnerabilitiesByAssetGroup", e); + throw new DataException(); + } + + } + for (Map map : results) { + map.remove("_routing"); + map.remove("_parent"); + map.remove("_id"); + } + return results; + } + + public List> getDetailsByResourceId(String assetGroup, Map mustFilter, + List resourceFieldList, Map mustTermFilter) throws DataException { + List> results = new ArrayList<>(); + try { + + results = elasticSearchRepository.getSortedDataFromES(assetGroup, null, mustFilter, null, null, + resourceFieldList, mustTermFilter, null); + + } catch (Exception e) { + LOGGER.error("Error in getDetailsByResourceId", e); + throw new DataException(); + } + + return results; + } + + /** + * Gets the assets affected count. + * + * @param assetGroup + * the asset group + * @param filter + * the filter + * @param parentType + * the parent type + * @return the assets affected count + */ + public Map getAssetsAffectedCount(String assetGroup, Map filter, String parentType) { + + Map assetsAffectedCount = new HashMap<>(); + Map filterForQuery = new HashMap<>(); + if (!CollectionUtils.isEmpty(filter)) { + filterForQuery = new HashMap<>(filter); + } + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(VULN_INFO); + urlToQuery.append("/").append(SEARCH); + String responseJson = ""; + try { + String severity = SEVERITY_LEVELS; + if (filterForQuery.containsKey(SEVEITY_LEVEL)) { + severity = filterForQuery.get(SEVEITY_LEVEL); + filterForQuery.remove(SEVEITY_LEVEL); + } + + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel.keyword\":["); + requestBody.append(severity + "]}},"); + requestBody.append("{\"has_parent\":{\"parent_type\":\"" + parentType + + "\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}"); + + if (!filterForQuery.isEmpty()) { + requestBody.append(",{\"match\":"); + requestBody.append(new GsonBuilder().create().toJson(filterForQuery)); + requestBody.append("}"); + } + requestBody.append("]}}}}]}},\"aggs\":{\"qid\":{\"terms\":{\"field\":\"qid.keyword\",\"size\":"); + requestBody.append(ES_PAGE_SIZE); + requestBody.append("}}}}"); + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getAssetsAffectedCount from ES", e); + } + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray outerBuckets = aggsJson.getAsJsonObject("qid").getAsJsonArray(BUCKETS); + if (outerBuckets.size() > 0) { + for (int i = 0; i < outerBuckets.size(); i++) { + assetsAffectedCount.put( + String.valueOf(outerBuckets.get(i).getAsJsonObject().get("key").getAsLong()), + outerBuckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); + } + } + } + return assetsAffectedCount; + } + + /** + * Gets the vulnerabily across app and env. + * + * @param assetGroup + * the asset group + * @param filter + * the filter + * @param application + * the application + * @param parentType + * the parent type + * @param severity + * the severity + * @return the vulnerabily across app and env + * @throws Exception + * the exception + */ + public List> getVulnerabilyAcrossAppAndEnv(String assetGroup, String filter, String application, + String parentType, String severity) throws Exception { + + List> vulnApplications = new ArrayList<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(parentType); + urlToQuery.append("/").append(SEARCH); + + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}"); + if (StringUtils.isNotEmpty(application)) { + requestBody.append(",{\"match\":{\"tags.Application.keyword\":\""); + requestBody.append(application); + requestBody.append("\"}}"); + } + requestBody.append("]}},\"aggs\":{\"apps\":{\"terms\":{\"field\":\""); + requestBody.append(filter); + requestBody.append( + "\",\"size\":10000},\"aggs\":{\"vulns\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\""); + if (StringUtils.isNotEmpty(severity)) { + requestBody.append("S").append(severity); + requestBody.append("\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"term\":{\"severitylevel.keyword\":") + .append(severity).append("}}]}}"); + } else { + requestBody.append( + "S3\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel.keyword\":3}},{\"match\":{\"latest\":true}}]}},\"S4\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel.keyword\":4}},{\"match\":{\"latest\":true}}]}},\"S5\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel.keyword\":5}},{\"match\":{\"latest\":true}}]}}"); + } + requestBody.append("}}}}}}}}}"); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilyAcrossAppAndEnv from ES", e); + throw e; + } + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray outerBuckets = aggsJson.getAsJsonObject("apps").getAsJsonArray(BUCKETS); + if (outerBuckets.size() > 0) { + for (int i = 0; i < outerBuckets.size(); i++) { + String appName = outerBuckets.get(i).getAsJsonObject().get("key").getAsString(); + List> severityInfo = getSeverityInfo(outerBuckets.get(i).getAsJsonObject() + .getAsJsonObject(VULN).getAsJsonObject("NAME").getAsJsonObject(BUCKETS), severity); + Map applicationInfo = new HashMap<>(); + if (filter.equals(TAGS_APPS)) { + applicationInfo.put(APPS, appName); + } else { + applicationInfo.put("environment", appName); + } + applicationInfo.put("severityinfo", severityInfo); + if (StringUtils.isEmpty(severity)) { + applicationInfo.put(VULNEREBILITIES, + Integer.valueOf(severityInfo.get(0).get(COUNT).toString()) + + Integer.valueOf(severityInfo.get(1).get(COUNT).toString()) + + Integer.valueOf(severityInfo.get(2).get(COUNT).toString())); + } else { + applicationInfo.put(VULNEREBILITIES, Integer.valueOf(severityInfo.get(0).get(COUNT).toString())); + } + vulnApplications.add(applicationInfo); + } + } + return vulnApplications; + } + + /** + * Gets the vulnerability trend. + * + * @param assetGroup + * the asset group + * @param filter + * the filter + * @param from + * the from + * @param to + * the to + * @return the vulnerability trend + * @throws Exception + * the exception + */ + public List> getVulnerabilityTrend(String assetGroup, Map filter, Date from, + Date to) throws Exception { + List> vulnTrendList = new ArrayList<>(); + try { + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/assetgroup_stats/count_vuln/_search"); + StringBuilder request = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"ag.keyword\":" + "\"" + assetGroup + + "\"}}"); + + if (filter != null) { + Set filterkeys = filter.keySet(); + if (filterkeys.contains(TAGS_APPS)) { + request.append( + ",{ \"match\": {\"tags.Application.keyword\": " + "\"" + filter.get(TAGS_APPS) + "\"}}"); + } + if (filterkeys.contains("tags.Environment.keyword")) { + request.append(",{ \"match\": {\"tags.Environment.keyword\": " + "\"" + + filter.get("tags.Environment.keyword") + "\"}}"); + } + } + String gte = null; + String lte = null; + + if (from != null) { + gte = "\"gte\": \"" + new SimpleDateFormat("yyyy-MM-dd").format(from) + "\""; + } + if (to != null) { + lte = "\"lte\": \"" + new SimpleDateFormat("yyyy-MM-dd").format(to) + "\""; + } + + if (gte != null && lte != null) { + request.append(",{ \"range\": {\"date\": {" + gte + "," + lte + "}}}"); + } else if (gte != null) { + request.append(",{ \"range\": {\"date\": {" + gte + "}}}"); + } else { + request.append(",{ \"range\": {\"date\": {" + lte + "}}}"); + } + + request.append( + "]}},\"aggs\": {\"date\": {\"date_histogram\": {\"field\": \"date\",\"interval\": \"day\",\"format\": \"yyyy-MM-dd\"},\"aggs\": {\"vulns\": {\"sum\": {\"field\": \"count\"}}}}}}"); + + String responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), request.toString()); + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonArray buckets = resultJson.get(AGGREGATIONS).getAsJsonObject().get("date").getAsJsonObject() + .get(BUCKETS).getAsJsonArray(); + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + Map trend = new HashMap<>(); + JsonObject bucket = (JsonObject) buckets.get(i); + String date = bucket.get("key_as_string").getAsString(); + Long count = bucket.get(VULN).getAsJsonObject().get(VALUE).getAsLong(); + trend.put("date", date); + trend.put(COUNT, count); + vulnTrendList.add(trend); + } + } + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilityTrend from ES", e); + throw e; + } + + return vulnTrendList; + } + + /** + * Gets the vulnerabilities distribution. + * + * @param assetGroup + * the asset group + * @param parentType + * the parent type + * @return the vulnerabilities distribution + * @throws Exception + * the exception + */ + public List> getVulnerabilitiesDistribution(String assetGroup, String parentType) + throws Exception { + List> vulnDistributions = new ArrayList<>(); + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(parentType).append("/_search"); + String requestBody = "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}]}},\"aggs\":{\"apps\":{\"terms\":{\"field\":\"tags.Application.keyword\",\"size\":1000}," + + "\"aggs\":{\"envs\":{\"terms\":{\"field\":\"tags.Environment.keyword\",\"size\":1000},\"aggs\":{\"vulns\":{\"children\":{\"type\":\"vulninfo\"}," + + "\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\"S3\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel.keyword\":3}},{\"match\":{\"latest\":true}}]}},\"S4\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel.keyword\":4}},{\"match\":{\"latest\":true}}]}},\"S5\":{\"bool\":{\"must\":[{\"term\":{\"severitylevel.keyword\":5}},{\"match\":{\"latest\":true}}]}}}}}}}}}}}}}"; + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody); + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilitiesDistribution from ES", e); + throw e; + } + + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray outerBuckets = aggsJson.getAsJsonObject("apps").getAsJsonArray(BUCKETS); + if (outerBuckets.size() > 0) { + for (int i = 0; i < outerBuckets.size(); i++) { + Map applist = new HashMap<>(); + String appName = outerBuckets.get(i).getAsJsonObject().get("key").getAsString(); + JsonArray envs = outerBuckets.get(i).getAsJsonObject().getAsJsonObject("envs").getAsJsonArray(BUCKETS); + List> envDetails = new ArrayList<>(); + if (envs.size() > 0) { + for (int j = 0; j < envs.size(); j++) { + String envName = envs.get(j).getAsJsonObject().get("key").getAsString(); + List> severityInfo = getSeverityInfo(envs.get(j).getAsJsonObject() + .getAsJsonObject(VULN).getAsJsonObject("NAME").getAsJsonObject(BUCKETS), null); + Map envSeverity = new HashMap<>(); + envSeverity.put("environment", envName); + envSeverity.put(SEVERITY_INFO, severityInfo); + envSeverity.put(VULNEREBILITIES, + Integer.valueOf(severityInfo.get(0).get(COUNT).toString()) + + Integer.valueOf(severityInfo.get(ONE).get(COUNT).toString()) + + Integer.valueOf(severityInfo.get(TWO).get(COUNT).toString())); + envDetails.add(envSeverity); + } + } + applist.put(APPS, appName); + applist.put("applicationInfo", envDetails); + vulnDistributions.add(applist); + } + } + return vulnDistributions; + } + + /** + * Gets the vulnerabilitysummary by resource id. + * + * @param resourceId + * the resource id + * @return the vulnerabilitysummary by resource id + */ + public Map getVulnerabilitysummaryByResourceId(String resourceId) { + + Map vulnSummary = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl); + urlToQuery.append("/*");// any index + urlToQuery.append("/").append(VULN_INFO); + urlToQuery.append("/").append(SEARCH); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"_resourceid.keyword\":\""); + requestBody.append(resourceId); + requestBody.append( + "\"}},{\"terms\": {\"severitylevel.keyword\": [3,4,5]}}]}},\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\"S3\":{\"term\":{\"severitylevel.keyword\":\"3\"}},\"S4\":{\"term\":{\"severitylevel.keyword\":\"4\"}},\"S5\":{\"term\":{\"severitylevel.keyword\":\"5\"}}}}}}}"); + + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilitysummaryByResourceId from ES", e); + } + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get("hits").toString()); + vulnSummary.put(TOTAL, hitsJson.get(TOTAL).getAsLong()); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + try { + vulnSummary.put(SEVERITY_INFO, + getSeverityInfo(aggsJson.getAsJsonObject("NAME").getAsJsonObject(BUCKETS), null)); + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilitysummaryByResourceId ", e); + } + } + return vulnSummary; + + } + + /** + * Gets the vulnerability details by resource id. + * + * @param resourceId + * the resource id + * @return the vulnerability details by resource id + */ + public List> getVulnerabilityDetailsByResourceId(String resourceId) { + + List> results = new ArrayList<>(); + Long totalDocs = (Long) getVulnerabilitysummaryByResourceId(resourceId).get(TOTAL); + StringBuilder urlToQueryBuffer = new StringBuilder(esUrl); + urlToQueryBuffer.append("/*");// any index + urlToQueryBuffer.append("/").append(VULN_INFO); + urlToQueryBuffer.append("/").append(SEARCH).append(SCROLL).append(ES_PAGE_SCROLL_TTL); + + String urlToQuery = urlToQueryBuffer.toString(); + String urlToScroll = new StringBuilder(esUrl).append("/").append(SEARCH).append(SLASH_SCROLL).toString(); + + StringBuilder requestBody = new StringBuilder( + "{\"size\":10000,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel.keyword\":[3,4,5]}},{\"match\":{\"_resourceid.keyword\":\""); + requestBody.append(resourceId); + requestBody.append("\"}}]}}}"); + String request = requestBody.toString(); + String scrollId = null; + for (int index = 0; index <= (totalDocs / ES_PAGE_SIZE); index++) { + try { + if (!Strings.isNullOrEmpty(scrollId)) { + request = elasticSearchRepository.buildScrollRequest(scrollId, ES_PAGE_SCROLL_TTL); + urlToQuery = urlToScroll; + } + String responseDetails = PacHttpUtils.doHttpPost(urlToQuery, request); + scrollId = elasticSearchRepository.processResponseAndSendTheScrollBack(responseDetails, results); + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilityDetailsByResourceId", e); + } + } + return results; + } + + /** + * Gets the severity info. + * + * @param countBucket + * the count bucket + * @param severity + * the severity + * @return the severity info + */ + private List> getSeverityInfo(JsonObject countBucket, String severity) { + + List> severityInfo = new ArrayList<>(); + if (StringUtils.isEmpty(severity)) { + Map severity3 = new HashMap<>(); + severity3.put(SEVEITY_LEVEL, THREE); + severity3.put(SEVERITY, "S3"); + severity3.put(COUNT, countBucket.getAsJsonObject("S3").get(DOC_COUNT).getAsLong()); + severity3.put(VULN_COUNT, countBucket.getAsJsonObject("S3").get(DOC_COUNT).getAsLong()); + Map severity4 = new HashMap<>(); + severity4.put(SEVEITY_LEVEL, FOUR); + severity4.put(SEVERITY, "S4"); + severity4.put(COUNT, countBucket.getAsJsonObject("S4").get(DOC_COUNT).getAsLong()); + severity4.put(VULN_COUNT, countBucket.getAsJsonObject("S4").get(DOC_COUNT).getAsLong()); + Map severity5 = new HashMap<>(); + severity5.put(SEVEITY_LEVEL, FIVE); + severity5.put(COUNT, countBucket.getAsJsonObject("S5").get(DOC_COUNT).getAsLong()); + severity5.put(SEVERITY, "S5"); + severity5.put(VULN_COUNT, countBucket.getAsJsonObject("S5").get(DOC_COUNT).getAsLong()); + severityInfo.add(severity3); + severityInfo.add(severity4); + severityInfo.add(severity5); + } else { + Map severityMap = new HashMap<>(); + severityMap.put(SEVEITY_LEVEL, Integer.valueOf(severity)); + severityMap.put(COUNT, countBucket.getAsJsonObject("S" + severity).get(DOC_COUNT).getAsLong()); + severityMap.put(SEVERITY, "S" + severity); + severityMap.put(VULN_COUNT, countBucket.getAsJsonObject("S" + severity).get(DOC_COUNT).getAsLong()); + severityInfo.add(severityMap); + } + + return severityInfo; + } + + /** + * Fetch exec director apps. + * + * @return the list + * @throws Exception + * the exception + */ + @SuppressWarnings("deprecation") + public List> fetchExecDirectorApps() throws Exception { + Map mustFilter = new HashMap<>(); + mustFilter.put(Constants.LATEST, Constants.TRUE); + return elasticSearchRepository.getDataFromES("aws_apps", "apps", mustFilter, null, null, + Arrays.asList("appTag", "director", "executiveSponsor"), null); + + } + + /** + * Gets the unique host. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the unique host + */ + public Map getUniqueHost(String assetGroup, String severity) { + + Map uniqueHost = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(SEARCH); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[" + + severity + "]}}]}}}}]}},\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"}," + + "\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[" + + severity + "]}}]}}," + + "\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel.keyword\",\"size\":5}," + + "\"aggs\":{\"unique-host\":{\"cardinality\":{\"field\":\"_resourceid.keyword\",\"precision_threshold\":40000}}}}}}}}}}"); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error(Constants.ERROR_UNIQUEHOST, e); + } + + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get(HITS).toString()); + long total = hitsJson.get(TOTAL).getAsLong(); + uniqueHost.put(TOTAL, total); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter") + .getAsJsonObject(SEVERITY).getAsJsonArray(BUCKETS); + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + uniqueHost.put(buckets.get(i).getAsJsonObject().get("key").getAsString(), buckets.get(i) + .getAsJsonObject().get("unique-host").getAsJsonObject().get(VALUE).getAsLong()); + } + } + } + return uniqueHost; + } + + /** + * Gets the unique vuln. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the unique vuln + */ + public Map getVulnInfo(String assetGroup, String severity) { + + Map vulnInfo = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(SEARCH); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[" + + severity + "]}}]}}}}]}},\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"}," + + "\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[" + + severity + "]}}]}}," + + "\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel.keyword\",\"size\":5}," + + "\"aggs\":{\"unique-qid\":{\"cardinality\":{\"script\":\"doc['qid.keyword'].toString().replace('.0','')\",\"precision_threshold\": 40000}}}}}}}}}}"); + + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error(Constants.ERROR_UNIQUEHOST, e); + } + + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + long total = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter").get(DOC_COUNT).getAsLong(); + vulnInfo.put(TOTAL, total); + JsonArray buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter") + .getAsJsonObject(SEVERITY).getAsJsonArray(BUCKETS); + + Map sevInfo; + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + String sevKey = buckets.get(i).getAsJsonObject().get("key").getAsString(); + sevInfo = new HashMap<>(); + sevInfo.put(SEVERITY, sevKey); + sevInfo.put(UNIQUE_VULN_COUNT, + buckets.get(i).getAsJsonObject().get(UNIQUE_QID).getAsJsonObject().get(VALUE).getAsLong()); + sevInfo.put(VULN_COUNT, buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); + vulnInfo.put(sevKey, sevInfo); + } + } + } + return vulnInfo; + } + + /** + * Gets the unique app. + * + * @param assetGroup + * the asset group + * @return the unique app + */ + public Map getUniqueApp(String assetGroup) { + + Map uniqueApp = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append("_search?filter_path=aggregations"); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"_entity\":true}}]}}," + + "\"aggs\":{\"severity\":{\"filters\":{\"filters\":{" + + "\"S3\":{\"has_child\":{\"type\":\"vulninfo\",\"query\":{ \"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"severitylevel.keyword\":3}}]}}}}," + + "\"S4\":{\"has_child\":{\"type\":\"vulninfo\",\"query\":{ \"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"severitylevel.keyword\":4}}]}}}}," + + "\"S5\":{\"has_child\":{\"type\":\"vulninfo\",\"query\":{ \"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"match\":{\"severitylevel.keyword\":5}}]}}}}}}," + + "\"aggs\":{\"NAME\":{\"cardinality\":{\"field\":\"tags.Application.keyword\",\"precision_threshold\": 40000}}}}}}"); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error(Constants.ERROR_UNIQUEHOST, e); + } + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonObject buckets = aggsJson.getAsJsonObject(SEVERITY).getAsJsonObject(BUCKETS); + for (int i = 3; i <= 5; i++) { + uniqueApp.put(String.valueOf(i), + buckets.get("S" + i).getAsJsonObject().get("NAME").getAsJsonObject().get(VALUE).getAsLong()); + } + } + return uniqueApp; + } + + /** + * Gets the aging summary. + * + * @param assetGroup + * the asset group + * @return the aging summary + */ + public List> getAgingSummary(String assetGroup) { + + List> agingSummary = new ArrayList<>(); + Map avgAgingMap = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(VULN_INFO); + urlToQuery.append("/").append(SEARCH); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel.keyword\":[3,4,5]}}]}}," + + "\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel.keyword\",\"size\":10},\"aggs\":{\"aging\":{\"avg\":{\"field\":\"_vulnage\"}}}}}}"); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getAgingSummary from ES", e); + } + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray buckets = aggsJson.getAsJsonObject(SEVERITY).getAsJsonArray(BUCKETS); + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + avgAgingMap.put(buckets.get(i).getAsJsonObject().get("key").toString(), Math.floor( + buckets.get(i).getAsJsonObject().get(AGING).getAsJsonObject().get(VALUE).getAsDouble())); + } + } + + avgAgingMap.forEach((severity, avg) -> { + Map sevInfo = new HashMap<>(); + sevInfo.put(SEVERITY, "S" + severity); + sevInfo.put("days", avg); + agingSummary.add(sevInfo); + }); + } + return agingSummary; + } + + /** + * Gets the total qualys host count. + * + * @param index + * the index + * @param vulnType + * the vuln type + * @return the total qualys host count + * @throws DataException + * the data exception + */ + public long getTotalQualysHostCount(String index, String vulnType) throws DataException { + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(index).append("/").append(vulnType) + .append("/").append(UNDERSCORE_COUNT); + StringBuilder requestBody = new StringBuilder( + "{\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"qualysinfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}}]}}}}]}}}"); + try { + String responseDetails = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + JsonObject responseObj = (JsonObject) new JsonParser().parse(responseDetails); + return (long) responseObj.get("count").getAsLong(); + } catch (Exception e) { + LOGGER.error("Error in getTotalQualysAssetCount", e); + throw new DataException(e); + } + } + + /** + * Gets the vulnerability by qid. + * + * @param qid + * the qid + * @return the vulnerability by qid + */ + public Map getVulnerabilityByQid(String qid) { + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append("qualys-kb/kb/_search"); + StringBuilder requestBody = new StringBuilder( + "{\"query\":{\"bool\":{\"must\":[{\"term\":{\"latest\":\"true\"}},{\"term\":{\"qid.keyword\":\""); + requestBody.append(qid); + requestBody.append("\"}}]}}}"); + + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilityByQid from ES", e); + } + JsonParser jsonParser = new JsonParser(); + Map vuln = new HashMap<>(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonArray hits = resultJson.get("hits").getAsJsonObject().get("hits").getAsJsonArray(); + if (hits.size() > 0) { + for (int i = 0; i < hits.size(); i++) { + JsonObject obj = (JsonObject) hits.get(i); + JsonObject sourceJson = (JsonObject) obj.get("_source"); + if (sourceJson != null) { + vuln = new Gson().fromJson(sourceJson, new TypeToken>() { + }.getType()); + vuln.remove("latest"); + vuln.remove("_loadDate"); + } + } + } + } + return vuln; + } + + /** + * Gets the unique vuln with parent. + * + * @param assetGroup + * the asset group + * @param severitylevel + * the severitylevel + * @param parentType + * the parent type + * @return the vulnerability by qid + * @throws DataException + * the data exception + */ + public Map getDistributionSummaryByInfraType(String assetGroup, String severitylevel, + String parentType) throws DataException { + + Map infraInfo = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(parentType); + urlToQuery.append("/").append(SEARCH); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}}," + + "{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}}," + + "{\"terms\":{\"severitylevel.keyword\":[%s]}}]}}}}]}},\"aggs\":{\"NAME\":{\"children\":{\"type\":\"vulninfo\"}," + + "\"aggs\":{\"NAME\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}}," + + "\"aggs\":{\"NAME\":{\"cardinality\":{\"script\":\"doc['qid.keyword'].toString().replace('.0','')\",\"precision_threshold\":40000}}}}}}}}"); + String requestJson = String.format(requestBody.toString(), severitylevel, severitylevel); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestJson); + } catch (Exception e) { + LOGGER.error("Error in getDistributionSummaryByInfraType", e); + throw new DataException(e); + } + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get(HITS).toString()); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + long totalVulnerableAssets = hitsJson.get(TOTAL).getAsLong(); + long vulnerabilities = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()) + .get(DOC_COUNT).getAsLong(); + long uniqueVulnCount = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()) + .getAsJsonObject(NAME.toUpperCase()).get(VALUE).getAsLong(); + + infraInfo.put(TOTAL_VULN_ASSETS, totalVulnerableAssets); + infraInfo.put(VULNEREBILITIES, vulnerabilities); + infraInfo.put(UNIQUE_VULN_COUNT, uniqueVulnCount); + } + return infraInfo; + } + + /** + * Gets the prod info by env. + * + * @param assetGroup + * the asset group + * @param severitylevel + * the severitylevel + * @return the prod info by env + */ + public Map getProdInfoByEnv(String assetGroup, String severitylevel) { + + Map prodInfo = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(SEARCH); + + StringBuilder requestbody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},"); + requestbody.append("{\"terms\":{\"severitylevel.keyword\":[%s]}}]}}}}],") + .append("\"should\":[{\"prefix\":{\"tags.Environment.keyword\":\"Production\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"production\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"Prd\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"prd\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"PRD\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"Prod\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"PROD\"}}],") + .append("\"minimum_should_match\":1}},") + .append("\"aggs\":{\"NAME\":{\"children\":{\"type\":\"vulninfo\"},") + .append("\"aggs\":{\"NAME\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}},") + .append("\"aggs\":{\"NAME\":{\"cardinality\":{\"script\":\"doc['qid.keyword'].toString().replace('.0','')\",\"precision_threshold\": 40000}}}}}}}}"); + String requestJson = String.format(requestbody.toString(), severitylevel, severitylevel); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestJson); + } catch (Exception e) { + LOGGER.error("Error in getProdInfoByEnv", e); + } + + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get(HITS).toString()); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + long totalVulnerableAssets = hitsJson.get(TOTAL).getAsLong(); + long vulnerabilities = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()) + .get(DOC_COUNT).getAsLong(); + long uniqueVulnCount = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()) + .getAsJsonObject(NAME.toUpperCase()).get(VALUE).getAsLong(); + + prodInfo.put(TOTAL_VULN_ASSETS, totalVulnerableAssets); + prodInfo.put(VULNEREBILITIES, vulnerabilities); + prodInfo.put(UNIQUE_VULN_COUNT, uniqueVulnCount); + } + + return prodInfo; + + } + + /** + * Gets the non prod info by env. + * + * @param assetGroup + * the asset group + * @param severitylevel + * the severitylevel + * @return the non prod info by env + */ + public Map getNonProdInfoByEnv(String assetGroup, String severitylevel) { + + Map nonProdInfo = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(SEARCH); + + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},"); + requestBody.append( + "{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}}}}],") + .append("\"must_not\":[").append("{\"prefix\":{\"tags.Environment.keyword\":\"Production\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"production\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"Prd\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"prd\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"PRD\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"Prod\"}},") + .append("{\"prefix\":{\"tags.Environment.keyword\":\"PROD\"}}]}},") + .append("\"aggs\":{\"NAME\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"NAME\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}},") + .append("\"aggs\":{\"NAME\":{\"cardinality\":{\"script\":\"doc['qid.keyword'].toString().replace('.0','')\",\"precision_threshold\": 40000}}}}}}}}"); + String requestJson = String.format(requestBody.toString(), severitylevel, severitylevel); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestJson); + } catch (Exception e) { + LOGGER.error("Error in getNonProdInfoByEnv", e); + } + + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get(HITS).toString()); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + long totalVulnerableAssets = hitsJson.get(TOTAL).getAsLong(); + long vulnerabilities = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()) + .get(DOC_COUNT).getAsLong(); + long uniqueVulnCount = aggsJson.getAsJsonObject(NAME.toUpperCase()).getAsJsonObject(NAME.toUpperCase()) + .getAsJsonObject(NAME.toUpperCase()).get(VALUE).getAsLong(); + + nonProdInfo.put(TOTAL_VULN_ASSETS, totalVulnerableAssets); + nonProdInfo.put(VULNEREBILITIES, vulnerabilities); + nonProdInfo.put(UNIQUE_VULN_COUNT, uniqueVulnCount); + } + return nonProdInfo; + + } + + /** + * Gets the distribution summary by vuln type. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the distribution summary by vuln type + * @throws DataException + * the data exception + */ + public List> getDistributionSummaryByVulnType(String assetGroup, String severity) + throws DataException { + + List> distributionList = new ArrayList<>(); + long totalVulnCount = 0; + Map infoOS = new HashMap<>(); + infoOS.put("category", "OS"); + infoOS.put(TOTAL_VULN_ASSETS, 0); + infoOS.put(VULNEREBILITIES, 0); + infoOS.put(UNIQUE_VULN_COUNT, 0); + + Map infoApp = new HashMap<>(); + infoApp.put("category", "Application"); + infoApp.put(TOTAL_VULN_ASSETS, 0); + infoApp.put(VULNEREBILITIES, 0); + infoApp.put(UNIQUE_VULN_COUNT, 0); + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(SEARCH); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},").append( + "{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}}}}]}},") + .append("\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}},") + .append("\"aggs\":{\"classification\":{\"terms\":{\"field\":\"classification.keyword\",\"size\":10},\"aggs\":{\"resources\":{\"cardinality\":{\"field\":\"_resourceid.keyword\",\"precision_threshold\":40000}}}}}}}}}}"); + + String requestJson = String.format(requestBody.toString(), severity, severity); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestJson); + } catch (Exception e) { + LOGGER.error("Error in getVulnerabilitySummaryByClassification from ES", e); + throw new DataException(e); + } + + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter") + .getAsJsonObject("classification").getAsJsonArray(BUCKETS); + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + totalVulnCount += buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong(); + if (buckets.get(i).getAsJsonObject().get("key").toString().replace("\"", "").equals("OS")) { + infoOS.put(TOTAL_VULN_ASSETS, + buckets.get(i).getAsJsonObject().get("resources").getAsJsonObject().get(VALUE).getAsLong()); + infoOS.put(VULNEREBILITIES, buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); + } else { + infoApp.put(TOTAL_VULN_ASSETS, + buckets.get(i).getAsJsonObject().get("resources").getAsJsonObject().get(VALUE).getAsLong()); + infoApp.put(VULNEREBILITIES, buckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); + } + } + } + + requestBody = new StringBuilder("{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},") + .append("{\"has_child\":{\"type\":\"vulninfo\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}}}}]}},") + .append("\"aggs\":{\"vulninfo\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"sev-filter\":{\"filter\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[%s]}}]}},") + .append("\"aggs\":{\"classification\":{\"terms\":{\"field\":\"classification.keyword\",\"size\":10},\"aggs\":{\"unique-qid\":{\"cardinality\":{\"script\":\"doc['qid.keyword'].toString().replace('.0','')\",\"precision_threshold\":40000}}}}}}}}}}"); + + requestJson = String.format(requestBody.toString(), severity, severity); + responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestJson); + } catch (Exception e) { + LOGGER.error(Constants.ERROR_UNIQUEHOST, e); + throw new DataException(e); + } + + resultJson = (JsonObject) jsonParser.parse(responseJson); + aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + buckets = aggsJson.getAsJsonObject(VULN_INFO).getAsJsonObject("sev-filter").getAsJsonObject("classification") + .getAsJsonArray(BUCKETS); + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + if (buckets.get(i).getAsJsonObject().get("key").toString().replace("\"", "").equals("OS")) { + infoOS.put(UNIQUE_VULN_COUNT, + buckets.get(i).getAsJsonObject().get(UNIQUE_QID).getAsJsonObject().get(VALUE).getAsLong()); + } else { + infoApp.put(UNIQUE_VULN_COUNT, + buckets.get(i).getAsJsonObject().get(UNIQUE_QID).getAsJsonObject().get(VALUE).getAsLong()); + } + } + } + + if (totalVulnCount > 0) { + distributionList.add(infoOS); + distributionList.add(infoApp); + } + double contribution = HUNDRED; + for (int i = 0; i < distributionList.size(); i++) { + Map info = distributionList.get(i); + if (totalVulnCount > 0) { + double contributionPercent = Math + .floor((Double.valueOf(info.get(VULNEREBILITIES).toString()) / totalVulnCount) * HUNDRED); + if (i == distributionList.size() - 1) { + info.put("contribution", contribution); + } else { + info.put("contribution", contributionPercent); + contribution = contribution - contributionPercent; + } + } + } + return distributionList; + } + + /** + * Gets the all qid by AG. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the all qid by AG + * @throws DataException + * the data exception + */ + public Map getAllQidByAG(String assetGroup, String severity) throws DataException { + + Map qids = new HashMap<>(); + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(VULN_INFO); + urlToQuery.append("/").append(SEARCH); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":["); + requestBody.append(severity); + requestBody.append( + "]}}]}},\"aggs\":{\"qid\":{\"terms\":{\"script\":\"(doc['qid.keyword'].value+'~').replace('.0','')+doc['title.keyword'].value.toLowerCase()+'~'+doc['classification.keyword'].value\",\"size\":100000}}}}"); + + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getAllQidByAG from ES", e); + throw new DataException(e); + } + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray buckets = aggsJson.getAsJsonObject("qid").getAsJsonArray(BUCKETS); + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + qids.put(buckets.get(i).getAsJsonObject().get("key").toString().replace("\"", ""), + buckets.get(i).getAsJsonObject().get(DOC_COUNT)); + } + } + return qids; + } + + /** + * Gets the apps by severity. + * + * @param assetGroup + * the asset group + * @param parentType + * the parent type + * @param severity + * the severity + * @return the apps by severity + * @throws Exception + * the exception + */ + public Map getAppsBySeverity(String assetGroup, String parentType, String severity) throws Exception { + + Map appDetails = new HashMap<>(); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup); + urlToQuery.append("/").append(parentType); + urlToQuery.append("/").append(SEARCH); + + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}}]}}," + + "\"aggs\":{\"apps\":{\"terms\":{\"field\":\"tags.Application.keyword\",\"size\":10000}," + + "\"aggs\":{\"vulns\":{\"children\":{\"type\":\"vulninfo\"},\"aggs\":{\"NAME\":{\"filters\":{\"filters\":{\"severity\":{\"terms\":{\"severitylevel.keyword\":["); + requestBody.append(severity); + requestBody.append("]}}}}}}}}}}}"); + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getAppsBySeverity from ES", e); + throw e; + } + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray buckets = aggsJson.getAsJsonObject("apps").getAsJsonArray(BUCKETS); + if (buckets.size() > 0) { + for (int i = 0; i < buckets.size(); i++) { + appDetails.put(buckets.get(i).getAsJsonObject().get("key").getAsString(), + buckets.get(i).getAsJsonObject().getAsJsonObject("vulns").getAsJsonObject("NAME") + .getAsJsonObject("buckets").getAsJsonObject("severity").get(DOC_COUNT).getAsLong()); + } + } + return appDetails; + } + + /** + * Creates the trend annotation. + * + * @param request + * the request + * @return true, if successful + * @throws JsonProcessingException + * the json processing exception + */ + public boolean createTrendAnnotation(TrendNote request) throws JsonProcessingException { + + SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat dateformatId = new SimpleDateFormat("yyyyMMdd"); + String assetGroup; + if (StringUtils.isBlank(request.getAg())) { + assetGroup = ""; + } else { + assetGroup = request.getAg(); + } + Date date = request.getDate(); + Map payLoad = new HashMap<>(); + payLoad.put("ag", assetGroup); + payLoad.put("note", request.getNote()); + payLoad.put("date", dateformat.format(date)); + if (StringUtils.isEmpty(assetGroup)) { + payLoad.put(NOTE_ID, dateformatId.format(date)); + } else { + payLoad.put(NOTE_ID, assetGroup + "_" + dateformatId.format(date)); + } + + List> docs = new ArrayList<>(); + docs.add(payLoad); + createIndex("assetgroup_annotations"); + return uploadData("assetgroup_annotations", "annotations", docs, NOTE_ID); + } + + /** + * Creates the index. + * + * @param indexName + * the index name + */ + public void createIndex(String indexName) { + if (!indexExists(indexName)) { + String payLoad = "{\"settings\": { \"index.mapping.ignore_malformed\": true }}"; + invokeAPI("PUT", indexName, payLoad); + } + } + + /** + * Index exists. + * + * @param indexName + * the index name + * @return true, if successful + */ + private boolean indexExists(String indexName) { + Response response = invokeAPI("HEAD", indexName, null); + if (response != null) { + return response.getStatusLine().getStatusCode() == 200 ? true : false; + } + return false; + } + + /** + * Upload data. + * + * @param index + * the index + * @param type + * the type + * @param docs + * the docs + * @param idKey + * the id key + * @return true, if successful + */ + private boolean uploadData(String index, String type, List> docs, String idKey) { + String actionTemplate = "{ \"index\" : { \"_index\" : \"%s\", \"_type\" : \"%s\", \"_id\" : \"%s\"} }%n"; + + LOGGER.info("*********UPLOADING*** " + type); + if (null != docs && !docs.isEmpty()) { + StringBuilder bulkRequest = new StringBuilder(); + int i = 0; + for (Map doc : docs) { + if (doc != null) { + String id = doc.get(idKey).toString(); + StringBuilder docStrBuilder = new StringBuilder(createESDoc(doc)); + + if (docStrBuilder != null) { + bulkRequest.append(String.format(actionTemplate, index, type, id)); + bulkRequest.append(docStrBuilder + "\n"); + } + i++; + if (i % Constants.THOUSAND == 0 || bulkRequest.toString().getBytes().length + / (Constants.THOUSAND_TWENTY_FOUR * Constants.THOUSAND_TWENTY_FOUR) > Constants.FIVE) { + LOGGER.info("Uploaded" + i); + Response resp = invokeAPI("POST", "/_bulk?refresh=true", bulkRequest.toString()); + try { + String responseStr = ""; + if (null != resp) { + responseStr = EntityUtils.toString(resp.getEntity()); + } + if (responseStr.contains("\"errors\":true")) { + Response retryResp = invokeAPI("POST", "/_bulk?refresh=true", bulkRequest.toString()); + String retryResponse = ""; + if (null != retryResp) { + retryResponse = EntityUtils.toString(retryResp.getEntity()); + } + if (retryResponse.contains("\"errors\":true")) { + LOGGER.error(retryResponse); + } + } + } catch (Exception e) { + LOGGER.error("Bulk upload failed", e); + return false; + } + bulkRequest = new StringBuilder(); + } + } + } + if (bulkRequest.length() > 0) { + LOGGER.info("Uploaded" + i); + Response resp = invokeAPI("POST", "/_bulk?refresh=true", bulkRequest.toString()); + try { + String responseStr = ""; + if (null != resp) { + responseStr = EntityUtils.toString(resp.getEntity()); + } + if (responseStr.contains("\"errors\":true")) { + Response retryResp = invokeAPI("POST", "/_bulk?refresh=true", bulkRequest.toString()); + String retryResponse = ""; + if (null != retryResp) { + retryResponse = EntityUtils.toString(retryResp.getEntity()); + } + + if (retryResponse.contains("\"errors\":true")) { + LOGGER.error(retryResponse); + } + } + if (null != resp) { + return resp.getStatusLine().getStatusCode() == 200 ? true : false; + } else { + return false; + } + } catch (Exception e) { + LOGGER.error("Bulk upload failed", e); + return false; + } + } + } + return true; + } + + /** + * Creates the ES doc. + * + * @param doc + * the doc + * @return the string + */ + private String createESDoc(Map doc) { + ObjectMapper objMapper = new ObjectMapper(); + String docJson = "{}"; + try { + docJson = objMapper.writeValueAsString(doc); + } catch (JsonProcessingException e) { + LOGGER.error("Error in createESDoc", e); + } + return docJson; + } + + /** + * Invoke API. + * + * @param method + * the method + * @param endpoint + * the endpoint + * @param payLoad + * the pay load + * @return the response + */ + private Response invokeAPI(String method, String endpoint, String payLoad) { + HttpEntity entity = null; + try { + if (payLoad != null) { + entity = new NStringEntity(payLoad, ContentType.APPLICATION_JSON); + } + return getRestClient().performRequest(method, endpoint, Collections.emptyMap(), entity); + } catch (IOException e) { + LOGGER.error("Error in invokeAPI", e); + } + return null; + } + + /** + * Gets the rest client. + * + * @return the rest client + */ + private RestClient getRestClient() { + if (restClient == null) { + restClient = RestClient.builder(new HttpHost(updateESHost, updateESPort)).build(); + } + return restClient; + } + + /** + * Gets the trend annotations. + * + * @param ag + * the ag + * @param from + * the from + * @return the trend annotations + */ + public List> getTrendAnnotations(String ag, Date from) { + + List> notes = new ArrayList<>(); + SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd"); + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/") + .append("assetgroup_annotations/annotations/_search"); + StringBuilder requestBody = new StringBuilder( + "{\"size\":10000,\"query\":{\"bool\":{\"must\":[{\"range\":{\"date\":{\"gte\":\""); + requestBody.append(dateformat.format(from)); + requestBody.append("\",\"lte\":\""); + requestBody.append(dateformat.format(new Date())); + requestBody.append("\",\"format\":\"yyyy-MM-dd\"}}}"); + requestBody.append(",{\"terms\":{\"ag.keyword\":[\"\",\""); + requestBody.append(ag).append("\"]}}]}}}"); + + String responseJson = ""; + try { + responseJson = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getTrendAnnotations from ES", e); + } + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseJson)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonArray hits = resultJson.get("hits").getAsJsonObject().get("hits").getAsJsonArray(); + Map note; + if (hits.size() > 0) { + for (int i = 0; i < hits.size(); i++) { + JsonObject obj = (JsonObject) hits.get(i); + JsonObject sourceJson = (JsonObject) obj.get("_source"); + if (sourceJson != null) { + note = new Gson().fromJson(sourceJson, new TypeToken>() { + }.getType()); + notes.add(note); + } + } + } + } + return notes; + } + + /** + * Delete trend annotation. + * + * @param noteId + * the note id + * @return true, if successful + */ + public boolean deleteTrendAnnotation(String noteId) { + boolean result = false; + try { + result = invokeAPI("POST", "assetgroup_annotations/annotations/_delete_by_query?refresh&q=_id:" + noteId, + null).getStatusLine().getStatusCode() == 200; + } catch (Exception e) { + LOGGER.error("Error in deleteTrendAnnotation ", e); + } + return result; + } + + /** + * Gets the data from pacman RDS. + * + * @param query + * the query + * @return the data from pacman RDS + */ + public List> getDataFromPacmanRDS(String query) { + return rdsRepository.getDataFromPacman(query); + } + + /** + * Gets the running instances count. + * + * @param index + * the index + * @param vulnType + * the vuln type + * @return the running instances count + * @throws DataException + * the data exception + */ + public long getRunningInstancesCount(String index, String vulnType) throws DataException { + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(index).append("/").append(vulnType) + .append("/").append(UNDERSCORE_COUNT); + StringBuilder requestBody = new StringBuilder( + "{\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}}"); + if (vulnType.equals(EC2)) { + requestBody.append(",{\"match\":{\"statename\":\"running\"}}"); + } + requestBody.append("]}}}"); + + try { + String responseDetails = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + JsonObject responseObj = (JsonObject) new JsonParser().parse(responseDetails); + return responseObj.get("count").getAsLong(); + } catch (Exception e) { + LOGGER.error("Error in getRunningInstancesCount", e); + throw new DataException(e); + } + } + + /** + * Gets the exempted by rule count. + * + * @param index + * the index + * @param vulnType + * the vuln type + * @return the exempted by rule count + * @throws DataException + * the data exception + */ + public long getExemptedByRuleCount(String index, String vulnType) throws DataException { + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(index).append("/") + .append(UNDERSCORE_COUNT); + StringBuilder requestBody = new StringBuilder( + "{\"query\":{\"bool\":{\"must\":[{\"match\":{\"issueStatus.keyword\":\"exempted\"}},{\"match\":{\"ruleId.keyword\":\""); + if (vulnType.equals(EC2)) { + requestBody.append(EC2_QUALYS_RULEID); + }else if(vulnType.equals(VIRTUALMACHINE)) { + requestBody.append(VIRTUALMACHINE_QUALYS_RULEID); + }else { + requestBody.append( + "PacMan_Onprem-asset-scanned-by-qualys-API_version-1_OnpremassetscannedbyqualysAPI_onpremserver"); + } + requestBody.append("\"}}]}}}"); + + try { + String responseDetails = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + JsonObject responseObj = (JsonObject) new JsonParser().parse(responseDetails); + return responseObj.get("count").getAsLong(); + } catch (Exception e) { + LOGGER.error("Error in getExemptedCount", e); + throw new DataException(e); + } + } + + /** + * Gets the unique host by severity. + * + * @param index + * the index + * @param severity + * the severity + * @return the unique host by severity + * @throws DataException + * the data exception + */ + public Map getUniqueHostBySeverity(String index, String severity) throws DataException { + + Map severityInfo = new HashMap<>(); + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(index).append("/vulninfo/_search"); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel.keyword\":["); + requestBody.append(severity); + requestBody.append("]}}]}},\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel.keyword\",\"size\":10}}}}"); + + String responseDetails = ""; + try { + responseDetails = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getUniqueHostBySeverity", e); + throw new DataException(e); + } + + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseDetails)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseDetails); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray outerBuckets = aggsJson.getAsJsonObject("severity").getAsJsonArray(BUCKETS); + if (outerBuckets.size() > 0) { + for (int i = 0; i < outerBuckets.size(); i++) { + severityInfo.put("S" + outerBuckets.get(i).getAsJsonObject().get("key").getAsString(), + outerBuckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); + } + } else { + severityInfo.put("S3",0); + severityInfo.put("S4",0); + severityInfo.put("S5",0); + } + } + return severityInfo; + } + + /** + * Gets the compliant hosts by severity. + * + * @param assetGroup + * the asset group + * @return the compliant hosts by severity + * @throws DataException + * the data exception + */ + public Map getCompliantHostsBySeverity(String assetGroup) throws DataException { + + Map severityInfo = new HashMap<>(); + + List nonCompliantResourceIds = getNonCompliantResourceIds(assetGroup); + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(assetGroup).append("/vulninfo/_search"); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":true}},{\"terms\":{\"severitylevel.keyword\":[3,4,5]}}],\"must_not\":[{\"terms\":{\"_resourceid.keyword\":"); + requestBody.append(nonCompliantResourceIds); + requestBody.append("}}]}},\"aggs\":{\"severity\":{\"terms\":{\"field\":\"severitylevel.keyword\",\"size\":10}}}}"); + + String responseDetails = ""; + try { + responseDetails = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getCompliantHostsBySeverity", e); + throw new DataException(e); + } + + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseDetails)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseDetails); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray outerBuckets = aggsJson.getAsJsonObject("severity").getAsJsonArray(BUCKETS); + if (outerBuckets.size() > 0) { + for (int i = 0; i < outerBuckets.size(); i++) { + severityInfo.put("S" + outerBuckets.get(i).getAsJsonObject().get("key").getAsString(), + outerBuckets.get(i).getAsJsonObject().get(DOC_COUNT).getAsLong()); + } + } else { + severityInfo.put("S3",0); + severityInfo.put("S4",0); + severityInfo.put("S5",0); + } + } + + return severityInfo; + } + + /** + * Gets the non compliant resource ids. + * + * @param index + * the index + * @return the non compliant resource ids + * @throws DataException + * the data exception + */ + public List getNonCompliantResourceIds(String index) throws DataException { + + List resourceIds = new ArrayList<>(); + + StringBuilder urlToQuery = new StringBuilder(esUrl).append("/").append(index).append("/vulninfo/_search"); + StringBuilder requestBody = new StringBuilder( + "{\"size\":0,\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"terms\":{\"severitylevel.keyword\":[5]}}]}}," + + "\"aggs\":{\"resourceid\":{\"terms\":{\"field\":\"_resourceid.keyword\",\"size\":10000}}}}"); + + String responseDetails = ""; + try { + responseDetails = PacHttpUtils.doHttpPost(urlToQuery.toString(), requestBody.toString()); + } catch (Exception e) { + LOGGER.error("Error in getNonCompliantResourceIds", e); + throw new DataException(e); + } + + JsonParser jsonParser = new JsonParser(); + if (StringUtils.isNotEmpty(responseDetails)) { + JsonObject resultJson = (JsonObject) jsonParser.parse(responseDetails); + JsonObject aggsJson = (JsonObject) jsonParser.parse(resultJson.get(AGGREGATIONS).toString()); + JsonArray outerBuckets = aggsJson.getAsJsonObject("resourceid").getAsJsonArray(BUCKETS); + if (outerBuckets.size() > 0) { + for (int i = 0; i < outerBuckets.size(); i++) { + resourceIds.add(outerBuckets.get(i).getAsJsonObject().get("key").toString()); + } + } + } + return resourceIds; + } + + @SuppressWarnings("deprecation") + public List> fetchOrgInfoForApps() throws Exception { + Map mustFilter = new HashMap<>(); + mustFilter.put(Constants.LATEST, Constants.TRUE); + return elasticSearchRepository.getDataFromES("aws_apps", "apps", mustFilter, null, null, + Arrays.asList("appTag", "_orgInfo.mgmntLevel", "_orgInfo.name", "_orgInfo.isOwner"), null); + + } + + public List> getTrendProgress(String assetGroup, String ruleId, LocalDate startDate, + LocalDate endDate, String trendCategory) throws DataException { + Map mustFilter = new HashMap<>(); + mustFilter.put(CommonUtils.convertAttributetoKeyword("ag"), assetGroup); + if ("issuecompliance".equals(trendCategory)) { + mustFilter.put(CommonUtils.convertAttributetoKeyword("ruleId"), ruleId); + } + + Map rangeMap = new HashMap<>(); + rangeMap.put("gte", startDate.format(DateTimeFormatter.ISO_DATE)); + rangeMap.put("lte", endDate.format(DateTimeFormatter.ISO_DATE)); + + Map dateRangeMap = new HashMap<>(); + dateRangeMap.put("date", rangeMap); + + mustFilter.put(RANGE, dateRangeMap); + try { + return elasticSearchRepository.getSortedDataFromES(AG_STATS, trendCategory, mustFilter, null, null, + Arrays.asList("date", "total", "compliant", "noncompliant", "compliance_percent"), null, null); + } catch (Exception e) { + throw new DataException(e); + } + } + + public int vulnerabilityAssetsCount(String assetGroup, String targetType, Map mustFilter, int from, + int size, Map mustTermsFilter) throws Exception { + List> results = new ArrayList<>(); + results = elasticSearchRepository.getSortedDataFromES(assetGroup, targetType, mustFilter, null, null, null, + mustTermsFilter, null); + return results.size(); + } +} \ No newline at end of file diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityTrendGenerator.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityTrendGenerator.java new file mode 100644 index 000000000..0c1ee309b --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityTrendGenerator.java @@ -0,0 +1,598 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :kkumar28 + Modified Date: Oct 20, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.repository; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.entity.ContentType; +import org.apache.http.nio.entity.NStringEntity; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Repository; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.utils.PacHttpUtils; + + +/** + * The Class VulnerabilityTrendGenerator. + */ +@Repository +public class VulnerabilityTrendGenerator implements Constants { + + /** The es host. */ + @Value("${elastic-search.host}") + private String esHost; + + /** The es port. */ + @Value("${elastic-search.port}") + private int esPort; + + /** The es cluster name. */ + @Value("${elastic-search.clusterName}") + private String esClusterName; + + /** The date format. */ + @Value("${formats.date}") + private String dateFormat; + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory + .getLogger(VulnerabilityTrendGenerator.class); + + /** + * Generate trend. + * + * @param ag the ag + * @param severity the severity + * @param fromDate the from date + * @return the list + * @throws Exception the exception + */ + + public List> generateTrend(String ag,String severity, Date fromDate) throws Exception { + //long start = System.currentTimeMillis(); + List> dateList = new ArrayList<>(); + LocalDate from = LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(fromDate)); + + + + String queryBody = "\"query\":{\"bool\":{\"must\":[{\"terms\":{\"severitylevel.keyword\":["+severity+"]}}],\"should\":[{\"range\":{\"_closedate\":{\"gte\":\""+from+"\"}}},{\"match\":{\"_status\":\"open\"}}],\"minimum_should_match\":1}}"; + + + long totalCount = getTotalDocCount(ag,"vulninfo","{"+queryBody+"}"); + //System.out.println("TOtal Count Open New"+totalCount); + if (totalCount > 0) { + + + List issueOpenDates = new ArrayList<>(); + ExecutorService executionService = Executors.newFixedThreadPool(2); + Map newFoundMap = new HashMap<>(); + Map openCountMap = new HashMap<>(); + executionService.execute(()-> { + newFoundMap.putAll(fetchNewlyFoundVulnByDay(ag,severity,from)); + }); + + executionService.execute( () -> { + + // ES needs minimum 2 slices, if records are less , we need to slice + // accordingly + final int scrollSize = totalCount > 10000 ? 10000 + : (int) (totalCount / 2) + 1; + + final int slices = totalCount > scrollSize ? (int) totalCount + / scrollSize + 1 : 2; + + IntStream.range(0, slices) + .parallel() + .forEach(i -> { + List issueOpenDatesList = fetchVulnInfoDateRanges(ag,scrollSize,slices,i,queryBody,from); + synchronized(issueOpenDates){ + issueOpenDates.addAll(issueOpenDatesList); + } + }); + + openCountMap.putAll(issueOpenDates.parallelStream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))); + + }); + + executionService.shutdown(); + while(!executionService.isTerminated()){} + + + + openCountMap.entrySet().forEach(entry->{ + Map dateObj = new HashMap<>(); + String date = entry.getKey(); + Long open = entry.getValue(); + Long newlyFound = newFoundMap.get(date); + + dateObj.put("date",date); + dateObj.put("open",open); + dateObj.put("new",newlyFound==null?0l:newlyFound); + dateList.add(dateObj); + + }); + //System.out.println("Time taken Generate Trend :"+(System.currentTimeMillis()-start)); + return dateList ; + } else { + + throw new DataException(NO_DATA_FOUND); + } + } + + /** + * Fetch newly found vuln by day. + * + * @param ag the ag + * @param severity the severity + * @param from the from + * @return the map + */ + private Map fetchNewlyFoundVulnByDay(String ag,String severity,LocalDate from ){ + + StringBuilder queryBody = new StringBuilder(); + queryBody.append("\"query\":{\"bool\":{\"must\":["). + append("{\"terms\":{\"severitylevel.keyword\":["+severity+"]}}"). + append(",{\"range\":{\"_firstFound\":{\"gte\":\""). + append(from.toString()). + append("\"}}}]}}"); + + String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_search?size=0"; + StringBuilder request = new StringBuilder(); + request.append("{"). + append("\"aggs\":{\"dates\":{\"date_histogram\":{\"field\":\"_firstFound\",\"interval\":\"day\",\"format\":\"yyyy-MM-dd\"}}}"). + append(",").append(queryBody).append("}"); + + Map newFoundMap = new HashMap<>(); + try { + String searchResponse = PacHttpUtils.doHttpPost(searchUrl, request.toString()); + JsonParser parser = new JsonParser(); + JsonObject responeObj = parser.parse(searchResponse).getAsJsonObject(); + JsonArray dateBuckets = responeObj.getAsJsonObject("aggregations").getAsJsonObject("dates").getAsJsonArray("buckets"); + for(JsonElement jsonElement:dateBuckets){ + JsonObject dateObj = jsonElement.getAsJsonObject(); + newFoundMap.put(dateObj.get("key_as_string").getAsString(),dateObj.get("doc_count").getAsLong()); + + } + } catch (Exception e) { + LOGGER.error("error",e); + } + + return newFoundMap; + + } + + /** + * Fetch vuln info date ranges. + * + * @param ag the ag + * @param scrollSize the scroll size + * @param slices the slices + * @param sliceNo the slice no + * @param queryBody the query body + * @param from the from + * @return the list + */ + @SuppressWarnings("unchecked") + private List fetchVulnInfoDateRanges(String ag,int scrollSize,int slices,int sliceNo,String queryBody,LocalDate from){ + //String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + String searchUrl = "/"+ag+"/vulninfo/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + StringBuilder request = new StringBuilder(); + request.append("{\"size\":"). + append(scrollSize). + append(",\"_source\":[\"_firstFound\",\"_closedate\"],"). + append("\"slice\": {\"id\":"). + append(sliceNo).append(",\"max\":").append(slices).append("},"). + append(queryBody).append("}"); + try{ + List> hitsList = scrollAndFetch(searchUrl,request.toString()); + return hitsList.parallelStream().map(obj-> (Map)obj.get("_source")).flatMap( obj-> getDateRange(obj.get("_firstFound"),obj.get("_closedate"),from,DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[Z]['Z']")).stream()).collect(Collectors.toList()); + + }catch(Exception e){ + LOGGER.error("error",e); + } + return new ArrayList<>(); + + } + + + private List> scrollAndFetch(String searchUrl, String requestBody){ + List> hitsList = new ArrayList<>(); + String uri = searchUrl; + String request = requestBody; + String searchResponse ; + JsonParser parser = new JsonParser(); + JsonObject responeObj ; + long total ; + String scrollId ; + JsonArray hits; + //String scrollUri ="http://"+esHost+":"+esPort+"/_search/scroll"; + String scrollUri ="/_search/scroll?filter_path=hits.total,hits.hits._source,_scroll_id"; + String scrollRequest = "{\"scroll\":\"2m\",\"scroll_id\":\"%s\"}"; + try{ + do{ + + //searchResponse = PacHttpUtils.doHttpPost(uri, request); + searchResponse = invokeESCall("GET",uri, request); + parser = new JsonParser(); + responeObj = parser.parse(searchResponse).getAsJsonObject(); + scrollId = responeObj.get("_scroll_id").getAsString(); + total = responeObj.getAsJsonObject("hits").get("total").getAsLong(); + hits = responeObj.getAsJsonObject("hits").getAsJsonArray("hits"); + hitsList.addAll(new Gson().fromJson(hits,new TypeToken>>(){}.getType())); + uri = scrollUri ; + request = String.format(scrollRequest, scrollId); + //System.out.println("SCROLL:"+total+":"+hitsList.size()); + if(hits.size()==0) break; + }while(total>hitsList.size()); + }catch(Exception e){ + //System.out.println(uri); + //System.out.println(request); + LOGGER.error("error",e); + } + + return hitsList; + } + + /** + * Gets the total doc count. + * + * @param ag the ag + * @param type the type + * @param queryBody the query body + * @return the total doc count + * @throws DataException the data exception + */ + private long getTotalDocCount(String ag, String type, String queryBody) throws DataException{ + String countUrl = "http://"+esHost+":"+esPort+"/"+ag+"/"+type+"/_count"; + String countResponse = ""; + try { + countResponse = PacHttpUtils.doHttpPost(countUrl, queryBody); + } catch (Exception e) { + throw new DataException(e); + } + JsonParser jsonParser = new JsonParser(); + JsonObject response = jsonParser.parse(countResponse).getAsJsonObject(); + return Double.valueOf(response.get("count").getAsString()).longValue(); + + } + + /** + * Gets the date range. + * + * @param from the from + * @param to the to + * @param excludeBefore the exclude before + * @param inputFormatter the input formatter + * @return the date range + */ + private List getDateRange(Object from, Object to, LocalDate excludeBefore, DateTimeFormatter inputFormatter){ + LocalDate fromDt; + LocalDate toDt; + List dateRage = new ArrayList<>(); + if(from!=null){ + fromDt = LocalDateTime.parse(from.toString(),inputFormatter).toLocalDate(); + if(to==null){ + toDt = LocalDate.now(); + }else{ + toDt = LocalDateTime.parse(to.toString(),inputFormatter).toLocalDate(); + } + DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + while(fromDt.isBefore(toDt)){ + if(!fromDt.isBefore(excludeBefore)){ + dateRage.add(formatter.format(fromDt)); + } + fromDt = fromDt.plusDays(1); + } + } + return dateRage; + } + + private List getDateRangeWithResourceId(Object from, Object to, LocalDate excludeBefore, DateTimeFormatter inputFormatter,String resourceId){ + LocalDate fromDt; + LocalDate toDt; + List dateRage = new ArrayList<>(); + if(from!=null){ + fromDt = LocalDateTime.parse(from.toString(),inputFormatter).toLocalDate(); + if(to==null){ + toDt = LocalDate.now(); + }else{ + toDt = LocalDateTime.parse(to.toString(),inputFormatter).toLocalDate(); + } + DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + while(fromDt.isBefore(toDt)){ + if(!fromDt.isBefore(excludeBefore)){ + dateRage.add(new DateResInfo(formatter.format(fromDt),resourceId)); + } + fromDt = fromDt.plusDays(1); + } + } + return dateRage; + } + + /** + * Fetch assets date ranges for ec 2. + * + * @param ag the ag + * @param from the from + * @param isAssetsAffected the is assets affected + * @return the list + * @throws DataException the data exception + */ + @SuppressWarnings("unchecked") + public List fetchAssetsDateRangesForEc2(String ag, LocalDate from) throws DataException { + List dates = new ArrayList<>(); + //String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/ec2/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + String searchUrl = "/"+ag+"/ec2/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + StringBuilder request = new StringBuilder(); + request.append("{\"query\":{\"range\": {\"discoverydate.keyword\": {\"gte\":\""+from+"\"}}}}"); + long totalCount = getTotalDocCount(ag,"ec2",request.toString()); + //System.out.println("fetchAssetsDateRangesForEc2 Total Count :"+ totalCount ); + if (totalCount > 0) { + final int scrollSize = totalCount > 10000 ? 10000 + : (int) (totalCount / 2) + 1; + + final int slices = totalCount > scrollSize ? (int) totalCount + / scrollSize + 1 : 2; + + IntStream.range(0, slices).parallel().forEach(i -> { + StringBuilder query = new StringBuilder("{\"size\":").append(scrollSize); + query.append(",\"_source\":[\"firstdiscoveredon\",\"discoverydate\"],"); + query.append("\"slice\": {\"id\":").append(i).append(",\"max\":").append(slices).append("},"); + query.append(request.toString().substring(1, request.length())); + List ec2DatesList = new ArrayList<>(); + try{ + List> hitsList = scrollAndFetch(searchUrl,query.toString()); + ec2DatesList = hitsList.parallelStream().map(obj-> (Map)obj.get("_source")).flatMap( obj-> + getDateRange(obj.get(Constants.FIRST_DISCOVERED_ON),obj.get("discoverydate"), + from,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX")) + .stream()).collect(Collectors.toList()); + }catch(Exception e){ + LOGGER.error("Error in fetchAssetsDateRangesForEc2",e); + } + synchronized(dates){ + dates.addAll(ec2DatesList); + //System.out.println(dates.size()); + } + }); + } + return dates; + } + + /** + * Fetch assets date ranges on prem. + * + * @param ag the ag + * @param from the from + * @param isAssetsAffected the is assets affected + * @return the list + * @throws DataException the data exception + */ + @SuppressWarnings("unchecked") + public List fetchAssetsDateRangesOnPrem(String ag, LocalDate from) throws DataException { + + List dates = new ArrayList<>(); + //String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/onpremserver/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + String searchUrl = "/"+ag+"/onpremserver/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + StringBuilder queryBody = new StringBuilder(); + queryBody.append("\"query\":{\"bool\":{\"must\":[{\"script\":{\"script\":\"") + .append("LocalDate.parse(doc['discoverydate.keyword'].value.substring(0,10)).isAfter(LocalDate.of(").append(from.getYear()+","+from.getMonthValue()+","+from.getDayOfMonth()).append("))") + .append("|| ( !doc['last_discovered.keyword'].empty && LocalDate.parse(doc['last_discovered.keyword'].value.substring(0,10)).isAfter(LocalDate.of(").append(from.getYear()+","+from.getMonthValue()+","+from.getDayOfMonth()).append(")))") + .append("\"}}") + .append("]}}"); + long totalCount = getTotalDocCount(ag,"onpremserver","{"+queryBody.toString()+"}"); + if (totalCount > 0) { + final int scrollSize = totalCount > 10000 ? 10000 + : (int) (totalCount / 2) + 1; + + final int slices = totalCount > scrollSize ? (int) totalCount + / scrollSize + 1 : 2; + + IntStream.range(0, slices) + .parallel().forEach(i -> { + StringBuilder request = new StringBuilder("{\"size\":").append(scrollSize); + request.append(",\"_source\":[\"_resourceid\",\"first_discovered\",\"firstdiscoveredon\",\"discoverydate\",\"last_discovered\"],"); + request.append("\"slice\": {\"id\":").append(i).append(",\"max\":").append(slices).append("},").append(queryBody).append("}"); + + List onpremDatesList = new ArrayList<>(); + try{ + List> hitsList = scrollAndFetch(searchUrl,request.toString()); + List> docs = new ArrayList<>(); + hitsList.parallelStream().forEach(hit -> { + Map doc = (Map)hit.get("_source"); + if(doc.get("first_discovered") != null) { + doc.put(Constants.FIRST_DISCOVERED_ON, doc.get("first_discovered")); + } + //if(doc.get("last_discovered") != null) { + // doc.put("discoverydate", doc.get("last_discovered")); + // } + synchronized(docs){ + docs.add(doc); + } + }); + + onpremDatesList = docs.parallelStream().flatMap(obj-> + getDateRange(obj.get(Constants.FIRST_DISCOVERED_ON).toString().substring(0,19),obj.get("discoverydate").toString().substring(0,19), + from,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + .stream()).collect(Collectors.toList()); + + }catch(Exception e){ + LOGGER.error("Error in fetchAssetsDateRangesOnPrem",e); + } + synchronized(dates){ + dates.addAll(onpremDatesList); + } + }); + } + return dates; + } + + /** + * Fetch assets date ranges on prem. + * + * @param ag the ag + * @param from the from + * @param isAssetsAffected the is assets affected + * @return + * @return the list + * @throws DataException the data exception + */ + public Map fetchAssetsAffected(String ag, LocalDate from,String severity) throws DataException { + String queryBody = "\"query\":{\"bool\":{\"must\":[{\"terms\":{\"severitylevel.keyword\":["+severity+"]}}],\"should\":[{\"range\":{\"_closedate\":{\"gte\":\""+from+"\"}}},{\"match\":{\"_status\":\"open\"}}],\"minimum_should_match\":1}}"; + + long totalCount = getTotalDocCount(ag,"vulninfo","{"+queryBody+"}"); + //System.out.println("Assets Affected Total Count :"+ totalCount ); + List dateResouceCompleteList = new ArrayList<>(); + if (totalCount > 0) { + final int scrollSize = totalCount > 10000 ? 10000 + : (int) (totalCount / 2) + 1; + + final int slices = totalCount > scrollSize ? (int) totalCount + / scrollSize + 1 : 2; + + IntStream.range(0, slices) + .parallel().forEach(i -> { + List datesResourceList = fetchVulnInfoDateRangesPerResource(ag,scrollSize,slices,i,queryBody,from); + synchronized(dateResouceCompleteList){ + dateResouceCompleteList.addAll(datesResourceList); + } + }); + } + Map> dateResoruceMap = dateResouceCompleteList.parallelStream().collect(Collectors.groupingBy( + obj-> obj.getDate(), Collectors.mapping(obj->obj.getResoruceId(), Collectors.toSet()))); + return dateResoruceMap.entrySet().parallelStream().collect(Collectors.toMap(entry->entry.getKey(), entry-> Long.valueOf(""+entry.getValue().size()))); + + } + + + /** + * Fetch vuln info date ranges. + * + * @param ag the ag + * @param scrollSize the scroll size + * @param slices the slices + * @param sliceNo the slice no + * @param queryBody the query body + * @param from the from + * @return the list + */ + @SuppressWarnings("unchecked") + private List fetchVulnInfoDateRangesPerResource(String ag,int scrollSize,int slices,int sliceNo,String queryBody,LocalDate from){ + // String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + String searchUrl = "/"+ag+"/vulninfo/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + StringBuilder request = new StringBuilder(); + request.append("{\"size\":"). + append(scrollSize). + append(",\"_source\":[\"_firstFound\",\"_closedate\",\"_resourceid\"],"). + append("\"slice\": {\"id\":"). + append(sliceNo).append(",\"max\":").append(slices).append("},"). + append(queryBody).append("}"); + try{ + List> hitsList = scrollAndFetch(searchUrl,request.toString()); + return hitsList.parallelStream().map(obj-> (Map)obj.get("_source")).flatMap( obj-> getDateRangeWithResourceId(obj.get("_firstFound"),obj.get("_closedate"),from,DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[Z]['Z']"),obj.get("_resourceid").toString()).stream()).collect(Collectors.toList()); + + }catch(Exception e){ + LOGGER.error("error",e); + } + return new ArrayList<>(); + + } + + private RestClient getRestClient() { + RestClientBuilder builder = RestClient.builder(new HttpHost(esHost, esPort)); + builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { + @Override + public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { + return requestConfigBuilder.setConnectionRequestTimeout(0).setSocketTimeout(60000); + } + }).setMaxRetryTimeoutMillis(60000); + return builder.build(); + } + + private String invokeESCall(String method, String endpoint, String payLoad) { + + HttpEntity entity = null; + try { + if (payLoad != null) { + entity = new NStringEntity(payLoad, ContentType.APPLICATION_JSON); + } + return EntityUtils.toString(getRestClient() + .performRequest(method, endpoint, Collections.emptyMap(), entity).getEntity()); + } catch (IOException e) { + LOGGER.error("Error in invokeESCall ", e); + } + return null; + } +} + +class DateResInfo { + String date; + String resoruceId; + DateResInfo(String date, String resoruceId){ + this.date = date; + this.resoruceId = resoruceId; + } + public String getDate() { + return date; + } + public void setDate(String date) { + this.date = date; + } + public String getResoruceId() { + return resoruceId; + } + public void setResoruceId(String resoruceId) { + this.resoruceId = resoruceId; + } +} \ No newline at end of file diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityTrendGenerator2.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityTrendGenerator2.java new file mode 100644 index 000000000..9a8411ddd --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityTrendGenerator2.java @@ -0,0 +1,613 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Copyright (C) 2017 T Mobile Inc - All Rights Reserve + Purpose: + Author :kkumar28 + Modified Date: Oct 20, 2017 + + **/ +package com.tmobile.pacman.api.vulnerability.repository; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.entity.ContentType; +import org.apache.http.nio.entity.NStringEntity; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Repository; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.utils.PacHttpUtils; + + +/** + * The Class VulnerabilityTrendGenerator. + */ +@Repository +public class VulnerabilityTrendGenerator2 implements Constants { + + /** The es host. */ + @Value("${elastic-search.host}") + private String esHost; + + /** The es port. */ + @Value("${elastic-search.port}") + private int esPort; + + /** The es cluster name. */ + @Value("${elastic-search.clusterName}") + private String esClusterName; + + /** The date format. */ + @Value("${formats.date}") + private String dateFormat; + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory + .getLogger(VulnerabilityTrendGenerator2.class); + + /** + * Generate trend. + * + * @param ag the ag + * @param severity the severity + * @param fromDate the from date + * @return the list + * @throws Exception the exception + */ + + public List> generateTrend(String ag,String severity, Date fromDate) throws Exception { + + List> dateList = new ArrayList<>(); + LocalDate from = LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(fromDate)); + + + + String queryBody = "\"query\":{\"bool\":{\"must\":[{\"terms\":{\"severitylevel.keyword\":["+severity+"]}}],\"should\":[{\"range\":{\"_closedate\":{\"gte\":\""+from+"\"}}},{\"match\":{\"_status\":\"open\"}}],\"minimum_should_match\":1}}"; + + + long totalCount = getTotalDocCount(ag,"vulninfo","{"+queryBody+"}"); + long start = System.currentTimeMillis(); + if (totalCount > 0) { + + + ExecutorService executionService = Executors.newFixedThreadPool(2); + Map newFoundMap = new HashMap<>(); + Map openCountMap = new HashMap<>(); + + + executionService.execute( () -> { + openCountMap.putAll(fetchVulnInfoDateRanges(ag,queryBody,from)); + System.out.println("Time taken fetchVulnInfoDateRanges :"+(System.currentTimeMillis()-start)); + System.out.println("Time taken Date Grouping :"+(System.currentTimeMillis()-start)); + }); + + executionService.execute(()-> { + newFoundMap.putAll(fetchNewlyFoundVulnByDay(ag,severity,from)); + System.out.println("Time taken new Trend :"+(System.currentTimeMillis()-start)); + }); + + executionService.shutdown(); + while(!executionService.isTerminated()){} + + + + openCountMap.entrySet().forEach(entry->{ + Map dateObj = new HashMap<>(); + String date = entry.getKey(); + Long open = entry.getValue(); + Long newlyFound = newFoundMap.get(date); + + dateObj.put("date",date); + dateObj.put("open",open); + dateObj.put("new",newlyFound==null?0l:newlyFound); + dateList.add(dateObj); + + }); + System.out.println("Time taken Generate Trend :"+(System.currentTimeMillis()-start)); + return dateList ; + } else { + + throw new DataException(NO_DATA_FOUND); + } + } + + /** + * Fetch newly found vuln by day. + * + * @param ag the ag + * @param severity the severity + * @param from the from + * @return the map + */ + private Map fetchNewlyFoundVulnByDay(String ag,String severity,LocalDate from ){ + + StringBuilder queryBody = new StringBuilder(); + queryBody.append("\"query\":{\"bool\":{\"must\":["). + append("{\"terms\":{\"severitylevel.keyword\":["+severity+"]}}"). + append(",{\"range\":{\"_firstFound\":{\"gte\":\""). + append(from.toString()). + append("\"}}}]}}"); + + String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_search?size=0"; + StringBuilder request = new StringBuilder(); + request.append("{"). + append("\"aggs\":{\"dates\":{\"date_histogram\":{\"field\":\"_firstFound\",\"interval\":\"day\",\"format\":\"yyyy-MM-dd\"}}}"). + append(",").append(queryBody).append("}"); + + Map newFoundMap = new HashMap<>(); + try { + String searchResponse = PacHttpUtils.doHttpPost(searchUrl, request.toString()); + JsonParser parser = new JsonParser(); + JsonObject responeObj = parser.parse(searchResponse).getAsJsonObject(); + JsonArray dateBuckets = responeObj.getAsJsonObject("aggregations").getAsJsonObject("dates").getAsJsonArray("buckets"); + for(JsonElement jsonElement:dateBuckets){ + JsonObject dateObj = jsonElement.getAsJsonObject(); + newFoundMap.put(dateObj.get("key_as_string").getAsString(),dateObj.get("doc_count").getAsLong()); + + } + } catch (Exception e) { + LOGGER.error("error",e); + } + + return newFoundMap; + + } + + /** + * Fetch vuln info date ranges. + * + * @param ag the ag + * @param scrollSize the scroll size + * @param slices the slices + * @param sliceNo the slice no + * @param queryBody the query body + * @param from the from + * @return the list + */ + private Map fetchVulnInfoDateRanges(String ag,String queryBody,LocalDate fromDate){ + //String searchUrl = "http://"+esHost+":"+esPort+"/"+ag+"/vulninfo/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + + System.out.println("Inside fetchVulnInfoDateRanges "); + long start = System.currentTimeMillis(); + String searchUrl = "/"+ag+"/vulninfo/_search"; + StringBuilder request = new StringBuilder(); + request.append("{\"size\":0,"). + append("\"aggs\": {\"from\": { \"terms\": { \"script\": \"new SimpleDateFormat('yyyy-MM-dd').format(doc['_firstFound'].value)\", \"size\": 10000},\"aggs\":" + + " { \"to\": { \"terms\": {\"script\": \"new SimpleDateFormat('yyyy-MM-dd').format(doc['_closedate'].value)\", \"size\": 10000 } }}}},"). + + append(queryBody).append("}"); + + Map openCountMap = new ConcurrentHashMap<>(); + try{ + + String searchResponse = invokeESCall("GET",searchUrl, request.toString()); + System.out.println("****fetchVulnInfoDateRanges >> Time after ES Query"+ (System.currentTimeMillis()-start)); + JsonParser parser = new JsonParser(); + JsonObject responeObj = parser.parse(searchResponse).getAsJsonObject(); + System.out.println("****fetchVulnInfoDateRanges >> Time took in ES query "+ responeObj.get("took").getAsString()); + JsonArray fromBuckets = responeObj.getAsJsonObject("aggregations").getAsJsonObject("from").getAsJsonArray("buckets"); + Map> fromToMap = new HashMap<>(); + for(JsonElement from : fromBuckets) { + JsonObject fromObj = (JsonObject)from; + String fromDt = fromObj.get("key").getAsString(); + JsonArray toBukets = fromObj.getAsJsonObject("to").getAsJsonArray("buckets"); + Map toList = new HashMap<>(); + fromToMap.put(fromDt,toList); + for(JsonElement to : toBukets) { + JsonObject toObj = (JsonObject)to; + String toDt = toObj.get("key").getAsString(); + long count = toObj.get("doc_count").getAsLong(); + if("1969-12-31".equals(toDt)) { + toDt = null; + } + toList.put(toDt,count); + } + } + + System.out.println("****fetchVulnInfoDateRanges >> Time after Parsing Result"+ (System.currentTimeMillis()-start)); + + fromToMap.forEach((from,v)-> { + v.forEach((to,count)-> { + List ranges = getDateRange(from,to,fromDate,DateTimeFormatter.ofPattern("yyyy-MM-dd")); + ranges.parallelStream().forEach(date -> { + Long currentVal = openCountMap.get(date); + openCountMap.put(date,currentVal==null?count:(currentVal+count)); + } + ); + }); + + }); + + System.out.println("****fetchVulnInfoDateRanges >> Time after Finding date range "+ (System.currentTimeMillis()-start)); + + }catch(Exception e){ + LOGGER.error("error",e); + openCountMap.clear(); + } + + return openCountMap; + + } + + + private List> scrollAndFetch(String searchUrl, String requestBody){ + List> hitsList = new ArrayList<>(); + String uri = searchUrl; + String request = requestBody; + String searchResponse ; + JsonParser parser = new JsonParser(); + JsonObject responeObj ; + long total ; + String scrollId ; + JsonArray hits; + //String scrollUri ="http://"+esHost+":"+esPort+"/_search/scroll"; + String scrollUri ="/_search/scroll?filter_path=hits.total,hits.hits._source,_scroll_id"; + String scrollRequest = "{\"scroll\":\"2m\",\"scroll_id\":\"%s\"}"; + try{ + do{ + + //searchResponse = PacHttpUtils.doHttpPost(uri, request); + searchResponse = invokeESCall("GET",uri, request); + parser = new JsonParser(); + responeObj = parser.parse(searchResponse).getAsJsonObject(); + scrollId = responeObj.get("_scroll_id").getAsString(); + total = responeObj.getAsJsonObject("hits").get("total").getAsLong(); + hits = responeObj.getAsJsonObject("hits").getAsJsonArray("hits"); + hitsList.addAll(new Gson().fromJson(hits,new TypeToken>>(){}.getType())); + uri = scrollUri ; + request = String.format(scrollRequest, scrollId); + //System.out.println("SCROLL:"+total+":"+hitsList.size()); + if(hits.size()==0) break; + }while(total>hitsList.size()); + }catch(Exception e){ + //System.out.println(uri); + //System.out.println(request); + LOGGER.error("error",e); + } + + return hitsList; + } + + /** + * Gets the total doc count. + * + * @param ag the ag + * @param type the type + * @param queryBody the query body + * @return the total doc count + * @throws DataException the data exception + */ + private long getTotalDocCount(String ag, String type, String queryBody) throws DataException{ + String countUrl = "http://"+esHost+":"+esPort+"/"+ag+"/"+type+"/_count"; + String countResponse = ""; + try { + countResponse = PacHttpUtils.doHttpPost(countUrl, queryBody); + } catch (Exception e) { + throw new DataException(e); + } + JsonParser jsonParser = new JsonParser(); + JsonObject response = jsonParser.parse(countResponse).getAsJsonObject(); + return Double.valueOf(response.get("count").getAsString()).longValue(); + + } + + /** + * Gets the date range. + * + * @param from the from + * @param to the to + * @param excludeBefore the exclude before + * @param inputFormatter the input formatter + * @return the date range + */ + private List getDateRange(Object from, Object to, LocalDate excludeBefore, DateTimeFormatter inputFormatter){ + LocalDate fromDt; + LocalDate toDt; + List dateRage = new ArrayList<>(); + if(from!=null){ + fromDt = LocalDate.parse(from.toString(),inputFormatter); + if(fromDt.isBefore(excludeBefore)) { + fromDt = excludeBefore; + } + if(to==null){ + toDt = LocalDate.now(); + }else{ + toDt = LocalDate.parse(to.toString(),inputFormatter); + } + DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + int daysBetween = (int) ChronoUnit.DAYS.between(fromDt, toDt); + + for(int i=0;i fetchAssetsDateRangesForEc2(String ag, LocalDate from) throws DataException { + String searchUrl = "/"+ag+"/ec2/_search?filter_path=aggregations.resources.buckets.key,aggregations.resources.buckets.from.buckets.key,aggregations.resources.buckets.from.buckets.to.buckets.key,took"; + StringBuilder queryBody = new StringBuilder(); + queryBody.append("\"query\":{\"range\": {\"discoverydate.keyword\": {\"gte\":\""+from+"\"}}}"); + long totalCount = getTotalDocCount(ag,"ec2","{"+queryBody.toString()+"}"); + StringBuilder request = new StringBuilder(); + request.append("{\"size\":0,"). + append("\"aggs\": { \"resources\": {\"terms\": {\"field\": \"_resourceid.keyword\", \"size\": 1000000},\"aggs\": { \"from\": {\"terms\": { \"script\": \"doc['firstdiscoveredon.keyword'].value.substring(0,10)\", \"size\": 10000 }, \"aggs\": { \"to\": { \"terms\": { \"script\": \"doc['discoverydate.keyword'].value.substring(0,10)\",\"size\": 10000}} }}} }} ,"). + append(queryBody).append("}"); + + Map dateResourceCountMap = new HashMap<>(); + + if (totalCount > 0) { + + long start = System.currentTimeMillis(); + try{ + String searchResponse = invokeESCall("GET",searchUrl, request.toString()); + System.out.println("****fetchAssetsDateRangesForEc2 >> Time after ES Query"+ (System.currentTimeMillis()-start)); + dateResourceCountMap = findResoucerDistributionByDate(searchResponse,from); + + }catch(Exception e){ + LOGGER.error("error",e); + + } + + } + return dateResourceCountMap; + } + + /** + * Fetch assets date ranges on prem. + * + * @param ag the ag + * @param from the from + * @param isAssetsAffected the is assets affected + * @return the list + * @throws DataException the data exception + */ + @SuppressWarnings("unchecked") + public List fetchAssetsDateRangesOnPrem(String ag, LocalDate from) throws DataException { + + List dates = new ArrayList<>(); + String searchUrl = "/"+ag+"/onpremserver/_search?scroll=2m&filter_path=hits.total,hits.hits._source,_scroll_id"; + StringBuilder queryBody = new StringBuilder(); + queryBody.append("\"query\":{\"bool\":{\"must\":[{\"script\":{\"script\":\"") + .append("LocalDate.parse(doc['discoverydate.keyword'].value.substring(0,10)).isAfter(LocalDate.of(").append(from.getYear()+","+from.getMonthValue()+","+from.getDayOfMonth()).append("))") + .append("|| ( !doc['last_discovered.keyword'].empty && LocalDate.parse(doc['last_discovered.keyword'].value.substring(0,10)).isAfter(LocalDate.of(").append(from.getYear()+","+from.getMonthValue()+","+from.getDayOfMonth()).append(")))") + .append("\"}}") + .append("]}}"); + long totalCount = getTotalDocCount(ag,"onpremserver","{"+queryBody.toString()+"}"); + if (totalCount > 0) { + final int scrollSize = totalCount > 10000 ? 10000 + : (int) (totalCount / 2) + 1; + + final int slices = totalCount > scrollSize ? (int) totalCount + / scrollSize + 1 : 2; + + IntStream.range(0, slices) + .parallel().forEach(i -> { + StringBuilder request = new StringBuilder("{\"size\":").append(scrollSize); + request.append(",\"_source\":[\"_resourceid\",\"first_discovered\",\"firstdiscoveredon\",\"discoverydate\"],"); + request.append("\"slice\": {\"id\":").append(i).append(",\"max\":").append(slices).append("},").append(queryBody).append("}"); + + List onpremDatesList = new ArrayList<>(); + try{ + List> hitsList = scrollAndFetch(searchUrl,request.toString()); + List> docs = new ArrayList<>(); + hitsList.parallelStream().forEach(hit -> { + Map doc = (Map)hit.get("_source"); + if(doc.get("first_discovered") != null) { + doc.put(Constants.FIRST_DISCOVERED_ON, doc.get("first_discovered")); + } + + synchronized(docs){ + docs.add(doc); + } + }); + + onpremDatesList = docs.parallelStream().flatMap(obj-> + getDateRange(obj.get(Constants.FIRST_DISCOVERED_ON).toString().substring(0,10),obj.get("discoverydate").toString().substring(0,10), + from,DateTimeFormatter.ofPattern("yyyy-MM-dd")) + .stream()).collect(Collectors.toList()); + + }catch(Exception e){ + LOGGER.error("Error in fetchAssetsDateRangesOnPrem",e); + } + synchronized(dates){ + dates.addAll(onpremDatesList); + } + }); + } + return dates; + } + + /** + * Fetch assets date ranges on prem. + * + * @param ag the ag + * @param from the from + * @param isAssetsAffected the is assets affected + * @return + * @return the list + * @throws DataException the data exception + */ + public Map fetchAssetsAffected(String ag, LocalDate from,String severity) throws DataException { + String queryBody = "\"query\":{\"bool\":{\"must\":[{\"terms\":{\"severitylevel.keyword\":["+severity+"]}}],\"should\":[{\"range\":{\"_closedate\":{\"gte\":\""+from+"\"}}},{\"match\":{\"_status\":\"open\"}}],\"minimum_should_match\":1}}"; + + long totalCount = getTotalDocCount(ag,"vulninfo","{"+queryBody+"}"); + + if (totalCount > 0) { + return fetchVulnInfoDateRangesPerResource(ag,queryBody,from); + } + return new HashMap<>(); + + } + + + /** + * Fetch vuln info date ranges. + * + * @param ag the ag + * @param scrollSize the scroll size + * @param slices the slices + * @param sliceNo the slice no + * @param queryBody the query body + * @param from the from + * @return the list + */ + private Map fetchVulnInfoDateRangesPerResource(String ag,String queryBody,LocalDate fromDate){ + + String searchUrl = "/"+ag+"/vulninfo/_search?filter_path=aggregations.resources.buckets.key,aggregations.resources.buckets.from.buckets.key,aggregations.resources.buckets.from.buckets.to.buckets.key,took"; + StringBuilder request = new StringBuilder(); + request.append("{\"size\":0,"). + append("\"aggs\": { \"resources\": {\"terms\": {\"field\": \"_resourceid.keyword\", \"size\": 1000000},\"aggs\": { \"from\": {\"terms\": { \"script\": \"new SimpleDateFormat('yyyy-MM-dd').format(doc['_firstFound'].value)\", \"size\": 10000 }, \"aggs\": { \"to\": { \"terms\": { \"script\": \"new SimpleDateFormat('yyyy-MM-dd').format(doc['_closedate'].value)\",\"size\": 10000}} }}} }} ,"). + append(queryBody).append("}"); + + Map dateResourceCountMap = new ConcurrentHashMap<>(); + long start = System.currentTimeMillis(); + try { + String searchResponse = invokeESCall("GET",searchUrl, request.toString()); + System.out.println("****fetchVulnInfoDateRangesPerResource >> Time after ES Query"+ (System.currentTimeMillis()-start)); + dateResourceCountMap = findResoucerDistributionByDate(searchResponse,fromDate); + + System.out.println("****Time after Parsing Result"+ (System.currentTimeMillis()-start)); + }catch(Exception e){ + LOGGER.error("error",e); + + } + return dateResourceCountMap; + + } + /** + * Return the resoruce distribution based on the aggregated results + * + * The response follows the nested aggreation on resources > fromDate > ToDate + * + * @param searchResponse + * @return + */ + private Map findResoucerDistributionByDate(String searchResponse,LocalDate fromDate){ + JsonParser parser = new JsonParser(); + JsonObject responeObj = parser.parse(searchResponse).getAsJsonObject(); + System.out.println("****Time taken for ES Query "+responeObj.get("took").getAsLong()); + JsonArray resourceBuckets = responeObj.getAsJsonObject("aggregations").getAsJsonObject("resources").getAsJsonArray("buckets"); + Map> dateResourceMap = new ConcurrentHashMap<>(); + + for(JsonElement resourceElmnt : resourceBuckets) { + JsonObject resourceObj = (JsonObject)resourceElmnt; + String resource = resourceObj.get("key").getAsString(); + + JsonArray fromBukets = resourceObj.getAsJsonObject("from").getAsJsonArray("buckets"); + + for(JsonElement from : fromBukets) { + JsonObject fromObj = (JsonObject)from; + String fromDt = fromObj.get("key").getAsString(); + + JsonArray toBukets = fromObj.getAsJsonObject("to").getAsJsonArray("buckets"); + for(JsonElement to : toBukets) { + JsonObject toObj = (JsonObject)to; + String toDt = toObj.get("key").getAsString(); + if("1969-12-31".equals(toDt)) { + toDt = null; + } + List ranges = getDateRange(fromDt,toDt,fromDate,DateTimeFormatter.ofPattern("yyyy-MM-dd")); + ranges.parallelStream().forEach(date -> { + Set currentResources = dateResourceMap.get(date); + if(currentResources==null) { + currentResources = new HashSet<>(); + dateResourceMap.put(date, currentResources); + } + + currentResources.add(resource); + + } + ); + + } + + } + } + return dateResourceMap.entrySet().parallelStream().collect(Collectors.toMap(entry->entry.getKey(), entry-> Long.valueOf(""+entry.getValue().size()))); + } + + private RestClient getRestClient() { + RestClientBuilder builder = RestClient.builder(new HttpHost(esHost, esPort)); + builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { + @Override + public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { + return requestConfigBuilder.setConnectionRequestTimeout(0).setSocketTimeout(60000); + } + }).setMaxRetryTimeoutMillis(60000); + return builder.build(); + } + + private String invokeESCall(String method, String endpoint, String payLoad) { + + HttpEntity entity = null; + try { + if (payLoad != null) { + entity = new NStringEntity(payLoad, ContentType.APPLICATION_JSON); + } + return EntityUtils.toString(getRestClient() + .performRequest(method, endpoint, Collections.emptyMap(), entity).getEntity()); + } catch (IOException e) { + LOGGER.error("Error in invokeESCall ", e); + } + return null; + } +} diff --git a/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/service/VulnerabilityService.java b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/service/VulnerabilityService.java new file mode 100644 index 000000000..7b16bc3ac --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/java/com/tmobile/pacman/api/vulnerability/service/VulnerabilityService.java @@ -0,0 +1,2578 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.service; + +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Strings; +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.exception.ServiceException; +import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; +import com.tmobile.pacman.api.commons.utils.CommonUtils; +import com.tmobile.pacman.api.commons.utils.ResponseUtils; +import com.tmobile.pacman.api.vulnerability.client.AssetServiceClient; +import com.tmobile.pacman.api.vulnerability.client.ComplianceServiceClient; +import com.tmobile.pacman.api.vulnerability.domain.AssetApi; +import com.tmobile.pacman.api.vulnerability.domain.AssetApiData; +import com.tmobile.pacman.api.vulnerability.domain.AssetCount; +import com.tmobile.pacman.api.vulnerability.domain.AssetCountByAppEnvDTO; +import com.tmobile.pacman.api.vulnerability.domain.AssetCountDTO; +import com.tmobile.pacman.api.vulnerability.domain.AssetCountData; +import com.tmobile.pacman.api.vulnerability.domain.Request; +import com.tmobile.pacman.api.vulnerability.domain.ResponseData; +import com.tmobile.pacman.api.vulnerability.domain.TrendNote; +import com.tmobile.pacman.api.vulnerability.repository.VulnerabilityRepository; +import com.tmobile.pacman.api.vulnerability.repository.VulnerabilityTrendGenerator; +import com.tmobile.pacman.api.vulnerability.repository.VulnerabilityTrendGenerator2; + +/** + * The Class VulnerabilityService. + */ +@Service +public class VulnerabilityService implements Constants { + + /** The vulnerability repository. */ + @Autowired + private VulnerabilityRepository vulnerabilityRepository; + + /** The vuln trend generator. */ + @Autowired + VulnerabilityTrendGenerator2 vulnTrendGenerator; + + + + /** The compliance service. */ + // @Autowired + // ComplianceService complianceService; + + /** The vuln types. */ + @Value("${vulnerability.types}") + private String vulnTypes; + + /** The vuln summary severity. */ + @Value("${vulnerability.summary.severity}") + private String vulnSummarySeverity; + + /** The vuln application occurrence fields. */ + @Value("${vulnerability.application.occurance}") + private String vulnOccurrenceFields; + + /** The vuln resource Id fields. */ + @Value("${vulnerability.application.resourcedetails}") + private String vulnResourceIdFields; + + /** The vuln resource Id fields for both Ec2 and onprem. */ + @Value("${vulnerability.application.resourcedetailsboth}") + private String vulnResourceIdFieldsBoth; + + /** The asset service client. */ + @Autowired + private AssetServiceClient assetServiceClient; + @Autowired + private ComplianceServiceClient complianceServiceClient; + + /** The es repository. */ + @Autowired + ElasticSearchRepository esRepository; + + /** The Constant logger. */ + private static final Log logger = LogFactory.getLog(VulnerabilityService.class); + + /** + * Gets the vulnerabilities details. + * + * @param assetGroup + * the asset group + * @param filter + * the filter + * @return the vulnerabilities details + * @throws Exception + * the exception + */ + public List> getVulnerabilitiesDetails(String assetGroup, Map filter) + throws Exception { + List> vulnerabilitiesDetails = new ArrayList<>(); + try { + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + if (!vulnTargetTypes.isEmpty()) { + for (String parentType : vulnTargetTypes) { + Map vulnAssetsAffected = vulnerabilityRepository.getAssetsAffectedCount(assetGroup, + filter, parentType); + List> vulnerabilitiesData = formVulnerabilitiesData(vulnerabilityRepository + .getAllVulnerabilities(new ArrayList(vulnAssetsAffected.keySet())), + vulnAssetsAffected); + List> vulnerabilitiesDetailsTemp = new ArrayList<>(); + if (vulnerabilitiesDetails.isEmpty()) { + vulnerabilitiesDetails = new ArrayList<>(vulnerabilitiesData); + } else { + for (Map vulnData : vulnerabilitiesData) { + boolean qidMatched = false; + for (Map vulnDetail : vulnerabilitiesDetails) { + if (vulnData.get("qid").equals(vulnDetail.get("qid"))) { + vulnDetail.put(ASSETS_AFFECTED, + Long.valueOf(vulnDetail.get(ASSETS_AFFECTED).toString()) + + Long.valueOf(vulnData.get(ASSETS_AFFECTED).toString())); + qidMatched = true; + break; + } + } + if (!qidMatched) { + vulnerabilitiesDetailsTemp.add(vulnData); + } + } + vulnerabilitiesDetails.addAll(vulnerabilitiesDetailsTemp); + } + } + } + + } catch (Exception e) { + logger.error("Error in getVulnerabilitiesDetails ", e); + throw e; + } + + return vulnerabilitiesDetails; + } + + @SuppressWarnings("unchecked") + public List> getAllVulnerabilitiesDetailsByAssetGroup(String assetGroup, + Map filter,String applicationFilter,String environmentFilter, String searchText, int from, int size) throws Exception { + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + boolean flag = false; + if (vulnTargetTypes.size() > 1) { + flag = true; + } + List> vulnerabilitiesDetails = new ArrayList<>(); + List> vulnerabilitiesDetailsFinal = new ArrayList<>(); + /* Map mustFilter = new HashMap<>(); + Map mustTermsFilter = new HashMap<>(); + mustFilter.put("latest", "true"); + for (Map.Entry entry : filter.entrySet()) { + List severities = Arrays.asList(entry.getValue().split(",")); + mustTermsFilter.put(entry.getKey(), severities); + } + String targetType = "vulninfo"; + List occurrenceFieldList = Arrays.asList(vulnOccurrenceFields.split(","));*/ + List occurrenceFieldList = Arrays.asList(vulnOccurrenceFields.split(",")); + for (String parentType : vulnTargetTypes) { + String targetType = "vulninfo"; + Map mustFilterMap = new LinkedHashMap<>(); + mustFilterMap.put("latest", "true"); + Map parentBool = new HashMap<>(); + List> mustList = new ArrayList<>(); + Map matchMap = new HashMap<>(); + Map match = new HashMap<>(); + Map mustTermsFilter = new HashMap<>(); + for (Map.Entry entry : filter.entrySet()) { + List severities = Arrays.asList(entry.getValue().split(",")); + mustTermsFilter.put(entry.getKey(), severities); + } + // mustFilterMap.putAll(mustTermsFilter); + match.put(Constants.LATEST, Constants.TRUE); + matchMap.put(Constants.MATCH, match); + mustList.add(matchMap); + + if (applicationFilter != null) { + Map applicationFilterMap = new HashMap(); + Map applicationFilterMap1 = new HashMap(); + applicationFilterMap.put("tags.Application.keyword", applicationFilter); + applicationFilterMap1.put("match", applicationFilterMap); + mustList.add(applicationFilterMap1); + } + + if (environmentFilter != null) { + Map environmentFilterMap = new HashMap(); + Map environmentFilterMap1 = new HashMap(); + environmentFilterMap.put("tags.Environment.keyword", environmentFilter); + environmentFilterMap1.put("match", environmentFilterMap); + mustList.add(environmentFilterMap1); + } + + parentBool.put("must", mustList); + Map queryMap = new HashMap<>(); + queryMap.put("bool", parentBool); + Map parentEntryMap = new LinkedHashMap<>(); + parentEntryMap.put("parent_type", parentType); + parentEntryMap.put("query", queryMap); + mustFilterMap.put("has_parent", parentEntryMap); + + try { + + vulnerabilitiesDetails = vulnerabilityRepository.getAllVulnerabilitiesByAssetGroup(assetGroup, targetType, mustFilterMap,occurrenceFieldList, from, size, + mustTermsFilter); + vulnerabilitiesDetailsFinal.addAll(vulnerabilitiesDetails); + } catch (Exception e) { + logger.error("Error in getAllVulnerabilitiesDetailsByAssetGroup ", e); + throw e; + } + } + List listDistinctResourceId = getResourceId(vulnerabilitiesDetailsFinal); + List> resourceIdDetails = getResourcedetailsByResourceId(assetGroup, listDistinctResourceId, + flag); + + List> cartesianResultList = getCartesianProduct(vulnerabilitiesDetailsFinal, resourceIdDetails); + cartesianResultList = (List>) filterMatchingCollectionElements(cartesianResultList, + searchText, true); + for (Map map : cartesianResultList) { + List underscoreKeys = new ArrayList(); + for (Map.Entry entry : map.entrySet()) { + if (entry.getKey().startsWith("_")) { + underscoreKeys.add(entry.getKey()); + } + } + underscoreKeys.forEach(underscoreElement -> { + String underscoreRemovedKey = underscoreElement.substring(1, underscoreElement.length()); + map.put(underscoreRemovedKey, map.get(underscoreElement)); + map.remove(underscoreElement); + }); + } + + return cartesianResultList; + } + + public List> getResourcedetailsByResourceId(String assetGroup, + List listDistinctResourceId, boolean flag) throws Exception { + List> resourceDetails = new ArrayList<>(); + Map mustFilter = new HashMap<>(); + Map mustTermFilter = new HashMap<>(); + mustFilter.put("_entity", "true"); + // mustFilter.put("latest", "true"); + List resourceFieldList = Arrays.asList(vulnResourceIdFields.split(",")); + List resourceFieldListBoth = Arrays.asList(vulnResourceIdFieldsBoth.split(",")); + Map queryMap2 = new HashMap<>(); + Map queryMap1 = new HashMap<>(); + Map mustFilterAddition = new HashMap<>(); + queryMap1.put("latest", "true"); + queryMap2.put("match", queryMap1); + mustFilterAddition.put("type", "vulninfo"); + mustFilterAddition.put("query", queryMap2); + mustFilter.put("has_child", mustFilterAddition); + if (listDistinctResourceId != null && listDistinctResourceId.size() <= 1024) { + mustTermFilter.put("_resourceid.keyword", listDistinctResourceId); + } else { + mustTermFilter = null; + } + + try { + + if (flag == true) { + + resourceDetails = vulnerabilityRepository.getDetailsByResourceId(assetGroup, mustFilter, + resourceFieldListBoth, mustTermFilter); + } else { + resourceDetails = vulnerabilityRepository.getDetailsByResourceId(assetGroup, mustFilter, + resourceFieldList, mustTermFilter); + + } + + + } catch (Exception e) { + logger.error("Error in getResourcedetailsByResourceId ", e); + throw e; + } + + return resourceDetails; + } + + /** + * Gets the vulnerability summary. + * + * @param assetGroup + * the asset group + * @param reqSeverity + * the req severity + * @return the vulnerability summary + * @throws ServiceException + * the service exception + */ + @SuppressWarnings({ "unchecked" }) + public Map getVulnerabilitySummary(String assetGroup, String reqSeverity) throws ServiceException { + + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + + Map vulnerabilitySummary = new HashMap<>(); + List> severityInfo = new ArrayList<>(); + if (vulnTargetTypes.isEmpty()) { + for (int i = 3; i <= 5; i++) { + Map sevInfo = new HashMap<>(); + sevInfo.put(SEVERITY, "S" + i); + sevInfo.put(SEVEITY_LEVEL, i); + sevInfo.put(COUNT, 0); + sevInfo.put("appCount", 0); + sevInfo.put("hostCount", 0); + sevInfo.put(UNIQUE_VULN_COUNT, 0); + sevInfo.put(VULN_COUNT, 0); + severityInfo.add(sevInfo); + } + vulnerabilitySummary.put(SEV_INFO, severityInfo); + vulnerabilitySummary.put(VULNEREBILITIES, 0); + vulnerabilitySummary.put("hosts", 0); + vulnerabilitySummary.put(TOTAL_VULN_ASSETS, 0); + vulnerabilitySummary.put("compliantpercent", 100); + vulnerabilitySummary.put("assetsWithVulns", 0); + return vulnerabilitySummary; + + } else { + + Map> queryResults = new HashMap<>(); + + long totalQualysCount = 0; + long vulnerableAssetCount = 0; + long totalAssetCount = 0; + + ExecutorService executor = Executors.newFixedThreadPool(3); + executor.execute(() -> { + queryResults.put("uniqueHost", vulnerabilityRepository.getUniqueHost(assetGroup, reqSeverity)); + }); + executor.execute(() -> { + queryResults.put("VulnInfo", vulnerabilityRepository.getVulnInfo(assetGroup, reqSeverity)); + + }); + executor.execute(() -> { + queryResults.put("uniqueApp", vulnerabilityRepository.getUniqueApp(assetGroup)); + }); + executor.shutdown(); + while (!executor.isTerminated()) { + } + + Map uniqueHost = queryResults.get("uniqueHost"); + Map vulnInfo = queryResults.get("VulnInfo"); + Map uniqueApp = queryResults.get("uniqueApp"); + + List sevList = Arrays.asList(reqSeverity.split(",")); + List summarySevList = Arrays.asList(vulnSummarySeverity.split(",")); + Map sevVulnInfo; + Map vulnInfoMap; + + List> sevVulnfoList = new ArrayList<>(); + vulnerabilitySummary.put(SEV_INFO, sevVulnfoList); + + for (String sev : sevList) { + sevVulnInfo = new HashMap<>(); + sevVulnInfo.put(SEVEITY_LEVEL, Integer.valueOf(sev)); + sevVulnInfo.put(SEVERITY, "S" + sev); + sevVulnInfo.put("hostCount", uniqueHost.get(sev) == null ? 0 : uniqueHost.get(sev)); + if (summarySevList.contains(sev)) { + vulnerableAssetCount += Long.valueOf(sevVulnInfo.get("hostCount").toString()); + } + vulnInfoMap = (Map) vulnInfo.get(sev); + if (vulnInfoMap != null) { + sevVulnInfo.put(COUNT, vulnInfoMap.get(VULN_COUNT)); + sevVulnInfo.put(VULN_COUNT, vulnInfoMap.get(VULN_COUNT)); + sevVulnInfo.put(UNIQUE_VULN_COUNT, vulnInfoMap.get(UNIQUE_VULN_COUNT)); + } else { + sevVulnInfo.put(COUNT, 0); + sevVulnInfo.put(VULN_COUNT, 0); + sevVulnInfo.put(UNIQUE_VULN_COUNT, 0); + } + sevVulnInfo.put("appCount", uniqueApp.get(sev) == null ? 0 : uniqueApp.get(sev)); + sevVulnfoList.add(sevVulnInfo); + } + vulnerabilitySummary.put(UNIQUE_VULN_COUNT, sevVulnfoList.stream() + .mapToLong(sevData -> Long.valueOf(sevData.get(UNIQUE_VULN_COUNT).toString())).sum()); + vulnerabilitySummary.put("assetsWithVulns", uniqueHost.get(TOTAL) == null ? 0 : uniqueHost.get(TOTAL)); + vulnerabilitySummary.put(VULNEREBILITIES, vulnInfo.get(TOTAL) == null ? 0 : vulnInfo.get(TOTAL)); + + if (sevList.stream().filter(summarySevList::contains).count() != summarySevList.size()) { + vulnerableAssetCount = Long.valueOf( + vulnerabilityRepository.getUniqueHost(assetGroup, vulnSummarySeverity).get(TOTAL).toString()); + } + + for (String vulnType : vulnTargetTypes) { + try { + if (vulnType.equals(ONPREMSERVER)) { + + AssetCount totalAssets = assetServiceClient.getTotalAssetsCount(assetGroup, vulnType, null); + AssetCountData data = totalAssets.getData(); + AssetCountByAppEnvDTO[] assetcount = data.getAssetcount(); + Long totalAssetsCount = 0l; + for (AssetCountByAppEnvDTO assetCount_Count : assetcount) { + if (assetCount_Count.getType().equalsIgnoreCase(vulnType)) { + totalAssetsCount = Long.parseLong(assetCount_Count.getCount()); + } + } + totalAssetCount += totalAssetsCount; + totalQualysCount += vulnerabilityRepository.getTotalQualysHostCount(assetGroup, vulnType); + + } else { + Request request = new Request(); + request.setAg(assetGroup); + Map filter = new HashMap<>(); + filter.put("domain", "Infra & Platforms"); + if (vulnType.equals(EC2)) { + filter.put("ruleId.keyword", EC2_QUALYS_RULEID); + } + + if (vulnType.equals(VIRTUALMACHINE)) { + filter.put("ruleId.keyword", VIRTUALMACHINE_QUALYS_RULEID); + } + + request.setFilter(filter); + // Commenting the old code + // Map response = + // complianceService.getRulecompliance(request).getResponse().get(0); + // new code starts + + List> responses = new ArrayList<>(); + Map response = new HashMap<>(); + ResponseEntity nonCompliancePolicyRuleresponse = complianceServiceClient + .getNonCompliancePolicyByRule(request); + if (nonCompliancePolicyRuleresponse != null) { + Map responseBody = (Map) nonCompliancePolicyRuleresponse + .getBody(); + Map dataResponseMap = (Map) responseBody.get("data"); + responses = (List>) dataResponseMap.get("response"); + if (responses.size() > 0) { + response = responses.get(0); + // new code ends + totalAssetCount += Long.valueOf(response.get("assetsScanned").toString()); + totalQualysCount += Long.valueOf(response.get("passed").toString()); + } + } + } + } + // catch(ServiceException | DataException e){ + catch (DataException e) { + throw new ServiceException(); + } + } + + try { + + vulnerabilitySummary.put("hosts", totalAssetCount); + if (totalQualysCount > totalAssetCount) { + totalQualysCount = totalAssetCount; + } + + long totalVulnerableAssets = totalAssetCount - totalQualysCount + vulnerableAssetCount; + if (totalVulnerableAssets > totalAssetCount) { + totalVulnerableAssets = totalAssetCount; + } + vulnerabilitySummary.put(TOTAL_VULN_ASSETS, totalVulnerableAssets); + + float compliantCount = (float) totalAssetCount - totalVulnerableAssets; + float compliantpercent = 100; + if (totalAssetCount > 0) { + compliantpercent = (compliantCount / totalAssetCount) * 100; + } + DecimalFormat df = new DecimalFormat("#.00"); + vulnerabilitySummary.put("compliantpercent", Math.floor(Float.valueOf(df.format(compliantpercent)))); + vulnerabilitySummary.put("hostsScanned", totalQualysCount); + vulnerabilitySummary.put("hostsNotScanned", totalAssetCount - totalQualysCount); + if (totalAssetCount > 0) { + vulnerabilitySummary.put("hostsScanCoverage", + Math.floor((1.0 * totalQualysCount / totalAssetCount) * 100)); + } else { + vulnerabilitySummary.put("hostsScanCoverage", 0); + } + } catch (Exception e) { + logger.error(e); + throw new ServiceException(e); + } + if (vulnerabilitySummary.isEmpty()) { + throw new ServiceException(NO_DATA_FOUND); + } + return vulnerabilitySummary; + } + + } + + /** + * Gets the vulnerability by app and env. + * + * @param assetGroup + * the asset group + * @param filter + * the filter + * @param application + * the application + * @return the vulnerability by app and env + * @throws Exception + * the exception + */ + public List> getVulnerabilityByAppAndEnv(String assetGroup, String filter, String application) + throws Exception { + + List> vulnApplications = new ArrayList<>(); + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + + if (!vulnTargetTypes.isEmpty()) { + for (String parentType : vulnTargetTypes) { + vulnApplications.addAll(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv(assetGroup, filter, + application, parentType, null)); + } + } + + return vulnApplications; + } + + /** + * Gets the vulnerability trend. + * + * @param assetGroup + * the asset group + * @param filter + * the filter + * @param from + * the from + * @param to + * the to + * @return the vulnerability trend + * @throws Exception + * the exception + */ + public List> getVulnerabilityTrend(String assetGroup, Map filter, Date from, + Date to) throws Exception { + return vulnerabilityRepository.getVulnerabilityTrend(assetGroup, filter, from, to); + } + + /** + * Gets the vulnerability trend. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @param from + * the from + * @return the vulnerability trend with open new count + * @throws Exception + * the exception + */ + public List> getVulnerabilityNewOpenTrend(String assetGroup, String severity, Date from) + throws Exception { + return vulnTrendGenerator.generateTrend(assetGroup, severity, from); + } + + /** + * Gets the vulnerabilities distribution. + * + * @param assetGroup + * the asset group + * @return the vulnerabilities distribution + * @throws Exception + * the exception + */ + public List> getVulnerabilitiesDistribution(String assetGroup) throws Exception { + + List> vulnDistributions = new ArrayList<>(); + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + if (!vulnTargetTypes.isEmpty()) { + for (String parentType : vulnTargetTypes) { + vulnDistributions + .addAll(vulnerabilityRepository.getVulnerabilitiesDistribution(assetGroup, parentType)); + } + } + return vulnDistributions; + } + + /** + * Filter matching collection elements. + * + * @param masterDetailList + * the master detail list + * @param searchText + * the search text + * @param b + * the b + * @return the object + * @throws ServiceException + * the ServiceException + */ + public Object filterMatchingCollectionElements(List> masterDetailList, String searchText, + boolean b) throws ServiceException { + return CommonUtils.filterMatchingCollectionElements(masterDetailList, searchText, true); + } + + /** + * Gets the vulnerabilitysummary by resource id. + * + * @param instanceId + * the instance id + * @return the vulnerabilitysummary by resource id + */ + public Map getVulnerabilitysummaryByResourceId(String instanceId) { + return vulnerabilityRepository.getVulnerabilitysummaryByResourceId(instanceId); + } + + /** + * Gets the vulnerability details by resource id. + * + * @param instanceId + * the instance id + * @return the vulnerability details by resource id + */ + public List> getVulnerabilityDetailsByResourceId(String instanceId) { + + List> vulnerabilitiesDetails = new ArrayList<>(); + try { + List> vulnerabilitiesDetailsList = vulnerabilityRepository + .getVulnerabilityDetailsByResourceId(instanceId); + vulnerabilitiesDetails = formVulnerabilitiesData(vulnerabilitiesDetailsList, new HashMap()); + } catch (Exception e) { + logger.error("Error in getVulnerabilitiesDetails ", e); + throw e; + } + + return vulnerabilitiesDetails; + } + + /** + * Form vulnerabilities data. + * + * @param vulnerabilitiesDetails + * the vulnerabilities details + * @param vulnAssetsAffected + * the vuln assets affected + * @return the list + */ + private List> formVulnerabilitiesData(List> vulnerabilitiesDetails, + Map vulnAssetsAffected) { + + List> vulnerabilitiesDetailsList = new ArrayList<>(); + + vulnerabilitiesDetails.parallelStream().forEach(vulnObject -> { + Map vulnObj = new LinkedHashMap<>(); + vulnObj.put(TITLE, vulnObject.get(TITLE).toString()); + vulnObj.put(SEVERITY, "S" + Double.valueOf(vulnObject.get(SEVEITY_LEVEL).toString()).intValue()); + if (!CollectionUtils.isEmpty(vulnAssetsAffected)) { + vulnObj.put(ASSETS_AFFECTED, vulnAssetsAffected.get(String.valueOf(vulnObject.get("qid").toString()))); + } + vulnObj.put("qid", Double.valueOf(vulnObject.get("qid").toString()).longValue()); + vulnObj.put(CATEGORY, vulnObject.get(CATEGORY).toString()); + vulnObj.put(VULN_TYPE, vulnObject.get(VULN_TYPE).toString()); + if (vulnObject.containsKey(PATCHABLE)) { + vulnObj.put(PATCHABLE, "1".equals(vulnObject.get(PATCHABLE).toString()) ? true : false); + } + vulnObj.put(SEVEITY_LEVEL, Double.valueOf(vulnObject.get(SEVEITY_LEVEL).toString()).intValue()); + synchronized (vulnerabilitiesDetailsList) { + vulnerabilitiesDetailsList.add(vulnObj); + } + }); + + if (!CollectionUtils.isEmpty(vulnAssetsAffected)) { + return vulnerabilitiesDetailsList.stream() + .sorted((h1, + h2) -> (int) (Double.parseDouble(h2.get(ASSETS_AFFECTED).toString()) + - (Double.parseDouble(h1.get(ASSETS_AFFECTED).toString())))) + .sorted((h1, + h2) -> (int) (Double.parseDouble(h2.get(SEVEITY_LEVEL).toString()) + - (Double.parseDouble(h1.get(SEVEITY_LEVEL).toString())))) + .collect(Collectors.toList()); + } else { + return vulnerabilitiesDetailsList.stream() + .sorted((h1, + h2) -> (int) (Double.parseDouble(h2.get(SEVEITY_LEVEL).toString()) + - (Double.parseDouble(h1.get(SEVEITY_LEVEL).toString())))) + .collect(Collectors.toList()); + } + + } + + /** + * Gets the target types. + * + * @param assetGroup + * the asset group + * @return the target types + */ + private String getTargetTypes(String assetGroup) { + String tTypesTemp; + String ttypes = null; + AssetApi assetApi = assetServiceClient.getTargetTypeList(assetGroup, null); + AssetApiData data = assetApi.getData(); + AssetCountDTO[] targetTypes = data.getTargettypes(); + for (AssetCountDTO name : targetTypes) { + if (!Strings.isNullOrEmpty(name.getType())) { + tTypesTemp = new StringBuilder().append('\'').append(name.getType()).append('\'').toString(); + if (Strings.isNullOrEmpty(ttypes)) { + ttypes = tTypesTemp; + } else { + ttypes = new StringBuilder(ttypes).append(",").append(tTypesTemp).toString(); + } + } + } + return ttypes; + } + + /** + * Gets the aging summary. + * + * @param assetGroup + * the asset group + * @return the aging summary + */ + public List> getAgingSummary(String assetGroup) { + return vulnerabilityRepository.getAgingSummary(assetGroup); + } + + /** + * Gets the vulnerability by qid. + * + * @param qid + * the qid + * @return the vulnerability by qid + */ + public List> getVulnerabilityByQid(String qid) { + + List> vulnByCategories = new ArrayList<>(); + Map vulnKbData = vulnerabilityRepository.getVulnerabilityByQid(qid); + vulnByCategories.add(formGeneralCategory(vulnKbData)); + vulnByCategories.add(formDetailsCategory(vulnKbData)); + vulnByCategories.add(formSoftwareCategory(vulnKbData)); + vulnByCategories.add(formImpactCategory(vulnKbData)); + vulnByCategories.add(formThreatCategory(vulnKbData)); + vulnByCategories.add(formSolutionCategory(vulnKbData)); + vulnByCategories.add(formExploitabilityCategory(vulnKbData)); + vulnByCategories.add(formAssociatedMalware(vulnKbData)); + return vulnByCategories; + } + + /** + * Form general category. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + @SuppressWarnings("unchecked") + private Map formGeneralCategory(Map vulnKbData) { + + ObjectMapper oMapper = new ObjectMapper(); + + Map category = new LinkedHashMap<>(); + category.put("name", "General Information"); + Map attributes = new LinkedHashMap<>(); + attributes.put("QID", null == vulnKbData.get("qid") ? "" : vulnKbData.get("qid")); + attributes.put("Title", null == vulnKbData.get(TITLE) ? "" : vulnKbData.get(TITLE)); + attributes.put("Severity Level", null == vulnKbData.get(SEVEITY_LEVEL) ? "" : vulnKbData.get(SEVEITY_LEVEL)); + attributes.put("Vulnerability Type", null == vulnKbData.get(VULN_TYPE) ? "" : vulnKbData.get(VULN_TYPE)); + attributes.put("Category", null == vulnKbData.get(CATEGORY) ? "" : vulnKbData.get(CATEGORY)); + + Map discovery = oMapper.convertValue(vulnKbData.get("discovery"), Map.class); + + if (discovery != null) { + attributes.put("Authentication", fetchAttributes(discovery, "authtypelist", "authtype", true)); + } + + attributes.put("Service Modified", null == vulnKbData.get("lastservicemodificationdatetime") ? "" + : vulnKbData.get("lastservicemodificationdatetime")); + attributes.put("Published", + null == vulnKbData.get("publisheddatetime") ? "" : vulnKbData.get("publisheddatetime")); + + category.put(ATTRIBUTES, attributes); + return category; + } + + /** + * Form details category. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + @SuppressWarnings("unchecked") + private Map formDetailsCategory(Map vulnKbData) { + ObjectMapper oMapper = new ObjectMapper(); + Map category = new HashMap<>(); + category.put("name", "Details"); + Map attributes = new LinkedHashMap<>(); + if (Arrays + .asList(fetchAttributes(vulnKbData, "discovery", "additionalinfo", false).toString().split("\\s*,\\s*")) + .contains("Patch Available")) { + attributes.put("Patch Availble", "Yes"); + } else + attributes.put("Patch Availble", "No"); + + attributes.put("CVE ID", fetchAttributes(vulnKbData, "cvelist", "cve", true)); + attributes.put("Vendor Reference", fetchAttributes(vulnKbData, "vendorreferencelist", "vendorreference", true)); + attributes.put("Bugtraq ID", fetchAttributes(vulnKbData, "bugtraqlist", "bugtraq", true)); + + if (null != vulnKbData.get("pciflag")) { + attributes.put("PCI Flag", Double.valueOf(vulnKbData.get("pciflag").toString()) == 0 ? false : true); + } + + attributes.put("PCI Reasons", fetchAttributes(vulnKbData, "pcireasons", "pcireason", true)); + if (null != vulnKbData.get("supportedmodules")) { + attributes.put("Supported Modules", vulnKbData.get("supportedmodules")); + } + + Map cvss = oMapper.convertValue(vulnKbData.get("cvss"), Map.class); + Map cvss3 = oMapper.convertValue(vulnKbData.get("cvssv3"), Map.class); + if (cvss != null) { + attributes.put("CVSS Base", cvss.get("base")); + attributes.put("CVSS Temporal", cvss.get("temporal")); + attributes.put("CVSS Access Vector", fetchAttributes(cvss, "access", "vector", false)); + } + if (cvss3 != null) { + attributes.put("CVSS3 Base", cvss3.get("base")); + attributes.put("CVSS3 Temporal", cvss3.get("temporal")); + } + + category.put(ATTRIBUTES, attributes); + return category; + } + + /** + * Form software category. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + private Map formSoftwareCategory(Map vulnKbData) { + + Map category = new HashMap<>(); + category.put("name", "Software"); + category.put(ATTRIBUTES, fetchAttributes(vulnKbData, "softwarelist", "software", true)); + return category; + } + + /** + * Form threat category. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + private Map formThreatCategory(Map vulnKbData) { + + Map category = new HashMap<>(); + category.put("name", "Threat"); + category.put(ATTRIBUTES, null == vulnKbData.get("diagnosis") ? "" : vulnKbData.get("diagnosis")); + return category; + } + + /** + * Form impact category. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + private Map formImpactCategory(Map vulnKbData) { + + Map category = new HashMap<>(); + category.put("name", "Impact"); + category.put(ATTRIBUTES, null == vulnKbData.get("consequence") ? "" : vulnKbData.get("consequence")); + return category; + } + + /** + * Form solution category. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + private Map formSolutionCategory(Map vulnKbData) { + + Map category = new HashMap<>(); + category.put("name", "Solution"); + category.put(ATTRIBUTES, null == vulnKbData.get("solution") ? "" : vulnKbData.get("solution")); + return category; + } + + /** + * Form exploitability category. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + @SuppressWarnings("unchecked") + private Map formExploitabilityCategory(Map vulnKbData) { + + ObjectMapper oMapper = new ObjectMapper(); + List> attributes = new ArrayList<>(); + Map category = new HashMap<>(); + category.put("name", "Exploitability"); + + Map correlation = oMapper.convertValue(vulnKbData.get("correlation"), Map.class); + if (correlation != null && !correlation.isEmpty()) { + List> exploits = (List>) fetchAttributes(correlation, "exploits", + "expltsrc", true); + for (Map exploitTemp : exploits) { + Map exploit = new HashMap<>(); + exploit.put(SRC_NAME, exploitTemp.get(SRC_NAME)); + exploit.put("exploits", fetchAttributes(exploitTemp, "expltlist", "explt", true)); + attributes.add(exploit); + } + } + category.put(ATTRIBUTES, attributes); + return category; + } + + /** + * Form associated malware. + * + * @param vulnKbData + * the vuln kb data + * @return the map + */ + @SuppressWarnings("unchecked") + private Map formAssociatedMalware(Map vulnKbData) { + ObjectMapper oMapper = new ObjectMapper(); + List> attributes = new ArrayList<>(); + Map category = new HashMap<>(); + category.put("name", "Malware"); + + Map correlation = oMapper.convertValue(vulnKbData.get("correlation"), Map.class); + if (correlation != null && !correlation.isEmpty()) { + List> exploits = (List>) fetchAttributes(correlation, "malware", + "mwsrc", true); + for (Map exploitTemp : exploits) { + Map exploit = new HashMap<>(); + exploit.put(SRC_NAME, exploitTemp.get(SRC_NAME)); + exploit.put("malwares", fetchAttributes(exploitTemp, "mwlist", "mwinfo", true)); + attributes.add(exploit); + } + } + category.put(ATTRIBUTES, attributes); + return category; + } + + /** + * Fetch attributes. + * + * @param vulnKbData + * the vuln kb data + * @param parent + * the parent + * @param child + * the child + * @param isList + * the is list + * @return the object + */ + @SuppressWarnings("unchecked") + private Object fetchAttributes(Map vulnKbData, String parent, String child, boolean isList) { + Map parentMap = new ObjectMapper().convertValue(vulnKbData.get(parent), Map.class); + Object childObj; + if (parentMap != null) { + childObj = parentMap.get(child); + if (childObj != null) + return childObj; + } + + if (isList) { + return new ArrayList<>(); + } else { + return ""; + } + } + + + /** + * Gets the highest lowest performers. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @param type + * the type + * @return the highest lowest performers + */ + @SuppressWarnings("unchecked") + public Map getHighestLowestPerformers(String assetGroup, String severity, String type) { + + String mngtLevel2 = "2"; + String mngtLevel3 = "3"; + String mngtLevel4 = "4"; + String mngtLevel5 = "5"; + String mngtLevel6 = "6"; + String mngtLevel7 = "7"; + + Map appDetails = new HashMap<>(); + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + + if (StringUtils.isBlank(severity)) { + severity = SEVERITY_LEVELS; + } + Map perfData = new HashMap<>(); + + if ("org".equalsIgnoreCase(type)) { + if (!vulnTargetTypes.isEmpty()) { + for (String parentType : vulnTargetTypes) { + try { + Map appDetailsTemp = vulnerabilityRepository.getAppsBySeverity(assetGroup, + parentType, severity); + if (appDetails.isEmpty()) { + appDetails = new HashMap<>(appDetailsTemp); + } else { + for (Entry appDetailTemp : appDetailsTemp.entrySet()) { + boolean appExists = false; + for (Entry appDetail : appDetails.entrySet()) { + if (appDetail.getKey().equals(appDetailTemp.getKey())) { + appDetails.put(appDetail.getKey(), + appDetail.getValue() + appDetailTemp.getValue()); + appExists = true; + break; + } + } + if (!appExists) { + appDetails.put(appDetailTemp.getKey(), appDetailTemp.getValue()); + } + } + } + } catch (Exception e) { + logger.error("Exception in getHighestLowestPeformers org", e); + } + } + } + try { + Map>> directorsInfo = getDirectorsForAG(appDetails.keySet()); + if (directorsInfo.get(mngtLevel2) != null && directorsInfo.get(mngtLevel2).size() > 1) { + formPerformersData(appDetails, perfData, directorsInfo.get(mngtLevel2)); + } else if (directorsInfo.get(mngtLevel3) != null && directorsInfo.get(mngtLevel3).size() > 1) { + formPerformersData(appDetails, perfData, directorsInfo.get(mngtLevel3)); + } else if (directorsInfo.get(mngtLevel4) != null && directorsInfo.get(mngtLevel4).size() > 1) { + formPerformersData(appDetails, perfData, directorsInfo.get(mngtLevel4)); + } else { + Map> directorLevel5Above = new HashMap<>(); + if (directorsInfo.get(mngtLevel5) != null) { + directorLevel5Above.putAll(directorsInfo.get(mngtLevel5)); + } + if (directorsInfo.get(mngtLevel6) != null) { + directorLevel5Above.putAll(directorsInfo.get(mngtLevel6)); + } + if (directorsInfo.get(mngtLevel7) != null) { + directorLevel5Above.putAll(directorsInfo.get(mngtLevel7)); + } + formPerformersData(appDetails, perfData, directorLevel5Above); + } + } catch (Exception e) { + logger.error("Exception in getHighestLowestPeformers org", e); + } + } else if (APPLICATION.equalsIgnoreCase(type)) { + try { + List> vulnApplications = getVulnerabilityByAppAndEnv(assetGroup, TAGS_APPS, ""); + for (Map appInfo : vulnApplications) { + String app = appInfo.get(APPS).toString(); + List> sevInfo = (List>) appInfo.get(SEV_INFO); + perfData.put(app, getVulnInstanceCount(sevInfo, severity)); + } + } catch (Exception e) { + logger.error("Exception in getHighestLowestPeformers app", e); + } + + } else if (ENVIRONMENT.equalsIgnoreCase(type)) { + + try { + List> vulnEnvmnts = getVulnerabilityByAppAndEnv(assetGroup, TAGS_ENV, ""); + for (Map envInfo : vulnEnvmnts) { + String env = envInfo.get(ENV).toString(); + List> sevInfo = (List>) envInfo.get(SEV_INFO); + perfData.put(env, getVulnInstanceCount(sevInfo, severity)); + } + } catch (Exception e) { + logger.error("Exception in getHighestLowestPeformers env", e); + } + } + return perfData.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors + .toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); + } + + /** + * Gets the vuln instance count. + * + * @param sevInfoList + * the sev info list + * @param severity + * the severity + * @return the vuln instance count + */ + private int getVulnInstanceCount(List> sevInfoList, String severity) { + List sevList = Arrays.asList(severity.split(",")); + return sevInfoList.stream().filter(sevInfo -> sevList.contains(sevInfo.get("severitylevel").toString())) + .mapToInt(sevInfo -> Double.valueOf(sevInfo.get("vulnInstanceCount").toString()).intValue()).sum(); + } + + /** + * Gets the vuln target types. + * + * @param assetGroup + * the asset group + * @return the vuln target types + */ + private List getVulnTargetTypes(String assetGroup) { + + String validTargetTypes = getTargetTypes(assetGroup); + List vulnTargetTypes = new ArrayList<>(); + for (String vulnType : vulnTypes.split(",")) { + if (!StringUtils.isEmpty(validTargetTypes) && validTargetTypes.contains(vulnType.trim())) { + vulnTargetTypes.add(vulnType); + } + } + return vulnTargetTypes; + } + + /** + * Gets the distribution summary by infra type. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the distribution summary by infra type + * @throws ServiceException + * the service exception + */ + public List> getDistributionSummaryByInfraType(String assetGroup, String severity) + throws ServiceException { + + List> distributionList = new ArrayList<>(); + + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + if (StringUtils.isBlank(severity)) { + severity = SEVERITY_LEVELS; + } + long totalVulnCount = 0; + for (String vulnType : vulnTargetTypes) { + Map info = new HashMap<>(); + try { + info = vulnerabilityRepository.getDistributionSummaryByInfraType(assetGroup, severity, vulnType); + } catch (Exception e) { + logger.error("Error in getDistributionSummaryByInfraType ", e); + throw new ServiceException(); + } + + totalVulnCount += Long.valueOf(info.get(VULNEREBILITIES).toString()); + + if (vulnType.equals(ONPREMSERVER)) { + info.put(CATEGORY, "On-Prem"); + distributionList.add(info); + } else { + Optional> cloudInfoOptional = distributionList.stream() + .filter(distro -> distro.get(CATEGORY).equals("Cloud")).findAny(); + if (cloudInfoOptional.isPresent()) { + Map currentCloudInfo = cloudInfoOptional.get(); + currentCloudInfo.put(TOTAL_VULN_ASSETS, + Long.valueOf(currentCloudInfo.get(TOTAL_VULN_ASSETS).toString()) + + Long.valueOf(info.get(TOTAL_VULN_ASSETS).toString())); + currentCloudInfo.put(VULNEREBILITIES, Long.valueOf(currentCloudInfo.get(VULNEREBILITIES).toString()) + + Long.valueOf(info.get(VULNEREBILITIES).toString())); + currentCloudInfo.put(UNIQUE_VULN_COUNT, + Long.valueOf(currentCloudInfo.get(UNIQUE_VULN_COUNT).toString()) + + Long.valueOf(info.get(UNIQUE_VULN_COUNT).toString())); + } else { + info.put(CATEGORY, "Cloud"); + distributionList.add(info); + } + + } + + } + + double contribution = HUNDRED; + for (int i = 0; i < distributionList.size(); i++) { + Map info = distributionList.get(i); + double contributionPercent = Math + .floor((Double.valueOf(info.get(VULNEREBILITIES).toString()) / totalVulnCount) * HUNDRED); + if (i == distributionList.size() - 1) { + info.put(CONTRIBUTION, contribution); + } else { + info.put(CONTRIBUTION, contributionPercent); + contribution = contribution - contributionPercent; + } + } + return distributionList; + } + + /** + * Gets the distribution summary by env. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the distribution summary by env + * @throws ServiceException + * the service exception + */ + public List> getDistributionSummaryByEnv(String assetGroup, String severity) + throws ServiceException { + + List> distributionList = new ArrayList<>(); + if (StringUtils.isBlank(severity)) { + severity = SEVERITY_LEVELS; + } + + long totalVulnCount = 0; + + Map prodInfo = new HashMap<>(); + prodInfo.put(TOTAL_VULN_ASSETS, 0); + prodInfo.put(VULNEREBILITIES, 0); + prodInfo.put(UNIQUE_VULN_COUNT, 0); + + Map nonProdInfo = new HashMap<>(); + nonProdInfo.put(TOTAL_VULN_ASSETS, 0); + nonProdInfo.put(VULNEREBILITIES, 0); + nonProdInfo.put(UNIQUE_VULN_COUNT, 0); + try { + Map prodInfoTemp = vulnerabilityRepository.getProdInfoByEnv(assetGroup, severity); + Map nonProdInfoTemp = vulnerabilityRepository.getNonProdInfoByEnv(assetGroup, severity); + + totalVulnCount += prodInfoTemp.get(VULNEREBILITIES) + nonProdInfoTemp.get(VULNEREBILITIES); + + for (Entry entry : prodInfo.entrySet()) { + prodInfo.put(entry.getKey(), + Long.valueOf(entry.getValue().toString()) + prodInfoTemp.get(entry.getKey())); + } + + for (Entry entry : nonProdInfo.entrySet()) { + nonProdInfo.put(entry.getKey(), + Long.valueOf(entry.getValue().toString()) + nonProdInfoTemp.get(entry.getKey())); + } + } catch (Exception e) { + throw new ServiceException(e); + } + prodInfo.put(CATEGORY, "Prod"); + distributionList.add(prodInfo); + nonProdInfo.put(CATEGORY, "Non-Prod"); + distributionList.add(nonProdInfo); + + double contribution = HUNDRED; + for (int i = 0; i < distributionList.size(); i++) { + Map info = distributionList.get(i); + if (totalVulnCount > 0) { + double contributionPercent = Math + .floor((Double.valueOf(info.get(VULNEREBILITIES).toString()) / totalVulnCount) * HUNDRED); + if (i == distributionList.size() - 1) { + info.put(CONTRIBUTION, contribution); + } else { + info.put(CONTRIBUTION, contributionPercent); + contribution = contribution - contributionPercent; + } + } else { + info.put(CONTRIBUTION, 0); + } + } + return distributionList; + } + + /** + * Gets the distribution summary by vuln type. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the distribution summary by vuln type + * @throws DataException + * the data exception + */ + public List> getDistributionSummaryByVulnType(String assetGroup, String severity) + throws DataException { + if (StringUtils.isBlank(severity)) { + severity = SEVERITY_LEVELS; + } + return vulnerabilityRepository.getDistributionSummaryByVulnType(assetGroup, severity); + } + + /** + * Gets the remediation actions summary. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @return the remediation actions summary + * @throws DataException + * the data exception + */ + public List> getRemediationActionsSummary(String assetGroup, String severity) + throws DataException { + + List> remediationList = new ArrayList<>(); + if (StringUtils.isBlank(severity)) { + severity = SEVERITY_LEVELS; + } + + List> eolActions = vulnerabilityRepository + .getDataFromPacmanRDS("SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " + + "action='Remove/Replace EOL Software'"); + List> stopRemoveActions = vulnerabilityRepository + .getDataFromPacmanRDS("SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " + + "action='Stop Service/Remove Software'"); + List> swConfigChangeActions = vulnerabilityRepository + .getDataFromPacmanRDS("SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " + + "action='Software Configuration Change'"); + List> swUpdateActions = vulnerabilityRepository.getDataFromPacmanRDS( + "SELECT matchingString,subAction FROM cf_RemediationCriteria WHERE " + "action='Software Update'"); + + String softwareConfig = getAllMatchingString(swConfigChangeActions); + String softwareUpdate = getAllMatchingString(swUpdateActions); + + Map osPatching = new HashMap<>(); + osPatching.put(ACTION, "OS Patching"); + osPatching.put(DESCRIPTION, "Apply the patches released by the operating system provider"); + osPatching.put(CONTRIBUTION, 0); + Map eolSoftware = new HashMap<>(); + eolSoftware.put(ACTION, "Remove/Replace EOL Software"); + eolSoftware.put(CONTRIBUTION, 0); + eolSoftware.put(DESCRIPTION, "Remove or replace below listed End of Life Software versions"); + Map noSolution = new HashMap<>(); + noSolution.put(ACTION, "No Solution Available"); + noSolution.put(CONTRIBUTION, 0); + noSolution.put(DESCRIPTION, "Vulnerabilities with no published solution yet"); + Map stopRemove = new HashMap<>(); + stopRemove.put(ACTION, "Stop Service/Remove Software"); + stopRemove.put(CONTRIBUTION, 0); + stopRemove.put(DESCRIPTION, "Stop unimportant vulnerable services, remove malicious softwares from the hosts"); + Map swConfigChange = new HashMap<>(); + swConfigChange.put(ACTION, "Software Configuration Change"); + swConfigChange.put(CONTRIBUTION, 0); + swConfigChange.put(DESCRIPTION, + "Fix the configurations of the below listed softwares. Some default configurations like default admin username and password should be replaced with a stronger one"); + Map swUpdate = new HashMap<>(); + swUpdate.put(ACTION, "Software Update"); + swUpdate.put(CONTRIBUTION, 0); + swUpdate.put(DESCRIPTION, + "Update the below listed softwares to their latest version or apply patches released by the software provider "); + + List> eolSubActions = new ArrayList<>(); + List> stopRemoveSubActions = new ArrayList<>(); + List> swConfigChangeSubActions = new ArrayList<>(); + List> swUpdateSubActions = new ArrayList<>(); + + Map unclassified = new HashMap<>(); + unclassified.put(ACTION, "Unclassified"); + unclassified.put(DESCRIPTION, + "These vulnerabilities are not classified yet. Refer the vulnerability description to fix the vulnerability"); + unclassified.put(CONTRIBUTION, 0); + + Map qids = vulnerabilityRepository.getAllQidByAG(assetGroup, severity); + Long total = qids.entrySet().stream().mapToLong(entry -> Long.valueOf(entry.getValue().toString())).sum(); + for (String qidTitleClass : qids.keySet()) { + String qid = qidTitleClass.split("~")[0]; + String vulnTitle = qidTitleClass.split("~")[1].toLowerCase(); + String classification = qidTitleClass.split("~")[2]; + if ("OS".equalsIgnoreCase(classification)) { + osPatching.put(CONTRIBUTION, Long.valueOf(osPatching.get(CONTRIBUTION).toString()) + + Long.valueOf(qids.get(qidTitleClass).toString())); + } else if (vulnTitle.contains("EOL/Obsolete".toLowerCase())) { + eolSoftware.put(CONTRIBUTION, Long.valueOf(eolSoftware.get(CONTRIBUTION).toString()) + + Long.valueOf(qids.get(qidTitleClass).toString())); + formSubActionList(eolActions, eolSubActions, vulnTitle, + Long.valueOf(qids.get(qidTitleClass).toString())); + } else if ("11925".equals(qid) || "370914".equals(qid)) { + noSolution.put(CONTRIBUTION, Long.valueOf(noSolution.get(CONTRIBUTION).toString()) + + Long.valueOf(qids.get(qidTitleClass).toString())); + } else if (vulnTitle.contains("Java Debug Wire Protocol".toLowerCase())) { + stopRemove.put(CONTRIBUTION, Long.valueOf(stopRemove.get(CONTRIBUTION).toString()) + + Long.valueOf(qids.get(qidTitleClass).toString())); + formSubActionList(stopRemoveActions, stopRemoveSubActions, vulnTitle, + Long.valueOf(qids.get(qidTitleClass).toString())); + } else if (checkVulnTitle(vulnTitle, softwareConfig)) { + swConfigChange.put(CONTRIBUTION, Long.valueOf(swConfigChange.get(CONTRIBUTION).toString()) + + Long.valueOf(qids.get(qidTitleClass).toString())); + formSubActionList(swConfigChangeActions, swConfigChangeSubActions, vulnTitle, + Long.valueOf(qids.get(qidTitleClass).toString())); + } else if (checkVulnTitle(vulnTitle, softwareUpdate)) { + swUpdate.put(CONTRIBUTION, Long.valueOf(swUpdate.get(CONTRIBUTION).toString()) + + Long.valueOf(qids.get(qidTitleClass).toString())); + formSubActionList(swUpdateActions, swUpdateSubActions, vulnTitle, + Long.valueOf(qids.get(qidTitleClass).toString())); + } else { + unclassified.put(CONTRIBUTION, Long.valueOf(unclassified.get(CONTRIBUTION).toString()) + + Long.valueOf(qids.get(qidTitleClass).toString())); + } + } + + calculateContributionPercentage(eolSubActions, Long.valueOf(eolSoftware.get(CONTRIBUTION).toString())); + calculateContributionPercentage(stopRemoveSubActions, Long.valueOf(stopRemove.get(CONTRIBUTION).toString())); + calculateContributionPercentage(swConfigChangeSubActions, + Long.valueOf(swConfigChange.get(CONTRIBUTION).toString())); + calculateContributionPercentage(swUpdateSubActions, Long.valueOf(swUpdate.get(CONTRIBUTION).toString())); + + eolSoftware.put(SUB_ACTIONS, eolSubActions); + stopRemove.put(SUB_ACTIONS, stopRemoveSubActions); + swConfigChange.put(SUB_ACTIONS, swConfigChangeSubActions); + swUpdate.put(SUB_ACTIONS, swUpdateSubActions); + + remediationList.add(osPatching); + remediationList.add(eolSoftware); + remediationList.add(noSolution); + remediationList.add(stopRemove); + remediationList.add(swConfigChange); + remediationList.add(swUpdate); + remediationList.add(unclassified); + + calculateContributionPercentage(remediationList, total); + return remediationList; + } + + /** + * Check vuln title. + * + * @param vulnTitle + * the vuln title + * @param values + * the values + * @return true, if successful + */ + private boolean checkVulnTitle(String vulnTitle, String values) { + for (String value : values.split(",")) { + if (vulnTitle.contains(value)) { + return true; + } + } + return false; + } + + /** + * Form sub action list. + * + * @param actions + * the actions + * @param subActions + * the sub actions + * @param vulnTitle + * the vuln title + * @param contribution + * the contribution + */ + private void formSubActionList(List> actions, List> subActions, + String vulnTitle, long contribution) { + boolean titleMatched = false; + for (Map action : actions) { + if (vulnTitle.contains(action.get(MATCHING_STRING).toString().toLowerCase())) { + titleMatched = true; + formSubAction(subActions, action.get("subAction").toString(), action.get(MATCHING_STRING).toString(), + contribution); + break; + } + } + if (!titleMatched) { + formSubAction(subActions, "Others", "Others", contribution); + } + } + + /** + * Form sub action. + * + * @param subActions + * the sub actions + * @param subActionTitle + * the sub action title + * @param subActiondescr + * the sub actiondescr + * @param contribution + * the contribution + */ + private void formSubAction(List> subActions, String subActionTitle, String subActiondescr, + Long contribution) { + if (subActions.isEmpty()) { + Map subAction = new HashMap<>(); + subAction.put(ACTION, subActionTitle); + subAction.put(DESCRIPTION, subActiondescr); + subAction.put(CONTRIBUTION, contribution); + subActions.add(subAction); + } else { + boolean subActionExists = false; + for (Map subAction : subActions) { + if (subActionTitle.equals(subAction.get(ACTION).toString())) { + subActionExists = true; + subAction.put(CONTRIBUTION, Long.valueOf(subAction.get(CONTRIBUTION).toString()) + contribution); + break; + } + } + if (!subActionExists) { + Map subAction = new HashMap<>(); + subAction.put(ACTION, subActionTitle); + subAction.put(DESCRIPTION, subActiondescr); + subAction.put(CONTRIBUTION, contribution); + subActions.add(subAction); + } + } + } + + /** + * Gets the all matching string. + * + * @param actions + * the actions + * @return the all matching string + */ + private String getAllMatchingString(List> actions) { + List matchingStrings = new ArrayList<>(); + for (Map action : actions) { + matchingStrings.add(action.get(MATCHING_STRING).toString().toLowerCase()); + } + return StringUtils.join(matchingStrings, ","); + } + + /** + * Calculate contribution percentage. + * + * @param contributionList + * the contribution list + * @param total + * the total + */ + private void calculateContributionPercentage(List> contributionList, long total) { + DecimalFormat df = new DecimalFormat("###.##"); + ListIterator> it = contributionList.listIterator(); + String contributionPercent; + while (it.hasNext()) { + Map bucket = it.next(); + Long contribution = Long.valueOf(bucket.get(CONTRIBUTION).toString()); + if (contribution == 0) { + it.remove(); + } else { + contributionPercent = df.format((contribution * HUNDRED) / total); + if ("0".equals(contributionPercent)) { + it.remove(); + } else { + bucket.put(CONTRIBUTION, Float.valueOf(contributionPercent)); + } + } + } + } + + /** + * Creates the trend annotation. + * + * @param request + * the request + * @return true, if successful + * @throws JsonProcessingException + * the json processing exception + */ + public boolean createTrendAnnotation(TrendNote request) throws JsonProcessingException { + return vulnerabilityRepository.createTrendAnnotation(request); + } + + /** + * Gets the trend annotations. + * + * @param assetGroup + * the asset group + * @param from + * the from + * @return the trend annotations + * @throws DataException + * the data exception + */ + public List> getTrendAnnotations(String assetGroup, Date from) throws DataException { + + List> globalAnnotations = new ArrayList<>(); + List> assetGroupAnnotations = new ArrayList<>(); + List> annotations = vulnerabilityRepository.getTrendAnnotations(assetGroup, from); + + annotations.parallelStream().forEach(annotation -> { + if (StringUtils.isEmpty(annotation.get("ag").toString())) { + synchronized (globalAnnotations) { + globalAnnotations.add(annotation); + } + } else { + synchronized (assetGroupAnnotations) { + assetGroupAnnotations.add(annotation); + } + } + }); + + Map gloablMap = new HashMap<>(); + gloablMap.put("type", "Global"); + gloablMap.put("data", globalAnnotations); + + Map agMap = new HashMap<>(); + agMap.put("type", "AssetGroup"); + agMap.put("data", assetGroupAnnotations); + + List> noteList = new ArrayList<>(); + noteList.add(agMap); + noteList.add(gloablMap); + + return noteList; + } + + /** + * Delete trend annotation. + * + * @param noteId + * the note id + * @return true, if successful + */ + public boolean deleteTrendAnnotation(String noteId) { + return vulnerabilityRepository.deleteTrendAnnotation(noteId); + } + + /** + * Gets the vulnerability summary by assets. + * + * @param assetGroup + * the asset group + * @return the vulnerability summary by assets + * @throws ServiceException + * the service exception + * @throws DataException + * the data exception + */ + public Map getVulnerabilitySummaryByAssets(String assetGroup) + throws ServiceException, DataException { + + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + + long totalCount = 0; + long exemptedCount = 0; + long inscopeCount = 0; + long scannedCount = 0; + long unscannedCount = 0; + + for (String vulnType : vulnTargetTypes) { + try { + long tempTotalCount = vulnerabilityRepository.getRunningInstancesCount(assetGroup, vulnType); + long exemptedByRule = vulnerabilityRepository.getExemptedByRuleCount(assetGroup, vulnType); + + Request request = new Request(); + request.setAg(assetGroup); + Map filter = new HashMap<>(); + filter.put("domain", "Infra & Platforms"); + + if (vulnType.equals(EC2)) { + filter.put("ruleId.keyword", EC2_QUALYS_RULEID); + } else if (vulnType.equals(VIRTUALMACHINE)) { + filter.put("ruleId.keyword", VIRTUALMACHINE_QUALYS_RULEID); + } else { + filter.put("ruleId.keyword", ONPREM_QUALYS_RULEID); + } + request.setFilter(filter); + // + // Map response = + // complianceService.getRulecompliance(request).getResponse().get(0); + // new code starts + List> responses = new ArrayList<>(); + Map response = new HashMap<>(); + ResponseEntity nonCompliancePolicyRuleresponse = complianceServiceClient + .getNonCompliancePolicyByRule(request); + if (nonCompliancePolicyRuleresponse != null) { + Map responseBody = (Map) nonCompliancePolicyRuleresponse.getBody(); + Map dataResponseMap = (Map) responseBody.get("data"); + responses = (List>) dataResponseMap.get("response"); + if (responses.size() > 0) { + response = responses.get(0); + + // Response response = (Response) dataResponse.get("data"); + // new code ends + // This inScopeRule is total - exempted by age. SO exemptedByAge would be total- + // inScopeRule; + long inScopeRule = Long.valueOf(response.get("assetsScanned").toString()); + long exemptedByAge = tempTotalCount - inScopeRule; + totalCount += tempTotalCount; + exemptedCount += exemptedByAge + exemptedByRule; + inscopeCount += inScopeRule - exemptedByRule; // inScopeRule includes those exempted by Rule as + // well. + scannedCount += Long.valueOf(response.get("passed").toString()) - exemptedByRule; + unscannedCount += Long.valueOf(response.get("failed").toString()); + } + } + } catch (Exception e) { + throw new ServiceException(e); + } + } + + long nonCompliantCount = vulnerabilityRepository.getNonCompliantResourceIds(assetGroup).size(); + + Map compliant = vulnerabilityRepository.getCompliantHostsBySeverity(assetGroup); + Map noncompliant = vulnerabilityRepository.getUniqueHostBySeverity(assetGroup, "3,4,5"); + + noncompliant.put("S3", + Long.valueOf(noncompliant.get("S3").toString()) - Long.valueOf(compliant.get("S3").toString())); + noncompliant.put("S4", + Long.valueOf(noncompliant.get("S4").toString()) - Long.valueOf(compliant.get("S4").toString())); + + for (String key : compliant.keySet()) { + Map countMap = new HashMap<>(); + countMap.put(COUNT, Long.valueOf(compliant.get(key).toString())); + compliant.put(key, countMap); + } + + for (String key : noncompliant.keySet()) { + Map countMap = new HashMap<>(); + countMap.put(COUNT, Long.valueOf(noncompliant.get(key).toString())); + noncompliant.put(key, countMap); + } + + Map response = new HashMap<>(); + response.put(COUNT, totalCount); + + Map exempted = new HashMap<>(); + exempted.put(COUNT, exemptedCount); + response.put("exempted", exempted); + + Map inscope = new HashMap<>(); + inscope.put(COUNT, inscopeCount); + Map unscanned = new HashMap<>(); + unscanned.put(COUNT, unscannedCount); + inscope.put("unscanned", unscanned); + Map scanned = new HashMap<>(); + scanned.put(COUNT, scannedCount); + + compliant.put(COUNT, scannedCount - nonCompliantCount); + scanned.put("compliant", compliant); + noncompliant.put(COUNT, nonCompliantCount); + scanned.put("noncompliant", noncompliant); + + inscope.put("scanned", scanned); + response.put("inscope", inscope); + + return response; + } + + /** + * Gets the vulnerability assets trend. + * + * @param assetGroup + * the asset group + * @param severity + * the severity + * @param from + * the from + * @return the vulnerability assets trend + * @throws DataException + * the data exception + */ + public List> getVulnerabilityAssetsTrend(String assetGroup, String severity, Date from) + throws DataException { + + List> dateList = new ArrayList<>(); + + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + Map totalAssetsEc2 = new HashMap<>(); + Map totalAssetsOnPrem = new HashMap<>(); + + Map totalAssetsAffected = new HashMap<>(); + + ExecutorService executionService = Executors.newFixedThreadPool(3); + LocalDate fromDate = LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(from)); + + executionService.execute(() -> { + try { + long start = System.currentTimeMillis(); + totalAssetsAffected.putAll(vulnTrendGenerator.fetchAssetsAffected(assetGroup, fromDate, severity)); + System.out.println("Time taken assset affected " + (System.currentTimeMillis() - start)); + } catch (Exception e) { + logger.error("Error in fetchAssetsAffected fetch", e); + } + }); + + for (String vulnType : vulnTargetTypes) { + + switch(vulnType) { + + case EC2 : { + executionService.execute(() -> { + try { + long start = System.currentTimeMillis(); + totalAssetsEc2.putAll( + vulnTrendGenerator.fetchAssetsDateRangesForEc2(assetGroup, fromDate)); + //parallelStream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))); + System.out.println("Time taken EC2 Find ALL" + (System.currentTimeMillis() - start)); + } catch (Exception e) { + logger.error("Error in getVulnerabilityAssetsTrend fetch assets for EC2", e); + } + }); + break; + } + case ONPREMSERVER : { + executionService.execute(() -> { + long start = System.currentTimeMillis(); + + try { + totalAssetsOnPrem.putAll( + vulnTrendGenerator.fetchAssetsDateRangesOnPrem(assetGroup, fromDate).parallelStream() + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))); + System.out.println("Time taken ONPREM Find ALL" + (System.currentTimeMillis() - start)); + + } catch (Exception e) { + logger.error("Error in getVulnerabilityAssetsTrend fetch assets for On Prem", e); + } + }); + break; + + } + } + } + + executionService.shutdown(); + while (!executionService.isTerminated()) + ; + + Map totalAssets = addMapValues(totalAssetsEc2, totalAssetsOnPrem); + + totalAssets.entrySet().forEach(entry -> { + Map dateObj = new HashMap<>(); + String date = entry.getKey(); + Long asset = entry.getValue(); + Long assetAffected = totalAssetsAffected.get(date); + + dateObj.put("date", date); + dateObj.put("totalAssets", asset); + dateObj.put("assetsAffected", assetAffected == null ? 0l : assetAffected); + dateList.add(dateObj); + + }); + + return dateList; + } + + /** + * Adds the map values. + * + * @param ec2Assets + * the ec2 assets + * @param onpremAssets + * the onprem assets + * @return the map + */ + private Map addMapValues(Map ec2Assets, Map onpremAssets) { + Map totalMap = new HashMap<>(ec2Assets); + for (String key : onpremAssets.keySet()) { + if (totalMap.containsKey(key)) { + totalMap.put(key, onpremAssets.get(key) + totalMap.get(key)); + } else { + totalMap.put(key, onpremAssets.get(key)); + } + } + return totalMap; + } + + public Map> getDirectorsForAGByApp(Set appNames) throws Exception { + Map> directorsInfo = new HashMap<>(); + ObjectMapper mapper = new ObjectMapper(); + + vulnerabilityRepository.fetchOrgInfoForApps().forEach(app -> { + try { + if (appNames.contains(app.get(APP_TAG))) { + List> orgInfo = new ArrayList<>(); + if (null != app.get("list")) { + orgInfo.addAll(mapper.readValue(app.get("list").toString(), + new TypeReference>>() { + })); + } + orgInfo.forEach(info -> { + if (directorsInfo.containsKey(info.get("mgmntLevel"))) { + directorsInfo.get(info.get("mgmntLevel")).put(app.get(APP_TAG).toString(), + info.get("name")); + } else { + Map director = new HashMap<>(); + director.put(app.get(APP_TAG).toString(), info.get("name")); + directorsInfo.put(info.get("mgmntLevel"), director); + } + }); + } + } catch (Exception e) { + logger.error("Error in getDirectorsForAG ", e); + } + }); + return directorsInfo; + } + + private Map>> getDirectorsForAG(Set appNames) throws Exception { + + Map>> directorsInfo = new HashMap<>(); + ObjectMapper mapper = new ObjectMapper(); + + vulnerabilityRepository.fetchOrgInfoForApps().forEach(app -> { + try { + if (appNames.contains(app.get(APP_TAG))) { + List> orgInfo = new ArrayList<>(); + if (null != app.get("list")) { + orgInfo.addAll(mapper.readValue(app.get("list").toString(), + new TypeReference>>() { + })); + } + orgInfo.forEach(info -> { + if (directorsInfo.containsKey(info.get("mgmntLevel"))) { + if (directorsInfo.get(info.get("mgmntLevel")).containsKey(info.get("name"))) { + directorsInfo.get(info.get("mgmntLevel")).get(info.get("name")) + .add(app.get(APP_TAG).toString()); + } else { + List apps = new ArrayList<>(); + apps.add(app.get(APP_TAG).toString()); + directorsInfo.get(info.get("mgmntLevel")).put(info.get("name"), apps); + } + } else { + Map> director = new HashMap<>(); + List apps = new ArrayList<>(); + apps.add(app.get(APP_TAG).toString()); + director.put(info.get("name"), apps); + directorsInfo.put(info.get("mgmntLevel"), director); + } + }); + } + } catch (Exception e) { + logger.error("Error in getDirectorsForAG ", e); + } + }); + return directorsInfo; + } + + private void formPerformersData(Map appDetails, Map perfData, + Map> directApp) { + for (Entry> entry : directApp.entrySet()) { + + String director = entry.getKey(); + int directorVuln = 0; + for (String app : entry.getValue()) { + directorVuln += appDetails.get(app); + } + + if (!perfData.isEmpty()) { + boolean directorExists = false; + for (Entry existingDirectorData : perfData.entrySet()) { + if (director.equals(existingDirectorData.getKey())) { + perfData.put(director, existingDirectorData.getValue() + directorVuln); + directorExists = true; + break; + } + } + if (!directorExists) { + perfData.put(director, directorVuln); + } + } else { + perfData.put(director, directorVuln); + } + } + } + + private void formDistributionSummaryDetails(Map directApp, String appName, + List> directorData, Map sevInfo, String severity) { + if (!directorData.isEmpty()) { + if (StringUtils.isNotEmpty(directApp.get(appName))) { + String director = directApp.get(appName); + boolean directorExists = false; + for (Map existingDirectorData : directorData) { + if (director.equals(existingDirectorData.get("name"))) { + existingDirectorData.put(COUNT, Integer.valueOf(existingDirectorData.get(COUNT).toString()) + + Integer.valueOf(sevInfo.get("S" + severity).toString())); + directorExists = true; + break; + } + } + if (!directorExists) { + Map directorTemp = new HashMap<>(); + directorTemp.put("name", director); + directorTemp.put(COUNT, sevInfo.get("S" + severity)); + directorData.add(directorTemp); + } + } + } else { + if (StringUtils.isNotEmpty(directApp.get(appName))) { + Map directorTemp = new HashMap<>(); + directorTemp.put("name", directApp.get(appName)); + directorTemp.put(COUNT, sevInfo.get("S" + severity)); + directorData.add(directorTemp); + } + } + } + + private void formAgingDistributionSummaryDetails(Map directApp, String appName, + List> directorData, Map sevInfo, String severity) { + if (!directorData.isEmpty()) { + if (StringUtils.isNotEmpty(directApp.get(appName))) { + String director = directApp.get(appName); + boolean directorExists = false; + for (Map existingDirectorData : directorData) { + if (director.equals(existingDirectorData.get("name"))) { + existingDirectorData.put("days", Double.valueOf(existingDirectorData.get("days").toString()) + + Double.valueOf(sevInfo.get("days").toString())); + existingDirectorData.put(COUNT, Double.valueOf(existingDirectorData.get(COUNT).toString()) + + Double.valueOf(sevInfo.get(COUNT).toString())); + directorExists = true; + break; + } + } + if (!directorExists) { + Map directorTemp = new HashMap<>(); + directorTemp.put("name", director); + directorTemp.put("days", sevInfo.get("days")); + directorTemp.put(COUNT, sevInfo.get(COUNT)); + directorData.add(directorTemp); + } + } + } else { + if (StringUtils.isNotEmpty(directApp.get(appName))) { + Map directorTemp = new HashMap<>(); + directorTemp.put("name", directApp.get(appName)); + directorTemp.put("days", sevInfo.get("days")); + directorTemp.put(COUNT, sevInfo.get(COUNT)); + directorData.add(directorTemp); + } + } + } + + private void validatingAgingDays(List> directorData) { + + directorData.parallelStream().forEach(director -> { + if (director.get(COUNT).toString().equals(ZERO) || director.get(COUNT).toString().equals(DOUBLE_ZERO)) { + director.put("days", 0); + } else { + director.put("days", Math.floor(Double.valueOf(director.get("days").toString()) + / Double.valueOf(director.get(COUNT).toString()))); + } + director.remove(COUNT); + }); + } + + public ResponseEntity formatException(ServiceException e) { + if (e.getMessage().contains(NO_DATA_FOUND)) { + List> emptylist = new ArrayList<>(); + ResponseData res = new ResponseData(emptylist); + return ResponseUtils.buildSucessResponse(res); + } else { + return ResponseUtils.buildFailureResponse(e); + } + } + + public Map getTrendProgress(String assetGroup, String ruleId, LocalDate startDate, + LocalDate endDate, String trendCategory) throws ServiceException { + + List> trendList; + try { + trendList = vulnerabilityRepository.getTrendProgress(assetGroup, ruleId, startDate, endDate, trendCategory); + } catch (DataException e) { + throw new ServiceException(e); + } + if (!trendList.isEmpty()) { + + // Sort the list by the date in ascending order + Comparator> comp = (m1, m2) -> LocalDate + .parse(m1.get("date").toString(), DateTimeFormatter.ISO_DATE) + .compareTo(LocalDate.parse(m2.get("date").toString(), DateTimeFormatter.ISO_DATE)); + Collections.sort(trendList, comp); + LocalDate trendStartDate = LocalDate.parse(trendList.get(0).get("date").toString()); + + // Elastic Search might not have data for some dates. But we want to + // send consistent data to the consumers of this service, so we will + // populate previous where data is unavailable + fillNoDataDatesWithPrevious(trendList, trendStartDate, endDate); + + useRealTimeDataForLatestDate(trendList, assetGroup, trendCategory, ruleId, null); + + // ADD compliance_percent if not available . This is done + // temporarily.Will update with compliance_percent at source + + appendWithCompliancePercent(trendList); + + return segregateTrendProgressByWeek(assetGroup, trendList, trendStartDate, endDate); + } else { + return new HashMap<>(); + } + } + + /** + * Segregate trend progress by week. + * + * @param assetGroup + * the asset group + * @param trendProgressList + * the trend progress list + * @param startDate + * the start date + * @param endDate + * the end date + * @return the map + */ + private Map segregateTrendProgressByWeek(String assetGroup, + List> trendProgressList, LocalDate startDate, LocalDate endDate) { + + long maxInstancesForTheCompleteDateRange = 0; + + long totalNumberRunningValue = 0; + long compliantRunningValue = 0; + long noncompliantRunningValue = 0; + double complianceRunningValue = 0; + + List> allWeeksDataList = new ArrayList<>(); + + // The first day of date range is taken as the first day of week 1 of + // the + // quarter. This + // could be a Monday, Thursday or ANY day. + LocalDate startingDayOfWeek = startDate; + + // Add 6 days to get the end date. If we start on a Thursday, the week + // ends on next Wednesday + LocalDate endingDayOfWeek = startingDayOfWeek.plusDays(SIX); + + List> trendListForTheWeek = new ArrayList<>(); + + // We will send 100 weeks at most. Start with week 1(There + // is no week zero!) + for (int weekNumber = 1; weekNumber <= HUNDRED; weekNumber++) { + + LocalDate startingDayOfWeekLocalCopy = startingDayOfWeek; + LocalDate endingDayOfWeekLocalCopy = endingDayOfWeek; + + trendProgressList.forEach(ruleTrendProgressMap -> ruleTrendProgressMap.forEach((key, value) -> { + + if ("date".equals(key)) { + + // Check if this date falls in the week that we are + // currently interested in + LocalDate dateInThisIteration = LocalDate.parse(value.toString(), DateTimeFormatter.ISO_DATE); + if (dateInThisIteration.isAfter(startingDayOfWeekLocalCopy.minusDays(1)) + && (dateInThisIteration.isBefore(endingDayOfWeekLocalCopy.plusDays(1)))) { + // If the date matches, lets pick the map which + // represents this date's patching data and add + // it to + // the weeks list + trendListForTheWeek.add(ruleTrendProgressMap); + } + + } + + })); + + Map mapForTheWeek = new LinkedHashMap<>(); + + // First some k-v pairs for week number,week start date, week end + // date + mapForTheWeek.put("week", weekNumber); + mapForTheWeek.put("start_date", startingDayOfWeek.format(DateTimeFormatter.ISO_DATE)); + mapForTheWeek.put("end_date", endingDayOfWeek.format(DateTimeFormatter.ISO_DATE)); + + // Lets calculate the compliance for the week. We simply get the + // compliance for the last day of the week + + complianceRunningValue = calculateWeeklyCompliance(trendListForTheWeek); + mapForTheWeek.put(COMPLIANCE_PERCENTAGE, complianceRunningValue); + trendListForTheWeek.forEach(ruleTrendProgressMap -> { + // We don't need _id in the response + ruleTrendProgressMap.remove("_id"); + }); + + // Store a 'copy' of the weeks array list instead of the original, + // as we will clear the original and reuse it for the next + // iteration. Lets call this by the key 'compliance_info' + mapForTheWeek.put("compliance_info", new ArrayList>(trendListForTheWeek)); + + if (!trendListForTheWeek.isEmpty()) { + allWeeksDataList.add(mapForTheWeek); + + totalNumberRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList(TOTAL, + trendListForTheWeek); + compliantRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList(COMPLAINT, + trendListForTheWeek); + noncompliantRunningValue = (long) getLatestDaysNumericDataFromAWeeklyDataList(NON_COMPLIANT, + trendListForTheWeek); + + // Maintain a max instance number for the quarter that is being + // processed. + long maxInstancesRunningValue = (long) getMaxValueNumericDataFromAWeeklyDataList(TOTAL, + trendListForTheWeek); + if (maxInstancesRunningValue > maxInstancesForTheCompleteDateRange) { + maxInstancesForTheCompleteDateRange = maxInstancesRunningValue; + } + + } + + // Now, lets get ready for the iteration for next week + trendListForTheWeek.clear(); + startingDayOfWeek = startingDayOfWeek.plusDays(7); + endingDayOfWeek = endingDayOfWeek.plusDays(7); + + // If week ending date bypasses the quarter end date, lets rewind + // back to quarter end date. The quarter end date will be set as the + // week ending date. + } + + Map quarterlyDataMap = new LinkedHashMap<>(); + quarterlyDataMap.put("ag", assetGroup); + quarterlyDataMap.put("start_date", startDate.format(DateTimeFormatter.ISO_DATE)); + quarterlyDataMap.put("end_date", endDate.format(DateTimeFormatter.ISO_DATE)); + quarterlyDataMap.put("max", maxInstancesForTheCompleteDateRange); + quarterlyDataMap.put(TOTAL, totalNumberRunningValue); + quarterlyDataMap.put(COMPLAINT, compliantRunningValue); + quarterlyDataMap.put(NON_COMPLIANT, noncompliantRunningValue); + quarterlyDataMap.put(COMPLIANCE_PERCENTAGE, complianceRunningValue); + + quarterlyDataMap.put("compliance_trend", allWeeksDataList); + + return quarterlyDataMap; + + } + + private void fillNoDataDatesWithPrevious(List> trendList, LocalDate firstDay, + LocalDate lastDay) { + + // We don't want data for future weeks. If the quarter being + // requested is the ongoing quarter, the max we we are interested + // is data up to and including the ongoing day in the ongoing week. + if (lastDay.isAfter(LocalDate.now())) { + lastDay = LocalDate.now(); + } + + List listOfAllDates = new ArrayList<>(); + + LocalDate iterationDate = firstDay; + + // Have a temp variable called iterationDate. Keep incrementing it by 1, + // until we reach the end date. In each such iteration, add each date to + // our list of dates + while (!iterationDate.isAfter(lastDay)) { + listOfAllDates.add(iterationDate); + iterationDate = iterationDate.plusDays(1); + } + + // Iterate through each date. If the data from ES is missing for any + // such + // date, add a dummy map with zero values + Map currentData = new LinkedHashMap<>(); + currentData.put(TOTAL, 0); + currentData.put(COMPLAINT, 0); + currentData.put(NON_COMPLIANT, 0); + currentData.put(COMPLIANCE_PERCENT, HUNDRED); + + for (int i = 0; i < listOfAllDates.size(); i++) { + LocalDate date = listOfAllDates.get(i); + Map trendInfo = getTrendDataForDate(trendList, date); + if (trendInfo == null) { + trendInfo = new LinkedHashMap<>(); + trendInfo.put("date", date.format(DateTimeFormatter.ISO_DATE)); + trendInfo.put(NON_COMPLIANT, currentData.get(NON_COMPLIANT)); + trendInfo.put(TOTAL, currentData.get(TOTAL)); + trendInfo.put(COMPLAINT, currentData.get(COMPLAINT)); + if (currentData.get(COMPLIANCE_PERCENT) != null) { + trendInfo.put(COMPLIANCE_PERCENT, currentData.get(COMPLIANCE_PERCENT)); + } + trendList.add(i, trendInfo); + } else { + currentData = trendInfo; + } + } + + } + + /** + * Gets the trend data for date. + * + * @param trendList + * the trend list + * @param date + * the date + * @return the trend data for date + */ + private Map getTrendDataForDate(List> trendList, LocalDate date) { + + List> match = trendList.stream().filter(trendMap -> { + LocalDate dateInThisIteration = LocalDate.parse(trendMap.get("date").toString(), + DateTimeFormatter.ISO_DATE); + return dateInThisIteration.isEqual(date); + }).collect(Collectors.toList()); + if (match != null && !match.isEmpty()) { + return match.get(0); + } + return null; + } + + public void useRealTimeDataForLatestDate(List> trendList, String ag, String trendCategory, + String ruleId, String domain) throws ServiceException { + Map latestDaysTrendData = new HashMap<>(trendList.get(trendList.size() - 1)); + Map baseApiReturnMap = new HashMap<>(); + Map overallCompliance = new HashMap<>(); + long compliantQuantity = 0; + long noncompliantQuantity = 0; + long total = 0; + double compliance; + LocalDate today; + try { + switch (trendCategory) { + + case "vulncompliance": + Map vulnSummary = getVulnerabilitySummary(ag, SEVERITY_LEVELS); + total = Long.valueOf(vulnSummary.get("hosts").toString()); + noncompliantQuantity = Long.valueOf(vulnSummary.get("totalVulnerableAssets").toString()); + compliantQuantity = total - noncompliantQuantity; + + latestDaysTrendData.put(COMPLAINT, compliantQuantity); + latestDaysTrendData.put(NON_COMPLIANT, noncompliantQuantity); + latestDaysTrendData.put(TOTAL, total); + if (total > 0) { + compliance = Math.floor(compliantQuantity * HUNDRED / total); + } else { + compliance = INT_HUNDRED; + } + latestDaysTrendData.put(COMPLIANCE_PERCENT, compliance); + break; + + default: + // nothings + } + + // Check if the trend already has todays data (Compare dates) + // If yes, overwrite. If not, add at the end. + LocalDate date = null; + today = LocalDate.now(); + date = LocalDate.parse(latestDaysTrendData.get("date").toString(), DateTimeFormatter.ISO_LOCAL_DATE); + + if (date.isEqual(today)) { + logger.info("Latest days data available in trend data, so overwriting"); + trendList.set(trendList.size() - 1, latestDaysTrendData); + } else if (date.isEqual(today.minusDays(1))) { + // Ideally we need to consider this case only else, we may + // unnecessarily append wrong data. FOr eg. In case of patching + // if any previous/ progress is requested. + logger.info("Latest days data is NOT available in trend data, so adding at the end"); + latestDaysTrendData.put("date", today.format(DateTimeFormatter.ISO_LOCAL_DATE)); + trendList.add(latestDaysTrendData); + } + + } catch (ServiceException e) { + logger.error("Call to Base API to get todays data failed", e); + return; + } + + } + + /** + * Append with compliance percent. + * + * @param trendList + * the trend list + */ + private void appendWithCompliancePercent(List> trendList) { + + trendList.parallelStream().forEach(trend -> { + if (trend.get(COMPLIANCE_PERCENT) == null) { + double total = Double.parseDouble(trend.get(TOTAL).toString()); + double compliant = Double.parseDouble(trend.get(COMPLAINT).toString()); + double compliancePercent = HUNDRED; + if (total > 0) { + compliancePercent = Math.floor(compliant * HUNDRED / total); + } + trend.put(COMPLIANCE_PERCENT, compliancePercent); + } + }); + } + + /** + * Calculate weekly compliance. + * + * @param trendProgressListForTheWeek + * the trend progress list for the week + * @return the double + */ + private double calculateWeeklyCompliance(List> trendProgressListForTheWeek) { + + int index = trendProgressListForTheWeek.size() - 1; + while (index >= 0) { + Object percentObj = trendProgressListForTheWeek.get(index).get(COMPLIANCE_PERCENT); + if (null != percentObj && Double.valueOf(percentObj.toString()) != 0) { + return Double.valueOf(percentObj.toString()); + } + index--; + } + return HUNDRED; + + } + + /** + * Gets the max value numeric data from A weekly data list. + * + * @param dataKeyName + * the data key name + * @param trendProgressListForTheWeek + * the trend progress list for the week + * @return the max value numeric data from A weekly data list + */ + private double getMaxValueNumericDataFromAWeeklyDataList(String dataKeyName, + List> trendProgressListForTheWeek) { + + double maxValue = 0; + int index = trendProgressListForTheWeek.size() - 1; + + while (index >= 0) { + Object obj = trendProgressListForTheWeek.get(index).get(dataKeyName); + if (null != obj && Double.valueOf(obj.toString()) != 0 && (Double.valueOf(obj.toString()) > maxValue)) { + maxValue = Double.valueOf(obj.toString()); + } + index--; + } + + return maxValue; + } + + /** + * Gets the latest days numeric data from A weekly data list. + * + * @param dataKeyName + * the data key name + * @param ruleTrendProgressListForTheWeek + * the rule trend progress list for the week + * @return the latest days numeric data from A weekly data list + */ + private double getLatestDaysNumericDataFromAWeeklyDataList(String dataKeyName, + List> ruleTrendProgressListForTheWeek) { + + int index = ruleTrendProgressListForTheWeek.size() - 1; + + // We take the latest days data, provided its a non-zero value + while (index >= 0) { + Object obj = ruleTrendProgressListForTheWeek.get(index).get(dataKeyName); + if (null != obj && Double.valueOf(obj.toString()) != 0) { + return Double.valueOf(obj.toString()); + } + index--; + } + + return 0; + } + + public List getResourceId(List> vulnerabilityOccuranceList) { + List resourceIdList = new ArrayList(); + for (Map map : vulnerabilityOccuranceList) { + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + if (key.equals("_resourceid")) { + String value = entry.getValue().toString(); + resourceIdList.add(value); + } + + } + } + return resourceIdList.stream().distinct().collect(Collectors.toList()); + } + + public List> getCartesianProduct(List> vulnerabilityOccuranceList, + List> resourceIdDetails) { + List> finalVulnerabilityOccuranceList = new ArrayList>(); + LinkedHashMap> mapOfResourceAttributeMap = new LinkedHashMap>(); + for (Map resourceAttributeMap : resourceIdDetails) { + mapOfResourceAttributeMap.put((String) resourceAttributeMap.get("_resourceid"), resourceAttributeMap); + } + + /* + * mapOfResourceAttributeMap = resourceIdDetails.stream() + * .collect(Collectors.toMap(obj -> obj.get("_resourceid").toString(), obj -> + * obj)); + */ + for (Map vulnerabilityOccuranceMap : vulnerabilityOccuranceList) { + LinkedHashMap finalVulnerabilityOccuranceMap = new LinkedHashMap<>( + vulnerabilityOccuranceMap); + String resourceId = (String) vulnerabilityOccuranceMap.get("_resourceid"); + if (!mapOfResourceAttributeMap.containsKey(resourceId)) { + continue; + } + + finalVulnerabilityOccuranceMap.putAll(mapOfResourceAttributeMap.get(resourceId)); + finalVulnerabilityOccuranceList.add(finalVulnerabilityOccuranceMap); + } + + return finalVulnerabilityOccuranceList; + } + + public int vulnerabilityAssetCount(String assetGroup, Map termsFilter, String applicationFilter, + String environmentFilter, int from, int size) throws Exception { + + List vulnTargetTypes = getVulnTargetTypes(assetGroup); + int totalCount = 0; + if (!vulnTargetTypes.isEmpty()) { + for (String parentType : vulnTargetTypes) { + totalCount = totalCount + countForTargetType(assetGroup, parentType, termsFilter, applicationFilter, + environmentFilter, from, size); + } + } + + return totalCount; + } + + public int countForTargetType(String assetGroup, String parentType, Map termsFilter, + String applicationFilter, String environmentFilter, int from, int size) throws Exception { + int count = 0; + String targetType = "vulninfo"; + Map mustFilterMap = new LinkedHashMap<>(); + mustFilterMap.put("latest", "true"); + Map parentBool = new HashMap<>(); + List> mustList = new ArrayList<>(); + Map matchMap = new HashMap<>(); + Map match = new HashMap<>(); + Map mustTermsFilter = new HashMap<>(); + for (Map.Entry entry : termsFilter.entrySet()) { + List severities = Arrays.asList(entry.getValue().split(",")); + mustTermsFilter.put(entry.getKey(), severities); + } + match.put(Constants.LATEST, Constants.TRUE); + matchMap.put(Constants.MATCH, match); + mustList.add(matchMap); + + if (applicationFilter != null) { + Map applicationFilterMap = new HashMap(); + Map applicationFilterMap1 = new HashMap(); + applicationFilterMap.put("tags.Application.keyword", applicationFilter); + applicationFilterMap1.put("match", applicationFilterMap); + mustList.add(applicationFilterMap1); + } + + if (environmentFilter != null) { + Map environmentFilterMap = new HashMap(); + Map environmentFilterMap1 = new HashMap(); + environmentFilterMap.put("tags.Environment.keyword", environmentFilter); + environmentFilterMap1.put("match", environmentFilterMap); + mustList.add(environmentFilterMap1); + } + + parentBool.put("must", mustList); + Map queryMap = new HashMap<>(); + queryMap.put("bool", parentBool); + Map parentEntryMap = new LinkedHashMap<>(); + parentEntryMap.put("parent_type", parentType); + parentEntryMap.put("query", queryMap); + mustFilterMap.put("has_parent", parentEntryMap); + count = vulnerabilityRepository.vulnerabilityAssetsCount(assetGroup, targetType, mustFilterMap, from, size, + mustTermsFilter); + logger.info("vulnerability asset count {} " + count); + return count; + + } +} diff --git a/api/pacman-api-vulnerability/src/main/resources/banner.txt b/api/pacman-api-vulnerability/src/main/resources/banner.txt new file mode 100644 index 000000000..c17bc74a7 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/resources/banner.txt @@ -0,0 +1,52 @@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.WHITE}*${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}&${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_YELLOW}*${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.BRIGHT_YELLOW}.${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ \ No newline at end of file diff --git a/api/pacman-api-vulnerability/src/main/resources/bootstrap.yml b/api/pacman-api-vulnerability/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..b95702daa --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/resources/bootstrap.yml @@ -0,0 +1,21 @@ +spring: + application: + name: vulnerability-service + title: Pacman Service + description: Pacman API provides vulnerability capabilities + cloud: + config: + uri: ${CONFIG_SERVER_URL:http://localhost:8888/api/config/} + enabled: true + fail-fast: true + name: api,vulnerability-service + password: ${CONFIG_PASSWORD} + username: user + label: latest + profiles: + active: ${ENVIRONMENT:prd} + +security: + oauth2: + resource: + user-info-uri: ${PACMAN_HOST_NAME}/api/auth/user diff --git a/api/pacman-api-vulnerability/src/main/resources/spring-logback.xml b/api/pacman-api-vulnerability/src/main/resources/spring-logback.xml new file mode 100644 index 000000000..3224e2637 --- /dev/null +++ b/api/pacman-api-vulnerability/src/main/resources/spring-logback.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + ${consoleLoggingLevel} + + + %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level + %logger{36}.%M - %msg%n + + + + + + ${esLoggingLevel} + + /var/log/pacman-api-${microserviceName}-${profile}.log + true + + + true + yyyy-MM-dd'T'HH:mm:ss.SSSX + Etc/UTC + + false + + + + + + + + + + \ No newline at end of file diff --git a/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/controller/VulnerabilityControllerTest.java b/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/controller/VulnerabilityControllerTest.java new file mode 100644 index 000000000..8bfccdd14 --- /dev/null +++ b/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/controller/VulnerabilityControllerTest.java @@ -0,0 +1,652 @@ +package com.tmobile.pacman.api.vulnerability.controller; +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ + +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.anyListOf; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.exception.ServiceException; +import com.tmobile.pacman.api.vulnerability.controller.VulnerabilityController; +import com.tmobile.pacman.api.vulnerability.domain.Request; +import com.tmobile.pacman.api.vulnerability.domain.TrendNote; +import com.tmobile.pacman.api.vulnerability.domain.TrendRequest; +import com.tmobile.pacman.api.vulnerability.service.VulnerabilityService; + +@RunWith(PowerMockRunner.class) +public class VulnerabilityControllerTest { + + @InjectMocks + VulnerabilityController vulnerabilityController; + + @Mock + VulnerabilityService vulnerabilityService; + + @Test + public void getVulnerabilitiesDetailsTest() throws Exception { + + List> vulnDetails = new ArrayList<>(); + + Request request = new Request(); + request.setAg("ag"); + request.setFrom(0); + + when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(new ArrayList<>()); + + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); + + request.setFilter(new HashMap<>()); + vulnDetails.add(new HashMap<>()); + vulnDetails.add(new HashMap<>()); + + when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); + + request.setSize(1); + when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); + + request.setSize(3); + when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request).getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilitiesDetailsTest_Failure() throws Exception { + + Request request = new Request(); + + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + request.setAg("ag"); + request.setFrom(-1); + + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + request.setFrom(2); + List> vulnDetails = new ArrayList>(); + vulnDetails.add(new HashMap<>()); + + when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())).thenReturn(new ArrayList<>()); + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getCertificatesDetailsTest_Exception() throws Exception { + + Request request = new Request(); + request.setAg("ag"); + request.setFrom(0); + + when(vulnerabilityService.getVulnerabilitiesDetails(anyString(), anyObject())) + .thenThrow(new ServiceException()); + assertTrue(vulnerabilityController.getVulnerabilitiesDetails(request) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilitysummaryTest() throws Exception { + + when(vulnerabilityService.getVulnerabilitySummary(anyString(), anyString())).thenReturn(new HashMap<>()); + assertTrue(vulnerabilityController.getVulnerabilitysummary("ag", "3,4,5").getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilitysummaryTest_Exception() throws Exception { + + assertTrue(vulnerabilityController.getVulnerabilitysummary("", "3,4,5") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + when(vulnerabilityService.getVulnerabilitySummary(anyString(), anyString())).thenThrow(new ServiceException()); + assertTrue(vulnerabilityController.getVulnerabilitysummary("ag", "3,4,5") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilityByApplicationsTest() throws Exception { + + when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())) + .thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilityByApplications("ag").getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilityByApplicationsTest_Exception() throws Exception { + + assertTrue(vulnerabilityController.getVulnerabilityByApplications("") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())) + .thenThrow(new Exception()); + assertTrue(vulnerabilityController.getVulnerabilityByApplications("ag") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilitiesTrendTest() throws Exception { + + TrendRequest request = new TrendRequest(); + request.setAg("ag"); + + when(vulnerabilityService.getVulnerabilityTrend(anyString(), anyObject(), anyObject(), anyObject())) + .thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); + + request.setFrom(new Date()); + when(vulnerabilityService.getVulnerabilityTrend(anyString(), anyObject(), anyObject(), anyObject())) + .thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); + + request.setTo(new Date()); + when(vulnerabilityService.getVulnerabilityTrend(anyString(), anyObject(), anyObject(), anyObject())) + .thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); + + request = new TrendRequest(); + request.setAg("ag"); + request.setTo(new Date()); + when(vulnerabilityService.getVulnerabilityTrend(anyString(), anyObject(), anyObject(), anyObject())) + .thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request).getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilitiesTrendTest_Exception() throws Exception { + + TrendRequest request = new TrendRequest(); + assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + request.setAg("ag"); + when(vulnerabilityService.getVulnerabilityTrend(anyString(), anyObject(), anyObject(), anyObject())) + .thenThrow(new ServiceException()); + assertTrue(vulnerabilityController.getVulnerabilitiesTrend(request) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilityByEnvironmentTest() throws Exception { + + when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())) + .thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilityByEnvironment("ag", "app").getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilityByEnvironmentTest_Exception() throws Exception { + + assertTrue(vulnerabilityController.getVulnerabilityByEnvironment("", null) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + when(vulnerabilityService.getVulnerabilityByAppAndEnv(anyString(), anyString(), anyString())) + .thenThrow(new Exception()); + assertTrue(vulnerabilityController.getVulnerabilityByEnvironment("ag", "app") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilityDistributionTest() throws Exception { + + when(vulnerabilityService.getVulnerabilitiesDistribution(anyString())).thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilityDistribution("ag").getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilityDistributionTest_Exception() throws Exception { + + assertTrue(vulnerabilityController.getVulnerabilityDistribution("") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + when(vulnerabilityService.getVulnerabilitiesDistribution(anyString())).thenThrow(new ServiceException()); + assertTrue(vulnerabilityController.getVulnerabilityDistribution("ag") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilitysummaryByResourceIdTest() throws Exception { + + when(vulnerabilityService.getVulnerabilitysummaryByResourceId(anyString())).thenReturn(new HashMap<>()); + assertTrue(vulnerabilityController.getVulnerabilitysummaryByResourceId("ag").getStatusCode() == HttpStatus.OK); + } + + + /*@Test + public void getVulnerabilitysummaryByResourceIdTest_Exception() throws Exception { + + when(vulnerabilityService.getVulnerabilitysummaryByResourceId(anyString())).thenThrow(new Exception()); + assertTrue(vulnerabilityController.getVulnerabilitysummaryByResourceId("ag").getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + */ + + @Test + public void getVulnerabilityDetailsByResourceIdTest() throws Exception { + + when(vulnerabilityService.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(new ArrayList<>()); + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(new ArrayList<>()); + + assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id", "search", 0, 0) + .getStatusCode() == HttpStatus.OK); + assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id", "search", null, null) + .getStatusCode() == HttpStatus.OK); + + List> resourceDetails = new ArrayList<>(); + resourceDetails.add(new HashMap<>()); + resourceDetails.add(new HashMap<>()); + + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(resourceDetails); + assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id", "search", 0, 0) + .getStatusCode() == HttpStatus.OK); + + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(resourceDetails); + assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id", "search", 0, 1) + .getStatusCode() == HttpStatus.OK); + + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(resourceDetails); + assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id", "search", 0, 3) + .getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilityDetailsByResourceIdTest_Exception() throws Exception { + + List> resourceDetails = new ArrayList<>(); + resourceDetails.add(new HashMap<>()); + + when(vulnerabilityService.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(new ArrayList<>()); + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenReturn(resourceDetails); + assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id", "search", 2, 3) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + when(vulnerabilityService.filterMatchingCollectionElements(anyObject(), anyString(), anyBoolean())) + .thenThrow(new ServiceException()); + assertTrue(vulnerabilityController.getVulnerabilityDetailsByResourceId("id", "search", 0, 1) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getAgingSummaryTest() throws Exception { + + when(vulnerabilityService.getAgingSummary(anyString())).thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getAgingSummary("ag").getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilityByQidTest() throws Exception { + + when(vulnerabilityService.getVulnerabilityByQid(anyString())).thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getVulnerabilityByQid("qid").getStatusCode() == HttpStatus.OK); + } + + @Test + public void getDistributionSummaryByVulnTypeTest() throws Exception { + + when(vulnerabilityService.getDistributionSummaryByVulnType(anyString(), anyString())) + .thenReturn(new ArrayList<>()); + + ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByVulnType("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.OK); + } + + @Test + public void getDistributionSummaryByVulnTypeTest_Exception() throws Exception { + + when(vulnerabilityService.getDistributionSummaryByVulnType(anyString(), anyString())) + .thenThrow(new DataException()); + + ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByVulnType("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getDistributionSummaryByInfraTypeTest() throws Exception { + + when(vulnerabilityService.getDistributionSummaryByInfraType(anyString(), anyString())) + .thenReturn(new ArrayList<>()); + + ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByInfraType("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.OK); + } + + @Test + public void getDistributionSummaryByInfraTypeTest_Exception() throws Exception { + + when(vulnerabilityService.getDistributionSummaryByInfraType(anyString(), anyString())) + .thenThrow(new ServiceException()); + + ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByInfraType("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getDistributionSummaryByEnvTest() throws Exception { + + when(vulnerabilityService.getDistributionSummaryByEnv(anyString(), anyString())).thenReturn(new ArrayList<>()); + + ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByEnv("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.OK); + } + + @Test + public void getDistributionSummaryByEnvTest_Exception() throws Exception { + + when(vulnerabilityService.getDistributionSummaryByEnv(anyString(), anyString())) + .thenThrow(new ServiceException()); + + ResponseEntity responseObj = vulnerabilityController.getDistributionSummaryByEnv("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getRemediationActionsSummaryTest() throws Exception { + + when(vulnerabilityService.getRemediationActionsSummary(anyString(), anyString())).thenReturn(new ArrayList<>()); + + ResponseEntity responseObj = vulnerabilityController.getRemediationActionsSummary("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.OK); + } + + @Test + public void getRemediationActionsSummaryTest_Exception() throws Exception { + + when(vulnerabilityService.getRemediationActionsSummary(anyString(), anyString())) + .thenThrow(new DataException()); + + ResponseEntity responseObj = vulnerabilityController.getRemediationActionsSummary("ag", "3"); + assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getV1HighestLowestPeformersTest() throws Exception { + + Map directorData = new HashMap<>(); + directorData.put("dir1", 1); + directorData.put("dir2", 2); + + when(vulnerabilityService.getHighestLowestPerformers(anyString(), anyString(), anyString())) + .thenReturn(directorData); + assertTrue(vulnerabilityController.getHighestLowestPerformers("ag", "3").getStatusCode() == HttpStatus.OK); + + directorData.put("dir3", 3); + + when(vulnerabilityService.getHighestLowestPerformers(anyString(), anyString(), anyString())) + .thenReturn(directorData); + assertTrue(vulnerabilityController.getHighestLowestPerformers("ag", "3").getStatusCode() == HttpStatus.OK); + + directorData.put("dir4", 4); + directorData.put("dir5", 5); + directorData.put("dir6", 6); + directorData.put("dir7", 7); + directorData.put("dir8", 8); + directorData.put("dir9", 9); + directorData.put("dir10", 10); + directorData.put("dir11", 11); + directorData.put("dir12", 12); + + when(vulnerabilityService.getHighestLowestPerformers(anyString(), anyString(), anyString())) + .thenReturn(directorData); + assertTrue(vulnerabilityController.getHighestLowestPerformers("ag", "3").getStatusCode() == HttpStatus.OK); + + } + + @Test + public void getV2HighestLowestPeformersTest() throws Exception { + + Map directorData = new HashMap<>(); + directorData.put("dir1", 1); + directorData.put("dir2", 2); + + when(vulnerabilityService.getHighestLowestPerformers(anyString(), anyString(), anyString())) + .thenReturn(directorData); + assertTrue(vulnerabilityController.getHighestLowestPerformers("ag", "3", PerfType.org) + .getStatusCode() == HttpStatus.OK); + assertTrue(vulnerabilityController.getHighestLowestPerformers("ag", "3", PerfType.application) + .getStatusCode() == HttpStatus.OK); + assertTrue(vulnerabilityController.getHighestLowestPerformers("ag", "3", PerfType.environment) + .getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulerabilityTrendTest() throws Exception { + + TrendRequest request = new TrendRequest(); + request.setAg("ag"); + + when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(), anyString(), anyObject())) + .thenReturn(new ArrayList<>()); + + ResponseEntity responseObj = vulnerabilityController.getVulnerabilityTrend(request); + assertTrue(responseObj.getStatusCode() == HttpStatus.OK); + + request.setFrom(new Date()); + request.setFilter(new HashMap<>()); + + when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(), anyString(), anyObject())) + .thenReturn(new ArrayList<>()); + + ResponseEntity response1Obj = vulnerabilityController.getVulnerabilityTrend(request); + assertTrue(response1Obj.getStatusCode() == HttpStatus.OK); + + Map filter = new HashMap<>(); + filter.put("severity", "3"); + request.setFilter(filter); + when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(), anyString(), anyObject())) + .thenReturn(new ArrayList<>()); + + ResponseEntity response2Obj = vulnerabilityController.getVulnerabilityTrend(request); + assertTrue(response2Obj.getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulerabilityTrendTest_Failure() throws Exception { + + TrendRequest request = new TrendRequest(); + + ResponseEntity responseObj = vulnerabilityController.getVulnerabilityTrend(request); + assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + request.setAg("ag"); + when(vulnerabilityService.getVulnerabilityNewOpenTrend(anyString(), anyString(), anyObject())) + .thenThrow(new Exception()); + + ResponseEntity response1 = vulnerabilityController.getVulnerabilityTrend(request); + assertTrue(response1.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void createTrendAnnotationTest() throws Exception { + + when(vulnerabilityService.createTrendAnnotation(anyObject())).thenReturn(true); + assertTrue(vulnerabilityController.createTrendAnnotation(new TrendNote()).getStatusCode() == HttpStatus.OK); + + when(vulnerabilityService.createTrendAnnotation(anyObject())).thenReturn(false); + assertTrue(vulnerabilityController.createTrendAnnotation(new TrendNote()) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getTrendAnnotationsTest() throws Exception { + + when(vulnerabilityService.getTrendAnnotations(anyString(), any(Date.class))).thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getTrendAnnotations("ag", new Date()).getStatusCode() == HttpStatus.OK); + + when(vulnerabilityService.getTrendAnnotations(anyString(), any(Date.class))).thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityController.getTrendAnnotations("ag", null).getStatusCode() == HttpStatus.OK); + + when(vulnerabilityService.getTrendAnnotations(anyString(), any(Date.class))).thenThrow(new DataException()); + assertTrue(vulnerabilityController.getTrendAnnotations("ag", new Date()) + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void deleteTrendAnnotationTest() throws Exception { + + when(vulnerabilityService.deleteTrendAnnotation(anyString())).thenReturn(true); + assertTrue(vulnerabilityController.deleteTrendAnnotation("noteId").getStatusCode() == HttpStatus.OK); + + when(vulnerabilityService.deleteTrendAnnotation(anyString())).thenReturn(false); + assertTrue(vulnerabilityController.deleteTrendAnnotation("noteId") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilityAssetsTrendTest() throws Exception { + + TrendRequest request = new TrendRequest(); + request.setAg("ag"); + + when(vulnerabilityService.getVulnerabilityAssetsTrend(anyString(), anyString(), anyObject())) + .thenReturn(new ArrayList<>()); + + ResponseEntity responseObj = vulnerabilityController.getVulnerabilityAssetsTrend(request); + assertTrue(responseObj.getStatusCode() == HttpStatus.OK); + + request.setFrom(new Date()); + request.setFilter(new HashMap<>()); + + when(vulnerabilityService.getVulnerabilityAssetsTrend(anyString(), anyString(), anyObject())) + .thenReturn(new ArrayList<>()); + + ResponseEntity response1Obj = vulnerabilityController.getVulnerabilityAssetsTrend(request); + assertTrue(response1Obj.getStatusCode() == HttpStatus.OK); + + Map filter = new HashMap<>(); + filter.put("severity", "3"); + request.setFilter(filter); + when(vulnerabilityService.getVulnerabilityAssetsTrend(anyString(), anyString(), anyObject())) + .thenReturn(new ArrayList<>()); + + ResponseEntity response2Obj = vulnerabilityController.getVulnerabilityAssetsTrend(request); + assertTrue(response2Obj.getStatusCode() == HttpStatus.OK); + } + + @Test + public void getVulnerabilityAssetsTrendTest_Failure() throws Exception { + + TrendRequest request = new TrendRequest(); + + ResponseEntity responseObj = vulnerabilityController.getVulnerabilityAssetsTrend(request); + assertTrue(responseObj.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + + request.setAg("ag"); + when(vulnerabilityService.getVulnerabilityAssetsTrend(anyString(), anyString(), anyObject())) + .thenThrow(new DataException()); + + ResponseEntity response1 = vulnerabilityController.getVulnerabilityAssetsTrend(request); + assertTrue(response1.getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @Test + public void getVulnerabilitySummaryByAssetsTest() throws Exception { + + when(vulnerabilityService.getVulnerabilitySummaryByAssets(anyString())).thenReturn(new HashMap<>()); + assertTrue(vulnerabilityController.getVulnerabilitySummaryByAssets("ag").getStatusCode() == HttpStatus.OK); + + when(vulnerabilityService.getVulnerabilitySummaryByAssets(anyString())).thenThrow(new DataException()); + assertTrue(vulnerabilityController.getVulnerabilitySummaryByAssets("ag") + .getStatusCode() == HttpStatus.EXPECTATION_FAILED); + } + + @SuppressWarnings("unchecked") + @Test + public void getVulnerabilitiesOccurrencesTest() throws Exception { + + List> vulnDetails = new ArrayList<>(); + + Request request = new Request(); + request.setAg("ag"); + request.setFrom(0); + Map filter = new HashMap<>(); + filter.put("severity", "3"); + request.setFilter(filter); + + when(vulnerabilityService.vulnerabilityAssetCount(anyString(), anyMap(), anyString(),anyString(),anyInt(), anyInt())).thenReturn(10); + when(vulnerabilityService.getAllVulnerabilitiesDetailsByAssetGroup(anyString(), anyMap(),anyString(),anyString(),anyString(), anyInt(), anyInt())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesOccurrences(request) + .getStatusCode() == HttpStatus.OK); + + request.setFilter(new HashMap<>()); + vulnDetails.add(new HashMap<>()); + vulnDetails.add(new HashMap<>()); + + when(vulnerabilityService.vulnerabilityAssetCount(anyString(), anyMap(),anyString(),anyString() ,anyInt(), anyInt())).thenReturn(10); + when(vulnerabilityService.getAllVulnerabilitiesDetailsByAssetGroup(anyString(), anyMap(),anyString(),anyString(),anyString(), anyInt(), anyInt())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesOccurrences(request) + .getStatusCode() == HttpStatus.OK); + + request.setSize(0); + when(vulnerabilityService.vulnerabilityAssetCount(anyString(), anyMap(),anyString(),anyString(), anyInt(), anyInt())).thenReturn(10); + when(vulnerabilityService.getAllVulnerabilitiesDetailsByAssetGroup(anyString(), anyMap(),anyString(),anyString(),anyString(), anyInt(), anyInt())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesOccurrences(request) + .getStatusCode() == HttpStatus.OK); + + request.setSize(3); + when(vulnerabilityService.vulnerabilityAssetCount(anyString(), anyMap(),anyString(),anyString(), anyInt(), anyInt())).thenReturn(10); + when(vulnerabilityService.getAllVulnerabilitiesDetailsByAssetGroup(anyString(), anyMap(), anyString(),anyString(),anyString(),anyInt(), anyInt())) + .thenReturn(vulnDetails); + + assertTrue(vulnerabilityController.getVulnerabilitiesOccurrences(request) + .getStatusCode() == HttpStatus.OK); + } +} diff --git a/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityRepositoryTest.java b/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityRepositoryTest.java new file mode 100644 index 000000000..82013fe86 --- /dev/null +++ b/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/repository/VulnerabilityRepositoryTest.java @@ -0,0 +1,783 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.repository; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.repo.ElasticSearchRepository; +import com.tmobile.pacman.api.commons.repo.PacmanRdsRepository; +import com.tmobile.pacman.api.commons.utils.PacHttpUtils; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ PacHttpUtils.class }) +public class VulnerabilityRepositoryTest { + + @InjectMocks + private VulnerabilityRepository vulnerabilityRepository; + + @Mock + private ElasticSearchRepository elasticSearchRepository; + + @Mock + private PacmanRdsRepository rdsRepository; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void getAllVulnerabilitiesTest() throws Exception { + + String response = "{\"hits\":{\"total\":68,\"hits\":[{\"_index\":\"qualys-kb\",\"_type\":\"kb\",\"_id\":\"2\",\"_score\":8.899231," + + "\"_source\":{\"qid\":\"2\",\"vulntype\":\"Vulnerability\",\"severitylevel\":4,\"title\":\"Red Hat Update for kernel\"," + + "\"category\":\"RedHat\",\"lastservicemodificationdatetime\":\"2018-05-29T20:32:16z\",\"publisheddatetime\":\"2018-01-04T04:02:43z\"," + + "\"_loadDate\":\"2018-07-09T14:23:27z\",\"latest\":true,\"classification\":\"OS\"}}]}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + when(elasticSearchRepository.processResponseAndSendTheScrollBack(anyString(), anyObject())) + .thenCallRealMethod(); + + List> vulnerabilities = vulnerabilityRepository.getAllVulnerabilities(new ArrayList<>()); + assertTrue(vulnerabilities.size() == 1); + } + + @Test + public void getAllVulnerabilitiesTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getAllVulnerabilities(new ArrayList<>())) + .isInstanceOf(DataException.class); + } + + @Test + public void getAssetsAffectedCountTest() throws Exception { + + String response = "{\"aggregations\":{\"qid\":{\"buckets\":[{\"key\":105130,\"doc_count\":871}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + Map filter = new HashMap<>(); + filter.put("tags.Application.keyword", "app"); + filter.put(Constants.SEVEITY_LEVEL, "3"); + + Map assetsAffected = vulnerabilityRepository.getAssetsAffectedCount("ag", filter, "parent"); + assertTrue(assetsAffected.size() == 1); + } + + @Test + public void getAssetsAffectedCountTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + Map assetsAffected = vulnerabilityRepository.getAssetsAffectedCount("ag", null, "parent"); + assertTrue(assetsAffected.size() == 0); + } + + @Test + public void getVulnerabilyAcrossAppAndEnvTest() throws Exception { + + String response = "{\"hits\":{\"total\":905},\"aggregations\":{\"apps\":{\"buckets\":[{\"key\":\"ag\",\"doc_count\":905," + + "\"vulns\":{\"doc_count\":5522,\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":556},\"S4\":{\"doc_count\":469},\"S5\":{\"doc_count\":86}}}}}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository + .getVulnerabilyAcrossAppAndEnv("ag", "tags.Application.keyword", "", "parent", "3").size() == 1); + assertTrue(vulnerabilityRepository + .getVulnerabilyAcrossAppAndEnv("ag", "tags.Environment.keyword", "app", "parent", "").size() == 1); + } + + @Test + public void getVulnerabilyAcrossAppAndEnvTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv("ag", "tags.Application.keyword", + "", "parent", "3")).isInstanceOf(Exception.class); + } + + @Test + public void getVulnerabilityTrendTest() throws Exception { + + String response = "{\"aggregations\":{\"date\":{\"buckets\":[{\"key_as_string\":\"2018-07-25\",\"key\":1532476800000," + + "\"doc_count\":51,\"vulns\":{\"value\":11126}}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + Map filter = new HashMap<>(); + filter.put("tags.Application.keyword", "app"); + filter.put("tags.Environment.keyword", "env"); + assertTrue(vulnerabilityRepository.getVulnerabilityTrend("ag", filter, new Date(), new Date()).size() == 1); + } + + @Test + public void getVulnerabilityTrendTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilityTrend("ag", null, null, null)) + .isInstanceOf(Exception.class); + + Map filter = new HashMap<>(); + filter.put("test", "test"); + assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilityTrend("ag", filter, new Date(), null)) + .isInstanceOf(Exception.class); + } + + @Test + public void getVulnerabilitiesDistributionTest() throws Exception { + + String response = "{\"aggregations\":{\"apps\":{\"doc_count_error_upper_bound\":0,\"sum_other_doc_count\":0," + + "\"buckets\":[{\"key\":\"ag\",\"doc_count\":90,\"envs\":{\"doc_count_error_upper_bound\":0,\"sum_other_doc_count\":0," + + "\"buckets\":[{\"key\":\"Production::prd\",\"doc_count\":32,\"vulns\":{\"doc_count\":2002," + + "\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":197},\"S4\":{\"doc_count\":164},\"S5\":{\"doc_count\":30}}}}}]}}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getVulnerabilitiesDistribution("ag", "parent").size() == 1); + } + + @Test + public void getVulnerabilitiesDistributionTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getVulnerabilitiesDistribution("ag", "parent")) + .isInstanceOf(Exception.class); + } + + @Test + public void getVulnerabilitysummaryByResourceIdTest() throws Exception { + + String response = "{\"hits\":{\"total\":518},\"aggregations\":{\"NAME\":{\"buckets\":{\"S3\":{\"doc_count\":556},\"S4\":{\"doc_count\":469},\"S5\":{\"doc_count\":86}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + assertTrue(vulnerabilityRepository.getVulnerabilitysummaryByResourceId("resource").size() == 2); + } + + @Test + public void getVulnerabilitysummaryByResourceIdTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + assertTrue(vulnerabilityRepository.getVulnerabilitysummaryByResourceId("resource").size() == 0); + } + + @Test + public void fetchExecDirectorAppsTest() throws Exception { + + when(elasticSearchRepository.getDataFromES(anyString(), anyString(), anyObject(), anyObject(), anyObject(), + anyObject(), anyObject())).thenReturn(new ArrayList<>()); + assertThat(vulnerabilityRepository.fetchExecDirectorApps(), is(notNullValue())); + } + + @Test + public void getUniqueHostTest() throws Exception { + + String response = "{\"hits\":{\"total\":30056},\"aggregations\":{\"vulninfo\":{\"sev-filter\":{\"severity\":{\"buckets\":[" + + "{\"key\":4,\"unique-host\":{\"value\":25071}},{\"key\":3,\"unique-host\":{\"value\":23776}}," + + "{\"key\":5,\"unique-host\":{\"value\":19250}}]}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getUniqueHost("ag", "3,4,5").size() == 4); + } + + @Test + public void getUniqueHostTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getUniqueHost("ag", "3,4,5").size() == 0); + } + + @Test + public void getUniqueVulnTest() throws Exception { + + String response = "{\"aggregations\":{\"vulninfo\":{\"sev-filter\":{\"doc_count\":668732,\"severity\":{\"buckets\":[" + + "{\"key\":4,\"doc_count\":354352,\"unique-qid\":{\"value\":1377}},{\"key\":3,\"doc_count\":203380,\"unique-qid\":{\"value\":1868}}," + + "{\"key\":5,\"doc_count\":111000,\"unique-qid\":{\"value\":555}}]}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getVulnInfo("ag", "3,4,5").size() == 4); + } + + @Test + public void getUniqueVulnTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getVulnInfo("ag", "3,4,5").size() == 0); + } + + @Test + public void getUniqueAppTest() throws Exception { + + String response = "{\"aggregations\":{\"severity\":{\"buckets\":{\"S3\":{\"doc_count\":871,\"NAME\":{\"value\":1}}," + + "\"S4\":{\"doc_count\":871,\"NAME\":{\"value\":1}},\"S5\":{\"doc_count\":844,\"NAME\":{\"value\":1}}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getUniqueApp("ag").size() == 3); + } + + @Test + public void getUniqueAppTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + assertTrue(vulnerabilityRepository.getUniqueApp("ag").size() == 0); + } + + @Test + public void getAgingSummaryTest() throws Exception { + + String response = "{\"aggregations\":{\"severity\":{\"buckets\":[{\"key\":3,\"doc_count\":5581,\"aging\":{\"value\":53.36391327719047}}," + + "{\"key\":4,\"doc_count\":4704,\"aging\":{\"value\":41.863945578231295}},{\"key\":5,\"doc_count\":865,\"aging\":{\"value\":38.522543352601154}}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getAgingSummary("ag").size() == 3); + } + + @Test + public void getAgingSummaryTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + assertTrue(vulnerabilityRepository.getAgingSummary("ag").size() == 0); + } + + @Test + public void getTotalQualysHostCountTest() throws Exception { + + String response = "{\"count\":3}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getTotalQualysHostCount("ag", "parent") == 3); + } + + @Test + public void getTotalQualysHostCountTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getTotalQualysHostCount("ag", "parent")) + .isInstanceOf(DataException.class); + } + + @Test + public void getVulnerabilityByQidTest() throws Exception { + + String response = "{\"hits\":{\"total\":68,\"hits\":[{\"_index\":\"qualys-kb\",\"_type\":\"kb\",\"_id\":\"236591\",\"_score\":8.899231," + + "\"_source\":{\"qid\":\"236591\",\"vulntype\":\"Vulnerability\",\"severitylevel\":4,\"title\":\"Red Hat Update for kernel\"," + + "\"category\":\"RedHat\",\"lastservicemodificationdatetime\":\"2018-05-29T20:32:16z\",\"publisheddatetime\":\"2018-01-04T04:02:43z\"," + + "\"_loadDate\":\"2018-07-09T14:23:27z\",\"latest\":true,\"classification\":\"OS\"}}]}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThat(vulnerabilityRepository.getVulnerabilityByQid("qid"), is(notNullValue())); + } + + @Test + public void getVulnerabilityByQidTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getVulnerabilityByQid("ag").size() == 0); + } + + @Test + public void getDistributionSummaryByInfraTypeTest() throws Exception { + + String response = "{\"hits\":{\"total\":515,\"max_score\":0,\"hits\":[]},\"aggregations\":{\"NAME\":{\"doc_count\":32252," + + "\"NAME\":{\"doc_count\":6361,\"NAME\":{\"value\":37}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getDistributionSummaryByInfraType("ag", "", "parent").size() == 3); + } + + @Test + public void getDistributionSummaryByInfraTypeTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getDistributionSummaryByInfraType("ag", "3", "parent")) + .isInstanceOf(DataException.class); + } + + @Test + public void getProdInfoByEnvTest() throws Exception { + + String response = "{\"hits\":{\"total\":515,\"max_score\":0,\"hits\":[]},\"aggregations\":{\"NAME\":{\"doc_count\":32252," + + "\"NAME\":{\"doc_count\":6361,\"NAME\":{\"value\":37}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getProdInfoByEnv("ag", "").size() == 3); + } + + @Test + public void getProdInfoByEnvTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getProdInfoByEnv("ag", "3").size() == 0); + } + + @Test + public void getNonProdInfoByEnvTest() throws Exception { + + String response = "{\"hits\":{\"total\":515,\"max_score\":0,\"hits\":[]},\"aggregations\":{\"NAME\":{\"doc_count\":32252," + + "\"NAME\":{\"doc_count\":6361,\"NAME\":{\"value\":37}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getNonProdInfoByEnv("ag", "").size() == 3); + } + + @Test + public void getNonProdInfoByEnvTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getNonProdInfoByEnv("ag", "3").size() == 0); + } + + @Test + public void getDistributionSummaryByVulnTypeTest() throws Exception { + + String response1 = "{\"aggregations\":{\"vulninfo\":{\"doc_count\":126339,\"sev-filter\":" + + "{\"doc_count\":104821,\"classification\":{\"buckets\":[{\"key\":\"OS\",\"doc_count\":94207,\"resources\":{\"value\":4219}}," + + "{\"key\":\"Application\",\"doc_count\":10614,\"resources\":{\"value\":1869}}]}}}}}"; + + String response2 = "{\"aggregations\":{\"vulninfo\":{\"doc_count\":126339,\"sev-filter\":" + + "{\"doc_count\":104821,\"classification\":{\"buckets\":[{\"key\":\"OS\",\"doc_count\":94207,\"unique-qid\":{\"value\":1156}}," + + "{\"key\":\"Application\",\"doc_count\":10614,\"unique-qid\":{\"value\":428}}]}}}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response1, response2); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getDistributionSummaryByVulnType("ag", "").size() == 2); + } + + @Test + public void getDistributionSummaryByVulnTypeTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getDistributionSummaryByVulnType("ag", "3")) + .isInstanceOf(DataException.class); + } + + @Test + public void getAllQidByAGTest() throws Exception { + + String response = "{\"aggregations\":{\"qid\":{\"buckets\":[{\"key\":\"105130~unix group list~OS\",\"doc_count\":873}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getAllQidByAG("ag", "").size() == 1); + } + + @Test + public void getAllQidByAGTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getAllQidByAG("ag", "3")).isInstanceOf(DataException.class); + } + + @Test + public void getAppsBySeverityTest() throws Exception { + + String response = "{\"aggregations\":{\"apps\":{\"buckets\":[{\"key\":\"ag\",\"doc_count\":905," + + "\"vulns\":{\"doc_count\":55283,\"NAME\":{\"buckets\":{\"severity\":{\"doc_count\":12242}}}}}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getAppsBySeverity("ag", "parent", "").size() == 1); + } + + @Test + public void getAppsBySeverityTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getAppsBySeverity("ag", "parent", "3")) + .isInstanceOf(Exception.class); + } + + @Test + public void getTrendAnnotationsTest() throws Exception { + + String response = "{\"hits\":{\"total\":68,\"hits\":[{\"_index\":\"assetgroup_annotations\",\"_type\":\"annotations\",\"_id\":\"20180722\"," + + "\"_source\":{\"date\":\"2018-07-22\",\"note\":\"Test global\",\"ag\":\"\",\"noteId\":\"20180722\"}}]}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getTrendAnnotations("ag", new Date()).size() == 1); + } + + @Test + public void getTrendAnnotationsTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getTrendAnnotations("ag", new Date()).size() == 0); + } + + @Test + public void getDataFromPacmanRDSTest() throws Exception { + + when(rdsRepository.getDataFromPacman(anyString())).thenReturn(new ArrayList<>()); + assertTrue(vulnerabilityRepository.getDataFromPacmanRDS("query").size() == 0); + } + + @Test + public void getRunningInstancesCountTest() throws Exception { + + String response = "{\"count\":3}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getRunningInstancesCount("ag", "ec2") == 3); + assertTrue(vulnerabilityRepository.getRunningInstancesCount("ag", "onprem") == 3); + + } + + @Test + public void getRunningInstancesCountTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getRunningInstancesCount("ag", "ec2")) + .isInstanceOf(DataException.class); + } + + @Test + public void getExemptedByRuleCountTest() throws Exception { + + String response = "{\"count\":3}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getExemptedByRuleCount("ag", "ec2") == 3); + assertTrue(vulnerabilityRepository.getExemptedByRuleCount("ag", "onprem") == 3); + + } + + @Test + public void getExemptedByRuleCountTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getExemptedByRuleCount("ag", "ec2")) + .isInstanceOf(DataException.class); + } + + @Test + public void getUniqueHostBySeverityTest() throws Exception { + + String response = "{\"aggregations\":{\"severity\":{\"buckets\":[{\"key\":4,\"doc_count\":320}," + + "{\"key\":3,\"doc_count\":294},{\"key\":5,\"doc_count\":71}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getUniqueHostBySeverity("ag", "3").size() == 3); + + } + + @Test + public void getUniqueHostBySeverityTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getUniqueHostBySeverity("ag", "3")) + .isInstanceOf(DataException.class); + } + + @Test + public void getCompliantHostsBySeverityTest() throws Exception { + + String response1 = "{\"aggregations\":{\"severity\":{\"buckets\":[{\"key\":4,\"doc_count\":320}," + + "{\"key\":3,\"doc_count\":294},{\"key\":5,\"doc_count\":71}]}}}"; + String response2 = "{\"aggregations\":{\"resourceid\":{\"buckets\":[{\"key\":\"123\"},{\"key\":\"456\"}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response2, response1); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertTrue(vulnerabilityRepository.getCompliantHostsBySeverity("ag").size() == 3); + + } + + @Test + public void getCompliantHostsBySeverityTest_Exception() throws Exception { + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenThrow(new Exception()); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + + assertThatThrownBy(() -> vulnerabilityRepository.getCompliantHostsBySeverity("ag")) + .isInstanceOf(DataException.class); + } + + @SuppressWarnings("deprecation") + @Test + public void fetchOrgInfoForAppsTest() throws Exception { + + when(elasticSearchRepository.getDataFromES(anyString(), anyString(), anyObject(), anyObject(), anyObject(), + anyObject(), anyObject())).thenReturn(new ArrayList<>()); + assertThat(vulnerabilityRepository.fetchOrgInfoForApps().size(), is(0)); + } + + @Test + public void vulnerabilityAssetsCountTest() throws Exception { + List> results = new ArrayList>(); + Map map = new HashMap(); + Map map1 = new HashMap(); + map.put("ac", "66"); + map.put("acname", "second"); + map.put("res", "int"); + map.put("vp", "brt3"); + map.put("geid", "amigo"); + map1.put("rr", "345"); + map1.put("fd", "sec"); + map1.put("ij", "i"); + map1.put("cid", "b3"); + map1.put("mad", "mi"); + results.add(map); + results.add(map1); + + String assetGroup = "abc"; + Map mustFilter = new HashMap<>(); + Map mustTermsFilter = new HashMap<>(); + mustFilter.put("latest", "true"); + String targetType = "vulninfo"; + int from = 0; + int size = 0; + + String response1 = "{\"aggregations\":{\"severity\":{\"buckets\":[{\"key\":4,\"doc_count\":320}," + + "{\"key\":3,\"doc_count\":294},{\"key\":5,\"doc_count\":71}]}}}"; + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response1); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + when(elasticSearchRepository.getSortedDataFromES(anyString(), anyString(), anyObject(), anyObject(), + anyObject(), anyObject(), anyObject(), anyObject())).thenReturn(results); + assertThat(vulnerabilityRepository.vulnerabilityAssetsCount(assetGroup, targetType, mustFilter, from, size,mustTermsFilter), + is(2)); + } + + @Test + public void getAllVulnerabilitiesByAssetGroupTest() throws Exception { + List> results = new ArrayList>(); + Map map = new HashMap(); + Map map1 = new HashMap(); + map.put("ac", "66"); + map.put("acname", "second"); + map.put("res", "int"); + map.put("vp", "brt3"); + map.put("geid", "amigo"); + map1.put("rr", "345"); + map1.put("fd", "sec"); + map1.put("ij", "i"); + map1.put("cid", "b3"); + map1.put("mad", "mi"); + results.add(map); + results.add(map1); + + List occurrenceFieldList = new ArrayList(); + String assetGroup = "abc"; + Map mustFilter = new HashMap<>(); + Map mustTermsFilter = new HashMap<>(); + mustFilter.put("latest", "true"); + String targetType = "vulninfo"; + int from = 0; + int size = 5; + String response1 = "{\"aggregations\":{\"severity\":{\"buckets\":[{\"key\":4,\"doc_count\":320}," + + "{\"key\":3,\"doc_count\":294},{\"key\":5,\"doc_count\":71}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response1); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + when(elasticSearchRepository.getSortedDataFromESBySize(anyString(), anyString(), anyObject(), anyObject(), + anyObject(), anyObject(), anyInt(), anyInt(), anyObject(), anyObject(), anyObject())) + .thenReturn(results); + assertThat(vulnerabilityRepository + .getAllVulnerabilitiesByAssetGroup(assetGroup, targetType, mustFilter, occurrenceFieldList, from, size,mustTermsFilter) + .size(), is(2)); + size = 0; + + when(elasticSearchRepository.getSortedDataFromES(anyString(), anyString(), anyObject(), anyObject(), + anyObject(), anyObject(), anyObject(), anyObject())).thenReturn(results); + assertThat(vulnerabilityRepository + .getAllVulnerabilitiesByAssetGroup(assetGroup, targetType, mustFilter, occurrenceFieldList, from, size,mustTermsFilter) + .size(), is(2)); + } + + @Test + public void getDetailsByResourceIdTest() throws Exception { + List> results = new ArrayList>(); + Map map = new HashMap(); + Map map1 = new HashMap(); + map.put("ac", "66"); + map.put("acname", "second"); + map.put("res", "int"); + map.put("vp", "brt3"); + map.put("geid", "amigo"); + map1.put("rr", "345"); + map1.put("fd", "sec"); + map1.put("ij", "i"); + map1.put("cid", "b3"); + map1.put("mad", "mi"); + results.add(map); + results.add(map1); + + List occurrenceFieldList = new ArrayList(); + String assetGroup = "abc"; + Map mustFilter = new HashMap<>(); + mustFilter.put("latest", "true"); + String response1 = "{\"aggregations\":{\"severity\":{\"buckets\":[{\"key\":4,\"doc_count\":320}," + + "{\"key\":3,\"doc_count\":294},{\"key\":5,\"doc_count\":71}]}}}"; + + mockStatic(PacHttpUtils.class); + when(PacHttpUtils.doHttpPost(anyString(), anyString())).thenReturn(response1); + ReflectionTestUtils.setField(vulnerabilityRepository, "esUrl", "dummyEsURL"); + when(elasticSearchRepository.getSortedDataFromES(anyString(), anyString(), anyObject(), anyObject(), + anyObject(), anyObject(), anyObject(), anyObject())).thenReturn(results); + assertThat(vulnerabilityRepository + .getDetailsByResourceId(assetGroup, mustFilter, occurrenceFieldList, mustFilter).size(), is(2)); + + } + +} diff --git a/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/service/VulnerabilityServiceTest.java b/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/service/VulnerabilityServiceTest.java new file mode 100644 index 000000000..cc1648e95 --- /dev/null +++ b/api/pacman-api-vulnerability/src/test/java/com/tmobile/pacman/api/vulnerability/service/VulnerabilityServiceTest.java @@ -0,0 +1,983 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.pacman.api.vulnerability.service; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyList; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.http.ResponseEntity; +import org.springframework.test.util.ReflectionTestUtils; + +import com.tmobile.pacman.api.commons.Constants; +import com.tmobile.pacman.api.commons.exception.DataException; +import com.tmobile.pacman.api.commons.exception.ServiceException; +import com.tmobile.pacman.api.commons.utils.CommonUtils; +import com.tmobile.pacman.api.commons.utils.ResponseUtils; +import com.tmobile.pacman.api.vulnerability.client.AssetServiceClient; +import com.tmobile.pacman.api.vulnerability.client.ComplianceServiceClient; +import com.tmobile.pacman.api.vulnerability.domain.AssetApi; +import com.tmobile.pacman.api.vulnerability.domain.AssetApiData; +import com.tmobile.pacman.api.vulnerability.domain.AssetCount; +import com.tmobile.pacman.api.vulnerability.domain.AssetCountByAppEnvDTO; +import com.tmobile.pacman.api.vulnerability.domain.AssetCountDTO; +import com.tmobile.pacman.api.vulnerability.domain.AssetCountData; +import com.tmobile.pacman.api.vulnerability.domain.Request; +import com.tmobile.pacman.api.vulnerability.domain.ResponseWithOrder; +import com.tmobile.pacman.api.vulnerability.domain.TrendNote; +import com.tmobile.pacman.api.vulnerability.repository.VulnerabilityRepository; +import com.tmobile.pacman.api.vulnerability.repository.VulnerabilityTrendGenerator; + +@RunWith(PowerMockRunner.class) +public class VulnerabilityServiceTest { + + @InjectMocks + VulnerabilityService vulnerabilityService; + + @Mock + VulnerabilityRepository vulnerabilityRepository; + + @Mock + AssetServiceClient assetServiceClient; + + @Mock + VulnerabilityTrendGenerator vulnTrendGenerator; + + @Mock + ComplianceServiceClient complianceServiceClient; + + @Mock + CommonUtils commonUtils; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + AssetApi assetApi = new AssetApi(); + AssetApiData data = new AssetApiData(); + + List ttypes = new ArrayList<>(); + AssetCountDTO tt = new AssetCountDTO(); + tt.setType("ec2"); + ttypes.add(tt); + tt = new AssetCountDTO(); + tt.setType("onpremserver"); + ttypes.add(tt); + + data.setTargettypes(ttypes.toArray(new AssetCountDTO[ttypes.size()])); + assetApi.setData(data); + + when(assetServiceClient.getTargetTypeList(anyString(), anyObject())).thenReturn(assetApi); + } + + @Test + public void getVulnerabilitiesDetailsTest() throws Exception { + + List> vulnerabilitiesData = new ArrayList<>(); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getAssetsAffectedCount(anyString(), anyObject(), anyString())) + .thenReturn(new HashMap<>()); + when(vulnerabilityRepository.getAllVulnerabilities(anyObject())).thenReturn(vulnerabilitiesData); + assertThat(vulnerabilityService.getVulnerabilitiesDetails("ag", null), is(notNullValue())); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); + assertThat(vulnerabilityService.getVulnerabilitiesDetails("ag", null), is(notNullValue())); + + Map vuln = new HashMap<>(); + vuln.put("qid", "123"); + vuln.put("assetsAffected", 1); + vuln.put(Constants.TITLE, "test"); + vuln.put(Constants.SEVEITY_LEVEL, "3"); + vuln.put(Constants.CATEGORY, "test"); + vuln.put(Constants.VULN_TYPE, "type"); + vuln.put(Constants.PATCHABLE, "1"); + vulnerabilitiesData.add(vuln); + + vuln = new HashMap<>(); + vuln.put("qid", "456"); + vuln.put("assetsAffected", 2); + vuln.put(Constants.TITLE, "test"); + vuln.put(Constants.SEVEITY_LEVEL, "5"); + vuln.put(Constants.CATEGORY, "test"); + vuln.put(Constants.VULN_TYPE, "type"); + vuln.put(Constants.PATCHABLE, "0"); + vulnerabilitiesData.add(vuln); + + vuln = new HashMap<>(); + vuln.put("qid", "789"); + vuln.put("assetsAffected", 2); + vuln.put(Constants.TITLE, "test"); + vuln.put(Constants.SEVEITY_LEVEL, "5"); + vuln.put(Constants.CATEGORY, "test"); + vuln.put(Constants.VULN_TYPE, "type"); + vulnerabilitiesData.add(vuln); + + Map assetsAffected = new HashMap(); + assetsAffected.put("123", 10L); + assetsAffected.put("456", 10L); + assetsAffected.put("789", 10L); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); + when(vulnerabilityRepository.getAssetsAffectedCount(anyString(), anyObject(), anyString())) + .thenReturn(assetsAffected); + when(vulnerabilityRepository.getAllVulnerabilities(anyObject())).thenReturn(vulnerabilitiesData); + assertThat(vulnerabilityService.getVulnerabilitiesDetails("ag", null), is(notNullValue())); + } + + @Test + public void getVulnerabilitiesDetailsTest_Exception() throws Exception { + + when(vulnerabilityRepository.getAssetsAffectedCount(anyString(), anyObject(), anyString())) + .thenReturn(new HashMap<>()); + when(vulnerabilityRepository.getAllVulnerabilities(anyObject())).thenThrow(new DataException()); + assertThatThrownBy(() -> vulnerabilityService.getVulnerabilitiesDetails("ag", null)) + .isInstanceOf(Exception.class); + } + + @Test + public void getVulnerabilitySummaryTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); + assertThat(vulnerabilityService.getVulnerabilitySummary("ag", "3,4,5"), is(notNullValue())); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getUniqueHost(anyString(), anyString())).thenReturn(new HashMap()); + when(vulnerabilityRepository.getVulnInfo(anyString(), anyString())).thenReturn(new HashMap()); + when(vulnerabilityRepository.getUniqueApp(anyString())).thenReturn(new HashMap()); + + AssetCount totalAssets = new AssetCount(); + AssetCountData data = new AssetCountData(); + + AssetCountByAppEnvDTO assetCount_Count = new AssetCountByAppEnvDTO(); + assetCount_Count.setType("onpremserver"); + assetCount_Count.setCount("1"); + + List assetAppEnvDTOs = new ArrayList(); + assetAppEnvDTOs.add(assetCount_Count); + data.setAssetcount(assetAppEnvDTOs.toArray(new AssetCountByAppEnvDTO[assetAppEnvDTOs.size()])); + totalAssets.setData(data); + + List> response = new ArrayList<>(); + LinkedHashMap obj = new LinkedHashMap<>(); + obj.put("assetsScanned", 5); + obj.put("failed", 2); + obj.put("passed", 2); + response.add(obj); + Map responseMap = new HashMap<>(); + responseMap.put("response", response); + ResponseEntity nonCompliancePolicyRuleresponse = ResponseUtils.buildSucessResponse(responseMap); + + when(complianceServiceClient.getNonCompliancePolicyByRule(any(Request.class))) + .thenReturn(nonCompliancePolicyRuleresponse); + when(vulnerabilityRepository.getTotalQualysHostCount(anyString(), anyString())).thenReturn(1L); + ReflectionTestUtils.setField(vulnerabilityService, "vulnSummarySeverity", "3"); + + Map vulnSummary = new HashMap<>(); + List> severityInfo = new ArrayList<>(); + Map severity = new HashMap<>(); + severity.put(Constants.SEVEITY_LEVEL, 3); + severity.put(Constants.COUNT, 2); + severity.put(Constants.VULN_COUNT, 2); + severityInfo.add(severity); + severity = new HashMap<>(); + severity.put(Constants.SEVEITY_LEVEL, 4); + severity.put(Constants.COUNT, 2); + severity.put(Constants.VULN_COUNT, 2); + severityInfo.add(severity); + severity = new HashMap<>(); + severity.put(Constants.SEVEITY_LEVEL, 5); + severity.put(Constants.COUNT, 2); + severity.put(Constants.VULN_COUNT, 2); + severityInfo.add(severity); + + vulnSummary.put("severityInfo", severityInfo); + assertThat(vulnerabilityService.getVulnerabilitySummary("ag", "3,4,5"), is(notNullValue())); + + Map uniqueHost = new HashMap<>(); + uniqueHost.put("total", 10); + uniqueHost.put("3", 1); + Map vulnInfo = new HashMap<>(); + Map vulnInfoMap = new HashMap<>(); + vulnInfoMap.put(Constants.VULN_COUNT, 2); + vulnInfoMap.put(Constants.UNIQUE_VULN_COUNT, 2); + vulnInfo.put("total", 10); + vulnInfo.put("3", vulnInfoMap); + Map uniqueApp = new HashMap<>(); + uniqueApp.put("3", 1); + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); + when(vulnerabilityRepository.getUniqueHost(anyString(), anyString())).thenReturn(uniqueHost); + when(vulnerabilityRepository.getVulnInfo(anyString(), anyString())).thenReturn(vulnInfo); + when(vulnerabilityRepository.getUniqueApp(anyString())).thenReturn(uniqueApp); + + when(complianceServiceClient.getNonCompliancePolicyByRule(any(Request.class))) + .thenReturn(nonCompliancePolicyRuleresponse); + // when(complianceService.getRulecompliance(any(Request.class))).thenReturn(responseWithOrder); + when(assetServiceClient.getTotalAssetsCount(anyString(), anyString(), anyString())).thenReturn(totalAssets); + when(vulnerabilityRepository.getTotalQualysHostCount(anyString(), anyString())).thenReturn(1L); + ReflectionTestUtils.setField(vulnerabilityService, "vulnSummarySeverity", "3"); + + vulnSummary.put("severityInfo", severityInfo); + + assertThat(vulnerabilityService.getVulnerabilitySummary("ag", "3"), is(notNullValue())); + + } + + /** + * commenting this test case as we moved this method to the compliance service. + * + * @throws Exception + */ + @Test + public void getVulnerabilitySummaryTest_Exception() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getUniqueHost(anyString(), anyString())).thenReturn(new HashMap()); + when(vulnerabilityRepository.getVulnInfo(anyString(), anyString())).thenReturn(new HashMap()); + when(vulnerabilityRepository.getUniqueApp(anyString())).thenReturn(new HashMap()); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnSummarySeverity", "3"); + + ResponseWithOrder responseWithOrder = new ResponseWithOrder(); + List> response = new ArrayList<>(); + LinkedHashMap obj = new LinkedHashMap<>(); + obj.put("assetsScanned", 1); + obj.put("passed", 1); + response.add(obj); + responseWithOrder.setResponse(response); + + Map responseTest = new HashMap(); + responseTest.put(Constants.DATA_KEY, responseWithOrder); + responseTest.put(Constants.STATUS_KEY, Constants.STATUS_SUCCESS); + ResponseEntity nonCompliancePolicyRuleresponse = ResponseEntity.ok().body((Object) responseTest); + + // when(complianceServiceClient.getNonCompliancePolicyByRule(any(Request.class))).thenReturn(nonCompliancePolicyRuleresponse); + // when(complianceServiceClient.getNonCompliancePolicyByRule(any(Request.class))).thenThrow(new + // ServiceException()); + // assertThatThrownBy( + // () -> + // vulnerabilityService.getVulnerabilitySummary("ag","3,4,5")).isInstanceOf(ServiceException.class); + } + + @Test + public void getVulnerabilityByAppAndEnvTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv(anyString(), anyObject(), anyString(), anyString(), + anyString())).thenReturn(new ArrayList<>()); + assertThat(vulnerabilityService.getVulnerabilityByAppAndEnv("ag", "filter", "app"), is(notNullValue())); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); + assertThat(vulnerabilityService.getVulnerabilityByAppAndEnv("ag", "filter", "app").size(), is(0)); + } + + @Test + public void getVulnerabilityTrendTest() throws Exception { + + when(vulnerabilityRepository.getVulnerabilityTrend(anyString(), anyObject(), anyObject(), anyObject())) + .thenReturn(new ArrayList<>()); + assertThat(vulnerabilityService.getVulnerabilityTrend("ag", null, new Date(), new Date()), is(notNullValue())); + } + + /*@Test + public void getVulnerabilityNewOpenTrendTest() throws Exception { + + when(vulnTrendGenerator.generateTrend(anyString(), anyString(), anyObject())).thenReturn(new ArrayList<>()); + assertThat(vulnerabilityService.getVulnerabilityNewOpenTrend("ag", "sev", new Date()), is(notNullValue())); + }*/ + + @Test + public void getVulnerabilitiesDistributionTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getVulnerabilitiesDistribution(anyString(), anyString())) + .thenReturn(new ArrayList<>()); + assertThat(vulnerabilityService.getVulnerabilitiesDistribution("ag"), is(notNullValue())); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); + assertThat(vulnerabilityService.getVulnerabilitiesDistribution("ag").size(), is(0)); + } + + /* + * @SuppressWarnings("static-access") + * + * @Test public void filterMatchingCollectionElementsTest() throws Exception { + * + * when(commonUtils.filterMatchingCollectionElements(anyObject(), anyObject(), + * anyObject())).thenReturn(new Object()); + * assertThat(vulnerabilityService.filterMatchingCollectionElements(new + * ArrayList<>(),"sev",true), is(notNullValue())); } + */ + + @Test + public void getVulnerabilitysummaryByResourceIdTest() throws Exception { + + when(vulnerabilityRepository.getVulnerabilitysummaryByResourceId(anyString())).thenReturn(new HashMap<>()); + assertThat(vulnerabilityService.getVulnerabilitysummaryByResourceId("id"), is(notNullValue())); + } + + @Test + public void getVulnerabilityDetailsByResourceIdTest() throws Exception { + + List> vulnerabilitiesData = new ArrayList<>(); + + Map vuln = new HashMap<>(); + vuln.put("qid", "123"); + vuln.put("assetsAffected", 1); + vuln.put(Constants.TITLE, "test"); + vuln.put(Constants.SEVEITY_LEVEL, "3"); + vuln.put(Constants.CATEGORY, "test"); + vuln.put(Constants.VULN_TYPE, "type"); + vuln.put(Constants.PATCHABLE, "1"); + vulnerabilitiesData.add(vuln); + + when(vulnerabilityRepository.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(vulnerabilitiesData); + assertThat(vulnerabilityService.getVulnerabilityDetailsByResourceId("id"), is(notNullValue())); + + vuln = new HashMap<>(); + vuln.put("qid", "123"); + vuln.put("assetsAffected", 1); + vulnerabilitiesData.add(vuln); + + when(vulnerabilityRepository.getVulnerabilityDetailsByResourceId(anyString())).thenReturn(vulnerabilitiesData); + assertThatThrownBy(() -> vulnerabilityService.getVulnerabilityDetailsByResourceId("id")) + .isInstanceOf(Exception.class); + } + + @Test + public void getAgingSummaryTest() throws Exception { + + when(vulnerabilityRepository.getAgingSummary(anyString())).thenReturn(new ArrayList<>()); + assertThat(vulnerabilityService.getAgingSummary("ag"), is(notNullValue())); + } + + @Test + public void getVulnerabilityByQidTest() throws Exception { + + Map vuln = new HashMap<>(); + vuln.put("qid", "123"); + vuln.put("vulntype", "type"); + vuln.put("severitylevel", "3"); + vuln.put("title", "test"); + vuln.put("category", ""); + vuln.put("lastservicemodificationdatetime", "1234"); + vuln.put("publisheddatetime", "123"); + vuln.put("patchable", "1"); + Map softwarelist = new HashMap<>(); + List> softwares = new ArrayList<>(); + Map innerMap = new HashMap<>(); + innerMap.put("test", "test"); + innerMap.put("test", "test"); + softwares.add(innerMap); + softwarelist.put("software", softwares); + vuln.put("softwarelist", softwarelist); + Map vendorreferencelist = new HashMap<>(); + List> vendorreference = new ArrayList<>(); + vendorreference.add(innerMap); + vendorreferencelist.put("vendorreference", vendorreference); + vuln.put("vendorreferencelist", vendorreferencelist); + vuln.put("diagnosis", "test"); + vuln.put("consequence", "test"); + vuln.put("solution", "test"); + Map bugtraqlist = new HashMap<>(); + List> bugtraq = new ArrayList<>(); + bugtraq.add(innerMap); + bugtraqlist.put("vendorreference", bugtraq); + vuln.put("bugtraqlist", bugtraqlist); + vuln.put("pciflag", 0); + Map pcireasons = new HashMap<>(); + List> pcireason = new ArrayList<>(); + pcireason.add(innerMap); + pcireasons.put("pcireason", pcireason); + vuln.put("pcireasons", pcireasons); + Map authtypelist = new HashMap<>(); + List> authtype = new ArrayList<>(); + authtype.add(innerMap); + authtypelist.put("authtype", authtype); + Map discovery = new HashMap<>(); + discovery.put("authtypelist", authtypelist); + discovery.put("additionalinfo", "Patch Available"); + vuln.put("discovery", discovery); + vuln.put("supportedmodules", "test"); + Map cvelist = new HashMap<>(); + List> cve = new ArrayList<>(); + cve.add(innerMap); + cvelist.put("cve", cve); + vuln.put("cvelist", cvelist); + Map cvss = new HashMap<>(); + cvss.put("base", 1); + cvss.put("temporal", 1); + vuln.put("cvssv3", cvss); + Map access = new HashMap<>(); + access.put("vector", 1); + cvss.put("access", access); + vuln.put("cvss", cvss); + + when(vulnerabilityRepository.getVulnerabilityByQid(anyString())).thenReturn(vuln); + assertThat(vulnerabilityService.getVulnerabilityByQid("id"), is(notNullValue())); + + vuln = new HashMap<>(); + discovery = new HashMap<>(); + discovery.put("additionalinfo", "test"); + vuln.put("discovery", discovery); + vuln.put("pciflag", 1); + + when(vulnerabilityRepository.getVulnerabilityByQid(anyString())).thenReturn(vuln); + assertThat(vulnerabilityService.getVulnerabilityByQid("id"), is(notNullValue())); + + when(vulnerabilityRepository.getVulnerabilityByQid(anyString())).thenReturn(new HashMap<>()); + assertThat(vulnerabilityService.getVulnerabilityByQid("id"), is(notNullValue())); + } + + @Test + public void getHighestLowestPerformersTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "test"); + when(vulnerabilityRepository.fetchOrgInfoForApps()).thenReturn(fetchOrgInfoForApps()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", null, "org").size(), is(0)); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getAppsBySeverity(anyString(), anyString(), anyString())) + .thenReturn(new HashMap<>()); + when(vulnerabilityRepository.fetchOrgInfoForApps()).thenReturn(fetchOrgInfoForApps()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", null, "org").size(), is(0)); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); + Map apps = new HashMap<>(); + apps.put("app1", 1L); + apps.put("app2", 2L); + apps.put("app3", 3L); + when(vulnerabilityRepository.getAppsBySeverity(anyString(), anyString(), anyString())).thenReturn(apps); + when(vulnerabilityRepository.fetchOrgInfoForApps()).thenReturn(fetchOrgInfoForApps()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3", "org").size(), is(2)); + + when(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv(anyString(), anyString(), anyString(), anyString(), + anyString())).thenReturn(getVulnByApp()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3", Constants.APPLICATION).size(), is(2)); + + when(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv(anyString(), anyString(), anyString(), anyString(), + anyString())).thenReturn(getVulnByEnv()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3", Constants.ENVIRONMENT).size(), is(2)); + } + + @Test + public void getHighestLowestPerformersTest_Exception() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getAppsBySeverity(anyString(), anyString(), anyString())) + .thenReturn(new HashMap<>()); + when(vulnerabilityRepository.fetchOrgInfoForApps()).thenThrow(new Exception()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3", "org").size(), is(0)); + + when(vulnerabilityRepository.getAppsBySeverity(anyString(), anyString(), anyString())) + .thenThrow(new Exception()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3", "org").size(), is(0)); + + when(vulnerabilityRepository.getVulnerabilyAcrossAppAndEnv(anyString(), anyString(), anyString(), anyString(), + anyString())).thenThrow(new Exception()); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3", Constants.APPLICATION).size(), is(0)); + assertThat(vulnerabilityService.getHighestLowestPerformers("ag", "3", Constants.ENVIRONMENT).size(), is(0)); + } + + @Test + public void getDistributionSummaryByInfraTypeTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); + Map infraInfo = new HashMap<>(); + infraInfo.put(Constants.TOTAL_VULN_ASSETS, 1); + infraInfo.put(Constants.VULNEREBILITIES, 1); + infraInfo.put(Constants.UNIQUE_VULN_COUNT, 1); + when(vulnerabilityRepository.getDistributionSummaryByInfraType(anyString(), anyString(), anyString())) + .thenReturn(infraInfo); + assertThat(vulnerabilityService.getDistributionSummaryByInfraType("ag", null), is(notNullValue())); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getDistributionSummaryByInfraType(anyString(), anyString(), anyString())) + .thenReturn(infraInfo); + assertThat(vulnerabilityService.getDistributionSummaryByInfraType("ag", "3"), is(notNullValue())); + } + + @Test + public void getDistributionSummaryByInfraTypeTest_Exception() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getDistributionSummaryByInfraType(anyString(), anyString(), anyString())) + .thenThrow(new DataException()); + assertThatThrownBy(() -> vulnerabilityService.getDistributionSummaryByInfraType("ag", "3")) + .isInstanceOf(ServiceException.class); + } + + @Test + public void getDistributionSummaryByEnvTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); + + Map prodInfo = new HashMap<>(); + prodInfo.put("totalVulnerableAssets", 1L); + prodInfo.put(Constants.VULNEREBILITIES, 1L); + prodInfo.put("uniqueVulnCount", 1L); + + Map nonProdInfo = new HashMap<>(); + nonProdInfo.put("totalVulnerableAssets", 1L); + nonProdInfo.put(Constants.VULNEREBILITIES, 1L); + nonProdInfo.put("uniqueVulnCount", 1L); + + when(vulnerabilityRepository.getProdInfoByEnv(anyString(), anyString())).thenReturn(prodInfo); + when(vulnerabilityRepository.getNonProdInfoByEnv(anyString(), anyString())).thenReturn(nonProdInfo); + assertThat(vulnerabilityService.getDistributionSummaryByEnv("ag", "3"), is(notNullValue())); + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + + prodInfo = new HashMap<>(); + prodInfo.put("totalVulnerableAssets", 0L); + prodInfo.put(Constants.VULNEREBILITIES, 0L); + prodInfo.put("uniqueVulnCount", 0L); + + nonProdInfo = new HashMap<>(); + nonProdInfo.put("totalVulnerableAssets", 0L); + nonProdInfo.put(Constants.VULNEREBILITIES, 0L); + nonProdInfo.put("uniqueVulnCount", 0L); + + when(vulnerabilityRepository.getProdInfoByEnv(anyString(), anyString())).thenReturn(prodInfo); + when(vulnerabilityRepository.getNonProdInfoByEnv(anyString(), anyString())).thenReturn(nonProdInfo); + assertThat(vulnerabilityService.getDistributionSummaryByEnv("ag", ""), is(notNullValue())); + } + + @Test + public void getDistributionSummaryByEnvTest_Exception() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + Map prodInfo = new HashMap<>(); + prodInfo.put("totalVulnerableAssets", 1L); + prodInfo.put("uniqueVulnCount", 1L); + + Map nonProdInfo = new HashMap<>(); + nonProdInfo.put("totalVulnerableAssets", 1L); + nonProdInfo.put(Constants.VULNEREBILITIES, 1L); + nonProdInfo.put("uniqueVulnCount", 1L); + + when(vulnerabilityRepository.getProdInfoByEnv(anyString(), anyString())).thenReturn(prodInfo); + when(vulnerabilityRepository.getNonProdInfoByEnv(anyString(), anyString())).thenReturn(nonProdInfo); + assertThatThrownBy(() -> vulnerabilityService.getDistributionSummaryByEnv("ag", "3")) + .isInstanceOf(ServiceException.class); + } + + @Test + public void getDistributionSummaryByVulnTypeTest() throws Exception { + + when(vulnerabilityRepository.getDistributionSummaryByVulnType(anyString(), anyString())) + .thenReturn(new ArrayList<>()); + assertThat(vulnerabilityService.getDistributionSummaryByVulnType("ag", "3"), is(notNullValue())); + + when(vulnerabilityRepository.getDistributionSummaryByVulnType(anyString(), anyString())) + .thenReturn(new ArrayList<>()); + assertThat(vulnerabilityService.getDistributionSummaryByVulnType("ag", null), is(notNullValue())); + } + + @Test + public void getRemediationActionsSummaryTest() throws Exception { + + Map qids = new HashMap<>(); + qids.put("123~title~OS", 2); + qids.put("123~EOL/Obsolete~Infra", 2); + qids.put("11925~title~Infra", 2); + qids.put("370914~title~Infra", 2); + qids.put("123~Java Debug Wire Protocol~Infra", 0); + qids.put("123~Java JMX Server Insecure Configuration~Infra", 2); + qids.put("123~Java~Infra", 2); + qids.put("123~title~Infra", 2); + when(vulnerabilityRepository.getAllQidByAG(anyString(), anyString())).thenReturn(qids); + assertThat(vulnerabilityService.getRemediationActionsSummary("ag", null), is(notNullValue())); + } + + private List> getApps() { + + List> vulnApplications = new ArrayList<>(); + List> severityInfo = new ArrayList<>(); + + Map severity = new HashMap<>(); + severity.put(Constants.SEVERITY, "S3"); + severity.put(Constants.COUNT, 3); + severity.put("days", 3); + severityInfo.add(severity); + severity = new HashMap<>(); + severity.put(Constants.SEVERITY, "S4"); + severity.put(Constants.COUNT, 4); + severity.put("days", 4); + severityInfo.add(severity); + severity = new HashMap<>(); + severity.put(Constants.SEVERITY, "S5"); + severity.put(Constants.COUNT, 5); + severity.put("days", 5); + severityInfo.add(severity); + + Map vulnApp = new HashMap<>(); + vulnApp.put("application", "app1"); + vulnApp.put(Constants.SEV_INFO, severityInfo); + vulnApplications.add(vulnApp); + + vulnApp = new HashMap<>(); + vulnApp.put("application", "app2"); + vulnApp.put(Constants.SEV_INFO, severityInfo); + vulnApplications.add(vulnApp); + + vulnApp = new HashMap<>(); + vulnApp.put("application", "app3"); + vulnApp.put(Constants.SEV_INFO, severityInfo); + vulnApplications.add(vulnApp); + return vulnApplications; + } + + private List> getVulnByApp() { + + List> vulnEnvironments = new ArrayList<>(); + List> severityInfo = new ArrayList<>(); + + Map severity = new HashMap<>(); + severity.put("severitylevel", "3"); + severity.put("vulnInstanceCount", 3); + severityInfo.add(severity); + severity = new HashMap<>(); + + Map vulnApp = new HashMap<>(); + vulnApp.put("application", "app1"); + vulnApp.put(Constants.SEV_INFO, severityInfo); + vulnEnvironments.add(vulnApp); + + vulnApp = new HashMap<>(); + vulnApp.put("application", "app2"); + vulnApp.put(Constants.SEV_INFO, severityInfo); + vulnEnvironments.add(vulnApp); + + return vulnEnvironments; + } + + private List> getVulnByEnv() { + + List> vulnEnvironments = new ArrayList<>(); + List> severityInfo = new ArrayList<>(); + + Map severity = new HashMap<>(); + severity.put("severitylevel", "3"); + severity.put("vulnInstanceCount", 3); + severityInfo.add(severity); + severity = new HashMap<>(); + + Map vulnApp = new HashMap<>(); + vulnApp.put("environment", "env1"); + vulnApp.put(Constants.SEV_INFO, severityInfo); + vulnEnvironments.add(vulnApp); + + vulnApp = new HashMap<>(); + vulnApp.put("environment", "env2"); + vulnApp.put(Constants.SEV_INFO, severityInfo); + vulnEnvironments.add(vulnApp); + + return vulnEnvironments; + } + + private List> fetchOrgInfoForApps() { + List> apps = new ArrayList<>(); + Map app = new HashMap<>(); + app.put("appTag", "app1"); + app.put("list", "[{\"mgmntLevel\":\"2\",\"name\":\"svp1\"},{\"mgmntLevel\":\"3\",\"name\":\"vp1\"}]"); + apps.add(app); + + app = new HashMap<>(); + app.put("appTag", "app2"); + app.put("list", "[{\"mgmntLevel\":\"2\",\"name\":\"svp2\"},{\"mgmntLevel\":\"3\",\"name\":\"vp2\"}]"); + apps.add(app); + + app = new HashMap<>(); + app.put("appTag", "app3"); + app.put("list", "[{\"mgmntLevel\":\"4\",\"name\":\"sdir4\"}]"); + apps.add(app); + + app = new HashMap<>(); + app.put("appTag", "app5"); + app.put("list", "[{\"mgmntLevel\":\"2\",\"name\":\"svp5\"},{\"mgmntLevel\":\"5\",\"name\":\"dir5\"}]"); + apps.add(app); + + return apps; + } + + @Test + public void createTrendAnnotationTest() throws Exception { + + when(vulnerabilityRepository.createTrendAnnotation(any(TrendNote.class))).thenReturn(true); + assertThat(vulnerabilityService.createTrendAnnotation(new TrendNote()), is(true)); + } + + @Test + public void getTrendAnnotationTest() throws Exception { + + List> annotations = new ArrayList<>(); + Map annotation = new HashMap<>(); + annotation.put("ag", "ag"); + annotations.add(annotation); + + annotation = new HashMap<>(); + annotation.put("ag", ""); + annotations.add(annotation); + + when(vulnerabilityRepository.getTrendAnnotations(anyString(), any(Date.class))).thenReturn(annotations); + assertThat(vulnerabilityService.getTrendAnnotations("ag", new Date()).size(), is(2)); + } + + @Test + public void deleteTrendAnnotationTest() throws Exception { + + when(vulnerabilityRepository.deleteTrendAnnotation(anyString())).thenReturn(true); + assertThat(vulnerabilityService.deleteTrendAnnotation("noteId"), is(true)); + } + + @Test + public void getVulnerabilitySummaryByAssetsTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); + when(vulnerabilityRepository.getRunningInstancesCount(anyString(), anyString())).thenReturn(10L); + when(vulnerabilityRepository.getExemptedByRuleCount(anyString(), anyString())).thenReturn(1L); + + ResponseWithOrder responseWithOrder = new ResponseWithOrder(); + List> response = new ArrayList<>(); + LinkedHashMap obj = new LinkedHashMap<>(); + obj.put("assetsScanned", 5); + obj.put("failed", 2); + obj.put("passed", 2); + response.add(obj); + responseWithOrder.setResponse(response); + Map responseMap = new HashMap<>(); + responseMap.put("response", response); + ResponseEntity nonCompliancePolicyRuleresponse = ResponseUtils.buildSucessResponse(responseMap); + + when(complianceServiceClient.getNonCompliancePolicyByRule(any(Request.class))) + .thenReturn(nonCompliancePolicyRuleresponse); + // when(complianceServiceClient.getRulecompliance(any(Request.class))).thenReturn(responseWithOrder); + + Map compliant = new HashMap<>(); + compliant.put("S3", 2); + compliant.put("S4", 2); + + Map nonCompliant = new HashMap<>(); + nonCompliant.put("S3", 3); + nonCompliant.put("S4", 2); + nonCompliant.put("S5", 1); + + when(vulnerabilityRepository.getNonCompliantResourceIds(anyString())).thenReturn(new ArrayList<>()); + when(vulnerabilityRepository.getCompliantHostsBySeverity(anyString())).thenReturn(compliant); + when(vulnerabilityRepository.getUniqueHostBySeverity(anyString(), anyString())).thenReturn(nonCompliant); + + assertThat(vulnerabilityService.getVulnerabilitySummaryByAssets("ag").get(Constants.COUNT), is(20L)); + } + + @Test + public void getVulnerabilitySummaryByAssetsTest_Exception() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.getRunningInstancesCount(anyString(), anyString())).thenThrow(new DataException()); + assertThatThrownBy(() -> vulnerabilityService.getVulnerabilitySummaryByAssets("ag")) + .isInstanceOf(ServiceException.class); + } + + /*@Test + public void getVulnerabilityAssetsTrendTest() throws Exception { + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2,onpremserver"); + List assets = Arrays.asList("2018-10-01"); + when(vulnTrendGenerator.fetchAssetsDateRangesForEc2(anyString(), any(LocalDate.class))).thenReturn(assets); + when(vulnTrendGenerator.fetchAssetsDateRangesOnPrem(anyString(), any(LocalDate.class))).thenReturn(assets); + + assertThat(vulnerabilityService.getVulnerabilityAssetsTrend("ag", "3", new Date()).get(0).get("totalAssets"), + is(2L)); + + when(vulnTrendGenerator.fetchAssetsDateRangesForEc2(anyString(), any(LocalDate.class))) + .thenThrow(new DataException()); + when(vulnTrendGenerator.fetchAssetsDateRangesOnPrem(anyString(), any(LocalDate.class))) + .thenThrow(new DataException()); + + assertThat(vulnerabilityService.getVulnerabilityAssetsTrend("ag", "3", new Date()).size(), is(0)); + }*/ + + @SuppressWarnings("unchecked") + @Test + public void vulnerabilityAssetCountTest() throws Exception { + + Map mustFilterMap = new HashMap<>(); + mustFilterMap.put("latest", "true"); + mustFilterMap.put("entity", "true"); + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + when(vulnerabilityRepository.vulnerabilityAssetsCount(anyString(), anyString(), anyMap(), anyInt(), anyInt(), + anyMap())).thenReturn(5); + assertThat(vulnerabilityService.vulnerabilityAssetCount("ag", mustFilterMap, "pac", "pro", 0, 0), is(5)); + } + + @SuppressWarnings("unchecked") + @Test + public void getAllVulnerabilitiesDetailsByAssetGroupTest() throws Exception { + + List> vulnerabilitiesDetails = new ArrayList>(); + Map map = new HashMap(); + Map map1 = new HashMap(); + Map mapf = new HashMap(); + map.put("ac", "66"); + map.put("acname", "second"); + map.put("res", "int"); + map.put("vp", "brt3"); + map.put("geid", "amigo"); + map1.put("rr", "345"); + map1.put("fd", "sec"); + map1.put("ij", "i"); + map1.put("cid", "b3"); + map1.put("mad", "mi"); + vulnerabilitiesDetails.add(map); + vulnerabilitiesDetails.add(map1); + + List> resourceIdDetails = new ArrayList>(); + List> abc = new ArrayList>(); + Map map2 = new HashMap(); + Map map3 = new HashMap(); + map2.put("s", "s3445"); + map2.put("ced", "866"); + map2.put("cif=", "1"); + map2.put("lna", "21.0"); + map2.put("cat", "pp"); + map3.put("ver", "fr"); + map3.put("ed", "cd85"); + map3.put("ifl=", "1"); + map3.put("ule", "2261.0"); + map3.put("sif", "app7"); + resourceIdDetails.add(map2); + resourceIdDetails.add(map3); + String assetGroup = "abc"; + Map mustFilter = new HashMap<>(); + Map mustTermsFilter = new HashMap<>(); + mustFilter.put("latest", "true"); + String targetType = "vulninfo"; + String searchText = ""; + int from = 0; + int size = 0; + List occurrenceFieldList = null; + + ReflectionTestUtils.setField(vulnerabilityService, "vulnTypes", "ec2"); + ReflectionTestUtils.setField(vulnerabilityService, "vulnOccurrenceFields", + "severity,_resourceid,pciflag,_vulnage,vulntype,title,classification,_status,qid,patchable,category"); + ReflectionTestUtils.setField(vulnerabilityService, "vulnResourceIdFields", + "tags.Name,accountid,accountname,tags.Environment,tags.Application,privateipaddress,instanceid,region,availabilityzone,imageid,platform,privatednsname,instancetype,subnetid,_resourceid,publicipaddress,publicdnsname,vpcid"); + ReflectionTestUtils.setField(vulnerabilityService, "vulnResourceIdFieldsBoth", + "tags.Name,accountid,accountname,tags.Environment,tags.Application,privateipaddress,instanceid,region,availabilityzone,imageid,platform,privatednsname,instancetype,subnetid,_resourceid,publicipaddress,publicdnsname,vpcid"); + when(vulnerabilityRepository.getAllVulnerabilitiesByAssetGroup(assetGroup, targetType, mustFilter, + occurrenceFieldList, from, size, mustTermsFilter)).thenReturn(vulnerabilitiesDetails); + + when(vulnerabilityRepository.getDetailsByResourceId(anyString(), anyMap(), anyList(), anyMap())) + .thenReturn(resourceIdDetails); + + assertThat(vulnerabilityService.getAllVulnerabilitiesDetailsByAssetGroup(assetGroup, mapf, "pac", "pro", + searchText, from, size), is(notNullValue())); + + size = 25; + + ReflectionTestUtils.setField(vulnerabilityService, "vulnOccurrenceFields", + "severity,_resourceid,pciflag,_vulnage,vulntype,title,classification,_status,qid,patchable,category"); + ReflectionTestUtils.setField(vulnerabilityService, "vulnResourceIdFields", + "tags.Name,accountid,accountname,tags.Environment,tags.Application,privateipaddress,instanceid,region,availabilityzone,imageid,platform,privatednsname,instancetype,subnetid,_resourceid,publicipaddress,publicdnsname,vpcid"); + + when(vulnerabilityRepository.getAllVulnerabilitiesByAssetGroup(assetGroup, targetType, mustFilter, + occurrenceFieldList, from, size, mustTermsFilter)).thenReturn(vulnerabilitiesDetails); + + when(vulnerabilityRepository.getDetailsByResourceId(anyString(), anyMap(), anyList(), anyMap())) + .thenReturn(resourceIdDetails); + + assertThat(vulnerabilityService.getAllVulnerabilitiesDetailsByAssetGroup(assetGroup, mapf, "pac", "pro", + searchText, from, size), is(notNullValue())); + + } + + @SuppressWarnings("unchecked") + /*@Test + public void getResourcedetailsByResourceIdTest() throws Exception { + + List resourceDetails = new ArrayList<>(); + String asset = "abc"; + boolean flag = false; + ReflectionTestUtils.setField(vulnerabilityService, "vulnResourceIdFields", + "tags.Name,accountid,accountname,tags.Environment,tags.Application,privateipaddress,instanceid,region,availabilityzone,imageid,platform,privatednsname,instancetype,subnetid,_resourceid,publicipaddress,publicdnsname,vpcid"); + ReflectionTestUtils.setField(vulnerabilityService, "vulnResourceIdFieldsBoth", + "tags.Name,accountid,accountname,tags.Environment,tags.Application,privateipaddress,instanceid,region,availabilityzone,imageid,platform,privatednsname,instancetype,subnetid,_resourceid,publicipaddress,publicdnsname,vpcid"); + when(vulnerabilityRepository.getDetailsByResourceId(anyString(), anyMap(), anyList(), anyMap())) + .thenReturn(resourceDetails); + assertThat(vulnerabilityService.getResourcedetailsByResourceId(asset, resourceDetails, flag), + is(notNullValue())); + }*/ + + @Test + public void getResourceIdTest() throws Exception { + + List> resourceIdDetails = new ArrayList>(); + Map map2 = new HashMap(); + Map map3 = new HashMap(); + map2.put("s", "s3445"); + map2.put("ced", "866"); + map2.put("cif=", "1"); + map2.put("lna", "21.0"); + map2.put("cat", "pp"); + map3.put("ver", "fr"); + map3.put("ed", "cd85"); + map3.put("ifl=", "1"); + map3.put("ule", "2261.0"); + map3.put("sif", "app7"); + resourceIdDetails.add(map2); + resourceIdDetails.add(map3); + + assertThat(vulnerabilityService.getResourceId(resourceIdDetails), is(notNullValue())); + } + + @Test + public void getCartesianProductTest() throws Exception { + + List> resourceIdDetails = new ArrayList>(); + List> vulnerabilityOccuranceList = new ArrayList>(); + + assertThat(vulnerabilityService.getCartesianProduct(vulnerabilityOccuranceList, resourceIdDetails), + is(notNullValue())); + } + +} diff --git a/api/pacman-api-vulnerability/src/test/resources/application.yml b/api/pacman-api-vulnerability/src/test/resources/application.yml new file mode 100644 index 000000000..11bacd496 --- /dev/null +++ b/api/pacman-api-vulnerability/src/test/resources/application.yml @@ -0,0 +1,5 @@ +spring: + data: + mongodb: + database: piggymetrics + port: 0 \ No newline at end of file diff --git a/api/pacman-api-vulnerability/src/test/resources/bootstrap.yml b/api/pacman-api-vulnerability/src/test/resources/bootstrap.yml new file mode 100644 index 000000000..ef86170bd --- /dev/null +++ b/api/pacman-api-vulnerability/src/test/resources/bootstrap.yml @@ -0,0 +1,3 @@ +eureka: + client: + enabled: false \ No newline at end of file diff --git a/api/pom.xml b/api/pom.xml index 721f98d1b..3f80ac676 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,56 +1,57 @@ - - - 4.0.0 - - com.tmobile.cloud - api - 1.0.0-SNAPSHOT - pom - - PacMan Api Projects - Build for T-Mobile PacMan Api Projects - https://github.com/tmobile/pacman/api - - - - Apache - https://github.com/tmobile/pacman/blob/master/LICENSE - repo - - - - - - PacMan Team - PacMan Team - pacbot@t-mobile.com - - - - - T-Mobile - https://www.t-mobile.com - - - - scm:git:git://github.com/tmobile/pacman.git - scm:git:ssh://github.com/tmobile/pacman.git - https://github.com/tmobile/pacman/tree/master - - - - - pacman-api-admin - pacman-api-asset - pacman-api-config - pacman-api-compliance - pacman-api-notifications - pacman-api-statistics - pacman-api-auth - - - - - + + + 4.0.0 + + com.tmobile.cloud + api + 1.0.0-SNAPSHOT + pom + + PacMan Api Projects + Build for T-Mobile PacMan Api Projects + https://github.com/tmobile/pacman/api + + + + Apache + https://github.com/tmobile/pacman/blob/master/LICENSE + repo + + + + + + PacMan Team + PacMan Team + pacbot@t-mobile.com + + + + + T-Mobile + https://www.t-mobile.com + + + + scm:git:git://github.com/tmobile/pacman.git + scm:git:ssh://github.com/tmobile/pacman.git + https://github.com/tmobile/pacman/tree/master + + + + + pacman-api-admin + pacman-api-asset + pacman-api-config + pacman-api-compliance + pacman-api-notifications + pacman-api-statistics + pacman-api-auth + pacman-api-vulnerability + + + + + diff --git a/commons/pac-api-commons/src/main/java/com/tmobile/pacman/api/commons/Constants.java b/commons/pac-api-commons/src/main/java/com/tmobile/pacman/api/commons/Constants.java index 048e2b292..43e9b51db 100644 --- a/commons/pac-api-commons/src/main/java/com/tmobile/pacman/api/commons/Constants.java +++ b/commons/pac-api-commons/src/main/java/com/tmobile/pacman/api/commons/Constants.java @@ -293,5 +293,9 @@ public interface Constants { String EVENTCATEGORY = "eventtypecategory"; String EVENTSTATUS = "eventstatus"; String FILTER_MANDATORY = "Filter is mandatory, pass the resourceid/docid/issueid/planid"; + String EC2_QUALYS_RULEID = "PacMan_Ec2InstanceScannedByQualys_version-1_Ec2-instance-scanned-by-qualys-API_ec2"; + String VIRTUALMACHINE = "virtualmachine"; + String VIRTUALMACHINE_QUALYS_RULEID = "PacMan_Ec2InstanceScannedByQualys_version-1_VmInstanceScannedByQualys_virtualmachine"; + String ONPREM_QUALYS_RULEID = "PacMan_Onprem-asset-scanned-by-qualys-API_version-1_OnpremassetscannedbyqualysAPI_onpremserver"; } diff --git a/commons/pac-batch-commons/pom.xml b/commons/pac-batch-commons/pom.xml index df37dedb2..933b15554 100644 --- a/commons/pac-batch-commons/pom.xml +++ b/commons/pac-batch-commons/pom.xml @@ -94,8 +94,9 @@ - com.amazonaws - aws-java-sdk-s3 + com.amazonaws + aws-java-sdk-s3 + 1.11.636 diff --git a/installer/core/commands/__init__.py b/installer/core/commands/__init__.py index 74ee90d4d..5d1a77798 100644 --- a/installer/core/commands/__init__.py +++ b/installer/core/commands/__init__.py @@ -104,7 +104,8 @@ def get_resources_from_the_keys(self, resource_keys_to_process, input_instance): for name, obj_class in inspect.getmembers(resource_module, inspect.isclass): if obj_class.__module__ == resource: # To collect Resource Classes defined only in the resource file if BaseTerraformResource in inspect.getmro(obj_class): - resources_to_process.append(obj_class(input_instance)) # Create instance of that class + resource_instance = obj_class(input_instance) + resources_to_process.append(resource_instance) # Create instance of that class return resources_to_process diff --git a/installer/core/providers/aws/reinstall.py b/installer/core/providers/aws/reinstall.py new file mode 100644 index 000000000..7fdd67926 --- /dev/null +++ b/installer/core/providers/aws/reinstall.py @@ -0,0 +1,84 @@ +from core.config import Settings +from core.providers.aws.install import Install +from core import constants as K +from core.terraform import PyTerraform +from threading import Thread +from datetime import datetime +import os +import sys + + +class ReInstall(Install): + """ + AWS provider for destroy command + + Attributes: + executed_with_error (boolean): this is set to True if any error occurs + FOLDER_EXISTS_ERROR_NO (int): Error number of folder creation failure + install_statuses (dict): Available destroy statuses + terraform_thread (thread): Install python thread + terraform_outputs (dict): Terraform output dict + current_install_status (int): Current install status + """ + destroy = False + + def run_tf_execution_and_status_threads(self, resources, terraform_with_targets, dry_run): + """ + Creates 2 thread + 1. For actualy installation + 2. For displaying the status of installation + Since python is interpreted language we need to create threads to display the status in one and actual process in another + + Args: + resources (list): Resources to be installed + terraform_with_targets (boolean): If partial install is to be done (if --tags is supplied) + dry_run (boolean): Decides whether original install should be done + """ + self.terraform_thread = Thread(target=self.re_create_resources, args=(list(resources), terraform_with_targets, dry_run)) + progressbar_thread = Thread(target=self.show_progress_status, args=(list(resources), terraform_with_targets, dry_run)) + + self.terraform_thread.start() + progressbar_thread.start() + + self.terraform_thread.join() + progressbar_thread.join() + + def re_create_resources(self, resources, terraform_with_targets, dry_run): + """ + Start installing the resources by calling PyTerraform class destroy + + Args: + resources (list): Resources to be created + terraform_with_targets (boolean): If partial install is to be done (if --tags is supplied) + dry_run (boolean): Decides whether original install should be done + """ + try: + if not dry_run: + PyTerraform().terraform_destroy(resources) + self.destroy = True + self.terraform_apply(resources, terraform_with_targets, dry_run) + except Exception as e: + self.executed_with_error = True + self.exception = e + + self._cleanup_installation_process(dry_run) + + + def show_progress_status(self, resources, terraform_with_targets, dry_run): + """ + Show the status of installation continously in this thread + + Args: + resources (list): Resources to be created + terraform_with_targets (boolean): If partial install is to be done (if --tags is supplied) + dry_run (boolean): Decides whether original install should be done + """ + self.render_terraform_destroy_progress() + super().show_progress_status(resources, terraform_with_targets, dry_run) + + def render_terraform_destroy_progress(self): + """Show the status of terraform init command execution""" + start_time = datetime.now() + self.show_step_heading(K.TERRAFORM_DESTROY_STARTED, write_log=False) + while self.destroy is False and self.terraform_thread.isAlive(): + self.show_progress_message(K.TERRAFORM_DESTROY_STARTED, 0.5) diff --git a/installer/core/terraform/__init__.py b/installer/core/terraform/__init__.py index 2e84fa3d8..2f51ad382 100644 --- a/installer/core/terraform/__init__.py +++ b/installer/core/terraform/__init__.py @@ -203,10 +203,6 @@ def get_target_resources(self, resources): if resources: targets = [] for resource in resources: - # DO NOT process this resource as its definiiton asked to skip - if resource.PROCESS is False: - continue - if BaseTerraformVariable not in inspect.getmro(resource.__class__) and TerraformData not in inspect.getmro(resource.__class__): targets.append(get_terraform_resource_path(resource)) diff --git a/installer/core/terraform/resources/__init__.py b/installer/core/terraform/resources/__init__.py index 8d39b38d8..39273f5d6 100644 --- a/installer/core/terraform/resources/__init__.py +++ b/installer/core/terraform/resources/__init__.py @@ -196,6 +196,8 @@ def generate_terraform(self): print(msg) SysLog().write_error_log(str(e) + '\n' + msg) sys.exit() + else: + self.remove_terraform() def remove_terraform(self): """Delete the terraform file of the current resource from terraform directory""" diff --git a/installer/custom/commands/redeploy.py b/installer/custom/commands/redeploy.py index da89e942e..14a754d80 100644 --- a/installer/custom/commands/redeploy.py +++ b/installer/custom/commands/redeploy.py @@ -88,6 +88,7 @@ def re_deploy_pacbot(self, input_instance): resources_to_process = self.get_resources_to_process(input_instance) try: resources_to_taint = self.get_resources_with_given_tags(input_instance, ["deploy"]) + resources_to_taint = [resource for resource in resources_to_taint if resource.PROCESS is True] response = PyTerraform().terraform_taint(resources_to_taint) # If tainted or destroyed already then skip it except Exception as e: pass diff --git a/installer/custom/commands/reinstall.py b/installer/custom/commands/reinstall.py new file mode 100644 index 000000000..e59ca1c50 --- /dev/null +++ b/installer/custom/commands/reinstall.py @@ -0,0 +1,77 @@ +from core.commands import BaseCommand +from core.config import Settings +from core import constants as K +import time +import importlib +import sys +import os + + +class Reinstall(BaseCommand): + """ + This calss is defined to reinstall PacBot which is already installed by Installer command + + Attributes: + validation_class (class): This validate the input and resources + input_class (class): Main class to read input from user + install_class (class): Provider based install class + """ + def __init__(self, args): + args.append((K.CATEGORY_FIELD_NAME, "deploy")) + args.append((K.CATEGORY_FIELD_NAME, "batch-ecr")) + args.append((K.CATEGORY_FIELD_NAME, "batch-job")) + args.append((K.CATEGORY_FIELD_NAME, "submit-job")) + args.append((K.CATEGORY_FIELD_NAME, "rule-engine-job")) + args.append((K.CATEGORY_FIELD_NAME, "upload_tf")) + + Settings.set('SKIP_RESOURCE_EXISTENCE_CHECK', True) + super().__init__(args) + + def execute(self, provider): + """ + Command execution starting point + + Args: + provider (string): Provider name like AWS or Azure etc + """ + self.initialize_install_classes(provider) + + if self.check_pre_requisites() is False: + self.exit_system_with_pre_requisites_fail() + + input_instance = self.read_input() + self.re_deploy_pacbot(input_instance) + + def initialize_install_classes(self, provider): + """ + Initialise classes based on the provider + + Args: + provider (string): Provider name like AWS or Azure etc + """ + self.validation_class = getattr(importlib.import_module( + provider.provider_module + '.validate'), 'SystemInstallValidation') + self.input_class = getattr(importlib.import_module( + provider.provider_module + '.input'), 'SystemInstallInput') + self.install_class = getattr(importlib.import_module( + provider.provider_module + '.reinstall'), 'ReInstall') + + def re_deploy_pacbot(self, input_instance): + """ + Start method for redeploy + + Args: + input_instance (Input object): User input values + """ + resources_to_process = self.get_resources_to_process(input_instance) + terraform_with_targets = True + + self.install_class( + self.args, + input_instance, + check_dependent_resources=False + ).execute( + resources_to_process, + terraform_with_targets, + self.dry_run + ) diff --git a/installer/files/scripts/build_pacbot.py b/installer/files/scripts/build_pacbot.py index 609c1845c..7e7b55982 100644 --- a/installer/files/scripts/build_pacbot.py +++ b/installer/files/scripts/build_pacbot.py @@ -22,7 +22,7 @@ class Buildpacbot(object): archive_type = "zip" # What type of archive is required issue_email_template = '' - def __init__(self, aws_details, api_domain_url, upload_dir, log_dir, pacbot_code_dir): + def __init__(self, aws_details, api_domain_url, upload_dir, log_dir, pacbot_code_dir, enable_vulnerability_feautre): self.api_domain_url = api_domain_url self.cwd = pacbot_code_dir self.codebase_root_dir = pacbot_code_dir @@ -30,6 +30,7 @@ def __init__(self, aws_details, api_domain_url, upload_dir, log_dir, pacbot_code self.maven_build_log = os.path.join(log_dir, "maven_build.log") self.upload_dir = upload_dir self.s3_client = prepare_aws_client_with_given_aws_details('s3', aws_details) + self.enable_vulnerability_feautre = enable_vulnerability_feautre def _clean_up_all(self): os.chdir(self.cwd) @@ -154,6 +155,9 @@ def _update_variables_in_ui_config(self, webapp_dir): if "AD_AUTHENTICATION: false" in line: lines[idx] = lines[idx].replace("AD_AUTHENTICATION: false", "AD_AUTHENTICATION: true") + if "qualysEnabled: false" in line: + lines[idx] = lines[idx].replace("qualysEnabled: false", "qualysEnabled: %s" % self.enable_vulnerability_feautre) + if "ISSUE_MAIL_TEMPLATE_URL: ''" in line: lines[idx] = lines[idx].replace("ISSUE_MAIL_TEMPLATE_URL: ''", "ISSUE_MAIL_TEMPLATE_URL: '" + self.issue_email_template + "'") @@ -202,6 +206,7 @@ def write_to_debug_log(self, msg): provider_json_file = os.getenv('PROVIDER_FILE') s3_bucket = os.getenv('S3_BUCKET') s3_key_prefix = os.getenv('S3_KEY_PREFIX') + enable_vulnerability_feautre = os.getenv('ENABLE_VULNERABILITY_FEATURE') aws_details = get_provider_details("aws", provider_json_file) Buildpacbot( @@ -209,7 +214,8 @@ def write_to_debug_log(self, msg): api_domain_url, dist_files_upload_dir, log_dir, - pacbot_code_dir).build_api_and_ui_apps( + pacbot_code_dir, + enable_vulnerability_feautre).build_api_and_ui_apps( s3_bucket, s3_key_prefix ) diff --git a/installer/resources/datastore/es.py b/installer/resources/datastore/es.py index 910eca8c6..df974e78d 100644 --- a/installer/resources/datastore/es.py +++ b/installer/resources/datastore/es.py @@ -42,7 +42,7 @@ class ESDomain(ElasticsearchDomainResource): zone_awareness_enabled = False ebs_enabled = True volume_type = "gp2" - volume_size = 20 + volume_size = Settings.get('ES_VOLUME_SIZE', 20) automated_snapshot_start_hour = 23 security_group_ids = [InfraSecurityGroupResource.get_output_attr('id')] subnet_ids = [Settings.get('VPC')['SUBNETS'][0]] diff --git a/installer/resources/iam/all_read_role.py b/installer/resources/iam/all_read_role.py index 761cf1b68..004dc418c 100644 --- a/installer/resources/iam/all_read_role.py +++ b/installer/resources/iam/all_read_role.py @@ -96,8 +96,42 @@ class AllReadRoleAutoFixPolicyDocument(iam.IAMPolicyDocumentData): "ec2:DeleteSecurityGroup", ], 'resources': ["*"], + 'effect': "Allow", + 'condition': [ + { + 'test': "StringEquals", + 'variable': "ec2:ResourceTag/pacbot-delete-sg", + 'values': ["true"] + } + ] + }, + { + 'actions': [ + "ec2:ReleaseAddress", + ], + 'resources': ["*"], 'effect': "Allow" - } + }, + { + 'actions': [ + "rds:modifyDBInstance", + "rds:describeDBInstances", + "rds:AddTagsToResource", + "rds:CreateDBSecurityGroup", + "es:describeElasticsearchDomain", + "es:updateElasticsearchDomainConfig", + "es:addTags" + ], + 'resources': ["*"], + 'effect': "Allow" + }, + { + 'actions': [ + "s3:setPublicAccessBlock", + ], + 'resources': ["*"], + 'effect': "Allow" + }, ] diff --git a/installer/resources/iam/base_role.py b/installer/resources/iam/base_role.py index d81ffa313..e4680a7dc 100644 --- a/installer/resources/iam/base_role.py +++ b/installer/resources/iam/base_role.py @@ -59,6 +59,11 @@ class ECSTaskExecutionRolePolicyDocument(iam.IAMPolicyDocumentData): "effect": "Allow", "actions": ["logs:*"], "resources": ["*"] + }, + { + "effect": "Allow", + "actions": ["s3:getPublicAccessBlock"], + "resources": ["*"] } ] diff --git a/installer/resources/lambda_rule_engine/files/rule_engine_cloudwatch_rules.json b/installer/resources/lambda_rule_engine/files/rule_engine_cloudwatch_rules.json index 91edeb345..557210723 100644 --- a/installer/resources/lambda_rule_engine/files/rule_engine_cloudwatch_rules.json +++ b/installer/resources/lambda_rule_engine/files/rule_engine_cloudwatch_rules.json @@ -491,7 +491,7 @@ "targetType": "elasticip", "assetGroup": "aws", "alexaKeyword": "ElasticipWithNonStandardRule", - "ruleParams": "{\"params\":[{\"key\":\"splitterChar\",\"value\":\",\",\"encrypt\":false},{\"key\":\"ruleKey\",\"value\":\"check-for-non-standard-region-rule\",\"encrypt\":false},{\"key\":\"severity\",\"value\":\"low\",\"encrypt\":false},{\"key\":\"ruleCategory\",\"value\":\"governance\",\"encrypt\":false},{\"key\":\"standardRegions\",\"value\":\"us-west-2,us-east-1,us-east-2,us-west-1\",\"encrypt\":false}],\"environmentVariables\":[],\"ruleId\":\"PacMan_NonStandardRegionRule_version-1_ElasticipWithNonStandardRule_elasticip\",\"autofix\":false,\"alexaKeyword\":\"ElasticipWithNonStandardRule\",\"ruleRestUrl\":\"\",\"targetType\":\"elasticip\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_NonStandardRegionRule_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_elasticip_should_not_be_there_in_non_standard_region\",\"ruleType\":\"Manage Rule\"}", + "ruleParams": "{\"params\":[{\"encrypt\":false,\"value\":\"check-for-unused-elastic-ip\",\"key\":\"ruleKey\"},{\"key\":\"threadsafe\",\"value\":\"true\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"fixKey\",\"value\":\"unused-elastic-ip-fix\",\"isValueNew\":true,\"encrypt\":false},{\"encrypt\":false,\"value\":\"high\",\"key\":\"severity\"},{\"encrypt\":false,\"value\":\"governance\",\"key\":\"ruleCategory\"}],\"environmentVariables\":[],\"ruleId\":\"PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip\",\"autofix\":false,\"alexaKeyword\":\"UnusedElasticIpRule\",\"ruleRestUrl\":\"\",\"targetType\":\"elasticip\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_UnusedElasticIpRule_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_elasticip_should_not_be_there_in_non_standard_region\",\"ruleType\":\"ManageRule\"}", "ruleFrequency": "0 * * * ? *", "ruleExecutable": "", "ruleRestUrl": "", @@ -2330,5 +2330,138 @@ "modifiedDate": "2019-08-05", "severity": "high", "category": "governance" + }, + { + "ruleId": "PacMan_TaggingRule_version-1_VPNGatewayMandatoryTagging_vpngateway", + "ruleUUID": "aws_vpngateway_mandatory_tag_rule", + "policyId": "PacMan_TaggingRule_version-1", + "ruleName": "VpnGatewayTaggingRule", + "targetType": "vpngateway", + "assetGroup": "aws", + "alexaKeyword": "VpnGatewayTaggingRule", + "ruleParams": "{\"params\":[{\"key\":\"ruleKey\",\"value\":\"check-for-missing-mandatory-tags\",\"encrypt\":false},{\"key\":\"splitterChar\",\"value\":\",\",\"encrypt\":false},{\"key\":\"mandatoryTags\",\"value\":\"Application,Environment,Stack,Role\",\"encrypt\":false},{\"encrypt\":false,\"value\":\"low\",\"key\":\"severity\"},{\"encrypt\":false,\"value\":\"tagging\",\"key\":\"ruleCategory\"}],\"environmentVariables\":[],\"ruleId\":\"PacMan_TaggingRule_version-1_VPNGatewayMandatoryTagging_vpngateway\",\"autofix\":false,\"alexaKeyword\":\"VPNGatewayTagging\",\"ruleRestUrl\":\"\",\"targetType\":\"vpngateway\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_TaggingRule_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_vpngateway_mandatory_tag_rule\",\"ruleType\":\"ManageRule\"}", + "ruleFrequency": "0 * * * ? *", + "ruleExecutable": "", + "ruleRestUrl": "", + "ruleType": "ManageRule", + "ruleArn": "arn:aws:events:us-east-1:***REMOVED***:rule/aws_vpngateway_mandatory_tag_rule", + "status": "ENABLED", + "userId": "ASGC", + "displayName": "VPNGateway resources should be tagged with mandatory tags ", + "createdDate": "2019-09-13", + "modifiedDate": "2019-09-13", + "severity": "low", + "category": "tagging" + }, + { + "ruleId": "PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS3Vulnerability_ec2", + "ruleUUID": "aws_ec2_vuln_severity_rule", + "policyId": "PacMan_Ec2WithSeverityVulnerability_version-1", + "ruleName": "Ec2WithS3VulnerabilityRule", + "targetType": "ec2", + "assetGroup": "aws", + "alexaKeyword": "Ec2WithS3VulnerabilityRule", + "ruleParams": "{\"params\":[{\"encrypt\":false,\"value\":\"S3\",\"key\":\"severityVulnValue\"},{\"key\":\"esResourceWithVulnInfoForSeverityUrl\",\"value\":\"\/aws_ec2\/vulninfo\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"ruleKey\",\"value\":\"check-for-resource-with-severity-vulnerabilities\",\"isValueNew\":true,\"encrypt\":false},{\"encrypt\":false,\"value\":\"low\",\"key\":\"severity\"},{\"encrypt\":false,\"value\":\"security\",\"key\":\"ruleCategory\"}],\"environmentVariables\":[],\"ruleId\":\"PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS3Vulnerability_ec2\",\"autofix\":false,\"alexaKeyword\":\"Ec2WithS3Vulnerability\",\"ruleRestUrl\":\"\",\"targetType\":\"ec2\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_Ec2WithSeverityVulnerability_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_ec2_vuln_severity_rule\",\"ruleType\":\"ManageRule\"}", + "ruleFrequency": "0 * * * ? *", + "ruleExecutable": "", + "ruleRestUrl": "", + "ruleType": "ManageRule", + "ruleArn": "arn:aws:events:us-east-1:***REMOVED***:rule/aws_ec2_vuln_severity_rule", + "status": "ENABLED", + "userId": "ASGC", + "displayName": "Any Ec2 instance should not have S3 vulnerability", + "createdDate": "2019-09-13", + "modifiedDate": "2019-09-13", + "severity": "low", + "category": "security" + }, + { + "ruleId": "PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS4Vulnerability_ec2", + "ruleUUID": "aws_ec2_vuln_s4_rule", + "policyId": "PacMan_Ec2WithSeverityVulnerability_version-1", + "ruleName": "Ec2WithS4VulnerabilityRule", + "targetType": "ec2", + "assetGroup": "aws", + "alexaKeyword": "Ec2WithS4VulnerabilityRule", + "ruleParams": "{\"params\":[{\"encrypt\":false,\"value\":\"S4\",\"key\":\"severityVulnValue\"},{\"key\":\"esResourceWithVulnInfoForSeverityUrl\",\"value\":\"\/aws_ec2\/vulninfo\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"ruleKey\",\"value\":\"check-for-resource-with-severity-vulnerabilities\",\"isValueNew\":true,\"encrypt\":false},{\"encrypt\":false,\"value\":\"low\",\"key\":\"severity\"},{\"encrypt\":false,\"value\":\"security\",\"key\":\"ruleCategory\"}],\"environmentVariables\":[],\"ruleId\":\"PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS4Vulnerability_ec2\",\"autofix\":false,\"alexaKeyword\":\"Ec2WithS4Vulnerability\",\"ruleRestUrl\":\"\",\"targetType\":\"ec2\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_Ec2WithSeverityVulnerability_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_ec2_vuln_s4_rule\",\"ruleType\":\"ManageRule\"}", + "ruleFrequency": "0 * * * ? *", + "ruleExecutable": "", + "ruleRestUrl": "", + "ruleType": "ManageRule", + "ruleArn": "arn:aws:events:us-east-1:***REMOVED***:rule/aws_ec2_vuln_s4_rule", + "status": "ENABLED", + "userId": "ASGC", + "displayName": "Any Ec2 instance should not have S4 vulnerability", + "createdDate": "2019-09-13", + "modifiedDate": "2019-09-13", + "severity": "low", + "category": "security" + }, + { + "ruleId": "PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS5Vulnerability_ec2", + "ruleUUID": "aws_ec2_vuln_s5_rule", + "policyId": "PacMan_Ec2WithSeverityVulnerability_version-1", + "ruleName": "Ec2WithS5VulnerabilityRule", + "targetType": "ec2", + "assetGroup": "aws", + "alexaKeyword": "Ec2WithS5VulnerabilityRule", + "ruleParams": "{\"params\":[{\"encrypt\":false,\"value\":\"S5\",\"key\":\"severityVulnValue\"},{\"key\":\"esResourceWithVulnInfoForSeverityUrl\",\"value\":\"\/aws_ec2\/vulninfo\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"ruleKey\",\"value\":\"check-for-resource-with-severity-vulnerabilities\",\"isValueNew\":true,\"encrypt\":false},{\"encrypt\":false,\"value\":\"low\",\"key\":\"severity\"},{\"encrypt\":false,\"value\":\"security\",\"key\":\"ruleCategory\"}],\"environmentVariables\":[],\"ruleId\":\"PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS5Vulnerability_ec2\",\"autofix\":false,\"alexaKeyword\":\"Ec2WithS5Vulnerability\",\"ruleRestUrl\":\"\",\"targetType\":\"ec2\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_Ec2WithSeverityVulnerability_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_ec2_vuln_s5_rule\",\"ruleType\":\"ManageRule\"}", + "ruleFrequency": "0 * * * ? *", + "ruleExecutable": "", + "ruleRestUrl": "", + "ruleType": "ManageRule", + "ruleArn": "arn:aws:events:us-east-1:***REMOVED***:rule/aws_ec2_vuln_s5_rule", + "status": "ENABLED", + "userId": "ASGC", + "displayName": "Any Ec2 instance should not have S5 vulnerability", + "createdDate": "2019-09-13", + "modifiedDate": "2019-09-13", + "severity": "low", + "category": "security" + }, + { + "ruleId": "PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1_Ec2PublicAccessPortWithS5Vulnerability_ec2", + "ruleUUID": "aws_ec2_pub_vuln_s5_rule", + "policyId": "PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1", + "ruleName": "Ec2PublicAccessPortWithS5Vuln", + "targetType": "ec2", + "assetGroup": "aws", + "alexaKeyword": "Ec2PublicAccessPortWithS5Vuln", + "ruleParams": "{\"params\":[{\"encrypt\":false,\"value\":\"check-for-ec2-public-access-port-with-s5-vulnerabilities\",\"key\":\"ruleKey\"},{\"encrypt\":false,\"value\":\"S5\",\"key\":\"severityVulnValue\"},{\"encrypt\":false,\"value\":\"PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2\",\"key\":\"ec2PortRuleId\"},{\"key\":\"esEc2WithVulnInfoForS5Url\",\"value\":\"\/aws_ec2\/vulninfo\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"esEc2PubAccessPortUrl\",\"value\":\"\/aws\/issue_ec2\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"esAppElbWithInstanceUrl\",\"value\":\"\/aws_appelb\/appelb_instances\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"esClassicElbWithInstanceUrl\",\"value\":\"\/aws_classicelb\/classicelb_instances\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"esAppElbPubAccessPortUrl\",\"value\":\"\/aws_appelb\/issue_appelb\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"esClassicElbPubAccessPortUrl\",\"value\":\"\/aws_classicelb\/issue_classicelb\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"appElbPortRuleId\",\"value\":\"PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"classicElbPortRuleId\",\"value\":\"PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb\",\"isValueNew\":true,\"encrypt\":false},{\"encrypt\":false,\"value\":\"critical\",\"key\":\"severity\"},{\"encrypt\":false,\"value\":\"security\",\"key\":\"ruleCategory\"}],\"environmentVariables\":[],\"ruleId\":\"PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1_Ec2PublicAccessPortWithS5Vulnerability_ec2\",\"autofix\":false,\"alexaKeyword\":\"Ec2PublicAccessPortWithS5Vulnerability\",\"ruleRestUrl\":\"\",\"targetType\":\"ec2\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_ec2_pub_vuln_s5_rule\",\"ruleType\":\"ManageRule\"}", + "ruleFrequency": "0 * * * ? *", + "ruleExecutable": "", + "ruleRestUrl": "", + "ruleType": "ManageRule", + "ruleArn": "arn:aws:events:us-east-1:***REMOVED***:rule/aws_ec2_pub_vuln_s5_rule", + "status": "ENABLED", + "userId": "ASGC", + "displayName": "An Ec2 instance with remotely exploitable vulnerability (S5) should not be open to internet", + "createdDate": "2019-09-13", + "modifiedDate": "2019-09-13", + "severity": "low", + "category": "security" + }, + { + "ruleId": "PacMan_Ec2InstanceScannedByQualys_version-1_Ec2-instance-scanned-by-qualys-API_ec2", + "ruleUUID": "aws_ec2_qualys_scanned_rule", + "policyId": "PacMan_Ec2InstanceScannedByQualys_version-1", + "ruleName": "Ec2InstanceScannedByQualysAPI", + "targetType": "ec2", + "assetGroup": "aws", + "alexaKeyword": "Ec2InstanceScannedByQualysAPI", + "ruleParams": "{\"params\":[{\"encrypt\":false,\"value\":\"30\",\"key\":\"target\"},{\"key\":\"esQualysUrl\",\"value\":\"\/aws_ec2\/qualysinfo\/_search\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"discoveredDaysRange\",\"value\":\"7\",\"isValueNew\":true,\"encrypt\":false},{\"key\":\"ruleKey\",\"value\":\"check-for-resource-scanned-by-qualys\",\"isValueNew\":true,\"encrypt\":false},{\"encrypt\":false,\"value\":\"high\",\"key\":\"severity\"},{\"encrypt\":false,\"value\":\"security\",\"key\":\"ruleCategory\"}],\"environmentVariables\":[],\"ruleId\":\"PacMan_Ec2InstanceScannedByQualys_version-1_Ec2-instance-scanned-by-qualys-API_ec2\",\"autofix\":false,\"alexaKeyword\":\"Ec2InstanceScannedByQualysAPI\",\"ruleRestUrl\":\"\",\"targetType\":\"ec2\",\"pac_ds\":\"aws\",\"policyId\":\"PacMan_Ec2InstanceScannedByQualys_version-1\",\"assetGroup\":\"aws\",\"ruleUUID\":\"aws_ec2_qualys_scanned_rule\",\"ruleType\":\"ManageRule\"}", + "ruleFrequency": "0 * * * ? *", + "ruleExecutable": "", + "ruleRestUrl": "", + "ruleType": "ManageRule", + "ruleArn": "arn:aws:events:us-east-1:***REMOVED***:rule/aws_ec2_qualys_scanned_rule", + "status": "ENABLED", + "userId": "ASGC", + "displayName": "Every EC2 instance should be scanned by Qualys vulnerability assessment tool atleast once a month", + "createdDate": "2019-09-18", + "modifiedDate": "2019-09-18", + "severity": "high", + "category": "security" } + ] diff --git a/installer/resources/lambda_submit/function.py b/installer/resources/lambda_submit/function.py index 02d5c0428..1adf90d9b 100644 --- a/installer/resources/lambda_submit/function.py +++ b/installer/resources/lambda_submit/function.py @@ -10,6 +10,7 @@ from resources.data.aws_info import AwsAccount, AwsRegion from resources.lambda_submit.s3_upload import UploadLambdaSubmitJobZipFile, BATCH_JOB_FILE_NAME from resources.pacbot_app.alb import ApplicationLoadBalancer +from resources.pacbot_app.utils import need_to_deploy_vulnerability_service import json @@ -101,8 +102,10 @@ class DataShipperCloudWatchEventTarget(CloudWatchEventTargetResource): {'name': "AUTH_API_URL", 'value': ApplicationLoadBalancer.get_api_version_url('auth')}, {'name': "CONFIG_CREDENTIALS", 'value': "dXNlcjpwYWNtYW4="}, {'name': "CONFIG_SERVICE_URL", 'value': ApplicationLoadBalancer.get_http_url() + "/api/config/rule/prd/latest"} - - ], + ] + ([{ + 'name': "VULN_API_URL", + 'value': ApplicationLoadBalancer.get_api_version_url('vulnerability')} + ] if need_to_deploy_vulnerability_service() else []), 'params': [ {'encrypt': False, 'key': "package_hint", 'value': "com.tmobile"}, {'encrypt': False, 'key': "datasource", 'value': "aws"}, @@ -195,3 +198,85 @@ class CloudNotificationCollectorCloudWatchEventTarget(CloudWatchEventTargetResou {'encrypt': False, 'key': "conf_src", 'value': "api-prd,application-prd"}, ] }) + + +class QualysKBCollectorEventRule(CloudWatchEventRuleResource): + name = "qualys-kb-collector" + schedule_expression = "cron(0 * * * ? *)" + + DEPENDS_ON = [SubmitJobLambdaFunction] + PROCESS = need_to_deploy_vulnerability_service() + + +class QualysKBCollectorEventRuleLambdaPermission(LambdaPermission): + statement_id = "AllowExecutionFromQualysKBCollectorEvent" + action = "lambda:InvokeFunction" + function_name = SubmitJobLambdaFunction.get_output_attr('function_name') + principal = "events.amazonaws.com" + source_arn = QualysKBCollectorEventRule.get_output_attr('arn') + + PROCESS = need_to_deploy_vulnerability_service() + + +class QualysKBCollectorCloudWatchEventTarget(CloudWatchEventTargetResource): + rule = QualysKBCollectorEventRule.get_output_attr('name') + arn = SubmitJobLambdaFunction.get_output_attr('arn') + target_id = 'QualysKBCollectorTarget' # Unique identifier + target_input = json.dumps({ + 'jobName': "qualys-kb-collector", + 'jobUuid': "qualys-kb-collector", + 'jobType': "jar", + 'jobDesc': "Qualys KB Collector", + 'environmentVariables': [ + {'name': "CONFIG_URL", 'value': ApplicationLoadBalancer.get_api_base_url() + "/config/batch,qualys-enricher/prd/latest"}, + ], + 'params': [ + {'encrypt': False, 'key': "package_hint", 'value': "com.tmobile"}, + {'encrypt': False, 'key': "config_creds", 'value': "dXNlcjpwYWNtYW4="}, + {'encrypt': False, 'key': "job_hint", 'value': "qualys-kb"}, + ] + }) + + PROCESS = need_to_deploy_vulnerability_service() + + +class QualysAssetDataImporterEventRule(CloudWatchEventRuleResource): + name = "qualys-asset-data-importer" + schedule_expression = "cron(10 * * * ? *)" + + DEPENDS_ON = [SubmitJobLambdaFunction] + PROCESS = need_to_deploy_vulnerability_service() + + +class QualysAssetDataImporterEventRuleLambdaPermission(LambdaPermission): + statement_id = "AllowExecutionFromQualysAssetDataImporterEvent" + action = "lambda:InvokeFunction" + function_name = SubmitJobLambdaFunction.get_output_attr('function_name') + principal = "events.amazonaws.com" + source_arn = QualysAssetDataImporterEventRule.get_output_attr('arn') + + PROCESS = need_to_deploy_vulnerability_service() + + +class QualysAssetDataImporterCloudWatchEventTarget(CloudWatchEventTargetResource): + rule = QualysAssetDataImporterEventRule.get_output_attr('name') + arn = SubmitJobLambdaFunction.get_output_attr('arn') + target_id = 'QualysAssetDataImporterTarget' # Unique identifier + target_input = json.dumps({ + 'jobName': "qualys-asset-data-importer", + 'jobUuid': "qualys-asset-data-importer", + 'jobType': "jar", + 'jobDesc': "Qualys Asset Data Importer", + 'environmentVariables': [ + {'name': "CONFIG_URL", 'value': ApplicationLoadBalancer.get_api_base_url() + "/config/batch,qualys-enricher/prd/latest"}, + ], + 'params': [ + {'encrypt': False, 'key': "package_hint", 'value': "com.tmobile"}, + {'encrypt': False, 'key': "config_creds", 'value': "dXNlcjpwYWNtYW4="}, + {'encrypt': False, 'key': "job_hint", 'value': "qualys"}, + {'encrypt': False, 'key': "server_type", 'value': "ec2"}, + {'encrypt': False, 'key': "datasource", 'value': "aws"} + ] + }) + + PROCESS = need_to_deploy_vulnerability_service() diff --git a/installer/resources/pacbot_app/alb_https_listener.py b/installer/resources/pacbot_app/alb_https_listener.py index 87a711412..e285a1174 100644 --- a/installer/resources/pacbot_app/alb_https_listener.py +++ b/installer/resources/pacbot_app/alb_https_listener.py @@ -56,3 +56,8 @@ class AssetALBHttpsListenerRule(ALBListenerRuleResource, BaseLR): class AuthALBHttpsListenerRule(ALBListenerRuleResource, BaseLR): action_target_group_arn = tg.AuthALBTargetGroup.get_output_attr('arn') condition_values = [PATH_PREFIX + "auth*"] + + +class VulnerabilityALBHttpsListenerRule(ALBListenerRuleResource, BaseLR): + action_target_group_arn = tg.VulnerabilityALBTargetGroup.get_output_attr('arn') + condition_values = [PATH_PREFIX + "vulnerability*"] diff --git a/installer/resources/pacbot_app/alb_listener_rules.py b/installer/resources/pacbot_app/alb_listener_rules.py index 0232ad366..b42dff349 100644 --- a/installer/resources/pacbot_app/alb_listener_rules.py +++ b/installer/resources/pacbot_app/alb_listener_rules.py @@ -2,6 +2,7 @@ from core.config import Settings from resources.pacbot_app.alb import ApplicationLoadBalancer from resources.pacbot_app import alb_target_groups as tg +from resources.pacbot_app.utils import need_to_deploy_vulnerability_service PATH_PREFIX = '/api/' @@ -59,3 +60,9 @@ class AssetALBListenerRule(ALBListenerRuleResource, BaseLR): class AuthALBListenerRule(ALBListenerRuleResource, BaseLR): action_target_group_arn = tg.AuthALBTargetGroup.get_output_attr('arn') condition_values = [PATH_PREFIX + "auth*"] + + +class VulnerabilityALBListenerRule(ALBListenerRuleResource, BaseLR): + action_target_group_arn = tg.VulnerabilityALBTargetGroup.get_output_attr('arn', 0) + condition_values = [PATH_PREFIX + "vulnerability*"] + PROCESS = need_to_deploy_vulnerability_service() diff --git a/installer/resources/pacbot_app/alb_target_groups.py b/installer/resources/pacbot_app/alb_target_groups.py index 4fd84629f..2fc11e206 100644 --- a/installer/resources/pacbot_app/alb_target_groups.py +++ b/installer/resources/pacbot_app/alb_target_groups.py @@ -1,6 +1,7 @@ from core.terraform.resources.aws.load_balancer import ALBTargetGroupResource from resources.vpc.security_group import InfraSecurityGroupResource from core.config import Settings +from resources.pacbot_app.utils import need_to_deploy_vulnerability_service PATH_PREFIX = '/api/' @@ -58,6 +59,12 @@ class AuthALBTargetGroup(ALBTargetGroupResource, BaseTG): path = PATH_PREFIX + "auth/api.html" +class VulnerabilityALBTargetGroup(ALBTargetGroupResource, BaseTG): + name = "vulnerability" + path = PATH_PREFIX + "vulnerability/api.html" + PROCESS = need_to_deploy_vulnerability_service() + + class NginxALBTargetGroup(ALBTargetGroupResource, BaseTG): name = "ngnix" path = "/nginx" diff --git a/installer/resources/pacbot_app/build_ui_and_api.py b/installer/resources/pacbot_app/build_ui_and_api.py index be6a4790e..a9c28907f 100644 --- a/installer/resources/pacbot_app/build_ui_and_api.py +++ b/installer/resources/pacbot_app/build_ui_and_api.py @@ -28,7 +28,8 @@ def get_provisioners(self): 'DIST_FILES_UPLOAD_DIR': upload_dir, 'LOG_DIR': Settings.LOG_DIR, 'S3_BUCKET': BucketStorage.get_output_attr('bucket'), - 'S3_KEY_PREFIX': Settings.RESOURCE_NAME_PREFIX + 'S3_KEY_PREFIX': Settings.RESOURCE_NAME_PREFIX, + 'ENABLE_VULNERABILITY_FEATURE': str(Settings.ENABLE_VULNERABILITY_FEATURE).lower() }, 'interpreter': [Settings.PYTHON_INTERPRETER] } diff --git a/installer/resources/pacbot_app/ecs_services.py b/installer/resources/pacbot_app/ecs_services.py index 72f49e248..a7109a9d6 100644 --- a/installer/resources/pacbot_app/ecs_services.py +++ b/installer/resources/pacbot_app/ecs_services.py @@ -8,6 +8,7 @@ from resources.pacbot_app import alb_listener_rules as alr from resources.pacbot_app.build_ui_and_api import BuildUiAndApis from resources.pacbot_app.import_db import ImportDbSql +from resources.pacbot_app.utils import need_to_deploy_vulnerability_service import os @@ -104,3 +105,12 @@ class AuthEcsService(BaseEcsService, ECSServiceResource): load_balancer_target_group_arn = tg.AuthALBTargetGroup.get_output_attr('arn') load_balancer_container_name = "auth" DEPENDS_ON = [alr.AuthALBListenerRule, WaitConfigServiceToUp] + + +class VulnerabilityEcsService(BaseEcsService, ECSServiceResource): + name = "vulnerability" + task_definition = td.VulnerabilityEcsTaskDefinition.get_output_attr('arn', 0) + load_balancer_target_group_arn = tg.VulnerabilityALBTargetGroup.get_output_attr('arn', 0) + load_balancer_container_name = "vulnerability" + DEPENDS_ON = [alr.VulnerabilityALBListenerRule, WaitConfigServiceToUp] + PROCESS = need_to_deploy_vulnerability_service() diff --git a/installer/resources/pacbot_app/ecs_task_defintions.py b/installer/resources/pacbot_app/ecs_task_defintions.py index c3c4210c2..92489eafa 100644 --- a/installer/resources/pacbot_app/ecs_task_defintions.py +++ b/installer/resources/pacbot_app/ecs_task_defintions.py @@ -2,6 +2,7 @@ from resources.iam.ecs_role import ECSRole from resources.pacbot_app.task_def_variables import ContainerDefinitions from resources.pacbot_app.ecr import APIDockerImageBuild, UIDockerImageBuild +from resources.pacbot_app.utils import need_to_deploy_vulnerability_service container_def = ContainerDefinitions() @@ -65,3 +66,10 @@ class AuthEcsTaskDefinition(ECSTaskDefinitionResource, BaseTaskDefinition): family = "auth" container_definitions = container_def.get_container_definitions('auth') DEPENDS_ON = [APIDockerImageBuild] + + +class VulnerabilityEcsTaskDefinition(ECSTaskDefinitionResource, BaseTaskDefinition): + family = "vulnerability" + container_definitions = container_def.get_container_definitions('vulnerability') + DEPENDS_ON = [APIDockerImageBuild] + PROCESS = need_to_deploy_vulnerability_service() diff --git a/installer/resources/pacbot_app/files/DB.sql b/installer/resources/pacbot_app/files/DB.sql index 7a09aa7b3..4916b0d17 100644 --- a/installer/resources/pacbot_app/files/DB.sql +++ b/installer/resources/pacbot_app/files/DB.sql @@ -81,6 +81,9 @@ SET @PACMAN_LOGIN_PASSWORD='$PACMAN_LOGIN_PASSWORD'; SET @CONFIG_CREDENTIALS='$CONFIG_CREDENTIALS'; SET @CONFIG_SERVICE_URL='$CONFIG_SERVICE_URL'; SET @PACBOT_AUTOFIX_RESOURCEOWNER_FALLBACK_MAILID='$PACBOT_AUTOFIX_RESOURCEOWNER_FALLBACK_MAILID'; +SET @QUALYS_INFO='$QUALYS_INFO'; +SET @QUALYS_API_URL='$QUALYS_API_URL'; + CREATE TABLE IF NOT EXISTS `OmniSearch_Config` ( @@ -749,6 +752,20 @@ CREATE TABLE IF NOT EXISTS `oauth_user_role_mapping` ( `modifiedDate` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +DELETE FROM oauth_user_role_mapping where userRoleId in ("4747c0cf-63cc-4829-a1e8-f1e957ec5dd6","4747c0cf-63cc-4829-a1e8-f1e957ec5dd7","f5b2a689-c185-11e8-9c73-12d01119b604"); +DELIMITER $$ +DROP PROCEDURE IF EXISTS create_primary_key_if_not_exists_for_user_role_mapping $$ +CREATE PROCEDURE create_primary_key_if_not_exists_for_user_role_mapping() +BEGIN + IF((SELECT COUNT(1) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name='oauth_user_role_mapping' AND index_name='PRIMARY') < 1) THEN + SET @query = 'ALTER TABLE oauth_user_role_mapping ADD PRIMARY KEY (userRoleId);'; + PREPARE stmt FROM @query; + EXECUTE stmt; + END IF; +END $$ +DELIMITER ; +CALL create_primary_key_if_not_exists_for_user_role_mapping(); + CREATE TABLE IF NOT EXISTS `oauth_user_credentials` ( `id` bigint (75), @@ -768,6 +785,20 @@ CREATE TABLE IF NOT EXISTS `oauth_user_roles` ( `modifiedDate` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +DELETE FROM oauth_user_roles WHERE roleId in ("1", "703"); +DELIMITER $$ +DROP PROCEDURE IF EXISTS create_primary_key_if_not_exists_for_user_roles $$ +CREATE PROCEDURE create_primary_key_if_not_exists_for_user_roles() +BEGIN + IF((SELECT COUNT(1) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name='oauth_user_roles' AND index_name='PRIMARY') < 1) THEN + SET @query = 'ALTER TABLE oauth_user_roles ADD PRIMARY KEY (roleId)'; + PREPARE stmt FROM @query; + EXECUTE stmt; + END IF; +END $$ +DELIMITER ; +CALL create_primary_key_if_not_exists_for_user_roles(); + CREATE TABLE IF NOT EXISTS `task` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, @@ -1307,6 +1338,12 @@ INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`t INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_S3AccessLogsRule_version-1_S3AccessLogsRule_s3','aws_s3_accesslogs','PacMan_S3AccessLogsRule_version-1','S3AccessLogsRule','s3','aws','S3AccessLogsRule','{"params":[{"key":"ruleKey","value":"check-for-s3-access-logs","encrypt":false},{"key":"esS3PubAccessIssueUrl","value":"/aws_s3/issue_s3/_search","encrypt":false},{"key":"s3PublicAccessRuleId","value":"PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3","encrypt":false},{"key":"splitterChar","value":",","isValueNew":true,"encrypt":false},{"key":"fixKey","value":"private-s3-server-access-logs-fix","isValueNew":true,"encrypt":false},{"key":"accessLogsEnabledRegions","value":"","isValueNew":true,"encrypt":false},{"key":"destinationBucketForAutofix","value":"tmo-s3-accesslog-ACCOUNT_ID-REGION-dev","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"high","key":"severity"},{"encrypt":false,"value":"governance","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_S3AccessLogsRule_version-1_S3AccessLogsRule_s3","autofix":false,"alexaKeyword":"S3AccessLogsRule","ruleRestUrl":"","targetType":"s3","pac_ds":"aws","policyId":"PacMan_S3AccessLogsRule_version-1","assetGroup":"aws","ruleUUID":"aws_s3_accesslogs","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_s3_accesslogs'),'ENABLED','ASGC','Private s3 buckets should be enabled with access logs','2019-08-05','2019-08-05','high','governance'); INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_CloudWatchEventsForAllAccounts_version-1_CloudWatchEventsForAllAccounts_account','aws_account_cloud_watch_events','PacMan_CloudWatchEventsForAllAccounts_version-1','CloudWatchEventsForAllAccounts','account','aws','CloudWatchEventsForAllAccounts','{"params":[{"encrypt":false,"value":"check-cloudwatch-event-rule","key":"ruleKey"},{"encrypt":false,"value":"role/pac_ro","key":"roleIdentifyingString"},{"encrypt":false,"value":"DO-NOT-DELETE-pacman-all-events-to-eventbus-in-ACCOUNTID","key":"ruleName"},{"encrypt":false,"value":"high","key":"severity"},{"encrypt":false,"value":"governance","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_CloudWatchEventsForAllAccounts_version-1_CloudWatchEventsForAllAccounts_account","autofix":false,"alexaKeyword":"CloudWatchEventsForAllAccounts","ruleRestUrl":"","targetType":"account","pac_ds":"aws","policyId":"PacMan_CloudWatchEventsForAllAccounts_version-1","assetGroup":"aws","ruleUUID":"aws_account_cloud_watch_events","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_account_cloud_watch_events'),'ENABLED','ASGC','All Cloud watch events from all accounts should be sent to DEDICATED ACCOUNTID default event bus','2019-08-05','2019-08-05','high','governance'); INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_LowUtilizationAmazonEC2InstancesRule_version-1_LowUtilizationAmazonEC2InstancesRule_ec2','aws_ec2_low_utilization','PacMan_LowUtilizationAmazonEC2InstancesRule_version-1','LowUtilizationAmazonEC2InstancesRule','ec2','aws','LowUtilizationAmazonEC2InstancesRule','{"params":[{"encrypt":false,"value":"check-for-low-utilization-amazon-ec2-instance","key":"ruleKey"},{"encrypt":false,"value":"","key":"checkId"},{"encrypt":false,"value":"low","key":"severity"},{"isValueNew":true,"encrypt":false,"value":"costOptimization","key":"ruleCategory"},{"key":"esServiceURL","value":"/aws_checks/checks_resources/_search","isValueNew":true,"encrypt":false}],"environmentVariables":[],"ruleId":"PacMan_LowUtilizationAmazonEC2InstancesRule_version-1_LowUtilizationAmazonEC2InstancesRule_ec2","autofix":false,"alexaKeyword":"LowUtilizationAmazonEC2InstancesRule","ruleRestUrl":"","targetType":"ec2","pac_ds":"aws","policyId":"PacMan_LowUtilizationAmazonEC2InstancesRule_version-1","assetGroup":"aws","ruleUUID":"aws_ec2_low_utilization","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_ec2_low_utilization'),'ENABLED','ASGC','Amazon EC2 instances should not have low utilization','2019-08-05','2019-08-05','high','governance'); +INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_TaggingRule_version-1_VPNGatewayMandatoryTagging_vpngateway','aws_vpngateway_mandatory_tag_rule','PacMan_TaggingRule_version-1','VpnGatewayTaggingRule','vpngateway','aws','VpnGatewayTaggingRule','{"params":[{"key":"ruleKey","value":"check-for-missing-mandatory-tags","encrypt":false},{"key":"splitterChar","value":",","encrypt":false},{"key":"mandatoryTags","value":"Application,Environment,Stack,Role","encrypt":false},{"encrypt":false,"value":"low","key":"severity"},{"encrypt":false,"value":"tagging","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_TaggingRule_version-1_VPNGatewayMandatoryTagging_vpngateway","autofix":false,"alexaKeyword":"VPNGatewayTagging","ruleRestUrl":"","targetType":"vpngateway","pac_ds":"aws","policyId":"PacMan_TaggingRule_version-1","assetGroup":"aws","ruleUUID":"aws_vpngateway_mandatory_tag_rule","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_vpngateway_mandatory_tag_rule'),'ENABLED','ASGC','VPNGateway should be tagged with mandatory tags','2019-08-05','2019-08-05','high','governance'); +INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS3Vulnerability_ec2','aws_ec2_vuln_severity_rule','PacMan_Ec2WithSeverityVulnerability_version-1','Ec2WithS3VulnerabilityRule','ec2','aws','Ec2WithS3VulnerabilityRule','{"params":[{"encrypt":false,"value":"S3","key":"severityVulnValue"},{"key":"esResourceWithVulnInfoForSeverityUrl","value":"/aws_ec2/vulninfo/_search","isValueNew":true,"encrypt":false},{"key":"ruleKey","value":"check-for-resource-with-severity-vulnerabilities","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"low","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS3Vulnerability_ec2","autofix":false,"alexaKeyword":"Ec2WithS3Vulnerability","ruleRestUrl":"","targetType":"ec2","pac_ds":"aws","policyId":"PacMan_Ec2WithSeverityVulnerability_version-1","assetGroup":"aws","ruleUUID":"aws_ec2_vuln_severity_rule","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_ec2_vuln_severity_rule'),'ENABLED','ASGC','Any Ec2 instance should not have S3 vulnerability','2019-08-05','2019-08-05','high','governance'); +INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS4Vulnerability_ec2','aws_ec2_vuln_s4_rule','PacMan_Ec2WithSeverityVulnerability_version-1','Ec2WithS4VulnerabilityRule','ec2','aws','Ec2WithS4VulnerabilityRule','{"params":[{"encrypt":false,"value":"S4","key":"severityVulnValue"},{"key":"esResourceWithVulnInfoForSeverityUrl","value":"/aws_ec2/vulninfo/_search","isValueNew":true,"encrypt":false},{"key":"ruleKey","value":"check-for-resource-with-severity-vulnerabilities","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"low","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS4Vulnerability_ec2","autofix":false,"alexaKeyword":"Ec2WithS4Vulnerability","ruleRestUrl":"","targetType":"ec2","pac_ds":"aws","policyId":"PacMan_Ec2WithSeverityVulnerability_version-1","assetGroup":"aws","ruleUUID":"aws_ec2_vuln_s4_rule","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_ec2_vuln_s4_rule'),'ENABLED','ASGC','Any Ec2 instance should not have S4 vulnerability','2019-08-05','2019-08-05','high','governance'); +INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS5Vulnerability_ec2','aws_ec2_vuln_s5_rule','PacMan_Ec2WithSeverityVulnerability_version-1','Ec2WithS5VulnerabilityRule','ec2','aws','Ec2WithS5VulnerabilityRule','{"params":[{"encrypt":false,"value":"S5","key":"severityVulnValue"},{"key":"esResourceWithVulnInfoForSeverityUrl","value":"/aws_ec2/vulninfo/_search","isValueNew":true,"encrypt":false},{"key":"ruleKey","value":"check-for-resource-with-severity-vulnerabilities","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"low","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_Ec2WithSeverityVulnerability_version-1_Ec2WithS5Vulnerability_ec2","autofix":false,"alexaKeyword":"Ec2WithS5Vulnerability","ruleRestUrl":"","targetType":"ec2","pac_ds":"aws","policyId":"PacMan_Ec2WithSeverityVulnerability_version-1","assetGroup":"aws","ruleUUID":"aws_ec2_vuln_s5_rule","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_ec2_vuln_s5_rule'),'ENABLED','ASGC','Any Ec2 instance should not have S5 vulnerability','2019-08-05','2019-08-05','high','governance'); +INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1_Ec2PublicAccessPortWithS5Vulnerability_ec2','aws_ec2_pub_vuln_s5_rule','PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1','Ec2PublicAccessPortWithS5Vuln','ec2','aws','Ec2PublicAccessPortWithS5Vuln','{"params":[{"encrypt":false,"value":"check-for-ec2-public-access-port-with-s5-vulnerabilities","key":"ruleKey"},{"encrypt":false,"value":"S5","key":"severityVulnValue"},{"encrypt":false,"value":"PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2","key":"ec2PortRuleId"},{"key":"esEc2WithVulnInfoForS5Url","value":"/aws_ec2/vulninfo/_search","isValueNew":true,"encrypt":false},{"key":"esEc2PubAccessPortUrl","value":"/aws/issue_ec2/_search","isValueNew":true,"encrypt":false},{"key":"esAppElbWithInstanceUrl","value":"/aws_appelb/appelb_instances/_search","isValueNew":true,"encrypt":false},{"key":"esClassicElbWithInstanceUrl","value":"/aws_classicelb/classicelb_instances/_search","isValueNew":true,"encrypt":false},{"key":"esAppElbPubAccessPortUrl","value":"/aws_appelb/issue_appelb/_search","isValueNew":true,"encrypt":false},{"key":"esClassicElbPubAccessPortUrl","value":"/aws_classicelb/issue_classicelb/_search","isValueNew":true,"encrypt":false},{"key":"appElbPortRuleId","value":"PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb","isValueNew":true,"encrypt":false},{"key":"classicElbPortRuleId","value":"PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"critical","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1_Ec2PublicAccessPortWithS5Vulnerability_ec2","autofix":false,"alexaKeyword":"Ec2PublicAccessPortWithS5Vulnerability","ruleRestUrl":"","targetType":"ec2","pac_ds":"aws","policyId":"PacMan_Ec2PublicAccessPortWithS5Vulnerability_version-1","assetGroup":"aws","ruleUUID":"aws_ec2_pub_vuln_s5_rule","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_ec2_pub_vuln_s5_rule'),'ENABLED','ASGC','An Ec2 instance with remotely exploitable vulnerability (S5) should not be open to internet','2019-08-05','2019-08-05','high','governance'); +INSERT IGNORE INTO cf_RuleInstance (`ruleId`,`ruleUUID`,`policyId`,`ruleName`,`targetType`,`assetGroup`,`alexaKeyword`,`ruleParams`,`ruleFrequency`,`ruleExecutable`,`ruleRestUrl`,`ruleType`,`ruleArn`,`status`,`userId`,`displayName`,`createdDate`,`modifiedDate`,`severity`,`category`) VALUES ('PacMan_Ec2InstanceScannedByQualys_version-1_Ec2-instance-scanned-by-qualys-API_ec2','aws_ec2_qualys_scanned_rule','PacMan_Ec2InstanceScannedByQualys_version-1','Ec2InstanceScannedByQualysAPI','ec2','aws','Ec2InstanceScannedByQualysAPI','{"params":[{"encrypt":false,"value":"30","key":"target"},{"key":"esQualysUrl","value":"/aws_ec2/qualysinfo/_search","isValueNew":true,"encrypt":false},{"key":"discoveredDaysRange","value":"7","isValueNew":true,"encrypt":false},{"key":"ruleKey","value":"check-for-resource-scanned-by-qualys","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"high","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_Ec2InstanceScannedByQualys_version-1_Ec2-instance-scanned-by-qualys-API_ec2","autofix":false,"alexaKeyword":"Ec2InstanceScannedByQualysAPI","ruleRestUrl":"","targetType":"ec2","pac_ds":"aws","policyId":"PacMan_Ec2InstanceScannedByQualys_version-1","assetGroup":"aws","ruleUUID":"aws_ec2_qualys_scanned_rule","ruleType":"ManageRule"}','0 0 ? * MON *','','','Manage Rule',concat('arn:aws:events:',@region,':',@account,':rule/aws_ec2_qualys_scanned_rule'),'ENABLED','ASGC','Every EC2 instance should be scanned by Qualys vulnerability assessment tool atleast once a month','2019-09-18','2019-09-18','high','security'); @@ -1447,6 +1484,7 @@ INSERT IGNORE INTO pac_config_relation (application,parent) VALUES ('inventory', INSERT IGNORE INTO pac_config_relation (`application`,`parent`) VALUES ('rule','application'); INSERT IGNORE INTO pac_config_relation (application,parent) VALUES ('rule-engine','rule'); INSERT IGNORE INTO pac_config_relation (application,parent) VALUES ('recommendation-enricher','batch'); +INSERT IGNORE INTO pac_config_relation (application,parent) VALUES ('qualys-enricher','batch'); INSERT IGNORE INTO pac_config_key_metadata (`cfkey`,`description`) VALUES ('admin.api-role','Description PlaceHolder'); INSERT IGNORE INTO pac_config_key_metadata (`cfkey`,`description`) VALUES ('admin.push.notification.pollinterval.milliseconds','description'); @@ -1752,8 +1790,35 @@ INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pa INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.fix.notify.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg','Description PlaceHolder'); INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.mail.template.columns.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg','Description PlaceHolder'); INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.common.email.notifications.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg','Description PlaceHolder'); + +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('autofix.whitelist.accounts.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.mail.subject.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.warning.mail.subject.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.rule.violation.message.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.rule.warning.message.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.rule.post.fix.message.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.waittime.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.max.email.notifications.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.mail.template.columns.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.common.email.notifications.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','Description PlaceHolder'); INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('deleteSgTag','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('autofix.whitelist.accounts.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.contact.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.fix.type.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.mail.subject.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.rule.post.fix.message.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.fix.notify.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.mail.template.columns.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.auto.fix.common.email.notifications.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('pacman.autofix.issue.creation.time.elapsed.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Description PlaceHolder'); +INSERT IGNORE INTO pac_config_key_metadata (`cfkey`,`description`) VALUES ('service.url.vulnerability','Description PlaceHolder'); +INSERT IGNORE INTO pac_config_key_metadata (`cfkey`,`description`) VALUES ('vulnerability.application.occurance','Description PlaceHolder'); +INSERT IGNORE INTO pac_config_key_metadata (`cfkey`,`description`) VALUES ('vulnerability.application.resourcedetails','Description PlaceHolder'); +INSERT IGNORE INTO pac_config_key_metadata (`cfkey`,`description`) VALUES ('vulnerability.application.resourcedetailsboth','Description PlaceHolder'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('qualys_info','Base64 encoded user:password of qualys'); +INSERT IGNORE INTO `pac_config_key_metadata` (`cfkey`, `description`) values('qualys_api_url','Qualys api url'); + @@ -2030,6 +2095,29 @@ INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `pr INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.auto.fix.common.email.notifications.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch','commonTemplate','rule','prd','latest',NULL,NULL,NULL,NULL); INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('deleteSgTag','pacbot-delete-sg','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('autofix.whitelist.accounts.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.autofix.contact.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.autofix.fix.type.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','silent','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.auto.fix.mail.subject.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','PacBot - AWS Unassociated Elastic IP Addresses Auto Delete Report','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.autofix.fix.notify.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.autofix.issue.creation.time.elapsed.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','72','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.autofix.rule.post.fix.message.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','PacBot has now automatically deleted the following list of Unassociated Elastic IP Addresses','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.auto.fix.mail.template.columns.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','Resource Id,Account Id,Region,Allocation Id','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) values('pacman.auto.fix.common.email.notifications.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip','commonTemplate','rule','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO `pac_config_properties` (`cfkey`, `value`, `application`, `profile`, `label`, `createdBy`, `createdDate`, `modifiedBy`, `modifiedDate`) VALUES('service.url.vulnerability',concat(@PACMAN_HOST_NAME,'/api/vulnerability'),'api','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties(`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('api.services[6].name','Vulnerability Service','api','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties(`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('api.services[6].url','${PACMAN_HOST_NAME:http://localhost:8080}/api/vulnerability/v2/api-docs','api','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties(`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('api.services[6].version','2','api','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties (`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('server.servlet.context-path','/api/vulnerability','vulnerability-service','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties (`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('qualys_info',concat(@QUALYS_INFO,''),'qualys-enricher','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties (`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('qualys_api_url',concat(@QUALYS_API_URL,''),'qualys-enricher','prd','latest',NULL,NULL,NULL,NULL); + + +INSERT IGNORE INTO pac_config_properties (`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('vulnerability.application.occurance','severity,_resourceid,pciflag,_vulnage,vulntype,title,classification,_firstFound,_lastFound,qid,patchable,category','vulnerability-service','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties (`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('vulnerability.application.resourcedetails','tags.Name,accountid,accountname,tags.Environment,tags.Application,privateipaddress,instanceid,region,availabilityzone,imageid,platform,privatednsname,instancetype,subnetid,_resourceid,publicipaddress,publicdnsname,vpcid','vulnerability-service','prd','latest',NULL,NULL,NULL,NULL); +INSERT IGNORE INTO pac_config_properties (`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('vulnerability.application.resourcedetailsboth','tags.Name,tags.Environment,tags.Application,ip_address,privateipaddress,_entitytype,_resourceid','vulnerability-service','prd','latest',NULL,NULL,NULL,NULL); + + INSERT IGNORE INTO `Recommendation_Mappings`(`checkId`,`type`,`resourceInfo`,`_resourceId`,`monthlySavingsField`) values ('H7IgTzjTYb','volume','Volume ID','volumeid',NULL),('DAvU99Dc4C','volume','Volume ID','volumeid','Monthly Storage Cost'),('Qch7DwouX1','ec2','Instance ID','instanceid','Estimated Monthly Savings'),('1iG5NDGVre','sg','Security Group ID','groupid',NULL),('HCP4007jGY','sg','Security Group ID','groupid',NULL),('BueAdJ7NrP','s3','Bucket Name','name',NULL),('iqdCTZKCUp','classicelb','Load Balancer Name','loadbalancername',NULL),('R365s2Qddf','s3','Bucket Name','name',NULL),('Pfx0RwqBli','s3','Bucket Name','name',NULL),('a2sEc6ILx','classicelb','Load Balancer Name','loadbalancername',NULL),('xdeXZKIUy','classicelb','Load Balancer Name','loadbalancername',NULL),('CLOG40CDO8','asg','Auto Scaling Group Name','autoscalinggroupname',NULL),('7qGXsKIUw','classicelb','Load Balancer Name','loadbalancername',NULL),('hjLMh88uM8','classicelb','Load Balancer Name','loadbalancername','Estimated Monthly Savings'),('DqdJqYeRm5','iamuser','IAM User','username',NULL),('j3DFqYTe29','ec2','Instance ID','instanceid',NULL),('f2iK5R6Dep','rdsdb','DB Instance','dbinstanceidentifier',NULL),('1MoPEMsKx6','reservedinstance','Instance Type','instancetype','Estimated Monthly Savings'),('Ti39halfu8','rdsdb','DB Instance Name','dbinstanceidentifier','Estimated Monthly Savings (On Demand)'),('Wnwm9Il5bG','ec2','Instance ID','instanceid',NULL),('V77iOLlBqz','ec2','Instance ID','instanceid',NULL),('Z4AUBRNSmz','elasticip','IP Address','publicip',NULL),('8CNsSllI5v','asg','Auto Scaling Group Name','autoscalinggroupname',NULL),('N420c450f2','cloudfront','Distribution ID','id',NULL),('TyfdMXG69d','ec2','Instance ID','instanceid',NULL),('tfg86AVHAZ','sg','Group ID','groupid',NULL),('yHAGQJV9K5','ec2','Instance ID','instanceid',NULL),('S45wrEXrLz','vpnconnection','VPN ID','vpnconnectionid',NULL),('PPkZrjsH2q','volume','Volume ID','volumeid',NULL),('opQPADkZvH','rdsdb','DB Instance','dbinstanceidentifier',NULL),('796d6f3D83','s3','Bucket Name','name',NULL),('G31sQ1E9U','redshift','Cluster','clusteridentifier','Estimated Monthly Savings'),('xSqX82fQu','classicelb','Load Balancer Name','loadbalancername',NULL),('ZRxQlPsb6c','ec2','Instance ID','instanceid',NULL),('N430c450f2','cloudfront','Distribution ID','id',NULL),('4g3Nt5M1Th','virtualinterface','Gateway ID','virtualgatewayid',NULL),('0t121N1Ty3','directconnect','Connection ID','connectionid',NULL),('N425c450f2','cloudfront','Distribution ID','id',NULL),('xuy7H1avtl','rdscluster','Cluster','dbclusteridentifier',NULL),('1e93e4c0b5','reservedinstance','Reserved Instance ID','instanceid','Estimated Monthly Savings'),('51fC20e7I2','route53','Hosted Zone ID','hostedZoneId',NULL),('cF171Db240','route53','Hosted Zone ID','hostedZoneId',NULL),('Cb877eB72b','route53','Hosted Zone ID','hostedZoneId',NULL),('b73EEdD790','route53','Hosted Zone ID','hostedZoneId',NULL),('C056F80cR3','route53','Hosted Zone ID','hostedZoneId',NULL),('B913Ef6fb4','route53','Hosted Zone ID','hostedZoneId',NULL); INSERT IGNORE INTO `CloudNotification_mapping`(`NotificationId`,`eventType`,`resourceIdKey`,`resourceIdVal`,`esIndex`,`phdEntityKey`) values ('02BUF','CLOUDTRAIL','_resourceid.keyword','_resourceid','cloudtrl','entityvalue'),('4GIGN','S3','_resourceid.keyword','_resourceid','s3','entityvalue'),('5U846','ELASTICSEARCH','arn.keyword','arn','elasticsearch','entityvalue'),('DI3Q3','SQS','_resourceid.keyword','_resourceid','sqs','entityvalue'),('FZC49','VPN','vpnconnectionid.keyword','vpnconnectionid','vpnconnection','entityvalue'),('G30R7','KMS','_resourceid.keyword','_resourceid','kms','entityvalue'),('G4AIH','RDS','dbinstanceidentifier.keyword','dbinstanceidentifier','rdsdb','entityvalue'),('HL28B','EC2','_resourceid.keyword','_resourceid','ec2','entityvalue'),('KBDY2','DIRECTCONNECT','_resourceid.keyword','_resourceid','directconnect','entityvalue'),('LPB7Z','LAMBDA','_resourceid.keyword','_resourceid','lambda','entityvalue'),('PKI3S','CONFIG','_resourceid.keyword','_resourceid','config','entityvalue'),('S2QIA','REDSHIFT','clusteridentifier.keyword','clusteridentifier','redshift','entityvalue'),('W45AP','IAM','arn.keyword','arn','iamuser','entityvalue'),('X9GYT','VPC','_resourceid.keyword','_resourceid','vpc','entityvalue'),('YCFSX','CLOUDFRONT','_resourceid.keyword','_resourceid','cloudfront','entityvalue'),('YGS02','DYNAMODB','tablearn.keyword','tablearn','dynamodb','entityvalue'),('YGS03','MQ','_resourceid.keyword','_resourceid','mq','entityvalue'),('YGS05','APIGATEWAY','_resourceid.keyword','_resourceid','apigtw','entityvalue'); @@ -2105,7 +2193,338 @@ UPDATE `cf_RuleInstance` SET ruleParams = '{"params":[{"key":"roleIdentifyingStr UPDATE `cf_RuleInstance` SET ruleParams = '{"params":[{"key":"ruleKey","value":"iam-role-with-unapproved-access","isValueNew":true,"encrypt":false},{"key":"roleIdentifyingString","value":"role/pacbot_ro","isValueNew":true,"encrypt":false},{"key":"unApprovedIamActions","value":"ec2:CreateDefaultSubnet,ec2:CreateDefaultVpc,ec2:CreateInternetGateway,ec2:CreateSubnet,ec2:CreateVpc,ec2:CreateVpcEndpoint,ec2:CreateVpcEndpointConnectionNotification,ec2:CreateVpcEndpointServiceConfiguration,ec2:CreateVpcPeeringConnection,ec2:CreateVpnConnection,ec2:CreateVpnConnectionRoute,ec2:CreateVpnGateway,ec2:ModifySubnetAttribute,ec2:ModifyVpcAttribute,ec2:ModifyVpcEndpoint,ec2:ModifyVpcEndpointConnectionNotification,ec2:ModifyVpcEndpointServiceConfiguration,ec2:ModifyVpcEndpointServicePermissions,ec2:ModifyVpcPeeringConnectionOptions,ec2:ModifyVpcTenancy,ec2:MoveAddressToVpc,ec2:AttachInternetGateway,ec2:CreateEgressOnlyInternetGateway,ec2:AttachVpnGateway.ec2:*,*","isValueNew":true,"encrypt":false},{"key":"splitterChar","value":",","isValueNew":true,"encrypt":false},{"key":"fixKey","value":"iam-role-with-unapproved-access-autofix","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"critical","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_IAMRoleNetworkPrivilegesRule_version-1_IAMRoleNetworkPrivilegesRule_iamrole","autofix":false,"alexaKeyword":"networkprivileges","ruleRestUrl":"","targetType":"iamrole","pac_ds":"aws","policyId":"PacMan_IAMRoleNetworkPrivilegesRule_version-1","assetGroup":"aws","ruleUUID":"aws_iamrole_shouldnothave_network_privileges","ruleType":"ManageRule"}' WHERE ruleId = 'PacMan_IAMRoleNetworkPrivilegesRule_version-1_IAMRoleNetworkPrivilegesRule_iamrole'; UPDATE `cf_RuleInstance` SET ruleParams = '{"params":[{"key":"ruleKey","value":"iam-role-with-unapproved-access","encrypt":false},{"key":"roleIdentifyingString","value":"role/pacbot_ro","encrypt":false},{"key":"unApprovedIamActions","value":"lambda:CreateFunction,lambda:Create*,*,lambda:*","encrypt":false},{"key":"splitterChar","value":",","encrypt":false},{"key":"fixKey","value":"iam-role-with-unapproved-access-autofix","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"critical","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_UnapprovedIamRoleWithLambdaAccess_version-1_UnapprovedIamRoleLambdaAccess_iamrole","autofix":false,"alexaKeyword":"UnapprovedIamRoleWithLambdaAccess","ruleRestUrl":"","targetType":"iamrole","pac_ds":"aws","policyId":"PacMan_UnapprovedIamRoleWithLambdaAccess_version-1","assetGroup":"aws","ruleUUID":"aws_iamrole_shouldnothave_lambda_privilege","ruleType":"ManageRule"}' WHERE ruleId = 'PacMan_UnapprovedIamRoleWithLambdaAccess_version-1_UnapprovedIamRoleLambdaAccess_iamrole'; UPDATE `cf_RuleInstance` SET ruleParams = '{"params":[{"key":"roleIdentifyingString","value":"role/pacbot_ro","encrypt":false},{"key":"unApprovedIamActions","value":"ec2:CreateDefaultSubnet,ec2:CreateDefaultVpc,ec2:CreateInternetGateway,ec2:CreateSubnet,ec2:CreateVpc,ec2:CreateVpcEndpoint,ec2:CreateVpcEndpointConnectionNotification,ec2:CreateVpcEndpointServiceConfiguration,ec2:CreateVpcPeeringConnection,ec2:CreateVpnConnection,ec2:CreateVpnConnectionRoute,ec2:CreateVpnGateway,ec2:ModifySubnetAttribute,ec2:ModifyVpcAttribute,ec2:ModifyVpcEndpoint,ec2:ModifyVpcEndpointConnectionNotification,ec2:ModifyVpcEndpointServiceConfiguration,ec2:ModifyVpcEndpointServicePermissions,ec2:ModifyVpcPeeringConnectionOptions,ec2:ModifyVpcTenancy,ec2:MoveAddressToVpc,ec2:AttachInternetGateway,ec2:CreateEgressOnlyInternetGateway,ec2:AttachVpnGateway.ec2:*,*","encrypt":false},{"key":"splitterChar","value":",","encrypt":false},{"key":"ruleKey","value":"iam-user-with-unapproved-access","isValueNew":true,"encrypt":false},{"key":"fixKey","value":"iam-user-with-unapproved-access-autofix","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"critical","key":"severity"},{"encrypt":false,"value":"security","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_core-networking-iam-user-with-unapproved-access_version-1_core-networking-iam-user-with-unapproved-access_iamuser","autofix":false,"alexaKeyword":"core-networking-iam-user-with-unapproved-access","ruleRestUrl":"","targetType":"iamuser","pac_ds":"aws","policyId":"PacMan_core-networking-iam-user-with-unapproved-access_version-1","assetGroup":"aws","ruleUUID":"aws_iamuser_shouldnothave_corenetwork_privileges","ruleType":"ManageRule"}' WHERE ruleId = 'PacMan_core-networking-iam-user-with-unapproved-access_version-1_core-networking-iam-user-with-unapproved-access_iamuser'; +UPDATE `cf_RuleInstance` SET ruleParams = '{"params":[{"encrypt":false,"value":"check-for-unused-elastic-ip","key":"ruleKey"},{"key":"threadsafe","value":"true","isValueNew":true,"encrypt":false},{"key":"fixKey","value":"unused-elastic-ip-fix","isValueNew":true,"encrypt":false},{"encrypt":false,"value":"high","key":"severity"},{"encrypt":false,"value":"governance","key":"ruleCategory"}],"environmentVariables":[],"ruleId":"PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip","autofix":false,"alexaKeyword":"UnusedElasticIpRule","ruleRestUrl":"","targetType":"elasticip","pac_ds":"aws","policyId":"PacMan_UnusedElasticIpRule_version-1","assetGroup":"aws","ruleUUID":"aws_elasticip_should_not_be_there_in_non_standard_region","ruleType":"ManageRule"}' WHERE ruleId = 'PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; /* This is to delete row with below entry as we need only entry with application='application' which is added in insert query*/ DELETE FROM pac_config_properties WHERE cfkey = 'tagging.mandatoryTags' AND application='api' AND profile='prd' AND label='latest'; + + +/* Update query for updating the description field of pac_config_key_metadata */ +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Admin Role key' WHERE `cfkey` = 'admin.api-role'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Time in for admin push notification polling' WHERE `cfkey` = 'admin.push.notification.pollinterval.milliseconds'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Slack handle for auth service' WHERE `cfkey` = 'api.auth.owner.slack.handle'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Configuration for backing up asset' WHERE `cfkey` = 'api.backup.asset.config'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Getting last action by rule engine' WHERE `cfkey` = 'api.getlastaction'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Posting last action by rule engine' WHERE `cfkey` = 'api.postlastaction'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Reactors URL for register' WHERE `cfkey` = 'api.register.reactors.url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Resource creation date key' WHERE `cfkey` = 'api.resource.creationdate'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Name of API service at 0 position' WHERE `cfkey` = 'api.services[0].name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'URL of API service at 0 position' WHERE `cfkey` = 'api.services[0].url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Version of API service at 0 position' WHERE `cfkey` = 'api.services[0].version'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Name of API service at 1 position' WHERE `cfkey` = 'api.services[1].name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'URL of API service at 1 position' WHERE `cfkey` = 'api.services[1].url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Version of API service at 1 position' WHERE `cfkey` = 'api.services[1].version'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Name of API service at 2 position' WHERE `cfkey` = 'api.services[2].name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'URL of API service at 2 position' WHERE `cfkey` = 'api.services[2].url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Version of API service at 2 position' WHERE `cfkey` = 'api.services[2].version'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Name of API service at 3 position' WHERE `cfkey` = 'api.services[3].name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'URL of API service at 3 position' WHERE `cfkey` = 'api.services[3].url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Version of API service at 3 position' WHERE `cfkey` = 'api.services[3].version'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Name of API service at 4 position' WHERE `cfkey` = 'api.services[4].name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'URL of API service at 4 position' WHERE `cfkey` = 'api.services[4].url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Version of API service at 4 position' WHERE `cfkey` = 'api.services[4].version'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Name of API service at 5 position' WHERE `cfkey` = 'api.services[5].name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'URL of API service at 5 position' WHERE `cfkey` = 'api.services[5].url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Version of API service at 5 position' WHERE `cfkey` = 'api.services[5].version'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Name of API service at 6 position' WHERE `cfkey` = 'api.services[6].name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'URL of API service at 6 position' WHERE `cfkey` = 'api.services[6].url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Version of API service at 6 position' WHERE `cfkey` = 'api.services[6].version'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Domains to be allowed in CORS' WHERE `cfkey` = 'application.cors.allowed.domains'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Authication type' WHERE `cfkey` = 'auth.active'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Autofix cut off date' WHERE `cfkey` = 'autofix.cufoff.date'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts for applying autofix for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'autofix.whitelist.accounts.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'AWS access key' WHERE `cfkey` = 'aws.access-key'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'AWS secret key' WHERE `cfkey` = 'aws.secret-key'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory client id' WHERE `cfkey` = 'azure.activedirectory.client-id'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory client secret' WHERE `cfkey` = 'azure.activedirectory.client-secret'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory scope' WHERE `cfkey` = 'azure.activedirectory.scope'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory scope description' WHERE `cfkey` = 'azure.activedirectory.scopeDesc'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory scope state' WHERE `cfkey` = 'azure.activedirectory.state'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory tenant-id' WHERE `cfkey` = 'azure.activedirectory.tenant-id'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory authorizeEndpoint' WHERE `cfkey` = 'azure.authorizeEndpoint'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory claims email' WHERE `cfkey` = 'azure.id-token.claims.email'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory claims first-name' WHERE `cfkey` = 'azure.id-token.claims.first-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory claims last-name' WHERE `cfkey` = 'azure.id-token.claims.last-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory claims user-id' WHERE `cfkey` = 'azure.id-token.claims.user-id'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory claims user-name' WHERE `cfkey` = 'azure.id-token.claims.user-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory issuer' WHERE `cfkey` = 'azure.issuer'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Azure active directory public-key' WHERE `cfkey` = 'azure.public-key'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'AWS base account' WHERE `cfkey` = 'base.account'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'AWS base region' WHERE `cfkey` = 'base.region'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Branch max age' WHERE `cfkey` = 'branch.maxBranchAge'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Cloud insight CORP password' WHERE `cfkey` = 'cloudinsights.corp-password'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Cloud insight CORP user-id' WHERE `cfkey` = 'cloudinsights.corp-user-id'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Cloud insight costurl' WHERE `cfkey` = 'cloudinsights.costurl'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Cloud insight tokenurl' WHERE `cfkey` = 'cloudinsights.tokenurl'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts to whitelist for S3CreateBucketAndUpdateBucketPolicyReactor' WHERE `cfkey` = 'com.tmobile.pacman.reactors.impl.s3.S3CreateBucketAndUpdateBucketPolicyReactor.account.whitelist'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts to whitelist for SampleReactor' WHERE `cfkey` = 'com.tmobile.pacman.reactors.impl.sample.SampleReactor.account.whitelist'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Accounts to whitelist for SampleReactor2' WHERE `cfkey` = 'com.tmobile.pacman.reactors.impl.sample.SampleReactor2.account.whitelist'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Cron frequency for weekly-report-sync-trigger' WHERE `cfkey` = 'cron.frequency.weekly-report-sync-trigger'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Date format across the application' WHERE `cfkey` = 'date.format'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Date range age across the application' WHERE `cfkey` = 'days-range.age'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Delete Sg Tag' WHERE `cfkey` = 'deleteSgTag'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'AWS role where data discovery is done' WHERE `cfkey` = 'discovery.role'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search admin host' WHERE `cfkey` = 'elastic-search.admin-host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search clusterName' WHERE `cfkey` = 'elastic-search.clusterName'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search clusterName-heimdall' WHERE `cfkey` = 'elastic-search.clusterName-heimdall'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search dev-ingest-host' WHERE `cfkey` = 'elastic-search.dev-ingest-host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search dev-ingest-port' WHERE `cfkey` = 'elastic-search.dev-ingest-port'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search host' WHERE `cfkey` = 'elastic-search.host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search host-heimdall' WHERE `cfkey` = 'elastic-search.host-heimdall'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search port' WHERE `cfkey` = 'elastic-search.port'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search port-admin' WHERE `cfkey` = 'elastic-search.port-admin'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search port-admin-heimdall' WHERE `cfkey` = 'elastic-search.port-admin-heimdall'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search port-heimdall' WHERE `cfkey` = 'elastic-search.port-heimdall'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search update-clusterName' WHERE `cfkey` = 'elastic-search.update-clusterName'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search update-host' WHERE `cfkey` = 'elastic-search.update-host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Elastic search update-port' WHERE `cfkey` = 'elastic-search.update-port'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Email banner name' WHERE `cfkey` = 'email.banner'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Endpoints refresh required' WHERE `cfkey` = 'endpoints.refresh.sensitive'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Logging level that needs to be logged in ES' WHERE `cfkey` = 'esLoggingLevel'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Feature certificates are enabled or not' WHERE `cfkey` = 'features.certificate.enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Feature patching are enabled or not' WHERE `cfkey` = 'features.patching.enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Feature vulnerability are enabled or not' WHERE `cfkey` = 'features.vulnerability.enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'File path for storing the inventory collected data' WHERE `cfkey` = 'file.path'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Date format across the application' WHERE `cfkey` = 'formats.date'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Heimdall host' WHERE `cfkey` = 'heimdall-host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Heimdall port' WHERE `cfkey` = 'heimdall-port'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Hystrix command default execution isolation thread timeout In Milliseconds' WHERE `cfkey` = 'hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Hystrix shareSecurityContext enabled' WHERE `cfkey` = 'hystrix.shareSecurityContext'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule engine lambda action disabled or not' WHERE `cfkey` = 'job.lambda.action-disabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule engine lambda action enabled or not' WHERE `cfkey` = 'job.lambda.action-enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule engine lambda function-arn value' WHERE `cfkey` = 'job.lambda.function-arn'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule engine lambda function-name value' WHERE `cfkey` = 'job.lambda.function-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule engine lambda principal value' WHERE `cfkey` = 'job.lambda.principal'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule engine lambda target-id value' WHERE `cfkey` = 'job.lambda.target-id'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Inventory collection bucket-name' WHERE `cfkey` = 'job.s3.bucket-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP AD domain name' WHERE `cfkey` = 'ldap.ad.domain'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP AD provider URL' WHERE `cfkey` = 'ldap.ad.provider-url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP AD search-base' WHERE `cfkey` = 'ldap.ad.search-base'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP baseDn' WHERE `cfkey` = 'ldap.baseDn'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP connection timeout' WHERE `cfkey` = 'ldap.connectionTimeout'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP domain' WHERE `cfkey` = 'ldap.domain'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP host list' WHERE `cfkey` = 'ldap.hostList'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP authentication naming' WHERE `cfkey` = 'ldap.naming.authentication'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP context-factory naming' WHERE `cfkey` = 'ldap.naming.context-factory'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP NT domain' WHERE `cfkey` = 'ldap.nt.domain'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP NT provider-url' WHERE `cfkey` = 'ldap.nt.provider-url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP NT search-base' WHERE `cfkey` = 'ldap.nt.search-base'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP port' WHERE `cfkey` = 'ldap.port'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'LDAP response timeout' WHERE `cfkey` = 'ldap.responseTimeout'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Logging configuration' WHERE `cfkey` = 'logging.config'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Logging console level' WHERE `cfkey` = 'logging.consoleLoggingLevel'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'ES host for logging' WHERE `cfkey` = 'logging.esHost'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'ES logging level' WHERE `cfkey` = 'logging.esLoggingLevel'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'ES port logging' WHERE `cfkey` = 'logging.esPort'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Magenta skill cache name' WHERE `cfkey` = 'magenta.cache.name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Magenta skill default background image url' WHERE `cfkey` = 'magenta.default-background'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Magenta skill error background image url' WHERE `cfkey` = 'magenta.error-background'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Magenta skill goodbye background image url' WHERE `cfkey` = 'magenta.goodbye-background'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Magenta skill goodbye greeting text' WHERE `cfkey` = 'magenta.goodbye-greeting'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Magenta skill welcome background image url' WHERE `cfkey` = 'magenta.welcome-background'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Magenta skill welcome greeting text' WHERE `cfkey` = 'magenta.welcome-greeting'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Management endpoints which should be exposed' WHERE `cfkey` = 'management.endpoints.web.exposure.include'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Management health rabbit enabled' WHERE `cfkey` = 'management.health.rabbit.enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Management health security enabled' WHERE `cfkey` = 'management.security.enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Services which needs to be monitored' WHERE `cfkey` = 'monitoring.contextRootNames'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot resource owner email when autofix fallback occurs ' WHERE `cfkey` = 'pacbot.autofix.resourceowner.fallbak.email'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Oauth2 client-id for pacbot api' WHERE `cfkey` = 'pacman.api.oauth2.client-id'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Oauth2 client-secret for pacbot api' WHERE `cfkey` = 'pacman.api.oauth2.client-secret'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot API for sending mail' WHERE `cfkey` = 'pacman.api.sendmail'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix common notification template for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.auto.fix.common.email.notifications.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail recipients' WHERE `cfkey` = 'pacman.auto.fix.mail.cc.to'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail from mailId' WHERE `cfkey` = 'pacman.auto.fix.mail.from'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail subject for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.auto.fix.mail.subject.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix mail template columns for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.auto.fix.mail.template.columns.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix maximum number of email notification for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.auto.fix.max.email.notifications.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix orphan resource owner email' WHERE `cfkey` = 'pacman.auto.fix.orphan.resource.owner'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix resource name filter pattern' WHERE `cfkey` = 'pacman.auto.fix.resource.name.filter.pattern'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix role name' WHERE `cfkey` = 'pacman.auto.fix.role.name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix tag algorithm' WHERE `cfkey` = 'pacman.auto.fix.tag.encyption.algorithm'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix tag name' WHERE `cfkey` = 'pacman.auto.fix.tag.name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix tag salt' WHERE `cfkey` = 'pacman.auto.fix.tag.salt'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix warning mail subject' WHERE `cfkey` = 'pacman.auto.warning.mail.subject.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix warning mail subject for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.auto.warning.mail.subject.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix warning mail subject for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.auto.warning.mail.subject.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix warning mail subject for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.auto.warning.mail.subject.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix warning mail subject for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.auto.warning.mail.subject.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix warning mail subject for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.auto.warning.mail.subject.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix warning mail subject for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.auto.warning.mail.subject.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix contact mailid for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'pacman.autofix.contact.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix contact mailid for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.autofix.contact.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix exempted types for cutoff data' WHERE `cfkey` = 'pacman.autofix.exempted.types.for.cutoff.data'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix notify for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'pacman.autofix.fix.notify.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix notify for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.autofix.fix.notify.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix fix type for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'pacman.autofix.fix.type.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix fix type for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.autofix.fix.type.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix issue creation time elapsed for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.autofix.issue.creation.time.elapsed.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix non taggable services' WHERE `cfkey` = 'pacman.autofix.non.taggable.services'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix policy URL for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.autofix.policy.url.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix policy URL for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.autofix.policy.url.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix policy URL path' WHERE `cfkey` = 'pacman.autofix.policy.url.path'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_Unused-Security-group_version-1_UnusedSecurityGroup_sg'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_UnusedElasticIpRule_version-1_UnusedElasticIpRule_elasticip'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule post fix message for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.autofix.rule.post.fix.message.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule violation message for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.autofix.rule.violation.message.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule violation message for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.autofix.rule.violation.message.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule violation message for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.autofix.rule.violation.message.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule violation message for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.autofix.rule.violation.message.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule violation message for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.autofix.rule.violation.message.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule violation message for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.autofix.rule.violation.message.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule violation message for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.autofix.rule.violation.message.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule warning message for PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2' WHERE `cfkey` = 'pacman.autofix.rule.warning.message.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule warning message for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.autofix.rule.warning.message.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule warning message for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.autofix.rule.warning.message.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule warning message for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.autofix.rule.warning.message.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule warning message for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.autofix.rule.warning.message.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule warning message for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.autofix.rule.warning.message.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix rule warning message for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.autofix.rule.warning.message.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix wait time for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.autofix.waittime.PacMan_EC2WithPublicIPAccess_version-1_Ec2WithPublicAccess_ec2'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix wait time for PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch' WHERE `cfkey` = 'pacman.autofix.waittime.PacMan_ElasticSearchPublicAccess_version-1_ElasticSearchPublicAccessRule_elasticsearch'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix wait time for PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb' WHERE `cfkey` = 'pacman.autofix.waittime.PacMan_ElbWithPublicAccess_version-1_ApplicationElbWithPublicAccess_appelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix wait time for PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb' WHERE `cfkey` = 'pacman.autofix.waittime.PacMan_ElbWithPublicAccess_version-1_ClassicElbWithPublicAccess_classicelb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix wait time for PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift' WHERE `cfkey` = 'pacman.autofix.waittime.PacMan_RedShiftPublicAccess_version-1_RedShiftPublicAccess_redshift'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix wait time for PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3' WHERE `cfkey` = 'pacman.autofix.waittime.PacMan_S3GlobalAccess_version-1_S3BucketShouldnotpubliclyaccessble_s3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix wait time for PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb' WHERE `cfkey` = 'pacman.autofix.waittime.PacMan_rdsdb_version-1_RdsDbPublicAccess_rdsdb'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix ES transaction index' WHERE `cfkey` = 'pacman.es.auto.fix.transaction.index'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot autofix ES transaction type' WHERE `cfkey` = 'pacman.es.auto.fix.transaction.type'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot ES host' WHERE `cfkey` = 'pacman.es.host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot ES port' WHERE `cfkey` = 'pacman.es.port'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot ES reactors index' WHERE `cfkey` = 'pacman.es.reactors.index'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot ES reactors registry' WHERE `cfkey` = 'pacman.es.reactors.registry'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot ES stats index' WHERE `cfkey` = 'pacman.es.stats.index'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot ES stats type' WHERE `cfkey` = 'pacman.es.stats.type'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot exempted mail subject' WHERE `cfkey` = 'pacman.exempted.mail.subject'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot host' WHERE `cfkey` = 'pacman.host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot integrations slack webhook url' WHERE `cfkey` = 'pacman.integrations.slack.webhook.url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot login password' WHERE `cfkey` = 'pacman.login.password'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot login user name' WHERE `cfkey` = 'pacman.login.user.name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot service password' WHERE `cfkey` = 'pacman.service-password'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot service user' WHERE `cfkey` = 'pacman.service-user'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot target type alias' WHERE `cfkey` = 'pacman.target.type.alias'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot URL' WHERE `cfkey` = 'pacman.url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot projections assetgroups' WHERE `cfkey` = 'projections.assetgroups'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot projections targetTypes' WHERE `cfkey` = 'projections.targetTypes'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot redshift password' WHERE `cfkey` = 'redshift.password'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot redshift URL' WHERE `cfkey` = 'redshift.url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Pacbot redshift user name' WHERE `cfkey` = 'redshift.userName'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'AWS region to ignore' WHERE `cfkey` = 'region.ignore'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Remind mail cron' WHERE `cfkey` = 'remind.cron'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Remind mail subject' WHERE `cfkey` = 'remind.email.subject'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Remind mail text' WHERE `cfkey` = 'remind.email.text'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule Engine invoke URL' WHERE `cfkey` = 'rule-engine.invoke.url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule lambda action disabled' WHERE `cfkey` = 'rule.lambda.action-disabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule lambda action enabled' WHERE `cfkey` = 'rule.lambda.action-enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule lambda function arn' WHERE `cfkey` = 'rule.lambda.function-arn'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule lambda function name' WHERE `cfkey` = 'rule.lambda.function-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule lambda principal' WHERE `cfkey` = 'rule.lambda.principal'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule lambda target-id' WHERE `cfkey` = 'rule.lambda.target-id'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Rule s3 bucket-name' WHERE `cfkey` = 'rule.s3.bucket-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 's3 inventory' WHERE `cfkey` = 's3'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 's3 data' WHERE `cfkey` = 's3.data'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 's3 processed' WHERE `cfkey` = 's3.processed'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 's3 region' WHERE `cfkey` = 's3.region'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 's3 role' WHERE `cfkey` = 's3.role'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Basic security enabled' WHERE `cfkey` = 'security.basic.enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Security oauth2 resource user-info-uri' WHERE `cfkey` = 'security.oauth2.resource.user-info-uri'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Server context-path' WHERE `cfkey` = 'server.context-path'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Server context-path' WHERE `cfkey` = 'server.context-path'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Server context-path' WHERE `cfkey` = 'server.contextPath'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Server servlet context-path' WHERE `cfkey` = 'server.servlet.context-path'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Server type' WHERE `cfkey` = 'server_type'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service dns name' WHERE `cfkey` = 'service.dns.name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service admin URL' WHERE `cfkey` = 'service.url.admin'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service asset URL' WHERE `cfkey` = 'service.url.asset'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service auth URL' WHERE `cfkey` = 'service.url.auth'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service compliance URL' WHERE `cfkey` = 'service.url.compliance'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service devstandards URL' WHERE `cfkey` = 'service.url.devstandards'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service pac_auth URL' WHERE `cfkey` = 'service.url.pac_auth'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service statistics URL' WHERE `cfkey` = 'service.url.statistics'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Service vulnerability URL' WHERE `cfkey` = 'service.url.vulnerability'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot admin client instance health URL' WHERE `cfkey` = 'spring.boot.admin.client.instance.health-url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot admin client instance management URL' WHERE `cfkey` = 'spring.boot.admin.client.instance.management-url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot admin client instance service URL' WHERE `cfkey` = 'spring.boot.admin.client.instance.service-url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot admin client password' WHERE `cfkey` = 'spring.boot.admin.client.password'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot admin client URL' WHERE `cfkey` = 'spring.boot.admin.client.url[0]'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot admin client user name' WHERE `cfkey` = 'spring.boot.admin.client.username'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot cache names' WHERE `cfkey` = 'spring.cache.cache-names'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot caffeine spec' WHERE `cfkey` = 'spring.cache.caffeine.spec'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot cloud bus enabled' WHERE `cfkey` = 'spring.cloud.bus.enabled'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot datasource driver-class-name' WHERE `cfkey` = 'spring.datasource.driver-class-name'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot datasource password' WHERE `cfkey` = 'spring.datasource.password'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot datasource url' WHERE `cfkey` = 'spring.datasource.url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot datasource user name' WHERE `cfkey` = 'spring.datasource.username'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot JPA hibernate naming physical strategy' WHERE `cfkey` = 'spring.jpa.hibernate.naming.physical-strategy'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail default encoding' WHERE `cfkey` = 'spring.mail.defaultEncoding'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail host' WHERE `cfkey` = 'spring.mail.host'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail password' WHERE `cfkey` = 'spring.mail.password'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail port' WHERE `cfkey` = 'spring.mail.port'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail properties mail smtp auth' WHERE `cfkey` = 'spring.mail.properties.mail.smtp.auth'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail properties mail smtp ssl trust' WHERE `cfkey` = 'spring.mail.properties.mail.smtp.ssl.trust'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail properties mail smtp start tls enable' WHERE `cfkey` = 'spring.mail.properties.mail.smtp.starttls.enable'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail protocol' WHERE `cfkey` = 'spring.mail.protocol'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail test connection' WHERE `cfkey` = 'spring.mail.test-connection'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot mail user name' WHERE `cfkey` = 'spring.mail.username'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot sleuth sampler probability' WHERE `cfkey` = 'spring.sleuth.sampler.probability'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot zipkin base URL' WHERE `cfkey` = 'spring.zipkin.baseUrl'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Spring boot zipkin sender type' WHERE `cfkey` = 'spring.zipkin.sender.type'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Square one slack channel' WHERE `cfkey` = 'square.one.slack.channel'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Swagger auth whitelist URLs' WHERE `cfkey` = 'swagger.auth.whitelist'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Mandatory tags for resources' WHERE `cfkey` = 'tagging.mandatoryTags'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Categories for different target types' WHERE `cfkey` = 'target-types.categories'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Template digest-mail URL' WHERE `cfkey` = 'template.digest-mail.url'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Timezone across the application' WHERE `cfkey` = 'time.zone'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Vulnerability application occurance' WHERE `cfkey` = 'vulnerability.application.occurance'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Vulnerability application resource details' WHERE `cfkey` = 'vulnerability.application.resourcedetails'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Vulnerability application resource details both' WHERE `cfkey` = 'vulnerability.application.resourcedetailsboth'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Vulnerability severity summary' WHERE `cfkey` = 'vulnerability.summary.severity'; +UPDATE `pacmandata`.`pac_config_key_metadata` SET `description` = 'Vulnerability types' WHERE `cfkey` = 'vulnerability.types'; + +DELETE FROM `pac_config_properties` WHERE cfkey='features.vulnerability.enabled'; +INSERT IGNORE INTO pac_config_properties(`cfkey`,`value`,`application`,`profile`,`label`,`createdBy`,`createdDate`,`modifiedBy`,`modifiedDate`) VALUES ('features.vulnerability.enabled',concat(@VULNERABILITY_FEATURE_ENABLED,''),'api','prd','latest',NULL,NULL,NULL,NULL); + + diff --git a/installer/resources/pacbot_app/import_db.py b/installer/resources/pacbot_app/import_db.py index be7581696..f0c05e6e3 100644 --- a/installer/resources/pacbot_app/import_db.py +++ b/installer/resources/pacbot_app/import_db.py @@ -73,7 +73,7 @@ def get_provisioners(self): 'ENV_SVC_CORP_PASSWORD': "password", 'ENV_CERTIFICATE_FEATURE_ENABLED': "false", 'ENV_PATCHING_FEATURE_ENABLED': "false", - 'ENV_VULNERABILITY_FEATURE_ENABLED': "false", + 'ENV_VULNERABILITY_FEATURE_ENABLED': str(Settings.get('ENABLE_VULNERABILITY_FEATURE', False)).lower(), 'ENV_MAIL_SERVER': Settings.MAIL_SERVER, 'ENV_PACMAN_S3': "pacman-email-templates", 'ENV_DATA_IN_DIR': "inventory", @@ -94,7 +94,9 @@ def get_provisioners(self): 'ENV_PACMAN_LOGIN_PASSWORD': "pacman", 'ENV_CONFIG_CREDENTIALS': "dXNlcjpwYWNtYW4=", 'ENV_CONFIG_SERVICE_URL': ApplicationLoadBalancer.get_http_url() + "/api/config/rule/prd/latest", - 'ENV_PACBOT_AUTOFIX_RESOURCEOWNER_FALLBACK_MAILID': Settings.get('USER_EMAIL_ID', "") + 'ENV_PACBOT_AUTOFIX_RESOURCEOWNER_FALLBACK_MAILID': Settings.get('USER_EMAIL_ID', ""), + 'ENV_QUALYS_INFO': Settings.get('QUALYS_INFO', ""), + 'ENV_QUALYS_API_URL': Settings.get('QUALYS_API_URL', "") }, 'interpreter': [Settings.PYTHON_INTERPRETER] } @@ -120,7 +122,7 @@ def get_provisioners(self): local_execs = [ { 'local-exec': { - 'command': "mysql -u %s -p%s -h %s < %s" % (db_user_name, db_password, db_host, ReplaceSQLPlaceHolder.dest_file) + 'command': "mysql -u %s --password=%s -h %s < %s" % (db_user_name, db_password, db_host, ReplaceSQLPlaceHolder.dest_file) } } diff --git a/installer/resources/pacbot_app/task_def_variables.py b/installer/resources/pacbot_app/task_def_variables.py index 02f665968..aa8446f5f 100644 --- a/installer/resources/pacbot_app/task_def_variables.py +++ b/installer/resources/pacbot_app/task_def_variables.py @@ -143,3 +143,12 @@ def get_auth_container_env_vars(self): {'name': "PACMAN_HOST_NAME", 'value': self.PACMAN_HOST_NAME}, {'name': "DOMAIN_URL", 'value': ApplicationLoadBalancer.get_api_server_url('auth')} ] + + def get_vulnerability_container_env_vars(self): + return [ + {'name': "JAR_FILE", 'value': "pacman-api-vulnerability.jar"}, + {'name': "CONFIG_PASSWORD", 'value': self.CONFIG_PASSWORD}, + {'name': "CONFIG_SERVER_URL", 'value': self.CONFIG_SERVER_URL}, + {'name': "PACMAN_HOST_NAME", 'value': self.PACMAN_HOST_NAME}, + {'name': "DOMAIN_URL", 'value': ApplicationLoadBalancer.get_api_server_url('vulnerability')} + ] diff --git a/installer/resources/pacbot_app/utils.py b/installer/resources/pacbot_app/utils.py new file mode 100644 index 000000000..230047c03 --- /dev/null +++ b/installer/resources/pacbot_app/utils.py @@ -0,0 +1,7 @@ +from core.config import Settings + + +def need_to_deploy_vulnerability_service(): + feature_status = Settings.get('ENABLE_VULNERABILITY_FEATURE', False) + + return feature_status diff --git a/installer/settings/common.py b/installer/settings/common.py index 01cd46615..a436a5cf8 100644 --- a/installer/settings/common.py +++ b/installer/settings/common.py @@ -116,6 +116,8 @@ MAIL_SMTP_SSL_ENABLE = "true" MAIL_SMTP_SSL_TEST_CONNECTION = "false" +ENABLE_VULNERABILITY_FEATURE = False + try: from settings.local import * except: diff --git a/installer/settings/default.local.py b/installer/settings/default.local.py index f28ba11ab..d8483ad63 100644 --- a/installer/settings/default.local.py +++ b/installer/settings/default.local.py @@ -20,7 +20,7 @@ # ElasticSearch Related Configurations ES_INSTANCE_TYPE = "m4.large.elasticsearch" # Possibble values m4.xlarge.elasticsearch, t2.xlarge.elasticsearch etc - +ES_VOLUME_SIZE = 20 # ALB related configurations MAKE_ALB_INTERNAL = True # False if ALB need to be public(internet facing) else True @@ -28,6 +28,7 @@ SSL_CERTIFICATE_ARN = "" # Required only if ALB_PROTOCOL is defined as HTTPS PACBOT_DOMAIN = "" # Required only if you point a CNAME record to ALB ex: app.pacbot.com + # MAIL Server configuration MAIL_SERVER = "localhost" MAIL_SERVER_PORT = 587 @@ -44,3 +45,9 @@ AWS_ACCESS_KEY = "" AWS_SECRET_KEY = "" AWS_REGION = "" + + +# This settings enable Vulnerability feature and servie +ENABLE_VULNERABILITY_FEATURE = False +QUALYS_API_URL = "" # Qualys API Url without trailing slash +QUALYS_INFO = "" #Base64 encoded user:password of qualys diff --git a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRule.java b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRule.java index 502dc0e3d..1d8c3645b 100644 --- a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRule.java +++ b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRule.java @@ -109,7 +109,7 @@ public RuleResult execute(final Map ruleParam,Map severityList = PacmanUtils.getSeverityVulnerabilitiesByInstanceId(instanceId,ec2WithVulnInfoForS5Url,severityVulnValue); if(!severityList.isEmpty()){ diff --git a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/Ec2InstanceScannedByQualysRule.java b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/ResourceScannedByQualysRule.java similarity index 75% rename from jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/Ec2InstanceScannedByQualysRule.java rename to jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/ResourceScannedByQualysRule.java index dd1df58a2..ae99cda31 100644 --- a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/Ec2InstanceScannedByQualysRule.java +++ b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/ec2/ResourceScannedByQualysRule.java @@ -45,24 +45,20 @@ import com.tmobile.pacman.commons.rule.RuleResult; /** - * The Class Ec2InstanceScannedByQualysRule. + * The Class ResourceScannedByQualysRule. */ -@PacmanRule(key = "check-for-ec2-scanned-by-qualys", desc = "checks for Ec2 instance scanned by qualys,if not found then its an issue", severity = PacmanSdkConstants.SEV_HIGH, category = PacmanSdkConstants.GOVERNANCE) -public class Ec2InstanceScannedByQualysRule extends BaseRule { +@PacmanRule(key = "check-for-resource-scanned-by-qualys", desc = "checks for Ec2 instance or VM scanned by qualys,if not found then its an issue", severity = PacmanSdkConstants.SEV_HIGH, category = PacmanSdkConstants.GOVERNANCE) +public class ResourceScannedByQualysRule extends BaseRule { /** The Constant logger. */ - private static final Logger logger = LoggerFactory.getLogger(Ec2InstanceScannedByQualysRule.class); - + private static final Logger logger = LoggerFactory.getLogger(ResourceScannedByQualysRule.class); + /** * The method will get triggered from Rule Engine with following parameters. * * @param ruleParam ************* Following are the Rule Parameters*********

* - * ruleKey : check-for-ec2-scanned-by-qualys

- * - * severity : Enter the value of severity

- * - * ruleCategory : Enter the value of category

+ * ruleKey : check-for-resource-scanned-by-qualys

* * target : Enter the target days

* @@ -70,13 +66,12 @@ public class Ec2InstanceScannedByQualysRule extends BaseRule { * * esQualysUrl : Enter the qualys URL

* - * threadsafe : if true , rule will be executed on multiple threads

* @param resourceAttributes this is a resource in context which needs to be scanned this is provided by execution engine * @return the rule result */ public RuleResult execute(final Map ruleParam,Map resourceAttributes) { - logger.debug("========Ec2InstanceScannedByQualysRule started========="); + logger.debug("========ResourceScannedByQualysRule started========="); Annotation annotation = null; String instanceId = null; String severity = ruleParam.get(PacmanRuleConstants.SEVERITY); @@ -85,7 +80,7 @@ public RuleResult execute(final Map ruleParam,Map ruleParam,Map issue = new LinkedHashMap<>(); Gson gson = new Gson(); - if (resourceAttributes != null && PacmanRuleConstants.RUNNING_STATE.equalsIgnoreCase(resourceAttributes.get(PacmanRuleConstants.STATE_NAME))) { - instanceId = StringUtils.trim(resourceAttributes.get(PacmanRuleConstants.INSTANCEID)); + if (resourceAttributes != null && (PacmanRuleConstants.RUNNING_STATE.equalsIgnoreCase(resourceAttributes.get(PacmanRuleConstants.STATE_NAME)) || PacmanRuleConstants.RUNNING_STATE.equalsIgnoreCase(resourceAttributes.get(PacmanRuleConstants.STATUS)))) { + String entityType = resourceAttributes.get(PacmanRuleConstants.ENTITY_TYPE); + instanceId = StringUtils.trim(resourceAttributes.get(PacmanRuleConstants.RESOURCE_ID)); if(PacmanUtils.calculateLaunchedDuration(firstDiscoveredOn)>Long.parseLong(discoveredDaysRange)){ Map ec2ScannesByQualysMap = new HashMap<>(); try{ @@ -119,23 +115,23 @@ public RuleResult execute(final Map ruleParam,Map ruleParam,Map
+ * + * ruleKey : check-for-resource-with-severity-vulnerabilities

+ * + * esResourceWithVulnInfoForSeverityUrl : Enter the EC2 or vm with Vuln info ES API

+ * + * severityVulnValue : Enter the severity level such as S5,S4 or S3

+ * + * @param resourceAttributes this is a resource in context which needs to be scanned this is provided by execution engine + * + */ + + public RuleResult execute(final Map ruleParam, Map resourceAttributes) { + logger.debug("========ResourcewithSeverityVulnerabilityRule started========="); + Annotation annotation = null; + String instanceId = null; + + String severity = ruleParam.get(PacmanRuleConstants.SEVERITY); + String category = ruleParam.get(PacmanRuleConstants.CATEGORY); + String resourceWithVulnInfoForSeverityUrl = null; + String severityVulnValue = ruleParam.get(PacmanRuleConstants.SEVERITY_VULN); + + String formattedUrl = PacmanUtils.formatUrl(ruleParam,PacmanRuleConstants.ES_RESOURCE_WITH_VULN_INFO_SEVERITY_URL); + + if(!StringUtils.isNullOrEmpty(formattedUrl)){ + resourceWithVulnInfoForSeverityUrl = formattedUrl; + } + + MDC.put("executionId", ruleParam.get("executionId")); + MDC.put("ruleId", ruleParam.get(PacmanSdkConstants.RULE_ID)); + + List>issueList = new ArrayList<>(); + LinkedHashMapissue = new LinkedHashMap<>(); + + if (!PacmanUtils.doesAllHaveValue(resourceWithVulnInfoForSeverityUrl, severityVulnValue,severity,category)) { + logger.info(PacmanRuleConstants.MISSING_CONFIGURATION); + throw new InvalidInputException(PacmanRuleConstants.MISSING_CONFIGURATION); + } + + if (resourceAttributes != null) { + String entityType = resourceAttributes.get(PacmanRuleConstants.ENTITY_TYPE); + instanceId = StringUtils.trim(resourceAttributes.get(PacmanRuleConstants.RESOURCE_ID)); + try { + List severityList = PacmanUtils.getSeverityVulnerabilitiesByInstanceId(instanceId,resourceWithVulnInfoForSeverityUrl, severityVulnValue); + if (!severityList.isEmpty()) { + + annotation = Annotation.buildAnnotation(ruleParam,Annotation.Type.ISSUE); + annotation.put(PacmanSdkConstants.DESCRIPTION,""+entityType+" instance with vulnerability "+ severityVulnValue + " found!!"); + annotation.put(PacmanRuleConstants.SEVERITY, severity); + annotation.put(PacmanRuleConstants.CATEGORY, category); + + issue.put(PacmanRuleConstants.VIOLATION_REASON, ""+entityType+" instance with vulnerability "+ severityVulnValue + " found!!"); + issue.put("voilation_title", String.join(",", severityList)); + issueList.add(issue); + annotation.put("issueDetails",issueList.toString()); + + logger.debug("========ResourcewithSeverityVulnerabilityRule ended with an annotation {} : =========", annotation); + return new RuleResult(PacmanSdkConstants.STATUS_FAILURE,PacmanRuleConstants.FAILURE_MESSAGE, annotation); + + } + } catch (Exception e) { + logger.error("error", e); + throw new RuleExecutionFailedExeption(e.getMessage()); + } + + } + logger.debug("========ResourcewithSeverityVulnerabilityRule ended========="); + return new RuleResult(PacmanSdkConstants.STATUS_SUCCESS,PacmanRuleConstants.SUCCESS_MESSAGE); + } + + public String getHelpText() { + return "This rule checks for an EC2 Instance or VM having severity (S5,S4,S3) vulnerability if so reports it as an issue with severity High"; + } + +} diff --git a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/s3/S3GlobalAccessRule.java b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/s3/S3GlobalAccessRule.java index 815dd496d..b1d3c9522 100644 --- a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/s3/S3GlobalAccessRule.java +++ b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/s3/S3GlobalAccessRule.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -28,7 +29,10 @@ import org.slf4j.MDC; import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.model.GetPublicAccessBlockRequest; +import com.amazonaws.services.s3.model.GetPublicAccessBlockResult; import com.amazonaws.services.s3.model.Permission; +import com.amazonaws.services.s3.model.PublicAccessBlockConfiguration; import com.tmobile.cloud.awsrules.utils.PacmanUtils; import com.tmobile.cloud.awsrules.utils.S3PacbotUtils; import com.tmobile.cloud.constants.PacmanRuleConstants; @@ -74,7 +78,7 @@ public RuleResult execute(Map ruleParam, Map res logger.debug("========S3GlobalAccessRule started========="); Map map = null; AmazonS3Client awsS3Client = null; - Map checkPolicyMap = new HashMap(); + Map checkPolicyMap = new HashMap(); String roleIdentifyingString = ruleParam.get(PacmanSdkConstants.Role_IDENTIFYING_STRING); String s3BucketName = ruleParam.get(PacmanSdkConstants.RESOURCE_ID); String checkEsUrl = null; @@ -91,6 +95,9 @@ public RuleResult execute(Map ruleParam, Map res boolean aclFound = false; boolean bucketPolicyFound = false; + Boolean isRequiredAclCheck = true; + Boolean isRequiredPublicPolicyCheck = true; + Boolean isRequiredTrustedAdvisorCheck = true; Map s3HasOpenAccess = new HashMap<>(); String checkId = ruleParam.get(PacmanRuleConstants.CHECK_ID); List sourcesverified = new ArrayList<>(); @@ -112,9 +119,42 @@ public RuleResult execute(Map ruleParam, Map res throw new InvalidInputException(e.toString()); } } + + if (null != awsS3Client) { + GetPublicAccessBlockRequest publicAccessBlockRequest = new GetPublicAccessBlockRequest(); + publicAccessBlockRequest.setBucketName(s3BucketName); + try { + GetPublicAccessBlockResult accessBlockResult = awsS3Client.getPublicAccessBlock(publicAccessBlockRequest); + PublicAccessBlockConfiguration accessBlockConfiguration = accessBlockResult.getPublicAccessBlockConfiguration(); + + if (accessBlockConfiguration.getBlockPublicAcls() && accessBlockConfiguration.getIgnorePublicAcls() && accessBlockConfiguration.getBlockPublicPolicy() && accessBlockConfiguration.getRestrictPublicBuckets()) { + logger.debug(s3BucketName,"This Bucket is not publicly accessible"); + return new RuleResult(PacmanSdkConstants.STATUS_SUCCESS,PacmanRuleConstants.SUCCESS_MESSAGE); + } + if(accessBlockConfiguration.getBlockPublicAcls() || accessBlockConfiguration.getIgnorePublicAcls()){ + isRequiredAclCheck = false; + } + if(accessBlockConfiguration.getBlockPublicPolicy() || accessBlockConfiguration.getRestrictPublicBuckets()){ + isRequiredPublicPolicyCheck = false; + } + + } catch (Exception e) { + if(e.getMessage().contains("Access Denied")){ + logger.debug(s3BucketName,"This Bucket is not publicly accessable"); + return new RuleResult(PacmanSdkConstants.STATUS_SUCCESS,PacmanRuleConstants.SUCCESS_MESSAGE); + } + logger.debug("no PublicAccessBlockConfiguration found, proceeding with ACL, policy and trusted advisor check {}",e); + } + } + + + logger.info("checking bucket has public access through ACL"); String accessType = "READ,WRITE,READ_ACP"; - Set permissions = S3PacbotUtils.checkACLPermissions(awsS3Client, s3BucketName, accessType); + Set permissions = new HashSet<>(); + if(isRequiredAclCheck){ + permissions = S3PacbotUtils.checkACLPermissions(awsS3Client, s3BucketName, accessType); + } if (!permissions.isEmpty()) { description = description + " through ACL"; @@ -126,7 +166,7 @@ public RuleResult execute(Map ruleParam, Map res PacmanRuleConstants.GLOBAL_ACCESS, sourcesverified, accessLevels, resourceAttributes.get(PacmanRuleConstants.RESOURCE_ID))); - } else if (isPolicyTrue(awsS3Client, s3BucketName, accessType,checkPolicyMap)) { + } else if (isRequiredPublicPolicyCheck && isPolicyTrue(awsS3Client, s3BucketName, accessType,checkPolicyMap)) { List policyTypeList = new ArrayList<>(); for(Map.Entry policyType : checkPolicyMap.entrySet()){ policyTypeList.add(policyType.getKey()); @@ -143,7 +183,7 @@ public RuleResult execute(Map ruleParam, Map res PacmanRuleConstants.GLOBAL_ACCESS, sourcesverified, accessLevels, resourceAttributes.get(PacmanRuleConstants.RESOURCE_ID))); - }else{ + }else if(isRequiredTrustedAdvisorCheck){ // check bucket is opened through TA logger.info("checking S3 bucket has public access from Trusted Advisor"); @@ -180,9 +220,8 @@ public RuleResult execute(Map ruleParam, Map res } logger.info(s3BucketName, "This Bucket is not publicly accessable"); return new RuleResult(PacmanSdkConstants.STATUS_SUCCESS, PacmanRuleConstants.SUCCESS_MESSAGE); - + } -} /* * (non-Javadoc) * @@ -201,5 +240,4 @@ private boolean isPolicyTrue(AmazonS3Client awsS3Client, String s3BucketName, St } return false; } - } diff --git a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/utils/PacmanUtils.java b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/utils/PacmanUtils.java index 2d137fa22..247043160 100644 --- a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/utils/PacmanUtils.java +++ b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/awsrules/utils/PacmanUtils.java @@ -1144,6 +1144,7 @@ public static List getSeverityVulnerabilitiesByInstanceId(String instanc Map mustNotFilter = new HashMap<>(); HashMultimap shouldFilter = HashMultimap.create(); Map mustTermsFilter = new HashMap<>(); + mustFilter.put(PacmanRuleConstants.LATEST, PacmanRuleConstants.TRUE_VAL); mustFilter.put(convertAttributetoKeyword(PacmanRuleConstants.SEVERITY), severityVulnValue); mustFilter.put(convertAttributetoKeyword(PacmanRuleConstants.RESOURCE_ID), instanceId); JsonObject resultJson = RulesElasticSearchRepositoryUtil.getQueryDetailsFromES(ec2WithVulnUrl, mustFilter, @@ -2122,8 +2123,8 @@ public static List splitStringToAList(String toSplit, String separator){ */ public static Long calculateLaunchedDuration(String formattedDateString) { if(formattedDateString!=null){ - LocalDate expiryDate = LocalDateTime.parse(formattedDateString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toLocalDate(); - LocalDate today = LocalDateTime.now().toLocalDate(); + LocalDate expiryDate = LocalDate.parse(formattedDateString); + LocalDate today = LocalDate.now(); return java.time.temporal.ChronoUnit.DAYS.between(expiryDate, today); }else{ return 0l; @@ -2853,5 +2854,59 @@ private static String returnFieldValue(JsonArray jsonArray,String fieldKey) { } return null; } + + /** + * Check instance id for port rule in ES. + * + * @param instanceId + * the instance id + * @param ec2PortUrl + * the ec 2 port url + * @param ruleId + * the rule id + * @param type + * the type + * @return true, if successful + * @throws Exception + * the exception + */ + public static boolean checkInstanceIdForPortRuleInES(String instanceId, String ec2PortUrl, String ruleId, + String type) throws Exception { + JsonParser jsonParser = new JsonParser(); + String resourceid = null; + Map mustFilter = new HashMap<>(); + Map mustNotFilter = new HashMap<>(); + HashMultimap shouldFilter = HashMultimap.create(); + Map mustTermsFilter = new HashMap<>(); + if (StringUtils.isEmpty(type)) { + shouldFilter.put(convertAttributetoKeyword(PacmanSdkConstants.ISSUE_STATUS_KEY), + PacmanSdkConstants.STATUS_OPEN); + } else { + shouldFilter.put(convertAttributetoKeyword(PacmanSdkConstants.ISSUE_STATUS_KEY), + PacmanSdkConstants.STATUS_OPEN); + shouldFilter.put(convertAttributetoKeyword(PacmanSdkConstants.ISSUE_STATUS_KEY), + PacmanRuleConstants.STATUS_EXEMPTED); + } + + mustFilter.put(convertAttributetoKeyword(PacmanSdkConstants.RULE_ID), ruleId); + mustFilter.put(convertAttributetoKeyword(PacmanSdkConstants.RESOURCE_ID), instanceId); + + JsonObject resultJson = RulesElasticSearchRepositoryUtil.getQueryDetailsFromES(ec2PortUrl, mustFilter, + mustNotFilter, shouldFilter, null, 0, mustTermsFilter, null, null); + + if (resultJson != null && resultJson.has(PacmanRuleConstants.HITS)) { + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get(PacmanRuleConstants.HITS).toString()); + JsonArray hitsArray = hitsJson.getAsJsonArray(PacmanRuleConstants.HITS); + for (int i = 0; i < hitsArray.size(); i++) { + JsonObject source = hitsArray.get(i).getAsJsonObject().get(PacmanRuleConstants.SOURCE) + .getAsJsonObject(); + resourceid = source.get(PacmanSdkConstants.RESOURCE_ID).getAsString(); + if (!org.apache.commons.lang.StringUtils.isEmpty(resourceid)) { + return true; + } + } + } + return false; + } } diff --git a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/constants/PacmanRuleConstants.java b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/constants/PacmanRuleConstants.java index 30b292013..61af8b2ea 100644 --- a/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/constants/PacmanRuleConstants.java +++ b/jobs/pacman-awsrules/src/main/java/com/tmobile/cloud/constants/PacmanRuleConstants.java @@ -353,4 +353,6 @@ private PacmanRuleConstants() { public static final String ACCESSLOGS_ENABLED_REGIONS = "accessLogsEnabledRegions"; public static final String RULE_ID = "ruleId"; public static final String STATUS_EXEMPTED = "exempted"; + public static final String ES_RESOURCE_WITH_VULN_INFO_SEVERITY_URL = "esResourceWithVulnInfoForSeverityUrl"; + public static final int FIRST_DISCOVERED_DATE_FORMAT_LENGTH = 10; } diff --git a/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRuleTest.java b/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRuleTest.java index 2ffec662c..84dc72c6d 100644 --- a/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRuleTest.java +++ b/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/Ec2PublicAccessPortWithS5vulnerabilitiesRuleTest.java @@ -47,13 +47,13 @@ public void executeTest() throws Exception { when(PacmanUtils.doesAllHaveValue(anyString(),anyString(),anyString(),anyString(),anyString(),anyString())).thenReturn( true); when(PacmanUtils.getPacmanHost(anyString())).thenReturn("host"); - when(PacmanUtils.checkInstanceIdForPortRuleInES(anyString(),anyString(),anyString())).thenReturn(true); + when(PacmanUtils.checkInstanceIdForPortRuleInES(anyString(),anyString(),anyString(),anyString())).thenReturn(true); assertThat(ec2PublicAccessPortWithS5vulnerabilitiesRule.execute(CommonTestUtils.getMapString("r_123 "),CommonTestUtils.getMapString("r_123 ")), is(notNullValue())); when(PacmanUtils.getSeverityVulnerabilitiesByInstanceId(anyString(),anyString(),anyString())).thenReturn(CommonTestUtils.getListString()); assertThat(ec2PublicAccessPortWithS5vulnerabilitiesRule.execute(CommonTestUtils.getMapString("r_123 "),CommonTestUtils.getMapString("r_123 ")), is(notNullValue())); - when(PacmanUtils.checkInstanceIdForPortRuleInES(anyString(),anyString(),anyString())).thenThrow(new Exception()); + when(PacmanUtils.checkInstanceIdForPortRuleInES(anyString(),anyString(),anyString(),anyString())).thenThrow(new Exception()); assertThatThrownBy( () -> ec2PublicAccessPortWithS5vulnerabilitiesRule.execute(CommonTestUtils.getMapString("r_123 "),CommonTestUtils.getMapString("r_123 "))).isInstanceOf(RuleExecutionFailedExeption.class); diff --git a/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/Ec2InstanceScannedByQualysRuleTest.java b/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/ResourceScannedByQualysRuleTest.java similarity index 95% rename from jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/Ec2InstanceScannedByQualysRuleTest.java rename to jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/ResourceScannedByQualysRuleTest.java index 501b22bac..e813a046b 100644 --- a/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/Ec2InstanceScannedByQualysRuleTest.java +++ b/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/ResourceScannedByQualysRuleTest.java @@ -37,10 +37,10 @@ @RunWith(PowerMockRunner.class) @PrepareForTest({ PacmanUtils.class}) -public class Ec2InstanceScannedByQualysRuleTest { +public class ResourceScannedByQualysRuleTest { @InjectMocks - Ec2InstanceScannedByQualysRule ec2InstanceScannedByQualysRule; + ResourceScannedByQualysRule ec2InstanceScannedByQualysRule; @Test public void executeTest() throws Exception { diff --git a/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/ResourceWithSeverityVulnerabilityRuleTest.java b/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/ResourceWithSeverityVulnerabilityRuleTest.java new file mode 100644 index 000000000..e9f14ab2b --- /dev/null +++ b/jobs/pacman-awsrules/src/test/java/com/tmobile/cloud/awsrules/ec2/ResourceWithSeverityVulnerabilityRuleTest.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.cloud.awsrules.ec2; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.tmobile.cloud.awsrules.utils.CommonTestUtils; +import com.tmobile.cloud.awsrules.utils.PacmanUtils; +import com.tmobile.pacman.commons.exception.InvalidInputException; +import com.tmobile.pacman.commons.exception.RuleExecutionFailedExeption; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ PacmanUtils.class}) +public class ResourceWithSeverityVulnerabilityRuleTest { + + @InjectMocks + ResourceWithSeverityVulnerabilityRule ec2withSeverityVulnerabilityRule; + + @Test + public void executeTest() throws Exception { + mockStatic(PacmanUtils.class); + when(PacmanUtils.doesAllHaveValue(anyString(),anyString(),anyString(),anyString())).thenReturn( + true); + when(PacmanUtils.formatUrl(anyObject(),anyString())).thenReturn("host"); + when(PacmanUtils.getSeverityVulnerabilitiesByInstanceId(anyString(),anyString(),anyString())).thenReturn(CommonTestUtils.getListString()); + assertThat(ec2withSeverityVulnerabilityRule.execute(CommonTestUtils.getMapString("r_123 "),CommonTestUtils.getMapString("r_123 ")), is(notNullValue())); + + assertThat(ec2withSeverityVulnerabilityRule.execute(CommonTestUtils.getMapString("r_123 "),null), is(notNullValue())); + + when(PacmanUtils.getSeverityVulnerabilitiesByInstanceId(anyString(),anyString(),anyString())).thenThrow(new Exception()); + assertThatThrownBy( + () -> ec2withSeverityVulnerabilityRule.execute(CommonTestUtils.getMapString("r_123 "),CommonTestUtils.getMapString("r_123 "))).isInstanceOf(RuleExecutionFailedExeption.class); + + when(PacmanUtils.doesAllHaveValue(anyString(),anyString(),anyString(),anyString())).thenReturn( + false); + assertThatThrownBy( + () -> ec2withSeverityVulnerabilityRule.execute(CommonTestUtils.getMapString("r_123 "),CommonTestUtils.getMapString("r_123 "))).isInstanceOf(InvalidInputException.class); + + } + + @Test + public void getHelpTextTest(){ + assertThat(ec2withSeverityVulnerabilityRule.getHelpText(), is(notNullValue())); + } +} diff --git a/jobs/pacman-cloud-notifications/target/classes/META-INF/maven/com.tmobile.pacman.cloud/pacman-cloud-notifications/pom.xml b/jobs/pacman-cloud-notifications/target/classes/META-INF/maven/com.tmobile.pacman.cloud/pacman-cloud-notifications/pom.xml deleted file mode 100644 index 522c85fdf..000000000 --- a/jobs/pacman-cloud-notifications/target/classes/META-INF/maven/com.tmobile.pacman.cloud/pacman-cloud-notifications/pom.xml +++ /dev/null @@ -1,263 +0,0 @@ - - 4.0.0 - - com.tmobile.pacman.cloud - pacman-cloud-notifications - 0.0.1-SNAPSHOT - jar - - pacman-cloud-notifications - Cloud Notification service - - - UTF-8 - 1.8 - 1.6.4 - - - - org.powermock - powermock-api-mockito - ${powermock.version} - test - - - - org.powermock - powermock-module-junit4 - ${powermock.version} - test - - - - org.powermock - powermock-module-junit4 - ${powermock.version} - test - - - - org.mockito - mockito-core - 1.10.19 - test - - - org.springframework - spring-context - 4.3.8.RELEASE - - - org.springframework - spring-test - 5.0.8.RELEASE - test - - - com.google.guava - guava - 19.0 - - - org.apache.logging.log4j - log4j-api - 2.9.0 - - - org.apache.logging.log4j - log4j-core - 2.9.0 - - - org.elasticsearch - elasticsearch - 5.6.2 - - - org.elasticsearch.client - transport - 5.6.2 - - - - com.google.code.gson - gson - 2.8.1 - - - - commons-collections - commons-collections - 3.2.2 - - - org.apache.commons - commons-lang3 - 3.1 - - - com.tmobile.pacman - batch-commons - 1.0.0-SNAPSHOT - provided - - - com.amazonaws - aws-java-sdk-s3 - - - com.amazonaws - aws-java-sdk-rds - - - com.amazonaws - aws-java-sdk-events - - - com.amazonaws - aws-java-sdk-cloudwatch - - - com.amazonaws - aws-java-sdk-dynamodb - - - com.amazonaws - aws-java-sdk-cloudtrail - - - com.amazonaws - aws-java-sdk-core - - - com.amazonaws - - aws-java-sdk-elasticloadbalancingv2 - - - - com.amazonaws - aws-java-sdk-ec2 - - - com.amazonaws - aws-java-sdk-ses - - - com.amazonaws - aws-java-sdk-kms - - - com.amazonaws - aws-lambda-java-core - - - com.amazonaws - aws-java-sdk-iam - - - com.amazonaws - aws-java-sdk-config - - - com.amazonaws - aws-java-sdk-route53 - - - com.amazonaws - aws-java-sdk-sts - - - com.amazonaws - aws-java-sdk-api-gateway - - - com.amazonaws - aws-java-sdk-lambda - - - com.amazonaws - aws-java-sdk-guardduty - - - com.amazonaws - - aws-java-sdk-elasticloadbalancing - - - - - - org.apache.httpcomponents - httpclient - 4.5.3 - - - org.elasticsearch.client - rest - 5.3.0 - - - com.fasterxml.jackson.core - jackson-databind - 2.8.7 - - - mysql - mysql-connector-java - 5.1.17 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 - - 1.8 - 1.8 - - - - maven-assembly-plugin - - - build-a - - - jar-with-dependencies - - pacman-cloud-notifications - - package - - single - - - - - - org.jacoco - jacoco-maven-plugin - 0.7.6.201602180812 - - - - prepare-agent - - - - report - test - - report - - - - - - - \ No newline at end of file diff --git a/jobs/pacman-data-shipper/pom.xml b/jobs/pacman-data-shipper/pom.xml index 5983be8cc..a0d5dd557 100644 --- a/jobs/pacman-data-shipper/pom.xml +++ b/jobs/pacman-data-shipper/pom.xml @@ -144,7 +144,7 @@ com.fasterxml.jackson.core jackson-databind - 2.9.9.3 + 2.9.10 mysql diff --git a/jobs/pacman-data-shipper/src/main/java/com/tmobile/cso/pacman/datashipper/entity/AssetGroupStatsCollector.java b/jobs/pacman-data-shipper/src/main/java/com/tmobile/cso/pacman/datashipper/entity/AssetGroupStatsCollector.java index 4e8035b15..edaffcb76 100644 --- a/jobs/pacman-data-shipper/src/main/java/com/tmobile/cso/pacman/datashipper/entity/AssetGroupStatsCollector.java +++ b/jobs/pacman-data-shipper/src/main/java/com/tmobile/cso/pacman/datashipper/entity/AssetGroupStatsCollector.java @@ -27,6 +27,9 @@ public class AssetGroupStatsCollector implements Constants{ /** The Constant compApiUri. */ private static final String COMP_API_URL = System.getenv("CMPL_API_URL"); + + /** The Constant compApiUri. */ + private static final String VULN_API_URL = System.getenv("VULN_API_URL"); /** The ag stats. */ @@ -80,6 +83,9 @@ public List> collectAssetGroupStats() { ESManager.createType(AG_STATS, "compliance", errorList); ESManager.createType(AG_STATS, "tagcompliance", errorList); ESManager.createType(AG_STATS, "issues", errorList); + if(VULN_API_URL!=null) + ESManager.createType(AG_STATS, "vulncompliance", errorList); + List assetGroups = new ArrayList<>(assetGroupMap.keySet()); @@ -164,6 +170,26 @@ public List> collectAssetGroupStats() { } } }); + + if(VULN_API_URL!=null) { + executor.execute(() -> { + try { + uploadAssetGroupVulnCompliance(assetGroups); + } catch (Exception e) { + log.error("Exception in uploadAssetGroupVulnCompliance " , e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Exception in uploadAssetGroupVulnCompliance"); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + synchronized(errorList){ + errorList.add(errorMap); + } + } + }); + } + + + executor.shutdown(); while (!executor.isTerminated()); @@ -387,4 +413,41 @@ public void uploadAssetGroupIssues(Map> assetGroups) throws ESManager.uploadData(AG_STATS, "issues", docs, "@id", false); log.info(" End Collecing issues"); } + + /** + * Upload asset group vuln compliance. + * + * @param assetGroups the asset groups + * @throws Exception the exception + */ + public void uploadAssetGroupVulnCompliance(List assetGroups) throws Exception { + + + log.info(" Start Collecing vuln compliance"); + List> docs = new ArrayList<>(); + for (String ag : assetGroups) { + try { + Map doc = AssetGroupUtil.fetchVulnSummary(VULN_API_URL, ag, getToken()); + if (!doc.isEmpty()) { + doc.put("ag", ag); + doc.put("date", CURR_DATE); + doc.put("@id", Util.getUniqueID(ag + CURR_DATE)); + docs.add(doc); + } + } catch (Exception e) { + log.error("Exception in uploadAssetGroupVulnCompliance" , e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Exception in uploadAssetGroupVulnCompliance for Asset Group"+ag); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + synchronized(errorList){ + errorList.add(errorMap); + } + } + } + ESManager.uploadData(AG_STATS, "vulncompliance", docs, "@id", false); + log.info(" End Collecing vuln compliance"); + } + + } diff --git a/jobs/pacman-qualys-enricher/pom.xml b/jobs/pacman-qualys-enricher/pom.xml new file mode 100644 index 000000000..3ab8146f2 --- /dev/null +++ b/jobs/pacman-qualys-enricher/pom.xml @@ -0,0 +1,190 @@ + + 4.0.0 + com.tmobile.cso.pacman + pacman-qualys-enricher + 0.0.1-SNAPSHOT + + + org.elasticsearch.client + rest + 5.3.0 + + + + org.slf4j + slf4j-api + 1.7.25 + + + mysql + mysql-connector-java + 5.1.17 + + + com.google.code.gson + gson + 2.8.5 + + + com.google.guava + guava + 18.0 + + + commons-httpclient + commons-httpclient + 3.1 + + + + com.tmobile.cloud + batch-commons + 1.0.0-SNAPSHOT + provided + + + com.amazonaws + aws-java-sdk-s3 + + + com.amazonaws + aws-java-sdk-rds + + + com.amazonaws + aws-java-sdk-events + + + org.reflections + reflections + + + com.amazonaws + aws-java-sdk-cloudwatch + + + com.amazonaws + aws-java-sdk-dynamodb + + + com.amazonaws + aws-java-sdk-cloudtrail + + + com.amazonaws + + aws-java-sdk-elasticloadbalancingv2 + + + + com.google.guava + guava + + + com.amazonaws + aws-java-sdk-ec2 + + + com.amazonaws + aws-java-sdk-ses + + + com.amazonaws + aws-lambda-java-core + + + com.amazonaws + aws-java-sdk-iam + + + com.amazonaws + aws-java-sdk-config + + + com.amazonaws + aws-java-sdk-route53 + + + commons-httpclient + commons-httpclient + + + com.amazonaws + aws-java-sdk-sts + + + com.google.code.gson + gson + + + com.amazonaws + aws-java-sdk-api-gateway + + + com.amazonaws + aws-java-sdk-lambda + + + com.amazonaws + aws-java-sdk-guardduty + + + com.amazonaws + + aws-java-sdk-elasticloadbalancing + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + maven-assembly-plugin + + + build-a + + + jar-with-dependencies + + qualys-enricher + + package + + single + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + install + + + + + + + + run + + + + + + + \ No newline at end of file diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/Constants.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/Constants.java new file mode 100644 index 000000000..a481978c9 --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/Constants.java @@ -0,0 +1,53 @@ +package com.tmobile.cso.pacman.qualys; + + +/** + * The Interface Constants. + */ +public interface Constants { + + /** The aws ec2. */ + String AWS_EC2 = "aws_ec2"; + + /** The resource id. */ + String RESOURCE_ID = "_resourceid"; + + /** The doc id. */ + String DOC_ID = "_docid"; + + /** The vuln missing. */ + String VULN_MISSING = "vulnInfoMissing"; + + /** The processed. */ + String PROCESSED = "processed"; + + /** The uploaded. */ + String UPLOADED = "uploaded"; + + /** The failed. */ + String FAILED = "failed"; + + /** The error. */ + String ERROR = "error"; + + /** The exception. */ + String EXCEPTION = "exception"; + + /** The error type. */ + String ERROR_TYPE = "type"; + + /** The warn. */ + String WARN = "warn"; + + /** The fatal. */ + String FATAL = "fatal"; + + /** The source. */ + String SOURCE = "source"; + + /** The name. */ + String NAME = "name"; + + /** The config creds. */ + String CONFIG_CREDS = "config_creds"; +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/Main.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/Main.java new file mode 100644 index 000000000..538d5277a --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/Main.java @@ -0,0 +1,72 @@ +package com.tmobile.cso.pacman.qualys; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.naming.NamingException; + +import com.tmobile.cso.pacman.qualys.jobs.HostAssetDataImporter; +import com.tmobile.cso.pacman.qualys.jobs.KBDataImporter; +import com.tmobile.cso.pacman.qualys.util.ErrorManageUtil; +import com.tmobile.pacman.commons.jobs.PacmanJob; + + +/** + * The Class Main. + */ +@PacmanJob(methodToexecute = "execute", jobName = "Qualys Enricher", desc = "Job to enrich qualys data in ES", priority = 5) +public class Main { + + /** + * The main method. + * + * @param args the arguments + * @throws Exception the exception + */ + public static void main(String[] args) throws Exception { + Map params = new HashMap<>(); + Arrays.asList(args).stream().forEach(obj -> { + String[] paramArray = obj.split("[:]"); + params.put(paramArray[0], paramArray[1]); + }); + execute(params); + } + + /** + * Execute. + * + * @param params the params + * @return + * @throws NamingException the naming exception + */ + public static Map execute(Map params) throws NamingException { + + Map errorInfo = new HashMap<>() ; + List> errorList = new ArrayList<>(); + try { + MainUtil.setup(params); + } catch (Exception e) { + Map errorMap = new HashMap<>(); + errorMap.put(Constants.ERROR, "Exception in setting up Job "); + errorMap.put(Constants.ERROR_TYPE, Constants.WARN); + errorMap.put(Constants.EXCEPTION, e.getMessage()); + errorList.add(errorMap); + return ErrorManageUtil.formErrorCode(errorList); + } + + String jobHint = params.get("job_hint"); + switch (jobHint) { + case "qualys": + errorInfo = new HostAssetDataImporter().execute(); + break; + case "qualys-kb": + errorInfo = new KBDataImporter().execute(); + break; + } + return errorInfo; + } + +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/MainUtil.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/MainUtil.java new file mode 100644 index 000000000..1fe0351cb --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/MainUtil.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.cso.pacman.qualys; + +import java.util.Map; + +import com.tmobile.cso.pacman.qualys.util.ConfigUtil; + + +/** + * The Class MainUtil. + */ +public class MainUtil { + + /** + * Setup. + * + * @param params the params + * @throws Exception the exception + */ + public static void setup(Map params) throws Exception { + + ConfigUtil.setConfigProperties(params.get(Constants.CONFIG_CREDS)); + + if( !(params==null || params.isEmpty())){ + params.forEach((k,v) -> System.setProperty(k, v)); + } + + } + +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/dto/KNOWLEDGEBASEVULNLISTOUTPUT.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/dto/KNOWLEDGEBASEVULNLISTOUTPUT.java new file mode 100644 index 000000000..e00de7981 --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/dto/KNOWLEDGEBASEVULNLISTOUTPUT.java @@ -0,0 +1,5370 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2017.04.12 at 11:40:54 AM PDT +// + +package com.tmobile.cso.pacman.qualys.dto; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.datatype.XMLGregorianCalendar; + + +/** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content contained within + * this class. + * + *

+ * <complexType>
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="RESPONSE">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ *                   <element name="VULN_LIST">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="VULN" maxOccurs="unbounded" minOccurs="0">
+ *                               <complexType>
+ *                                 <complexContent>
+ *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                     <sequence>
+ *                                       <element name="QID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+ *                                       <element name="VULN_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="SEVERITY_LEVEL" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+ *                                       <element name="TITLE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="CATEGORY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="LAST_SERVICE_MODIFICATION_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ *                                       <element name="PUBLISHED_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ *                                       <element name="DETECTION_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="BUGTRAQ_LIST">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="BUGTRAQ" maxOccurs="unbounded" minOccurs="0">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="ID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+ *                                                           <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="PATCHABLE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+ *                                       <element name="SOFTWARE_LIST">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="SOFTWARE" maxOccurs="unbounded" minOccurs="0">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="PRODUCT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="VENDOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="VENDOR_REFERENCE_LIST">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="VENDOR_REFERENCE" maxOccurs="unbounded" minOccurs="0">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="URL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="CVE_LIST">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="CVE" maxOccurs="unbounded" minOccurs="0">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="DIAGNOSIS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="DIAGNOSIS_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="CONSEQUENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="CONSEQUENCE_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="SOLUTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="SOLUTION_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="COMPLIANCE_LIST">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="COMPLIANCE" maxOccurs="unbounded" minOccurs="0">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="SECTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="DESCRIPTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="CORRELATION">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="EXPLOITS">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="EXPLT_SRC" maxOccurs="unbounded" minOccurs="0">
+ *                                                             <complexType>
+ *                                                               <complexContent>
+ *                                                                 <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                                   <sequence>
+ *                                                                     <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                     <element name="EXPLT_LIST">
+ *                                                                       <complexType>
+ *                                                                         <complexContent>
+ *                                                                           <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                                             <choice maxOccurs="unbounded" minOccurs="0">
+ *                                                                               <element name="EXPLT">
+ *                                                                                 <complexType>
+ *                                                                                   <complexContent>
+ *                                                                                     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                                                       <sequence>
+ *                                                                                         <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                                         <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                                         <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+ *                                                                                       </sequence>
+ *                                                                                     </restriction>
+ *                                                                                   </complexContent>
+ *                                                                                 </complexType>
+ *                                                                               </element>
+ *                                                                             </choice>
+ *                                                                           </restriction>
+ *                                                                         </complexContent>
+ *                                                                       </complexType>
+ *                                                                     </element>
+ *                                                                   </sequence>
+ *                                                                 </restriction>
+ *                                                               </complexContent>
+ *                                                             </complexType>
+ *                                                           </element>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                                 <element name="MALWARE">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="MW_SRC" maxOccurs="unbounded" minOccurs="0">
+ *                                                             <complexType>
+ *                                                               <complexContent>
+ *                                                                 <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                                   <sequence>
+ *                                                                     <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                     <element name="MW_LIST">
+ *                                                                       <complexType>
+ *                                                                         <complexContent>
+ *                                                                           <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                                             <sequence>
+ *                                                                               <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+ *                                                                                 <complexType>
+ *                                                                                   <complexContent>
+ *                                                                                     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                                                       <sequence>
+ *                                                                                         <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                                         <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                                         <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                                         <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                                         <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                                                         <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+ *                                                                                       </sequence>
+ *                                                                                     </restriction>
+ *                                                                                   </complexContent>
+ *                                                                                 </complexType>
+ *                                                                               </element>
+ *                                                                             </sequence>
+ *                                                                           </restriction>
+ *                                                                         </complexContent>
+ *                                                                       </complexType>
+ *                                                                     </element>
+ *                                                                   </sequence>
+ *                                                                 </restriction>
+ *                                                               </complexContent>
+ *                                                             </complexType>
+ *                                                           </element>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="CVSS">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+ *                                                 <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+ *                                                 <element name="ACCESS">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                                 <element name="IMPACT">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                                 <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                 <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                 <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                 <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="CVSS_V3">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+ *                                                 <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+ *                                                 <element name="ACCESS">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                                 <element name="IMPACT">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                           <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                                 <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                 <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                 <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                                 <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="PCI_FLAG" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+ *                                       <element name="PCI_REASONS">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="PCI_REASON" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="SUPPORTED_MODULES" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                       <element name="DISCOVERY">
+ *                                         <complexType>
+ *                                           <complexContent>
+ *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                               <sequence>
+ *                                                 <element name="REMOTE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+ *                                                 <element name="AUTH_TYPE_LIST">
+ *                                                   <complexType>
+ *                                                     <complexContent>
+ *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                                         <sequence>
+ *                                                           <element name="AUTH_TYPE" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *                                                         </sequence>
+ *                                                       </restriction>
+ *                                                     </complexContent>
+ *                                                   </complexType>
+ *                                                 </element>
+ *                                                 <element name="ADDITIONAL_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                               </sequence>
+ *                                             </restriction>
+ *                                           </complexContent>
+ *                                         </complexType>
+ *                                       </element>
+ *                                       <element name="IS_DISABLED" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *                                     </sequence>
+ *                                   </restriction>
+ *                                 </complexContent>
+ *                               </complexType>
+ *                             </element>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { "response" }) +@XmlRootElement(name = "KNOWLEDGE_BASE_VULN_LIST_OUTPUT") +public class KNOWLEDGEBASEVULNLISTOUTPUT { + + /** The response. */ + @XmlElement(name = "RESPONSE", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE response; + + /** + * Gets the value of the response property. + * + * @return possible object is {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE getRESPONSE() { + return response; + } + + /** + * Sets the value of the response property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE } + * + */ + public void setRESPONSE(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE value) { + this.response = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content contained + * within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+     *         <element name="VULN_LIST">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="VULN" maxOccurs="unbounded" minOccurs="0">
+     *                     <complexType>
+     *                       <complexContent>
+     *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                           <sequence>
+     *                             <element name="QID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+     *                             <element name="VULN_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="SEVERITY_LEVEL" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+     *                             <element name="TITLE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="CATEGORY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="LAST_SERVICE_MODIFICATION_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+     *                             <element name="PUBLISHED_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+     *                             <element name="DETECTION_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="BUGTRAQ_LIST">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="BUGTRAQ" maxOccurs="unbounded" minOccurs="0">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="ID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+     *                                                 <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="PATCHABLE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+     *                             <element name="SOFTWARE_LIST">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="SOFTWARE" maxOccurs="unbounded" minOccurs="0">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="PRODUCT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="VENDOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="VENDOR_REFERENCE_LIST">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="VENDOR_REFERENCE" maxOccurs="unbounded" minOccurs="0">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="URL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="CVE_LIST">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="CVE" maxOccurs="unbounded" minOccurs="0">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="DIAGNOSIS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="DIAGNOSIS_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="CONSEQUENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="CONSEQUENCE_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="SOLUTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="SOLUTION_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="COMPLIANCE_LIST">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="COMPLIANCE" maxOccurs="unbounded" minOccurs="0">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="SECTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="DESCRIPTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="CORRELATION">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="EXPLOITS">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="EXPLT_SRC" maxOccurs="unbounded" minOccurs="0">
+     *                                                   <complexType>
+     *                                                     <complexContent>
+     *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                                         <sequence>
+     *                                                           <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                           <element name="EXPLT_LIST">
+     *                                                             <complexType>
+     *                                                               <complexContent>
+     *                                                                 <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                                                   <choice maxOccurs="unbounded" minOccurs="0">
+     *                                                                     <element name="EXPLT">
+     *                                                                       <complexType>
+     *                                                                         <complexContent>
+     *                                                                           <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                                                             <sequence>
+     *                                                                               <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                                               <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                                               <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+     *                                                                             </sequence>
+     *                                                                           </restriction>
+     *                                                                         </complexContent>
+     *                                                                       </complexType>
+     *                                                                     </element>
+     *                                                                   </choice>
+     *                                                                 </restriction>
+     *                                                               </complexContent>
+     *                                                             </complexType>
+     *                                                           </element>
+     *                                                         </sequence>
+     *                                                       </restriction>
+     *                                                     </complexContent>
+     *                                                   </complexType>
+     *                                                 </element>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                       <element name="MALWARE">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="MW_SRC" maxOccurs="unbounded" minOccurs="0">
+     *                                                   <complexType>
+     *                                                     <complexContent>
+     *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                                         <sequence>
+     *                                                           <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                           <element name="MW_LIST">
+     *                                                             <complexType>
+     *                                                               <complexContent>
+     *                                                                 <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                                                   <sequence>
+     *                                                                     <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+     *                                                                       <complexType>
+     *                                                                         <complexContent>
+     *                                                                           <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                                                             <sequence>
+     *                                                                               <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                                               <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                                               <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                                               <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                                               <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                                               <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+     *                                                                             </sequence>
+     *                                                                           </restriction>
+     *                                                                         </complexContent>
+     *                                                                       </complexType>
+     *                                                                     </element>
+     *                                                                   </sequence>
+     *                                                                 </restriction>
+     *                                                               </complexContent>
+     *                                                             </complexType>
+     *                                                           </element>
+     *                                                         </sequence>
+     *                                                       </restriction>
+     *                                                     </complexContent>
+     *                                                   </complexType>
+     *                                                 </element>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="CVSS">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+     *                                       <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+     *                                       <element name="ACCESS">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                       <element name="IMPACT">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                       <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                       <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                       <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                       <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="CVSS_V3">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+     *                                       <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+     *                                       <element name="ACCESS">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                       <element name="IMPACT">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                                 <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                       <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                       <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                       <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                       <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="PCI_FLAG" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+     *                             <element name="PCI_REASONS">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="PCI_REASON" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="SUPPORTED_MODULES" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                             <element name="DISCOVERY">
+     *                               <complexType>
+     *                                 <complexContent>
+     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                     <sequence>
+     *                                       <element name="REMOTE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+     *                                       <element name="AUTH_TYPE_LIST">
+     *                                         <complexType>
+     *                                           <complexContent>
+     *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                                               <sequence>
+     *                                                 <element name="AUTH_TYPE" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+     *                                               </sequence>
+     *                                             </restriction>
+     *                                           </complexContent>
+     *                                         </complexType>
+     *                                       </element>
+     *                                       <element name="ADDITIONAL_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                                     </sequence>
+     *                                   </restriction>
+     *                                 </complexContent>
+     *                               </complexType>
+     *                             </element>
+     *                             <element name="IS_DISABLED" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *                           </sequence>
+     *                         </restriction>
+     *                       </complexContent>
+     *                     </complexType>
+     *                   </element>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "datetime", "vulnlist" }) + public static class RESPONSE { + + /** The datetime. */ + @XmlElement(name = "DATETIME", required = true) + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar datetime; + + /** The vulnlist. */ + @XmlElement(name = "VULN_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST vulnlist; + + /** + * Gets the value of the datetime property. + * + * @return possible object is {@link XMLGregorianCalendar } + * + */ + public XMLGregorianCalendar getDATETIME() { + return datetime; + } + + /** + * Sets the value of the datetime property. + * + * @param value + * allowed object is {@link XMLGregorianCalendar } + * + */ + public void setDATETIME(XMLGregorianCalendar value) { + this.datetime = value; + } + + /** + * Gets the value of the vulnlist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST getVULNLIST() { + return vulnlist; + } + + /** + * Sets the value of the vulnlist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST } + * + */ + public void setVULNLIST(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST value) { + this.vulnlist = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="VULN" maxOccurs="unbounded" minOccurs="0">
+         *           <complexType>
+         *             <complexContent>
+         *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                 <sequence>
+         *                   <element name="QID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+         *                   <element name="VULN_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="SEVERITY_LEVEL" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+         *                   <element name="TITLE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="CATEGORY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="LAST_SERVICE_MODIFICATION_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+         *                   <element name="PUBLISHED_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+         *                   <element name="DETECTION_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="BUGTRAQ_LIST">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="BUGTRAQ" maxOccurs="unbounded" minOccurs="0">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="ID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+         *                                       <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="PATCHABLE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+         *                   <element name="SOFTWARE_LIST">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="SOFTWARE" maxOccurs="unbounded" minOccurs="0">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="PRODUCT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="VENDOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="VENDOR_REFERENCE_LIST">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="VENDOR_REFERENCE" maxOccurs="unbounded" minOccurs="0">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="URL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="CVE_LIST">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="CVE" maxOccurs="unbounded" minOccurs="0">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="DIAGNOSIS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="DIAGNOSIS_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="CONSEQUENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="CONSEQUENCE_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="SOLUTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="SOLUTION_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="COMPLIANCE_LIST">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="COMPLIANCE" maxOccurs="unbounded" minOccurs="0">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="SECTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="DESCRIPTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="CORRELATION">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="EXPLOITS">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="EXPLT_SRC" maxOccurs="unbounded" minOccurs="0">
+         *                                         <complexType>
+         *                                           <complexContent>
+         *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                               <sequence>
+         *                                                 <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                 <element name="EXPLT_LIST">
+         *                                                   <complexType>
+         *                                                     <complexContent>
+         *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                                         <choice maxOccurs="unbounded" minOccurs="0">
+         *                                                           <element name="EXPLT">
+         *                                                             <complexType>
+         *                                                               <complexContent>
+         *                                                                 <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                                                   <sequence>
+         *                                                                     <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                                     <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                                     <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+         *                                                                   </sequence>
+         *                                                                 </restriction>
+         *                                                               </complexContent>
+         *                                                             </complexType>
+         *                                                           </element>
+         *                                                         </choice>
+         *                                                       </restriction>
+         *                                                     </complexContent>
+         *                                                   </complexType>
+         *                                                 </element>
+         *                                               </sequence>
+         *                                             </restriction>
+         *                                           </complexContent>
+         *                                         </complexType>
+         *                                       </element>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                             <element name="MALWARE">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="MW_SRC" maxOccurs="unbounded" minOccurs="0">
+         *                                         <complexType>
+         *                                           <complexContent>
+         *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                               <sequence>
+         *                                                 <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                 <element name="MW_LIST">
+         *                                                   <complexType>
+         *                                                     <complexContent>
+         *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                                         <sequence>
+         *                                                           <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+         *                                                             <complexType>
+         *                                                               <complexContent>
+         *                                                                 <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                                                   <sequence>
+         *                                                                     <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                                     <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                                     <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                                     <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                                     <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                                                     <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+         *                                                                   </sequence>
+         *                                                                 </restriction>
+         *                                                               </complexContent>
+         *                                                             </complexType>
+         *                                                           </element>
+         *                                                         </sequence>
+         *                                                       </restriction>
+         *                                                     </complexContent>
+         *                                                   </complexType>
+         *                                                 </element>
+         *                                               </sequence>
+         *                                             </restriction>
+         *                                           </complexContent>
+         *                                         </complexType>
+         *                                       </element>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="CVSS">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+         *                             <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+         *                             <element name="ACCESS">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                             <element name="IMPACT">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                             <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                             <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                             <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                             <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="CVSS_V3">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+         *                             <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+         *                             <element name="ACCESS">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                             <element name="IMPACT">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                       <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                             <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                             <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                             <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                             <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="PCI_FLAG" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+         *                   <element name="PCI_REASONS">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="PCI_REASON" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="SUPPORTED_MODULES" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                   <element name="DISCOVERY">
+         *                     <complexType>
+         *                       <complexContent>
+         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                           <sequence>
+         *                             <element name="REMOTE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+         *                             <element name="AUTH_TYPE_LIST">
+         *                               <complexType>
+         *                                 <complexContent>
+         *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *                                     <sequence>
+         *                                       <element name="AUTH_TYPE" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+         *                                     </sequence>
+         *                                   </restriction>
+         *                                 </complexContent>
+         *                               </complexType>
+         *                             </element>
+         *                             <element name="ADDITIONAL_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                           </sequence>
+         *                         </restriction>
+         *                       </complexContent>
+         *                     </complexType>
+         *                   </element>
+         *                   <element name="IS_DISABLED" type="{http://www.w3.org/2001/XMLSchema}string"/>
+         *                 </sequence>
+         *               </restriction>
+         *             </complexContent>
+         *           </complexType>
+         *         </element>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "vuln" }) + public static class VULNLIST { + + /** The vuln. */ + @XmlElement(name = "VULN") + protected List vuln; + + /** + * Gets the value of the vuln property. + * + *

+ * This accessor method returns a reference to the live list, not a + * snapshot. Therefore any modification you make to the returned + * list will be present inside the JAXB object. This is why there is + * not a set method for the vuln property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+             * getVULN().add(newItem);
+             * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN } + * + * @return the vuln + */ + public List getVULN() { + if (vuln == null) { + vuln = new ArrayList<>(); + } + return this.vuln; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+             * <complexType>
+             *   <complexContent>
+             *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *       <sequence>
+             *         <element name="QID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+             *         <element name="VULN_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="SEVERITY_LEVEL" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+             *         <element name="TITLE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="CATEGORY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="LAST_SERVICE_MODIFICATION_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+             *         <element name="PUBLISHED_DATETIME" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+             *         <element name="DETECTION_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="BUGTRAQ_LIST">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="BUGTRAQ" maxOccurs="unbounded" minOccurs="0">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="ID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+             *                             <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="PATCHABLE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+             *         <element name="SOFTWARE_LIST">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="SOFTWARE" maxOccurs="unbounded" minOccurs="0">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="PRODUCT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="VENDOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="VENDOR_REFERENCE_LIST">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="VENDOR_REFERENCE" maxOccurs="unbounded" minOccurs="0">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="URL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="CVE_LIST">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="CVE" maxOccurs="unbounded" minOccurs="0">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="DIAGNOSIS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="DIAGNOSIS_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="CONSEQUENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="CONSEQUENCE_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="SOLUTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="SOLUTION_COMMENT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="COMPLIANCE_LIST">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="COMPLIANCE" maxOccurs="unbounded" minOccurs="0">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="SECTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="DESCRIPTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="CORRELATION">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="EXPLOITS">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="EXPLT_SRC" maxOccurs="unbounded" minOccurs="0">
+             *                               <complexType>
+             *                                 <complexContent>
+             *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                                     <sequence>
+             *                                       <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                       <element name="EXPLT_LIST">
+             *                                         <complexType>
+             *                                           <complexContent>
+             *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                                               <choice maxOccurs="unbounded" minOccurs="0">
+             *                                                 <element name="EXPLT">
+             *                                                   <complexType>
+             *                                                     <complexContent>
+             *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                                                         <sequence>
+             *                                                           <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                                           <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                                           <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+             *                                                         </sequence>
+             *                                                       </restriction>
+             *                                                     </complexContent>
+             *                                                   </complexType>
+             *                                                 </element>
+             *                                               </choice>
+             *                                             </restriction>
+             *                                           </complexContent>
+             *                                         </complexType>
+             *                                       </element>
+             *                                     </sequence>
+             *                                   </restriction>
+             *                                 </complexContent>
+             *                               </complexType>
+             *                             </element>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                   <element name="MALWARE">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="MW_SRC" maxOccurs="unbounded" minOccurs="0">
+             *                               <complexType>
+             *                                 <complexContent>
+             *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                                     <sequence>
+             *                                       <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                       <element name="MW_LIST">
+             *                                         <complexType>
+             *                                           <complexContent>
+             *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                                               <sequence>
+             *                                                 <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+             *                                                   <complexType>
+             *                                                     <complexContent>
+             *                                                       <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                                                         <sequence>
+             *                                                           <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                                           <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                                           <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                                           <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                                           <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                                                           <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+             *                                                         </sequence>
+             *                                                       </restriction>
+             *                                                     </complexContent>
+             *                                                   </complexType>
+             *                                                 </element>
+             *                                               </sequence>
+             *                                             </restriction>
+             *                                           </complexContent>
+             *                                         </complexType>
+             *                                       </element>
+             *                                     </sequence>
+             *                                   </restriction>
+             *                                 </complexContent>
+             *                               </complexType>
+             *                             </element>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="CVSS">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+             *                   <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+             *                   <element name="ACCESS">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                   <element name="IMPACT">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                   <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                   <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                   <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                   <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="CVSS_V3">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+             *                   <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+             *                   <element name="ACCESS">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                   <element name="IMPACT">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                             <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                   <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                   <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                   <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                   <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="PCI_FLAG" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+             *         <element name="PCI_REASONS">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="PCI_REASON" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="SUPPORTED_MODULES" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *         <element name="DISCOVERY">
+             *           <complexType>
+             *             <complexContent>
+             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                 <sequence>
+             *                   <element name="REMOTE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+             *                   <element name="AUTH_TYPE_LIST">
+             *                     <complexType>
+             *                       <complexContent>
+             *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+             *                           <sequence>
+             *                             <element name="AUTH_TYPE" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+             *                           </sequence>
+             *                         </restriction>
+             *                       </complexContent>
+             *                     </complexType>
+             *                   </element>
+             *                   <element name="ADDITIONAL_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *                 </sequence>
+             *               </restriction>
+             *             </complexContent>
+             *           </complexType>
+             *         </element>
+             *         <element name="IS_DISABLED" type="{http://www.w3.org/2001/XMLSchema}string"/>
+             *       </sequence>
+             *     </restriction>
+             *   </complexContent>
+             * </complexType>
+             * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "qid", "vulntype", "severitylevel", "title", "category", + "lastservicemodificationdatetime", "publisheddatetime", "detectioninfo", "bugtraqlist", "patchable", + "softwarelist", "vendorreferencelist", "cvelist", "diagnosis", "diagnosiscomment", "consequence", + "consequencecomment", "solution", "solutioncomment", "compliancelist", "correlation", "cvss", + "cvssv3", "pciflag", "pcireasons", "supportedmodules", "discovery", "isdisabled" }) + public static class VULN { + + /** The qid. */ + @XmlElement(name = "QID") + protected long qid; + + /** The vulntype. */ + @XmlElement(name = "VULN_TYPE", required = true) + protected String vulntype; + + /** The severitylevel. */ + @XmlElement(name = "SEVERITY_LEVEL") + protected byte severitylevel; + + /** The title. */ + @XmlElement(name = "TITLE", required = true) + protected String title; + + /** The category. */ + @XmlElement(name = "CATEGORY", required = true) + protected String category; + + /** The lastservicemodificationdatetime. */ + @XmlElement(name = "LAST_SERVICE_MODIFICATION_DATETIME", required = true) + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar lastservicemodificationdatetime; + + /** The publisheddatetime. */ + @XmlElement(name = "PUBLISHED_DATETIME", required = true) + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar publisheddatetime; + + /** The detectioninfo. */ + @XmlElement(name = "DETECTION_INFO", required = true) + protected String detectioninfo; + + /** The bugtraqlist. */ + @XmlElement(name = "BUGTRAQ_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST bugtraqlist; + + /** The patchable. */ + @XmlElement(name = "PATCHABLE") + protected byte patchable; + + /** The softwarelist. */ + @XmlElement(name = "SOFTWARE_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST softwarelist; + + /** The vendorreferencelist. */ + @XmlElement(name = "VENDOR_REFERENCE_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST vendorreferencelist; + + /** The cvelist. */ + @XmlElement(name = "CVE_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST cvelist; + + /** The diagnosis. */ + @XmlElement(name = "DIAGNOSIS", required = true) + protected String diagnosis; + + /** The diagnosiscomment. */ + @XmlElement(name = "DIAGNOSIS_COMMENT", required = true) + protected String diagnosiscomment; + + /** The consequence. */ + @XmlElement(name = "CONSEQUENCE", required = true) + protected String consequence; + + /** The consequencecomment. */ + @XmlElement(name = "CONSEQUENCE_COMMENT", required = true) + protected String consequencecomment; + + /** The solution. */ + @XmlElement(name = "SOLUTION", required = true) + protected String solution; + + /** The solutioncomment. */ + @XmlElement(name = "SOLUTION_COMMENT", required = true) + protected String solutioncomment; + + /** The compliancelist. */ + @XmlElement(name = "COMPLIANCE_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST compliancelist; + + /** The correlation. */ + @XmlElement(name = "CORRELATION", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION correlation; + + /** The cvss. */ + @XmlElement(name = "CVSS", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS cvss; + + /** The cvssv 3. */ + @XmlElement(name = "CVSS_V3", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 cvssv3; + + /** The pciflag. */ + @XmlElement(name = "PCI_FLAG") + protected byte pciflag; + + /** The pcireasons. */ + @XmlElement(name = "PCI_REASONS", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS pcireasons; + + /** The supportedmodules. */ + @XmlElement(name = "SUPPORTED_MODULES", required = true) + protected String supportedmodules; + + /** The discovery. */ + @XmlElement(name = "DISCOVERY", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY discovery; + + /** The isdisabled. */ + @XmlElement(name = "IS_DISABLED", required = true) + protected String isdisabled; + + /** + * Gets the value of the qid property. + * + * @return the qid + */ + public long getQID() { + return qid; + } + + /** + * Sets the value of the qid property. + * + * @param value the new qid + */ + public void setQID(long value) { + this.qid = value; + } + + /** + * Gets the value of the vulntype property. + * + * @return possible object is {@link String } + * + */ + public String getVULNTYPE() { + return vulntype; + } + + /** + * Sets the value of the vulntype property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setVULNTYPE(String value) { + this.vulntype = value; + } + + /** + * Gets the value of the severitylevel property. + * + * @return the severitylevel + */ + public byte getSEVERITYLEVEL() { + return severitylevel; + } + + /** + * Sets the value of the severitylevel property. + * + * @param value the new severitylevel + */ + public void setSEVERITYLEVEL(byte value) { + this.severitylevel = value; + } + + /** + * Gets the value of the title property. + * + * @return possible object is {@link String } + * + */ + public String getTITLE() { + return title; + } + + /** + * Sets the value of the title property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setTITLE(String value) { + this.title = value; + } + + /** + * Gets the value of the category property. + * + * @return possible object is {@link String } + * + */ + public String getCATEGORY() { + return category; + } + + /** + * Sets the value of the category property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setCATEGORY(String value) { + this.category = value; + } + + /** + * Gets the value of the lastservicemodificationdatetime + * property. + * + * @return possible object is {@link XMLGregorianCalendar } + * + */ + public XMLGregorianCalendar getLASTSERVICEMODIFICATIONDATETIME() { + return lastservicemodificationdatetime; + } + + /** + * Sets the value of the lastservicemodificationdatetime + * property. + * + * @param value + * allowed object is {@link XMLGregorianCalendar } + * + */ + public void setLASTSERVICEMODIFICATIONDATETIME(XMLGregorianCalendar value) { + this.lastservicemodificationdatetime = value; + } + + /** + * Gets the value of the publisheddatetime property. + * + * @return possible object is {@link XMLGregorianCalendar } + * + */ + public XMLGregorianCalendar getPUBLISHEDDATETIME() { + return publisheddatetime; + } + + /** + * Sets the value of the publisheddatetime property. + * + * @param value + * allowed object is {@link XMLGregorianCalendar } + * + */ + public void setPUBLISHEDDATETIME(XMLGregorianCalendar value) { + this.publisheddatetime = value; + } + + /** + * Gets the value of the detectioninfo property. + * + * @return possible object is {@link String } + * + */ + public String getDETECTIONINFO() { + return detectioninfo; + } + + /** + * Sets the value of the detectioninfo property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setDETECTIONINFO(String value) { + this.detectioninfo = value; + } + + /** + * Gets the value of the bugtraqlist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST getBUGTRAQLIST() { + return bugtraqlist; + } + + /** + * Sets the value of the bugtraqlist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST } + * + */ + public void setBUGTRAQLIST(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST value) { + this.bugtraqlist = value; + } + + /** + * Gets the value of the patchable property. + * + * @return the patchable + */ + public byte getPATCHABLE() { + return patchable; + } + + /** + * Sets the value of the patchable property. + * + * @param value the new patchable + */ + public void setPATCHABLE(byte value) { + this.patchable = value; + } + + /** + * Gets the value of the softwarelist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST getSOFTWARELIST() { + return softwarelist; + } + + /** + * Sets the value of the softwarelist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST } + * + */ + public void setSOFTWARELIST(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST value) { + this.softwarelist = value; + } + + /** + * Gets the value of the vendorreferencelist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST getVENDORREFERENCELIST() { + return vendorreferencelist; + } + + /** + * Sets the value of the vendorreferencelist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST } + * + */ + public void setVENDORREFERENCELIST( + KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST value) { + this.vendorreferencelist = value; + } + + /** + * Gets the value of the cvelist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST getCVELIST() { + return cvelist; + } + + /** + * Sets the value of the cvelist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST } + * + */ + public void setCVELIST(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST value) { + this.cvelist = value; + } + + /** + * Gets the value of the diagnosis property. + * + * @return possible object is {@link String } + * + */ + public String getDIAGNOSIS() { + return diagnosis; + } + + /** + * Sets the value of the diagnosis property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setDIAGNOSIS(String value) { + this.diagnosis = value; + } + + /** + * Gets the value of the diagnosiscomment property. + * + * @return possible object is {@link String } + * + */ + public String getDIAGNOSISCOMMENT() { + return diagnosiscomment; + } + + /** + * Sets the value of the diagnosiscomment property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setDIAGNOSISCOMMENT(String value) { + this.diagnosiscomment = value; + } + + /** + * Gets the value of the consequence property. + * + * @return possible object is {@link String } + * + */ + public String getCONSEQUENCE() { + return consequence; + } + + /** + * Sets the value of the consequence property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setCONSEQUENCE(String value) { + this.consequence = value; + } + + /** + * Gets the value of the consequencecomment property. + * + * @return possible object is {@link String } + * + */ + public String getCONSEQUENCECOMMENT() { + return consequencecomment; + } + + /** + * Sets the value of the consequencecomment property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setCONSEQUENCECOMMENT(String value) { + this.consequencecomment = value; + } + + /** + * Gets the value of the solution property. + * + * @return possible object is {@link String } + * + */ + public String getSOLUTION() { + return solution; + } + + /** + * Sets the value of the solution property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setSOLUTION(String value) { + this.solution = value; + } + + /** + * Gets the value of the solutioncomment property. + * + * @return possible object is {@link String } + * + */ + public String getSOLUTIONCOMMENT() { + return solutioncomment; + } + + /** + * Sets the value of the solutioncomment property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setSOLUTIONCOMMENT(String value) { + this.solutioncomment = value; + } + + /** + * Gets the value of the compliancelist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST getCOMPLIANCELIST() { + return compliancelist; + } + + /** + * Sets the value of the compliancelist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST } + * + */ + public void setCOMPLIANCELIST(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST value) { + this.compliancelist = value; + } + + /** + * Gets the value of the correlation property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION getCORRELATION() { + return correlation; + } + + /** + * Sets the value of the correlation property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION } + * + */ + public void setCORRELATION(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION value) { + this.correlation = value; + } + + /** + * Gets the value of the cvss property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS getCVSS() { + return cvss; + } + + /** + * Sets the value of the cvss property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS } + * + */ + public void setCVSS(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS value) { + this.cvss = value; + } + + /** + * Gets the value of the cvssv3 property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 getCVSSV3() { + return cvssv3; + } + + /** + * Sets the value of the cvssv3 property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 } + * + */ + public void setCVSSV3(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 value) { + this.cvssv3 = value; + } + + /** + * Gets the value of the pciflag property. + * + * @return the pciflag + */ + public byte getPCIFLAG() { + return pciflag; + } + + /** + * Sets the value of the pciflag property. + * + * @param value the new pciflag + */ + public void setPCIFLAG(byte value) { + this.pciflag = value; + } + + /** + * Gets the value of the pcireasons property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS getPCIREASONS() { + return pcireasons; + } + + /** + * Sets the value of the pcireasons property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS } + * + */ + public void setPCIREASONS(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS value) { + this.pcireasons = value; + } + + /** + * Gets the value of the supportedmodules property. + * + * @return possible object is {@link String } + * + */ + public String getSUPPORTEDMODULES() { + return supportedmodules; + } + + /** + * Sets the value of the supportedmodules property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setSUPPORTEDMODULES(String value) { + this.supportedmodules = value; + } + + /** + * Gets the value of the discovery property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY getDISCOVERY() { + return discovery; + } + + /** + * Sets the value of the discovery property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY } + * + */ + public void setDISCOVERY(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY value) { + this.discovery = value; + } + + /** + * Gets the value of the isdisabled property. + * + * @return possible object is {@link String } + * + */ + public String getISDISABLED() { + return isdisabled; + } + + /** + * Sets the value of the isdisabled property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setISDISABLED(String value) { + this.isdisabled = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="BUGTRAQ" maxOccurs="unbounded" minOccurs="0">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="ID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+                 *                   <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "bugtraq" }) + public static class BUGTRAQLIST { + + /** The bugtraq. */ + @XmlElement(name = "BUGTRAQ") + protected List bugtraq; + + /** + * Gets the value of the bugtraq property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you make + * to the returned list will be present inside the JAXB + * object. This is why there is not a set + * method for the bugtraq property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                     * getBUGTRAQ().add(newItem);
+                     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST.BUGTRAQ } + * + * @return the bugtraq + */ + public List getBUGTRAQ() { + if (bugtraq == null) { + bugtraq = new ArrayList<>(); + } + return this.bugtraq; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="ID" type="{http://www.w3.org/2001/XMLSchema}long"/>
+                     *         <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "id", "url" }) + public static class BUGTRAQ { + + /** The id. */ + @XmlElement(name = "ID") + protected long id; + + /** The url. */ + @XmlElement(name = "URL", required = true) + @XmlSchemaType(name = "anyURI") + protected String url; + + /** + * Gets the value of the id property. + * + * @return the id + */ + public long getID() { + return id; + } + + /** + * Sets the value of the id property. + * + * @param value the new id + */ + public void setID(long value) { + this.id = value; + } + + /** + * Gets the value of the url property. + * + * @return possible object is {@link String } + * + */ + public String getURL() { + return url; + } + + /** + * Sets the value of the url property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setURL(String value) { + this.url = value; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="COMPLIANCE" maxOccurs="unbounded" minOccurs="0">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="SECTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="DESCRIPTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "compliance" }) + public static class COMPLIANCELIST { + + /** The compliance. */ + @XmlElement(name = "COMPLIANCE") + protected List compliance; + + /** + * Gets the value of the compliance property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you make + * to the returned list will be present inside the JAXB + * object. This is why there is not a set + * method for the compliance property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                     * getCOMPLIANCE().add(newItem);
+                     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST.COMPLIANCE } + * + * @return the compliance + */ + public List getCOMPLIANCE() { + if (compliance == null) { + compliance = new ArrayList<>(); + } + return this.compliance; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="SECTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="DESCRIPTION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "type", "section", "description" }) + public static class COMPLIANCE { + + /** The type. */ + @XmlElement(name = "TYPE", required = true) + protected String type; + + /** The section. */ + @XmlElement(name = "SECTION", required = true) + protected String section; + + /** The description. */ + @XmlElement(name = "DESCRIPTION", required = true) + protected String description; + + /** + * Gets the value of the type property. + * + * @return possible object is {@link String } + * + */ + public String getTYPE() { + return type; + } + + /** + * Sets the value of the type property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setTYPE(String value) { + this.type = value; + } + + /** + * Gets the value of the section property. + * + * @return possible object is {@link String } + * + */ + public String getSECTION() { + return section; + } + + /** + * Sets the value of the section property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setSECTION(String value) { + this.section = value; + } + + /** + * Gets the value of the description property. + * + * @return possible object is {@link String } + * + */ + public String getDESCRIPTION() { + return description; + } + + /** + * Sets the value of the description property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setDESCRIPTION(String value) { + this.description = value; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="EXPLOITS">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="EXPLT_SRC" maxOccurs="unbounded" minOccurs="0">
+                 *                     <complexType>
+                 *                       <complexContent>
+                 *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                           <sequence>
+                 *                             <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                             <element name="EXPLT_LIST">
+                 *                               <complexType>
+                 *                                 <complexContent>
+                 *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                                     <choice maxOccurs="unbounded" minOccurs="0">
+                 *                                       <element name="EXPLT">
+                 *                                         <complexType>
+                 *                                           <complexContent>
+                 *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                                               <sequence>
+                 *                                                 <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                                                 <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                                                 <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                 *                                               </sequence>
+                 *                                             </restriction>
+                 *                                           </complexContent>
+                 *                                         </complexType>
+                 *                                       </element>
+                 *                                     </choice>
+                 *                                   </restriction>
+                 *                                 </complexContent>
+                 *                               </complexType>
+                 *                             </element>
+                 *                           </sequence>
+                 *                         </restriction>
+                 *                       </complexContent>
+                 *                     </complexType>
+                 *                   </element>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *         <element name="MALWARE">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="MW_SRC" maxOccurs="unbounded" minOccurs="0">
+                 *                     <complexType>
+                 *                       <complexContent>
+                 *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                           <sequence>
+                 *                             <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                             <element name="MW_LIST">
+                 *                               <complexType>
+                 *                                 <complexContent>
+                 *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                                     <sequence>
+                 *                                       <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+                 *                                         <complexType>
+                 *                                           <complexContent>
+                 *                                             <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                                               <sequence>
+                 *                                                 <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                                                 <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                                                 <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                                                 <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                                                 <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                                                 <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                 *                                               </sequence>
+                 *                                             </restriction>
+                 *                                           </complexContent>
+                 *                                         </complexType>
+                 *                                       </element>
+                 *                                     </sequence>
+                 *                                   </restriction>
+                 *                                 </complexContent>
+                 *                               </complexType>
+                 *                             </element>
+                 *                           </sequence>
+                 *                         </restriction>
+                 *                       </complexContent>
+                 *                     </complexType>
+                 *                   </element>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "exploits", "malware" }) + public static class CORRELATION { + + /** The exploits. */ + @XmlElement(name = "EXPLOITS", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS exploits; + + /** The malware. */ + @XmlElement(name = "MALWARE", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE malware; + + /** + * Gets the value of the exploits property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS getEXPLOITS() { + return exploits; + } + + /** + * Sets the value of the exploits property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS } + * + */ + public void setEXPLOITS( + KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS value) { + this.exploits = value; + } + + /** + * Gets the value of the malware property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE getMALWARE() { + return malware; + } + + /** + * Sets the value of the malware property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE } + * + */ + public void setMALWARE( + KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE value) { + this.malware = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="EXPLT_SRC" maxOccurs="unbounded" minOccurs="0">
+                     *           <complexType>
+                     *             <complexContent>
+                     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *                 <sequence>
+                     *                   <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                   <element name="EXPLT_LIST">
+                     *                     <complexType>
+                     *                       <complexContent>
+                     *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *                           <choice maxOccurs="unbounded" minOccurs="0">
+                     *                             <element name="EXPLT">
+                     *                               <complexType>
+                     *                                 <complexContent>
+                     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *                                     <sequence>
+                     *                                       <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                                       <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                                       <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                     *                                     </sequence>
+                     *                                   </restriction>
+                     *                                 </complexContent>
+                     *                               </complexType>
+                     *                             </element>
+                     *                           </choice>
+                     *                         </restriction>
+                     *                       </complexContent>
+                     *                     </complexType>
+                     *                   </element>
+                     *                 </sequence>
+                     *               </restriction>
+                     *             </complexContent>
+                     *           </complexType>
+                     *         </element>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "expltsrc" }) + public static class EXPLOITS { + + /** The expltsrc. */ + @XmlElement(name = "EXPLT_SRC") + protected List expltsrc; + + /** + * Gets the value of the expltsrc property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you + * make to the returned list will be present inside the + * JAXB object. This is why there is not a + * set method for the expltsrc property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                         * getEXPLTSRC().add(newItem);
+                         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the + * list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS.EXPLTSRC } + * + * @return the expltsrc + */ + public List getEXPLTSRC() { + if (expltsrc == null) { + expltsrc = new ArrayList<>(); + } + return this.expltsrc; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                         * <complexType>
+                         *   <complexContent>
+                         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                         *       <sequence>
+                         *         <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *         <element name="EXPLT_LIST">
+                         *           <complexType>
+                         *             <complexContent>
+                         *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                         *                 <choice maxOccurs="unbounded" minOccurs="0">
+                         *                   <element name="EXPLT">
+                         *                     <complexType>
+                         *                       <complexContent>
+                         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                         *                           <sequence>
+                         *                             <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *                             <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *                             <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                         *                           </sequence>
+                         *                         </restriction>
+                         *                       </complexContent>
+                         *                     </complexType>
+                         *                   </element>
+                         *                 </choice>
+                         *               </restriction>
+                         *             </complexContent>
+                         *           </complexType>
+                         *         </element>
+                         *       </sequence>
+                         *     </restriction>
+                         *   </complexContent>
+                         * </complexType>
+                         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "srcname", "expltlist" }) + public static class EXPLTSRC { + + /** The srcname. */ + @XmlElement(name = "SRC_NAME", required = true) + protected String srcname; + + /** The expltlist. */ + @XmlElement(name = "EXPLT_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS.EXPLTSRC.EXPLTLIST expltlist; + + /** + * Gets the value of the srcname property. + * + * @return possible object is {@link String } + * + */ + public String getSRCNAME() { + return srcname; + } + + /** + * Sets the value of the srcname property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setSRCNAME(String value) { + this.srcname = value; + } + + /** + * Gets the value of the expltlist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS.EXPLTSRC.EXPLTLIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS.EXPLTSRC.EXPLTLIST getEXPLTLIST() { + return expltlist; + } + + /** + * Sets the value of the expltlist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS.EXPLTSRC.EXPLTLIST } + * + */ + public void setEXPLTLIST( + KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS.EXPLTSRC.EXPLTLIST value) { + this.expltlist = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the + * expected content contained within this class. + * + *

+                             * <complexType>
+                             *   <complexContent>
+                             *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                             *       <choice maxOccurs="unbounded" minOccurs="0">
+                             *         <element name="EXPLT">
+                             *           <complexType>
+                             *             <complexContent>
+                             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                             *                 <sequence>
+                             *                   <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                             *                   <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                             *                   <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                             *                 </sequence>
+                             *               </restriction>
+                             *             </complexContent>
+                             *           </complexType>
+                             *         </element>
+                             *       </choice>
+                             *     </restriction>
+                             *   </complexContent>
+                             * </complexType>
+                             * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "explt" }) + public static class EXPLTLIST { + + /** The explt. */ + @XmlElement(name = "EXPLT") + protected List explt; + + /** + * Gets the value of the explt property. + * + *

+ * This accessor method returns a reference to + * the live list, not a snapshot. Therefore any + * modification you make to the returned list + * will be present inside the JAXB object. This + * is why there is not a set method + * for the explt property. + * + *

+ * For example, to add a new item, do as + * follows: + * + *

+                                 * getEXPLT().add(newItem);
+                                 * 
+ * + * + *

+ * Objects of the following type(s) are allowed + * in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.EXPLOITS.EXPLTSRC.EXPLTLIST.EXPLT } + * + * @return the explt + */ + public List getEXPLT() { + if (explt == null) { + explt = new ArrayList<>(); + } + return this.explt; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the + * expected content contained within this class. + * + *

+                                 * <complexType>
+                                 *   <complexContent>
+                                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                                 *       <sequence>
+                                 *         <element name="REF" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                                 *         <element name="DESC" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                                 *         <element name="LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                                 *       </sequence>
+                                 *     </restriction>
+                                 *   </complexContent>
+                                 * </complexType>
+                                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "ref", "desc", "link" }) + public static class EXPLT { + + /** The ref. */ + @XmlElement(name = "REF", required = true) + protected String ref; + + /** The desc. */ + @XmlElement(name = "DESC", required = true) + protected String desc; + + /** The link. */ + @XmlElement(name = "LINK", required = true) + @XmlSchemaType(name = "anyURI") + protected String link; + + /** + * Gets the value of the ref property. + * + * @return possible object is {@link String + * } + * + */ + public String getREF() { + return ref; + } + + /** + * Sets the value of the ref property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setREF(String value) { + this.ref = value; + } + + /** + * Gets the value of the desc property. + * + * @return possible object is {@link String + * } + * + */ + public String getDESC() { + return desc; + } + + /** + * Sets the value of the desc property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setDESC(String value) { + this.desc = value; + } + + /** + * Gets the value of the link property. + * + * @return possible object is {@link String + * } + * + */ + public String getLINK() { + return link; + } + + /** + * Sets the value of the link property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setLINK(String value) { + this.link = value; + } + + } + + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="MW_SRC" maxOccurs="unbounded" minOccurs="0">
+                     *           <complexType>
+                     *             <complexContent>
+                     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *                 <sequence>
+                     *                   <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                   <element name="MW_LIST">
+                     *                     <complexType>
+                     *                       <complexContent>
+                     *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *                           <sequence>
+                     *                             <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+                     *                               <complexType>
+                     *                                 <complexContent>
+                     *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *                                     <sequence>
+                     *                                       <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                                       <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                                       <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                                       <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                                       <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *                                       <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                     *                                     </sequence>
+                     *                                   </restriction>
+                     *                                 </complexContent>
+                     *                               </complexType>
+                     *                             </element>
+                     *                           </sequence>
+                     *                         </restriction>
+                     *                       </complexContent>
+                     *                     </complexType>
+                     *                   </element>
+                     *                 </sequence>
+                     *               </restriction>
+                     *             </complexContent>
+                     *           </complexType>
+                     *         </element>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "mwsrc" }) + public static class MALWARE { + + /** The mwsrc. */ + @XmlElement(name = "MW_SRC") + protected List mwsrc; + + /** + * Gets the value of the mwsrc property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you + * make to the returned list will be present inside the + * JAXB object. This is why there is not a + * set method for the mwsrc property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                         * getMWSRC().add(newItem);
+                         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the + * list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE.MWSRC } + * + * @return the mwsrc + */ + public List getMWSRC() { + if (mwsrc == null) { + mwsrc = new ArrayList<>(); + } + return this.mwsrc; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                         * <complexType>
+                         *   <complexContent>
+                         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                         *       <sequence>
+                         *         <element name="SRC_NAME" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *         <element name="MW_LIST">
+                         *           <complexType>
+                         *             <complexContent>
+                         *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                         *                 <sequence>
+                         *                   <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+                         *                     <complexType>
+                         *                       <complexContent>
+                         *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                         *                           <sequence>
+                         *                             <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *                             <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *                             <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *                             <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *                             <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                         *                             <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                         *                           </sequence>
+                         *                         </restriction>
+                         *                       </complexContent>
+                         *                     </complexType>
+                         *                   </element>
+                         *                 </sequence>
+                         *               </restriction>
+                         *             </complexContent>
+                         *           </complexType>
+                         *         </element>
+                         *       </sequence>
+                         *     </restriction>
+                         *   </complexContent>
+                         * </complexType>
+                         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "srcname", "mwlist" }) + public static class MWSRC { + + /** The srcname. */ + @XmlElement(name = "SRC_NAME", required = true) + protected String srcname; + + /** The mwlist. */ + @XmlElement(name = "MW_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE.MWSRC.MWLIST mwlist; + + /** + * Gets the value of the srcname property. + * + * @return possible object is {@link String } + * + */ + public String getSRCNAME() { + return srcname; + } + + /** + * Sets the value of the srcname property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setSRCNAME(String value) { + this.srcname = value; + } + + /** + * Gets the value of the mwlist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE.MWSRC.MWLIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE.MWSRC.MWLIST getMWLIST() { + return mwlist; + } + + /** + * Sets the value of the mwlist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE.MWSRC.MWLIST } + * + */ + public void setMWLIST( + KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE.MWSRC.MWLIST value) { + this.mwlist = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the + * expected content contained within this class. + * + *

+                             * <complexType>
+                             *   <complexContent>
+                             *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                             *       <sequence>
+                             *         <element name="MW_INFO" maxOccurs="unbounded" minOccurs="0">
+                             *           <complexType>
+                             *             <complexContent>
+                             *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                             *                 <sequence>
+                             *                   <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                             *                   <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                             *                   <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                             *                   <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                             *                   <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                             *                   <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                             *                 </sequence>
+                             *               </restriction>
+                             *             </complexContent>
+                             *           </complexType>
+                             *         </element>
+                             *       </sequence>
+                             *     </restriction>
+                             *   </complexContent>
+                             * </complexType>
+                             * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "mwinfo" }) + public static class MWLIST { + + /** The mwinfo. */ + @XmlElement(name = "MW_INFO") + protected List mwinfo; + + /** + * Gets the value of the mwinfo property. + * + *

+ * This accessor method returns a reference to + * the live list, not a snapshot. Therefore any + * modification you make to the returned list + * will be present inside the JAXB object. This + * is why there is not a set method + * for the mwinfo property. + * + *

+ * For example, to add a new item, do as + * follows: + * + *

+                                 * getMWINFO().add(newItem);
+                                 * 
+ * + * + *

+ * Objects of the following type(s) are allowed + * in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION.MALWARE.MWSRC.MWLIST.MWINFO } + * + * @return the mwinfo + */ + public List getMWINFO() { + if (mwinfo == null) { + mwinfo = new ArrayList<>(); + } + return this.mwinfo; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the + * expected content contained within this class. + * + *

+                                 * <complexType>
+                                 *   <complexContent>
+                                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                                 *       <sequence>
+                                 *         <element name="MW_ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                                 *         <element name="MW_TYPE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                                 *         <element name="MW_PLATFORM" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                                 *         <element name="MW_ALIAS" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                                 *         <element name="MW_RATING" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                                 *         <element name="MW_LINK" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                                 *       </sequence>
+                                 *     </restriction>
+                                 *   </complexContent>
+                                 * </complexType>
+                                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "mwid", "mwtype", "mwplatform", "mwalias", "mwrating", + "mwlink" }) + public static class MWINFO { + + /** The mwid. */ + @XmlElement(name = "MW_ID", required = true) + protected String mwid; + + /** The mwtype. */ + @XmlElement(name = "MW_TYPE", required = true) + protected String mwtype; + + /** The mwplatform. */ + @XmlElement(name = "MW_PLATFORM", required = true) + protected String mwplatform; + + /** The mwalias. */ + @XmlElement(name = "MW_ALIAS", required = true) + protected String mwalias; + + /** The mwrating. */ + @XmlElement(name = "MW_RATING", required = true) + protected String mwrating; + + /** The mwlink. */ + @XmlElement(name = "MW_LINK", required = true) + @XmlSchemaType(name = "anyURI") + protected String mwlink; + + /** + * Gets the value of the mwid property. + * + * @return possible object is {@link String + * } + * + */ + public String getMWID() { + return mwid; + } + + /** + * Sets the value of the mwid property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMWID(String value) { + this.mwid = value; + } + + /** + * Gets the value of the mwtype property. + * + * @return possible object is {@link String + * } + * + */ + public String getMWTYPE() { + return mwtype; + } + + /** + * Sets the value of the mwtype property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMWTYPE(String value) { + this.mwtype = value; + } + + /** + * Gets the value of the mwplatform + * property. + * + * @return possible object is {@link String + * } + * + */ + public String getMWPLATFORM() { + return mwplatform; + } + + /** + * Sets the value of the mwplatform + * property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMWPLATFORM(String value) { + this.mwplatform = value; + } + + /** + * Gets the value of the mwalias property. + * + * @return possible object is {@link String + * } + * + */ + public String getMWALIAS() { + return mwalias; + } + + /** + * Sets the value of the mwalias property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMWALIAS(String value) { + this.mwalias = value; + } + + /** + * Gets the value of the mwrating property. + * + * @return possible object is {@link String + * } + * + */ + public String getMWRATING() { + return mwrating; + } + + /** + * Sets the value of the mwrating property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMWRATING(String value) { + this.mwrating = value; + } + + /** + * Gets the value of the mwlink property. + * + * @return possible object is {@link String + * } + * + */ + public String getMWLINK() { + return mwlink; + } + + /** + * Sets the value of the mwlink property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMWLINK(String value) { + this.mwlink = value; + } + + } + + } + + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="CVE" maxOccurs="unbounded" minOccurs="0">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "cve" }) + public static class CVELIST { + + /** The cve. */ + @XmlElement(name = "CVE") + protected List cve; + + /** + * Gets the value of the cve property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you make + * to the returned list will be present inside the JAXB + * object. This is why there is not a set + * method for the cve property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                     * getCVE().add(newItem);
+                     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST.CVE } + * + * @return the cve + */ + public List getCVE() { + if (cve == null) { + cve = new ArrayList<>(); + } + return this.cve; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="URL" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "id", "url" }) + public static class CVE { + + /** The id. */ + @XmlElement(name = "ID", required = true) + protected String id; + + /** The url. */ + @XmlElement(name = "URL", required = true) + @XmlSchemaType(name = "anyURI") + protected String url; + + /** + * Gets the value of the id property. + * + * @return possible object is {@link String } + * + */ + public String getID() { + return id; + } + + /** + * Sets the value of the id property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setID(String value) { + this.id = value; + } + + /** + * Gets the value of the url property. + * + * @return possible object is {@link String } + * + */ + public String getURL() { + return url; + } + + /** + * Sets the value of the url property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setURL(String value) { + this.url = value; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+                 *         <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+                 *         <element name="ACCESS">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *         <element name="IMPACT">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *         <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *         <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *         <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *         <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "base", "temporal", "access", "impact", "authentication", + "exploitability", "remediationlevel", "reportconfidence" }) + public static class CVSS { + + /** The base. */ + @XmlElement(name = "BASE") + protected float base; + + /** The temporal. */ + @XmlElement(name = "TEMPORAL") + protected float temporal; + + /** The access. */ + @XmlElement(name = "ACCESS", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.ACCESS access; + + /** The impact. */ + @XmlElement(name = "IMPACT", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.IMPACT impact; + + /** The authentication. */ + @XmlElement(name = "AUTHENTICATION", required = true) + protected String authentication; + + /** The exploitability. */ + @XmlElement(name = "EXPLOITABILITY", required = true) + protected String exploitability; + + /** The remediationlevel. */ + @XmlElement(name = "REMEDIATION_LEVEL", required = true) + protected String remediationlevel; + + /** The reportconfidence. */ + @XmlElement(name = "REPORT_CONFIDENCE", required = true) + protected String reportconfidence; + + /** + * Gets the value of the base property. + * + * @return the base + */ + public float getBASE() { + return base; + } + + /** + * Sets the value of the base property. + * + * @param value the new base + */ + public void setBASE(float value) { + this.base = value; + } + + /** + * Gets the value of the temporal property. + * + * @return the temporal + */ + public float getTEMPORAL() { + return temporal; + } + + /** + * Sets the value of the temporal property. + * + * @param value the new temporal + */ + public void setTEMPORAL(float value) { + this.temporal = value; + } + + /** + * Gets the value of the access property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.ACCESS } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.ACCESS getACCESS() { + return access; + } + + /** + * Sets the value of the access property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.ACCESS } + * + */ + public void setACCESS(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.ACCESS value) { + this.access = value; + } + + /** + * Gets the value of the impact property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.IMPACT } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.IMPACT getIMPACT() { + return impact; + } + + /** + * Sets the value of the impact property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.IMPACT } + * + */ + public void setIMPACT(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS.IMPACT value) { + this.impact = value; + } + + /** + * Gets the value of the authentication property. + * + * @return possible object is {@link String } + * + */ + public String getAUTHENTICATION() { + return authentication; + } + + /** + * Sets the value of the authentication property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setAUTHENTICATION(String value) { + this.authentication = value; + } + + /** + * Gets the value of the exploitability property. + * + * @return possible object is {@link String } + * + */ + public String getEXPLOITABILITY() { + return exploitability; + } + + /** + * Sets the value of the exploitability property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setEXPLOITABILITY(String value) { + this.exploitability = value; + } + + /** + * Gets the value of the remediationlevel property. + * + * @return possible object is {@link String } + * + */ + public String getREMEDIATIONLEVEL() { + return remediationlevel; + } + + /** + * Sets the value of the remediationlevel property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setREMEDIATIONLEVEL(String value) { + this.remediationlevel = value; + } + + /** + * Gets the value of the reportconfidence property. + * + * @return possible object is {@link String } + * + */ + public String getREPORTCONFIDENCE() { + return reportconfidence; + } + + /** + * Sets the value of the reportconfidence property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setREPORTCONFIDENCE(String value) { + this.reportconfidence = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "vector", "complexity" }) + public static class ACCESS { + + /** The vector. */ + @XmlElement(name = "VECTOR", required = true) + protected String vector; + + /** The complexity. */ + @XmlElement(name = "COMPLEXITY", required = true) + protected String complexity; + + /** + * Gets the value of the vector property. + * + * @return possible object is {@link String } + * + */ + public String getVECTOR() { + return vector; + } + + /** + * Sets the value of the vector property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setVECTOR(String value) { + this.vector = value; + } + + /** + * Gets the value of the complexity property. + * + * @return possible object is {@link String } + * + */ + public String getCOMPLEXITY() { + return complexity; + } + + /** + * Sets the value of the complexity property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setCOMPLEXITY(String value) { + this.complexity = value; + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "confidentiality", "integrity", "availability" }) + public static class IMPACT { + + /** The confidentiality. */ + @XmlElement(name = "CONFIDENTIALITY", required = true) + protected String confidentiality; + + /** The integrity. */ + @XmlElement(name = "INTEGRITY", required = true) + protected String integrity; + + /** The availability. */ + @XmlElement(name = "AVAILABILITY", required = true) + protected String availability; + + /** + * Gets the value of the confidentiality property. + * + * @return possible object is {@link String } + * + */ + public String getCONFIDENTIALITY() { + return confidentiality; + } + + /** + * Sets the value of the confidentiality property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setCONFIDENTIALITY(String value) { + this.confidentiality = value; + } + + /** + * Gets the value of the integrity property. + * + * @return possible object is {@link String } + * + */ + public String getINTEGRITY() { + return integrity; + } + + /** + * Sets the value of the integrity property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setINTEGRITY(String value) { + this.integrity = value; + } + + /** + * Gets the value of the availability property. + * + * @return possible object is {@link String } + * + */ + public String getAVAILABILITY() { + return availability; + } + + /** + * Sets the value of the availability property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setAVAILABILITY(String value) { + this.availability = value; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="BASE" type="{http://www.w3.org/2001/XMLSchema}float"/>
+                 *         <element name="TEMPORAL" type="{http://www.w3.org/2001/XMLSchema}float"/>
+                 *         <element name="ACCESS">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *         <element name="IMPACT">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *         <element name="AUTHENTICATION" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *         <element name="EXPLOITABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *         <element name="REMEDIATION_LEVEL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *         <element name="REPORT_CONFIDENCE" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "base", "temporal", "access", "impact", "authentication", + "exploitability", "remediationlevel", "reportconfidence" }) + public static class CVSSV3 { + + /** The base. */ + @XmlElement(name = "BASE") + protected float base; + + /** The temporal. */ + @XmlElement(name = "TEMPORAL") + protected float temporal; + + /** The access. */ + @XmlElement(name = "ACCESS", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3.ACCESS access; + + /** The impact. */ + @XmlElement(name = "IMPACT", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3.IMPACT impact; + + /** The authentication. */ + @XmlElement(name = "AUTHENTICATION", required = true) + protected String authentication; + + /** The exploitability. */ + @XmlElement(name = "EXPLOITABILITY", required = true) + protected String exploitability; + + /** The remediationlevel. */ + @XmlElement(name = "REMEDIATION_LEVEL", required = true) + protected String remediationlevel; + + /** The reportconfidence. */ + @XmlElement(name = "REPORT_CONFIDENCE", required = true) + protected String reportconfidence; + + /** + * Gets the value of the base property. + * + * @return the base + */ + public float getBASE() { + return base; + } + + /** + * Sets the value of the base property. + * + * @param value the new base + */ + public void setBASE(float value) { + this.base = value; + } + + /** + * Gets the value of the temporal property. + * + * @return the temporal + */ + public float getTEMPORAL() { + return temporal; + } + + /** + * Sets the value of the temporal property. + * + * @param value the new temporal + */ + public void setTEMPORAL(float value) { + this.temporal = value; + } + + /** + * Gets the value of the access property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 .ACCESS } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3.ACCESS getACCESS() { + return access; + } + + /** + * Sets the value of the access property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 .ACCESS } + * + */ + public void setACCESS(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3.ACCESS value) { + this.access = value; + } + + /** + * Gets the value of the impact property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 .IMPACT } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3.IMPACT getIMPACT() { + return impact; + } + + /** + * Sets the value of the impact property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 .IMPACT } + * + */ + public void setIMPACT(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3.IMPACT value) { + this.impact = value; + } + + /** + * Gets the value of the authentication property. + * + * @return possible object is {@link String } + * + */ + public String getAUTHENTICATION() { + return authentication; + } + + /** + * Sets the value of the authentication property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setAUTHENTICATION(String value) { + this.authentication = value; + } + + /** + * Gets the value of the exploitability property. + * + * @return possible object is {@link String } + * + */ + public String getEXPLOITABILITY() { + return exploitability; + } + + /** + * Sets the value of the exploitability property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setEXPLOITABILITY(String value) { + this.exploitability = value; + } + + /** + * Gets the value of the remediationlevel property. + * + * @return possible object is {@link String } + * + */ + public String getREMEDIATIONLEVEL() { + return remediationlevel; + } + + /** + * Sets the value of the remediationlevel property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setREMEDIATIONLEVEL(String value) { + this.remediationlevel = value; + } + + /** + * Gets the value of the reportconfidence property. + * + * @return possible object is {@link String } + * + */ + public String getREPORTCONFIDENCE() { + return reportconfidence; + } + + /** + * Sets the value of the reportconfidence property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setREPORTCONFIDENCE(String value) { + this.reportconfidence = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="VECTOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="COMPLEXITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "vector", "complexity" }) + public static class ACCESS { + + /** The vector. */ + @XmlElement(name = "VECTOR", required = true) + protected String vector; + + /** The complexity. */ + @XmlElement(name = "COMPLEXITY", required = true) + protected String complexity; + + /** + * Gets the value of the vector property. + * + * @return possible object is {@link String } + * + */ + public String getVECTOR() { + return vector; + } + + /** + * Sets the value of the vector property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setVECTOR(String value) { + this.vector = value; + } + + /** + * Gets the value of the complexity property. + * + * @return possible object is {@link String } + * + */ + public String getCOMPLEXITY() { + return complexity; + } + + /** + * Sets the value of the complexity property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setCOMPLEXITY(String value) { + this.complexity = value; + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="CONFIDENTIALITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="INTEGRITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="AVAILABILITY" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "confidentiality", "integrity", "availability" }) + public static class IMPACT { + + /** The confidentiality. */ + @XmlElement(name = "CONFIDENTIALITY", required = true) + protected String confidentiality; + + /** The integrity. */ + @XmlElement(name = "INTEGRITY", required = true) + protected String integrity; + + /** The availability. */ + @XmlElement(name = "AVAILABILITY", required = true) + protected String availability; + + /** + * Gets the value of the confidentiality property. + * + * @return possible object is {@link String } + * + */ + public String getCONFIDENTIALITY() { + return confidentiality; + } + + /** + * Sets the value of the confidentiality property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setCONFIDENTIALITY(String value) { + this.confidentiality = value; + } + + /** + * Gets the value of the integrity property. + * + * @return possible object is {@link String } + * + */ + public String getINTEGRITY() { + return integrity; + } + + /** + * Sets the value of the integrity property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setINTEGRITY(String value) { + this.integrity = value; + } + + /** + * Gets the value of the availability property. + * + * @return possible object is {@link String } + * + */ + public String getAVAILABILITY() { + return availability; + } + + /** + * Sets the value of the availability property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setAVAILABILITY(String value) { + this.availability = value; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="REMOTE" type="{http://www.w3.org/2001/XMLSchema}byte"/>
+                 *         <element name="AUTH_TYPE_LIST">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="AUTH_TYPE" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *         <element name="ADDITIONAL_INFO" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "remote", "authtypelist", "additionalinfo" }) + public static class DISCOVERY { + + /** The remote. */ + @XmlElement(name = "REMOTE") + protected byte remote; + + /** The authtypelist. */ + @XmlElement(name = "AUTH_TYPE_LIST", required = true) + protected KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY.AUTHTYPELIST authtypelist; + + /** The additionalinfo. */ + @XmlElement(name = "ADDITIONAL_INFO", required = true) + protected String additionalinfo; + + /** + * Gets the value of the remote property. + * + * @return the remote + */ + public byte getREMOTE() { + return remote; + } + + /** + * Sets the value of the remote property. + * + * @param value the new remote + */ + public void setREMOTE(byte value) { + this.remote = value; + } + + /** + * Gets the value of the authtypelist property. + * + * @return possible object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY.AUTHTYPELIST } + * + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY.AUTHTYPELIST getAUTHTYPELIST() { + return authtypelist; + } + + /** + * Sets the value of the authtypelist property. + * + * @param value + * allowed object is + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY.AUTHTYPELIST } + * + */ + public void setAUTHTYPELIST( + KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY.AUTHTYPELIST value) { + this.authtypelist = value; + } + + /** + * Gets the value of the additionalinfo property. + * + * @return possible object is {@link String } + * + */ + public String getADDITIONALINFO() { + return additionalinfo; + } + + /** + * Sets the value of the additionalinfo property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setADDITIONALINFO(String value) { + this.additionalinfo = value; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="AUTH_TYPE" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "authtype" }) + public static class AUTHTYPELIST { + + /** The authtype. */ + @XmlElement(name = "AUTH_TYPE") + protected List authtype; + + /** + * Gets the value of the authtype property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you + * make to the returned list will be present inside the + * JAXB object. This is why there is not a + * set method for the authtype property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                         * getAUTHTYPE().add(newItem);
+                         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the + * list {@link String } + * + * @return the authtype + */ + public List getAUTHTYPE() { + if (authtype == null) { + authtype = new ArrayList<>(); + } + return this.authtype; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="PCI_REASON" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "pcireason" }) + public static class PCIREASONS { + + /** The pcireason. */ + @XmlElement(name = "PCI_REASON") + protected List pcireason; + + /** + * Gets the value of the pcireason property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you make + * to the returned list will be present inside the JAXB + * object. This is why there is not a set + * method for the pcireason property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                     * getPCIREASON().add(newItem);
+                     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link String } + * + * @return the pcireason + */ + public List getPCIREASON() { + if (pcireason == null) { + pcireason = new ArrayList<>(); + } + return this.pcireason; + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="SOFTWARE" maxOccurs="unbounded" minOccurs="0">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="PRODUCT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="VENDOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "software" }) + public static class SOFTWARELIST { + + /** The software. */ + @XmlElement(name = "SOFTWARE") + protected List software; + + /** + * Gets the value of the software property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you make + * to the returned list will be present inside the JAXB + * object. This is why there is not a set + * method for the software property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                     * getSOFTWARE().add(newItem);
+                     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST.SOFTWARE } + * + * @return the software + */ + public List getSOFTWARE() { + if (software == null) { + software = new ArrayList<>(); + } + return this.software; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="PRODUCT" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="VENDOR" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "product", "vendor" }) + public static class SOFTWARE { + + /** The product. */ + @XmlElement(name = "PRODUCT", required = true) + protected String product; + + /** The vendor. */ + @XmlElement(name = "VENDOR", required = true) + protected String vendor; + + /** + * Gets the value of the product property. + * + * @return possible object is {@link String } + * + */ + public String getPRODUCT() { + return product; + } + + /** + * Sets the value of the product property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setPRODUCT(String value) { + this.product = value; + } + + /** + * Gets the value of the vendor property. + * + * @return possible object is {@link String } + * + */ + public String getVENDOR() { + return vendor; + } + + /** + * Sets the value of the vendor property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setVENDOR(String value) { + this.vendor = value; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+                 * <complexType>
+                 *   <complexContent>
+                 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *       <sequence>
+                 *         <element name="VENDOR_REFERENCE" maxOccurs="unbounded" minOccurs="0">
+                 *           <complexType>
+                 *             <complexContent>
+                 *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                 *                 <sequence>
+                 *                   <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                   <element name="URL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                 *                 </sequence>
+                 *               </restriction>
+                 *             </complexContent>
+                 *           </complexType>
+                 *         </element>
+                 *       </sequence>
+                 *     </restriction>
+                 *   </complexContent>
+                 * </complexType>
+                 * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "vendorreference" }) + public static class VENDORREFERENCELIST { + + /** The vendorreference. */ + @XmlElement(name = "VENDOR_REFERENCE") + protected List vendorreference; + + /** + * Gets the value of the vendorreference property. + * + *

+ * This accessor method returns a reference to the live + * list, not a snapshot. Therefore any modification you make + * to the returned list will be present inside the JAXB + * object. This is why there is not a set + * method for the vendorreference property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+                     * getVENDORREFERENCE().add(newItem);
+                     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST.VENDORREFERENCE } + * + * @return the vendorreference + */ + public List getVENDORREFERENCE() { + if (vendorreference == null) { + vendorreference = new ArrayList<>(); + } + return this.vendorreference; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected + * content contained within this class. + * + *

+                     * <complexType>
+                     *   <complexContent>
+                     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+                     *       <sequence>
+                     *         <element name="ID" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *         <element name="URL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+                     *       </sequence>
+                     *     </restriction>
+                     *   </complexContent>
+                     * </complexType>
+                     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "id", "url" }) + public static class VENDORREFERENCE { + + /** The id. */ + @XmlElement(name = "ID", required = true) + protected String id; + + /** The url. */ + @XmlElement(name = "URL", required = true) + protected String url; + + /** + * Gets the value of the id property. + * + * @return possible object is {@link String } + * + */ + public String getID() { + return id; + } + + /** + * Sets the value of the id property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setID(String value) { + this.id = value; + } + + /** + * Gets the value of the url property. + * + * @return possible object is {@link String } + * + */ + public String getURL() { + return url; + } + + /** + * Sets the value of the url property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setURL(String value) { + this.url = value; + } + + } + + } + + } + + } + + } + +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/dto/Vuln.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/dto/Vuln.java new file mode 100644 index 000000000..3bc509b1f --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/dto/Vuln.java @@ -0,0 +1,660 @@ +package com.tmobile.cso.pacman.qualys.dto; + +import java.util.Date; + +import javax.xml.datatype.XMLGregorianCalendar; + + +/** + * The Class Vuln. + */ +public class Vuln { + + /** The qid. */ + private String qid; + + /** The vulntype. */ + private String vulntype; + + /** The severitylevel. */ + private byte severitylevel; + + /** The title. */ + private String title; + + /** The category. */ + private String category; + + /** The lastservicemodificationdatetime. */ + private XMLGregorianCalendar lastservicemodificationdatetime; + + /** The publisheddatetime. */ + private XMLGregorianCalendar publisheddatetime; + + /** The bugtraqlist. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST bugtraqlist; + + /** The patchable. */ + private String patchable; + + /** The softwarelist. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST softwarelist; + + /** The vendorreferencelist. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST vendorreferencelist; + + /** The cvelist. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST cvelist; + + /** The diagnosis. */ + private String diagnosis; + + /** The diagnosiscomment. */ + private String diagnosiscomment; + + /** The consequence. */ + private String consequence; + + /** The consequencecomment. */ + private String consequencecomment; + + /** The solution. */ + private String solution; + + /** The solutioncomment. */ + private String solutioncomment; + + /** The compliancelist. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST compliancelist; + + /** The correlation. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION correlation; + + /** The cvss. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS cvss; + + /** The cvssv 3. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 cvssv3; + + /** The pciflag. */ + private byte pciflag; + + /** The pcireasons. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS pcireasons; + + /** The supportedmodules. */ + private String supportedmodules; + + /** The discovery. */ + private KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY discovery; + + /** The isdisabled. */ + private String isdisabled; + + /** The load date. */ + private Date _loadDate; + + /** The latest. */ + private boolean latest; + + /** The classification. */ + private String classification; + + /** + * Gets the qid. + * + * @return the qid + */ + public String getQid() { + return qid; + } + + /** + * Sets the qid. + * + * @param qid the new qid + */ + public void setQid(String qid) { + this.qid = qid; + } + + /** + * Gets the vulntype. + * + * @return the vulntype + */ + public String getVulntype() { + return vulntype; + } + + /** + * Sets the vulntype. + * + * @param vulntype the new vulntype + */ + public void setVulntype(String vulntype) { + this.vulntype = vulntype; + } + + /** + * Gets the severitylevel. + * + * @return the severitylevel + */ + public byte getSeveritylevel() { + return severitylevel; + } + + /** + * Sets the severitylevel. + * + * @param severitylevel the new severitylevel + */ + public void setSeveritylevel(byte severitylevel) { + this.severitylevel = severitylevel; + } + + /** + * Gets the title. + * + * @return the title + */ + public String getTitle() { + return title; + } + + /** + * Sets the title. + * + * @param title the new title + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * Gets the category. + * + * @return the category + */ + public String getCategory() { + return category; + } + + /** + * Sets the category. + * + * @param category the new category + */ + public void setCategory(String category) { + this.category = category; + } + + /** + * Gets the lastservicemodificationdatetime. + * + * @return the lastservicemodificationdatetime + */ + public XMLGregorianCalendar getLastservicemodificationdatetime() { + return lastservicemodificationdatetime; + } + + /** + * Sets the lastservicemodificationdatetime. + * + * @param lastservicemodificationdatetime the new lastservicemodificationdatetime + */ + public void setLastservicemodificationdatetime(XMLGregorianCalendar lastservicemodificationdatetime) { + this.lastservicemodificationdatetime = lastservicemodificationdatetime; + } + + /** + * Gets the publisheddatetime. + * + * @return the publisheddatetime + */ + public XMLGregorianCalendar getPublisheddatetime() { + return publisheddatetime; + } + + /** + * Sets the publisheddatetime. + * + * @param publisheddatetime the new publisheddatetime + */ + public void setPublisheddatetime(XMLGregorianCalendar publisheddatetime) { + this.publisheddatetime = publisheddatetime; + } + + /** + * Gets the bugtraqlist. + * + * @return the bugtraqlist + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST getBugtraqlist() { + return bugtraqlist; + } + + /** + * Sets the bugtraqlist. + * + * @param bugtraqlist the new bugtraqlist + */ + public void setBugtraqlist(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.BUGTRAQLIST bugtraqlist) { + this.bugtraqlist = bugtraqlist; + } + + /** + * Gets the patchable. + * + * @return the patchable + */ + public String getPatchable() { + return patchable; + } + + /** + * Sets the patchable. + * + * @param patchable the new patchable + */ + public void setPatchable(String patchable) { + this.patchable = patchable; + } + + /** + * Gets the softwarelist. + * + * @return the softwarelist + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST getSoftwarelist() { + return softwarelist; + } + + /** + * Sets the softwarelist. + * + * @param softwarelist the new softwarelist + */ + public void setSoftwarelist(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.SOFTWARELIST softwarelist) { + this.softwarelist = softwarelist; + } + + /** + * Gets the vendorreferencelist. + * + * @return the vendorreferencelist + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST getVendorreferencelist() { + return vendorreferencelist; + } + + /** + * Sets the vendorreferencelist. + * + * @param vendorreferencelist the new vendorreferencelist + */ + public void setVendorreferencelist( + KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.VENDORREFERENCELIST vendorreferencelist) { + this.vendorreferencelist = vendorreferencelist; + } + + /** + * Gets the cvelist. + * + * @return the cvelist + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST getCvelist() { + return cvelist; + } + + /** + * Sets the cvelist. + * + * @param cvelist the new cvelist + */ + public void setCvelist(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVELIST cvelist) { + this.cvelist = cvelist; + } + + /** + * Gets the diagnosis. + * + * @return the diagnosis + */ + public String getDiagnosis() { + return diagnosis; + } + + /** + * Sets the diagnosis. + * + * @param diagnosis the new diagnosis + */ + public void setDiagnosis(String diagnosis) { + this.diagnosis = diagnosis; + } + + /** + * Gets the diagnosiscomment. + * + * @return the diagnosiscomment + */ + public String getDiagnosiscomment() { + return diagnosiscomment; + } + + /** + * Sets the diagnosiscomment. + * + * @param diagnosiscomment the new diagnosiscomment + */ + public void setDiagnosiscomment(String diagnosiscomment) { + this.diagnosiscomment = diagnosiscomment; + } + + /** + * Gets the consequence. + * + * @return the consequence + */ + public String getConsequence() { + return consequence; + } + + /** + * Sets the consequence. + * + * @param consequence the new consequence + */ + public void setConsequence(String consequence) { + this.consequence = consequence; + } + + /** + * Gets the consequencecomment. + * + * @return the consequencecomment + */ + public String getConsequencecomment() { + return consequencecomment; + } + + /** + * Sets the consequencecomment. + * + * @param consequencecomment the new consequencecomment + */ + public void setConsequencecomment(String consequencecomment) { + this.consequencecomment = consequencecomment; + } + + /** + * Gets the solution. + * + * @return the solution + */ + public String getSolution() { + return solution; + } + + /** + * Sets the solution. + * + * @param solution the new solution + */ + public void setSolution(String solution) { + this.solution = solution; + } + + /** + * Gets the solutioncomment. + * + * @return the solutioncomment + */ + public String getSolutioncomment() { + return solutioncomment; + } + + /** + * Sets the solutioncomment. + * + * @param solutioncomment the new solutioncomment + */ + public void setSolutioncomment(String solutioncomment) { + this.solutioncomment = solutioncomment; + } + + /** + * Gets the compliancelist. + * + * @return the compliancelist + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST getCompliancelist() { + return compliancelist; + } + + /** + * Sets the compliancelist. + * + * @param compliancelist the new compliancelist + */ + public void setCompliancelist(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.COMPLIANCELIST compliancelist) { + this.compliancelist = compliancelist; + } + + /** + * Gets the correlation. + * + * @return the correlation + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION getCorrelation() { + return correlation; + } + + /** + * Sets the correlation. + * + * @param correlation the new correlation + */ + public void setCorrelation(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CORRELATION correlation) { + this.correlation = correlation; + } + + /** + * Gets the cvss. + * + * @return the cvss + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS getCvss() { + return cvss; + } + + /** + * Sets the cvss. + * + * @param cvss the new cvss + */ + public void setCvss(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSS cvss) { + this.cvss = cvss; + } + + /** + * Gets the cvssv 3. + * + * @return the cvssv 3 + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 getCvssv3() { + return cvssv3; + } + + /** + * Sets the cvssv 3. + * + * @param cvssv3 the new cvssv 3 + */ + public void setCvssv3(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.CVSSV3 cvssv3) { + this.cvssv3 = cvssv3; + } + + /** + * Gets the pciflag. + * + * @return the pciflag + */ + public byte getPciflag() { + return pciflag; + } + + /** + * Sets the pciflag. + * + * @param pciflag the new pciflag + */ + public void setPciflag(byte pciflag) { + this.pciflag = pciflag; + } + + /** + * Gets the pcireasons. + * + * @return the pcireasons + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS getPcireasons() { + return pcireasons; + } + + /** + * Sets the pcireasons. + * + * @param pcireasons the new pcireasons + */ + public void setPcireasons(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.PCIREASONS pcireasons) { + this.pcireasons = pcireasons; + } + + /** + * Gets the supportedmodules. + * + * @return the supportedmodules + */ + public String getSupportedmodules() { + return supportedmodules; + } + + /** + * Sets the supportedmodules. + * + * @param supportedmodules the new supportedmodules + */ + public void setSupportedmodules(String supportedmodules) { + this.supportedmodules = supportedmodules; + } + + /** + * Gets the discovery. + * + * @return the discovery + */ + public KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY getDiscovery() { + return discovery; + } + + /** + * Sets the discovery. + * + * @param discovery the new discovery + */ + public void setDiscovery(KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST.VULN.DISCOVERY discovery) { + this.discovery = discovery; + } + + /** + * Gets the isdisabled. + * + * @return the isdisabled + */ + public String getIsdisabled() { + return isdisabled; + } + + /** + * Sets the isdisabled. + * + * @param isdisabled the new isdisabled + */ + public void setIsdisabled(String isdisabled) { + this.isdisabled = isdisabled; + } + + /** + * Gets the load date. + * + * @return the load date + */ + public Date get_loadDate() { + return _loadDate; + } + + /** + * Sets the load date. + * + * @param date the new load date + */ + public void set_loadDate(Date date) { + this._loadDate = date; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Vuln [qid=" + qid + ", vulntype=" + vulntype + ", severitylevel=" + severitylevel + ", title=" + title + + ", category=" + category + ", lastservicemodificationdatetime=" + lastservicemodificationdatetime + + ", publisheddatetime=" + publisheddatetime + ", bugtraqlist=" + bugtraqlist + ", patchable=" + + patchable + ", softwarelist=" + softwarelist + ", vendorreferencelist=" + vendorreferencelist + + ", cvelist=" + cvelist + ", diagnosis=" + diagnosis + ", diagnosiscomment=" + diagnosiscomment + + ", consequence=" + consequence + ", consequencecomment=" + consequencecomment + ", solution=" + + solution + ", solutioncomment=" + solutioncomment + ", compliancelist=" + compliancelist + + ", correlation=" + correlation + ", cvss=" + cvss + ", cvssv3=" + cvssv3 + ", pciflag=" + pciflag + + ", pcireasons=" + pcireasons + ", supportedmodules=" + supportedmodules + ", discovery=" + discovery + + ", isdisabled=" + isdisabled + "]"; + } + + /** + * Checks if is latest. + * + * @return true, if is latest + */ + public boolean isLatest() { + return latest; + } + + /** + * Sets the latest. + * + * @param latest the new latest + */ + public void setLatest(boolean latest) { + this.latest = latest; + } + + /** + * Gets the classification. + * + * @return the classification + */ + public String getClassification() { + return classification; + } + + /** + * Sets the classification. + * + * @param classification the new classification + */ + public void setClassification(String classification) { + this.classification = classification; + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/exception/UnAuthorisedException.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/exception/UnAuthorisedException.java new file mode 100644 index 000000000..4d7e611d0 --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/exception/UnAuthorisedException.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.cso.pacman.qualys.exception; + +/** + * The Class UnAuthorisedException. + */ +public class UnAuthorisedException extends Exception { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; + + /** + * Instantiates a new un authorised exception. + */ + public UnAuthorisedException() { + } + + /** + * Instantiates a new un authorised exception. + * + * @param msg the msg + */ + public UnAuthorisedException(String msg) { + super(msg); + } + +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/HostAssetDataImporter.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/HostAssetDataImporter.java new file mode 100644 index 000000000..b93308770 --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/HostAssetDataImporter.java @@ -0,0 +1,825 @@ +package com.tmobile.cso.pacman.qualys.jobs; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.http.ParseException; +import org.joda.time.LocalDate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Strings; +import com.tmobile.cso.pacman.qualys.Constants; +import com.tmobile.cso.pacman.qualys.util.ElasticSearchManager; +import com.tmobile.cso.pacman.qualys.util.ErrorManageUtil; + + +/** + * The Class HostAssetDataImporter. + */ +public class HostAssetDataImporter extends QualysDataImporter implements Constants { + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory.getLogger(HostAssetDataImporter.class); + + /** The Constant TIME_FORMAT. */ + private static final String TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; + + /** The Constant MODIFIED. */ + private static final String MODIFIED = "modified"; + + /** The Constant NW_INTERFACE. */ + private static final String NW_INTERFACE = "networkInterface"; + + /** The Constant HOST_ASSET_INTERFACE. */ + private static final String HOST_ASSET_INTERFACE = "HostAssetInterface"; + + /** The Constant ADDRESS. */ + private static final String ADDRESS = "address"; + + /** The Constant MATCH_FOUND_BY. */ + private static final String MATCH_FOUND_BY = "matchFoundBy"; + + /** The Constant TRACKING_METHOD. */ + private static final String TRACKING_METHOD = "trackingMethod"; + + private static final String LAST_VULN_SCAN = "lastVulnScan"; + + /** The Constant VPC_ID. */ + private static final String VPC_ID = "vpcid"; + + /** The vuln info map. */ + private Map> vulnInfoMap; + + /** The current info. */ + private Map> currentInfo; + + /** The current qualys info. */ + private Map> currentQualysInfo; + + /** The vpc nat ip assets. */ + private Map>>> vpcNatIpAssets = new HashMap<>();// vpciid>> + + /** The ec 2 eni map. */ + private Map> ec2EniMap; + + /** The eni mac map. */ + private Map eniMacMap; + + /** The curr date. */ + private String CURR_DATE = new SimpleDateFormat(TIME_FORMAT).format(new java.util.Date()); + + /** The type. */ + private String type = System.getProperty("server_type"); + + /** The type. */ + private String ds = System.getProperty("datasource"); + + /** The uri post. */ + private String uriPost = BASE_API_URL + apiMap.get("hostAssetSearch"); + + private int scanThreshold = 30; + + /** The last vuln date. */ + private String lastVulnDate = LocalDate.now().minusDays(scanThreshold).toString(); + + private static List> errorList = new ArrayList<>(); + + /** + * Execute. + * @return + */ + public Map execute() { + + Map stats = new LinkedHashMap<>(); + stats.put("type", type); + stats.put("start_time", new SimpleDateFormat(TIME_FORMAT).format(new java.util.Date())); + + init(); + + Map> procssInfo = new HashMap<>(); + try { + procssInfo = fetchHostAssets(type); + } catch (Exception e) { + LOGGER.error("Error fetching host assets ", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Error fetching host assets"); + errorMap.put(ERROR_TYPE, FATAL); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + + List processList = procssInfo.get(PROCESSED); + List uploadList = procssInfo.get(UPLOADED); + List failedList = procssInfo.get(FAILED); + + LOGGER.info("Total processed {}", uploadList.size()); + + if (!uploadList.isEmpty()) { + new HostAssetsEsIndexer().wrapUp(type, CURR_DATE,errorList); + } + + stats.put("end_time", new SimpleDateFormat(TIME_FORMAT).format(new java.util.Date())); + stats.put(PROCESSED, processList.size()); + stats.put("type", type); + stats.put(UPLOADED, uploadList.size()); + stats.put(FAILED, failedList.size()); + stats.put("processedHosts", processList); + stats.put("uploadedHosts", uploadList); + stats.put("failedHosts", failedList); + updateStas(stats); + + return ErrorManageUtil.formErrorCode(errorList); + + } + + /** + * Inits the. + */ + private void init() { + + String indexName = ds+"_" + type; + List filters = new ArrayList<>(); + if ("ec2".equals(type)) { + filters = Arrays.asList("_docid", "privateipaddress", "tags.Name", RESOURCE_ID, "tags.Application", + "accountid", "accountname", "statename", "platform", VPC_ID, "publicipaddress", "imageid"); + } else if ("onpremserver".equals(type)) { + filters = Arrays.asList("_docid", "name", "fqdn", "ip_address", RESOURCE_ID); + }else if("virtualmachine".equals(type)){ + filters = Arrays.asList("_docid", "computerName", "privateIpAddress","primaryNCIMacAddress", RESOURCE_ID); + } + currentInfo = ElasticSearchManager.getExistingInfo(indexName, type, filters, true); + + + filters = Arrays.asList(RESOURCE_ID, "id"); + currentQualysInfo = ElasticSearchManager.getExistingInfo(indexName, "qualysinfo", filters, true); + + LOGGER.debug("Total current resources : {}", currentInfo.size()); + + if ("ec2".equals(type)) { + currentInfo = currentInfo.entrySet().stream() + .filter(entry -> "running".equals(entry.getValue().get("statename"))) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + + LOGGER.info("Total current resources Running : {}", currentInfo.size()); + + ec2EniMap = Util.fetchEc2EniInfo(); + + Set ec2EniList = ec2EniMap.entrySet().stream().flatMap(entry -> entry.getValue().stream()) + .collect(Collectors.toSet()); + eniMacMap = Util.fetchEniMacInfo(); + Set eniList = eniMacMap.keySet(); + + Set missingEniMappings = ec2EniList.stream().filter(ec2Eni -> !eniList.contains(ec2Eni)) + .collect(Collectors.toSet()); + + LOGGER.info("Missing Enis {} > {}", missingEniMappings.size(), missingEniMappings); + Map> VpcPublicIpInfo = Util.fetchVPCtoNatIPInfo(); + + Set vpcList = currentInfo.entrySet().stream().map(entry -> entry.getValue().get(VPC_ID)) + .collect(Collectors.toSet()); + VpcPublicIpInfo = VpcPublicIpInfo.entrySet().stream().filter(entry -> vpcList.contains(entry.getKey())) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + vpcNatIpAssets = fetchAssetsWithNatIpAsAddress(VpcPublicIpInfo); + LOGGER.debug("Initialisation Complete"); + } + + filters = Arrays.asList("qid", "vulntype", "severitylevel", "title", "category", "patchable", "pciflag", + "classification"); + vulnInfoMap = ElasticSearchManager.getExistingInfo("qualys-kb", "kb", filters, true); + } + + /** + * Fetch host assets. + * + * @param type the type + * @return the map + * @throws Exception the exception + */ + private Map> fetchHostAssets(String type) throws Exception { + + Map> procssInfo = new HashMap<>(); + + List> processList = new ArrayList<>(); + List uploadList = new ArrayList<>(); + List> noPrfileList = new ArrayList<>(); + + procssInfo.put(PROCESSED, processList); + procssInfo.put(UPLOADED, uploadList); + procssInfo.put(FAILED, noPrfileList); + + Map> hostAssets = new HashMap<>(); + + currentInfo.entrySet().stream().forEach(entry -> { + try { + String docid = entry.getKey(); + String resouceId = entry.getValue().get(RESOURCE_ID); + String name = ""; + String ip = ""; + String vmMac=""; + if ("onpremserver".equals(type)) { + name = entry.getValue().get("name"); + ip = entry.getValue().get("ip_address"); + } else if("ec2".equals("type")) { + name = entry.getValue().get("tags.Name"); + ip = entry.getValue().get("privateipaddress"); + }else if("virtualmachine".equals(type)){ + name = entry.getValue().get("computerName"); + ip = entry.getValue().get("privateIpAddress"); + vmMac = entry.getValue().get("primaryNCIMacAddress"); + } + + Map processinfo = new LinkedHashMap<>(); + processinfo.put("_resouceId", resouceId); + processinfo.put("name", name == null ? "" : name); + processinfo.put("ip", ip); + + Map hostAsset = null; + if ("ec2".equals(type)) { + /* + * EC2 Instance ID based lookup is currently supported and is the preferred approach + * If it fails, we need to search based on IP and other fallback approaches. + * Onprem still continues with ip and name + */ + hostAsset = fetchBasedOnInstanceID(resouceId,processinfo); + } + + if(hostAsset==null){ // For ec2, instancedid based lookup fails + String inputXml = " " + "100" + + "" + "%s" + + "%s" + "" + + ""; + + List> respData = null; + if (!Strings.isNullOrEmpty(ip)) { + String _inputXml = String.format(inputXml, ip, lastVulnDate); + + respData = getHostData(uriPost, _inputXml); + + } + + if (respData == null) + respData = new ArrayList<>(); + + processinfo.put("totalProfilesFound", respData.size()); + processinfo.put("profiles", Util.fetchTrackinMethodAndQids(respData)); + + List> _respData = Util.sortOnLastVulnScan(respData); + + if ("ec2".equals(type)) { + for (int i = 0; i < _respData.size(); i++) { + Map host = _respData.get(i); + Long id = Double.valueOf(host.get("id").toString()).longValue(); + String trackingMethod = host.get(TRACKING_METHOD).toString(); + + if (matchBasedonInstanceId(host, resouceId)) { + processinfo.put(TRACKING_METHOD, trackingMethod); + processinfo.put(MATCH_FOUND_BY, "InstanceId > Id:" + id); + hostAsset = host; + } else if (matchBasedonMacAddress(host, resouceId, ip, processinfo)) { + processinfo.put(TRACKING_METHOD, trackingMethod); + hostAsset = host; + processinfo.put(MATCH_FOUND_BY, "Mac/Eni > Id:" + id); + } + if (hostAsset != null) { + if (i > 0) { + processinfo.put("matchFoundAt", i); + } + break; + } + } + + if (hostAsset == null) { + hostAsset = fallbackNameBasedMatch(name, ip); + if (hostAsset != null) { + processinfo.put(TRACKING_METHOD, hostAsset.get(TRACKING_METHOD).toString()); + processinfo.put(MATCH_FOUND_BY, "FallBack Name Match > Id:" + + Double.valueOf(hostAsset.get("id").toString()).longValue()); + } + } + if (hostAsset == null) { + hostAsset = fallbackNatIpBasedMatch(docid, ip); + if (hostAsset != null) { + processinfo.put(TRACKING_METHOD, hostAsset.get(TRACKING_METHOD).toString()); + processinfo.put(MATCH_FOUND_BY, "FallBack NAT-IP Match > Id:" + + Double.valueOf(hostAsset.get("id").toString()).longValue()); + } + } + } else { + + // Azure VM : MacID based lookup + if("virtualmachine".equals(type)){ + for (int i = 0; i < _respData.size(); i++) { + Map host = _respData.get(i); + if (matchBasedonMacAddressVM(ip, vmMac, host)) { + hostAsset = host; + processinfo.put(TRACKING_METHOD, hostAsset.get(TRACKING_METHOD).toString()); + processinfo.put(MATCH_FOUND_BY, + "MacAddress > Id:" + Double.valueOf(hostAsset.get("id").toString()).longValue()); + } + if (hostAsset != null) { + if (i > 0) { + processinfo.put("matchFoundAt", i); + } + break; + } + } + } + + if(hostAsset==null){ + for (int i = 0; i < _respData.size(); i++) { + Map host = _respData.get(i); + if (matchBasedonName(host, name)) { + hostAsset = host; + processinfo.put(TRACKING_METHOD, hostAsset.get(TRACKING_METHOD).toString()); + processinfo.put(MATCH_FOUND_BY, + "Name > Id:" + Double.valueOf(hostAsset.get("id").toString()).longValue()); + } + if (hostAsset != null) { + if (i > 0) { + processinfo.put("matchFoundAt", i); + } + break; + } + } + } + + } + + if (hostAsset == null) { + hostAsset = fallbackIdBasedMatch(resouceId, processinfo); + } + + if (hostAsset == null) { + hostAsset = fallbackToCurrentInfo(resouceId, processinfo); + } + } + + // This is needed to ensure the vulnifo is available in the hostasset if not we need to fetch it by retry or from current data + hostAsset = checkAndFetchVulnInfo(type, resouceId, processinfo, hostAsset); + + synchronized (processList) { + processList.add(processinfo); + } + + Map> _hostAssets = null; + if (hostAsset != null) { + hostAsset.put(RESOURCE_ID, resouceId); + processinfo.put(LAST_VULN_SCAN, hostAsset.get(LAST_VULN_SCAN)); + synchronized (hostAssets) { + uploadList.add(resouceId); + hostAssets.put(docid, hostAsset); + if (hostAssets.size() >= 50) { + _hostAssets = new HashMap<>(hostAssets); + hostAssets.clear(); + } + } + } else { + synchronized (noPrfileList) { + noPrfileList.add(entry.getValue()); + } + } + if (_hostAssets != null) { + Util.processAndTransform(_hostAssets, vulnInfoMap, CURR_DATE); + new HostAssetsEsIndexer().postHostAssetToES(_hostAssets, ds,type,errorList); + } + } catch (Exception e) { + LOGGER.error("Error Fetching data for " + entry.getKey(), e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Error Fetching data for " + entry.getKey()); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + }); + + Util.processAndTransform(hostAssets, vulnInfoMap, CURR_DATE); + new HostAssetsEsIndexer().postHostAssetToES(hostAssets,ds, type,errorList); + return procssInfo; + } + + private Map fetchBasedOnInstanceID(String resouceId, Map processinfo) { + Map hostAsset = null; + String inputXmlWithInstanceId = " " + "100" + + "" + "%s" + + "%s" + "" + + ""; + String _inputXml = String.format(inputXmlWithInstanceId, resouceId, lastVulnDate); + List> respData = getHostData(uriPost, _inputXml); + if(respData!=null && !respData.isEmpty()){ + hostAsset = respData.get(0); + Long id = Double.valueOf(hostAsset.get("id").toString()).longValue(); + String trackingMethod = hostAsset.get(TRACKING_METHOD).toString(); + processinfo.put(TRACKING_METHOD, trackingMethod); + processinfo.put(MATCH_FOUND_BY, "InstanceId Lookup > Id:" + id); + } + return hostAsset; + } + private Map fallbackToCurrentInfo(String resouceId, Map processinfo) { + Map hostAsset = null; + try { + if (currentQualysInfo.get(resouceId) != null) { + String strQid = currentQualysInfo.get(resouceId).get("id"); + Long qualysId = Double.valueOf(strQid).longValue(); + hostAsset = Util.fetchCurretQualysInfo(type,resouceId); + if (hostAsset != null && Util.isScanInfoAvailable(hostAsset,scanThreshold)) { + processinfo.put("fallbackInfo", "Existing Match, Id:" + qualysId); + } else { + hostAsset = null; + } + } + }catch (Exception e) { + LOGGER.error("Error Fetching Current Info ",e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Error Fetching Current Info"); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + return hostAsset; + } + + /** + * Check and fetch vuln info. + * + * @param type the type + * @param resouceId the resouce id + * @param processinfo the processinfo + * @param hostAsset the host asset + * @return the map + */ + private Map checkAndFetchVulnInfo(String type, String resouceId, Map processinfo, + Map hostAsset) { + + Map host = hostAsset; + if (host != null && host.get("vuln") == null) { + + processinfo.put(VULN_MISSING, "true"); + // Retry with the current matched ID + host = fetchhostAssetWithID(Double.valueOf(host.get("id").toString()).longValue()); + + if (host != null && host.get("vuln") != null) { + processinfo.put(VULN_MISSING, "FetchedInRetry"); + } else { + try { + Map _hostAsset = null; + if (currentQualysInfo.get(resouceId) != null) { + _hostAsset = Util.fetchCurretQualysInfo(type, resouceId); + if(!Util.isScanInfoAvailable(_hostAsset, scanThreshold)){ + _hostAsset = null; + } + } + host = _hostAsset; + if (host != null) { + processinfo.put(VULN_MISSING, "OldInfoUsed"); + } + + } catch (ParseException | IOException e) { + LOGGER.error("Error in checkAndFetchVulnInfo", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Error in checkAndFetchVulnInfo"); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + } + } + return host; + } + + /** + * Match basedon instance id. + * + * @param host the host + * @param instanceId the instance id + * @return true, if successful + */ + @SuppressWarnings("unchecked") + private boolean matchBasedonInstanceId(Map host, String instanceId) { + Map sourceInfo = (Map) host.get("sourceInfo"); + String _instanceId = ""; + if (sourceInfo != null) { + List> sourceInfoList = (List>) sourceInfo.get("list"); + if (sourceInfoList != null) { + _instanceId = sourceInfoList.stream() + .filter(_sourceInfo -> _sourceInfo.get("Ec2AssetSourceSimple") != null) + .map(_sourceInfo -> ((Map) _sourceInfo.get("Ec2AssetSourceSimple")) + .get("instanceId").toString()) + .collect(Collectors.joining()); + } + } + return instanceId.equalsIgnoreCase(_instanceId); + } + + /** + * Update stas. + * + * @param stats the stats + */ + private void updateStas(Map stats) { + String statsJson = ElasticSearchManager.createESDoc(stats); + try { + ElasticSearchManager.invokeAPI("POST", "/datashipper/qualys-stats", statsJson); + } catch (IOException e) { + LOGGER.error("Error in updateStas", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Error in updateStas"); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + } + + /** + * Fallback nat ip based match. + * + * @param resouceId the resouce id + * @param ip the ip + * @return the map + */ + private Map fallbackNatIpBasedMatch(String resouceId, String ip) { + + Map hostAsset = null; + + String vpcid = currentInfo.get(resouceId).get(VPC_ID); + List>> natIpAssets = vpcNatIpAssets.get(vpcid); + if (natIpAssets != null) { + List> idList = natIpAssets.stream().filter(obj -> obj.get(ip) != null) + .map(obj -> obj.get(ip)) + .sorted((obj1, obj2) -> LocalDateTime + .parse(obj2.get(MODIFIED).toString(), DateTimeFormatter.ISO_DATE_TIME) + .compareTo(LocalDateTime.parse(obj1.get(MODIFIED).toString(), + DateTimeFormatter.ISO_DATE_TIME))) + .collect(Collectors.toList()); + if (!idList.isEmpty()) { + Long qualysId = Double.valueOf(idList.get(0).get("id").toString()).longValue(); + hostAsset = fetchhostAssetWithID(qualysId); + } + } + return hostAsset; + } + + /** + * Fallback name based match. + * + * @param name the name + * @param ip the ip + * @return the map + */ + @SuppressWarnings("unchecked") + private Map fallbackNameBasedMatch(String name, String ip) { + Map hostAsset = null; + String inputXml = " " + "100" + + "" + "%s" + + "%s" + "" + + ""; + String _inputXml = String.format(inputXml, name, lastVulnDate); + List> hosts = getHostData(uriPost, _inputXml); + if (hosts != null && !hosts.isEmpty()) { + String _ip = ip; + hosts = hosts.stream().filter(host -> { + boolean isIpMatches = false; + Map nwinterfaces = (Map) host.get(NW_INTERFACE); + if (nwinterfaces != null) { + List>> nwInterfaceList = (List>>) nwinterfaces + .get("list"); + if (nwInterfaceList != null) { + isIpMatches = nwInterfaceList.stream() + .filter(obj -> _ip.equals(obj.get(HOST_ASSET_INTERFACE).get(ADDRESS))).count() > 0; + } + } + return isIpMatches; + }).sorted((obj1, obj2) -> LocalDateTime + .parse(obj2.get("lastVulnScan").toString(), DateTimeFormatter.ISO_DATE_TIME).compareTo( + LocalDateTime.parse(obj1.get("lastVulnScan").toString(), DateTimeFormatter.ISO_DATE_TIME))) + .collect(Collectors.toList()); + + if (hosts != null && !hosts.isEmpty()) { + hostAsset = hosts.get(0); + } + } + + return hostAsset; + + } + + /** + * Fallback id based match. + * + * @param resouceId the resouce id + * @param processinfo the processinfo + * @return the map + */ + private Map fallbackIdBasedMatch(String resouceId, Map processinfo) { + Map hostAsset = null; + if (currentQualysInfo.get(resouceId) != null) { + String strQid = currentQualysInfo.get(resouceId).get("id"); + Long qualysId = Double.valueOf(strQid).longValue(); + hostAsset = fetchhostAssetWithID(qualysId); + if (hostAsset != null && Util.isScanInfoAvailable(hostAsset,scanThreshold)) { + processinfo.put("fallbackInfo", "Id Match, Id:" + qualysId); + } else { + hostAsset = null; + } + } + return hostAsset; + } + + /** + * Fetchhost asset with ID. + * + * @param qualysId the qualys id + * @return the map + */ + private Map fetchhostAssetWithID(Long qualysId) { + Map hostAsset = null; + String inputXml; + String _inputXml; + List> hosts; + inputXml = " " + "1" + "" + + "%s" + + "%s" + "" + + ""; + _inputXml = String.format(inputXml, qualysId, lastVulnDate); + + hosts = getHostData(uriPost, _inputXml); + + if (hosts != null && !hosts.isEmpty()) { + hostAsset = hosts.get(0); + } + return hostAsset; + } + + + /** + * Fetch assets with nat ip as address. + * + * @param vpcIpInfo the vpc ip info + * @return the map + */ + @SuppressWarnings("unchecked") + public Map>>> fetchAssetsWithNatIpAsAddress( + Map> vpcIpInfo) { + + Map>>> vpcAssets = new HashMap<>(); // vpciid-natip-ip-qid + + vpcIpInfo.entrySet().forEach(entry -> { + String vpcId = entry.getKey(); + List ipList = entry.getValue(); + List>> natIpQidInfo = new ArrayList<>(); + for (String natIp : ipList) { + + String inputXml = " " + "1000" + + "" + "%s" + + "%s" + "" + + ""; + String _inputXml = String.format(inputXml, natIp, lastVulnDate); + + List> hosts = getHostData(uriPost+"?fields=id,modified,networkInterface.list", _inputXml); + Map> ipQidInfo = new HashMap<>(); + if (hosts != null && !hosts.isEmpty()) { + hosts.stream().forEach(host -> { + String id = host.get("id").toString(); + Object modified = host.get(MODIFIED); + Map nwinterfaces = (Map) host.get(NW_INTERFACE); + if (nwinterfaces != null) { + List>> nwInterfaceList = (List>>) nwinterfaces + .get("list"); + if (nwInterfaceList != null) { + nwInterfaceList.stream().forEach(obj -> { + String ip = obj.get(HOST_ASSET_INTERFACE).get(ADDRESS); + Map qidInfo = ipQidInfo.get(ip); + if (qidInfo == null || (LocalDateTime + .parse(modified.toString(), DateTimeFormatter.ISO_DATE_TIME) + .isAfter(LocalDateTime.parse(qidInfo.get(MODIFIED).toString(), + DateTimeFormatter.ISO_DATE_TIME)))) { + qidInfo = new HashMap<>(); + qidInfo.put("id", id); + qidInfo.put(MODIFIED, modified); + ipQidInfo.put(ip, qidInfo); + } + }); + } + } + }); + } + natIpQidInfo.add(ipQidInfo); + } + vpcAssets.put(vpcId, natIpQidInfo); + }); + return vpcAssets; + } + + /** + * Match basedon mac address. + * + * @param host the host + * @param resouceId the resouce id + * @param ip the ip + * @param processInfo the process info + * @return true, if successful + */ + @SuppressWarnings("unchecked") + private boolean matchBasedonMacAddress(Map host, String resouceId, String ip, + Map processInfo) { + List eniList = ec2EniMap.get(resouceId); + List macAddressList = new ArrayList<>(); + if (eniList != null) { + eniList.forEach(eni -> macAddressList.add(eniMacMap.get(eni))); + Map nwinterfaces = (Map) host.get(NW_INTERFACE); + if (nwinterfaces != null) { + List>> nwInterfaceList = (List>>) nwinterfaces + .get("list"); + return isMatchBasedOnMac(ip, nwInterfaceList, eniList, macAddressList, host, processInfo); + } + } + return false; + } + + /** + * Checks if is match based on mac. + * + * @param ip the ip + * @param nwInterfaceList the nw interface list + * @param eniList the eni list + * @param macAddressList the mac address list + * @param host the host + * @param processInfo the process info + * @return true, if is match based on mac + */ + private boolean isMatchBasedOnMac(String ip, List>> nwInterfaceList, + List eniList, List macAddressList, Map host, + Map processInfo) { + String trackingMethod = host.get(TRACKING_METHOD).toString(); + String id = Long.toString(Double.valueOf(host.get("id").toString()).longValue()); + if (nwInterfaceList != null) { + for (Map> nwInterface : nwInterfaceList) { + String _ip = nwInterface.get(HOST_ASSET_INTERFACE).get(ADDRESS); + String mac = nwInterface.get(HOST_ASSET_INTERFACE).get("macAddress"); + String eniId = nwInterface.get(HOST_ASSET_INTERFACE).get("interfaceId"); + + if ("QAGENT".equals(trackingMethod) && mac == null) { + processInfo.put("QAGNT_MAC_MISSING", id); + LOGGER.info("QAGNT_MAC_MISSING : {}", id); + } + mac = (mac == null ? "" : mac.toLowerCase()); + eniId = (eniId == null ? "" : eniId.toLowerCase()); + if (_ip.equals(ip) && (macAddressList.contains(mac) || eniList.contains(eniId))) { + return true; + } + } + } + return false; + + } + + @SuppressWarnings("unchecked") + private boolean matchBasedonMacAddressVM(String vmIp,String vmMac,Map host){ + Map nwinterfaces = (Map) host.get(NW_INTERFACE); + if (nwinterfaces != null && vmMac !=null) { + List>> nwInterfaceList = (List>>) nwinterfaces + .get("list"); + String macRegex = "[^a-z0-9]"; + vmMac = vmMac.toLowerCase().replaceAll(macRegex, ""); + if (nwInterfaceList != null) { + for (Map> nwInterface : nwInterfaceList) { + String _ip = nwInterface.get(HOST_ASSET_INTERFACE).get(ADDRESS); + String mac = nwInterface.get(HOST_ASSET_INTERFACE).get("macAddress"); + mac = (mac == null ? "" : mac.toLowerCase().replaceAll(macRegex, "")); + if (vmIp.equals(_ip) && vmMac.equals(mac)) { + return true; + } + } + } + } + + return false; + } + + /** + * Match basedon name. + * + * @param host the host + * @param nameParam the name param + * @return true, if successful + */ + private boolean matchBasedonName(Map host, String nameParam) { + String name = nameParam.toLowerCase(); + String _name = (String) host.get("name"); + + _name = _name == null ? "null" : _name.toLowerCase(); + return (_name.contains(name) || name.contains(_name)); + + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/HostAssetsEsIndexer.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/HostAssetsEsIndexer.java new file mode 100644 index 000000000..89e0da6be --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/HostAssetsEsIndexer.java @@ -0,0 +1,222 @@ +package com.tmobile.cso.pacman.qualys.jobs; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.amazonaws.util.CollectionUtils; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tmobile.cso.pacman.qualys.Constants; +import com.tmobile.cso.pacman.qualys.util.ElasticSearchManager; + + +/** + * The Class HostAssetsEsIndexer. + */ +@SuppressWarnings("unchecked") +public class HostAssetsEsIndexer implements Constants { + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory.getLogger(HostAssetsEsIndexer.class); + + /** + * Post host asset to ES. + * + * @param qualysInfo the qualys info + * @param type the type + */ + public void postHostAssetToES(Map> qualysInfo, String ds,String type,List> errorList) { + LOGGER.info("Uploading"); + String index = ds+"_" + type; + ElasticSearchManager.createType(index, "qualysinfo", type); + ElasticSearchManager.createType(index, "vulninfo", type); + + String createTemplate = "{ \"index\" : { \"_index\" : \"%s\", \"_type\" : \"%s\", \"_id\" : \"%s\", \"_parent\" : \"%s\" } }%n"; + + Iterator>> it = qualysInfo.entrySet().iterator(); + int i = 0; + StringBuilder createRequest = new StringBuilder(); + StringBuilder vulnRequest = new StringBuilder(); + + while (it.hasNext()) { + Entry> entry = it.next(); + String parent = entry.getKey(); + Map asset = entry.getValue(); + String assetDoc = createESDoc(asset,errorList); + createRequest.append(String.format(createTemplate, index, "qualysinfo", asset.get(DOC_ID), parent)); + createRequest.append(assetDoc + "\n"); + List> vulnInfo = fetchVulnInfo(asset,errorList); + if (!CollectionUtils.isNullOrEmpty(vulnInfo)) { + for (Map vuln : vulnInfo) { + vulnRequest + .append(String.format(createTemplate, index, "vulninfo", vuln.get("@id"), parent)); + vuln.remove("@id"); + vulnRequest.append(createESDoc(vuln,errorList) + "\n"); + } + } + i++; + + if (i % 50 == 0) { + bulkUpload(createRequest.toString(),errorList); + bulkUpload(vulnRequest.toString(),errorList); + createRequest = new StringBuilder(); + vulnRequest = new StringBuilder(); + } + } + + if (createRequest.length() > 0) { + + bulkUpload(createRequest.toString(),errorList); + } + if (vulnRequest.length() > 0) { + bulkUpload(vulnRequest.toString(),errorList); + } + + } + + /** + * Bulk upload. + * + * @param bulkRequest the bulk request + */ + private void bulkUpload(String bulkRequest,List> errorList) { + try { + Response resp = ElasticSearchManager.invokeAPI("POST", "/_bulk", bulkRequest); + String responseStr = EntityUtils.toString(resp.getEntity()); + if (responseStr.contains("\"errors\":true")) { + LOGGER.error(responseStr); + } + } catch (IOException e) { + LOGGER.error("BulkUpload Failed", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "BulkUpload Failed"); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + } + + /** + * Creates the ES doc. + * + * @param asset the asset + * @return the string + */ + private String createESDoc(Object asset,List> errorList) { + ObjectMapper objMapper = new ObjectMapper(); + try { + return objMapper.writeValueAsString(asset); + } catch (JsonProcessingException e) { + LOGGER.error("Unexpected Error:", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Unexpected Error:"); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + return null; + } + + /** + * Fetch vuln info. + * + * @param asset the asset + * @return the list + */ + private List> fetchVulnInfo(Map asset,List> errorList) { + List> vulnInfoList = new ArrayList<>(); + try { + Map> vulnMap = (Map>) asset.get("vuln"); + if (vulnMap != null) { + List> vulnList = (List>) vulnMap.get("list"); + if (vulnList != null) { + for (Map hostvuln : vulnList) { + Map vuln = new HashMap<>((Map) hostvuln.get("HostAssetVuln")); + if(vuln.containsKey("severitylevel") && vuln.containsKey("vulntype")) { + if(Long.valueOf(vuln.get("severitylevel").toString())>=3 && "Vulnerability".equals(vuln.get("vulntype"))){ + vuln.put(DOC_ID, asset.get(DOC_ID)); + vuln.put("discoverydate", asset.get("discoverydate")); + vuln.put("severity", "S" + vuln.get("severitylevel")); + vuln.put("@id", asset.get(DOC_ID).toString() + "_" + vuln.get("qid").toString()); + vuln.put("latest", true); + vuln.put("_resourceid", asset.get("_resourceid")); + + Object firstFound = vuln.get("firstFound"); + Object lastFound = vuln.get("lastFound"); + + Object _firstFound = null; + Object _lastFound = null; + vuln.put("_vulnage", Util.calculteAgeInDays(firstFound, lastFound)); + + if (firstFound != null) { + _firstFound = firstFound; + } + + if (lastFound != null) { + _lastFound = lastFound; + } else { + _lastFound = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new java.util.Date()); + } + + if (_firstFound == null) { + _firstFound = _lastFound; + } + vuln.put("_firstFound", _firstFound); + vuln.put("_lastFound", _lastFound); + + vulnInfoList.add(vuln); + } + } + } + } + } + } catch (Exception e) { + LOGGER.error("fetchVulnInfo Failed", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Unexpected Error:"); + errorMap.put(ERROR_TYPE, FATAL); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + return vulnInfoList; + } + + /** + * Wrap up. + * + * @param type the type + * @param CURR_DATE the curr date + */ + public void wrapUp(String type, String CURR_DATE,List> errorList) { + + String index = "aws_" + type; + ElasticSearchManager.refresh(index); + String closeQidsJson = "{\"script\":{\"inline\": \"ctx._source._status='Closed';ctx._source._closedate='" + + CURR_DATE + + "';ctx._source.latest=false\"},\"query\": {\"bool\": {\"must\": [{ \"match\": {\"latest\":true}}], \"must_not\": [{\"match\": {\"discoverydate.keyword\":\"" + + CURR_DATE + "\"}}]}}}"; + try { + ElasticSearchManager.invokeAPI("POST", "/"+index + "/vulninfo/" + "_update_by_query", closeQidsJson); + } catch (IOException e) { + LOGGER.error("wrapUp Failed", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "wrapUp Failed"); + errorMap.put(ERROR_TYPE, WARN); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + + ElasticSearchManager.updateLatestStatus(index, "qualysinfo", CURR_DATE); + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/KBDataImporter.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/KBDataImporter.java new file mode 100644 index 000000000..2c064423f --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/KBDataImporter.java @@ -0,0 +1,124 @@ +package com.tmobile.cso.pacman.qualys.jobs; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tmobile.cso.pacman.qualys.Constants; +import com.tmobile.cso.pacman.qualys.dto.KNOWLEDGEBASEVULNLISTOUTPUT; +import com.tmobile.cso.pacman.qualys.dto.KNOWLEDGEBASEVULNLISTOUTPUT.RESPONSE.VULNLIST; +import com.tmobile.cso.pacman.qualys.dto.Vuln; +import com.tmobile.cso.pacman.qualys.util.ElasticSearchManager; +import com.tmobile.cso.pacman.qualys.util.ErrorManageUtil; + + +/** + * The Class KBDataImporter. + */ +public class KBDataImporter extends QualysDataImporter implements Constants{ + + /** The log. */ + private static Logger log = LoggerFactory.getLogger(QualysDataImporter.class); + + /** The Constant index. */ + private final static String index = "qualys-kb"; + + /** The Constant type. */ + private final static String type = "kb"; + + /** The Constant docid. */ + private final static String docid = "qid"; + + private static List> errorList = new ArrayList<>(); + + /** + * Execute. + * @return + */ + @SuppressWarnings("unchecked") + public Map execute() { + + // long DAY_IN_MS = 1000 * 60 * 60 * 24l; + String kbGetUri = BASE_API_URL + apiMap.get("listKnowledgebase") ; + /*"&last_modified_after=" + + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") + .format(new java.util.Date(System.currentTimeMillis() - (10 * DAY_IN_MS)));*/ + log.info("Calling API {}", kbGetUri); + + List> vulnDetails = new ArrayList<>(); + try { + String resultXML = callApi(kbGetUri, "GET", null, null); + XMLStreamReader reader = buildXMLReader(resultXML); + + JAXBContext jaxbContext = JAXBContext.newInstance(KNOWLEDGEBASEVULNLISTOUTPUT.class); + Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + KNOWLEDGEBASEVULNLISTOUTPUT resp = (KNOWLEDGEBASEVULNLISTOUTPUT) jaxbUnmarshaller.unmarshal(reader); + VULNLIST vulnList = resp.getRESPONSE().getVULNLIST(); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'z'")); + vulnList.getVULN().parallelStream().forEach(vuln -> { + Vuln vulnInfo = new Vuln(); + vulnInfo.setQid(String.valueOf(vuln.getQID())); + vulnInfo.setVulntype(vuln.getVULNTYPE()); + vulnInfo.setSeveritylevel(vuln.getSEVERITYLEVEL()); + vulnInfo.setTitle(vuln.getTITLE()); + vulnInfo.setCategory(vuln.getCATEGORY()); + vulnInfo.setLastservicemodificationdatetime(vuln.getLASTSERVICEMODIFICATIONDATETIME()); + vulnInfo.setPublisheddatetime(vuln.getPUBLISHEDDATETIME()); + vulnInfo.setBugtraqlist(vuln.getBUGTRAQLIST()); + vulnInfo.setPatchable(String.valueOf(vuln.getPATCHABLE())); + vulnInfo.setSoftwarelist(vuln.getSOFTWARELIST()); + vulnInfo.setVendorreferencelist(vuln.getVENDORREFERENCELIST()); + vulnInfo.setCvelist(vuln.getCVELIST()); + vulnInfo.setDiagnosis(vuln.getDIAGNOSIS()); + vulnInfo.setDiagnosiscomment(vuln.getDIAGNOSISCOMMENT()); + vulnInfo.setConsequence(vuln.getCONSEQUENCE()); + vulnInfo.setConsequencecomment(vuln.getCONSEQUENCECOMMENT()); + vulnInfo.setSolution(vuln.getSOLUTION()); + vulnInfo.setSolutioncomment(vuln.getSOLUTIONCOMMENT()); + vulnInfo.setCompliancelist(vuln.getCOMPLIANCELIST()); + vulnInfo.setCorrelation(vuln.getCORRELATION()); + vulnInfo.setCvss(vuln.getCVSS()); + vulnInfo.setCvssv3(vuln.getCVSSV3()); + vulnInfo.setPciflag(vuln.getPCIFLAG()); + vulnInfo.setPcireasons(vuln.getPCIREASONS()); + vulnInfo.setSupportedmodules(vuln.getSUPPORTEDMODULES()); + vulnInfo.setDiscovery(vuln.getDISCOVERY()); + vulnInfo.setIsdisabled(vuln.getISDISABLED()); + vulnInfo.setIsdisabled(vuln.getISDISABLED()); + vulnInfo.set_loadDate(new java.util.Date()); + vulnInfo.setLatest(true); + vulnInfo.setClassification(Util.classifyVuln(vulnInfo)); + synchronized (vulnDetails) { + vulnDetails.add(objectMapper.convertValue(vulnInfo, Map.class)); + } + }); + } catch (JAXBException | IOException | XMLStreamException e) { + log.error("Error in KBDataImporter ", e); + Map errorMap = new HashMap<>(); + errorMap.put(ERROR, "Error in KBDataImporter"); + errorMap.put(ERROR_TYPE, FATAL); + errorMap.put(EXCEPTION, e.getMessage()); + errorList.add(errorMap); + } + ElasticSearchManager.createIndex(index); + ElasticSearchManager.createType(index, type); + ElasticSearchManager.uploadData(index, type, vulnDetails, docid); + + return ErrorManageUtil.formErrorCode(errorList); + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/QualysDataImporter.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/QualysDataImporter.java new file mode 100644 index 000000000..c86d5476d --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/QualysDataImporter.java @@ -0,0 +1,205 @@ +package com.tmobile.cso.pacman.qualys.jobs; + +import java.io.IOException; +import java.io.StringReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.tmobile.cso.pacman.qualys.util.Util; + + +/** + * The Class QualysDataImporter. + */ +public abstract class QualysDataImporter { + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory.getLogger(QualysDataImporter.class); + + /** The Constant DEFAULT_USER. */ + private static final String DEFAULT_USER = Util.base64Decode(System.getProperty("qualys_info")).split(":")[0]; + + /** The Constant DEFAULT_PASS. */ + private static final String DEFAULT_PASS = Util.base64Decode(System.getProperty("qualys_info")).split(":")[1]; + + /** The Constant UTF8. */ + private static final String UTF8 = "UTF-8"; + + /** The api map. */ + protected Map apiMap; + + /** + * Gets the api map. + * + * @return the api map + */ + public Map getApiMap() { + return apiMap; + } + + /** + * Sets the api map. + * + * @param apiMap the api map + */ + public void setApiMap(Map apiMap) { + this.apiMap = apiMap; + } + + /** The Constant BASE_API_URL. */ + protected static final String BASE_API_URL = System.getProperty("qualys_api_url"); + + /** + * Instantiates a new qualys data importer. + */ + public QualysDataImporter() { + apiMap = new HashMap(); + apiMap.put("hostList", + "/api/2.0/fo/asset/host?action=list&use_tags=1&tag_set_by=name&tag_set_include=Cloud%20Agent"); + apiMap.put("listKnowledgebase", + "/api/2.0/fo/knowledge_base/vuln/?action=list&details=All&show_pci_reasons=1&show_supported_modules_info=1"); + apiMap.put("hostAssetSearch", "/qps/rest/2.0/search/am/hostasset"); + apiMap.put("hostassetcount", "/qps/rest/2.0/count/am/hostasset"); + } + + /** + * Call api. + * + * @param uri the uri + * @param httpMethod the http method + * @param xmlToPost the xml to post + * @param parameters the parameters + * @return the string + * @throws ClientProtocolException the client protocol exception + * @throws IOException Signals that an I/O exception has occurred. + */ + @SuppressWarnings("deprecation") + protected static String callApi(String uri, String httpMethod, String xmlToPost, + List parameters) throws ClientProtocolException, IOException { + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + + if ("GET".equals(httpMethod)) { + HttpGet httpGet = new HttpGet(uri); + httpGet.addHeader("content-type", "application/xml"); + httpGet.addHeader("cache-control", "no-cache"); + httpGet.addHeader("Accept", "application/json"); + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS); + httpGet.addHeader(BasicScheme.authenticate(credentials, UTF8, false)); + httpGet.addHeader("X-Requested-With", "DEFAULT_USER"); + HttpResponse httpResponse = httpClient.execute(httpGet); + return EntityUtils.toString(httpResponse.getEntity()); + } else if ("POST".equals(httpMethod)) { + + HttpPost post = new HttpPost(uri); + post.addHeader("content-type", "application/xml"); + post.addHeader("cache-control", "no-cache"); + post.addHeader("Accept", "application/json"); + UsernamePasswordCredentials creds = new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS); + post.addHeader(BasicScheme.authenticate(creds, UTF8, false)); + if (xmlToPost != null) { + HttpEntity entity = new ByteArrayEntity(xmlToPost.getBytes(UTF8)); + post.setEntity(entity); + } + + if (parameters != null) { + post.setEntity(new UrlEncodedFormEntity(parameters)); + } + HttpResponse response = httpClient.execute(post); + return EntityUtils.toString(response.getEntity()); + } else { + throw new UnsupportedOperationException(); + } + } + + /** + * Builds the XML reader. + * + * @param xmlContent the xml content + * @return the XML stream reader + * @throws XMLStreamException the XML stream exception + */ + protected XMLStreamReader buildXMLReader(final String xmlContent) throws XMLStreamException { + final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + final StringReader reader = new StringReader(xmlContent); + return inputFactory.createXMLStreamReader(reader); + } + + /** + * Gets the service response. + * + * @param result the result + * @return the service response + */ + @SuppressWarnings("unchecked") + private Map getServiceResponse(String result) { + Map serviceResponse = new Gson().fromJson(result, new TypeToken>() { + }.getType()); + if (serviceResponse != null) + return (Map) serviceResponse.get("ServiceResponse"); + return null; + } + + /** + * Gets the host data. + * + * @param uriPost the uri post + * @param inputXml the input xml + * @return the host data + */ + @SuppressWarnings("unchecked") + protected List> getHostData(String uriPost, String inputXml) { + String resultJson = null; + int retryCnt = 3; + for (int i = 1; i <= retryCnt; i++) { // Retry 2 times if error occurs + try { + resultJson = callApi(uriPost, "POST", inputXml, null); + } catch (IOException e) { + if (i == retryCnt) { + LOGGER.error("Error in fetching host info: Request :{}", inputXml); + } + } + if (resultJson != null) { + Map resp = getServiceResponse(resultJson); + if (resp != null && "SUCCESS".equals(resp.get("responseCode"))) { + List> data = (List>) resp.get("data"); + if (data != null) { + return data.stream().map(obj -> (Map) obj.get("HostAsset")) + .collect(Collectors.toList()); + } + break; + } else { + if (i == retryCnt) { + LOGGER.error("Error in fetching host info: Request :{}", inputXml); + LOGGER.error("Response : {}", new Gson().toJson(resultJson)); + } + } + } + } + + return null; + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/Util.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/Util.java new file mode 100644 index 000000000..912d1224e --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/jobs/Util.java @@ -0,0 +1,427 @@ +package com.tmobile.cso.pacman.qualys.jobs; + +import java.io.IOException; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.http.ParseException; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.amazonaws.util.CollectionUtils; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import com.tmobile.cso.pacman.qualys.dto.Vuln; +import com.tmobile.cso.pacman.qualys.util.ElasticSearchManager; + + +/** + * The Class Util. + */ +public class Util { + + private static final Logger LOGGER = LoggerFactory.getLogger(Util.class); + private static final String SOURCE = "_source"; + private static final String SCROLL_URI = "/_search/scroll?scroll=2m&scroll_id="; + private static final String LAST_VULN_SCAN = "lastVulnScan"; + + /** + * Process and transform. + * + * @param hostAssets the host assets + * @param vulnInfoMap the vuln info map + * @param discoveryDate the discovery date + */ + public static void processAndTransform(Map> hostAssets, + Map> vulnInfoMap, String discoveryDate) { + if (null != hostAssets && !hostAssets.isEmpty()) { + hostAssets.entrySet().forEach(entry -> { + Map assetMap = entry.getValue(); + appendVulnInfo(assetMap, vulnInfoMap); + flattenAgentVersionInfo(assetMap); + assetMap.put("_docid", entry.getKey()); + assetMap.put("discoverydate", discoveryDate); + assetMap.put("latest", true); + }); + } + } + + /** + * Append vuln info. + * + * @param assetMap the asset map + * @param vulnInfoMap the vuln info map + */ + @SuppressWarnings("unchecked") + public static void appendVulnInfo(Map assetMap, Map> vulnInfoMap) { + Map> vulnMap = (Map>) assetMap.get("vuln"); + if (vulnMap != null) { + List> vulnList = (List>) vulnMap.get("list"); + if (vulnList != null) { + Iterator> it = vulnList.iterator(); + while (it.hasNext()) { + Map vuln = (Map) it.next().get("HostAssetVuln"); + if (vuln != null) { + String qid = String.valueOf(Double.valueOf(vuln.get("qid").toString()).longValue()); + Map vulninfo = vulnInfoMap.get(qid); + if (vulninfo != null) { + vuln.putAll(vulninfo); + vuln.put("qid", qid); + vuln.put("_status", "Open"); + } + } + } + } + } + + } + + /** + * Calculte age in days. + * + * @param firstFound the first found + * @param lastFound the last found + * @return the long + */ + public static long calculteAgeInDays(Object firstFound, Object lastFound) { + if (firstFound != null) { + if (lastFound != null) { + return Duration.between(LocalDateTime.parse(firstFound.toString(), DateTimeFormatter.ISO_DATE_TIME), + LocalDateTime.parse(lastFound.toString(), DateTimeFormatter.ISO_DATE_TIME)).toDays(); + } + return Duration.between(LocalDateTime.parse(firstFound.toString(), DateTimeFormatter.ISO_DATE_TIME), + LocalDateTime.now()).toDays(); + } + return 0; + } + + /** + * Classify vuln. + * + * @param vuln the vuln + * @return the string + */ + public static String classifyVuln(Vuln vuln) { + String classification = "OS"; + String title = vuln.getTitle().toLowerCase(); + String cateogry = vuln.getCategory().toLowerCase(); + + List titlteMatchStrings = Arrays.asList("adobe", "apache", "apple", "cisco", "elasticsearch", + "git server", "google", "openssl", "ibm business process manager", "jetbrains", "mozilla", "notepad", + "opera ", "mysql", "oracle java", "oracle jrockit", "python", "putty", "virtualbox", "rubygems", + "crystal reports", "netweaver", "firefox", "postgresql", "pidgin", "solarwinds", "sourcetree", + "sun java", "sun jdk", "tableau", "tibco", "netbackup", "videolan", "vmware", "winrar", "winscp", + "wireshark", ".net", "sql server", "eol/obsolete", "java"); + List catetoryMatchStrings = Arrays.asList("web server", "database", "web application", "e-commerce", + "cgi", "proxy"); + + if (titlteMatchStrings.parallelStream().anyMatch(title::contains) + || catetoryMatchStrings.parallelStream().anyMatch(cateogry::contains)) + classification = "Application"; + + return classification; + } + + /** + * Find qid status. + * + * @param qid the qid + * @param currentQids the current qids + * @return the string + */ + public static String findQidStatus(String qid, List currentQids) { + return currentQids == null || !currentQids.contains(qid) ? "New" : "Open"; + } + + /** + * Fetch current qid info. + * + * @param type the type + * @return the map + */ + public static Map> fetchCurrentQidInfo(String type) { + + String endPoint = "/aws_" + type + "/vulninfo/_search?scroll=2m&size=10000"; + String payLoad = "{\"_source\":[\"_resourceid\",\"qid\"],\"query\":{\"bool\":{\"must\":[{\"terms\":{\"severitylevel\":[3,4,5]}}]}}}"; + + List> data = new ArrayList<>(); + String scrollId = fetchDataAndScrollId(endPoint, data, payLoad); + do { + endPoint = SCROLL_URI + scrollId; + scrollId = fetchDataAndScrollId(endPoint, data, null); + } while (scrollId != null); + + Map> hostQidMapping = new HashMap<>(); + data.stream().collect(Collectors.groupingBy(obj -> obj.get("_resourceid"))).entrySet().stream() + .forEach(entry -> { + String key = entry.getKey(); + List value = entry.getValue().stream().map(obj -> obj.get("qid")) + .collect(Collectors.toList()); + hostQidMapping.put(key, value); + }); + return hostQidMapping; + } + + /** + * Fetch VP cto nat IP info. + * + * @return the map + */ + public static Map> fetchVPCtoNatIPInfo() { + String endPoint = "/aws_nat/nat/_search?filter_path=hits.hits._source.vpcid,hits.hits.inner_hits.nat_addresses.hits.hits._source.publicip"; + String payLoad = "{\"size\":10000,\"_source\":\"vpcid\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"nat_addresses\",\"query\":{\"match_all\":{}},\"inner_hits\":{\"size\":100,\"_source\":\"publicip\"}}}]}}}{\"size\":10000,\"_source\":\"vpcid\",\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"has_child\":{\"type\":\"nat_addresses\",\"query\":{\"match_all\":{}},\"inner_hits\":{\"size\":100,\"_source\":\"publicip\"}}}]}}}"; + Map> VpcPublicIpInfo = new HashMap<>(); + try { + Response response = ElasticSearchManager.invokeAPI("GET", endPoint, payLoad); + String responseJson = EntityUtils.toString(response.getEntity()); + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get("hits").toString()); + JsonArray jsonArray = hitsJson.getAsJsonObject().get("hits").getAsJsonArray(); + for (int i = 0; i < jsonArray.size(); i++) { + JsonObject obj = (JsonObject) jsonArray.get(i); + String vpcId = obj.get(SOURCE).getAsJsonObject().get("vpcid").getAsString(); + JsonArray innerHits = obj.getAsJsonObject("inner_hits").getAsJsonObject("nat_addresses") + .getAsJsonObject("hits").getAsJsonArray("hits"); + for (int j = 0; j < innerHits.size(); j++) { + String ip = innerHits.get(j).getAsJsonObject().getAsJsonObject(SOURCE).get("publicip") + .getAsString(); + List ipList = VpcPublicIpInfo.get(vpcId); + if (ipList == null) { + ipList = new ArrayList<>(); + VpcPublicIpInfo.put(vpcId, ipList); + } + ipList.add(ip); + } + } + + } catch (Exception e) { + LOGGER.error("Error in fetchVPCtoNatIPInfo",e); + } + return VpcPublicIpInfo; + } + + /** + * Fetch data and scroll id. + * + * @param endPoint the end point + * @param _data the data + * @param payLoad the pay load + * @return the string + */ + private static String fetchDataAndScrollId(String endPoint, List> _data, String payLoad) { + try { + Response response = ElasticSearchManager.invokeAPI("GET", endPoint, payLoad); + String responseJson; + + responseJson = EntityUtils.toString(response.getEntity()); + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + String scrollId = resultJson.get("_scroll_id").getAsString(); + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get("hits").toString()); + JsonArray jsonArray = hitsJson.getAsJsonObject().get("hits").getAsJsonArray(); + if (jsonArray.size() > 0) { + for (int i = 0; i < jsonArray.size(); i++) { + JsonObject obj = (JsonObject) jsonArray.get(i); + JsonObject sourceJson = (JsonObject) obj.get(SOURCE); + if (sourceJson != null) { + Map doc = new Gson().fromJson(sourceJson, new TypeToken>() { + }.getType()); + _data.add(doc); + } + } + return scrollId; + } else { + return null; + } + + } catch (ParseException | IOException e) { + LOGGER.error("Error in fetchDataAndScrollId",e); + } + return null; + } + + /** + * Find latest profile. + * + * @param resp the resp + * @return the map + */ + /* public static Map findLatestProfile(List> resp) { + + List> respData = resp.stream().filter(host -> host.get("vuln") != null) + .filter(Util::isScanInfoAvailable).collect(Collectors.toList()); + if (!CollectionUtils.isNullOrEmpty(respData)) { + respData.sort((obj1, obj2) -> + LocalDateTime.parse(obj2.get(LAST_VULN_SCAN).toString(), DateTimeFormatter.ISO_DATE_TIME) + .compareTo(LocalDateTime.parse(obj1.get(LAST_VULN_SCAN).toString(), + DateTimeFormatter.ISO_DATE_TIME)) + ); + + return respData.get(0); + } + return null; + + }*/ + + /** + * Sort on last vuln scan. + * + * @param resp the resp + * @return the list + */ + public static List> sortOnLastVulnScan(List> resp) { + + List> respData = resp.stream().filter(host -> host.get(LAST_VULN_SCAN) != null) + .collect(Collectors.toList()); + if (!CollectionUtils.isNullOrEmpty(respData)) { + respData.sort((obj1, obj2) -> + LocalDateTime.parse(obj2.get(LAST_VULN_SCAN).toString(), DateTimeFormatter.ISO_DATE_TIME) + .compareTo(LocalDateTime.parse(obj1.get(LAST_VULN_SCAN).toString(), + DateTimeFormatter.ISO_DATE_TIME)) + ); + + } + return respData; + } + + /** + * Fetch ec 2 eni info. + * + * @return the map + */ + public static Map> fetchEc2EniInfo() { + String endPoint = "/aws_ec2/ec2_nwinterfaces/_search?scroll=2m&size=10000"; + String payLoad = "{\"_source\":[\"instanceid\",\"networkinterfaceid\"],\"query\":{\"has_parent\":{\"parent_type\":\"ec2\",\"query\":{\"match\":{\"latest\":\"true\"}}}}}"; + List> data = new ArrayList<>(); + String scrollId = fetchDataAndScrollId(endPoint, data, payLoad); + do { + endPoint = SCROLL_URI + scrollId; + scrollId = fetchDataAndScrollId(endPoint, data, null); + } while (scrollId != null); + + Map> ec2EniMap = new HashMap<>(); + data.stream().collect(Collectors.groupingBy(obj -> obj.get("instanceid"))).entrySet().stream() + .forEach(entry -> { + String key = entry.getKey(); + List value = entry.getValue().stream() + .map(obj -> obj.get("networkinterfaceid").toLowerCase()).collect(Collectors.toList()); + ec2EniMap.put(key, value); + }); + return ec2EniMap; + } + + /** + * Fetch eni mac info. + * + * @return the map + */ + public static Map fetchEniMacInfo() { + String endPoint = "/aws_eni/eni/_search?scroll=2m&size=10000"; + String payLoad = "{\"_source\":[\"_resourceid\",\"macaddress\"],\"query\":{\"match\":{\"latest\":\"true\"}}}"; + List> data = new ArrayList<>(); + String scrollId = fetchDataAndScrollId(endPoint, data, payLoad); + do { + endPoint = SCROLL_URI + scrollId; + scrollId = fetchDataAndScrollId(endPoint, data, null); + } while (scrollId != null); + + return data.stream().collect(Collectors.toMap(info -> info.get("_resourceid").toLowerCase(), + info -> info.get("macaddress").toLowerCase())); + + } + + /** + * Checks if is scan info available. + * + * @param host the host + * @return true, if is scan info available + */ + public static boolean isScanInfoAvailable(Map host,int scanThreshold) { + if (host != null) { + return (host.get(LAST_VULN_SCAN) != null + && LocalDateTime.parse(host.get(LAST_VULN_SCAN).toString(), DateTimeFormatter.ISO_DATE_TIME) + .isAfter(LocalDateTime.now().minusDays(scanThreshold))); + } + return false; + } + + /** + * Fetch trackin method and qids. + * + * @param respData the resp data + * @return the map + */ + public static Map> fetchTrackinMethodAndQids(List> respData) { + + if (respData != null && !respData.isEmpty()) { + return respData.stream() + .collect(Collectors.groupingBy(host -> host.get("trackingMethod").toString(), + Collectors.mapping( + host -> Long.toString(Double.valueOf(host.get("id").toString()).longValue()), + Collectors.toList()))); + } + return new HashMap<>(); + + } + + /** + * Fetch curret qualys info. + * + * @param type the type + * @param resourceId the resource id + * @return the map + * @throws ParseException the parse exception + * @throws IOException Signals that an I/O exception has occurred. + */ + public static Map fetchCurretQualysInfo(String type, String resourceId) + throws IOException { + String endPoint = "/aws_" + type + "/qualysinfo/_search"; + String payLoad = "{\"query\":{\"bool\":{\"must\":[{\"match\":{\"latest\":\"true\"}},{\"match\":{\"_resourceid.keyword\":\"" + + resourceId + "\"}},{\"exists\":{\"field\":\"vuln\"}}]}}}"; + Response response = ElasticSearchManager.invokeAPI("GET", endPoint, payLoad); + String responseJson = EntityUtils.toString(response.getEntity()); + JsonParser jsonParser = new JsonParser(); + JsonObject resultJson = (JsonObject) jsonParser.parse(responseJson); + JsonObject hitsJson = (JsonObject) jsonParser.parse(resultJson.get("hits").toString()); + JsonArray jsonArray = hitsJson.getAsJsonObject().get("hits").getAsJsonArray(); + if (jsonArray.size() > 0) { + JsonObject obj = (JsonObject) jsonArray.get(0); + JsonObject sourceJson = (JsonObject) obj.get(SOURCE); + return new Gson().fromJson(sourceJson, new TypeToken>() { + }.getType()); + + } + return null; + + } + + /** + * + * + * @param assetMap + * + * Convert the manifestVersion in agentInfo to a String to make the qualysinfo ingest working. + * manifestVersion is changed from string to object and es type is created as string + */ + @SuppressWarnings("unchecked") + private static void flattenAgentVersionInfo(Map assetMap) { + Map agentInfo = (Map) assetMap.get("agentInfo"); + if(agentInfo!=null && agentInfo.get("manifestVersion")!=null){ + agentInfo.put("manifestVersion", agentInfo.get("manifestVersion").toString()); + } + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ConfigUtil.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ConfigUtil.java new file mode 100644 index 000000000..ed70554df --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ConfigUtil.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.cso.pacman.qualys.util; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tmobile.cso.pacman.qualys.Constants; + +/** + * The Class ConfigUtil. + */ +public class ConfigUtil { + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigUtil.class); + + /** + * Sets the config properties. + * + * @param configCreds the new config properties + * @throws Exception the exception + */ + public static void setConfigProperties(String configCreds) throws Exception{ + Properties properties = new Properties(); + properties.putAll(System.getProperties()); + properties.putAll(fetchConfigProperties(configCreds)); + System.setProperties(properties); + } + + /** + * Fetch config properties. + * + * @param configCreds the config creds + * @return the map + * @throws Exception the exception + */ + @SuppressWarnings("unchecked") + public static Map fetchConfigProperties(String configCreds) throws Exception { + + Map properties = new HashMap<>(); + + String configUrl = System.getenv("CONFIG_URL"); + ObjectMapper objectMapper = new ObjectMapper(); + try { + Map appProps = new HashMap<>(); + Map batchProps = new HashMap<>(); + Map invProps = new HashMap<>(); + Map response = objectMapper.readValue(HttpUtil.httpGetMethodWithHeaders(configUrl, Util.getHeader(configCreds)), new TypeReference>(){}); + List> propertySources = (List>)response.get("propertySources"); + for(Map propertySource : propertySources) { + if(propertySource.get(Constants.NAME).toString().contains("application")) { + appProps.putAll((Map)propertySource.get(Constants.SOURCE)); + } + if(propertySource.get(Constants.NAME).toString().contains("batch")) { + batchProps.putAll((Map)propertySource.get(Constants.SOURCE)); + } + if(propertySource.get(Constants.NAME).toString().contains("qualys-enricher")) { + invProps.putAll((Map)propertySource.get(Constants.SOURCE)); + } + properties.putAll(appProps); + properties.putAll(batchProps); + properties.putAll(invProps); + } + } catch (Exception e) { + LOGGER.error("Error in fetchConfigProperties",e); + throw e; + } + if(properties.isEmpty()){ + throw new Exception("No config properties fetched from "+configUrl); + } + LOGGER.info("Config are feteched from {}",configUrl); + properties.forEach((k,v)-> LOGGER.debug("{} : {} ",k,v)); + return properties; + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ElasticSearchManager.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ElasticSearchManager.java new file mode 100644 index 000000000..32b6d052f --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ElasticSearchManager.java @@ -0,0 +1,474 @@ +package com.tmobile.cso.pacman.qualys.util; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.ParseException; +import org.apache.http.entity.ContentType; +import org.apache.http.nio.entity.NStringEntity; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.RestClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; + + +/** + * The Class ElasticSearchManager. + */ +public class ElasticSearchManager { + + /** The Constant LOGGER. */ + private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchManager.class); + + /** The Constant ES_HOST_KEY_NAME. */ + private static final String ES_HOST_KEY_NAME = System.getProperty("elastic-search.host"); + + /** The Constant ES_HTTP_PORT. */ + private static final Integer ES_HTTP_PORT = Integer.parseInt(System.getProperty("elastic-search.port")); + + /** The rest client. */ + private static RestClient restClient; + + /** + * Instantiates a new elastic search manager. + */ + private ElasticSearchManager() { + + } + + /** + * Gets the rest client. + * + * @return the rest client + */ + private static RestClient getRestClient() { + if (restClient == null) + restClient = RestClient.builder(new HttpHost(ES_HOST_KEY_NAME, ES_HTTP_PORT)).build(); + return restClient; + + } + + /** + * Creates the index. + * + * @param indexName the index name + */ + public static void createIndex(String index) { + String indexName = "/"+index; + if (!indexExists(indexName)) { + String payLoad = "{\"settings\": { \"index.mapping.ignore_malformed\": true }}"; + try { + invokeAPI("PUT", indexName, payLoad); + } catch (IOException e) { + LOGGER.error("Error createIndex ", e); + } + } + } + + /** + * Creates the type. + * + * @param indexName the index name + * @param typename the typename + */ + public static void createType(String index, String typename) { + String indexName = "/"+index; + if (!typeExists(indexName, typename)) { + String endPoint = indexName + "/_mapping/" + typename; + try { + invokeAPI("PUT", endPoint, "{ \"properties\":{}}"); + } catch (IOException e) { + LOGGER.error("Error in method createType", e); + ; + } + } + } + + /** + * Creates the type as parent. + * + * @param indexName the index name + * @param typename the typename + */ + public static void createTypeAsParent(String indexName, String typename) { + if (!typeExists(indexName, typename)) { + String endPoint = indexName + "/_mapping/" + typename; + try { + invokeAPI("PUT", endPoint, "{ \"properties\":{}, \"issue_" + typename + + "\":{ \"_parent\": { \"type\": \"" + typename + "\" }} }"); + } catch (IOException e) { + LOGGER.error("Error at createTypeAsParent", e); + } + } + } + + /** + * Creates the alias. + * + * @param indexName the index name + * @param aliasName the alias name + */ + public static void createAlias(String indexName, String aliasName) { + try { + invokeAPI("PUT", "/" + indexName + "/_alias/" + aliasName, null); + } catch (IOException e) { + LOGGER.error("Error in createAlias ", e); + } + } + + /** + * Bulk upload. + * + * @param bulkRequest the bulk request + */ + private static void bulkUpload(StringBuilder bulkRequest) { + try { + Response resp = invokeAPI("POST", "/_bulk", bulkRequest.toString()); + String responseStr = EntityUtils.toString(resp.getEntity()); + if (responseStr.contains("\"errors\":true")) { + LOGGER.error(responseStr); + } + } catch (ParseException | IOException e) { + LOGGER.error("Error in uploading data", e); + } + } + + /** + * Upload data. + * + * @param index the index + * @param type the type + * @param docs the docs + * @param idKey the id key + */ + public static void uploadData(String index, String type, List> docs, String idKey) { + String actionTemplate = "{ \"index\" : { \"_index\" : \"%s\", \"_type\" : \"%s\", \"_id\" : \"%s\"} }%n"; + + LOGGER.info("*********UPLOADING*** {}", type); + if (null != docs && !docs.isEmpty()) { + StringBuilder bulkRequest = new StringBuilder(); + int i = 0; + for (Map doc : docs) { + String id = doc.get(idKey).toString(); + StringBuilder _doc = new StringBuilder(createESDoc(doc)); + bulkRequest.append(String.format(actionTemplate, index, type, id)); + bulkRequest.append(_doc + "\n"); + i++; + if (i % 1000 == 0 || bulkRequest.toString().getBytes().length / (1024 * 1024) > 5) { + LOGGER.info("Uploaded {}", i); + bulkUpload(bulkRequest); + bulkRequest = new StringBuilder(); + } + } + if (bulkRequest.length() > 0) { + LOGGER.info("Uploaded {}", i); + bulkUpload(bulkRequest); + } + refresh(index); + } + + } + + /** + * added for uploading Child docs where parent id could be dervied from + * child. + * + * @param index the index + * @param type the type + * @param docs the docs + * @param parentKey the parent key + */ + public static void uploadData(String index, String type, List> docs, String parentKey,String idKey,boolean removeIdKey) { + String actionTemplate = "{ \"index\" : { \"_index\" : \"%s\", \"_type\" : \"%s\", \"_id\" : \"%s\" , \"_parent\" : \"%s\"} }%n"; + + LOGGER.info("*********UPLOADING*** {}", type); + if (null != docs && !docs.isEmpty()) { + StringBuilder bulkRequest = new StringBuilder(); + int i = 0; + for (Map doc : docs) { + + + String parent = doc.get(parentKey).toString(); + String id = doc.get(idKey).toString(); + if(removeIdKey){ + doc.remove(idKey); + } + StringBuilder _doc = new StringBuilder(new Gson().toJson(doc)); + bulkRequest.append(String.format(actionTemplate, index, type,id, parent)); + bulkRequest.append(_doc + "\n"); + i++; + if (i % 1000 == 0 || bulkRequest.toString().getBytes().length / (1024 * 1024) > 5) { + LOGGER.info("Uploading {}", i); + bulkUpload(bulkRequest); + bulkRequest = new StringBuilder(); + } + } + if (bulkRequest.length() > 0) { + LOGGER.info("Uploaded {}", i); + bulkUpload(bulkRequest); + } + refresh(index); + } + } + + /** + * Refresh. + * + * @param index the index + */ + public static void refresh(String index) { + String indexName = "/"+index; + try { + Response refrehsResponse = invokeAPI("POST", indexName + "/" + "_refresh", null); + if (refrehsResponse != null && HttpStatus.SC_OK != refrehsResponse.getStatusLine().getStatusCode()) { + LOGGER.error("Refreshing index {} failed", index, refrehsResponse); + } + } catch (IOException e) { + LOGGER.error("Error refresh ", e); + } + + } + + /** + * Creates the ES doc. + * + * @param doc the doc + * @return the string + */ + public static String createESDoc(Map doc) { + return new Gson().toJson(doc); + } + + /** + * Invoke API. + * + * @param method the method + * @param endpoint the endpoint + * @param payLoad the pay load + * @return the response + * @throws IOException Signals that an I/O exception has occurred. + */ + public static Response invokeAPI(String method, String endpoint, String payLoad) throws IOException { + HttpEntity entity = null; + if (payLoad != null) + entity = new NStringEntity(payLoad, ContentType.APPLICATION_JSON); + return getRestClient().performRequest(method, endpoint, Collections.emptyMap(), entity); + } + + /** + * Index exists. + * + * @param indexName the index name + * @return true, if successful + */ + private static boolean indexExists(String indexName) { + + try { + Response response = invokeAPI("HEAD", indexName, null); + if (response != null) { + return response.getStatusLine().getStatusCode() == 200 ? true : false; + } + } catch (IOException e) { + LOGGER.error("Error indexExists ", e); + } + + return false; + } + + /** + * Type exists. + * + * @param indexName the index name + * @param type the type + * @return true, if successful + */ + private static boolean typeExists(String indexName, String type) { + + try { + Response response = invokeAPI("HEAD", indexName + "/_mapping/" + type, null); + if (response != null) { + return response.getStatusLine().getStatusCode() == 200 ? true : false; + } + } catch (IOException e) { + LOGGER.error("Error typeExists ", e); + } + + return false; + } + + /** + * Gets the type count. + * + * @param indexName the index name + * @param type the type + * @return the type count + */ + private static int getTypeCount(String indexName, String type) { + + try { + Response response = invokeAPI("GET", indexName + "/" + type + "/_count?filter_path=count", null); + String rspJson = EntityUtils.toString(response.getEntity()); + return new ObjectMapper().readTree(rspJson).at("/count").asInt(); + } catch (IOException e) { + LOGGER.error("Error getTypeCount ", e); + } + return 0; + } + + /** + * Creates the type. + * + * @param index the index + * @param type the type + * @param parent the parent + */ + public static void createType(String index, String type, String parent) { + String indexName = "/"+index; + if (!typeExists(indexName, type)) { + String endPoint = indexName + "/_mapping/" + type; + String payLoad = "{\"_parent\": { \"type\": \"" + parent + "\" } }"; + try { + invokeAPI("PUT", endPoint, payLoad); + } catch (IOException e) { + LOGGER.error("Error createType ", e); + } + } + } + + /** + * Gets the existing info. + * + * @param indexName the index name + * @param type the type + * @param filters the filters + * @param latest the latest + * @return the existing info + */ + public static Map> getExistingInfo(String index, String type, List filters, + boolean latest) { + String indexName = "/"+index; + int count = getTypeCount(indexName, type); + int _count = count; + boolean scroll = false; + int SCROLL_SIZE = 10000; + if (count > SCROLL_SIZE) { + _count = SCROLL_SIZE; + scroll = true; + } + + String keyField = filters.get(0); + String filter_path = "&filter_path=hits.hits._source,_scroll_id"; + + StringBuilder payLoad = new StringBuilder("{ \"_source\": ["); + for (String _filter : filters) { + payLoad.append("\"" + _filter + "\","); + } + payLoad.deleteCharAt(payLoad.length() - 1); + if (latest) + payLoad.append("],\"query\": { \"match\": {\"latest\": true}}}"); + else + payLoad.append("]}"); + + String endPoint = indexName + "/" + type + "/_search?scroll=1m" + filter_path + "&size=" + _count; + + Map> _data = new HashMap<>(); + String scrollId = fetchDataAndScrollId(endPoint, _data, keyField, payLoad.toString()); + + if (scroll) { + count -= SCROLL_SIZE; + do { + endPoint = "/_search/scroll?scroll=1m&scroll_id=" + scrollId + filter_path; + scrollId = fetchDataAndScrollId(endPoint, _data, keyField, null); + count -= SCROLL_SIZE; + if (count < 0) + scroll = false; + } while (scroll); + } + // invokeAPI("DELETE", "/_search/scroll?scroll_id="+scrollId, null); + return _data; + } + + /** + * Fetch data and scroll id. + * + * @param endPoint the end point + * @param _data the data + * @param keyField the key field + * @param payLoad the pay load + * @return the string + */ + private static String fetchDataAndScrollId(String endPoint, Map> _data, String keyField, + String payLoad) { + try { + ObjectMapper objMapper = new ObjectMapper(); + Response response = invokeAPI("GET", endPoint, payLoad); + String responseJson = EntityUtils.toString(response.getEntity()); + JsonNode _info = objMapper.readTree(responseJson).at("/hits/hits"); + String scrollId = objMapper.readTree(responseJson).at("/_scroll_id").textValue(); + Iterator it = _info.elements(); + while (it.hasNext()) { + String doc = it.next().fields().next().getValue().toString(); + Map docMap = new ObjectMapper().readValue(doc, + new TypeReference>() { + }); + _data.put(docMap.get(keyField), docMap); + docMap.remove(keyField); + } + return scrollId; + } catch (ParseException | IOException e) { + LOGGER.error("Error fetchDataAndScrollId ", e); + } + return ""; + + } + + /** + * Update latest status. + * + * @param index the index + * @param type the type + * @param discoveryDate the discovery date + */ + public static void updateLatestStatus(String index, String type, String discoveryDate) { + String indexName = "/"+index; + String updateJson = "{\"script\":{\"inline\": \"ctx._source.latest=false\"},\"query\": {\"bool\": {\"must\": [{ \"match\": {\"latest\":true}}], \"must_not\": [{\"match\": {\"discoverydate.keyword\":\"" + + discoveryDate + "\"}}]}}}"; + try { + invokeAPI("POST", indexName + "/" + type + "/" + "_update_by_query", updateJson); + } catch (IOException e) { + LOGGER.error("Error updateLatestStatus ", e); + } + } + + /** + * Delete old documents. + * + * @param index the index + * @param type the type + * @param field the field + * @param value the value + */ + public static void deleteOldDocuments(String index, String type, String field, String value) { + String indexName = "/"+index; + String deleteJson = "{\"query\": {\"bool\": {\"must_not\": [{ \"match\": {\"" + field + "\":\"" + value + + "\"}}]}}}"; + try { + invokeAPI("POST", indexName + "/" + type + "/" + "_delete_by_query", deleteJson); + } catch (IOException e) { + LOGGER.error("Error deleteOldDocuments ", e); + } + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ErrorManageUtil.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ErrorManageUtil.java new file mode 100644 index 000000000..e95fc9750 --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/ErrorManageUtil.java @@ -0,0 +1,53 @@ +package com.tmobile.cso.pacman.qualys.util; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.tmobile.cso.pacman.qualys.Constants; + + + +public class ErrorManageUtil implements Constants{ + + private ErrorManageUtil() { + + } + + public static Map formErrorCode(List> errorList) { + Map errorCode = new HashMap<>(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + errorCode.put("endTime", sdf.format(new Date())); + + String status = ""; + + List> errors = new ArrayList<>(); + if(!errorList.isEmpty()) { + for(Map errorDetail :errorList) { + Map error = new HashMap<>(); + error.put(ERROR, errorDetail.get(ERROR)); + + List> details = new ArrayList<>(); + Map detail = new HashMap<>(); + detail.put(EXCEPTION,errorDetail.get(EXCEPTION)); + details.add(detail); + error.put("details",details); + errors.add(error); + + if(!FAILED.equalsIgnoreCase(status)) { + status = (FATAL.equalsIgnoreCase(errorDetail.get(ERROR_TYPE))) ? FAILED:"Partial Success"; + } + } + } + else { + status = "success"; + } + + errorCode.put("errors", errors); + errorCode.put("status", status); + return errorCode; + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/HttpUtil.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/HttpUtil.java new file mode 100644 index 000000000..79fba54a7 --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/HttpUtil.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package com.tmobile.cso.pacman.qualys.util; + +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.TrustStrategy; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Strings; +import com.tmobile.cso.pacman.qualys.exception.UnAuthorisedException; + + +/** + * The Class HttpUtil. + */ +public class HttpUtil { + + /** The log. */ + static final Logger LOGGER = LoggerFactory.getLogger(HttpUtil.class); + + /** + * Instantiates a new http util. + */ + private HttpUtil(){ + } + + /** + * Gets the. + * + * @param uri the uri + * @param bearerToken the bearer token + * @return the string + * @throws Exception the exception + */ + public static String get(String uri ,String bearerToken) throws Exception { + HttpGet httpGet = new HttpGet(uri); + httpGet.addHeader("content-type", "application/json"); + httpGet.addHeader("cache-control", "no-cache"); + if(!Strings.isNullOrEmpty(bearerToken)){ + httpGet.addHeader("Authorization", "Bearer "+bearerToken); + } + CloseableHttpClient httpClient = getHttpClient(); + if(httpClient!=null){ + HttpResponse httpResponse; + try { + + httpResponse = httpClient.execute(httpGet); + if( httpResponse.getStatusLine().getStatusCode()==HttpStatus.SC_UNAUTHORIZED){ + throw new UnAuthorisedException(); + } + return EntityUtils.toString(httpResponse.getEntity()); + } catch (Exception e) { + LOGGER.error("Error getting the data " , e); + throw e; + } + } + return "{}"; + } + + /** + * Post. + * + * @param url the url + * @param requestBody the request body + * @param token the token + * @param tokeType the toke type + * @return the string + * @throws Exception the exception + */ + public static String post(String url, String requestBody,String token,String tokeType) throws Exception { + try { + CloseableHttpClient httpClient = getHttpClient(); + if(httpClient!=null){ + HttpPost httppost = new HttpPost(url); + httppost.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString()); + if(!Strings.isNullOrEmpty(token)){ + httppost.addHeader("Authorization", tokeType+" "+token); + } + httppost.setEntity(new StringEntity(requestBody)); + HttpResponse httpresponse = httpClient.execute(httppost); + if( httpresponse.getStatusLine().getStatusCode()==HttpStatus.SC_UNAUTHORIZED){ + throw new UnAuthorisedException(); + } + return EntityUtils.toString(httpresponse.getEntity()); + } + } catch (Exception e) { + LOGGER.error("Error getting the data " , e); + throw e; + } + return null; + + } + + /** + * Gets the http client. + * + * @return the http client + */ + private static CloseableHttpClient getHttpClient() { + CloseableHttpClient httpClient = null; + try { + httpClient = HttpClientBuilder.create().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + return true; + } + }).build()).build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + LOGGER.error("Error getting getHttpClient " , e); + } + return httpClient; + } + + /** + * Http get method with headers. + * + * @param url the url + * @param headers the headers + * @return the string + * @throws Exception the exception + */ + public static String httpGetMethodWithHeaders(String url,Map headers) throws Exception { + String json = null; + + HttpGet get = new HttpGet(url); + CloseableHttpClient httpClient = null; + if (headers != null && !headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + get.setHeader(entry.getKey(), entry.getValue().toString()); + } + } + try { + httpClient = getHttpClient(); + CloseableHttpResponse res = httpClient.execute(get); + if (res.getStatusLine().getStatusCode() == 200) { + json = EntityUtils.toString(res.getEntity()); + } + } finally { + if (httpClient != null) { + httpClient.close(); + } + } + return json; + } +} diff --git a/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/Util.java b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/Util.java new file mode 100644 index 000000000..94a7717bd --- /dev/null +++ b/jobs/pacman-qualys-enricher/src/main/java/com/tmobile/cso/pacman/qualys/util/Util.java @@ -0,0 +1,48 @@ +package com.tmobile.cso.pacman.qualys.util; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.entity.ContentType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.io.BaseEncoding; + + +/** + * The Class Util. + */ +public class Util { + + private static final Logger LOGGER = LoggerFactory.getLogger(Util.class); + + /** + * Base 64 decode. + * + * @param encodedStr the encoded str + * @return the string + */ + public static String base64Decode(String encodedStr) { + try { + return new String(BaseEncoding.base64().decode(encodedStr), "UTF-8"); + } catch (UnsupportedEncodingException e) { + LOGGER.error("Error in base64Decode",e); + return ""; + } + } + + /** + * Gets the header. + * + * @param base64Creds the base 64 creds + * @return the header + */ + public static Map getHeader(String base64Creds){ + Map authToken = new HashMap<>(); + authToken.put("Content-Type", ContentType.APPLICATION_JSON.toString()); + authToken.put("Authorization", "Basic "+base64Creds); + return authToken; + } +} diff --git a/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/autofix/elasticip/UnusedElasticIPAutofix.java b/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/autofix/elasticip/UnusedElasticIPAutofix.java new file mode 100644 index 000000000..19f1f8bdd --- /dev/null +++ b/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/autofix/elasticip/UnusedElasticIPAutofix.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +/** + Author :Kanchana + Modified Date: 12th September, 2019 + +**/ +package com.tmobile.pacman.autofix.elasticip; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.amazonaws.services.ec2.AmazonEC2; +import com.amazonaws.services.ec2.model.ReleaseAddressRequest; +import com.amazonaws.util.StringUtils; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.tmobile.pacman.common.PacmanSdkConstants; +import com.tmobile.pacman.common.exception.AutoFixException; +import com.tmobile.pacman.commons.autofix.BaseFix; +import com.tmobile.pacman.commons.autofix.FixResult; +import com.tmobile.pacman.commons.autofix.PacmanFix; +import com.tmobile.pacman.dto.AutoFixTransaction; +import com.tmobile.pacman.util.CommonUtils; + +/** + * UnusedElasticIPAutofix class executes fix by releasing unused elastic ip by + * allocation-id. + */ +@PacmanFix(key = "unused-elastic-ip-fix", desc = "Auto fixes by releasing the unused elastic ip") +public class UnusedElasticIPAutofix extends BaseFix { + private static final String ELASTICIPDETAILS = "elasticIPDetails"; + private static final Integer AUTOFIX_DEFAULT_INTERVAL = 72; + private static final Logger LOGGER = LoggerFactory.getLogger(UnusedElasticIPAutofix.class); + private static final String ELASTIC_IP_ALLOCATION_ID_RELEASED = "The Elastic ip with allocation id [{}] [{}] released"; + private static final String ELASTIC_IP_ALLOCATION_ID_RELEASE_FAILED = "The Elastic ip with allocation id [{}] [{}] release failed [{}]"; + + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + private static final String ISSUE_CREATION_TIME_ELAPSED = "pacman.autofix.issue.creation.time.elapsed"; + + /* + * (non-Javadoc) + * + * @see com.tmobile.pacman.commons.autofix.BaseFix#executeFix(java.util.Map, + * java.util.Map, java.util.Map) + */ + @Override + public FixResult executeFix(Map issue, Map clientMap, + Map ruleParams) { + + try { + AmazonEC2 amazonEC2 = (AmazonEC2) clientMap.get(PacmanSdkConstants.CLIENT); + + ReleaseAddressRequest request = new ReleaseAddressRequest().withAllocationId(issue.get(PacmanSdkConstants.ALLOCATION_ID)); + amazonEC2.releaseAddress(request); + if (LOGGER.isDebugEnabled()) + LOGGER.debug(String.format(ELASTIC_IP_ALLOCATION_ID_RELEASED, issue.get(PacmanSdkConstants.RESOURCE_ID), + issue.get(PacmanSdkConstants.ALLOCATION_ID))); + return new FixResult(PacmanSdkConstants.STATUS_SUCCESS_CODE, + String.format(ELASTIC_IP_ALLOCATION_ID_RELEASED, issue.get(PacmanSdkConstants.RESOURCE_ID), + issue.get(PacmanSdkConstants.ALLOCATION_ID))); + } catch (Exception e) { + LOGGER.error(String.format(ELASTIC_IP_ALLOCATION_ID_RELEASE_FAILED, + issue.get(PacmanSdkConstants.RESOURCE_ID), issue.get(PacmanSdkConstants.ALLOCATION_ID)), e.getMessage()); + return new FixResult(PacmanSdkConstants.STATUS_FAILURE_CODE, + String.format(ELASTIC_IP_ALLOCATION_ID_RELEASE_FAILED, issue.get(PacmanSdkConstants.RESOURCE_ID), + issue.get(PacmanSdkConstants.ALLOCATION_ID), e.getMessage())); + } + + } + + /* + * (non-Javadoc) + * + * @see + * com.tmobile.pacman.commons.autofix.BaseFix#backupExistingConfigForResource( + * java.lang.String, java.lang.String, java.util.Map, java.util.Map) + */ + @Override + public boolean backupExistingConfigForResource(final String resourceId, final String resourceType, + Map clientMap, Map ruleParams, Map issue) + throws AutoFixException { + + Gson gson = new GsonBuilder().create(); + return backupOldConfig(resourceId, ELASTICIPDETAILS, gson.toJson(issue)); + } + + @Override + public boolean isFixCandidate(String resourceId, String resourceType, Map clientMap, + Map ruleParams, Map issue) throws AutoFixException { + int hours = AUTOFIX_DEFAULT_INTERVAL;// Default + try { + hours = Integer.parseInt(CommonUtils + .getPropValue(ISSUE_CREATION_TIME_ELAPSED + "." + ruleParams.get(PacmanSdkConstants.RULE_ID))); + } catch (Exception e) { + LOGGER.error("Exception retrieving autofix configuration[{}]", e.getMessage()); + } + return isCreateDateDaysOld(issue.get("createdDate"), hours); + } + + static boolean isCreateDateDaysOld(String createDate, int hours) { + + LocalDateTime firstActionTime = LocalDateTime.parse(createDate, DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)); + LocalDateTime currentTime = LocalDateTime.now(); + long elapsedHours = ChronoUnit.HOURS.between(firstActionTime, currentTime); + + return elapsedHours > hours; + } + + /* (non-Javadoc) + * @see com.tmobile.pacman.commons.autofix.BaseFix#addDetailsToTransactionLog() + */ + @Override + public AutoFixTransaction addDetailsToTransactionLog(Map annotation) { + LinkedHashMap transactionParams = new LinkedHashMap(); + if(!StringUtils.isNullOrEmpty(annotation.get("_resourceid"))){ + transactionParams.put("resourceId", annotation.get("_resourceid")); + }else{ + transactionParams.put("resourceId","No Data"); + } + if(!StringUtils.isNullOrEmpty(annotation.get("accountid"))){ + transactionParams.put("accountId", annotation.get("accountid")); + }else{ + transactionParams.put("accountId", "No Data"); + } + + if(!StringUtils.isNullOrEmpty(annotation.get("region"))){ + transactionParams.put("region", annotation.get("region")); + }else{ + transactionParams.put("region", "No Data"); + } + + if(!StringUtils.isNullOrEmpty(annotation.get("allocationId"))){ + transactionParams.put("allocationId", annotation.get(PacmanSdkConstants.ALLOCATION_ID)); + }else{ + transactionParams.put("allocationId", "No Data"); + } + return new AutoFixTransaction(null,transactionParams); + } +} diff --git a/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/autofix/s3/S3GlobalAccessAutoFix.java b/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/autofix/s3/S3GlobalAccessAutoFix.java index 973b0cc65..77814ea60 100644 --- a/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/autofix/s3/S3GlobalAccessAutoFix.java +++ b/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/autofix/s3/S3GlobalAccessAutoFix.java @@ -28,6 +28,8 @@ import com.amazonaws.services.s3.model.AmazonS3Exception; import com.amazonaws.services.s3.model.BucketPolicy; import com.amazonaws.services.s3.model.Grant; +import com.amazonaws.services.s3.model.PublicAccessBlockConfiguration; +import com.amazonaws.services.s3.model.SetPublicAccessBlockRequest; import com.amazonaws.util.CollectionUtils; import com.google.common.base.Strings; import com.google.gson.Gson; @@ -63,10 +65,16 @@ public FixResult executeFix(Map issue, Map clien AmazonS3Client awsS3Client = null; awsS3Client = (AmazonS3Client) clientMap.get(PacmanSdkConstants.CLIENT); String s3BucketName = issue.get(PacmanSdkConstants.RESOURCE_ID); - LOGGER.info("revoking all ACL permissions"); - revokeACLPublicPermission(awsS3Client, s3BucketName); - LOGGER.info("revking all Bucket Policy"); - revokePublicBucketPolicy(awsS3Client, s3BucketName); + try{ + LOGGER.info("block all public permissions"); + blockAllPublicAcces(awsS3Client, s3BucketName); + }catch(Exception e){ + LOGGER.debug("Error while blocking all public permissions {} ",e); + LOGGER.info("revoking all ACL permissions"); + revokeACLPublicPermission(awsS3Client, s3BucketName); + LOGGER.info("revking all Bucket Policy"); + revokePublicBucketPolicy(awsS3Client, s3BucketName); + } return new FixResult(PacmanSdkConstants.STATUS_SUCCESS_CODE, "the s3 bucket is now fixed"); } @@ -142,4 +150,19 @@ private void revokePublicBucketPolicy(AmazonS3Client awsS3Client, String s3Bucke awsS3Client.deleteBucketPolicy(s3BucketName); } } + + private void blockAllPublicAcces(AmazonS3Client awsS3Client, String s3BucketName) { + Boolean globalFlag = Boolean.parseBoolean(PacmanSdkConstants.BOOLEAN_TRUE); + + PublicAccessBlockConfiguration accessBlockConfiguration = new PublicAccessBlockConfiguration(); + accessBlockConfiguration.setBlockPublicAcls(globalFlag); + accessBlockConfiguration.setBlockPublicPolicy(globalFlag); + accessBlockConfiguration.setIgnorePublicAcls(globalFlag); + accessBlockConfiguration.setRestrictPublicBuckets(globalFlag); + SetPublicAccessBlockRequest setPublicAccessBlockRequest = new SetPublicAccessBlockRequest(); + setPublicAccessBlockRequest.setBucketName(s3BucketName); + setPublicAccessBlockRequest.setPublicAccessBlockConfiguration(accessBlockConfiguration); + + awsS3Client.setPublicAccessBlock(setPublicAccessBlockRequest); + } } diff --git a/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/common/PacmanSdkConstants.java b/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/common/PacmanSdkConstants.java index 678e94f86..bfb75d8b3 100644 --- a/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/common/PacmanSdkConstants.java +++ b/jobs/pacman-rule-engine-2.0/src/main/java/com/tmobile/pacman/common/PacmanSdkConstants.java @@ -605,5 +605,11 @@ public interface PacmanSdkConstants extends com.tmobile.pacman.commons.PacmanSdk /** *. */ String PACBOT_CREATED_SG_DESC = "PacBot created SG During Autofix"; + + /** ALLOCATIONID KEY. */ + String ALLOCATION_ID = "allocationid"; + + /** The boolean true. */ + String BOOLEAN_TRUE = "true"; } diff --git a/jobs/pom.xml b/jobs/pom.xml index 6ef454280..af114c155 100644 --- a/jobs/pom.xml +++ b/jobs/pom.xml @@ -47,6 +47,7 @@ pacman-rule-engine-2.0 pacman-cloud-notifications recommendation-enricher + pacman-qualys-enricher diff --git a/webapp/src/app/core/services/domain-mapping.service.ts b/webapp/src/app/core/services/domain-mapping.service.ts index ccbff4f89..665d3dd14 100644 --- a/webapp/src/app/core/services/domain-mapping.service.ts +++ b/webapp/src/app/core/services/domain-mapping.service.ts @@ -18,6 +18,7 @@ import { COMPLIANCE_ROUTES, TOOLS_ROUTES, ADMIN_ROUTES, OMNISEARCH_ROUTES } from import { ASSETS_ROUTES } from '../../shared/constants/routes'; import { DataCacheService } from './data-cache.service'; import * as _ from 'lodash'; +import { CONFIGURATIONS } from '../../../config/configurations'; @Injectable() export class DomainMappingService { @@ -50,10 +51,14 @@ export class DomainMappingService { domains.forEach((domain) => { const domainObj = this.getDomainInfoForSelectedDomain(domain); const dashboardsObj = this.getDashboardsPathForADomain(domainObj.dashboards, moduleName); - ListOfDashboards = ListOfDashboards.concat(dashboardsObj.dashboards); }); + // check qualys enabled or not + if (!CONFIGURATIONS.optional.general.qualysEnabled) { + ListOfDashboards = ListOfDashboards.filter(item => !(item.name === 'Vulnerabilities' && item.route === 'vulnerabilities-compliance')); + } + let updatedListOfLinks = ListOfDashboards.map(dashboard => { // Get title from routes data diff --git a/webapp/src/app/pacman-features/modules/admin/create-rule/create-rule.component.html b/webapp/src/app/pacman-features/modules/admin/create-rule/create-rule.component.html index 9a27d84fe..c2eae82f1 100644 --- a/webapp/src/app/pacman-features/modules/admin/create-rule/create-rule.component.html +++ b/webapp/src/app/pacman-features/modules/admin/create-rule/create-rule.component.html @@ -232,7 +232,7 @@

{{pageTitle}}

- + @@ -476,4 +476,4 @@

{{pageTitle}}

- \ No newline at end of file + diff --git a/webapp/src/app/pacman-features/modules/admin/update-rule/update-rule.component.html b/webapp/src/app/pacman-features/modules/admin/update-rule/update-rule.component.html index 03c9851c1..d82062b97 100644 --- a/webapp/src/app/pacman-features/modules/admin/update-rule/update-rule.component.html +++ b/webapp/src/app/pacman-features/modules/admin/update-rule/update-rule.component.html @@ -206,7 +206,7 @@

{{pageTitle}}

- + diff --git a/webapp/src/app/pacman-features/modules/compliance/compliance.module.ts b/webapp/src/app/pacman-features/modules/compliance/compliance.module.ts index 55aa2c938..c00c029b3 100644 --- a/webapp/src/app/pacman-features/modules/compliance/compliance.module.ts +++ b/webapp/src/app/pacman-features/modules/compliance/compliance.module.ts @@ -91,13 +91,11 @@ import { PatchingSnapshotComponent } from './../../secondary-components/patching import { PatchingProjectionsComponent } from './patching-projections/patching-projections.component'; import { VulnerabilitySummaryTableComponent } from './../../secondary-components/vulnerability-summary-table/vulnerability-summary-table.component'; import { AgGridModule } from 'ag-grid-angular/main'; -import { VulnerabilitySummaryDistributionComponent } from './../../secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component'; import { DigitalDevDashboardComponent } from './digital-dev-dashboard/digital-dev-dashboard.component'; import { PullRequestLineMetricsComponent } from './../../secondary-components/pull-request-line-metrics/pull-request-line-metrics.component'; import { DigitalApplicationDistributionComponent } from './../../secondary-components/digital-application-distribution/digital-application-distribution.component'; import { DigitalDevStrategyDistributionComponent } from './../../secondary-components/digital-dev-strategy-distribution/digital-dev-strategy-distribution.component'; import { VulnerabilityAgingGraphComponent } from './../../secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component'; -import { VulnerabilityAgingDistributionSummaryComponent } from './../../secondary-components/vulnerability-aging-distribution-summary/vulnerability-aging-distribution-summary.component'; import { DevStandardPullRequestAgeComponent } from './../../secondary-components/dev-standard-pull-request-age/dev-standard-pull-request-age.component'; import { DevStandardStaleBranchAgeComponent } from './../../secondary-components/dev-standard-stale-branch-age/dev-standard-stale-branch-age.component'; import { DevStandardTotalStaleBranchesComponent } from './../../secondary-components/dev-standard-total-stale-branches/dev-standard-total-stale-branches.component'; @@ -112,6 +110,7 @@ import { IssueListingService } from '../../services/issue-listing.service'; import { RecommendationsComponent} from '../../modules/compliance/recommendations/recommendations.component'; import { RecommandCategoryComponent } from '../../secondary-components/recommand-category/recommand-category.component'; import { RecommendationsDetailsComponent } from './recommendations-details/recommendations-details.component'; +import { OverallVulnerabilitiesComponent } from './../../secondary-components/overall-vulnerabilities/overall-vulnerabilities.component'; @NgModule({ imports: [ @@ -123,8 +122,6 @@ import { RecommendationsDetailsComponent } from './recommendations-details/recom PatchingSnapshotComponent, PatchingSponsorComponent, VulnerabilitySummaryTableComponent, - VulnerabilitySummaryDistributionComponent, - VulnerabilityAgingDistributionSummaryComponent, DevPullRequestApplicationsComponent, DevStaleBranchApplicationsComponent ]) @@ -202,12 +199,10 @@ import { RecommendationsDetailsComponent } from './recommendations-details/recom PatchingProjectionsComponent, PatchingSponsorComponent, VulnerabilitySummaryTableComponent, - VulnerabilitySummaryDistributionComponent, DigitalDevDashboardComponent, DigitalApplicationDistributionComponent, DigitalDevStrategyDistributionComponent, VulnerabilityAgingGraphComponent, - VulnerabilityAgingDistributionSummaryComponent, DevStandardPullRequestAgeComponent, DevStandardStaleBranchAgeComponent, DevStandardTotalStaleBranchesComponent, @@ -219,7 +214,8 @@ import { RecommendationsDetailsComponent } from './recommendations-details/recom PolicyViolationsListComponent, RecommendationsComponent, RecommandCategoryComponent, - RecommendationsDetailsComponent + RecommendationsDetailsComponent, + OverallVulnerabilitiesComponent ], providers: [ SelectComplianceDropdown, diff --git a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.css b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.css index d5ef252dd..160f4c600 100644 --- a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.css +++ b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.css @@ -28,11 +28,7 @@ .arrow-img:hover{ transform: rotate(180deg) translateX(20%); } - -.vulnerabilities-wrapper /deep/ .data-table-wrap .table-cells:nth-child(1) { - width: 330px; +.dashboards-header { + padding: 1em 1.8em 2em; + flex-shrink: 0; } - -.vulnerabilities-wrapper /deep/ .data-table-wrap .table-cells { - width: 120px; -} \ No newline at end of file diff --git a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.html b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.html index 9b1d9f753..49adfe509 100644 --- a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.html +++ b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.html @@ -14,11 +14,10 @@
- -
+ +
- -

{{pageTitle}}

+
@@ -37,21 +36,11 @@

{{pageTitle}}

-
  • -
    - -
    -
  • -
  • -
    - -
    -
  • diff --git a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.ts b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.ts index 7ddb94388..e89f71ec7 100644 --- a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.ts +++ b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities-compliance/vulnerabilities-compliance.component.ts @@ -3,9 +3,9 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); You may not use * this file except in compliance with the License. A copy of the License is located at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * or in the "license" file accompanying this file. This file is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or * implied. See the License for the specific language governing permissions and @@ -21,7 +21,7 @@ import { } from '@angular/core'; import { AssetGroupObservableService } from '../../../../core/services/asset-group-observable.service'; import { SelectComplianceDropdown } from './../../../services/select-compliance-dropdown.service'; -import { Subscription } from 'rxjs/Subscription'; +import { Subscription } from 'rxjs'; import { environment } from './../../../../../environments/environment'; import { Router } from '@angular/router'; import { IssueFilterService } from './../../../services/issue-filter.service'; @@ -56,7 +56,6 @@ export class VulnerabilitiesComplianceComponent implements OnInit, OnDestroy { searchDropdownData: any = {}; selectedDD = ''; currentObj: any = {}; - filterArr: any = []; subscriptionToAssetGroup: Subscription; selectedAssetGroup: string; selectedComplianceDropdown: any; @@ -66,8 +65,6 @@ export class VulnerabilitiesComplianceComponent implements OnInit, OnDestroy { filterTagOptions = []; filterTagLabels = []; filters = []; - public pageLevel = 0; - public backButtonRequired; private filterTypesSubscription: Subscription; constructor( @@ -82,9 +79,6 @@ export class VulnerabilitiesComplianceComponent implements OnInit, OnDestroy { this.subscriptionToAssetGroup = this.assetGroupObservableService .getAssetGroup() .subscribe(assetGroupName => { - this.backButtonRequired = this.workflowService.checkIfFlowExistsCurrently( - this.pageLevel - ); this.selectedAssetGroup = assetGroupName; this.deleteFilters(); this.getFilters(); @@ -122,7 +116,7 @@ export class VulnerabilitiesComplianceComponent implements OnInit, OnDestroy { changeFilterType(value) { this.currentFilterType = _.find(this.filterTypeOptions, { - optionName: value.value + optionName: value.id }); this.filterTypesSubscription = this.issueFilterService .getFilters( @@ -142,7 +136,7 @@ export class VulnerabilitiesComplianceComponent implements OnInit, OnDestroy { changeFilterTags(value) { if (this.currentFilterType) { - const filterTag = _.find(this.filterTagOptions, { name: value.value }); + const filterTag = _.find(this.filterTagOptions, { name: value.id }); this.utils.addOrReplaceElement( this.filters, { @@ -161,14 +155,13 @@ export class VulnerabilitiesComplianceComponent implements OnInit, OnDestroy { this.selectComplianceDropdown.updateCompliance( this.utils.arrayToObject(this.filters, 'filterkey', 'value') ); + this.filterTagOptions = []; + this.filterTagLabels = []; + this.currentFilterType = null; } this.utils.clickClearDropdown(); } - navigateBack() { - this.workflowService.goBackToLastOpenedPageAndUpdateLevel(this.router.routerState.snapshot.root); - } - deleteFilters(event?) { try { if (!event) { diff --git a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.css b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.css index 43d126bfa..562d82a11 100644 --- a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.css +++ b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.css @@ -32,14 +32,13 @@ .widget-wrapper { min-height: 17em; position: relative; -} - -.issue-listing-wrapper /deep/ .data-table-wrap .table-cells:nth-child(1) { - width: 320px; } -.issue-listing-wrapper /deep/ .data-table-wrap .table-cells { - width: 130px; +.h-100 { + height:100%; +} +.w-100 { + width:100%; } /* css for edge browser */ @@ -47,4 +46,4 @@ .floating-widgets-container { overflow: auto; } -} +} diff --git a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.html b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.html index ce459f3ca..a933bc9b1 100644 --- a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.html +++ b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.html @@ -13,32 +13,28 @@ -->
    - -
    +
    + +
    +
    - -

    {{pageTitle}}

    + +
    -
    - -
    - +
    -
    -
    -
      -
    • -
      - +
      +
      +
        +
      • +
        +
      • diff --git a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.ts b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.ts index f93bbe15f..a789168fa 100644 --- a/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.ts +++ b/webapp/src/app/pacman-features/modules/compliance/vulnerabilities/vulnerabilities.component.ts @@ -3,9 +3,9 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); You may not use * this file except in compliance with the License. A copy of the License is located at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * or in the "license" file accompanying this file. This file is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or * implied. See the License for the specific language governing permissions and @@ -26,7 +26,6 @@ import { LoggerService } from '../../../../shared/services/logger.service'; import { ErrorHandlingService } from '../../../../shared/services/error-handling.service'; import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/pairwise'; -import { ToastObservableService } from '../../../../post-login-app/common/services/toast-observable.service'; import { DownloadService } from '../../../../shared/services/download.service'; import { RefactorFieldsService } from './../../../../shared/services/refactor-fields.service'; import { WorkflowService } from '../../../../core/services/workflow.service'; @@ -44,7 +43,7 @@ import { RouterUtilityService } from '../../../../shared/services/router-utility ] }) export class VulnerabilitiesComponent implements OnInit, OnDestroy { - pageTitle = 'All Vulnerabilities'; + pageTitle = 'Vulnerabilities'; issueListingdata: any; selectedAssetGroup: string; breadcrumbArray: any = ['Compliance']; @@ -65,12 +64,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { showLoader = true; paginatorSize = 25; searchTxt = ''; - popRows: any = ['Download Data']; - filterTypeOptions: any = []; - filterTagOptions: any = []; - currentFilterType; - filterTypeLabels = []; - filterTagLabels = []; + popRows: any = ['Vulnerability list', 'Vulnerability list with asset details']; dataTableData: any = []; tableDataLoaded = false; filters: any = []; @@ -82,8 +76,9 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { public labels: any; FullQueryParams: any; queryParamsWithoutFilter: any; - private previousUrl: any = ''; urlToRedirect: any = ''; + backButtonRequired; + pageLevel = 0; private assetGroupSubscription: Subscription; private routeSubscription: Subscription; @@ -91,8 +86,6 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { private issueListingSubscription: Subscription; private issueFilterSubscription: Subscription; private downloadSubscription: Subscription; - public pageLevel = 0; - public backButtonRequired; constructor( private assetGroupObservableService: AssetGroupObservableService, @@ -106,18 +99,16 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { private logger: LoggerService, private errorHandling: ErrorHandlingService, private downloadService: DownloadService, - private toastObservableService: ToastObservableService, private refactorFieldsService: RefactorFieldsService, private routerUtilityService: RouterUtilityService ) { this.assetGroupSubscription = this.assetGroupObservableService .getAssetGroup() .subscribe(assetGroupName => { + this.selectedAssetGroup = assetGroupName; this.backButtonRequired = this.workflowService.checkIfFlowExistsCurrently( this.pageLevel ); - this.selectedAssetGroup = assetGroupName; - this.getFilters(); this.routerParam(); this.deleteFilters(); this.getFilterArray(); @@ -125,6 +116,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { }); } + ngOnInit() { this.breadcrumbPresent = 'All Vulnerabilities'; } @@ -160,6 +152,13 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { } } + updatePaginator(event) { + if (event !== this.paginatorSize) { + this.paginatorSize = event; + this.updateComponent(); + } + } + deleteFilters(event?) { try { if (!event) { @@ -198,7 +197,6 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { } catch (error) { this.logger.log('error', error); } - /* TODO: Aditya: Why are we not calling any updateCompliance function in observable to update the filters */ } /* @@ -222,7 +220,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { // add By trinanjan const formattedFilters = dataArray.map(function(data) { data.name = - refactoredService.getDisplayNameForAKey(data.name) || data.name; + refactoredService.getDisplayNameForAKey(data.name.toLowerCase()) || data.name; return data; }); @@ -264,14 +262,6 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { this.getData(); } - navigateBack() { - try { - this.workflowService.goBackToLastOpenedPageAndUpdateLevel(this.router.routerState.snapshot.root); - } catch (error) { - this.logger.log('error', error); - } - } - getData() { try { if (this.issueListingSubscription) { @@ -319,7 +309,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { if (this.lastPaginator > this.totalRows) { this.lastPaginator = this.totalRows; } - const updatedResponse = this.massageData(this.issueListingdata); + const updatedResponse = this.utils.massageTableData(this.issueListingdata); this.currentBucket[this.bucketNumber] = updatedResponse; this.processData(updatedResponse); } @@ -347,27 +337,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { this.logger.log('error', error); } } - massageData(data) { - /* - * added by Trinanjan 14/02/2017 - * the funciton replaces keys of the table header data to a readable format - */ - const refactoredService = this.refactorFieldsService; - const newData = []; - data.map(function(responseData) { - const KeysTobeChanged = Object.keys(responseData); - let newObj = {}; - KeysTobeChanged.forEach(element => { - const elementnew = - refactoredService.getDisplayNameForAKey( - element.toLocaleLowerCase() - ) || element; - newObj = Object.assign(newObj, { [elementnew]: responseData[element] }); - }); - newData.push(newObj); - }); - return newData; - } + processData(data) { try { let innerArr = {}; @@ -388,7 +358,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { if (getCols[col].toLowerCase() === 'title' || getCols[col].toLowerCase() === 'qid') { cellObj = { - link: 'true', + link: 'View Vulnerability Details', properties: { color: '', 'text-shadow': '0.1px 0' @@ -468,7 +438,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { } else if ( getCols[col].toLowerCase() === 'assets affected' || getCols[col].toLowerCase() === 'assetsaffected') { cellObj = { - link: 'true', + link: 'View Asset List', properties: { color: '', 'text-decoration': 'underline #383C4D' @@ -493,7 +463,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { colName: getCols[col], hasPreImg: false, imgLink: '', - text: this.calculateDate(getData[row][getCols[col]]), + text: this.utils.calculateDate(getData[row][getCols[col]]), valText: new Date(getData[row][getCols[col]]).getTime() }; } else { @@ -526,6 +496,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { } goToDetails(row) { + console.log(row); try { const apiTarget = { TypeAsset: 'vulnerable' }; this.workflowService.addRouterSnapshotToLevel(this.router.routerState.snapshot.root); @@ -536,15 +507,17 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { let newParams = this.utils.makeFilterObj(eachParams); newParams = Object.assign(newParams, apiTarget); newParams['mandatory'] = 'qid'; - this.router.navigate(['../../', 'assets', 'asset-list'], { + this.router.navigate(['../../../assets', 'asset-list'], + { relativeTo: this.activatedRoute, queryParams: newParams, queryParamsHandling: 'merge' }); } else if (row.col.toLowerCase() === 'qid' || row.col.toLowerCase() === 'title') { - this.router.navigate(['./vulnerability-details', row.row.qid.valText ], { + this.router.navigate(['../../vulnerabilities/vulnerability-details', row.row.qid.valText ], { relativeTo: this.activatedRoute, - queryParams: this.queryParamsWithoutFilter + queryParams: this.queryParamsWithoutFilter, + queryParamsHandling: 'merge' }); } } catch (error) { @@ -553,29 +526,6 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { } } - calculateDate(_JSDate) { - if (!_JSDate) { - return 'No Data'; - } - const date = new Date(_JSDate); - const year = date.getFullYear().toString(); - const month = date.getMonth() + 1; - let monthString; - if (month < 10) { - monthString = '0' + month.toString(); - } else { - monthString = month.toString(); - } - const day = date.getDate(); - let dayString; - if (day < 10) { - dayString = '0' + day.toString(); - } else { - dayString = day.toString(); - } - return monthString + '-' + dayString + '-' + year; - } - searchCalled(search) { this.searchTxt = search; } @@ -620,24 +570,33 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { this.getData(); } - handlePopClick(rowText) { + vulnerabilitiesCSV(serviceName) { const fileType = 'csv'; + let downloadCsvName; + let downloadSize = 0; try { let queryParams; queryParams = { fileFormat: 'csv', - serviceId: 6, fileType: fileType }; + if (serviceName === 'Vulnerability list') { + queryParams.serviceId = 6; + downloadCsvName = 'All Vulnerabilities'; + downloadSize = this.totalRows; + } else if (serviceName === 'Vulnerability list with asset details') { + queryParams.serviceId = 19; + downloadCsvName = 'All Vulnerabilities with Details'; + } const downloadRequest = { ag: this.selectedAssetGroup, filter: this.filterText, from: 0, searchtext: this.searchTxt, - size: this.totalRows + size: downloadSize }; const downloadUrl = environment.download.url; @@ -648,7 +607,7 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { downloadUrl, downloadMethod, downloadRequest, - 'All Vulnerabilities', + downloadCsvName, this.totalRows ); } catch (error) { @@ -656,78 +615,10 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { } } - /** - * This function get calls the keyword service before initializing - * the filter array ,so that filter keynames are changed - */ - - getFilters() { - try { - this.issueFilterSubscription = this.issueFilterService - .getFilters( - { filterId: 2 }, - environment.issueFilter.url, - environment.issueFilter.method - ) - .subscribe(response => { - this.filterTypeLabels = _.map(response[0].response, 'optionName'); - this.filterTypeOptions = response[0].response; - }); - } catch (error) { - this.errorMessage = this.errorHandling.handleJavascriptError(error); - this.logger.log('error', error); - } - } - - changeFilterType(value) { - try { - this.currentFilterType = _.find(this.filterTypeOptions, { - optionName: value.value - }); - this.issueFilterSubscription = this.issueFilterService - .getFilters( - { - ag: this.selectedAssetGroup - }, - environment.base + - this.utils.getParamsFromUrlSnippet(this.currentFilterType.optionURL) - .url, - 'GET' - ) - .subscribe(response => { - this.filterTagOptions = response[0].response; - this.filterTagLabels = _.map(response[0].response, 'name'); - }); - } catch (error) { - this.errorMessage = this.errorHandling.handleJavascriptError(error); - this.logger.log('error', error); - } - } - - changeFilterTags(value) { - try { - if (this.currentFilterType) { - const filterTag = _.find(this.filterTagOptions, { name: value.value }); - this.utils.addOrReplaceElement( - this.filters, - { - key: this.currentFilterType.optionName, - value: filterTag['id'], - filterkey: this.currentFilterType.optionValue.trim(), - compareKey : this.currentFilterType.optionValue.toLowerCase().trim() - }, - el => { - return el.compareKey === this.currentFilterType.optionValue.toLowerCase().trim(); - } - ); - } - this.getUpdatedUrl(); - this.utils.clickClearDropdown(); - this.updateComponent(); - } catch (error) { - this.errorMessage = this.errorHandling.handleJavascriptError(error); - this.logger.log('error', error); - } + updateUrlWithNewFilters(filterArr) { + this.filters = filterArr; + this.getUpdatedUrl(); + this.updateComponent(); } getUpdatedUrl() { @@ -759,6 +650,15 @@ export class VulnerabilitiesComponent implements OnInit, OnDestroy { this.filterText = this.utils.processFilterObj(this.filterText); } + navigateBack() { + try { + this.workflowService.goBackToLastOpenedPageAndUpdateLevel(this.router.routerState.snapshot.root); + } catch (error) { + this.logger.log('error', error); + } + } + + ngOnDestroy() { try { // pushes the current url to datastore diff --git a/webapp/src/app/pacman-features/modules/compliance/vulnerability-details/vulnerability-details.component.css b/webapp/src/app/pacman-features/modules/compliance/vulnerability-details/vulnerability-details.component.css index d78e73503..00487e906 100644 --- a/webapp/src/app/pacman-features/modules/compliance/vulnerability-details/vulnerability-details.component.css +++ b/webapp/src/app/pacman-features/modules/compliance/vulnerability-details/vulnerability-details.component.css @@ -18,6 +18,7 @@ } .vul-details-wrapper { border-radius: 3px; + height:100%; } .tabs-container { diff --git a/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.html b/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.html index cffc48132..eab84ab10 100644 --- a/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.html +++ b/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.html @@ -22,7 +22,7 @@
        overall
      -
      +
      {{instance[1].title}}
      diff --git a/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.ts b/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.ts index b7a0cae12..377ecb3c3 100644 --- a/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.ts +++ b/webapp/src/app/pacman-features/secondary-components/multi-band-donut/multi-band-donut.component.ts @@ -42,12 +42,16 @@ export class MultiBandDonutComponent implements OnInit, OnChanges { private width: number; private height: number; private radius: number; - + private arc: any; private pie: any; private color: any; - private g: any; + + private outerRadiusLimit = 54; + private innerRadiusLimit = 66; + textTransformVal = 0; + radiusDelta = 14; constructor() {} @@ -92,9 +96,18 @@ export class MultiBandDonutComponent implements OnInit, OnChanges { } private initSvg(indx: any) { - + const dataDelta = this.donutData.length>5 ? this.donutData.length - 5 : 0; + this.radiusDelta = 14; // Reset to 14 everytime calling this function. + if(dataDelta) { + this.radiusDelta = dataDelta<4 ? this.radiusDelta-dataDelta-1 : this.radiusDelta-dataDelta-2; + if(dataDelta === 4) { + this.textTransformVal = -3; + } + } else { + this.textTransformVal = (( this.donutData.length - 5 ) * 14 - 3 ) + } this.svg = d3.select('#overallComplianceSvg'); - + const svgContainer = document.getElementsByClassName('complaince-graph-container'); if (document.getElementById('overallComplianceSvg') != null ) { @@ -104,15 +117,22 @@ export class MultiBandDonutComponent implements OnInit, OnChanges { this.width = +this.svg.attr('width'); this.height = +this.svg.attr('height'); - this.radius = ( Math.min(this.height, this.width) / 2.1 ) + 14 * indx ; + + this.radius = ( Math.min(this.height, this.width) / 2.1 ) + this.radiusDelta * indx ; this.color = d3Scale.scaleOrdinal() .range([ this.colorTransData[indx % 5], this.colorData[indx % 5], 'transparent']); if (this.donutData.length > 1) { + if(dataDelta) { + const arcRadiusDelta = 12 - (2*dataDelta) + const innerStart = 48 + arcRadiusDelta; + this.outerRadiusLimit = 48 + (arcRadiusDelta*dataDelta); + this.innerRadiusLimit = innerStart + (arcRadiusDelta*dataDelta); + } this.arc = d3Shape.arc() - .outerRadius(this.radius - 54) - .innerRadius(this.radius - 66); + .outerRadius(this.radius - this.outerRadiusLimit) + .innerRadius(this.radius - this.innerRadiusLimit); } else { this.arc = d3Shape.arc() .outerRadius(this.radius - 34) diff --git a/webapp/src/app/pacman-features/secondary-components/multiline-brush-zoom/multiline-brush-zoom.component.ts b/webapp/src/app/pacman-features/secondary-components/multiline-brush-zoom/multiline-brush-zoom.component.ts index dce49f1f8..3ade74395 100644 --- a/webapp/src/app/pacman-features/secondary-components/multiline-brush-zoom/multiline-brush-zoom.component.ts +++ b/webapp/src/app/pacman-features/secondary-components/multiline-brush-zoom/multiline-brush-zoom.component.ts @@ -3,9 +3,9 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); You may not use * this file except in compliance with the License. A copy of the License is located at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * or in the "license" file accompanying this file. This file is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or * implied. See the License for the specific language governing permissions and @@ -21,9 +21,10 @@ import { ViewChild, ElementRef, OnChanges, - SimpleChanges + SimpleChanges, + HostListener } from '@angular/core'; -import { AutorefreshService } from '../../services/autorefresh.service'; +// import { AutorefreshService } from './pacman-features/services/autorefresh.service'; import * as d3 from 'd3-selection'; import * as d3Shape from 'd3-shape'; import * as d3Scale from 'd3-scale'; @@ -38,7 +39,6 @@ import { LoggerService } from '../../../shared/services/logger.service'; selector: 'app-multiline-brush-zoom', templateUrl: './multiline-brush-zoom.component.html', styleUrls: ['./multiline-brush-zoom.component.css'], - providers: [AutorefreshService] }) export class MultilineBrushZoomComponent implements OnInit, OnChanges { @@ -68,23 +68,27 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { private lineColorsObject = { // Colors for different type lines - total: '#3F4A59', // Dark blue(shade) - overall: '#3F4A59', // Dark blue(shade) - tagging: '#00B946', // Green - security: '#00B946', // Green - Compliance: '#00B946', // Green - patching: '#00569D', // Dark blue(shade) - 'other policies': '#F2425F', // Rose Red - certificate: '#289CF7', // Sky Blue - governance: '#289CF7', // Sky Blue - vulnerability: '#645EC5', // Purple - high: '#F75C03', // Orange - low: '#FFE00D', // Green - medium: '#FFB00D', // Sky blue - critical: '#D40325', // Red - extra1: '#00b946', // Green - noncompliant: '#D40325', // Red - compliant: '#00B946' // Green + 'total': '#3F4A59', // Dark blue(shade) + 'overall': '#3F4A59', // Dark blue(shade) + 'tagging': '#f2425f', // Red + 'security': '#00569d', // Blue + 'Compliance': '#00B946', // Green + 'patching': '#00569D', // Dark blue(shade) + 'other policies': '#F2425F', // Red + 'costOptimization': '#289cf7', // Light Blue + 'certificate': '#289CF7', // Sky Blue + 'governance': '#26ba9d', // Green + 'vulnerability': '#645EC5', // Purple + 'high': '#F75C03', // Orange + 'low': '#FFE00D', // Green + 'medium': '#FFB00D', // Sky blue + 'critical': '#D40325', // Red + 'extra1': '#00b946', // Green + 'noncompliant': '#D40325', // Red + 'compliant': '#00B946', // Green + 'pullrequest': '#f2425f', // Red + 'repository': '#3f4a59', // Dark Blue, + 'noOfAlerts': '#3F4A59' // Dark Blue }; private lineColorsArray = Object.keys(this.lineColorsObject); private countInRange: any; @@ -119,9 +123,7 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { private brush: any; private brush2: any; private zoom: any; - private area2: any; private focus: any; - private areaAxis: any; // Main graph highlighted area start and end points private highlightAreaStart: any; @@ -138,16 +140,17 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { private yLogAxis = false; - private rendered = false; private legendHover: any = []; private searchAnObjectFromArray: any; - private legendsvalue: any = []; - private lineColorsObjectLegends: any = []; private bisectDate: any; private firstMouseMove = 0; constructor(private loggerService: LoggerService) {} + @HostListener('window:resize', ['$event']) onSizeChanges() { + this.init(); + } + plotGraph() { try { this.removeZeroValues(); @@ -157,8 +160,8 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { this.computeLowerAndHigherLines(); this.formatDataForArea(); } - this.drawAxisAndGrid(); - this.drawLine(); + this.drawAxisAndGrid(); + this.drawLine(); if (this.hoverActive && this.data.length > 1) { this.drawHover(); } @@ -179,6 +182,7 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { } private removeInvalidValues() { + this.graphLinesData.forEach(line => { if (line.key === 'compliance_percent') { line.key = 'Compliance'; @@ -503,7 +507,6 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { 'transform', 'translate(0,' + (2 * this.margin.top + this.height2 + 40) + ')' ); - this.context = this.svg .append('g') .attr('class', 'context') @@ -1331,7 +1334,7 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { private drawHover() { const self = this; - let numOfLines; + const numOfLines = this.graphLinesData.length - 1; this.legendHover = this.graphLinesData.map((eachLine) => { return eachLine.values; @@ -1345,7 +1348,6 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { return obj; }; - this.margin.left = this.margin.left + 20; this.bisectDate = d3Array.bisector(d => d[`date`]).left; if (this.firstMouseMove > 0) { @@ -1375,7 +1377,6 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { .attr('x', -5) .attr('dy', '1.5em'); - numOfLines = this.graphLinesData.length - 1; for (let i = 0; i < self.graphLinesData.length; i++) { self.focus .append('rect') @@ -1436,7 +1437,6 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { .attr('y1', 0) .attr('y2', this.height); } - this.svg .append('rect') .attr('transform', 'translate(' + 0 + ',' + (this.margin.left - 10) + ')') @@ -1455,7 +1455,6 @@ export class MultilineBrushZoomComponent implements OnInit, OnChanges { self.focus.selectAll('.hover').style('display', 'none'); }) .on('mousemove', mousemove); - function mousemove() { try { self.firstMouseMove++; diff --git a/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.css b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.css new file mode 100644 index 000000000..8c0525769 --- /dev/null +++ b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.css @@ -0,0 +1,107 @@ + /* + *Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); You may not use + * this file except in compliance with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or + * implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +.overall-vuln-wrap { + min-height: 21em; + padding: 1em; +} + +.sub-head { + padding: 0.6em 0.5em 0.7em 1em; + background-color: #dce3e9; + font-size: 1em; + color: #3f4a59; +} + +.vuln-top-section { + background: #fff; + border-radius: 3em; + border: 1px solid #e2e2e2; + padding: 1em 0.5em; + flex-flow: wrap; +} + +.each-wrap { + padding: 0 1em; + justify-content: space-between; + flex-grow: 1; +} + +.num-wrap { + padding-right: 0.5em; +} + +.compliant-percent { + font-size: 2em; + font-family: ex2-light; +} + +.percent-sym { + font-size: 1.2em; + padding-bottom: 1px; + font-family: ex2-light; +} + +.compliant-txt { + font-size: 0.92em; + color: #6b6b6b; + line-height: 1.2; + padding: 0.1em 0; + text-align: right; +} + +.green-txt { + color: #00B946; +} + +.red-txt { + color: #D40325; +} + +.italics { + font-style: italic; +} + +.vuln-link { + border-bottom: 1px solid #d40325; + cursor: pointer; + transition: 0.2s ease; +} + +.vuln-link:hover { + color: #ed0274; + border-bottom: 1px solid #ed0274; + letter-spacing: 0.4px; + text-shadow: 0.1px 0; +} + +.links-wrapper { + flex-flow: wrap; + justify-content: center; + line-height: 1.4; + font-size: 0.92em; +} + +.link-separators { + padding: 0 4px; +} + +.active-link { + color: #ed0274; + text-shadow: 0.2px 0; +} + +#vulnSummaryPie /deep/ .graph-outer-container { + display: inline-block; +} \ No newline at end of file diff --git a/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.html b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.html new file mode 100644 index 000000000..39b47c19d --- /dev/null +++ b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.html @@ -0,0 +1,53 @@ + + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      +
      {{vulnData.compliantpercent}}
      +
      %
      +
      +
      Compliant
      +
      +
      +
      +
      {{vulnData.vulnerabilities | number}}
      +
      +
      +
      Vulnerabilities
      +
      (Across {{vulnData.hosts | number}} Hosts)
      +
      +
      +
      +
      +
      + +
      + +
      +
      diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.spec.ts b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.spec.ts similarity index 66% rename from webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.spec.ts rename to webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.spec.ts index 8b9f73d15..fdc885f6d 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.spec.ts +++ b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.spec.ts @@ -1,11 +1,11 @@ -/* + /* *Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); You may not use * this file except in compliance with the License. A copy of the License is located at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * or in the "license" file accompanying this file. This file is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or * implied. See the License for the specific language governing permissions and @@ -14,21 +14,21 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { VulnerabilitySummaryDistributionComponent } from './vulnerability-summary-distribution.component'; +import { OverallVulnerabilitiesComponent } from './overall-vulnerabilities.component'; -describe('VulnerabilitySummaryDistributionComponent', () => { - let component: VulnerabilitySummaryDistributionComponent; - let fixture: ComponentFixture; +describe('OverallVulnerabilitiesComponent', () => { + let component: OverallVulnerabilitiesComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ VulnerabilitySummaryDistributionComponent ] + declarations: [ OverallVulnerabilitiesComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(VulnerabilitySummaryDistributionComponent); + fixture = TestBed.createComponent(OverallVulnerabilitiesComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.ts b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.ts new file mode 100644 index 000000000..c0c9a29bb --- /dev/null +++ b/webapp/src/app/pacman-features/secondary-components/overall-vulnerabilities/overall-vulnerabilities.component.ts @@ -0,0 +1,305 @@ + /* + *Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); You may not use + * this file except in compliance with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or + * implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subscription } from 'rxjs/Subscription'; +import { AssetGroupObservableService } from '../../../core/services/asset-group-observable.service'; +import { AutorefreshService } from '../../services/autorefresh.service'; +import { environment } from './../../../../environments/environment'; +import { Router, ActivatedRoute } from '@angular/router'; +import { LoggerService } from '../../../shared/services/logger.service'; +import { UtilsService } from '../../../shared/services/utils.service'; +import { WorkflowService } from '../../../core/services/workflow.service'; +import { CommonResponseService } from '../../../shared/services/common-response.service'; + +@Component({ + selector: 'app-overall-vulnerabilities', + templateUrl: './overall-vulnerabilities.component.html', + styleUrls: ['./overall-vulnerabilities.component.css'], + providers: [AutorefreshService] +}) +export class OverallVulnerabilitiesComponent implements OnInit, OnDestroy { + + subscriptionToAssetGroup: Subscription; + dataSubscription: Subscription; + selectedAssetGroup; + durationParams; + autoRefresh; + autorefreshInterval; + errorVal = 0; + errorMessage = 'apiResponseError'; + urlToRedirect; + routeTo = 'vulnerabilities'; + vulnData; + donutData = {}; + widgetWidth = 210; + widgetHeight = 250; + innerRadius: any = 0; + selectedLink = 0; + outerRadius: any = 50; + errorSumVal = 0; + cntInterval; + selectedLevel = 0; + lastLevelData; + lastLevelSelectedKeys; + modifiedResponse; + selectedGraph = 'total'; + colorsData = { + inscope: '#00B946', + exempted: '#BA808A', + S3: '#ffe003', + S4: '#f75c03', + S5: '#da0c0c', + compliant: '#00B946', + noncompliant: '#E60127', + scanned: '#00B946', + unscanned: '#BA808A' + }; + donutObj; + linksData = [{name: 'Total', level: 0, key: 'total'}, {name: 'Inscope', level: 1, key: 'inscope'}, {name: 'Scanned', level: 2, key: 'scanned'}, {name: 'Non Compliant', level: 3, key: 'noncompliant'}, {name: 'Compliant', level: 3, key: 'compliant'}]; + + constructor(private commonResponseService: CommonResponseService, + private assetGroupObservableService: AssetGroupObservableService, + private autorefreshService: AutorefreshService, + private logger: LoggerService, + private router: Router, + private utils: UtilsService, + private activatedRoute: ActivatedRoute, + private workflowService: WorkflowService) { + this.subscriptionToAssetGroup = this.assetGroupObservableService.getAssetGroup().subscribe( + assetGroupName => { + this.selectedAssetGroup = assetGroupName; + this.updateComponent(); + }); + this.durationParams = this.autorefreshService.getDuration(); + this.durationParams = parseInt(this.durationParams, 10); + this.autoRefresh = this.autorefreshService.autoRefresh; + } + + ngOnInit() { + this.urlToRedirect = this.router.routerState.snapshot.url; + const afterLoad = this; + if (this.autoRefresh !== undefined) { + if ((this.autoRefresh === true ) || (this.autoRefresh.toString() === 'true')) { + this.autorefreshInterval = setInterval(function() { + afterLoad.getData(); + }, this.durationParams); + } + } + } + + navigatePage() { + try { + this.workflowService.addRouterSnapshotToLevel(this.router.routerState.snapshot.root); + const eachParams = {}; + const newParams = this.utils.makeFilterObj(eachParams); + if (this.routeTo !== undefined ) { + this.router.navigate(['../vulnerabilities-compliance', this.routeTo], { relativeTo: this.activatedRoute, queryParams: newParams, queryParamsHandling: 'merge'}); + } + } catch (error) { + this.logger.log('error', error); + } + } + + updateComponent() { + this.errorVal = 0; + this.errorSumVal = 0; + this.selectedLink = 0; + this.selectedGraph = 'total'; + this.donutData = {}; + this.selectedLevel = 0; + if (this.cntInterval) { + clearInterval(this.cntInterval); + } + this.getData(); + } + + clearLinkInterval() { + if (this.cntInterval) { + clearInterval(this.cntInterval); + } + this.widgetWidth = 210 - this.linksData[this.selectedLink].level * 10; + this.selectedLevel = this.linksData[this.selectedLink].level; + this.selectedGraph = this.linksData[this.selectedLink].key; + } + + getData() { + this.getSummaryData(); + this.getGraphData(); + } + + getSummaryData() { + if (this.dataSubscription) { + this.dataSubscription.unsubscribe(); + } + const queryParams = { + 'ag': this.selectedAssetGroup + }; + const vulnerabilitySummaryUrl = environment.vulnerabilitySummary.url; + const vulnerabilitySummaryMethod = environment.vulnerabilitySummary.method; + + this.dataSubscription = this.commonResponseService.getData(vulnerabilitySummaryUrl, vulnerabilitySummaryMethod, {}, queryParams).subscribe( + response => { + try { + if (!response.distribution) { + this.errorSumVal = -1; + this.errorMessage = 'noDataAvailable'; + this.logger.log('error', 'noDataAvailable'); + } else { + this.errorSumVal = 1; + this.vulnData = response.distribution; + } + } catch (error) { + this.errorMessage = 'jsError'; + this.logger.log('error', error); + this.errorSumVal = -1; + } + }, + error => { + this.errorMessage = 'apiResponseError'; + this.logger.log('error', error); + this.errorSumVal = -1; + }); + } + + getGraphData() { + const queryParams = { + 'ag': this.selectedAssetGroup + }; + const vulnerabilitySummaryUrl = environment.vulnerabilityGraphSummary.url; + const vulnerabilitySummaryMethod = environment.vulnerabilityGraphSummary.method; + + this.commonResponseService.getData(vulnerabilitySummaryUrl, vulnerabilitySummaryMethod, {}, queryParams).subscribe( + response => { + try { + if (!response.count && response.count !== 0 && response.count !== '0') { + this.errorVal = -1; + this.errorMessage = 'noDataAvailable'; + this.logger.log('error', 'noDataAvailable'); + } else { + this.createObjectForVulSummary(response); + const self = this; + this.cntInterval = setInterval(function(){ + if (self.selectedLink < self.linksData.length - 1) { + self.selectedLink++; + } else { + self.selectedLink = 0; + } + self.widgetWidth = 210 - self.linksData[self.selectedLink].level * 10; + self.selectedLevel = self.linksData[self.selectedLink].level; + self.selectedGraph = self.linksData[self.selectedLink].key; + }, 7000); + this.errorVal = 1; + } + } catch (error) { + this.errorMessage = 'jsError'; + this.logger.log('error', error); + this.errorVal = -1; + } + }, + error => { + this.errorMessage = 'apiResponseError'; + this.logger.log('error', error); + this.errorVal = -1; + }); + } + + createObjectForVulSummary(apiResponse) { + this.lastLevelSelectedKeys = []; + this.lastLevelData = {}; + this.donutData = {}; + this.modifiedResponse = this.processGraphData(apiResponse, null, this.donutData); + } + + processGraphData(data, parent, donutData) { + this.donutObj = {}; + if (data) { + const currentData = JSON.parse(JSON.stringify(data)); + const currentObj = Object.keys(currentData); + this.donutObj = { + 'color': [], + 'data': [], 'legendWithText': [], + 'legendTextcolor': '#000', + 'legend': '', + 'totalCount': 0, + 'centerText': 'Total', + 'link': false, + 'styling': { + 'cursor': 'pointer' + }, + 'cursor': [] + }; + const selectedKeys = []; + for (let i = 0; i < currentObj.length; i++) { + if (currentObj[i].toLowerCase() !== 'total' && currentObj[i].toLowerCase() !== 'count') { + this.donutObj['legendWithText'].push(currentObj[i]); + this.donutObj['color'].push(this.colorsData[currentObj[i]]); + this.donutObj['data'].push(currentData[currentObj[i]].count); + this.donutObj['totalCount'] += currentData[currentObj[i]].count; + if (currentObj[i].toLowerCase() === 'inscope' || currentObj[i].toLowerCase() === 'scanned' || currentObj[i].toLowerCase() === 'compliant' || currentObj[i].toLowerCase() === 'noncompliant' ) { + this.donutObj['cursor'].push('pointer'); + } else { + this.donutObj['cursor'].push('default'); + } + if (Object.keys(currentData[currentObj[i]]).length > 1) { + selectedKeys.push(currentObj[i]); + } + } + } + if (parent) { + donutData[parent] = this.donutObj; + } else { + donutData['total'] = this.donutObj; + } + for (let j = selectedKeys.length - 1; j >= 0; j--) { + if (j === selectedKeys.length - 1) { + this.lastLevelData = currentData; + this.lastLevelSelectedKeys = selectedKeys; + } + const pop = this.lastLevelSelectedKeys[j]; + this.processGraphData(this.lastLevelData[pop], pop, donutData); + } + } + return donutData; + } + + pieClicked(data) { + const type = data.legend; + if (type === 'inscope' || type === 'scanned' || type === 'noncompliant' || type === 'compliant') { + if (this.cntInterval) { + clearInterval(this.cntInterval); + } + this.selectedGraph = type; + for (let i = 0; i < this.linksData.length; i++ ) { + if (this.selectedGraph === this.linksData[i].key) { + this.selectedLink = i; + break; + } + this.widgetWidth = 210 - this.linksData[this.selectedLink].level * 10; + this.selectedLevel = this.linksData[this.selectedLink].level; + } + } + + } + + ngOnDestroy() { + this.subscriptionToAssetGroup.unsubscribe(); + if (this.dataSubscription) { + this.dataSubscription.unsubscribe(); + } + clearInterval(this.autorefreshInterval); + clearInterval(this.cntInterval); + } + +} diff --git a/webapp/src/app/pacman-features/secondary-components/pacman-issues/pacman-issues.component.html b/webapp/src/app/pacman-features/secondary-components/pacman-issues/pacman-issues.component.html index 4d964ddfd..2c35a53b7 100644 --- a/webapp/src/app/pacman-features/secondary-components/pacman-issues/pacman-issues.component.html +++ b/webapp/src/app/pacman-features/secondary-components/pacman-issues/pacman-issues.component.html @@ -41,9 +41,9 @@
    -
    -
    -
    +
    +
    +
    diff --git a/webapp/src/app/pacman-features/secondary-components/total-tag-compliance/total-tag-compliance.component.css b/webapp/src/app/pacman-features/secondary-components/total-tag-compliance/total-tag-compliance.component.css index c9e2c8cca..5cbad3052 100644 --- a/webapp/src/app/pacman-features/secondary-components/total-tag-compliance/total-tag-compliance.component.css +++ b/webapp/src/app/pacman-features/secondary-components/total-tag-compliance/total-tag-compliance.component.css @@ -49,14 +49,10 @@ app-multi-band-donut { .tag-compliance-details { width: 100%; - height: 18em; + min-height: 18em; overflow-y: hidden; } -.tag-compliance-details:hover { - overflow-y: auto; overflow-y: overlay; -} - .tag-compliance-details app-list-table { width: 100%; display: block; diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerabilities-compliance-trend/vulnerabilities-compliance-trend.component.ts b/webapp/src/app/pacman-features/secondary-components/vulnerabilities-compliance-trend/vulnerabilities-compliance-trend.component.ts index 844626fad..0a7ecbdec 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerabilities-compliance-trend/vulnerabilities-compliance-trend.component.ts +++ b/webapp/src/app/pacman-features/secondary-components/vulnerabilities-compliance-trend/vulnerabilities-compliance-trend.component.ts @@ -47,8 +47,8 @@ export class VulnerabilitiesComplianceTrendComponent implements OnInit, OnDestro private graphWidth: any; private graphData: any; - private dataLoaded: any = false; - private error: any = false; + dataLoaded: any = false; + error: any = false; private loading: any = false; private errorMessage: any = 'apiResponseError'; private distributedFiltersObject: any = {}; @@ -102,6 +102,7 @@ export class VulnerabilitiesComplianceTrendComponent implements OnInit, OnDestro prevDate.setMonth(prevDate.getMonth() - 1); let fromDay; fromDay = prevDate.toISOString().split('T')[0]; + const queryParameters = { 'ag': this.selectedAssetGroup, 'from': fromDay, @@ -128,7 +129,7 @@ export class VulnerabilitiesComplianceTrendComponent implements OnInit, OnDestro } }, error => { - this.setError('apiResponseError'); + this.setError(error.message || 'apiResponseError'); } ); } catch (error) { diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.css b/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.css index dbcea2402..8cf364da5 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.css +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.css @@ -26,7 +26,7 @@ } .vul-app-wrapper { - width: 100%; + width: calc(100% - 8px); overflow-y: auto; overflow-y: overlay; margin: 2em 0; min-height: 20em; diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.html b/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.html index b04f06cdb..6d4464e22 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.html +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-across-application/vulnerability-across-application.component.html @@ -20,7 +20,7 @@
    - +
    - -
    -
    - - -
    -
    -
    -
    Distribute by:
    -
    - -
    -
    - {{tab.name}} ({{tab.length}}) -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-distribution-summary/vulnerability-aging-distribution-summary.component.spec.ts b/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-distribution-summary/vulnerability-aging-distribution-summary.component.spec.ts deleted file mode 100644 index 47629bb3e..000000000 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-distribution-summary/vulnerability-aging-distribution-summary.component.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - *Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); You may not use - * this file except in compliance with the License. A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or - * implied. See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { VulnerabilityAgingDistributionSummaryComponent } from './vulnerability-aging-distribution-summary.component'; - -describe('VulnerabilityAgingDistributionSummaryComponent', () => { - let component: VulnerabilityAgingDistributionSummaryComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ VulnerabilityAgingDistributionSummaryComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(VulnerabilityAgingDistributionSummaryComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-distribution-summary/vulnerability-aging-distribution-summary.component.ts b/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-distribution-summary/vulnerability-aging-distribution-summary.component.ts deleted file mode 100644 index 9a25bf649..000000000 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-distribution-summary/vulnerability-aging-distribution-summary.component.ts +++ /dev/null @@ -1,264 +0,0 @@ -/* - *Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); You may not use - * this file except in compliance with the License. A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or - * implied. See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs/Subscription'; -import { environment } from './../../../../environments/environment'; -import { LoggerService } from '../../../shared/services/logger.service'; -import { AssetGroupObservableService } from '../../../core/services/asset-group-observable.service'; -import { GridOptions } from 'ag-grid'; -import * as _ from 'lodash'; -import { VulnerabilityAgingSummaryDistributionService } from '../../services/vulnerability-aging-summary-distribution.service'; - -@Component({ - selector: 'app-vulnerability-aging-distribution-summary', - templateUrl: './vulnerability-aging-distribution-summary.component.html', - styleUrls: ['./vulnerability-aging-distribution-summary.component.css'], - providers: [VulnerabilityAgingSummaryDistributionService, LoggerService] -}) - -export class VulnerabilityAgingDistributionSummaryComponent implements OnDestroy { - - selectedAssetGroup: string; - private errorMessage = 'apiResponseError'; - - getContextMenuItems: any; - gridApi: any; - gridColumnApi: any; - columns: any = []; - initComplete = false; - showtable = false; - - private gridOptions: GridOptions; - private subscriptionToAssetGroup: Subscription; - private dataSubscription: Subscription; - - errorValue = 0; - tabsData: any = []; - selected: any; - rowsData: any; - tabsName: any; - - constructor( - private assetGroupObservableService: AssetGroupObservableService, - private logger: LoggerService, - private vulnerabilityAgingSummaryDistributionService: VulnerabilityAgingSummaryDistributionService ) { - - this.gridOptions = {}; - this.gridOptions.columnDefs = []; - - this.gridOptions.rowData = []; - this.getContextMenuItems = function getContextMenuItems(params) { - const result = [ - 'toolPanel', - 'separator', - 'copy', - 'separator', - 'csvExport', - 'separator', - 'autoSizeAll', - 'resetColumns' - ]; - return result; - }; - - this.subscriptionToAssetGroup = this.assetGroupObservableService.getAssetGroup().subscribe( - assetGroupName => { - this.showtable = false; - this.selectedAssetGroup = assetGroupName; - setTimeout(() => { - this.showtable = true; - this.resetPage(); - this.updateComponent(); - }, 10); - }); - - } - - resetPage() { - this.tabsData = []; - this.rowsData = []; - } - - updateComponent() { - this.errorValue = 0; - this.getData(); - } - - downloadCsv() { - this.gridApi.exportDataAsCsv(); - } - - getData() { - - if (this.dataSubscription) { - this.dataSubscription.unsubscribe(); - } - - const payload = {}; - const queryParam = { - 'ag': this.selectedAssetGroup - }; - this.errorValue = 0; - - const url = environment.vulnerabilityAgingDistributionSummary.url; - const method = environment.vulnerabilityAgingDistributionSummary.method; - - this.dataSubscription = this.vulnerabilityAgingSummaryDistributionService.getData(url, method, payload, queryParam).subscribe( - response => { - try { - if (this.checkForEmptyData(response)) { - this.errorValue = -1; - this.errorMessage = 'vulnerabilityMessage'; - } else { - this.errorValue = 1; - this.processData(response); - } - - } catch (e) { - this.errorValue = -1; - this.errorMessage = 'jsError'; - this.logger.log('error', e); - } - }, - error => { - this.errorValue = -1; - this.errorMessage = 'apiResponseError'; - this.logger.log('error', error); - }); - } - - processData(data) { - - for ( const key of Object.keys(data) ) { - this.tabsData.push({ - name: key, - length: data[key].length - }); - } - - this.selected = this.tabsData[0].name; - this.rowsData = data; - this.columns = []; - const keys = Object.keys(data); - const columns = Object.keys(data[keys[0]][0]); - this.columns = columns; - - let eachObj = {}; - this.gridOptions.columnDefs = []; - this.gridOptions.rowData = []; - - for ( let i = 0; i < columns.length; i++) { - if (columns[i].toLowerCase() === 'name') { - eachObj = { - pinned: 'left', - lockPosition: true, - field: columns[i], - headerName: columns[i], - minWidth: 160, - maxWidth: 800 - }; - } else { - eachObj = { - field: columns[i], - headerName: columns[i], - minWidth: 160, - maxWidth: 800 - }; - } - this.gridOptions.columnDefs.push(eachObj); - } - if (this.gridApi) { - this.gridApi.setColumnDefs(this.gridOptions.columnDefs); - this.setGridRowData(); - this.onresize(); - } - } - - onGridReady(params) { - this.gridApi = params.api; - this.gridColumnApi = params.columnApi; - } - - setGridRowData() { - this.gridOptions.rowData = this.rowsData[this.selected]; - this.gridApi.setRowData(this.gridOptions.rowData); - } - - onresize() { - if (this.columns.length < 6 && this.columns.length > 0) { - setTimeout(() => { - this.gridApi.sizeColumnsToFit(); - }, 3); - } else { - this.autoSizeAll(); - } - } - - autoSizeAll() { - const allColumnIds = []; - if (this.gridColumnApi) { - this.gridColumnApi.getAllColumns().forEach(function(column) { - allColumnIds.push(column.colId); - }); - this.gridColumnApi.autoSizeColumns(allColumnIds); - } - } - - selectTab(tab, index) { - if (tab === this.selected) { - return; - } - const prevIndex = !!this.selected ? _.findIndex(this.tabsData, (tabData) => { - return tabData === this.selected; - }) + 1 : 0; - - this.selected = tab; - this.setGridRowData(); - - } - -tabSelected(tab) { - if (!this.selected) { - return false; - } - return this.selected === tab; -} - -checkForEmptyData(response) { - let emptyResponse = true; - const keys = Object.keys(response); - for ( let index = 0; index < keys.length; index++) { - if (response[keys[index]].length > 0) { - emptyResponse = false; - return emptyResponse; - } - } - return emptyResponse; -} - -ngOnDestroy() { - try { - if (this.subscriptionToAssetGroup) { - this.subscriptionToAssetGroup.unsubscribe(); - } - if (this.dataSubscription) { - this.dataSubscription.unsubscribe(); - } - } catch (error) { - this.logger.log('error', '--- Error while unsubscribing ---'); - } -} - -} diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.html b/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.html index fc4f2e053..b79d44459 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.html +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.html @@ -16,8 +16,8 @@
    -
    - +
    +
    diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.ts b/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.ts index 1925a8725..12398e4e2 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.ts +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-aging-graph/vulnerability-aging-graph.component.ts @@ -36,7 +36,7 @@ export class VulnerabilityAgingGraphComponent implements OnInit, OnDestroy { private dataSubscription: Subscription; private subscriptionToAssetGroup: Subscription; - private errorValue = 0; + errorValue = 0; public graphData: any = []; private legend_text: any; diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-assets-trend/vulnerability-assets-trend.component.ts b/webapp/src/app/pacman-features/secondary-components/vulnerability-assets-trend/vulnerability-assets-trend.component.ts index e66aaebba..05ca1003a 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-assets-trend/vulnerability-assets-trend.component.ts +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-assets-trend/vulnerability-assets-trend.component.ts @@ -44,8 +44,8 @@ export class VulnerabilityAssetsTrendComponent implements OnInit, OnDestroy { private graphWidth: any; private graphData: any; - private dataLoaded: any = false; - private error: any = false; + dataLoaded: any = false; + error: any = false; private loading: any = false; private errorMessage: any = 'apiResponseError'; private distributedFiltersObject: any = {}; @@ -130,7 +130,7 @@ export class VulnerabilityAssetsTrendComponent implements OnInit, OnDestroy { } }, error => { - this.setError('apiResponseError'); + this.setError(error.message || 'apiResponseError'); } ); } catch (error) { diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.html b/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.html index 9e6a31926..69911afdd 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.html +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.html @@ -13,6 +13,7 @@ -->
    - - + + +
    diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.ts b/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.ts index b3a3c7852..4efe9c7cd 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.ts +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-issue/vulnerability-issue.component.ts @@ -22,8 +22,7 @@ import { Component } from '@angular/core'; export class VulnerabilityIssueComponent { - public pageLevel = 0; - + pageTitle = 'Vulnerabilities'; constructor() { } } diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.css b/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.css deleted file mode 100644 index 239322118..000000000 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.css +++ /dev/null @@ -1,81 +0,0 @@ -/* - *Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); You may not use - * this file except in compliance with the License. A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or - * implied. See the License for the specific language governing permissions and - * limitations under the License. - */ - -.ag-theme-material { - border: 1px solid #ededed; - border-radius: 3px; - box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.15); -} - -.table-wrap { - height: 31.5em; -} - -.flex-grow { - flex-grow: 1; - min-height: 25em; -} - -.ag-theme-material .ag-cell { - line-height: 36px!important; -} - -.open-vulnerability-table-wrapper{ - width: 100%; - height: 100%; - position: relative; - max-height: 50em; -} -.data-table-tabs{ - background-color: #eff3f6; - color: #5a616b; - font-size: 1em; - font-family: ex2-light; - overflow-x: auto; - white-space: nowrap; -} - -.individual-tag-header{ - padding: 1em; - transition: 0.2s; - min-width: 6.4em; - text-align: center; - font-size: 1.1em; -} - -.individual-tag-header:hover { - text-shadow: 1px 0; - letter-spacing: 0.3px; - cursor: pointer; -} - -.individual-tag-header.filter-by { - font-size: 0.88em; -} - -.individual-tag-header.filter-by:hover{ - font-family: ex2-light; - letter-spacing: 0.1px; - cursor: default; -} - -.selected { - background-color: #5a616b; - color: #fff; - text-shadow: 1px 0; -} - -.sub-head /deep/ .header-text { - text-transform: initial; -} \ No newline at end of file diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.html b/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.html deleted file mode 100644 index 0c921bda5..000000000 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.html +++ /dev/null @@ -1,65 +0,0 @@ - - -
    -
    - - -
    -
    -
    -
    Distribute by:
    -
    - -
    -
    - {{tab.name}} ({{tab.length}}) -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.ts b/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.ts deleted file mode 100644 index 0974e246a..000000000 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-distribution/vulnerability-summary-distribution.component.ts +++ /dev/null @@ -1,270 +0,0 @@ -/* - *Copyright 2018 T Mobile, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); You may not use - * this file except in compliance with the License. A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or - * implied. See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, OnDestroy, Output, EventEmitter } from '@angular/core'; -import { Subscription } from 'rxjs/Subscription'; -import { environment } from './../../../../environments/environment'; -import { LoggerService } from '../../../shared/services/logger.service'; -import { AssetGroupObservableService } from '../../../core/services/asset-group-observable.service'; -import { GridOptions } from 'ag-grid'; -import * as _ from 'lodash'; -import { VulnerabilitySummaryDistributionService } from '../../services/vulnerability-summary-distribution.service'; - -@Component({ - selector: 'app-vulnerability-summary-distribution', - templateUrl: './vulnerability-summary-distribution.component.html', - styleUrls: ['./vulnerability-summary-distribution.component.css'], - providers: [VulnerabilitySummaryDistributionService, LoggerService] -}) -export class VulnerabilitySummaryDistributionComponent implements OnDestroy { - - selectedAssetGroup: string; - private errorMessage = 'apiResponseError'; - - getContextMenuItems: any; - gridApi: any; - gridColumnApi: any; - columns: any = []; - initComplete = false; - showtable = false; - - private gridOptions: GridOptions; - private subscriptionToAssetGroup: Subscription; - private dataSubscription: Subscription; - - @Output() errorOccurred = new EventEmitter(); - - errorValue = 0; - tabsData: any = []; - selected: any; - rowsData: any; - tabsName: any; - - constructor( - private assetGroupObservableService: AssetGroupObservableService, - private logger: LoggerService, - private vulnerabilitySummaryDistributionService: VulnerabilitySummaryDistributionService ) { - - this.gridOptions = {}; - this.gridOptions.columnDefs = []; - - this.gridOptions.rowData = []; - this.getContextMenuItems = function getContextMenuItems(params) { - const result = [ - 'toolPanel', - 'separator', - 'copy', - 'separator', - 'csvExport', - 'separator', - 'autoSizeAll', - 'resetColumns' - ]; - return result; - }; - - this.subscriptionToAssetGroup = this.assetGroupObservableService.getAssetGroup().subscribe( - assetGroupName => { - this.showtable = false; - this.selectedAssetGroup = assetGroupName; - setTimeout(() => { - this.showtable = true; - this.resetPage(); - this.updateComponent(); - }, 10); - }); - - } - - resetPage() { - this.tabsData = []; - this.rowsData = []; - } - - updateComponent() { - this.errorValue = 0; - this.getData(); - } - - getData() { - - if (this.dataSubscription) { - this.dataSubscription.unsubscribe(); - } - - const payload = {}; - const queryParam = { - 'ag': this.selectedAssetGroup - }; - this.errorValue = 0; - - const url = environment.openVulnerabilityTable.url; - const method = environment.openVulnerabilityTable.method; - - this.dataSubscription = this.vulnerabilitySummaryDistributionService.getData(url, method, payload, queryParam).subscribe( - response => { - try { - if (this.checkForEmptyData(response)) { - this.errorOccurred.emit(); - this.errorValue = -1; - this.errorMessage = 'vulnerabilityMessage'; - } else { - this.errorValue = 1; - this.processData(response); - } - - } catch (e) { - this.errorOccurred.emit(); - this.errorValue = -1; - this.errorMessage = 'jsError'; - this.logger.log('error', e); - } - }, - error => { - this.errorOccurred.emit(); - this.errorValue = -1; - this.errorMessage = 'apiResponseError'; - this.logger.log('error', error); - }); - } - - downloadCsv() { - this.gridApi.exportDataAsCsv(); - } - - processData(data) { - - for (const key of Object.keys(data)) { - this.tabsData.push({ - name: key, - length: data[key].length - }); - } - - - this.selected = this.tabsData[0].name; - this.rowsData = data; - this.columns = []; - const keys = Object.keys(data); - const columns = Object.keys(data[keys[0]][0]); - this.columns = columns; - - let eachObj = {}; - this.gridOptions.columnDefs = []; - this.gridOptions.rowData = []; - - for ( let i = 0; i < columns.length; i++) { - if (columns[i].toLowerCase() === 'name') { - eachObj = { - pinned: 'left', - lockPosition: true, - field: columns[i], - headerName: columns[i], - minWidth: 160, - maxWidth: 800 - }; - } else { - eachObj = { - field: columns[i], - headerName: columns[i], - minWidth: 160, - maxWidth: 800 - }; - } - this.gridOptions.columnDefs.push(eachObj); - } - if (this.gridApi) { - this.gridApi.setColumnDefs(this.gridOptions.columnDefs); - this.setGridRowData(); - this.onresize(); - } - } - - onGridReady(params) { - this.gridApi = params.api; - this.gridColumnApi = params.columnApi; - } - - setGridRowData() { - this.gridOptions.rowData = this.rowsData[this.selected]; - this.gridApi.setRowData(this.gridOptions.rowData); - } - - onresize() { - if (this.columns.length < 6 && this.columns.length > 0) { - setTimeout(() => { - this.gridApi.sizeColumnsToFit(); - }, 3); - } else { - this.autoSizeAll(); - } - } - - autoSizeAll() { - const allColumnIds = []; - if (this.gridColumnApi) { - this.gridColumnApi.getAllColumns().forEach(function(column) { - allColumnIds.push(column.colId); - }); - this.gridColumnApi.autoSizeColumns(allColumnIds); - } - } - - selectTab(tab, index) { - if (tab === this.selected) { - return; - } - - const prevIndex = !!this.selected ? _.findIndex(this.tabsData, (tabData) => { - return tabData === this.selected; - }) + 1 : 0; - - this.selected = tab; - this.setGridRowData(); - } - -tabSelected(tab) { - if (!this.selected) { - return false; - } - return this.selected === tab; -} - -checkForEmptyData(response) { - let emptyResponse = true; - const keys = Object.keys(response); - for ( let index = 0; index < keys.length; index++) { - if (response[keys[index]].length > 0) { - emptyResponse = false; - return emptyResponse; - } - } - return emptyResponse; -} - -ngOnDestroy() { - try { - if (this.subscriptionToAssetGroup) { - this.subscriptionToAssetGroup.unsubscribe(); - } - if (this.dataSubscription) { - this.dataSubscription.unsubscribe(); - } - } catch (error) { - this.logger.log('error', '--- Error while unsubscribing ---'); - } -} - - -} diff --git a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-table/vulnerability-summary-table.component.html b/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-table/vulnerability-summary-table.component.html index 2a670a166..e8cb4d78b 100644 --- a/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-table/vulnerability-summary-table.component.html +++ b/webapp/src/app/pacman-features/secondary-components/vulnerability-summary-table/vulnerability-summary-table.component.html @@ -15,7 +15,7 @@
    - +
    {{row[column].text}}
    - +
    @@ -69,7 +69,7 @@
    {{row[column].text}}
    - +
    @@ -81,7 +81,7 @@ diff --git a/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.css b/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.css index 865a5c0ba..914ca0f36 100644 --- a/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.css +++ b/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.css @@ -28,9 +28,10 @@ .legend-color { display: inline-block; - width: 1em; - height: 1em; - margin-right: 1em; + width: 10px; + height: 10px; + margin-right: 10px; + /* border: 1px solid #9e9e9e; */ background-color: #e60127; vertical-align: middle; } @@ -59,8 +60,6 @@ } .graph-outer-container { - /* width: 100%; - height: 100%; */ text-align: center; } @@ -97,9 +96,21 @@ text-align: center; } +.concentric-ring { + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border-radius: 110px; + border: 2px solid #e8e8e8; + z-index: -1; +} +.white-txt { + color: #fff !important; +} + @media print { - #donut-chart{ + /* #donut-chart{ width: 125px; height: 125px; - } + } */ } \ No newline at end of file diff --git a/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.html b/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.html index 1009e7e97..842236bb8 100644 --- a/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.html +++ b/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.html @@ -17,13 +17,14 @@
    {{this.graphData.centerText}}
    +
    - -
    +
    - {{eachGraphPath}} - {{graphData.data[i]}} + {{eachGraphPath}}: +  {{graphData.data[i]}}
    @@ -37,15 +38,14 @@
    - +
    -
    {{eachGraphPath}} - - {{graphData.data[i]}}% + {{graphData.data[i]}} %
    - \ No newline at end of file + diff --git a/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.ts b/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.ts index c795944dc..ba7db9424 100644 --- a/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.ts +++ b/webapp/src/app/shared/doughnut-chart/doughnut-chart.component.ts @@ -3,9 +3,9 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); You may not use * this file except in compliance with the License. A copy of the License is located at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * or in the "license" file accompanying this file. This file is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or * implied. See the License for the specific language governing permissions and @@ -24,10 +24,14 @@ import { // d3 imports -import * as d3 from 'd3-selection'; +import * as d3 from 'd3'; import * as d3Shape from 'd3-shape'; import * as d3Interpolate from 'd3-interpolate'; +// import { select , selectAll } from 'd3-selection'; +// import { transition } from 'd3-transition'; + + @Component({ selector: 'app-doughnut-chart', templateUrl: './doughnut-chart.component.html', @@ -39,21 +43,25 @@ export class DoughnutChartComponent implements OnInit, OnChanges { @Input() graphData: any; @Input() graphWidth: any; @Input() graphHeight: any; - @Input() MainTextcolor: '#fff'; + @Input() isPieChart = false; + @Input() ringData; + @Input() selectedLevel; + @Input() MainTextcolor; @Input() innerRadious: 0; @Input() outerRadious: 0; @Input() strokeColor: 'transparent'; @Input() flexTrue: any; + @Input() isFullScreen; @Output() error: EventEmitter = new EventEmitter(); @Output() navigatePage: EventEmitter = new EventEmitter(); @Output() linkData: EventEmitter = new EventEmitter(); + @Output() emitClick: EventEmitter = new EventEmitter(); public dataset: any; public labels: any; public arc: any; public path: any; public pie: any; - public radius: any; public svg: any; public duration = 600; @@ -62,7 +70,10 @@ export class DoughnutChartComponent implements OnInit, OnChanges { public outerRadius = 0; public fontSize = 0; - constructor() {} + constructor() { + // select.prototype.transition = transition; + // selectAll.prototype.transition = transition; + } ngOnInit() { setTimeout(() => { @@ -109,6 +120,11 @@ export class DoughnutChartComponent implements OnInit, OnChanges { } } processGraphdata() { + if (this.isFullScreen) { + this.MainTextcolor = '#fff'; + } else { + this.MainTextcolor = '#000'; + } let total; let centerText; if (this.graphData.centerText) { @@ -126,6 +142,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges { if (this.graphData.data) { try { this.zeroData = false; + const self = this; setTimeout(() => { if (Math.min(this.graphWidth, this.graphHeight) < 140) { @@ -134,19 +151,27 @@ export class DoughnutChartComponent implements OnInit, OnChanges { } this.radius = Math.min(this.graphWidth, this.graphHeight) / 1.5; this.outerRadius = (Math.min(this.graphWidth, this.graphHeight) / 2) - 10; - this.innerRadius = this.outerRadius - 20; - + if (!this.isPieChart) { + // If donut + // this.innerRadius = this.outerRadius - 20; + this.innerRadius = this.outerRadius - 10; + } else { + // If Pie chart + this.innerRadius = 0; + } // --------- remove old svg before plotting -------------// - if ( - d3.selectAll('#' + this.chartContId) + if (d3. + selectAll('#' + this.chartContId) .select('svg') .selectAll('g') !== undefined) { - d3.selectAll('#' + this.chartContId) + d3. + selectAll('#' + this.chartContId) .select('svg') .selectAll('g') .remove(); - d3.selectAll('#' + this.chartContId) + d3. + selectAll('#' + this.chartContId) .select('svg') .append('g'); } @@ -163,8 +188,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges { .outerRadius(this.outerRadius); // --------this appends a svg to the selected container and positions the svg------// - this.svg = d3 - .select('#' + this.chartContId) + this.svg = d3.select('#' + this.chartContId) .select('svg') .attr('width', this.graphWidth) .attr('height', this.graphHeight) @@ -202,10 +226,20 @@ export class DoughnutChartComponent implements OnInit, OnChanges { // --------fill color with animation to donut chart--------// g.append('path') .attr('fill', (d, i) => { + if (this.graphData.legendWithText && this.graphData.legendWithText[i]) { + d['legend'] = this.graphData.legendWithText[i]; + } return this.graphData.color[i]; }) - .transition().delay(function(d, i) { - return i * 500; }).duration(500) + .style('cursor', (d, i) => { + if (this.graphData.cursor && this.graphData.cursor[i]) { + return this.graphData.cursor[i] === 'pointer' ? 'pointer' : 'default'; + } else { + return 'default'; + } + }) + .transition('rotate').delay(function(d, i) { + return i * 250; }).duration(250) .attrTween('d', function(d) { const i = d3Interpolate.interpolate(d.startAngle + 0.1, d.endAngle); return function(t) { @@ -214,20 +248,32 @@ export class DoughnutChartComponent implements OnInit, OnChanges { }; }); - d3.selectAll('path').on('mouseover', function(d, i) { - d3.select(this) - .transition() - .duration(250) - .attr('d', arcHoverIn) - .attr('stroke-width', 4); - }) - .on('mouseout', function(d, i) { - d3.select(this) - .transition() - .duration(250) - .attr('d', arcHoverOut) - .attr('stroke-width', 1); - }); + if (this.isPieChart) { + + setTimeout(() => { + d3. + selectAll('path') + .on('mouseover', function(d, i) { + d3. + select(this) + .transition('hoverIn') + .duration(250) + .attr('d', arcHoverIn) + .attr('stroke-width', 4); + }) + .on('mouseout', function(d, i) { + d3. + select(this) + .transition('hoverOut') + .duration(250) + .attr('d', arcHoverOut) + .attr('stroke-width', 1); + }) + .on('click', function(d) { + self.emitClick.emit(d); + }); + }, 350 ); + } // --------plots total count------------// if (centerText === undefined) { @@ -242,7 +288,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges { .attr('y', this.radius / 15); } } else { - if ((this.graphData.totalCount && total !== -1) && centerText !== undefined ) { + if ((this.graphData.totalCount && total !== -1) && centerText !== undefined && !this.isPieChart ) { this.svg .append('text') .text(total) @@ -295,7 +341,8 @@ export class DoughnutChartComponent implements OnInit, OnChanges { } removeExistingGraph() { - d3.selectAll('svg#' + this.chartContId + ' > *').remove(); + d3. + selectAll('svg#' + this.chartContId + ' > *').remove(); } onResize() { diff --git a/webapp/src/app/shared/main-filter/main-filter.component.css b/webapp/src/app/shared/main-filter/main-filter.component.css index aad202415..5f9f6e026 100644 --- a/webapp/src/app/shared/main-filter/main-filter.component.css +++ b/webapp/src/app/shared/main-filter/main-filter.component.css @@ -38,6 +38,7 @@ } .filter-main-content { flex: 1; + height:100%; } .each-filter-column { border-right: 1px solid #c3cbd7; diff --git a/webapp/src/app/shared/services/auth-guard.service.ts b/webapp/src/app/shared/services/auth-guard.service.ts index f2a41edcd..8d56a6e72 100644 --- a/webapp/src/app/shared/services/auth-guard.service.ts +++ b/webapp/src/app/shared/services/auth-guard.service.ts @@ -15,17 +15,20 @@ /* Created by Puneet Baser 20/11/2017 */ import { Injectable } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, ActivatedRoute, Router} from '@angular/router'; import { AuthService } from '../../core/services/auth.service'; import { LoggerService } from './logger.service'; import { DataCacheService } from '../../core/services/data-cache.service'; +import { CONFIGURATIONS } from '../../../config/configurations'; @Injectable() export class AuthGuardService implements CanActivate { constructor( private authService: AuthService, private loggerService: LoggerService, - private dataStore: DataCacheService) {} + private dataStore: DataCacheService, + private router: Router, + private activatedRoute: ActivatedRoute) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { @@ -50,6 +53,15 @@ export class AuthGuardService implements CanActivate { this.loggerService.log('info', '**Error in setting user Fetched information**'); }); } + + if (state.url.includes('vulnerabilities-compliance') && !CONFIGURATIONS.optional.general.qualysEnabled) { + this.loggerService.log('info', 'Qualys required to access this page'); + this.router.navigate( + ['../../../../compliance/compliance-dashboard'], + { relativeTo: this.activatedRoute, queryParamsHandling: 'merge' } + ); + return false; + } return true; } } diff --git a/webapp/src/app/shared/services/router-utility.service.ts b/webapp/src/app/shared/services/router-utility.service.ts index af260138e..01bf04ae9 100644 --- a/webapp/src/app/shared/services/router-utility.service.ts +++ b/webapp/src/app/shared/services/router-utility.service.ts @@ -149,4 +149,25 @@ export class RouterUtilityService { return false; } + public getFullPageUrlSegmentFromSnapshot(routerSnapshot: ActivatedRouteSnapshot) { + let urlSegmentDetails = []; + + const urlSegment = routerSnapshot.url; + const outlet = routerSnapshot.outlet; + + urlSegmentDetails.push({ + 'urlSegment': urlSegment, + 'outlet': outlet + }); + + const children = routerSnapshot.children; + if (children) { + for (let i = 0; i < children.length; i++ ) { + const child = children[i]; + urlSegmentDetails = urlSegmentDetails.concat(this.getFullPageUrlSegmentFromSnapshot(child)); + } + } + + return urlSegmentDetails; + } } diff --git a/webapp/src/assets/icons/download-magenta.svg b/webapp/src/assets/icons/download-magenta.svg new file mode 100644 index 000000000..3dd027240 --- /dev/null +++ b/webapp/src/assets/icons/download-magenta.svg @@ -0,0 +1,17 @@ + + + + Download + Created with Sketch. + + + + + + + + + + + + diff --git a/webapp/src/config/configurations.ts b/webapp/src/config/configurations.ts index f19700aae..8156070f6 100644 --- a/webapp/src/config/configurations.ts +++ b/webapp/src/config/configurations.ts @@ -31,7 +31,7 @@ export const CONFIGURATIONS = { OMNI_SEARCH_MODULE: true, // Expected values: true || false TOOLS_MODULE: false, // Expected values: true || false ADMIN_MODULE: true, // Expected values: true || false - } + }, }, optional: { auth: { @@ -60,6 +60,7 @@ export const CONFIGURATIONS = { NT_ID: '', // Add NT ID for e2e login NT_PASSWORD: '' // Add respective password for e2e login }, + qualysEnabled: false, OSS: true } } diff --git a/webapp/src/config/domain-mapping.ts b/webapp/src/config/domain-mapping.ts index 28dda899f..523484747 100644 --- a/webapp/src/config/domain-mapping.ts +++ b/webapp/src/config/domain-mapping.ts @@ -52,6 +52,11 @@ export const DOMAIN_MAPPING = [ 'groupBy': 'compliance-dashboard', 'cloudSpecific': true }, + { + 'route': 'vulnerabilities-compliance', + 'sequence': 4, + 'groupBy': 'compliance-dashboard' + }, ] }, { diff --git a/webapp/src/environments/environment.prod.ts b/webapp/src/environments/environment.prod.ts index ba61e338e..85f430598 100644 --- a/webapp/src/environments/environment.prod.ts +++ b/webapp/src/environments/environment.prod.ts @@ -16,7 +16,7 @@ export const environment = { production: true, base: '{{baseUrl}}', envName: 'prod', - version: '2.2.0', + version: '2.8.3', users: { url: '{{cloudBaseUrl}}/api/platform/ad/users', method: 'GET' @@ -66,7 +66,7 @@ export const environment = { method: 'GET' }, hostVulnerabilitiesTable: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/detail/{resourceId}', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/detail/{resourceId}', method: 'GET' }, InventoryTraker: { @@ -90,7 +90,7 @@ export const environment = { method: 'GET' }, vulnerabilityTrend: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend', method: 'POST' }, ruleDesc: { @@ -155,8 +155,8 @@ export const environment = { }, complianceCategories: { complianceCategoriesData: { - Vulnerabilities: { - url: '{{baseUrl}}/compliance/v1/vulnerabilites', + Vulnerabilities: { + url: '{{baseUrl}}/vulnerability/v1/vulnerabilites', method: 'GET' }, Tagging: { @@ -222,7 +222,7 @@ export const environment = { method: 'GET' }, vulnerabilitySummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summary', method: 'GET' }, issueListing: { @@ -230,11 +230,11 @@ export const environment = { method: 'POST' }, vulnerabilityAcrossApplication: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summarybyapplication', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyapplication', method: 'GET' }, allVulnerability: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/detail', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/detail', method: 'POST' }, saveDefaultAssetGroup: { @@ -285,6 +285,26 @@ export const environment = { url: '{{baseUrl}}/compliance/v1/noncompliancepolicy', method: 'POST' }, + cloudNotifications : { + url: '{{baseUrl}}/asset/v1/cloud/notifications', + method: 'POST' + }, + getEventDescription : { + url: '{{baseUrl}}/asset/v1/cloud/notifications/info', + method: 'GET' + }, + getEventDetails : { + url: '{{baseUrl}}/asset/v1/cloud/notifications/detail', + method: 'GET' + }, + getAutofixDetails : { + url: '{{baseUrl}}/asset/v1/autofix/notifications/detail', + method: 'POST' + }, + cloudNotifSummary : { + url: '{{baseUrl}}/asset/v1/cloud/notifications/summary', + method: 'GET' + }, policyContentSlider: { url: '{{baseUrl}}/compliance/v1/policydescription', method: 'GET' @@ -334,7 +354,7 @@ export const environment = { method: 'POST' }, vulnerabilityComplianceTrend: { - url: '{{baseUrl}}/compliance/v1/trend/compliance/vulnerabilities', + url: '{{baseUrl}}/vulnerability/v1/trend/compliance/vulnerabilities', method: 'POST' }, certificatesComplianceTrend: { @@ -354,7 +374,7 @@ export const environment = { method: 'GET' }, hostVulnerabilitiesGraph: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summary/{resourceId}', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summary/{resourceId}', method: 'GET' }, cpuUtilizationGraph: { @@ -382,7 +402,7 @@ export const environment = { method: 'POST' }, vulnerabilityAcrossEnv: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summarybyenvironment', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyenvironment', method: 'GET' }, assetDetails: { @@ -454,7 +474,7 @@ export const environment = { method: 'GET' }, openVulnerabilityTable: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distributionsummary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distributionsummary', method: 'GET' }, devStrategyDist: { @@ -466,31 +486,11 @@ export const environment = { method: 'GET' }, vulnerabilityAgingSummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/aging/summary', - method: 'GET' - }, - cloudNotifications : { - url: '{{baseUrl}}/asset/v1/cloud/notifications', - method: 'POST' - }, - getEventDescription : { - url: '{{baseUrl}}/asset/v1/cloud/notifications/info', - method: 'GET' - }, - getEventDetails : { - url: '{{baseUrl}}/asset/v1/cloud/notifications/detail', - method: 'GET' - }, - getAutofixDetails : { - url: '{{baseUrl}}/asset/v1/autofix/notifications/detail', - method: 'POST' - }, - cloudNotifSummary : { - url: '{{baseUrl}}/asset/v1/cloud/notifications/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/aging/summary', method: 'GET' }, vulnerabilityAgingDistributionSummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/aging/distributionsummary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/aging/distributionsummary', method: 'GET' }, devStandardPullRequestAge: { @@ -731,7 +731,7 @@ export const environment = { method: 'GET' }, vulnerabilityQidDetails: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/qids', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/qids', method: 'GET' }, applicationUntagged: { @@ -747,19 +747,19 @@ export const environment = { method: 'POST' }, VulnerabilitiesDistributionEnv: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-env', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-env', method: 'GET' }, VulnerabilitiesDistributionInfra: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-infra', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-infra', method: 'GET' }, VulnerabilitiesDistributionVulnType: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-vulntype', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-vulntype', method: 'GET' }, remediationTable : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/remediations/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/remediations/summary', method: 'GET' }, postPlugins : { @@ -767,19 +767,19 @@ export const environment = { method: 'POST' }, performersTable : { - url: '{{baseUrl}}/compliance/v2/vulnerabilities/performers', + url: '{{baseUrl}}/vulnerability/v2/vulnerabilities/performers', method: 'GET' }, vulnReportGraph : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/open-new', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/open-new', method: 'POST' }, getVulnTrendNotes : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'GET' }, postVulnTrendNotes : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'POST' }, azureAuthorize : { @@ -787,7 +787,7 @@ export const environment = { method: 'POST' }, deleteVulnNote : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'DELETE' }, devDistribution: { @@ -889,6 +889,9 @@ export const environment = { recommendationsDetails: { url: '{{baseUrl}}/asset/v1/recommendations/detail', method: 'POST' - } - + }, + vulnerabilityGraphSummary: { + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyassets', + method: 'GET' + }, }; diff --git a/webapp/src/environments/environment.stg.ts b/webapp/src/environments/environment.stg.ts index 3ba8bb5da..90a4a7086 100644 --- a/webapp/src/environments/environment.stg.ts +++ b/webapp/src/environments/environment.stg.ts @@ -16,7 +16,7 @@ export const environment = { production: true, base: '{{baseUrl}}', envName: 'stg', - version: '2.2.0', + version: '2.8.3', users: { url: '{{cloudBaseUrl}}/api/platform/ad/users', method: 'GET' @@ -66,7 +66,7 @@ export const environment = { method: 'GET' }, hostVulnerabilitiesTable: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/detail/{resourceId}', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/detail/{resourceId}', method: 'GET' }, InventoryTraker: { @@ -90,7 +90,7 @@ export const environment = { method: 'GET' }, vulnerabilityTrend: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend', method: 'POST' }, ruleDesc: { @@ -155,8 +155,8 @@ export const environment = { }, complianceCategories: { complianceCategoriesData: { - Vulnerabilities: { - url: '{{baseUrl}}/compliance/v1/vulnerabilites', + Vulnerabilities: { + url: '{{baseUrl}}/vulnerability/v1/vulnerabilites', method: 'GET' }, Tagging: { @@ -222,27 +222,7 @@ export const environment = { method: 'GET' }, vulnerabilitySummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summary', - method: 'GET' - }, - cloudNotifications : { - url: '{{baseUrl}}/asset/v1/cloud/notifications', - method: 'POST' - }, - getEventDescription : { - url: '{{baseUrl}}/asset/v1/cloud/notifications/info', - method: 'GET' - }, - getEventDetails : { - url: '{{baseUrl}}/asset/v1/cloud/notifications/detail', - method: 'GET' - }, - getAutofixDetails : { - url: '{{baseUrl}}/asset/v1/autofix/notifications/detail', - method: 'POST' - }, - cloudNotifSummary : { - url: '{{baseUrl}}/asset/v1/cloud/notifications/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summary', method: 'GET' }, issueListing: { @@ -250,11 +230,11 @@ export const environment = { method: 'POST' }, vulnerabilityAcrossApplication: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summarybyapplication', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyapplication', method: 'GET' }, allVulnerability: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/detail', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/detail', method: 'POST' }, saveDefaultAssetGroup: { @@ -305,6 +285,26 @@ export const environment = { url: '{{baseUrl}}/compliance/v1/noncompliancepolicy', method: 'POST' }, + cloudNotifications : { + url: '{{baseUrl}}/asset/v1/cloud/notifications', + method: 'POST' + }, + getEventDescription : { + url: '{{baseUrl}}/asset/v1/cloud/notifications/info', + method: 'GET' + }, + getEventDetails : { + url: '{{baseUrl}}/asset/v1/cloud/notifications/detail', + method: 'GET' + }, + getAutofixDetails : { + url: '{{baseUrl}}/asset/v1/autofix/notifications/detail', + method: 'POST' + }, + cloudNotifSummary : { + url: '{{baseUrl}}/asset/v1/cloud/notifications/summary', + method: 'GET' + }, policyContentSlider: { url: '{{baseUrl}}/compliance/v1/policydescription', method: 'GET' @@ -354,7 +354,7 @@ export const environment = { method: 'POST' }, vulnerabilityComplianceTrend: { - url: '{{baseUrl}}/compliance/v1/trend/compliance/vulnerabilities', + url: '{{baseUrl}}/vulnerability/v1/trend/compliance/vulnerabilities', method: 'POST' }, certificatesComplianceTrend: { @@ -374,7 +374,7 @@ export const environment = { method: 'GET' }, hostVulnerabilitiesGraph: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summary/{resourceId}', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summary/{resourceId}', method: 'GET' }, cpuUtilizationGraph: { @@ -402,7 +402,7 @@ export const environment = { method: 'POST' }, vulnerabilityAcrossEnv: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summarybyenvironment', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyenvironment', method: 'GET' }, assetDetails: { @@ -474,7 +474,7 @@ export const environment = { method: 'GET' }, openVulnerabilityTable: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distributionsummary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distributionsummary', method: 'GET' }, devStrategyDist: { @@ -486,11 +486,11 @@ export const environment = { method: 'GET' }, vulnerabilityAgingSummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/aging/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/aging/summary', method: 'GET' }, vulnerabilityAgingDistributionSummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/aging/distributionsummary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/aging/distributionsummary', method: 'GET' }, devStandardPullRequestAge: { @@ -731,7 +731,7 @@ export const environment = { method: 'GET' }, vulnerabilityQidDetails: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/qids', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/qids', method: 'GET' }, applicationUntagged: { @@ -747,19 +747,19 @@ export const environment = { method: 'POST' }, VulnerabilitiesDistributionEnv: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-env', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-env', method: 'GET' }, VulnerabilitiesDistributionInfra: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-infra', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-infra', method: 'GET' }, VulnerabilitiesDistributionVulnType: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-vulntype', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-vulntype', method: 'GET' }, remediationTable : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/remediations/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/remediations/summary', method: 'GET' }, postPlugins : { @@ -767,19 +767,19 @@ export const environment = { method: 'POST' }, performersTable : { - url: '{{baseUrl}}/compliance/v2/vulnerabilities/performers', + url: '{{baseUrl}}/vulnerability/v2/vulnerabilities/performers', method: 'GET' }, vulnReportGraph : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/open-new', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/open-new', method: 'POST' }, getVulnTrendNotes : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'GET' }, postVulnTrendNotes : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'POST' }, azureAuthorize : { @@ -787,7 +787,7 @@ export const environment = { method: 'POST' }, deleteVulnNote : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'DELETE' }, devDistribution: { @@ -889,5 +889,9 @@ export const environment = { recommendationsDetails: { url: '{{baseUrl}}/asset/v1/recommendations/detail', method: 'POST' - } + }, + vulnerabilityGraphSummary: { + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyassets', + method: 'GET' + }, }; diff --git a/webapp/src/environments/environment.ts b/webapp/src/environments/environment.ts index 838fa45ff..ba8541148 100644 --- a/webapp/src/environments/environment.ts +++ b/webapp/src/environments/environment.ts @@ -66,7 +66,7 @@ export const environment = { method: 'GET' }, hostVulnerabilitiesTable: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/detail/{resourceId}', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/detail/{resourceId}', method: 'GET' }, InventoryTraker: { @@ -90,7 +90,7 @@ export const environment = { method: 'GET' }, vulnerabilityTrend: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend', method: 'POST' }, ruleDesc: { @@ -155,8 +155,8 @@ export const environment = { }, complianceCategories: { complianceCategoriesData: { - Vulnerabilities: { - url: '{{baseUrl}}/compliance/v1/vulnerabilites', + Vulnerabilities: { + url: '{{baseUrl}}/vulnerability/v1/vulnerabilites', method: 'GET' }, Tagging: { @@ -222,7 +222,7 @@ export const environment = { method: 'GET' }, vulnerabilitySummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summary', method: 'GET' }, issueListing: { @@ -230,11 +230,11 @@ export const environment = { method: 'POST' }, vulnerabilityAcrossApplication: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summarybyapplication', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyapplication', method: 'GET' }, allVulnerability: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/detail', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/detail', method: 'POST' }, saveDefaultAssetGroup: { @@ -354,7 +354,7 @@ export const environment = { method: 'POST' }, vulnerabilityComplianceTrend: { - url: '{{baseUrl}}/compliance/v1/trend/compliance/vulnerabilities', + url: '{{baseUrl}}/vulnerability/v1/trend/compliance/vulnerabilities', method: 'POST' }, certificatesComplianceTrend: { @@ -374,7 +374,7 @@ export const environment = { method: 'GET' }, hostVulnerabilitiesGraph: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summary/{resourceId}', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summary/{resourceId}', method: 'GET' }, cpuUtilizationGraph: { @@ -402,7 +402,7 @@ export const environment = { method: 'POST' }, vulnerabilityAcrossEnv: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/summarybyenvironment', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyenvironment', method: 'GET' }, assetDetails: { @@ -474,7 +474,7 @@ export const environment = { method: 'GET' }, openVulnerabilityTable: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distributionsummary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distributionsummary', method: 'GET' }, devStrategyDist: { @@ -486,11 +486,11 @@ export const environment = { method: 'GET' }, vulnerabilityAgingSummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/aging/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/aging/summary', method: 'GET' }, vulnerabilityAgingDistributionSummary: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/aging/distributionsummary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/aging/distributionsummary', method: 'GET' }, devStandardPullRequestAge: { @@ -731,7 +731,7 @@ export const environment = { method: 'GET' }, vulnerabilityQidDetails: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/qids', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/qids', method: 'GET' }, applicationUntagged: { @@ -747,19 +747,19 @@ export const environment = { method: 'POST' }, VulnerabilitiesDistributionEnv: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-env', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-env', method: 'GET' }, VulnerabilitiesDistributionInfra: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-infra', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-infra', method: 'GET' }, VulnerabilitiesDistributionVulnType: { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/distribution-vulntype', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/distribution-vulntype', method: 'GET' }, remediationTable : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/remediations/summary', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/remediations/summary', method: 'GET' }, postPlugins : { @@ -767,19 +767,19 @@ export const environment = { method: 'POST' }, performersTable : { - url: '{{baseUrl}}/compliance/v2/vulnerabilities/performers', + url: '{{baseUrl}}/vulnerability/v2/vulnerabilities/performers', method: 'GET' }, vulnReportGraph : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/open-new', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/open-new', method: 'POST' }, getVulnTrendNotes : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'GET' }, postVulnTrendNotes : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'POST' }, azureAuthorize : { @@ -787,7 +787,7 @@ export const environment = { method: 'POST' }, deleteVulnNote : { - url: '{{baseUrl}}/compliance/v1/vulnerabilities/trend/notes', + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/trend/notes', method: 'DELETE' }, devDistribution: { @@ -889,5 +889,9 @@ export const environment = { recommendationsDetails: { url: '{{baseUrl}}/asset/v1/recommendations/detail', method: 'POST' - } + }, + vulnerabilityGraphSummary: { + url: '{{baseUrl}}/vulnerability/v1/vulnerabilities/summarybyassets', + method: 'GET' + }, }; diff --git a/webapp/src/styles.css b/webapp/src/styles.css index 388bbee28..ff7d6a0f4 100644 --- a/webapp/src/styles.css +++ b/webapp/src/styles.css @@ -947,6 +947,7 @@ html body .offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-retry { box-shadow: -1px 0px 5px -1px rgba(0, 0, 0, 0.15); position: relative; z-index: 3; + min-width: 25.4em; } .compliance-issues-container {