4476b388be82c3585e5aa6a04deb04d17b556d82
[policy/engine.git] / ECOMP-PDP-REST / src / main / java / org / openecomp / policy / pdp / rest / api / services / PDPServices.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ECOMP-PDP-REST
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20 package org.openecomp.policy.pdp.rest.api.services;
21
22 import java.io.File;
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;
31 import java.util.Map;
32 import java.util.Properties;
33 import java.util.UUID;
34
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;
44
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;
59
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;
71
72 public class PDPServices {
73     private static 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 Matches match = null;
79     
80     public Collection<PDPResponse> generateRequest(String jsonString, UUID requestID, boolean unique, boolean decide) throws PolicyException{
81         this.unique = unique;
82         this.decide = decide;
83         Collection<PDPResponse> results = null;
84         Response response = null;
85         // Create Request. We need XACML API here.
86         try {
87             Request request = JSONRequest.load(jsonString);
88             // Call the PDP
89             LOGGER.debug("--- Generating Request: ---\n" + JSONRequest.toString(request));
90             response = callPDP(request, requestID);
91         } catch (Exception e) {
92             LOGGER.error(XACMLErrorConstants.ERROR_SCHEMA_INVALID + e);
93             PDPResponse pdpResponse = new PDPResponse();
94             results = new HashSet<PDPResponse>();
95             pdpResponse.setPolicyConfigMessage("Unable to Call PDP. Error with the URL");
96             pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND);
97             pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.NO_ACTION_REQUIRED);
98             results.add(pdpResponse);
99             throw new PolicyException(e);
100         }
101         if (response != null) {
102             results = checkResponse(response);
103         } else {
104             LOGGER.debug("No Response Received from PDP");
105             PDPResponse pdpResponse = new PDPResponse();
106             results = new HashSet<PDPResponse>();
107             pdpResponse.setPolicyConfigMessage("No Response Received");
108             pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND);
109             pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.NO_ACTION_REQUIRED);
110             results.add(pdpResponse);
111         }
112         return results;
113     }
114
115     private Collection<PDPResponse> checkResponse(Response response) throws PolicyException{
116         String pdpConfigLocation = null;
117         Collection<PDPResponse> combinedResult = new HashSet<PDPResponse>();
118         int priority = DEFAULT_PRIORITY;
119         Map<Integer, PDPResponse> uniqueResult = new HashMap<Integer, PDPResponse>();
120         for (Result result : response.getResults()) {
121             if (!result.getDecision().equals(Decision.PERMIT)) {
122                 LOGGER.debug("Decision not a Permit. "  + result.getDecision().toString());
123                 PDPResponse pdpResponse = new PDPResponse();
124                 if (decide) {
125                     pdpResponse.setDecision(PolicyDecision.DENY);
126                     for(Advice advice: result.getAssociatedAdvice()){
127                         for(AttributeAssignment attribute: advice.getAttributeAssignments()){
128                             pdpResponse.setDetails(attribute.getAttributeValue().getValue().toString());
129                             break;
130                         }
131                     }
132                     combinedResult.add(pdpResponse);
133                     return combinedResult;
134                 }
135                 pdpResponse.setStatus(XACMLErrorConstants.ERROR_DATA_ISSUE + "Incorrect Params passed: Decision not a Permit.",PolicyResponseStatus.NO_ACTION_REQUIRED,PolicyConfigStatus.CONFIG_NOT_FOUND);
136                 combinedResult.add(pdpResponse);
137                 return combinedResult;
138             } else {
139                 if (decide) {
140                     // check for Decision for decision based calls.
141                     PDPResponse pdpResponse = new PDPResponse();
142                     pdpResponse.setDecision(PolicyDecision.PERMIT);
143                     pdpResponse.setDetails("Decision Permit. OK!");
144                     combinedResult.add(pdpResponse);
145                     return combinedResult;
146                 }
147                 if (!result.getAssociatedAdvice().isEmpty()) {
148                     // Configurations should be in advice. 
149                     // Also PDP took actions could be here.
150                     for (Advice advice : result.getAssociatedAdvice()) {
151                         int config = 0, uri = 0;
152                         String configURL = null;
153                         String policyName = null;
154                         String policyVersion = null;
155                         match = new Matches();
156                         Map<String, String> matchingConditions = new HashMap<String, String>();
157                         Map<String, String> configAttributes = new HashMap<String, String>();
158                         Map<String, String> responseAttributes = new HashMap<String,String>();
159                         Map<String, String> actionTaken = new HashMap<String, String>();
160                         PDPResponse pdpResponse = new PDPResponse();
161                         Map<String, String> adviseAttributes = new HashMap<String, String>();
162                         for (AttributeAssignment attribute : advice.getAttributeAssignments()) {
163                             adviseAttributes.put(attribute.getAttributeId().stringValue(), attribute.getAttributeValue().getValue().toString());
164                             if (attribute.getAttributeValue().getValue().toString().equalsIgnoreCase("CONFIGURATION")) {
165                                 config++;
166                             } else if (attribute.getDataTypeId().stringValue().endsWith("anyURI")) {
167                                 uri++;
168                                 if (uri == 1) {
169                                     configURL = attribute.getAttributeValue().getValue().toString();
170                                     pdpConfigLocation = configURL.replace("$URL", XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_WEBAPPS));
171                                 } else {
172                                     if (!(attribute.getIssuer().equalsIgnoreCase("PDP"))) {
173                                         throw new PolicyException(XACMLErrorConstants.ERROR_DATA_ISSUE + "Error having multiple URI in the Policy");
174                                     }
175                                 }
176                             } else if (attribute.getAttributeId().stringValue().equalsIgnoreCase("PolicyName")) {
177                                 policyName = attribute.getAttributeValue().getValue().toString();
178                             } else if (attribute.getAttributeId().stringValue().equalsIgnoreCase("VersionNumber")) {
179                                 policyVersion = attribute.getAttributeValue().getValue().toString();
180                             } else if (attribute.getAttributeId().stringValue().equalsIgnoreCase("Priority")){
181                                 try{
182                                     priority = Integer.parseInt(attribute.getAttributeValue().getValue().toString());
183                                 } catch(Exception e){
184                                     LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE+ "Unable to Parse Integer for Priority. Setting to default value");
185                                     priority = DEFAULT_PRIORITY;
186                                 }
187                             } else if (attribute.getAttributeId().stringValue().startsWith("matching")) {
188                                 matchingConditions.put(attribute.getAttributeId().stringValue()
189                                         .replaceFirst("(matching).", ""),attribute.getAttributeValue().getValue().toString());
190                                 if (attribute.getAttributeId().stringValue()
191                                         .replaceFirst("(matching).", "").equals("ECOMPName")) {
192                                     match.setEcompName(attribute.getAttributeValue().getValue().toString());
193                                 } else if (attribute.getAttributeId().stringValue()
194                                         .replaceFirst("(matching).", "").equals("ConfigName")) {
195                                     match.setConfigName(attribute.getAttributeValue().getValue().toString());
196                                 } else {
197                                     configAttributes.put(attribute.getAttributeId().stringValue()
198                                             .replaceFirst("(matching).", ""),attribute.getAttributeValue().getValue().toString());
199                                 }
200                             } else if (attribute.getAttributeId().stringValue().startsWith("key:")) {
201                                 responseAttributes.put(attribute.getAttributeId().stringValue().replaceFirst("(key).", ""),
202                                         attribute.getAttributeValue().getValue().toString());
203                             } else if (attribute.getAttributeId().stringValue().startsWith("controller:")) {
204                                 responseAttributes.put("$"+ attribute.getAttributeId().stringValue(),
205                                         attribute.getAttributeValue().getValue().toString());
206                             } else if (attribute.getAttributeId().stringValue().startsWith("dependencies:")) {
207                                 responseAttributes.put("$dependency$",
208                                         attribute.getAttributeValue().getValue().toString());
209                             }
210                         }
211                         if (!configAttributes.isEmpty()) {
212                             match.setConfigAttributes(configAttributes);
213                         }
214                         if ((config == 1) && (uri == 1)) {
215                             // If there is a configuration.
216                             try {
217                                 LOGGER.debug("Configuration Call to : " + configURL);
218                                 pdpResponse = configCall(pdpConfigLocation);
219                             } catch (Exception e) {
220                                 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW+ e);
221                                 pdpResponse.setStatus("Error in Calling the Configuration URL "+ e,
222                                                 PolicyResponseStatus.NO_ACTION_REQUIRED,
223                                                 PolicyConfigStatus.CONFIG_NOT_FOUND);
224                             }
225                             pdpResponse.setPolicyName(policyName);
226                             pdpResponse.setPolicyVersion(policyVersion);
227                             pdpResponse.setMatchingConditions(matchingConditions);
228                             pdpResponse.setResponseAttributes(responseAttributes);
229                             if(!unique){
230                                 combinedResult.add(pdpResponse);
231                             }else{
232                                 if(!uniqueResult.isEmpty()){
233                                     if(uniqueResult.containsKey(priority)){
234                                         // Not any more unique, check the matching conditions size
235                                         int oldSize = uniqueResult.get(priority).getMatchingConditions().size();
236                                         int newSize = matchingConditions.size();
237                                         if(oldSize < newSize){
238                                             uniqueResult.put(priority, pdpResponse);
239                                         }else if(oldSize == newSize){
240                                             pdpResponse = new PDPResponse();
241                                             pdpResponse.setStatus("Two/more Policies have Same Priority and matching conditions, Please correct your policies.",
242                                                     PolicyResponseStatus.NO_ACTION_REQUIRED,
243                                                     PolicyConfigStatus.CONFIG_NOT_FOUND);
244                                             combinedResult.add(pdpResponse);
245                                             unique = false;
246                                             return combinedResult;
247                                         }
248                                     }else{
249                                         uniqueResult.put(priority, pdpResponse);
250                                     }
251                                 }else{
252                                     uniqueResult.put(priority, pdpResponse);
253                                 }
254                             }
255                         } else {
256                             // Else it is Action Taken.
257                             LOGGER.info("Action Taken by PDP. ");
258                             actionTaken.putAll(adviseAttributes);
259                             pdpResponse.setActionTaken(actionTaken);
260                             pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.ACTION_TAKEN);
261                             pdpResponse.setPolicyResponseMessage("Action Taken by the PDP");
262                             combinedResult.add(pdpResponse);
263                         }
264                     }
265                 }
266                 if (!result.getObligations().isEmpty()) {
267                     // Obligation actions
268                     // Action advised should be in obligations.
269                     for (Obligation obligation : result.getObligations()) {
270                         Map<String, String> actionAdvised = new HashMap<String, String>();
271                         PDPResponse pdpResponse = new PDPResponse();
272                         for (AttributeAssignment attribute : obligation.getAttributeAssignments()) {
273                             actionAdvised.put(attribute.getAttributeId().stringValue(),
274                                     attribute.getAttributeValue().getValue().toString());
275                         }
276                         pdpResponse.setActionAdvised(actionAdvised);
277                         pdpResponse.setPolicyResponseStatus(PolicyResponseStatus.ACTION_ADVISED);
278                         pdpResponse.setPolicyResponseMessage("Action has been Advised ");
279                         combinedResult.add(pdpResponse);
280                     }
281                 }
282             }
283         }
284         if(unique){
285             // Select Unique policy. 
286             int minNum = DEFAULT_PRIORITY;
287             for(int num: uniqueResult.keySet()){
288                 if(num < minNum){
289                     minNum = num;
290                 }
291             }
292             combinedResult.add(uniqueResult.get(minNum));
293             // Turn off Unique
294             unique = false;
295         }
296         
297         return combinedResult;
298     }
299
300     private PDPResponse configCall(String pdpConfigLocation) throws Exception{
301         PDPResponse pdpResponse = new PDPResponse();
302         if(pdpConfigLocation.contains("/")){
303             pdpConfigLocation = pdpConfigLocation.replace("/", File.separator);
304         }
305         try {
306             InputStream inputStream = new FileInputStream(new File(pdpConfigLocation));
307             try {
308                 if (pdpConfigLocation.endsWith("json")) {
309                     pdpResponse.setType(PolicyType.JSON);
310                     JsonReader jsonReader = Json.createReader(inputStream);
311                     pdpResponse.setConfig(jsonReader.readObject().toString());
312                     jsonReader.close();
313                 } else if (pdpConfigLocation.endsWith("xml")) {
314                     pdpResponse.setType(PolicyType.XML);
315                     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
316                     dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
317                     dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
318                     DocumentBuilder db = null;
319                     try {
320                         db = dbf.newDocumentBuilder();
321                         Document document = db.parse(inputStream);
322                         DOMSource domSource = new DOMSource(document);
323                         StringWriter writer = new StringWriter();
324                         StreamResult result = new StreamResult(writer);
325                         TransformerFactory tf = TransformerFactory.newInstance();
326                         Transformer transformer;
327                         transformer = tf.newTransformer();
328                         transformer.transform(domSource, result);
329                         pdpResponse.setConfig(writer.toString());
330                     } catch (Exception e) {
331                         LOGGER.error(XACMLErrorConstants.ERROR_SCHEMA_INVALID+ e);
332                         throw new Exception(XACMLErrorConstants.ERROR_SCHEMA_INVALID+ "Unable to parse the XML config", e);
333                     }
334                 } else if (pdpConfigLocation.endsWith("properties")) {
335                     pdpResponse.setType(PolicyType.PROPERTIES);
336                     Properties configProp = new Properties();
337                     configProp.load(inputStream);
338                     Map<String, String> propVal = new HashMap<String, String>();
339                     for(String name: configProp.stringPropertyNames()) {
340                         propVal.put(name, configProp.getProperty(name));
341                     }
342                     pdpResponse.setProperty(propVal);
343                 } else if (pdpConfigLocation.endsWith("txt")) {
344                     pdpResponse.setType(PolicyType.OTHER);
345                     String other = IOUtils.toString(inputStream);
346                     IOUtils.closeQuietly(inputStream);
347                     pdpResponse.setConfig(other);
348                 } else {
349                     LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Config Not Found");
350                     pdpResponse.setPolicyConfigStatus(PolicyConfigStatus.CONFIG_NOT_FOUND);
351                     pdpResponse.setPolicyConfigMessage("Illegal form of Configuration Type Found.");
352                     inputStream.close();
353                     return pdpResponse;
354                 }
355                 LOGGER.info("config Retrieved " + pdpConfigLocation);
356                 pdpResponse.setStatus("Config Retrieved! ",
357                         PolicyResponseStatus.NO_ACTION_REQUIRED,
358                         PolicyConfigStatus.CONFIG_RETRIEVED);
359                 return pdpResponse;
360             } catch (IOException e) {
361                 LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e);
362                 throw new Exception(XACMLErrorConstants.ERROR_PROCESS_FLOW +
363                         "Cannot open a connection to the configURL", e);
364             }
365         } catch (MalformedURLException e) {
366             LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
367             throw new Exception(XACMLErrorConstants.ERROR_DATA_ISSUE + "Error in ConfigURL", e);
368         }
369     }
370
371     private Response callPDP(Request request,
372             UUID requestID) throws Exception{
373         Response response = null;
374         // Get the PDPEngine
375         if (requestID == null) {
376             requestID = UUID.randomUUID();
377             LOGGER.debug("No request ID provided, sending generated ID: " + requestID.toString());
378         } else {
379             LOGGER.debug("Using provided request ID: " + requestID.toString());
380         }
381         PDPEngine pdpEngine = XACMLPdpServlet.getPDPEngine();
382         if (pdpEngine == null) {
383             String message = "PDPEngine not loaded.";
384             LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + message);
385             return response;
386         }
387         // call the PDPEngine to decide and give the response on the Request.
388         try {
389             response = pdpEngine.decide(request);
390             LOGGER.debug("Response from the PDP is: \n" + JSONResponse.toString(response));
391         } catch (Exception e) {
392             LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e);
393             return null;
394         }
395         return response;
396     }
397
398 }