diff options
Diffstat (limited to 'ecomp-sdk-app/src/main/java/org/openecomp/policy/elk')
6 files changed, 3099 insertions, 0 deletions
diff --git a/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/ElkConnector.java b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/ElkConnector.java new file mode 100644 index 000000000..617e67ccb --- /dev/null +++ b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/ElkConnector.java @@ -0,0 +1,1235 @@ +/*- + * ============LICENSE_START======================================================= + * ECOMP Policy Engine + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.policy.elk.client; + + +import io.searchbox.action.Action; +import io.searchbox.client.JestClient; +import io.searchbox.client.JestClientFactory; +import io.searchbox.client.JestResult; +import io.searchbox.client.config.HttpClientConfig; +import io.searchbox.core.Delete; +import io.searchbox.core.Get; +import io.searchbox.core.Index; +import io.searchbox.core.Search; +import io.searchbox.core.Search.Builder; +import io.searchbox.indices.IndicesExists; +import io.searchbox.indices.type.TypeExist; +import io.searchbox.params.Parameters; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Map.Entry; + +import javax.xml.bind.JAXBException; + +//import org.apache.commons.logging.Log; +//import org.apache.commons.logging.LogFactory; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.QueryStringQueryBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.Option; +import org.openecomp.policy.elk.converter.ElkRecord; +import org.openecomp.policy.elk.converter.Xacml2Elk; + +import org.openecomp.policy.xacml.api.XACMLErrorConstants; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; + +public interface ElkConnector { + + public static final String ELK_URL = "http://localhost:9200"; + public static final String ELK_INDEX_POLICY = "policy"; + + public enum PolicyIndexType { + config, + action, + decision, + closedloop, + all, + } + + public enum PolicyType { + Config, + Action, + Decision, + Config_Fault, + Config_PM, + Config_FW, + Config_MS, + none, + } + + public enum PolicyBodyType { + json, + xml, + properties, + txt, + none, + } + + public ElkRecord create(PolicyType type, String name, String owner, String scope, + File xacmlFile, PolicyBodyType bodyType, String body, + File destinationDir) + throws IllegalStateException; + + public boolean testAndUpdate(File xacmlFile) throws IllegalStateException; + + public JestResult policy(String policyId) + throws IllegalStateException, IllegalArgumentException; + + public boolean clone(String origPolicyId, String clonePolicyId) + throws IllegalStateException; + + public boolean delete(File xacmlFile) + throws IllegalStateException; + + public ArrayList<PolicyLocator> policyLocators(PolicyIndexType type, String text,int connector) + throws IllegalStateException, IllegalArgumentException; + + public ArrayList<PolicyLocator> policyLocators(PolicyIndexType type, String text, + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s,int connector) + throws IllegalStateException, IllegalArgumentException; + + public JestResult search(PolicyIndexType type, String text) + throws IllegalStateException, IllegalArgumentException; + + public JestResult search(PolicyIndexType type, String text, + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s) + throws IllegalStateException, IllegalArgumentException; + + public boolean update(File xacmlFile) throws IllegalStateException; + + public ElkConnector singleton = new ElkConnectorImpl(); + + public static PolicyIndexType toPolicyIndexType(PolicyType type) + throws IllegalArgumentException { + if (type == null) + throw new IllegalArgumentException("Unsupported NULL type conversion"); + + switch(type) { + case Config: + return PolicyIndexType.config; + case Action: + return PolicyIndexType.action; + case Decision: + return PolicyIndexType.decision; + case Config_Fault: + return PolicyIndexType.closedloop; + case Config_PM: + return PolicyIndexType.closedloop; + case Config_FW: + return PolicyIndexType.config; + case Config_MS: + return PolicyIndexType.config; + case none: + return PolicyIndexType.all; + default: + throw new IllegalArgumentException("Unsupported type conversion to index: " + type.name()); + } + } + + public static PolicyIndexType toPolicyIndexType(String policyName) + throws IllegalArgumentException { + if (policyName == null) + throw new IllegalArgumentException("Unsupported NULL policy name conversion"); + + if (policyName.startsWith("Config_Fault")) { + return PolicyIndexType.closedloop; + } else if (policyName.startsWith("Config_PM")) { + return PolicyIndexType.closedloop; + } else if (policyName.startsWith("Config_FW")) { + return PolicyIndexType.config; + } else if (policyName.startsWith("Config_MS")) { + return PolicyIndexType.config; + }else if (policyName.startsWith("Action")) { + return PolicyIndexType.action; + } else if (policyName.startsWith("Decision")) { + return PolicyIndexType.decision; + } else if (policyName.startsWith("Config")) { + return PolicyIndexType.config; + } else { + throw new IllegalArgumentException + ("Unsupported policy name conversion to index: " + + policyName); + } + } + + public static PolicyType toPolicyType(String policyName) + throws IllegalArgumentException { + if (policyName == null) + throw new IllegalArgumentException("Unsupported NULL policy name conversion to Policy Type"); + + if (policyName.startsWith("Config_Fault")) { + return PolicyType.Config_Fault; + } else if (policyName.startsWith("Config_PM")) { + return PolicyType.Config_PM; + } else if (policyName.startsWith("Config_FW")) { + return PolicyType.Config_FW; + } else if (policyName.startsWith("Config_MS")) { + return PolicyType.Config_MS; + }else if (policyName.startsWith("Action")) { + return PolicyType.Action; + } else if (policyName.startsWith("Decision")) { + return PolicyType.Decision; + } else if (policyName.startsWith("Config")) { + return PolicyType.Config; + } else { + throw new IllegalArgumentException + ("Unsupported policy name conversion to index: " + + policyName); + } + } + + public static void main(String args[]) + throws JAXBException, IOException, CmdLineException, IllegalStateException { + ElkConnectorImpl.CLIOptions cliOptions = new ElkConnectorImpl.CLIOptions(); + CmdLineParser cliParser= new CmdLineParser(cliOptions); + try { + cliParser.parseArgument(args); + } catch (CmdLineException e) { + System.out.println("Usage: ElkConnector"); + cliParser.printUsage(System.out); + throw e; + } + + if (cliOptions.searchText != null && !cliOptions.searchText.isEmpty()) { + ArrayList<PolicyLocator> locators = + ElkConnector.singleton.policyLocators(PolicyIndexType.all, cliOptions.searchText,0); + for (PolicyLocator l: locators) { + System.out.println(l); + } + } else if (cliOptions.testFile != null && cliOptions.testFile.canRead()) { + boolean ok = ElkConnector.singleton.testAndUpdate(cliOptions.testFile); + System.out.println(cliOptions.testFile.getName() + ":" + ok); + } + } +} + +class ElkConnectorImpl implements ElkConnector { + + protected static class CLIOptions { + @Option(name="-s", usage="search", aliases={"-search", "--search"}, required=false, metaVar="<search text>") + protected String searchText; + + @Option(name="-e", usage="test and update policy if not exists", aliases={"-exist", "--exists"}, required=false, metaVar="<policy file>") + protected File testFile; + + @Option(name = "-h", aliases = {"-help", "--help"}, usage = "print this message") + private boolean help = false; + }; + + private static final String POLICY_RESULT_FIELDS = "[ \"Policy.PolicyType\", " + + "\"Policy.PolicyName\", " + + "\"Policy.Owner\", " + + "\"Policy.Scope\", " + + "\"Policy.PolicyId\", " + + "\"Policy.Version\" ]"; + + private static final String SOURCE_RESULT_FIELDS = "\"_source\": " + POLICY_RESULT_FIELDS; + + private static final Logger logger = FlexLogger.getLogger(ElkConnector.class); + + protected final JestClientFactory jestFactory = new JestClientFactory(); + protected final JestClient jestClient; + protected static int QUERY_MAXRECORDS = 1000; + + public ElkConnectorImpl() { + if (logger.isDebugEnabled()) logger.debug("ENTER: -"); + + HttpClientConfig jestClientConfig = + new HttpClientConfig.Builder(ELK_URL).multiThreaded(true).build(); + jestFactory.setHttpClientConfig(jestClientConfig); + jestClient = jestFactory.getObject(); + } + + protected boolean isType(PolicyIndexType type) throws IOException { + if (logger.isDebugEnabled()) logger.debug("ENTER: -"); + + try { + Action<JestResult> typeQuery = new TypeExist.Builder(ELK_INDEX_POLICY). + addType(type.toString()). + build(); + JestResult result = jestClient.execute(typeQuery); + + if (logger.isInfoEnabled()) { + logger.info("JSON:" + result.getJsonString()); + logger.info("ERROR:" + result.getErrorMessage()); + logger.info("PATH:" + result.getPathToResult()); + logger.info(result.getJsonObject()); + } + return result.isSucceeded(); + } catch (IOException e) { + logger.warn("Error checking type existance of " + type.toString() + + ": " + e.getMessage(), e); + throw e; + } + } + + protected boolean isIndex() throws IOException { + try { + Action<JestResult> indexQuery = + new IndicesExists.Builder(ELK_INDEX_POLICY).build(); + + JestResult result = jestClient.execute(indexQuery); + if (logger.isInfoEnabled()) { + logger.info("JSON:" + result.getJsonString()); + logger.info("ERROR:" + result.getErrorMessage()); + logger.info("PATH:" + result.getPathToResult()); + logger.info(result.getJsonObject()); + } + return result.isSucceeded(); + } catch (IOException e) { + logger.warn("Error checking index existance of " + + ELK_INDEX_POLICY + + ": " + e.getMessage(), e); + throw e; + } + } + + @Override + public JestResult search(PolicyIndexType type, String text) throws IllegalStateException, IllegalArgumentException { + if (logger.isTraceEnabled()) + logger.trace("ENTER: " + text); + + if (text == null || text.isEmpty()) { + throw new IllegalArgumentException("No search string provided"); + } + + // MatchQueryBuilder mQ = QueryBuilders.matchQuery("_all", text); + QueryStringQueryBuilder mQ = QueryBuilders.queryStringQuery(text); + SearchSourceBuilder searchSourceBuilder = + new SearchSourceBuilder().query(mQ). + fetchSource(new String[]{"Policy.PolicyType", + "Policy.PolicyName", + "Policy.Owner", + "Policy.Scope", + "Policy.PolicyId", + "Policy.Version"}, + null); + Builder searchBuilder = new Search.Builder(searchSourceBuilder.toString()). + addIndex(ELK_INDEX_POLICY). + setParameter(Parameters.SIZE, ElkConnectorImpl.QUERY_MAXRECORDS); + + if (type == null || type == PolicyIndexType.all) { + for (PolicyIndexType pT: PolicyIndexType.values()) { + if (pT != PolicyIndexType.all) { + searchBuilder.addType(pT.toString()); + } + } + } else { + searchBuilder.addType(type.toString()); + } + + Search search = searchBuilder.build(); + + JestResult result; + try { + result = jestClient.execute(search); + } catch (IOException ioe) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + search + ": " + ioe.getMessage(), ioe); + throw new IllegalStateException(ioe); + } + + if (result.isSucceeded()) { + if (logger.isInfoEnabled()) + logger.info("OK:" + result.getResponseCode() + ":" + search + ": " + + result.getPathToResult() + ":" + System.lineSeparator() + + result.getJsonString()); + } else { + /* Unsuccessful search */ + if (logger.isWarnEnabled()) + logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + ":" + + result.getResponseCode() + ": " + + search.getURI() + ":" + + result.getPathToResult() + ":" + + result.getJsonString() + ":" + + result.getErrorMessage()); + + String errorMessage = result.getErrorMessage(); + if (errorMessage != null && !errorMessage.isEmpty()) { + String xMessage = errorMessage; + if (errorMessage.contains("TokenMgrError")) { + int indexError = errorMessage.lastIndexOf("TokenMgrError"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("QueryParsingException")) { + int indexError = errorMessage.lastIndexOf("QueryParsingException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("JsonParseException")) { + int indexError = errorMessage.lastIndexOf("JsonParseException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("Parse Failure")) { + int indexError = errorMessage.lastIndexOf("Parse Failure"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("SearchParseException")) { + int indexError = errorMessage.lastIndexOf("SearchParseException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else { + xMessage = result.getErrorMessage(); + } + throw new IllegalStateException(xMessage); + } + } + + return result; + } + + public JestResult searchKey(PolicyIndexType type, String text, + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s,int connector) + throws IllegalStateException, IllegalArgumentException { + if (logger.isTraceEnabled()) + logger.trace("ENTER: " + text); + + if (filter_s == null || filter_s.size() <= 0) { + return search(type, text); + } + + String matches_s = ""; + + if(connector==0)// AND CONNECTOR + { + matches_s = "{\n" + + " " + SOURCE_RESULT_FIELDS + ",\n" + + " \"size\" : "+ ElkConnectorImpl.QUERY_MAXRECORDS + ",\n" + + " \"query\": {\n" + + " \"bool\" : {\n" + + " \"must\" : ["; + } + else if (connector ==1)//OR CONNECTOR + { + matches_s = "{\n" + + " " + SOURCE_RESULT_FIELDS + ",\n" + + " \"size\" : "+ ElkConnectorImpl.QUERY_MAXRECORDS + ",\n" + + " \"query\": {\n" + + " \"bool\" : {\n" + + " \"should\" : ["; + } + + for (Pair<ArrayList<String>,ArrayList<String>> p : filter_s) { + ArrayList<String> name_s = p.left(); + ArrayList<String> value_s = p.right(); + + if (name_s == null || name_s.size() <= 0) { + if (logger.isWarnEnabled()) + logger.warn("Defaulting to text search: Empty field name array passed in"); + return search(type, text); + } + + if (logger.isDebugEnabled()) { + for (String n: name_s) { + logger.debug("Filter Name: " + n); + } + } + + if (value_s == null || value_s.size() <= 0) { + if (logger.isWarnEnabled()) + logger.warn("Defaulting to text search: Empty field value array passed in"); + return search(type, text); + } + + if (logger.isDebugEnabled()) { + for (String v: value_s) { + logger.debug("Filter Value: " + v); + } + } + + /* common case: # filter names == # filter values */ + if (name_s.size() == value_s.size()) { + String match = ""; + for (int i=0; i<name_s.size(); i++) { + if (name_s.get(i).contains("*")) { + match = + "{ \"query_string\": { \"fields\": [ \"" + + name_s.get(i) + "\" ], " + + "\"query\" : \"" + + value_s.get(i) + "\" } },"; + } else { + match = + "{ \"match_phrase\": { \"" + + name_s.get(i) + "\" : \"" + + value_s.get(i) + "\" } },"; + } + if (logger.isDebugEnabled()) + logger.debug("Adding Match Line: " + match); + matches_s = matches_s + "\n " + match; + } + } + else if (name_s.size() > value_s.size() && (value_s.size() == 1)) { + String match = + "{ \"multi_match\": { \"query\": \"" + value_s.get(0) + "\", \"type\": \"phrase\", \"fields\": ["; + for (String n: name_s) { + match += " \"" + n + "\","; + } + match = match.substring(0, match.length()-1); + //match += " ] } },"; + match += " ] } },";//debug + if (logger.isDebugEnabled()) + logger.debug("Adding Match Line: " + match); + matches_s = matches_s + "\n " + match; + } else { + if (logger.isWarnEnabled()) + logger.warn("Defaulting to text search: different number of filter names and values"); + return search(type, text); + } + } + + matches_s = matches_s.substring(0, matches_s.length()-1); // remove last comma + + matches_s = matches_s + + " ]\n" + + " }\n" + + " }\n" + + "}"; + + if (logger.isDebugEnabled()) { + logger.debug(matches_s); + } + + Builder searchBuilder = new Search.Builder(matches_s). + addIndex(ELK_INDEX_POLICY); + + if (type == null || type == PolicyIndexType.all) { + for (PolicyIndexType pT: PolicyIndexType.values()) { + if (pT != PolicyIndexType.all) { + searchBuilder.addType(pT.toString()); + } + } + } else { + searchBuilder.addType(type.toString()); + } + + Search search = searchBuilder.build(); + + JestResult result; + try { + result = jestClient.execute(search); + } catch (IOException ioe) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + search + ": " + ioe.getMessage(), ioe); + throw new IllegalStateException(ioe); + } + + if (result.isSucceeded()) { + if (logger.isInfoEnabled()) + logger.info("OK:" + result.getResponseCode() + ":" + search + ": " + + result.getPathToResult() + ":" + System.lineSeparator() + + result.getJsonString()); + } else { + /* Unsuccessful search */ + if (logger.isWarnEnabled()) + logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + ":" + + result.getResponseCode() + ": " + + search.getURI() + ":" + + result.getPathToResult() + ":" + + result.getJsonString() + ":" + + result.getErrorMessage()); + + String errorMessage = result.getErrorMessage(); + if (errorMessage != null && !errorMessage.isEmpty()) { + String xMessage = errorMessage; + if (errorMessage.contains("TokenMgrError")) { + int indexError = errorMessage.lastIndexOf("TokenMgrError"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("QueryParsingException")) { + int indexError = errorMessage.lastIndexOf("QueryParsingException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("JsonParseException")) { + int indexError = errorMessage.lastIndexOf("JsonParseException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("Parse Failure")) { + int indexError = errorMessage.lastIndexOf("Parse Failure"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("SearchParseException")) { + int indexError = errorMessage.lastIndexOf("SearchParseException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else { + xMessage = result.getErrorMessage(); + } + throw new IllegalStateException(xMessage); + } + } + + return result; + } + + + @Override + public JestResult search(PolicyIndexType type, String text, + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s) + throws IllegalStateException, IllegalArgumentException { + if (logger.isTraceEnabled()) + logger.trace("ENTER: " + text); + + if (filter_s == null || filter_s.size() <= 0) { + return search(type, text); + } + + String matches_s = ""; + matches_s = "{\n" + + " " + SOURCE_RESULT_FIELDS + ",\n" + + " \"size\" : "+ ElkConnectorImpl.QUERY_MAXRECORDS + ",\n" + + " \"query\": {\n" + + " \"bool\" : {\n" + + " \"must\" : ["; + for (Pair<ArrayList<String>,ArrayList<String>> p : filter_s) { + ArrayList<String> name_s = p.left(); + ArrayList<String> value_s = p.right(); + + if (name_s == null || name_s.size() <= 0) { + if (logger.isWarnEnabled()) + logger.warn("Defaulting to text search: Empty field name array passed in"); + return search(type, text); + } + + if (logger.isDebugEnabled()) { + for (String n: name_s) { + logger.debug("Filter Name: " + n); + } + } + + if (value_s == null || value_s.size() <= 0) { + if (logger.isWarnEnabled()) + logger.warn("Defaulting to text search: Empty field value array passed in"); + return search(type, text); + } + + if (logger.isDebugEnabled()) { + for (String v: value_s) { + logger.debug("Filter Value: " + v); + } + } + + /* common case: # filter names == # filter values */ + if (name_s.size() == value_s.size()) { + String match = ""; + for (int i=0; i<name_s.size(); i++) { + if (name_s.get(i).contains("*")) { + match = + "{ \"query_string\": { \"fields\": [ \"" + + name_s.get(i) + "\" ], " + + "\"query\" : \"" + + value_s.get(i) + "\" } },"; + } else { + match = + "{ \"match_phrase\": { \"" + + name_s.get(i) + "\" : \"" + + value_s.get(i) + "\" } },"; + } + if (logger.isDebugEnabled()) + logger.debug("Adding Match Line: " + match); + matches_s = matches_s + "\n " + match; + } + } else if (name_s.size() > value_s.size() && (value_s.size() == 1)) { + String match = + "{ \"multi_match\": { \"query\": \"" + value_s.get(0) + "\", \"type\": \"phrase\", \"fields\": ["; + for (String n: name_s) { + match += " \"" + n + "\","; + } + match = match.substring(0, match.length()-1); + match += " ] } },"; + if (logger.isDebugEnabled()) + logger.debug("Adding Match Line: " + match); + matches_s = matches_s + "\n " + match; + } else { + if (logger.isWarnEnabled()) + logger.warn("Defaulting to text search: different number of filter names and values"); + return search(type, text); + } + } + if (text != null && !text.isEmpty()) { + if (logger.isDebugEnabled()) + logger.debug("Adding Match Line for search text: " + text); + + final JsonObject jsonText = new JsonObject(); + jsonText.addProperty("_all", text); + String escapedText = jsonText.toString(); + + matches_s = matches_s + "\n " + + "{ \"match\": " + + escapedText + " },"; + } + matches_s = matches_s.substring(0, matches_s.length()-1); // remove last comma + matches_s = matches_s + "\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + + if (logger.isDebugEnabled()) { + logger.debug(matches_s); + } + + Builder searchBuilder = new Search.Builder(matches_s). + addIndex(ELK_INDEX_POLICY); + + if (type == null || type == PolicyIndexType.all) { + for (PolicyIndexType pT: PolicyIndexType.values()) { + if (pT != PolicyIndexType.all) { + searchBuilder.addType(pT.toString()); + } + } + } else { + searchBuilder.addType(type.toString()); + } + + Search search = searchBuilder.build(); + + JestResult result; + try { + result = jestClient.execute(search); + } catch (IOException ioe) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + search + ": " + ioe.getMessage(), ioe); + throw new IllegalStateException(ioe); + } + + if (result.isSucceeded()) { + if (logger.isInfoEnabled()) + logger.info("OK:" + result.getResponseCode() + ":" + search + ": " + + result.getPathToResult() + ":" + System.lineSeparator() + + result.getJsonString()); + } else { + /* Unsuccessful search */ + if (logger.isWarnEnabled()) + logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + ":" + + result.getResponseCode() + ": " + + search.getURI() + ":" + + result.getPathToResult() + ":" + + result.getJsonString() + ":" + + result.getErrorMessage()); + + String errorMessage = result.getErrorMessage(); + if (errorMessage != null && !errorMessage.isEmpty()) { + String xMessage = errorMessage; + if (errorMessage.contains("TokenMgrError")) { + int indexError = errorMessage.lastIndexOf("TokenMgrError"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("QueryParsingException")) { + int indexError = errorMessage.lastIndexOf("QueryParsingException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("JsonParseException")) { + int indexError = errorMessage.lastIndexOf("JsonParseException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("Parse Failure")) { + int indexError = errorMessage.lastIndexOf("Parse Failure"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else if (errorMessage.contains("SearchParseException")) { + int indexError = errorMessage.lastIndexOf("SearchParseException"); + xMessage = "Invalid Search Expression. Details: " + errorMessage.substring(indexError); + } else { + xMessage = result.getErrorMessage(); + } + throw new IllegalStateException(xMessage); + } + } + + return result; + } + + @Override + public JestResult policy(String policyId) + throws IllegalStateException, IllegalArgumentException { + if (logger.isTraceEnabled()) + logger.trace("ENTER: " + policyId); + + if (policyId == null || policyId.isEmpty()) { + throw new IllegalArgumentException("No policy id string provided"); + } + + Get policyRequest = new Get.Builder(ELK_INDEX_POLICY, policyId).build(); + + if (logger.isInfoEnabled()) + logger.info("ELK Search body request: " + policyRequest.toString()); + + JestResult result; + try { + result = jestClient.execute(policyRequest); + } catch (IOException ioe) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + policyId + ": " + ioe.getMessage(), ioe); + throw new IllegalStateException(ioe); + } + + if (result.isSucceeded()) { + if (logger.isInfoEnabled()) + logger.info("OK:" + result.getResponseCode() + ":" + policyId + ":" + + result.getPathToResult() + ":" + System.lineSeparator() + + result.getJsonString()); + + return result; + } + + /* Unsuccessful search */ + if (logger.isWarnEnabled()) + logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + ":" + + result.getResponseCode() + ": " + policyId + ":" + + result.getPathToResult() + ":" + + result.getErrorMessage()); + + return result; + } + + protected JsonObject getJsonObject(JsonObject jsonObject, String member) throws IllegalArgumentException { + if (jsonObject == null) { + if (logger.isWarnEnabled()) + logger.warn("No JSON object provided to get " + member); + + throw new IllegalArgumentException("No JSON Object provided"); + } + + if (logger.isTraceEnabled()) { + logger.trace("ENTER: " + member); + for (Entry<String, JsonElement> entry: jsonObject.entrySet()) { + logger.trace("JSONOBJECT: " + entry.getKey() + "->" + entry.getValue()); + } + } + + if (jsonObject.has(member)) { + JsonElement element = jsonObject.getAsJsonObject(member); + if (element.isJsonObject()) { + return (JsonObject) element; + } + } + + throw new IllegalArgumentException(member + " is not a JSON Object"); + } + + protected JsonArray getJsonArray(JsonObject jsonObject, String member) throws IllegalArgumentException { + if (jsonObject == null) { + throw new IllegalArgumentException("No JSON Object provided"); + } + + if (jsonObject.has(member)) { + if (jsonObject.get(member).isJsonArray()) { + return (JsonArray) jsonObject.get(member); + } + } + + throw new IllegalArgumentException(member + " is not a JSON Array"); + } + + protected String getJsonPolicyMember(JsonObject aHit, String member) throws IllegalArgumentException { + if (aHit == null) { + throw new IllegalArgumentException("No JSON Object provided"); + } + + JsonObject jSource = getJsonObject(aHit, "_source"); + JsonObject jPolicy = getJsonObject(jSource, "Policy"); + JsonElement jMember = jPolicy.get(member); + if (jMember == null) { + throw new IllegalArgumentException(member + " is not a JSON Object"); + } + return jMember.getAsString(); + } + + @Override + public ArrayList<PolicyLocator> policyLocators(PolicyIndexType indexType, String text, int connector) + throws IllegalStateException, IllegalArgumentException { + return policyLocators(indexType, text, new ArrayList<Pair<ArrayList<String>,ArrayList<String>>>(),connector); + } + + @Override + public ArrayList<PolicyLocator> policyLocators(PolicyIndexType indexType, + String text, + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s, int connector) + throws IllegalStateException, IllegalArgumentException { + final ArrayList<PolicyLocator> policyLocators = new ArrayList<PolicyLocator>(); + + JestResult results = searchKey(indexType, text, filter_s,connector); + if (!results.isSucceeded()) { + return policyLocators; + } + + JsonArray jsonHit_s = null; + try { + JsonObject jsonHits = getJsonObject(results.getJsonObject(), "hits"); + jsonHit_s = getJsonArray(jsonHits, "hits"); + } catch (IllegalArgumentException e) { + logger.warn("SEARCH:" + text + " no valid element provided", e); + return policyLocators; + } + + for (JsonElement e : jsonHit_s) { + JsonObject elkSource = (JsonObject) e; + try { + String policyType = getJsonPolicyMember(elkSource,"PolicyType"); + String policyName = getJsonPolicyMember(elkSource,"PolicyName"); + String owner = getJsonPolicyMember(elkSource,"Owner"); + String scope = getJsonPolicyMember(elkSource,"Scope"); + String policyId = getJsonPolicyMember(elkSource,"PolicyId"); + String version = getJsonPolicyMember(elkSource,"Version"); + PolicyLocator policyLocator = + new PolicyLocator(policyType, policyName, owner, + scope, policyId, version); + policyLocators.add(policyLocator); + if (logger.isInfoEnabled()) { + logger.info("SEARCH:" + text + "|FOUND:" + policyLocator); + } + } catch (IllegalArgumentException ex) { + logger.warn("SEARCH:" + text + " missing locator information.", ex); + } + } + return policyLocators; + } + + public boolean put(String record, PolicyType type, String id) + throws IOException, IllegalStateException { + if (logger.isTraceEnabled()) logger.trace("ENTER"); + + PolicyIndexType indexType; + try { + indexType = ElkConnector.toPolicyIndexType(type); + } catch (IllegalArgumentException e) { + throw new IllegalStateException("ELK: Index: " + ELK_INDEX_POLICY + + " Type: " + type + " :" + e.getMessage()); + } + + if (indexType == PolicyIndexType.all) { + throw new IllegalStateException("ELK: Index: " + ELK_INDEX_POLICY + + " Bad Type: " + type.toString()); + } + + if (!isType(indexType)) { + throw new IllegalStateException("ELK: Index: " + ELK_INDEX_POLICY + + " Type: " + type.toString() + + " is not configured"); + } + + Index elkPut = new Index.Builder(record). + index(ELK_INDEX_POLICY). + type(indexType.name()). + id(id). + build(); + + JestResult result = jestClient.execute(elkPut); + + if (result.isSucceeded()) { + if (logger.isInfoEnabled()) + logger.info("OK: PUT operation of " + type.name() + "->" + indexType + ":" + id + ": " + + "success=" + result.isSucceeded() + "[" + result.getResponseCode() + ":" + + result.getPathToResult() + "]" + System.lineSeparator() + + result.getJsonString()); + } else { + if (logger.isWarnEnabled()) + logger.warn("FAILURE: PUT operation of " + type.name() + "->" + indexType + ":" + id + ": " + + "success=" + result.isSucceeded() + "[" + result.getResponseCode() + ":" + + result.getPathToResult() + "]" + System.lineSeparator() + + result.getJsonString()); + + } + + return result.isSucceeded(); + } + + @Override + public boolean clone(String origPolicyId, String clonePolicyId) + throws IllegalStateException { + if (logger.isTraceEnabled()) logger.trace("ENTER"); + + String methodLog = "[" + + "original-policy-id:" + origPolicyId + "|" + + "cloned-policy-id:" + clonePolicyId + "]"; + + if (logger.isDebugEnabled()) + logger.debug(methodLog); + + if (origPolicyId == null || clonePolicyId == null || + origPolicyId.isEmpty() || clonePolicyId.isEmpty()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "Internal Error: original and cloned policy ids are identical: " + + origPolicyId + "->" + clonePolicyId + " :" + + methodLog); + throw new IllegalStateException(": " + "original and cloned policy ids are identical."); + } + + // GET original record + JestResult result = this.policy(origPolicyId); + if (!result.isSucceeded()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "Internal Error: not found policy id: " + + origPolicyId + " :" + + methodLog); + throw new IllegalStateException(": " + "policy id: " + origPolicyId + " not found"); + } + + try { + String policyId = getJsonPolicyMember(result.getJsonObject(),"PolicyId"); + String policyType = getJsonPolicyMember(result.getJsonObject(),"PolicyType"); + if (policyType == null || policyType.isEmpty()) { + throw new IllegalStateException(": " + origPolicyId + + " invalid policy type: " + policyType); + } + PolicyType policyTypeEnum = PolicyType.valueOf(policyType); + String newPolicyId = policyId.replace(origPolicyId, clonePolicyId); + + JsonObject jsonSource = getJsonObject(result.getJsonObject(), "_source"); + JsonObject jsonPolicy = getJsonObject(jsonSource, "Policy"); + jsonPolicy.addProperty("PolicyId", newPolicyId); + String sourcePolicy = new Gson().toJson(jsonPolicy); + return put(sourcePolicy, policyTypeEnum, clonePolicyId); + } catch (IllegalArgumentException e) { + logger.warn("POLICY-SEARCH:" + origPolicyId + " not properly found", e); + throw new IllegalStateException(": " + origPolicyId + " not found in ELK"); + } catch (IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "cannot create searchable record for " + methodLog + + ". Reason: " + e.getMessage(), e); + throw new IllegalStateException(": Communication Problem with ELK server"); + } + } + + @Override + public boolean delete(File xacmlFile) throws IllegalStateException { + if (logger.isDebugEnabled()) + logger.debug("ENTER: " + "[xacml-file:" + + ((xacmlFile != null) ? xacmlFile.getPath() : "null")+ "]"); + + if (xacmlFile == null || !xacmlFile.canRead()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "Internal Error: invalid arguments provided: " + + ((xacmlFile != null) ? xacmlFile.getPath() : "null")+ "]"); + throw new IllegalStateException(": " + "Invalid arguments to convert to ELK format."); + } + + String policyId = ""; + PolicyIndexType indexType = null; + JestResult result; + try { + indexType = ElkConnector.toPolicyIndexType(xacmlFile.getName()); + if (!isType(indexType)) { + throw new IllegalStateException("ELK: Index: " + ELK_INDEX_POLICY + + " Type: " + indexType + + " is not configured"); + } + Xacml2Elk searchablePolicy = new Xacml2Elk(xacmlFile, true); + policyId = searchablePolicy.getPolicy().getValue().getPolicyId(); + policyId = policyId.substring(policyId.lastIndexOf(":")+1); + Delete deleteRequest = + new Delete.Builder(policyId).index(ELK_INDEX_POLICY). + type(indexType.name()).build(); + result = jestClient.execute(deleteRequest); + } catch (IllegalArgumentException | IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ": delete:" + + ((indexType != null) ? indexType.name() : "null") + ":" + policyId + ": " + + e.getMessage(), e); + throw new IllegalStateException(e); + } + + if (result.isSucceeded()) { + if (logger.isInfoEnabled()) + logger.info("OK: DELETE operation of " + indexType + ":" + policyId + ": " + + "success=" + result.isSucceeded() + "[" + result.getResponseCode() + ":" + + result.getPathToResult() + "]" + System.lineSeparator() + + result.getJsonString()); + } else { + if (logger.isWarnEnabled()) + logger.warn("FAILURE: DELETE operation of " + indexType + ":" + policyId + ": " + + "success=" + result.isSucceeded() + "[" + result.getResponseCode() + ":" + + result.getPathToResult() + "]" + System.lineSeparator() + + result.getJsonString()); + } + + return result.isSucceeded(); + } + + @Override + public ElkRecord create(PolicyType policyType, + String name, + String owner, + String scope, + File xacmlFile, + PolicyBodyType bodyType, + String body, + File destinationDir) + throws IllegalStateException { + if (logger.isTraceEnabled()) logger.trace("ENTER"); + + String methodLog = "[" + + "type:" + policyType.name() + "|" + + "owner:" + owner + "|" + + "scope:" + scope + "|" + + "xacml-file:" + ((xacmlFile != null) ? xacmlFile.getPath() : "null")+ "|" + + "body-type:" + bodyType.name() + "|" + + "body:" + body + "|" + + "destination-dir:" + ((destinationDir != null) ? destinationDir.getPath() : "null")+ "]"; + + if (logger.isDebugEnabled()) + logger.debug(methodLog); + + if (policyType == null || name == null || owner == null || scope == null || + xacmlFile == null) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "Internal Error: invalid arguments provided for " + methodLog); + throw new IllegalStateException(": " + "Invalid arguments to convert to ELK format."); + } + + try { + Xacml2Elk searchablePolicy = + new Xacml2Elk(policyType.name(), + name, + owner, + scope, + xacmlFile, + bodyType, + body, + destinationDir); + ElkRecord elkRecord = searchablePolicy.record(); + put(elkRecord.record, policyType, elkRecord.policyId); + return elkRecord; + } catch (JAXBException | JsonProcessingException | IllegalArgumentException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "cannot create searchable record for " + methodLog + + ". Reason: " + e.getMessage(), e); + throw new IllegalStateException(": " + "Error encountered converting to ELK format."); + } catch (IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "cannot create searchable record for " + methodLog + + ". Reason: " + e.getMessage(), e); + throw new IllegalStateException(": " + "Communication Problem with ELK server."); + } + } + + @Override + public boolean update(File xacmlFile) throws IllegalStateException { + if (logger.isDebugEnabled()) + logger.debug("ENTER: " + "[xacml-file:" + + ((xacmlFile != null) ? xacmlFile.getPath() : "null")+ "]"); + + if (xacmlFile == null || !xacmlFile.canRead()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "Internal Error: invalid arguments provided: " + + ((xacmlFile != null) ? xacmlFile.getPath() : "null")+ "]"); + throw new IllegalStateException(": " + "Invalid arguments to convert to ELK format."); + } + + Xacml2Elk searchablePolicy = new Xacml2Elk(xacmlFile, false); + return update(xacmlFile, searchablePolicy); + } + + protected boolean update(File xacmlFile, Xacml2Elk searchablePolicy) throws IllegalStateException { + if (logger.isDebugEnabled()) + logger.debug("ENTER"); + + try { + ElkRecord elkRecord = searchablePolicy.record(); + boolean success = put(elkRecord.record, ElkConnector.toPolicyType(xacmlFile.getName()), elkRecord.policyId); + return success; + } catch (JAXBException | JsonProcessingException | IllegalArgumentException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "cannot create searchable record for " + xacmlFile.getAbsolutePath() + + ". Reason: " + e.getMessage(), e); + throw new IllegalStateException(": " + "Error encountered converting to ELK format for " + + xacmlFile.getAbsolutePath()); + } catch (IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "cannot create ELK searchable record for " + xacmlFile.getAbsolutePath() + + ". Reason: " + e.getMessage(), e); + throw new IllegalStateException(": " + "Communication Problem with ELK server."); + } catch (IllegalStateException e) { + /* unexpected */ + throw e; + } catch (Exception e) { + logger.warn(XACMLErrorConstants.ERROR_UNKNOWN + ":" + "cannot test and update", e); + throw new IllegalStateException(e); + } + } + + @Override + public boolean testAndUpdate(File xacmlFile) throws IllegalStateException { + if (logger.isDebugEnabled()) + logger.debug("ENTER: " + "[xacml-file:" + + ((xacmlFile != null) ? xacmlFile.getPath() : "null")+ "]"); + + if (xacmlFile == null || !xacmlFile.canRead()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "Internal Error: invalid arguments provided: " + + ((xacmlFile != null) ? xacmlFile.getPath() : "null")+ "]"); + throw new IllegalStateException(": " + "Invalid arguments to convert to ELK format."); + } + + try { + Xacml2Elk searchablePolicy = new Xacml2Elk(xacmlFile, true); + String policyId = searchablePolicy.getPolicy().getValue().getPolicyId(); + policyId = policyId.substring(policyId.lastIndexOf(":")+1); + JestResult result = this.policy(policyId); + if (result.isSucceeded()) { + logger.info("Policy exists: " + policyId); + + /* validation tests */ + + String policyType = getJsonPolicyMember(result.getJsonObject(), "PolicyType"); + String scope = getJsonPolicyMember(result.getJsonObject(), "Scope"); + String policyName = getJsonPolicyMember(result.getJsonObject(), "PolicyName"); + if (policyType == null || policyType.isEmpty() || + scope == null || scope.isEmpty() || + policyName == null || policyName.isEmpty()) { + logger.warn("Policy metadata not found. Updating record .."); + update(xacmlFile, searchablePolicy); + return false; + } + + if (!xacmlFile.getName().startsWith(policyType)) { + logger.warn(xacmlFile.getName() + " does not match Policy Type: " + + policyType); + update(xacmlFile, searchablePolicy); + return false; + } + + java.nio.file.Path xacmlElkPath = Paths.get(scope, policyType + "_" + policyName + ".xml"); + java.nio.file.Path xacmlPath = xacmlFile.toPath(); + + if (logger.isDebugEnabled()) { + logger.debug(xacmlElkPath + " in " + xacmlElkPath + "? "); + } + + if (!xacmlPath.endsWith(xacmlElkPath)) { + logger.warn(xacmlPath + " does not match ELK inferred path: " + + xacmlElkPath); + update(xacmlFile, searchablePolicy); + return false; + } + + if (logger.isInfoEnabled()) { + logger.warn("OK: " + xacmlPath + " matches ELK inferred path: " + + xacmlElkPath); + } + return true; + } else { + logger.info("Policy ID not found. Adding to database: " + policyId); + update(xacmlFile, searchablePolicy); + return false; + } + } catch (Exception e) { + logger.warn(XACMLErrorConstants.ERROR_UNKNOWN + ":" + "cannot test and update", e); + throw new IllegalStateException(e); + } + } +}
\ No newline at end of file diff --git a/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/Pair.java b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/Pair.java new file mode 100644 index 000000000..3c7b9951d --- /dev/null +++ b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/Pair.java @@ -0,0 +1,35 @@ +/*- + * ============LICENSE_START======================================================= + * ECOMP Policy Engine + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.policy.elk.client; + + +public class Pair<L,R> { + private L left; + private R right; + public Pair(L l, R r){ + this.left = l; + this.right = r; + } + public L left(){ return left; } + public R right(){ return right; } + public void left(L l){ this.left = l; } + public void right(R r){ this.right = r; } +} diff --git a/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/PolicyElasticSearchController.java b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/PolicyElasticSearchController.java new file mode 100644 index 000000000..ee745236f --- /dev/null +++ b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/PolicyElasticSearchController.java @@ -0,0 +1,756 @@ +/*- + * ============LICENSE_START======================================================= + * ECOMP Policy Engine + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.policy.elk.client; + + +import java.io.File; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.json.JSONObject; +import org.openecomp.policy.adapter.ClosedLoopPerformanceMetrics; +import org.openecomp.policy.adapter.ClosedLoopPolicy; +import org.openecomp.policy.dao.PolicyVersionDao; +import org.openecomp.policy.elk.client.ElkConnector.PolicyIndexType; +import org.openecomp.policy.rest.dao.DescriptiveScopeDao; +import org.openecomp.policy.rest.jpa.ActionPolicyDict; +import org.openecomp.policy.rest.jpa.Attribute; +import org.openecomp.policy.rest.jpa.BRMSParamTemplate; +import org.openecomp.policy.rest.jpa.ClosedLoopD2Services; +import org.openecomp.policy.rest.jpa.ClosedLoopSite; +import org.openecomp.policy.rest.jpa.DCAEuuid; +import org.openecomp.policy.rest.jpa.DecisionSettings; +import org.openecomp.policy.rest.jpa.DescriptiveScope; +import org.openecomp.policy.rest.jpa.EcompName; +import org.openecomp.policy.rest.jpa.EnforcingType; +import org.openecomp.policy.rest.jpa.GroupPolicyScopeList; +import org.openecomp.policy.rest.jpa.MicroServiceLocation; +import org.openecomp.policy.rest.jpa.MicroServiceModels; +import org.openecomp.policy.rest.jpa.PEPOptions; +import org.openecomp.policy.rest.jpa.PolicyVersion; +import org.openecomp.policy.rest.jpa.RiskType; +import org.openecomp.policy.rest.jpa.SafePolicyWarning; +import org.openecomp.policy.rest.jpa.TermList; +import org.openecomp.policy.rest.jpa.VNFType; +import org.openecomp.policy.rest.jpa.VSCLAction; +import org.openecomp.policy.rest.jpa.VarbindDictionary; +import org.openecomp.portalsdk.core.controller.RestrictedBaseController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; + +import org.openecomp.policy.xacml.api.XACMLErrorConstants; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Controller +@RequestMapping({"/"}) +public class PolicyElasticSearchController extends RestrictedBaseController{ + + private static final Logger logger = FlexLogger.getLogger(PolicyElasticSearchController.class); + private volatile HashMap<Path, String> filteredPolicies = new HashMap<Path, String>(); + private List<JSONObject> policyNames = null; + + enum Mode{ + attribute, ecompName, actionPolicy, brmsParam, pepOptions, clSite, clService, clVarbind, clVnf, clVSCL, decision, enforcer, fwTerm, gocEventAlarm, + gocTraversal, gocRootCause, gocVnfType, gocServerScope, gocHPEventSource, msDCAEUUID, msConfigName, msLocation, msModels, + psGroupPolicy, safeRisk, safePolicyWarning + } + + public static final HashMap<String, String> name2jsonPath = new HashMap<String, String>() { + private static final long serialVersionUID = 1L; + { + put(ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_TRINITY, ClosedLoopPolicy.CLFAULT_UIJSON_D2_SERVICES_TRINITY); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_VUSP, ClosedLoopPolicy.CLFAULT_UIJSON_D2_SERVICES_VUSP); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_MCR, ClosedLoopPolicy.CLFAULT_UIJSON_D2_SERVICES_MCR); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_GAMMA, ClosedLoopPolicy.CLFAULT_UIJSON_D2_SERVICES_GAMMA); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_VDNS, ClosedLoopPolicy.CLFAULT_UIJSON_D2_SERVICES_VDNS); + + put(ClosedLoopPolicy.CLFAULT_UIFIELD_EMAIL_ADDRESS, ClosedLoopPolicy.CLFAULT_UIJSON_EMAIL_ADDRESS); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_TRIGGER_SIGNATURE, ClosedLoopPolicy.CLFAULT_UIJSON_TRIGGER_SIGNATURE); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_VERIFICATION_SIGNATURE, ClosedLoopPolicy.CLFAULT_UIJSON_VERIFICATION_SIGNATURE); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_CONNECT_ALL_TRAPS, ClosedLoopPolicy.CLFAULT_UIJSON_CONNECT_ALL_TRAPS); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_CONNECT_ALL_FAULTS, ClosedLoopPolicy.CLFAULT_UIJSON_CONNECT_ALL_FAULTS); + + put(ClosedLoopPolicy.CLFAULT_UIFIELD_POLICY_STATUS_INACTIVE, ClosedLoopPolicy.CLFAULT_UIJSON_POLICY_STATUS_ACTIVE); + put(ClosedLoopPolicy.CLFAULT_UIFIELD_POLICY_STATUS_ACTIVE, ClosedLoopPolicy.CLFAULT_UIJSON_POLICY_STATUS_INACTIVE); + + put(ClosedLoopPerformanceMetrics.CLPM_UIFIELD_ONSET_MESSAGE, ClosedLoopPerformanceMetrics.CLPM_UIJSON_ONSET_MESSAGE); + put(ClosedLoopPerformanceMetrics.CLPM_UIFIELD_POLICY_NAME, ClosedLoopPerformanceMetrics.CLPM_UIJSON_POLICY_NAME); + put(ClosedLoopPerformanceMetrics.CLPM_UIFIELD_ABATEMENT_MESSAGE, ClosedLoopPerformanceMetrics.CLPM_UIJSON_ABATEMENT_MESSAGE); + put(ClosedLoopPerformanceMetrics.CLPM_UIFIELD_GEOLINK, ClosedLoopPerformanceMetrics.CLPM_UIJSON_GEOLINK); + }}; + + + //For AND and OR logical connector AND=0 and OR=1 + private int connectorSelected; + + public static DescriptiveScopeDao descriptiveScopeDao; + public static PolicyVersionDao policyVersionDao; + + @Autowired + public PolicyElasticSearchController(DescriptiveScopeDao descriptiveScopeDao, PolicyVersionDao policyVersionDao) { + PolicyElasticSearchController.descriptiveScopeDao = descriptiveScopeDao; + PolicyElasticSearchController.policyVersionDao = policyVersionDao; + + } + + public PolicyElasticSearchController() { + } + + @RequestMapping(value={"/searchPolicy"}, method={org.springframework.web.bind.annotation.RequestMethod.POST}) + public ModelAndView searchPolicy(HttpServletRequest request, HttpServletResponse response) throws Exception{ + List<JSONObject> resultList = new ArrayList<JSONObject>(); + try { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + JsonNode root = mapper.readTree(request.getReader()); + SearchData searchData = (SearchData)mapper.readValue(root.get("searchdata").toString(), SearchData.class); + + String policyType = searchData.getPolicyType(); + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s = new ArrayList<Pair<ArrayList<String>,ArrayList<String>>>(); + + String searchText = searchData.getQuery(); + if (searchText == null || searchText.isEmpty()) { + String descriptiveValue = searchData.getDescriptiveScope(); + if(descriptiveValue != null){ + searchText = "Descriptive-Scope="+descriptiveValue; + } + if (policyType == null || policyType.isEmpty() && + !policyType.equals(ElkConnector.PolicyIndexType.closedloop.toString())) { + if (logger.isDebugEnabled()) { + logger.debug("Clearing search filters, nothing to search and not closed loop."); + } + } + } else { + searchText = searchText.trim(); + //Descriptive Scope. + /* + When a item is selected in the "descriptiveScope" comboBox, the name of the item + is added to the Search-Text Box with the prefix "Descriptive-Scope" + User needs to press the "Search" button to perform the search. + */ + if(searchText.contains("Descriptive-Scope=")){ + if (logger.isDebugEnabled()) { + logger.debug("Inside the Descriptive Scope"); + } + /* + First item is always String "Descriptive-Scope" before the "=", + So taking the second item of "split using =" + */ + String[] dsName= searchText.split("=",2); + /* + Trying to find the search String by traversing different items from the dictionary by Scope-Name + Once when the the "scope-name" is found, we get the search string from dictionary. + */ + if(searchData.getDescriptiveScope() != null){ + DescriptiveScope dsSearch = descriptiveScopeDao.getDescriptiveScopeById(searchData.getDescriptiveScope()); + if(dsSearch.getScopeName().equals(dsName[1])){ + searchText=dsSearch.getSearch(); + if (logger.isDebugEnabled()) { + logger.debug("DescriptiveScope Search String is " +searchText ); + } + } + } + + } + // '&' turned to "AND" to make it inline with Freeform search. + if(searchText.contains(":")){ + String connector="AND"; + if(searchText.contains("AND")){ + connector="AND"; + connectorSelected=0; + }else if(searchText.contains("OR")){ + connector=Pattern.quote("OR"); + connectorSelected=1; + } + for (String retval: searchText.split(connector)){ + + int index= retval.indexOf(':'); + String filterKey=null; + String filterValue=null; + + filterKey=retval.substring(0,index).trim(); + filterValue= retval.substring(index+1).trim(); + + logger.debug("Key is "+filterKey+" and value is "+filterValue); + String clSearchBoxFilter=filterKey; + + ArrayList<String> clSearchBoxFilterField_s = new ArrayList<String>(); + + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_Fault.name() + "_Body." + clSearchBoxFilter); + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_PM.name() + "_Body." + clSearchBoxFilter); + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_FW.name() + "_Body." + clSearchBoxFilter); + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_MS.name() + "_Body." + clSearchBoxFilter); + + + ArrayList<String> clSearchBoxFilterValue_s = new ArrayList<String>(); + clSearchBoxFilterValue_s.add(filterValue); + + filter_s.add(new Pair<ArrayList<String>,ArrayList<String>>(clSearchBoxFilterField_s, clSearchBoxFilterValue_s)); + } + } + } + + if (policyType != null && !policyType.isEmpty() && + policyType.equals(ElkConnector.PolicyIndexType.closedloop.toString())) { + + /* closed loop policy type */ + + String clPolicyType = searchData.getClosedLooppolicyType(); + if (clPolicyType != null && !clPolicyType.isEmpty()) { + ArrayList<String> clPolicyTypeField_s = new ArrayList<String>(); + clPolicyTypeField_s.add("Policy.PolicyType"); + + ArrayList<String> clPolicyTypeValue_s = new ArrayList<String>(); + clPolicyTypeValue_s.add(clPolicyType); + + filter_s.add(new Pair<ArrayList<String>,ArrayList<String>>(clPolicyTypeField_s, clPolicyTypeValue_s)); + } + + String clEcompName = searchData.getEcompName(); + if (clEcompName != null && !clEcompName.isEmpty()) { + clSearchBody(clPolicyType, "ecompname", clEcompName, filter_s); + } + + String clD2Services = searchData.getD2Service(); + if (clD2Services != null && !clD2Services.isEmpty()) { + switch (clD2Services) { + case ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_TRINITY: + case ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_VUSP: + case ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_MCR: + case ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_GAMMA: + case ClosedLoopPolicy.CLFAULT_UIFIELD_D2_SERVICES_VDNS: + clSearchBody(clPolicyType, name2jsonPath.get(clD2Services), "true", filter_s); + break; + default: + if (logger.isWarnEnabled()) + logger.warn("Unexpected D2 Service: " + clD2Services); + break; + } + } + + String clFaultAction = searchData.getVproAction(); + if (clFaultAction != null && !clFaultAction.isEmpty()) { + if (clPolicyType == null || clPolicyType.equals(ElkConnector.PolicyType.Config_Fault.name())) { + clSearchFilter(ElkConnector.PolicyType.Config_Fault.name(), "actions", clFaultAction, filter_s); + } + } + + String clFaultStatus = searchData.getPolicyStatus(); + if (clFaultStatus != null && !clFaultStatus.isEmpty()) { + if (clPolicyType == null || clPolicyType.equals(ElkConnector.PolicyType.Config_Fault.name())) { + clSearchFilter(ElkConnector.PolicyType.Config_Fault.name(), "closedLoopPolicyStatus", clFaultStatus, filter_s); + } + } + + String clFaultVnfTypes = searchData.getVnfType(); + if (clFaultVnfTypes != null && !clFaultVnfTypes.isEmpty()) { + if (clPolicyType == null || clPolicyType.equals(ElkConnector.PolicyType.Config_Fault.name())) { + clSearchFilter(ElkConnector.PolicyType.Config_Fault.name(), "vnfType", clFaultVnfTypes, filter_s); + } + } + + String clPMServiceType = searchData.getServiceType(); + if (clPMServiceType != null && !clPMServiceType.isEmpty()) { + if (clPolicyType == null || clPolicyType.equals(ElkConnector.PolicyType.Config_PM.name())) { + clSearchFilter(ElkConnector.PolicyType.Config_PM.name(), "serviceTypePolicyName", clPMServiceType, filter_s); + } + } + + String clSearchBoxFilter = searchData.getBindTextSearch(); + if (clSearchBoxFilter != null && !clSearchBoxFilter.isEmpty() && + searchText != null && !searchText.isEmpty()) { + + if (name2jsonPath.containsKey(clSearchBoxFilter)) { + clSearchBoxFilter = name2jsonPath.get(clSearchBoxFilter); + } + + ArrayList<String> clSearchBoxFilterField_s = new ArrayList<String>(); + if (clPolicyType == null || clPolicyType.isEmpty()) { + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_Fault.name() + "_Body." + clSearchBoxFilter); + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_PM.name() + "_Body." + clSearchBoxFilter); + } else { + clSearchBoxFilterField_s.add("Policy.Body." + clPolicyType + "_Body." + clSearchBoxFilter); + } + + ArrayList<String> clSearchBoxFilterValue_s = new ArrayList<String>(); + clSearchBoxFilterValue_s.add(searchText); + + filter_s.add(new Pair<ArrayList<String>,ArrayList<String>>(clSearchBoxFilterField_s, clSearchBoxFilterValue_s)); + + // deactivate search all fields in case a searchbox filter is provided + searchText = ""; + } + } + + if ((searchText == null || searchText.isEmpty()) && + (filter_s == null || filter_s.size() <=0) ) { + if (logger.isWarnEnabled()) { + logger.warn("Clearing search filters, closed loop but nothing to search nor filters"); + } + } + + ArrayList<PolicyLocator> locators = null; + try { + locators = ElkConnector.singleton.policyLocators(toPolicyIndexType(policyType), + searchText, filter_s,connectorSelected); + } catch (Exception ise) { + logger.warn("Search is unavailable: " + ise.getMessage()); + } + + synchronized(this.filteredPolicies) { + if (locators.isEmpty()) { + if (logger.isInfoEnabled()) { + logger.info("No match has been found"); + } + logger.warn("No match has been found"); + } + + HashMap<String, Boolean> policyVersion_s = new HashMap<String, Boolean>(); + List<PolicyVersion> policyVersionList = policyVersionDao.getPolicyVersionData(); + for(int i = 0; i < policyVersionList.size(); i++) { + PolicyVersion entityVersion = policyVersionList.get(i); + String dbPolicy = entityVersion.getPolicyName() + "." + entityVersion.getActiveVersion(); + policyVersion_s.put(dbPolicy, true); + if (logger.isDebugEnabled()) + logger.debug("Map addition: DB Policy Name: " + dbPolicy); + } + + this.filteredPolicies.clear(); + for (PolicyLocator p: locators) { + String dbPolicyName = p.scope + File.separator + p.policyType + "_" + p.policyName; + if (policyVersion_s.containsKey(dbPolicyName)) { + String filterPolicyName = dbPolicyName + ".xml"; + this.filteredPolicies.put(Paths.get(filterPolicyName), filterPolicyName); + JSONObject el = new JSONObject(); + el.put("name", dbPolicyName); + resultList.add(el); + if (logger.isInfoEnabled()) + logger.info("Active Version Policy found in search: " + dbPolicyName + " -> " + filterPolicyName); + } else { + if (logger.isInfoEnabled()) + logger.info("Inactive Version Policy found in search: " + dbPolicyName); + } + } + + if (this.filteredPolicies.isEmpty()) { + if (logger.isInfoEnabled()) { + logger.info("No match has been found for active versions"); + } + JSONObject result = new JSONObject(); + result.put("success", false); + result.put("error", "No match has been found for active versions"); + resultList.add(result); + logger.warn("No match has been found for active versions"); + + } + + System.out.println(this.filteredPolicies); + } + + response.setCharacterEncoding("UTF-8"); + response.setContentType("application / json"); + request.setCharacterEncoding("UTF-8"); + + PrintWriter out = response.getWriter(); + JSONObject j = new JSONObject("{result: " + resultList + "}"); + out.write(j.toString()); + return null; + }catch(Exception e){ + response.setCharacterEncoding("UTF-8"); + request.setCharacterEncoding("UTF-8"); + PrintWriter out = response.getWriter(); + out.write(e.getMessage()); + } + return null; + } + + protected void clSearchBody(String clPolicyType, String bodyField, String bodyValue, + ArrayList<Pair<ArrayList<String>, ArrayList<String>>> filter_s) { + if (logger.isDebugEnabled()) + logger.debug("ENTER: " + clPolicyType + ":" + bodyField + ":" + bodyValue); + + final ArrayList<String> clBodyField_s = new ArrayList<String>(); + final ArrayList<String> clBodyValue_s = new ArrayList<String>(); + + if (clPolicyType == null || clPolicyType.isEmpty()) { + clBodyField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_Fault.name() + "_Body." + bodyField); + clBodyField_s.add("Policy.Body."+ ElkConnector.PolicyType.Config_PM.name() + "_Body." + bodyField); + clBodyValue_s.add(bodyValue); + } else { + clBodyField_s.add("Policy.Body." + clPolicyType + "_Body." + bodyField); + clBodyValue_s.add(bodyValue); + } + filter_s.add(new Pair<ArrayList<String>, ArrayList<String>>(clBodyField_s, clBodyValue_s)); + } + + protected void clSearchFilter(String clType, String clField, String clValue, + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s) { + if (logger.isDebugEnabled()) + logger.debug("ENTER: " + clType + ":" + clField + ":" + clValue); + + ArrayList<String> clSearchField_s = new ArrayList<String>(); + clSearchField_s.add("Policy.Body." + clType + "_Body." + clField); + + ArrayList<String> clSearchValue_s = new ArrayList<String>(); + clSearchValue_s.add(clValue); + + filter_s.add(new Pair<ArrayList<String>,ArrayList<String>>(clSearchField_s, clSearchValue_s)); + } + + public ElkConnector.PolicyIndexType toPolicyIndexType(String type) throws IllegalArgumentException { + if (type == null || type.isEmpty()) + return PolicyIndexType.all; + + return PolicyIndexType.valueOf(type); + } + + public boolean updateElk(String xacmlFilePath) { + boolean success = true; + try { + File xacmlPolicy = new File(xacmlFilePath); + success = ElkConnector.singleton.update(xacmlPolicy); + if (!success) { + if (logger.isWarnEnabled()) { + logger.warn("FAILURE to create ELK record created for " + xacmlPolicy.getPath()); + } + } else { + if (logger.isInfoEnabled()) { + logger.warn("SUCCESS creating ELK record created for " + xacmlPolicy.getPath()); + } + } + } catch (Exception e) { + logger.warn(XACMLErrorConstants.ERROR_DATA_ISSUE + ": " + e.getMessage(), e); + success = false; + } + return success; + } + + @RequestMapping(value={"/searchDictionary"}, method={org.springframework.web.bind.annotation.RequestMethod.POST}) + public ModelAndView searchDictionary(HttpServletRequest request, HttpServletResponse response) throws Exception{ + try{ + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + JsonNode root = mapper.readTree(request.getReader()); + String dictionaryType = root.get("type").textValue(); + Mode mode = Mode.valueOf(dictionaryType); + String value; + String msg; + switch (mode){ + case attribute : + Attribute attributedata = (Attribute)mapper.readValue(root.get("data").toString(), Attribute.class); + value = attributedata.getXacmlId(); + msg = searchElkDatabase("pholder",value); + break; + case ecompName : + EcompName ecompName = (EcompName)mapper.readValue(root.get("data").toString(), EcompName.class); + value = ecompName.getEcompName(); + msg = searchElkDatabase("pholder",value); + break; + case actionPolicy : + ActionPolicyDict actionPolicyDict = (ActionPolicyDict)mapper.readValue(root.get("data").toString(), ActionPolicyDict.class); + value = actionPolicyDict.getAttributeName(); + msg = searchElkDatabase("pholder",value); + break; + case brmsParam : + BRMSParamTemplate bRMSParamTemplate = (BRMSParamTemplate)mapper.readValue(root.get("data").toString(), BRMSParamTemplate.class); + value = bRMSParamTemplate.getRuleName(); + msg = searchElkDatabase("BRMSParamTemplate AND " + value); + break; + case pepOptions : + PEPOptions pEPOptions = (PEPOptions)mapper.readValue(root.get("data").toString(), PEPOptions.class); + value = pEPOptions.getPepName(); + msg = searchElkDatabase("pepName",value); + break; + case clSite : + ClosedLoopSite closedLoopSite = (ClosedLoopSite)mapper.readValue(root.get("data").toString(), ClosedLoopSite.class); + value = closedLoopSite.getSiteName(); + msg = searchElkDatabase("siteNames",value); + break; + case clService : + ClosedLoopD2Services closedLoopD2Services = (ClosedLoopD2Services)mapper.readValue(root.get("data").toString(), ClosedLoopD2Services.class); + value = closedLoopD2Services.getServiceName(); + msg = searchElkDatabase("d2Services",value); + break; + case clVarbind : + VarbindDictionary varbindDictionary = (VarbindDictionary)mapper.readValue(root.get("data").toString(), VarbindDictionary.class); + value = varbindDictionary.getVarbindName(); + msg = searchElkDatabase("triggerSignaturesUsedForUI.signatures",value); + break; + case clVnf : + VNFType vNFType = (VNFType)mapper.readValue(root.get("data").toString(), VNFType.class); + value = vNFType.getVnftype(); + msg = searchElkDatabase("vnfType",value); + break; + case clVSCL : + VSCLAction vsclAction = (VSCLAction)mapper.readValue(root.get("data").toString(), VSCLAction.class); + value = vsclAction.getVsclaction(); + msg = searchElkDatabase("actions",value); + break; + case decision : + DecisionSettings decisionSettings = (DecisionSettings)mapper.readValue(root.get("data").toString(), DecisionSettings.class); + value = decisionSettings.getXacmlId(); + msg = searchElkDatabase("pholder",value); + break; + case enforcer : + EnforcingType enforcingType = (EnforcingType)mapper.readValue(root.get("data").toString(), EnforcingType.class); + value = enforcingType.getEnforcingType(); + msg = searchElkDatabase("pholder",value); + break; + case fwTerm : + TermList term = (TermList)mapper.readValue(root.get("data").toString(), TermList.class); + value = term.getTermName(); + msg = searchElkDatabase("firewallRuleList.ruleName",value); + break; + case msDCAEUUID : + DCAEuuid dcaeUUID = (DCAEuuid)mapper.readValue(root.get("data").toString(), DCAEuuid.class); + value = dcaeUUID.getName(); + msg = searchElkDatabase("uuid",value); + break; + case msLocation : + MicroServiceLocation mslocation = (MicroServiceLocation)mapper.readValue(root.get("data").toString(), MicroServiceLocation.class); + value = mslocation.getName(); + msg = searchElkDatabase("location",value); + break; + case msModels : + MicroServiceModels msModels = (MicroServiceModels)mapper.readValue(root.get("data").toString(), MicroServiceModels.class); + value = msModels.getModelName(); + msg = searchElkDatabase("configName",value); + break; + case psGroupPolicy : + GroupPolicyScopeList groupPoilicy = (GroupPolicyScopeList)mapper.readValue(root.get("data").toString(), GroupPolicyScopeList.class); + value = groupPoilicy.getGroupName(); + msg = searchElkDatabase("PolicyScope",value); + break; + case safeRisk : + RiskType riskType= (RiskType)mapper.readValue(root.get("data").toString(), RiskType.class); + value = riskType.getRiskName(); + msg = searchElkDatabase("Risk Type",value); + break; + case safePolicyWarning : + SafePolicyWarning safePolicy = (SafePolicyWarning)mapper.readValue(root.get("data").toString(), SafePolicyWarning.class); + value = safePolicy.getName(); + msg = searchElkDatabase("Safe Warning",value); + break; + default: + } + response.setCharacterEncoding("UTF-8"); + response.setContentType("application / json"); + request.setCharacterEncoding("UTF-8"); + + PrintWriter out = response.getWriter(); + JSONObject j = new JSONObject("{result: " + policyNames + "}"); + out.write(j.toString()); + return null; + }catch(Exception e){ + response.setCharacterEncoding("UTF-8"); + request.setCharacterEncoding("UTF-8"); + PrintWriter out = response.getWriter(); + out.write(e.getMessage()); + } + return null; + } + + //Search Elk database + public String searchElkDatabase(String value){ + String policyType = ""; + String searchText = value; + ArrayList<PolicyLocator> locators; + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s = new ArrayList<Pair<ArrayList<String>,ArrayList<String>>>(); + try { + locators = ElkConnector.singleton.policyLocators(toPolicyIndexType(policyType), searchText, filter_s,0); + } catch (Exception ise) { + logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR+"Search is unavailable: " + ise.getMessage()); + value = "$notSuccess%"; + return value; + } + policyNames = new ArrayList<JSONObject>(); + for (PolicyLocator p: locators) { + String dbPolicyName = p.scope + "/" + p.policyType + "_" + p.policyName + "." +p.version + ".xml"; + logger.debug(dbPolicyName); + JSONObject el = new JSONObject(); + el.put("name", dbPolicyName); + policyNames.add(el); + } + if(!locators.isEmpty()){ + value = "$success%"; + return value; + } + return value; + } + + //Search the Elk database + public String searchElkDatabase(String key, String value){ + String policyType = ""; + String searchText = key+":"+value; + ArrayList<PolicyLocator> locators; + ArrayList<Pair<ArrayList<String>,ArrayList<String>>> filter_s = new ArrayList<Pair<ArrayList<String>,ArrayList<String>>>(); + logger.debug("Parameter value is"+value); + + String clSearchKey=null; + clSearchKey=key; + + logger.debug("Filter value is"+clSearchKey); + + ArrayList<String> clSearchBoxFilterField_s = new ArrayList<String>(); + + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_Fault.name() + "_Body." + clSearchKey); + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_PM.name() + "_Body." + clSearchKey); + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_FW.name() + "_Body." + clSearchKey); + clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_MS.name() + "_Body." + clSearchKey); + //clSearchBoxFilterField_s.add("Policy.Body." + ElkConnector.PolicyType.Config_PM.name() + "_Body." + clSearchKey); + + String clSearchValue=null; + clSearchValue=value; + + logger.debug("Search value is"+clSearchValue); + + ArrayList<String> clSearchBoxFilterValue_s = new ArrayList<String>(); + clSearchBoxFilterValue_s.add(clSearchValue); + + filter_s.add(new Pair<ArrayList<String>,ArrayList<String>>(clSearchBoxFilterField_s, clSearchBoxFilterValue_s)); + + try { + locators = ElkConnector.singleton.policyLocators(toPolicyIndexType(policyType), searchText, filter_s,0); + logger.debug("No Exceptions"); + for (PolicyLocator l: locators) { + logger.debug(l.policyName); + } + logger.debug("After for"); + } catch (Exception ise) { + logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR+"Search is unavailable: " + ise.getMessage()); + //PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, ise, "AttributeDictionary", " Exception while searching Elk database "); + logger.debug("Exceptions"); + value = "$notSuccess%"; + return value; + } + policyNames = new ArrayList<JSONObject>(); + for (PolicyLocator p: locators) { + String dbPolicyName = p.scope + File.separator + p.policyType + "_" + p.policyName + ".xml"; + logger.debug(dbPolicyName); + JSONObject el = new JSONObject(); + el.put("name", dbPolicyName); + policyNames.add(el); + } + if(!locators.isEmpty()){ + value = "$success%"; + logger.debug("Success"); + return value; + } + return value; + } + +} + + +class SearchData{ + private String query; + private String policyType; + private String descriptiveScope; + private String closedLooppolicyType; + private String ecompName; + private String d2Service; + private String vnfType; + private String policyStatus; + private String vproAction; + private String serviceType; + private String bindTextSearch; + public String getQuery() { + return query; + } + public void setQuery(String query) { + this.query = query; + } + public String getPolicyType() { + return policyType; + } + public void setPolicyType(String policyType) { + this.policyType = policyType; + } + public String getDescriptiveScope() { + return descriptiveScope; + } + public void setDescriptiveScope(String descriptiveScope) { + this.descriptiveScope = descriptiveScope; + } + public String getClosedLooppolicyType() { + return closedLooppolicyType; + } + public void setClosedLooppolicyType(String closedLooppolicyType) { + this.closedLooppolicyType = closedLooppolicyType; + } + public String getEcompName() { + return ecompName; + } + public void setEcompName(String ecompName) { + this.ecompName = ecompName; + } + public String getD2Service() { + return d2Service; + } + public void setD2Service(String d2Service) { + this.d2Service = d2Service; + } + public String getVnfType() { + return vnfType; + } + public void setVnfType(String vnfType) { + this.vnfType = vnfType; + } + public String getPolicyStatus() { + return policyStatus; + } + public void setPolicyStatus(String policyStatus) { + this.policyStatus = policyStatus; + } + public String getVproAction() { + return vproAction; + } + public void setVproAction(String vproAction) { + this.vproAction = vproAction; + } + public String getServiceType() { + return serviceType; + } + public void setServiceType(String serviceType) { + this.serviceType = serviceType; + } + public String getBindTextSearch() { + return bindTextSearch; + } + public void setBindTextSearch(String bindTextSearch) { + this.bindTextSearch = bindTextSearch; + } +}
\ No newline at end of file diff --git a/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/PolicyLocator.java b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/PolicyLocator.java new file mode 100644 index 000000000..f7cc58fa2 --- /dev/null +++ b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/client/PolicyLocator.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ECOMP Policy Engine + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.policy.elk.client; + + +public class PolicyLocator { + public final String policyType; + public final String policyName; + public final String owner; + public final String scope; + public final String policyId; + public final String version; + + public PolicyLocator(String policyType, String policyName, + String owner, String scope, String policyId, + String version) { + this.policyType = policyType; + this.policyName= policyName; + this.owner = owner; + this.scope = scope; + this.policyId = policyId; + this.version = version; + } + + public String toString() { + return "[" + + this.owner + "|" + + this.scope + "|" + + this.policyType + "|" + + this.policyName + "|" + + this.policyId + "|" + + "v" + this.version + "|" + "]"; + + } +} diff --git a/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/converter/ElkRecord.java b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/converter/ElkRecord.java new file mode 100644 index 000000000..40bdb7929 --- /dev/null +++ b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/converter/ElkRecord.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ECOMP Policy Engine + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.policy.elk.converter; + + +import com.fasterxml.jackson.databind.JsonNode; + +public class ElkRecord { + public final String record; + public final String policyId; + public final JsonNode jsonRecord; + public final boolean bodyAttached; + + public ElkRecord(final String policyId, + final String record, + final JsonNode jsonRecord, + final boolean bodyAttached) { + this.policyId = policyId; + this.record = record; + this.jsonRecord = jsonRecord; + this.bodyAttached = bodyAttached; + } + +} diff --git a/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/converter/Xacml2Elk.java b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/converter/Xacml2Elk.java new file mode 100644 index 000000000..f7aa34ff2 --- /dev/null +++ b/ecomp-sdk-app/src/main/java/org/openecomp/policy/elk/converter/Xacml2Elk.java @@ -0,0 +1,978 @@ +/*- + * ============LICENSE_START======================================================= + * ECOMP Policy Engine + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.policy.elk.converter; + + +import io.searchbox.core.Update; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.Result; +import javax.xml.transform.stream.StreamResult; + +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; + +import org.apache.commons.io.IOUtils; +import org.eclipse.persistence.jaxb.JAXBContextFactory; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.eclipse.persistence.jaxb.json.JsonSchemaOutputResolver; + +import com.att.research.xacml.api.Advice; +import com.att.research.xacml.api.AttributeAssignment; +import com.att.research.xacml.api.Identifier; +import com.att.research.xacml.api.Obligation; +import org.openecomp.policy.xacml.api.XACMLErrorConstants; +import com.att.research.xacml.util.XACMLPolicyScanner; +import com.att.research.xacml.util.XACMLProperties; +import com.att.research.xacml.util.XACMLPolicyScanner.CallbackResult; +import com.att.research.xacml.util.XACMLPolicyScanner.SimpleCallback; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; +import com.fasterxml.jackson.module.jsonSchema.JsonSchema; +import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper; + +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.Option; +import org.openecomp.policy.elk.client.ElkConnector; +import org.openecomp.policy.elk.client.ElkConnector.PolicyBodyType; +import org.openecomp.policy.rest.XACMLRestProperties; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; + + +@SuppressWarnings("unused") +public class Xacml2Elk { + public static final String URLID_ATTRIBUTE = "URLID"; + public static final String BODY_ATTRIBUTE = "body"; + + protected static final Logger logger = FlexLogger.getLogger(Xacml2Elk.class); + protected static JAXBContext jaxbContext = jaxbContext(); + + protected static String toConfigsWebDirectory(String policyType) + throws IllegalArgumentException { + if (policyType == null || policyType.isEmpty()) + throw new IllegalArgumentException("Unexpected policy type: " + policyType); + + ElkConnector.PolicyType type = ElkConnector.PolicyType.valueOf(policyType); + switch(type) { + case Config: + return type.name(); + case Action: + return type.name(); + case Decision: + return type.name(); + case Config_Fault: + case Config_PM: + case Config_FW: + case Config_MS: + return ElkConnector.PolicyType.Config.name(); + default: + throw new IllegalArgumentException("Unexpected policy type: " + policyType); + } + } + + protected synchronized static JAXBContext jaxbContext() { + if (jaxbContext != null) { + return jaxbContext; + } + + try { + jaxbContext = JAXBContextFactory.createContext(new Class[] {PolicyType.class}, null); + } catch (JAXBException e) { + logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" + + "JAXB Context cannot be created"); + return null; + } + + return jaxbContext; + } + + protected static class CLIOptions { + @Option(name="-t", usage="policy type", aliases={"-type", "--type"}, required=true) + protected String type; + + @Option(name="-n", usage="policy name", aliases={"-name", "--name"}, required=true) + protected String name; + + @Option(name="-o", usage="git repository owner", aliases={"-owner", "--owner"}, required=true) + protected String owner; + + @Option(name="-s", usage="enclosing scope", aliases={"-scope", "--scope"}, required=true) + protected String scope; + + @Option(name="-x", usage="xacml input file", aliases={"-xacml", "--xacml"}, required=true, metaVar="<xacml input file>") + protected File xacmlFile; + + @Option(name="-p", usage="payload body type", aliases={"-payloadType", "--payloadType"}, required=false, metaVar="<bayload body type>", depends={"-b"}) + protected PolicyBodyType bodyType; + + @Option(name="-b", usage="payload body", aliases={"-body", "--body"}, required=false, metaVar="<bayload body type>", depends={"-p"}) + protected String body; + + @Option(name="-d", usage="elk record output directory", aliases={"-d", "--directory"}, required=true, metaVar="<elk directory>") + protected File elkDirectory; + + @Option(name = "-h", aliases = {"-help", "--help"}, usage = "print this message") + private boolean help = false; + }; + + class AttributeAssignmentFinderProcessor extends SimpleCallback { + protected final String attributeId; + protected String attributeValue = null; + + public AttributeAssignmentFinderProcessor(String attributeId) { + this.attributeId = attributeId; + } + + public String getAttributeValue() { + return attributeValue; + } + + public boolean isAttributeValue() { + return (this.attributeValue != null && !this.attributeValue.isEmpty()); + } + + private boolean processAssignments( + List<AttributeAssignmentExpressionType> assignments) { + if (logger.isTraceEnabled()) + logger.trace("ENTER"); + + for (AttributeAssignmentExpressionType assignment : assignments) { + if (!assignment.getAttributeId().equals(attributeId)) { + if (logger.isDebugEnabled()) + logger.debug("Ignoring: " + assignment.getAttributeId()); + continue; + } + + if (logger.isDebugEnabled()) + logger.debug("Found Attribute ID: " + assignment.getAttributeId()); + + JAXBElement<?> jaxbExp = assignment.getExpression(); + Object assignmentObject = jaxbExp.getValue(); + if (assignmentObject instanceof AttributeValueType) { + AttributeValueType avt = (AttributeValueType) assignmentObject; + if (avt.getContent().size() <= 0) { + logger.warn("Ignoring: " + assignment.getAttributeId() + ": No values"); + continue; + } + + this.attributeValue = avt.getContent().get(0).toString(); + if (logger.isInfoEnabled()) + logger.info("Found: " + this.attributeValue); + + return true; + } + } + return false; + } + + @Override + public CallbackResult onAdvice(Object parent, AdviceExpressionType expression, Advice advice) { + if (logger.isTraceEnabled()) + logger.trace("ENTER"); + + List<AttributeAssignmentExpressionType> assignments = + expression.getAttributeAssignmentExpression(); + + if (assignments != null) { + boolean found = processAssignments(assignments); + if (found) + return CallbackResult.STOP; + } + + return super.onAdvice(parent, expression, advice); + } + + @Override + public CallbackResult onObligation(Object parent, ObligationExpressionType expression, Obligation obligation) { + if (logger.isTraceEnabled()) + logger.trace("ENTER"); + + List<AttributeAssignmentExpressionType> assignments = + expression.getAttributeAssignmentExpression(); + + if (assignments != null) { + boolean found = processAssignments(assignments); + if (found) + return CallbackResult.STOP; + } + + return super.onObligation(parent, expression, obligation); + + } + } + + final protected String type; + final protected String name; + final protected String owner; + final protected String scope; + final protected File xacmlFile; + final protected File elkDirectory; + + final protected JAXBElement<PolicyType> policy; + + protected PolicyBodyType bodyType; + protected String body; + + + public Xacml2Elk(String type, String name, + String owner, String scope, + File xacmlFile, File elkDirectory) + throws IllegalArgumentException { + + this.type = type; + this.name = name; + this.owner = owner; + this.scope = scope; + this.xacmlFile = xacmlFile; + this.elkDirectory = elkDirectory; + + this.policy = jaxbXacml(xacmlFile); + + this.body = ""; + this.bodyType = PolicyBodyType.none; + bodyFromXacml(); + } + + public Xacml2Elk(CLIOptions args) throws IllegalArgumentException { + this.type = args.type; + this.name = args.name; + this.owner = args.owner; + this.scope = args.scope; + this.xacmlFile = args.xacmlFile; + this.elkDirectory = args.elkDirectory; + + this.policy = jaxbXacml(xacmlFile); + + if (args.body == null || args.body.isEmpty()) { + this.body = ""; + this.bodyType = PolicyBodyType.none; + bodyFromXacml(); + } else { + this.body = args.body; + this.bodyType = args.bodyType; + } + } + + public Xacml2Elk(String type, String name, String owner, + String scope, File xacmlFile, PolicyBodyType bodyType, + String body, File destinationDir) + throws IllegalArgumentException { + this.type = type; + this.name = name; + this.owner = owner; + this.scope = scope; + this.xacmlFile = xacmlFile; + this.bodyType = bodyType; + this.body = body; + this.elkDirectory = destinationDir; + + this.policy = jaxbXacml(xacmlFile); + } + + public Xacml2Elk(File xacmlFile, boolean skipBody) + throws IllegalArgumentException { + this.policy = jaxbXacml(xacmlFile); + PolicyType jPolicy = this.policy.getValue(); + + this.xacmlFile = xacmlFile; + + this.type = ElkConnector.toPolicyType(xacmlFile.getName()).name(); + String fileName = xacmlFile.getName().replaceFirst(this.type + "_", ""); + if (fileName.indexOf(".") > 0) + this.name = fileName.substring(0, fileName.lastIndexOf(".")); + else + this.name = fileName; + + this.owner = "admin"; + this.scope = getScope(xacmlFile.getParent()); + this.elkDirectory = null; + + this.body = ""; + this.bodyType = PolicyBodyType.none; + if (!skipBody) { + bodyFromXacml(); + } + } + + @SuppressWarnings("unchecked") + protected JAXBElement<PolicyType> jaxbXacml(File xacmlFile) throws IllegalArgumentException { + Path xacmlPath = xacmlFile.toPath(); + if (!Files.isReadable(xacmlPath) || !Files.isRegularFile(xacmlPath)) { + if (logger.isWarnEnabled()) { + logger.warn("Error: " + xacmlPath + " is invalid."); + } + throw new IllegalArgumentException("Error: " + xacmlPath + " is invalid."); + } + + try { + Unmarshaller u = jaxbContext.createUnmarshaller(); + return (JAXBElement<PolicyType>) u.unmarshal(xacmlFile); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_DATA_ISSUE + " - error: " + xacmlPath + " is invalid."); + } + throw new IllegalArgumentException(xacmlFile.getAbsolutePath() + " does not contain valid XACML"); + } + } + + public JAXBElement<PolicyType> getPolicy() { + return policy; + } + + protected String getScope(String xacmlDirPath) { + if (logger.isTraceEnabled()) logger.trace("ENTER"); + + xacmlDirPath = xacmlDirPath.replaceAll("//", "/"); + xacmlDirPath = xacmlDirPath.replaceAll("\\\\", "/"); + xacmlDirPath = xacmlDirPath.replace('\\', '/'); + + String ws = XACMLProperties.getProperty(XACMLRestProperties.PROP_ADMIN_WORKSPACE); + String adminRepo = XACMLProperties.getProperty(XACMLRestProperties.PROP_ADMIN_REPOSITORY); + Path wsPath = Paths.get(ws, "admin", adminRepo); + File repoDir = wsPath.toFile(); + String repoPath = repoDir.getPath(); + repoPath = repoPath.replaceAll("//", "/"); + repoPath = repoPath.replaceAll("\\\\", "/"); + repoPath = repoPath.replace('\\', '/'); + + int startIndex = xacmlDirPath.indexOf(repoPath.toString()) + repoPath.toString().length() + 1; + String scope = xacmlDirPath.substring(startIndex, xacmlDirPath.length()); + + if (logger.isInfoEnabled()) + logger.info("xacml-policy-path=" + xacmlDirPath + "|" + + "repository-path=" + repoPath + "|" + + "scope=" + scope); + + return scope; + } + + @SuppressWarnings("deprecation") + private boolean bodyFromXacml() { + if (logger.isTraceEnabled()) + logger.trace("ENTER"); + + String urlAttribute = URLID_ATTRIBUTE; + try { + switch (ElkConnector.toPolicyType(this.type)) { + case Action: + urlAttribute = BODY_ATTRIBUTE; + break; + case Decision: + case none: + /* no body attached to decision policies */ + if (logger.isInfoEnabled()) + logger.info("No body attached for this type of policy: " + this.xacmlFile.getAbsolutePath()); + return false; + default: + /* a flavour of a config policy - default is fine */ + break; + } + } catch (IllegalArgumentException iae) { + if (logger.isWarnEnabled()) { + logger.warn(this.type + " cannot be converted to a valid type: " + iae.getMessage(), iae); + } + return false; + } + + AttributeAssignmentFinderProcessor + processor = new AttributeAssignmentFinderProcessor(urlAttribute); + XACMLPolicyScanner xacmlScanner = + new XACMLPolicyScanner(this.policy.getValue(), processor); + xacmlScanner.scan(); + if (!processor.isAttributeValue()) { + if (logger.isInfoEnabled()) + logger.info(urlAttribute + " not found in " + this.xacmlFile.getAbsolutePath()); + return false; + } + + String configsUrl = XACMLProperties.getProperty(XACMLRestProperties.PROP_CONFIG_URL); + if (configsUrl == null || configsUrl.isEmpty() || !configsUrl.startsWith("http")) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLRestProperties.PROP_CONFIG_URL + " property is not set."); + } + configsUrl = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL); + if (configsUrl == null || configsUrl.isEmpty() || !configsUrl.startsWith("http")) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLRestProperties.PROP_PAP_URL + " property is not set."); + } + return false; + } else { + configsUrl = configsUrl.replaceFirst("/pap", ""); + } + } + + if (!configsUrl.endsWith("/")) { + configsUrl += "/"; + } + + String urlXacml = processor.getAttributeValue(); + if (logger.isDebugEnabled()) { + logger.debug("configs url is " + configsUrl + "and url in xacml is " + urlXacml); + } + + if (urlXacml.startsWith("http")) { + // assuming this an unescaped url + } else if (urlXacml.startsWith("$URLConfig/")) { + urlXacml = urlXacml.replace("$URLConfig/", configsUrl); + } else if (urlXacml.startsWith("$URL/")) { + urlXacml = urlXacml.replace("$URL/", configsUrl); + } else{ + if (logger.isWarnEnabled()) { + logger.warn("XACML url is not in the expected format: " + urlXacml); + } + return false; + } + + if (urlXacml.endsWith(".properties")) { + this.bodyType = PolicyBodyType.properties; + } else if (urlXacml.endsWith(".json")) { + this.bodyType = PolicyBodyType.json; + } else if (urlXacml.endsWith(".xml")) { + this.bodyType = PolicyBodyType.xml; + } else if (urlXacml.endsWith(".txt")) { + this.bodyType = PolicyBodyType.txt; + } + + if (logger.isDebugEnabled()) { + logger.debug("converted url from xacml is " + urlXacml + ", body-type is " + this.bodyType); + } + + InputStream inConfigs = null; + try { + URL url = new URL(urlXacml); + URLConnection connection = url.openConnection(); + inConfigs = connection.getInputStream(); + String encoding = connection.getContentEncoding(); + encoding = (encoding == null ? "UTF-8" : encoding); + this.body = IOUtils.toString(inConfigs, encoding); + if (logger.isInfoEnabled()) { + logger.info("The following document of type " + this.bodyType.toString() + + " has been fetched from " + urlXacml + System.lineSeparator() + + this.body); + } + try { + inConfigs.close(); + } catch (IOException e) { + // ignore + logger.warn("Unexpected error closing stream to " + urlXacml, e); + } + return true; + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- XACML url is not in the expected format: " + e.getMessage() + + ": " + urlXacml, e); + } + // continue + } finally { + if (inConfigs != null) { + try { + inConfigs.close(); + } catch (IOException e) { + // ignore + logger.warn("Unexpected error closing stream to " + urlXacml, e); + } + } + } + + // if retrieval through PAP url was not possible, try to retrieve it from + // filesystem instead. + + if (this.body == null || this.body.isEmpty()) { + Path webappsPath = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_WEBAPPS)); + if (webappsPath == null) { + logger.error("Invalid Webapps Path Location property : " + + XACMLRestProperties.PROP_PAP_WEBAPPS); + return false; + } + String waPath = webappsPath.toFile().getAbsolutePath(); + + String typeDir = null; + try { + typeDir = Xacml2Elk.toConfigsWebDirectory(this.type); + } catch (IllegalArgumentException iae) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- " + this.type + + " cannot be converted to body-directory: " + iae.getMessage(), + iae); + } + this.bodyType = PolicyBodyType.none; + return false; + } + + String scopePrefix = this.scope.replace('/', '.'); + Path bodyPath = Paths.get(waPath, + typeDir, + scopePrefix + "." + this.type + "_" + + this.name + "." + this.bodyType.name()); + File bodyFile = bodyPath.toFile(); + if (Files.notExists(bodyPath)) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "The following document of type " + this.bodyType.toString() + + " does not exist at filesystem location " + bodyFile.getAbsolutePath()); + } + this.bodyType = PolicyBodyType.none; + return false; + } else { + if (logger.isInfoEnabled()) { + logger.info("The following document of type " + this.bodyType.toString() + + " will be fetched from filesystem location " + bodyFile.getAbsolutePath()); + } + } + + try { + inConfigs = new FileInputStream(bodyFile); + this.body = IOUtils.toString(inConfigs); + inConfigs.close(); + if (logger.isInfoEnabled()) { + logger.info("The document of type " + this.bodyType.toString() + + " has been found at filesystem location " + bodyFile.getAbsolutePath()); + } + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- XACML Body File cannot be read: " + bodyFile.getAbsolutePath(), e); + } + this.bodyType = PolicyBodyType.none; + return false; + } finally { + if (inConfigs != null) { + try { + inConfigs.close(); + } catch (IOException e) { + // ignore + logger.warn("Unexpected error closing stream to " + urlXacml, e); + } + } else { + return false; + } + } + } + return true; + } + + public boolean attachJsonBody(JsonNode jPolicy) { + if (this.body == null) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- JSON Body expected but none provided from " + + this.scope + ":" + this.type + ":" + this.name); + } + return true; + } + + ObjectNode jPolicyRoot = (ObjectNode) jPolicy; + + // verify the json is valid + final ObjectMapper mapper = new ObjectMapper(); + JsonNode jBodyContent; + try { + jBodyContent = mapper.readTree(this.body); + } catch (IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- JSON Body is invalid in " + + this.scope + ":" + this.type + ":" + this.name + ":" + + e.getMessage() + System.lineSeparator() + this.body, e); + return false; + } + + String jBodyName = this.type + "_" + "Body"; + ObjectNode jBodyContainer = mapper.createObjectNode(); + jBodyContainer.set(jBodyName, jBodyContent); + + jPolicyRoot.set("Body", jBodyContainer); + + if (logger.isDebugEnabled()) + logger.debug("Attaching JSON to " + + this.scope + ":" + + this.type + ":" + this.name + ":" + + jBodyName + System.lineSeparator() + + jBodyContent); + + return true; + } + + @SuppressWarnings("unchecked") + public boolean attachXmlBody(JsonNode jPolicy) { + if (this.body == null) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- JSON Body expected but none provided from " + + this.scope + ":" + this.type + ":" + this.name); + } + return true; + } + + XmlMapper xmlMapper = new XmlMapper(); + xmlMapper.setConfig(xmlMapper.getSerializationConfig().withRootName("")); + Map<Object, Object> map; + try { + map = xmlMapper.readValue(this.body, Map.class); + } catch (IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- XML Body is invalid in " + + this.scope + ":" + this.type + ":" + this.name + ":" + + e.getMessage() + System.lineSeparator() + this.body, e); + return false; + } + + final ObjectMapper mapper = new ObjectMapper(); + String jXmlBody; + try { + jXmlBody = mapper.writeValueAsString(map); + } catch (JsonProcessingException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- Cannot convert XML Body to JSON in " + + this.scope + ":" + this.type + ":" + this.name + ":" + + e.getMessage() + System.lineSeparator() + this.body, e); + return false; + } + + if (logger.isDebugEnabled()) + logger.debug("XML-to-JSON Body conversion: " + this.scope + ":" + + this.type + ":" + this.name +jXmlBody); + + JsonNode jBodyContent; + try { + jBodyContent = mapper.readTree(jXmlBody); + } catch (IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- JSON Body (converted from XML) is invalid in " + + this.scope + ":" + this.type + ":" + this.name + ":" + + e.getMessage() + System.lineSeparator() + jXmlBody, e); + return false; + } + + ObjectNode jPolicyRoot = (ObjectNode) jPolicy; + + String jBodyName = this.type + "_" + "Body"; + ObjectNode jBodyContainer = mapper.createObjectNode(); + jBodyContainer.set(jBodyName, jBodyContent); + + jPolicyRoot.set("Body", jBodyContainer); + + + if (logger.isDebugEnabled()) + logger.debug("Attaching JSON to " + + this.scope + ":" + + this.type + ":" + this.name + ":" + + jBodyName + System.lineSeparator() + + jBodyContent); + + return true; + } + + protected boolean attachPropertiesBody(JsonNode jPolicy) { + if (this.body == null) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- JSON Body expected but none provided from " + + this.scope + ":" + this.type + ":" + this.name); + } + return true; + } + + final Properties propBody = new Properties(); + try { + propBody.load(new StringReader(this.body)); + } catch (IOException e) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- JSON Body is invalid in " + + this.scope + ":" + this.type + ":" + this.name + ":" + + e.getMessage() + System.lineSeparator() + this.body, e); + return false; + } + + if (propBody.isEmpty()) { + if (logger.isInfoEnabled()) { + logger.info("Empty set of properties: " + + this.scope + ":" + this.type + ":" + this.name + + System.lineSeparator() + this.body); + } + return true; + } + + + final ObjectMapper mapper = new ObjectMapper(); + + ObjectNode jPolicyRoot = (ObjectNode) jPolicy; + ObjectNode jBody = jPolicyRoot.putObject("Body"); + String jBodyName = this.type + "_" + "Body"; + ObjectNode jBodyContainer = jBody.putObject(jBodyName); + + // ObjectNode jBodyContainer = mapper.createObjectNode(); + + for(String key : propBody.stringPropertyNames()) { + String value = propBody.getProperty(key); + if (logger.isDebugEnabled()) { + logger.debug("Attaching JSON field to " + jBodyName + " for " + + this.type.toString() + ":" + + this.scope + ":" + this.name + ":" + jBodyName + ":" + + " <" + key +"," + value + ">"); + } + jBodyContainer.put(key, propBody.getProperty(key)); + } + + return true; + } + + public boolean attachTextBody(JsonNode jPolicy) { + if (this.body == null) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- JSON Body expected but none provided from " + + this.scope + ":" + this.type + ":" + this.name); + } + return true; + } + + final ObjectMapper mapper = new ObjectMapper(); + StringWriter jsonEscapedTextWriter = new StringWriter(); + try { + mapper.writer().writeValue(jsonEscapedTextWriter, this.body); + } catch (IOException e) { + if (logger.isWarnEnabled()) { + logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + + "- Text Body cannot be converted from " + + this.scope + ":" + this.type + ":" + this.name + ":" + + e.getMessage() + ":" + jsonEscapedTextWriter , e); + } + return false; + } + String jTextBody = jsonEscapedTextWriter.toString(); + + if (logger.isDebugEnabled()) + logger.debug("XML 2JSON Body conversion: " + this.scope + ":" + + this.type + ":" + this.name + ":" + jTextBody); + + ObjectNode jPolicyRoot = (ObjectNode) jPolicy; + + String jBodyName = this.type + "_" + "Body"; + ObjectNode jBodyContainer = mapper.createObjectNode(); + jBodyContainer.put(jBodyName, jTextBody); + + jPolicyRoot.set("Body", jBodyContainer); + + if (logger.isDebugEnabled()) + logger.debug("Attaching JSON to " + + this.scope + ":" + + this.type + ":" + this.name + ":" + + jBodyName + ":" + + jTextBody); + + return true; + } + + protected boolean attachBody(JsonNode jPolicy) { + if (logger.isTraceEnabled()) logger.trace("ENTER"); + + if (this.bodyType == PolicyBodyType.none) { + if (logger.isInfoEnabled()) + logger.info("No body to attach for policy " + + this.scope + "/" + this.type + "_" + this.name); + + return true; + } + + if (this.body == null || this.body.isEmpty()) { + if (logger.isWarnEnabled()) + logger.warn("No body to attach for policy " + + this.bodyType + this.type + this.scope + this.name); + + return true; + } + + switch (this.bodyType) { + case json: + return attachJsonBody(jPolicy); + case properties: + return attachPropertiesBody(jPolicy); + case xml: + return attachXmlBody(jPolicy); + case txt: + return attachTextBody(jPolicy); + case none: + default: + if (logger.isWarnEnabled()) + logger.warn("Unexpected body type: " + this.bodyType + + this.bodyType + this.type + this.scope + this.name); + return false; + } + } + + public ElkRecord record() throws JAXBException, JsonProcessingException, + IOException, IllegalArgumentException { + if (logger.isTraceEnabled()) logger.trace("ENTER"); + + Marshaller m = jaxbContext.createMarshaller(); + m.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json"); + m.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.setProperty(MarshallerProperties.JSON_REDUCE_ANY_ARRAYS, true); + m.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false); + + StringWriter policyStringWriter = new StringWriter(); + m.marshal(policy, policyStringWriter); + + // add metadata to elk record + + final ObjectMapper mapper = new ObjectMapper(); + JsonNode jRoot = mapper.readTree(policyStringWriter.toString()); + JsonNode jPolicy = jRoot.path("Policy"); + if (jPolicy.isMissingNode()) { + logger.warn("Aborting: Policy root node is missing."); + throw new IllegalArgumentException("Missing policy root node"); + } + + ((ObjectNode) jPolicy).put("PolicyType", this.type.toString()); + ((ObjectNode) jPolicy).put("PolicyName", this.name); + ((ObjectNode) jPolicy).put("Owner", this.owner); + ((ObjectNode) jPolicy).put("Scope", this.scope); + + JsonNode jPolicyId = jPolicy.path("PolicyId"); + if (jPolicyId.isMissingNode()) { + logger.warn("Aborting: Policy ID node is missing."); + throw new IllegalArgumentException("Missing policy id"); + } + + if (!jPolicyId.isTextual() || !jPolicyId.isValueNode()) { + logger.warn("Aborting: Policy ID invalid."); + throw new IllegalArgumentException("Invalid policy id"); + } + + String xacmlPolicyId = jPolicyId.asText(); + String policyId = xacmlPolicyId.substring(xacmlPolicyId.lastIndexOf(":")+1); + + boolean success = attachBody(jPolicy); + + mapper.configure(SerializationFeature.INDENT_OUTPUT, true); + mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true); + mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false); + mapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, true); + + String recordText = mapper.writeValueAsString(jRoot); + if (logger.isDebugEnabled()) { + logger.debug("ELK Record: " + System.lineSeparator() + recordText); + } + + ElkRecord elkRecord = new ElkRecord(policyId, recordText, jRoot, success); + return elkRecord; + } + + public void store(String policyId, String record) throws IOException { + if (logger.isTraceEnabled()) logger.trace("ENTER"); + + if (this.elkDirectory != null) { + Files.createDirectories(this.elkDirectory.toPath());; + Path elkPolicyFile = Paths.get(this.elkDirectory.getPath(), policyId + ".json"); + + if (logger.isDebugEnabled()) { + logger.info("Output: " + elkPolicyFile.toAbsolutePath().toString()); + logger.info("---------------------------------------------------"); + } + + Files.write(elkPolicyFile, record.getBytes()); + } + } + + public static void main(String args[]) + throws JAXBException, IOException, CmdLineException, IllegalStateException { + + CLIOptions cliOptions = new CLIOptions(); + CmdLineParser cliParser= new CmdLineParser(cliOptions); + + try { + cliParser.parseArgument(args); + } catch (CmdLineException e) { + System.err.println("Usage: Xacml2elk"); + cliParser.printUsage(System.err); + throw e; + } + + System.out.println("---------------------------------------------------"); + System.out.println("Converting " + cliOptions.xacmlFile.getName() + " to ELK format"); + System.out.println("Metadata=" + "[type:" + cliOptions.type + + "|name:" + cliOptions.name + + "|owner:" + cliOptions.owner + + "|scope:" + cliOptions.scope + "]"); + + // generate json from jaxb input file + + Path xacmlPath = cliOptions.xacmlFile.toPath(); + if (!Files.isReadable(xacmlPath) || !Files.isRegularFile(xacmlPath)) { + System.out.println("Error: " + xacmlPath + " is invalid."); + throw new IllegalArgumentException("Error: " + xacmlPath + " is invalid."); + } + + + Xacml2Elk convertor = new Xacml2Elk(cliOptions); + ElkRecord elkRecord = convertor.record(); + System.out.println(elkRecord.record); + + Path elkOutDir = cliOptions.elkDirectory.toPath(); + if (!Files.isReadable(elkOutDir) || !Files.isDirectory(elkOutDir) || + !Files.isWritable(elkOutDir) || !Files.isExecutable(elkOutDir)) { + System.out.println("Error: " + elkOutDir.getFileName() + " is invalid."); + throw new IllegalArgumentException("Error: " + elkOutDir.getFileName() + " is invalid."); + } + + convertor.store(elkRecord.policyId, elkRecord.record); + } +} |