XACML Platform Enhancements
[policy/engine.git] / ONAP-PDP-REST / src / main / java / org / onap / policy / pdp / rest / api / services / GetDecisionService.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-PDP-REST
4  * ================================================================================
5  * Copyright (C) 2017-2018 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
21 package org.onap.policy.pdp.rest.api.services;
22
23 import com.att.research.xacml.api.Decision;
24 import com.att.research.xacml.api.Request;
25 import com.att.research.xacml.api.Response;
26 import com.att.research.xacml.std.dom.DOMRequest;
27 import com.att.research.xacml.std.dom.DOMResponse;
28 import com.att.research.xacml.std.json.JSONRequest;
29 import com.att.research.xacml.std.json.JSONResponse;
30 import java.util.Collection;
31 import java.util.Map;
32 import java.util.Map.Entry;
33 import java.util.UUID;
34 import javax.json.Json;
35 import javax.json.JsonArrayBuilder;
36 import javax.json.JsonObject;
37 import javax.json.JsonObjectBuilder;
38 import org.apache.commons.text.StringEscapeUtils;
39 import org.apache.commons.lang3.StringUtils;
40 import org.onap.policy.api.DecisionRequestParameters;
41 import org.onap.policy.api.DecisionResponse;
42 import org.onap.policy.api.PolicyDecision;
43 import org.onap.policy.api.PolicyDecisionException;
44 import org.onap.policy.common.logging.flexlogger.FlexLogger;
45 import org.onap.policy.common.logging.flexlogger.Logger;
46 import org.onap.policy.pdp.rest.api.models.PDPResponse;
47 import org.onap.policy.std.StdDecisionResponse;
48 import org.onap.policy.xacml.api.XACMLErrorConstants;
49 import org.springframework.http.HttpStatus;
50
51
52
53 public class GetDecisionService {
54     private static final Logger LOGGER = FlexLogger.getLogger(GetDecisionService.class.getName());
55
56     private DecisionResponse decisionResponse = null;
57     private HttpStatus status = HttpStatus.BAD_REQUEST;
58     private DecisionRequestParameters decisionRequestParameters = null;
59     private String message = null;
60     private String onapComponentName = null;
61     private Map<String, String> decisionAttributes = null;
62     private UUID requestUuid = null;
63     private String requestType = null;
64
65     /**
66      * Instantiates a new gets the decision service.
67      *
68      * @param decisionRequestParameters the decision request parameters
69      * @param requestId the request id
70      */
71     public GetDecisionService(DecisionRequestParameters decisionRequestParameters, String requestId) {
72         this.decisionRequestParameters = decisionRequestParameters;
73         if (decisionRequestParameters.getRequestID() == null) {
74             if (!StringUtils.isBlank(requestId)) {
75                 try {
76                     requestUuid = UUID.fromString(requestId);
77                 } catch (IllegalArgumentException e) {
78                     requestUuid = UUID.randomUUID();
79                     LOGGER.info("Generated Random UUID: " + requestUuid.toString(), e);
80                 }
81             } else {
82                 requestUuid = UUID.randomUUID();
83                 LOGGER.info("Generated Random UUID: " + requestUuid.toString());
84             }
85             this.decisionRequestParameters.setRequestID(requestUuid);
86         }
87         try {
88             run();
89         } catch (PolicyDecisionException e) {
90             StdDecisionResponse decisionResp = new StdDecisionResponse();
91             decisionResp.setDecision(PolicyDecision.ERROR);
92             decisionResp.setDetails(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
93             this.decisionResponse = decisionResp;
94             status = HttpStatus.BAD_REQUEST;
95         }
96     }
97
98     private void run() throws PolicyDecisionException {
99         // Get Validation.
100         if (!getValidation()) {
101             LOGGER.error(message);
102             throw new PolicyDecisionException(message);
103         }
104
105         try {
106             // first check whether it is a raw xacml req
107             if (!StringUtils.isBlank(requestType) && PDPServices.DECISION_RAW_XACML.equals(requestType)) {
108                 this.setRequestType(PDPServices.DECISION_RAW_XACML);
109                 processRawXacmlReq();
110                 return;
111             }
112
113             // Generate Request.
114             String modelString = getModel().toString();
115             LOGGER.debug("Generated JSON Request is: " + modelString);
116             // Process Result.
117
118             PDPServices pdpServices = new PDPServices();
119             if (modelString.contains(PDPServices.RAINYDAY_TYPE)) {
120                 pdpServices.setRequestType(PDPServices.RAINYDAY_TYPE);
121                 this.setRequestType(PDPServices.RAINYDAY_TYPE);
122             } else if (PDPServices.DECISION_MS_NAMING_TYPE.equals(requestType)) {
123                 pdpServices.setRequestType(PDPServices.DECISION_MS_NAMING_TYPE);
124             }
125             status = HttpStatus.OK;
126             decisionResponse = decisionResult(
127                     pdpServices.generateRequest(modelString, decisionRequestParameters.getRequestID(), false, true));
128         } catch (Exception e) {
129             LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
130             status = HttpStatus.BAD_REQUEST;
131             throw new PolicyDecisionException(e);
132         }
133     }
134
135     private void processRawXacmlReq() throws PolicyDecisionException {
136         Request pdpRequest = null;
137         Response pdpResponse = null;
138         // Process Result.
139         try {
140             PDPServices pdpServices = new PDPServices();
141             pdpServices.setRequestType(PDPServices.DECISION_RAW_XACML);
142             String rawXacmlReq = decisionAttributes.get(PDPServices.DECISION_RAW_XACML);
143             if (StringUtils.isBlank(rawXacmlReq)) {
144                 LOGGER.error("Raw XACML request cannot be empty.");
145                 throw new PolicyDecisionException(
146                         "Raw XACML request cannot be empty. Please provide the XACML request in "
147                                 + PDPServices.DECISION_RAW_XACML);
148             }
149             String rawXacmlReqMode = decisionAttributes.get(PDPServices.DECISION_RAW_XACML_TYPE);
150             String reqType = PDPServices.DECISION_RAW_XACML_XML_TYPE;
151             if (!StringUtils.isBlank(rawXacmlReqMode)
152                     && PDPServices.DECISION_RAW_XACML_JSON_TYPE.equalsIgnoreCase(rawXacmlReqMode.trim())) {
153                 pdpRequest = JSONRequest.load(rawXacmlReq);
154                 reqType = PDPServices.DECISION_RAW_XACML_JSON_TYPE;
155             } else {
156                 pdpRequest = DOMRequest.load(StringEscapeUtils.unescapeXml(rawXacmlReq));
157                 pdpServices.setRequestFormat(PDPServices.DECISION_RAW_XACML_XML_TYPE);
158             }
159
160             status = HttpStatus.OK;
161             pdpResponse = pdpServices.callPdp(pdpRequest, getRequestUuid());
162
163             String outgoingResponseString = null;
164             if (PDPServices.DECISION_RAW_XACML_JSON_TYPE.equalsIgnoreCase(reqType)) {
165                 outgoingResponseString = JSONResponse.toString(pdpResponse, false);
166             } else {
167                 outgoingResponseString = DOMResponse.toString(pdpResponse, false);
168                 if (!StringUtils.isBlank(outgoingResponseString)) {
169                     outgoingResponseString = StringEscapeUtils.escapeXml10(outgoingResponseString);
170                 }
171             }
172
173             LOGGER.info("processRawXacmlReq - Request - \n" + rawXacmlReq + "\n Reponse:\n" + outgoingResponseString);
174             StdDecisionResponse decisionResp = new StdDecisionResponse();
175             if (!StringUtils.isBlank(outgoingResponseString)
176                     && outgoingResponseString.contains(Decision.PERMIT.toString())) {
177                 decisionResp.setDecision(PolicyDecision.PERMIT);
178             } else if (!StringUtils.isBlank(outgoingResponseString)
179                     && outgoingResponseString.contains(Decision.DENY.toString())) {
180                 decisionResp.setDecision(PolicyDecision.DENY);
181             } else {
182                 decisionResp.setDecision(PolicyDecision.ERROR);
183             }
184             decisionResp.setDetails(outgoingResponseString);
185             this.decisionResponse = decisionResp;
186         } catch (Exception e) {
187             LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
188             status = HttpStatus.BAD_REQUEST;
189             throw new PolicyDecisionException(e);
190         }
191     }
192
193     private DecisionResponse decisionResult(Collection<PDPResponse> generateRequest) {
194         StdDecisionResponse policyDecision = new StdDecisionResponse();
195         if (generateRequest == null) {
196             return policyDecision;
197         }
198         if (!generateRequest.isEmpty()) {
199             for (PDPResponse stdStatus : generateRequest) {
200                 policyDecision.setDecision(stdStatus.getDecision());
201                 policyDecision.setDetails(stdStatus.getDetails());
202             }
203         }
204         return policyDecision;
205     }
206
207     private JsonObject getModel() throws PolicyDecisionException {
208         JsonArrayBuilder resourceArray = Json.createArrayBuilder();
209         for (Entry<String, String> entry : decisionAttributes.entrySet()) {
210             if (entry.getKey().isEmpty()) {
211                 String msg = XACMLErrorConstants.ERROR_DATA_ISSUE + "Cannot have an Empty Key";
212                 LOGGER.error(msg);
213                 throw new PolicyDecisionException(msg);
214             }
215             if (PDPServices.DECISION_MS_NAMING_TYPE.equalsIgnoreCase(entry.getKey().trim())) {
216                 // this is used for only Model execution and not for identifying
217                 // policy. It is input data for MS Naming model execution and
218                 // will be parsed in the naming service. Skip here.
219                 this.setRequestType(PDPServices.DECISION_MS_NAMING_TYPE);
220                 continue;
221             }
222
223             JsonObjectBuilder resourceBuilder = Json.createObjectBuilder();
224             if (entry.getValue().matches("[0-9]+")) {
225
226                 if ((entry.getKey().equals("ErrorCode")) || (entry.getKey().equals("WorkStep"))) {
227
228                     resourceBuilder.add("Value", entry.getValue());
229
230                 } else {
231
232                     int val = Integer.parseInt(entry.getValue());
233                     resourceBuilder.add("Value", val);
234
235                 }
236
237             } else {
238                 resourceBuilder.add("Value", entry.getValue());
239             }
240             resourceBuilder.add("AttributeId", entry.getKey());
241             resourceArray.add(resourceBuilder);
242         }
243         return Json.createObjectBuilder().add("Request", Json.createObjectBuilder().add("AccessSubject",
244                 Json.createObjectBuilder().add("Attribute",
245                         Json.createObjectBuilder().add("Value", onapComponentName).add("AttributeId", "ONAPName")))
246                 .add("Resource", Json.createObjectBuilder().add("Attribute", resourceArray))
247                 .add("Action", Json.createObjectBuilder().add("Attribute", Json.createObjectBuilder()
248                         .add("Value", "DECIDE").add("AttributeId", "urn:oasis:names:tc:xacml:1.0:action:action-id"))))
249                 .build();
250     }
251
252     private boolean getValidation() {
253         if (decisionRequestParameters == null) {
254             message = XACMLErrorConstants.ERROR_DATA_ISSUE + "No Decision Request Paramaters";
255             return false;
256         }
257         onapComponentName = decisionRequestParameters.getOnapName();
258         decisionAttributes = decisionRequestParameters.getDecisionAttributes();
259         if (decisionAttributes == null || decisionAttributes.isEmpty()) {
260             message = XACMLErrorConstants.ERROR_DATA_ISSUE + "No Decision Attributes Given. ";
261             return false;
262         }
263         if (decisionAttributes.containsKey(PDPServices.DECISION_RAW_XACML)) {
264             // onapName not mandatory for raw requests
265             requestType = PDPServices.DECISION_RAW_XACML;
266         } else if (onapComponentName == null || onapComponentName.isEmpty()) {
267             message = XACMLErrorConstants.ERROR_DATA_ISSUE + "No onapComponentName given : " + onapComponentName;
268             return false;
269         }
270
271         return true;
272     }
273
274     public DecisionResponse getResult() {
275         return decisionResponse;
276     }
277
278     public HttpStatus getResponseCode() {
279         return status;
280     }
281
282     public UUID getRequestUuid() {
283         return requestUuid;
284     }
285
286     public void setRequestUuid(UUID requestId) {
287         this.requestUuid = requestId;
288     }
289
290     public String getRequestType() {
291         return requestType;
292     }
293
294     public void setRequestType(String requestType) {
295         this.requestType = requestType;
296     }
297
298 }