2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
20 package org.openecomp.policy.pdp.rest.api.services;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.StringWriter;
27 import java.net.MalformedURLException;
28 import java.util.Collection;
29 import java.util.HashMap;
30 import java.util.HashSet;
32 import java.util.Properties;
33 import java.util.UUID;
35 import javax.json.Json;
36 import javax.json.JsonReader;
37 import javax.xml.XMLConstants;
38 import javax.xml.parsers.DocumentBuilder;
39 import javax.xml.parsers.DocumentBuilderFactory;
40 import javax.xml.transform.Transformer;
41 import javax.xml.transform.TransformerFactory;
42 import javax.xml.transform.dom.DOMSource;
43 import javax.xml.transform.stream.StreamResult;
45 import org.apache.commons.io.IOUtils;
46 import org.openecomp.policy.api.PolicyConfigStatus;
47 import org.openecomp.policy.api.PolicyDecision;
48 import org.openecomp.policy.api.PolicyException;
49 import org.openecomp.policy.api.PolicyResponseStatus;
50 import org.openecomp.policy.api.PolicyType;
51 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
52 import org.openecomp.policy.common.logging.flexlogger.Logger;
53 import org.openecomp.policy.pdp.rest.XACMLPdpServlet;
54 import org.openecomp.policy.pdp.rest.api.models.PDPResponse;
55 import org.openecomp.policy.rest.XACMLRestProperties;
56 import org.openecomp.policy.std.Matches;
57 import org.openecomp.policy.xacml.api.XACMLErrorConstants;
58 import org.w3c.dom.Document;
60 import com.att.research.xacml.api.Advice;
61 import com.att.research.xacml.api.AttributeAssignment;
62 import com.att.research.xacml.api.Decision;
63 import com.att.research.xacml.api.Obligation;
64 import com.att.research.xacml.api.Request;
65 import com.att.research.xacml.api.Response;
66 import com.att.research.xacml.api.Result;
67 import com.att.research.xacml.api.pdp.PDPEngine;
68 import com.att.research.xacml.std.json.JSONRequest;
69 import com.att.research.xacml.std.json.JSONResponse;
70 import com.att.research.xacml.util.XACMLProperties;
72 public class PDPServices {
73 private static final Logger LOGGER = FlexLogger.getLogger(PDPServices.class.getName());
74 // Change the default Priority value here.
75 private static final int DEFAULT_PRIORITY = 9999;
76 private boolean unique = false;
77 private Boolean decide = false;
78 private Request rainydayRequest = null;
80 public Collection<PDPResponse> generateRequest(String jsonString, UUID requestID, boolean unique, boolean decide) throws PolicyException{
83 Collection<PDPResponse> results = null;
84 Response response = null;
85 // Create Request. We need XACML API here.
87 Request request = JSONRequest.load(jsonString);
88 // Assign a rainy day treatment request to parse the decided treatment
89 if (jsonString.contains("BB_ID")) {
90 rainydayRequest = request;
93 LOGGER.info("--- Generating Request: ---\n" + JSONRequest.toString(request));
94 response = callPDP(request, requestID);
95 } catch (Exception e) {
96 LOGGER.error(XACMLErrorConstants.ERROR_SCHEMA_INVALID + e);
97 PDPResponse pdpResponse = new PDPResponse();
98 results = new HashSet<>();
99 pdpResponse.setPolicyConfigMessage("Unable to Call PDP. Error with the URL");
100 pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND);
101 pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.NO_ACTION_REQUIRED);
102 results.add(pdpResponse);
103 throw new PolicyException(e);
105 if (response != null) {
106 results = checkResponse(response);
108 LOGGER.info("No Response Received from PDP");
109 PDPResponse pdpResponse = new PDPResponse();
110 results = new HashSet<>();
111 pdpResponse.setPolicyConfigMessage("No Response Received");
112 pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND);
113 pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.NO_ACTION_REQUIRED);
114 results.add(pdpResponse);
119 private Collection<PDPResponse> checkResponse(Response response) throws PolicyException{
120 String pdpConfigLocation = null;
121 Collection<PDPResponse> combinedResult = new HashSet<>();
122 int priority = DEFAULT_PRIORITY;
123 Map<Integer, PDPResponse> uniqueResult = new HashMap<>();
124 for (Result result : response.getResults()) {
125 if (!result.getDecision().equals(Decision.PERMIT)) {
126 LOGGER.info("Decision not a Permit. " + result.getDecision().toString());
127 PDPResponse pdpResponse = new PDPResponse();
129 String indeterminatePropValue = XACMLProperties.getProperty("decision.inStringdeterminate.response");
130 if(result.getDecision().equals(Decision.INDETERMINATE)&& indeterminatePropValue != null){
131 if("PERMIT".equalsIgnoreCase(indeterminatePropValue)){
132 pdpResponse.setDecision(PolicyDecision.PERMIT);
134 pdpResponse.setDecision(PolicyDecision.DENY);
137 pdpResponse.setDecision(PolicyDecision.DENY);
139 for(Advice advice: result.getAssociatedAdvice()){
140 for(AttributeAssignment attribute: advice.getAttributeAssignments()){
141 pdpResponse.setDetails(attribute.getAttributeValue().getValue().toString());
145 combinedResult.add(pdpResponse);
146 return combinedResult;
148 pdpResponse.setStatus(XACMLErrorConstants.ERROR_DATA_ISSUE + "Incorrect Params passed: Decision not a Permit.",PolicyResponseStatus.NO_ACTION_REQUIRED,PolicyConfigStatus.CONFIG_NOT_FOUND);
149 combinedResult.add(pdpResponse);
150 return combinedResult;
153 // check for Decision for decision based calls.
154 PDPResponse pdpResponse = new PDPResponse();
155 pdpResponse.setDecision(PolicyDecision.PERMIT);
157 //if this is a Rainy Day treatment decision we need to get the selected treatment
158 if(rainydayRequest!=null){
159 pdpResponse.setDetails(getRainyDayTreatment(result));
161 pdpResponse.setDetails("Decision Permit. OK!");
163 combinedResult.add(pdpResponse);
164 return combinedResult;
166 if (!result.getAssociatedAdvice().isEmpty()) {
167 // Configurations should be in advice.
168 // Also PDP took actions could be here.
169 for (Advice advice : result.getAssociatedAdvice()) {
170 int config = 0, uri = 0;
171 String configURL = null;
172 String policyName = null;
173 String policyVersion = null;
174 Matches match = new Matches();
175 Map<String, String> matchingConditions = new HashMap<>();
176 Map<String, String> configAttributes = new HashMap<>();
177 Map<String, String> responseAttributes = new HashMap<>();
178 Map<String, String> actionTaken = new HashMap<>();
179 PDPResponse pdpResponse = new PDPResponse();
180 Map<String, String> adviseAttributes = new HashMap<>();
181 for (AttributeAssignment attribute : advice.getAttributeAssignments()) {
182 adviseAttributes.put(attribute.getAttributeId().stringValue(), attribute.getAttributeValue().getValue().toString());
183 if ("CONFIGURATION".equalsIgnoreCase(attribute.getAttributeValue().getValue().toString())) {
185 } else if (attribute.getDataTypeId().stringValue().endsWith("anyURI")) {
188 configURL = attribute.getAttributeValue().getValue().toString();
189 pdpConfigLocation = configURL.replace("$URL", XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS));
191 if (!("PDP".equalsIgnoreCase(attribute.getIssuer()))) {
192 throw new PolicyException(XACMLErrorConstants.ERROR_DATA_ISSUE + "Error having multiple URI in the Policy");
195 } else if ("PolicyName".equalsIgnoreCase(attribute.getAttributeId().stringValue())) {
196 policyName = attribute.getAttributeValue().getValue().toString();
197 } else if ("VersionNumber".equalsIgnoreCase(attribute.getAttributeId().stringValue())) {
198 policyVersion = attribute.getAttributeValue().getValue().toString();
199 } else if ("Priority".equalsIgnoreCase(attribute.getAttributeId().stringValue())){
201 priority = Integer.parseInt(attribute.getAttributeValue().getValue().toString());
202 } catch(Exception e){
203 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE+ "Unable to Parse Integer for Priority. Setting to default value",e);
204 priority = DEFAULT_PRIORITY;
206 } else if (attribute.getAttributeId().stringValue().startsWith("matching")) {
207 matchingConditions.put(attribute.getAttributeId().stringValue()
208 .replaceFirst("(matching).", ""),attribute.getAttributeValue().getValue().toString());
209 if ("ECOMPName".equals(attribute.getAttributeId().stringValue()
210 .replaceFirst("(matching).", ""))) {
211 match.setEcompName(attribute.getAttributeValue().getValue().toString());
212 } else if ("ConfigName".equals(attribute.getAttributeId().stringValue()
213 .replaceFirst("(matching).", ""))) {
214 match.setConfigName(attribute.getAttributeValue().getValue().toString());
216 configAttributes.put(attribute.getAttributeId().stringValue()
217 .replaceFirst("(matching).", ""),attribute.getAttributeValue().getValue().toString());
219 } else if (attribute.getAttributeId().stringValue().startsWith("key:")) {
220 responseAttributes.put(attribute.getAttributeId().stringValue().replaceFirst("(key).", ""),
221 attribute.getAttributeValue().getValue().toString());
222 } else if (attribute.getAttributeId().stringValue().startsWith("controller:")) {
223 responseAttributes.put("$"+ attribute.getAttributeId().stringValue(),
224 attribute.getAttributeValue().getValue().toString());
225 } else if (attribute.getAttributeId().stringValue().startsWith("dependencies:")) {
226 responseAttributes.put("$dependency$",
227 attribute.getAttributeValue().getValue().toString());
230 if (!configAttributes.isEmpty()) {
231 match.setConfigAttributes(configAttributes);
233 if ((config == 1) && (uri == 1)) {
234 // If there is a configuration.
236 LOGGER.debug("Configuration Call to : " + configURL);
237 pdpResponse = configCall(pdpConfigLocation);
238 } catch (Exception e) {
239 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW+ e);
240 pdpResponse.setStatus("Error in Calling the Configuration URL "+ e,
241 PolicyResponseStatus.NO_ACTION_REQUIRED,
242 PolicyConfigStatus.CONFIG_NOT_FOUND);
244 pdpResponse.setPolicyName(policyName);
245 pdpResponse.setPolicyVersion(policyVersion);
246 pdpResponse.setMatchingConditions(matchingConditions);
247 pdpResponse.setResponseAttributes(responseAttributes);
249 combinedResult.add(pdpResponse);
251 if(!uniqueResult.isEmpty()){
252 if(uniqueResult.containsKey(priority)){
253 // Not any more unique, check the matching conditions size
254 int oldSize = uniqueResult.get(priority).getMatchingConditions().size();
255 int newSize = matchingConditions.size();
256 if(oldSize < newSize){
257 uniqueResult.put(priority, pdpResponse);
258 }else if(oldSize == newSize){
259 pdpResponse = new PDPResponse();
260 pdpResponse.setStatus("Two/more Policies have Same Priority and matching conditions, Please correct your policies.",
261 PolicyResponseStatus.NO_ACTION_REQUIRED,
262 PolicyConfigStatus.CONFIG_NOT_FOUND);
263 combinedResult.add(pdpResponse);
265 return combinedResult;
268 uniqueResult.put(priority, pdpResponse);
271 uniqueResult.put(priority, pdpResponse);
275 // Else it is Action Taken.
276 LOGGER.info("Action Taken by PDP. ");
277 actionTaken.putAll(adviseAttributes);
278 pdpResponse.setActionTaken(actionTaken);
279 pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.ACTION_TAKEN);
280 pdpResponse.setPolicyResponseMessage("Action Taken by the PDP");
281 combinedResult.add(pdpResponse);
285 if (!result.getObligations().isEmpty()) {
286 // Obligation actions
287 // Action advised should be in obligations.
288 for (Obligation obligation : result.getObligations()) {
289 Map<String, String> actionAdvised = new HashMap<>();
290 PDPResponse pdpResponse = new PDPResponse();
291 for (AttributeAssignment attribute : obligation.getAttributeAssignments()) {
292 actionAdvised.put(attribute.getAttributeId().stringValue(),
293 attribute.getAttributeValue().getValue().toString());
295 pdpResponse.setActionAdvised(actionAdvised);
296 pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.ACTION_ADVISED);
297 pdpResponse.setPolicyResponseMessage("Action has been Advised ");
298 combinedResult.add(pdpResponse);
304 // Select Unique policy.
305 int minNum = DEFAULT_PRIORITY;
306 for(int num: uniqueResult.keySet()){
311 combinedResult.add(uniqueResult.get(minNum));
316 return combinedResult;
319 private String getRainyDayTreatment(Result result) {
320 String treatment = null;
321 if (rainydayRequest!=null&& !result.getAssociatedAdvice().isEmpty()) {
322 // Get the desired treatment for requested errorCode from the Advice
323 for (Advice advice : result.getAssociatedAdvice()) {
324 Map<String, String> adviseAttributes = new HashMap<>();
325 for (AttributeAssignment attribute : advice.getAttributeAssignments()) {
326 adviseAttributes.put(attribute.getAttributeId().stringValue(), attribute.getAttributeValue().getValue().toString());
327 if ("treatment".equalsIgnoreCase(attribute.getAttributeId().stringValue())){
328 treatment = attribute.getAttributeValue().getValue().toString();
336 private PDPResponse configCall(String pdpConfigLocation) throws Exception{
337 PDPResponse pdpResponse = new PDPResponse();
338 if(pdpConfigLocation.contains("/")){
339 pdpConfigLocation = pdpConfigLocation.replace("/", File.separator);
341 InputStream inputStream = null;
343 inputStream = new FileInputStream(new File(pdpConfigLocation));
345 if (pdpConfigLocation.endsWith("json")) {
346 pdpResponse.setType(PolicyType.JSON);
347 JsonReader jsonReader = Json.createReader(inputStream);
348 pdpResponse.setConfig(jsonReader.readObject().toString());
350 } else if (pdpConfigLocation.endsWith("xml")) {
351 pdpResponse.setType(PolicyType.XML);
352 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
353 dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
354 dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
355 DocumentBuilder db = null;
357 db = dbf.newDocumentBuilder();
358 Document document = db.parse(inputStream);
359 DOMSource domSource = new DOMSource(document);
360 StringWriter writer = new StringWriter();
361 StreamResult result = new StreamResult(writer);
362 TransformerFactory tf = TransformerFactory.newInstance();
363 Transformer transformer;
364 transformer = tf.newTransformer();
365 transformer.transform(domSource, result);
366 pdpResponse.setConfig(writer.toString());
367 } catch (Exception e) {
368 LOGGER.error(XACMLErrorConstants.ERROR_SCHEMA_INVALID+ e);
369 throw new Exception(XACMLErrorConstants.ERROR_SCHEMA_INVALID+ "Unable to parse the XML config", e);
371 } else if (pdpConfigLocation.endsWith("properties")) {
372 pdpResponse.setType(PolicyType.PROPERTIES);
373 Properties configProp = new Properties();
374 configProp.load(inputStream);
375 Map<String, String> propVal = new HashMap<>();
376 for(String name: configProp.stringPropertyNames()) {
377 propVal.put(name, configProp.getProperty(name));
379 pdpResponse.setProperty(propVal);
380 } else if (pdpConfigLocation.endsWith("txt")) {
381 pdpResponse.setType(PolicyType.OTHER);
382 String other = IOUtils.toString(inputStream);
383 IOUtils.closeQuietly(inputStream);
384 pdpResponse.setConfig(other);
386 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Config Not Found");
387 pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND);
388 pdpResponse.setPolicyConfigMessage("Illegal form of Configuration Type Found.");
392 LOGGER.info("config Retrieved " + pdpConfigLocation);
393 pdpResponse.setStatus("Config Retrieved! ",
394 PolicyResponseStatus.NO_ACTION_REQUIRED,
395 PolicyConfigStatus.CONFIG_RETRIEVED);
397 } catch (IOException e) {
398 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e);
399 throw new Exception(XACMLErrorConstants.ERROR_PROCESS_FLOW +
400 "Cannot open a connection to the configURL", e);
402 } catch (MalformedURLException e) {
403 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
404 throw new Exception(XACMLErrorConstants.ERROR_DATA_ISSUE + "Error in ConfigURL", e);
406 if(inputStream != null){
412 private Response callPDP(Request request,
413 UUID requestID) throws Exception{
414 Response response = null;
416 if (requestID == null) {
417 requestID = UUID.randomUUID();
418 LOGGER.debug("No request ID provided, sending generated ID: " + requestID.toString());
420 LOGGER.debug("Using provided request ID: " + requestID.toString());
422 PDPEngine pdpEngine = XACMLPdpServlet.getPDPEngine();
423 if (pdpEngine == null) {
424 String message = "PDPEngine not loaded.";
425 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + message);
428 // call the PDPEngine to decide and give the response on the Request.
430 response = pdpEngine.decide(request);
431 LOGGER.info("Response from the PDP is: \n" + JSONResponse.toString(response));
432 } catch (Exception e) {
433 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e);