diff options
Diffstat (limited to 'ONAP-PDP-REST/src/main/java/org/onap/policy/pdp/rest/api/services/PDPServices.java')
-rw-r--r-- | ONAP-PDP-REST/src/main/java/org/onap/policy/pdp/rest/api/services/PDPServices.java | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/ONAP-PDP-REST/src/main/java/org/onap/policy/pdp/rest/api/services/PDPServices.java b/ONAP-PDP-REST/src/main/java/org/onap/policy/pdp/rest/api/services/PDPServices.java new file mode 100644 index 000000000..e495c9950 --- /dev/null +++ b/ONAP-PDP-REST/src/main/java/org/onap/policy/pdp/rest/api/services/PDPServices.java @@ -0,0 +1,439 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP-PDP-REST + * ================================================================================ + * 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.onap.policy.pdp.rest.api.services; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.net.MalformedURLException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import javax.json.Json; +import javax.json.JsonReader; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.io.IOUtils; +import org.onap.policy.api.PolicyConfigStatus; +import org.onap.policy.api.PolicyDecision; +import org.onap.policy.api.PolicyException; +import org.onap.policy.api.PolicyResponseStatus; +import org.onap.policy.api.PolicyType; +import org.onap.policy.common.logging.flexlogger.FlexLogger; +import org.onap.policy.common.logging.flexlogger.Logger; +import org.onap.policy.pdp.rest.XACMLPdpServlet; +import org.onap.policy.pdp.rest.api.models.PDPResponse; +import org.onap.policy.rest.XACMLRestProperties; +import org.onap.policy.std.Matches; +import org.onap.policy.xacml.api.XACMLErrorConstants; +import org.w3c.dom.Document; + +import com.att.research.xacml.api.Advice; +import com.att.research.xacml.api.AttributeAssignment; +import com.att.research.xacml.api.Decision; +import com.att.research.xacml.api.Obligation; +import com.att.research.xacml.api.Request; +import com.att.research.xacml.api.Response; +import com.att.research.xacml.api.Result; +import com.att.research.xacml.api.pdp.PDPEngine; +import com.att.research.xacml.std.json.JSONRequest; +import com.att.research.xacml.std.json.JSONResponse; +import com.att.research.xacml.util.XACMLProperties; + +public class PDPServices { + private static final Logger LOGGER = FlexLogger.getLogger(PDPServices.class.getName()); + // Change the default Priority value here. + private static final int DEFAULT_PRIORITY = 9999; + private boolean unique = false; + private Boolean decide = false; + private Request rainydayRequest = null; + + public Collection<PDPResponse> generateRequest(String jsonString, UUID requestID, boolean unique, boolean decide) throws PolicyException{ + this.unique = unique; + this.decide = decide; + Collection<PDPResponse> results = null; + Response response = null; + // Create Request. We need XACML API here. + try { + Request request = JSONRequest.load(jsonString); + // Assign a rainy day treatment request to parse the decided treatment + if (jsonString.contains("BB_ID")) { + rainydayRequest = request; + } + // Call the PDP + LOGGER.info("--- Generating Request: ---\n" + JSONRequest.toString(request)); + response = callPDP(request, requestID); + } catch (Exception e) { + LOGGER.error(XACMLErrorConstants.ERROR_SCHEMA_INVALID + e); + PDPResponse pdpResponse = new PDPResponse(); + results = new HashSet<>(); + pdpResponse.setPolicyConfigMessage("Unable to Call PDP. Error with the URL"); + pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND); + pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.NO_ACTION_REQUIRED); + results.add(pdpResponse); + throw new PolicyException(e); + } + if (response != null) { + results = checkResponse(response); + } else { + LOGGER.info("No Response Received from PDP"); + PDPResponse pdpResponse = new PDPResponse(); + results = new HashSet<>(); + pdpResponse.setPolicyConfigMessage("No Response Received"); + pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND); + pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.NO_ACTION_REQUIRED); + results.add(pdpResponse); + } + return results; + } + + private Collection<PDPResponse> checkResponse(Response response) throws PolicyException{ + String pdpConfigLocation = null; + Collection<PDPResponse> combinedResult = new HashSet<>(); + int priority = DEFAULT_PRIORITY; + Map<Integer, PDPResponse> uniqueResult = new HashMap<>(); + for (Result result : response.getResults()) { + if (!result.getDecision().equals(Decision.PERMIT)) { + LOGGER.info("Decision not a Permit. " + result.getDecision().toString()); + PDPResponse pdpResponse = new PDPResponse(); + if (decide) { + String indeterminatePropValue = XACMLProperties.getProperty("decision.inStringdeterminate.response"); + if(result.getDecision().equals(Decision.INDETERMINATE)&& indeterminatePropValue != null){ + if("PERMIT".equalsIgnoreCase(indeterminatePropValue)){ + pdpResponse.setDecision(PolicyDecision.PERMIT); + }else{ + pdpResponse.setDecision(PolicyDecision.DENY); + } + }else{ + pdpResponse.setDecision(PolicyDecision.DENY); + } + for(Advice advice: result.getAssociatedAdvice()){ + for(AttributeAssignment attribute: advice.getAttributeAssignments()){ + pdpResponse.setDetails(attribute.getAttributeValue().getValue().toString()); + break; + } + } + combinedResult.add(pdpResponse); + return combinedResult; + } + pdpResponse.setStatus(XACMLErrorConstants.ERROR_DATA_ISSUE + "Incorrect Params passed: Decision not a Permit.",PolicyResponseStatus.NO_ACTION_REQUIRED,PolicyConfigStatus.CONFIG_NOT_FOUND); + combinedResult.add(pdpResponse); + return combinedResult; + } else { + if (decide) { + // check for Decision for decision based calls. + PDPResponse pdpResponse = new PDPResponse(); + pdpResponse.setDecision(PolicyDecision.PERMIT); + + //if this is a Rainy Day treatment decision we need to get the selected treatment + if(rainydayRequest!=null){ + pdpResponse.setDetails(getRainyDayTreatment(result)); + } else { + pdpResponse.setDetails("Decision Permit. OK!"); + } + combinedResult.add(pdpResponse); + return combinedResult; + } + if (!result.getAssociatedAdvice().isEmpty()) { + // Configurations should be in advice. + // Also PDP took actions could be here. + for (Advice advice : result.getAssociatedAdvice()) { + int config = 0, uri = 0; + String configURL = null; + String policyName = null; + String policyVersion = null; + Matches match = new Matches(); + Map<String, String> matchingConditions = new HashMap<>(); + Map<String, String> configAttributes = new HashMap<>(); + Map<String, String> responseAttributes = new HashMap<>(); + Map<String, String> actionTaken = new HashMap<>(); + PDPResponse pdpResponse = new PDPResponse(); + Map<String, String> adviseAttributes = new HashMap<>(); + for (AttributeAssignment attribute : advice.getAttributeAssignments()) { + adviseAttributes.put(attribute.getAttributeId().stringValue(), attribute.getAttributeValue().getValue().toString()); + if ("CONFIGURATION".equalsIgnoreCase(attribute.getAttributeValue().getValue().toString())) { + config++; + } else if (attribute.getDataTypeId().stringValue().endsWith("anyURI")) { + uri++; + if (uri == 1) { + configURL = attribute.getAttributeValue().getValue().toString(); + pdpConfigLocation = configURL.replace("$URL", XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS)); + } else { + if (!("PDP".equalsIgnoreCase(attribute.getIssuer()))) { + throw new PolicyException(XACMLErrorConstants.ERROR_DATA_ISSUE + "Error having multiple URI in the Policy"); + } + } + } else if ("PolicyName".equalsIgnoreCase(attribute.getAttributeId().stringValue())) { + policyName = attribute.getAttributeValue().getValue().toString(); + } else if ("VersionNumber".equalsIgnoreCase(attribute.getAttributeId().stringValue())) { + policyVersion = attribute.getAttributeValue().getValue().toString(); + } else if ("Priority".equalsIgnoreCase(attribute.getAttributeId().stringValue())){ + try{ + priority = Integer.parseInt(attribute.getAttributeValue().getValue().toString()); + } catch(Exception e){ + LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE+ "Unable to Parse Integer for Priority. Setting to default value",e); + priority = DEFAULT_PRIORITY; + } + } else if (attribute.getAttributeId().stringValue().startsWith("matching")) { + matchingConditions.put(attribute.getAttributeId().stringValue() + .replaceFirst("(matching).", ""),attribute.getAttributeValue().getValue().toString()); + if ("ONAPName".equals(attribute.getAttributeId().stringValue() + .replaceFirst("(matching).", ""))) { + match.setOnapName(attribute.getAttributeValue().getValue().toString()); + } else if ("ConfigName".equals(attribute.getAttributeId().stringValue() + .replaceFirst("(matching).", ""))) { + match.setConfigName(attribute.getAttributeValue().getValue().toString()); + } else { + configAttributes.put(attribute.getAttributeId().stringValue() + .replaceFirst("(matching).", ""),attribute.getAttributeValue().getValue().toString()); + } + } else if (attribute.getAttributeId().stringValue().startsWith("key:")) { + responseAttributes.put(attribute.getAttributeId().stringValue().replaceFirst("(key).", ""), + attribute.getAttributeValue().getValue().toString()); + } else if (attribute.getAttributeId().stringValue().startsWith("controller:")) { + responseAttributes.put("$"+ attribute.getAttributeId().stringValue(), + attribute.getAttributeValue().getValue().toString()); + } else if (attribute.getAttributeId().stringValue().startsWith("dependencies:")) { + responseAttributes.put("$dependency$", + attribute.getAttributeValue().getValue().toString()); + } + } + if (!configAttributes.isEmpty()) { + match.setConfigAttributes(configAttributes); + } + if ((config == 1) && (uri == 1)) { + // If there is a configuration. + try { + LOGGER.debug("Configuration Call to : " + configURL); + pdpResponse = configCall(pdpConfigLocation); + } catch (Exception e) { + LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW+ e); + pdpResponse.setStatus("Error in Calling the Configuration URL "+ e, + PolicyResponseStatus.NO_ACTION_REQUIRED, + PolicyConfigStatus.CONFIG_NOT_FOUND); + } + pdpResponse.setPolicyName(policyName); + pdpResponse.setPolicyVersion(policyVersion); + pdpResponse.setMatchingConditions(matchingConditions); + pdpResponse.setResponseAttributes(responseAttributes); + if(!unique){ + combinedResult.add(pdpResponse); + }else{ + if(!uniqueResult.isEmpty()){ + if(uniqueResult.containsKey(priority)){ + // Not any more unique, check the matching conditions size + int oldSize = uniqueResult.get(priority).getMatchingConditions().size(); + int newSize = matchingConditions.size(); + if(oldSize < newSize){ + uniqueResult.put(priority, pdpResponse); + }else if(oldSize == newSize){ + pdpResponse = new PDPResponse(); + pdpResponse.setStatus("Two/more Policies have Same Priority and matching conditions, Please correct your policies.", + PolicyResponseStatus.NO_ACTION_REQUIRED, + PolicyConfigStatus.CONFIG_NOT_FOUND); + combinedResult.add(pdpResponse); + unique = false; + return combinedResult; + } + }else{ + uniqueResult.put(priority, pdpResponse); + } + }else{ + uniqueResult.put(priority, pdpResponse); + } + } + } else { + // Else it is Action Taken. + LOGGER.info("Action Taken by PDP. "); + actionTaken.putAll(adviseAttributes); + pdpResponse.setActionTaken(actionTaken); + pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.ACTION_TAKEN); + pdpResponse.setPolicyResponseMessage("Action Taken by the PDP"); + combinedResult.add(pdpResponse); + } + } + } + if (!result.getObligations().isEmpty()) { + // Obligation actions + // Action advised should be in obligations. + for (Obligation obligation : result.getObligations()) { + Map<String, String> actionAdvised = new HashMap<>(); + PDPResponse pdpResponse = new PDPResponse(); + for (AttributeAssignment attribute : obligation.getAttributeAssignments()) { + actionAdvised.put(attribute.getAttributeId().stringValue(), + attribute.getAttributeValue().getValue().toString()); + } + pdpResponse.setActionAdvised(actionAdvised); + pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.ACTION_ADVISED); + pdpResponse.setPolicyResponseMessage("Action has been Advised "); + combinedResult.add(pdpResponse); + } + } + } + } + if(unique){ + // Select Unique policy. + int minNum = DEFAULT_PRIORITY; + for(int num: uniqueResult.keySet()){ + if(num < minNum){ + minNum = num; + } + } + combinedResult.add(uniqueResult.get(minNum)); + // Turn off Unique + unique = false; + } + + return combinedResult; + } + + private String getRainyDayTreatment(Result result) { + String treatment = null; + if (rainydayRequest!=null&& !result.getAssociatedAdvice().isEmpty()) { + // Get the desired treatment for requested errorCode from the Advice + for (Advice advice : result.getAssociatedAdvice()) { + Map<String, String> adviseAttributes = new HashMap<>(); + for (AttributeAssignment attribute : advice.getAttributeAssignments()) { + adviseAttributes.put(attribute.getAttributeId().stringValue(), attribute.getAttributeValue().getValue().toString()); + if ("treatment".equalsIgnoreCase(attribute.getAttributeId().stringValue())){ + treatment = attribute.getAttributeValue().getValue().toString(); + } + } + } + } + return treatment; + } + + private PDPResponse configCall(String pdpConfigLocation) throws Exception{ + PDPResponse pdpResponse = new PDPResponse(); + if(pdpConfigLocation.contains("/")){ + pdpConfigLocation = pdpConfigLocation.replace("/", File.separator); + } + InputStream inputStream = null; + try { + inputStream = new FileInputStream(new File(pdpConfigLocation)); + try { + if (pdpConfigLocation.endsWith("json")) { + pdpResponse.setType(PolicyType.JSON); + JsonReader jsonReader = Json.createReader(inputStream); + pdpResponse.setConfig(jsonReader.readObject().toString()); + jsonReader.close(); + } else if (pdpConfigLocation.endsWith("xml")) { + pdpResponse.setType(PolicyType.XML); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + DocumentBuilder db = null; + try { + db = dbf.newDocumentBuilder(); + Document document = db.parse(inputStream); + DOMSource domSource = new DOMSource(document); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer; + transformer = tf.newTransformer(); + transformer.transform(domSource, result); + pdpResponse.setConfig(writer.toString()); + } catch (Exception e) { + LOGGER.error(XACMLErrorConstants.ERROR_SCHEMA_INVALID+ e); + throw new Exception(XACMLErrorConstants.ERROR_SCHEMA_INVALID+ "Unable to parse the XML config", e); + } + } else if (pdpConfigLocation.endsWith("properties")) { + pdpResponse.setType(PolicyType.PROPERTIES); + Properties configProp = new Properties(); + configProp.load(inputStream); + Map<String, String> propVal = new HashMap<>(); + for(String name: configProp.stringPropertyNames()) { + propVal.put(name, configProp.getProperty(name)); + } + pdpResponse.setProperty(propVal); + } else if (pdpConfigLocation.endsWith("txt")) { + pdpResponse.setType(PolicyType.OTHER); + String other = IOUtils.toString(inputStream); + IOUtils.closeQuietly(inputStream); + pdpResponse.setConfig(other); + } else { + LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Config Not Found"); + pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND); + pdpResponse.setPolicyConfigMessage("Illegal form of Configuration Type Found."); + inputStream.close(); + return pdpResponse; + } + LOGGER.info("config Retrieved " + pdpConfigLocation); + pdpResponse.setStatus("Config Retrieved! ", + PolicyResponseStatus.NO_ACTION_REQUIRED, + PolicyConfigStatus.CONFIG_RETRIEVED); + return pdpResponse; + } catch (IOException e) { + LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e); + throw new Exception(XACMLErrorConstants.ERROR_PROCESS_FLOW + + "Cannot open a connection to the configURL", e); + } + } catch (MalformedURLException e) { + LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e); + throw new Exception(XACMLErrorConstants.ERROR_DATA_ISSUE + "Error in ConfigURL", e); + }finally{ + if(inputStream != null){ + inputStream.close(); + } + } + } + + private Response callPDP(Request request, + UUID requestID) throws Exception{ + Response response = null; + // Get the PDPEngine + if (requestID == null) { + requestID = UUID.randomUUID(); + LOGGER.debug("No request ID provided, sending generated ID: " + requestID.toString()); + } else { + LOGGER.debug("Using provided request ID: " + requestID.toString()); + } + PDPEngine pdpEngine = XACMLPdpServlet.getPDPEngine(); + if (pdpEngine == null) { + String message = "PDPEngine not loaded."; + LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + message); + return response; + } + // call the PDPEngine to decide and give the response on the Request. + try { + response = pdpEngine.decide(request); + LOGGER.info("Response from the PDP is: \n" + JSONResponse.toString(response)); + } catch (Exception e) { + LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e); + return null; + } + return response; + } + +} |