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=========================================================
21 package org.openecomp.policy.pdp.rest;
23 import java.io.BufferedReader;
24 import java.io.ByteArrayInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.OutputStream;
29 import java.net.InetAddress;
30 import java.net.UnknownHostException;
31 import java.nio.file.Files;
32 import java.util.Properties;
33 import java.util.UUID;
34 import java.util.concurrent.BlockingQueue;
35 import java.util.concurrent.LinkedBlockingQueue;
37 import javax.servlet.Servlet;
38 import javax.servlet.ServletConfig;
39 import javax.servlet.ServletException;
40 import javax.servlet.annotation.WebInitParam;
41 import javax.servlet.annotation.WebServlet;
42 import javax.servlet.http.HttpServlet;
43 import javax.servlet.http.HttpServletRequest;
44 import javax.servlet.http.HttpServletResponse;
46 import org.apache.commons.io.IOUtils;
47 import org.apache.commons.logging.Log;
48 import org.apache.commons.logging.LogFactory;
49 import org.apache.http.entity.ContentType;
50 import org.openecomp.policy.pdp.rest.jmx.PdpRestMonitor;
51 import org.openecomp.policy.rest.XACMLRest;
52 import org.openecomp.policy.rest.XACMLRestProperties;
53 import org.openecomp.policy.common.logging.ECOMPLoggingContext;
54 import org.openecomp.policy.common.logging.ECOMPLoggingUtils;
55 import org.openecomp.policy.common.logging.eelf.MessageCodes;
56 import org.openecomp.policy.common.logging.eelf.PolicyLogger;
57 import org.openecomp.policy.common.im.AdministrativeStateException;
58 import org.openecomp.policy.common.im.ForwardProgressException;
59 import org.openecomp.policy.common.im.IntegrityMonitor;
60 import org.openecomp.policy.common.im.IntegrityMonitorProperties;
61 import org.openecomp.policy.common.im.StandbyStatusException;
63 import com.att.research.xacml.api.Request;
64 import com.att.research.xacml.api.Response;
65 import org.openecomp.policy.xacml.api.XACMLErrorConstants;
66 import com.att.research.xacml.api.pap.PDPStatus.Status;
67 import com.att.research.xacml.api.pdp.PDPEngine;
68 import com.att.research.xacml.api.pdp.PDPException;
69 import com.att.research.xacml.std.dom.DOMRequest;
70 import com.att.research.xacml.std.dom.DOMResponse;
71 import com.att.research.xacml.std.json.JSONRequest;
72 import com.att.research.xacml.std.json.JSONResponse;
73 import com.att.research.xacml.util.XACMLProperties;
74 import org.openecomp.policy.xacml.pdp.std.functions.PolicyList;
75 import org.openecomp.policy.xacml.std.pap.StdPDPStatus;
76 import com.fasterxml.jackson.databind.ObjectMapper;
79 * Servlet implementation class XacmlPdpServlet
81 * This is an implementation of the XACML 3.0 RESTful Interface with added features to support
82 * simple PAP RESTful API for policy publishing and PIP configuration changes.
84 * If you are running this the first time, then we recommend you look at the xacml.pdp.properties file.
85 * This properties file has all the default parameter settings. If you are running the servlet as is,
86 * then we recommend setting up you're container to run it on port 8080 with context "/pdp". Wherever
87 * the default working directory is set to, a "config" directory will be created that holds the policy
88 * and pip cache. This setting is located in the xacml.pdp.properties file.
90 * When you are ready to customize, you can create a separate xacml.pdp.properties on you're local file
91 * system and setup the parameters as you wish. Just set the Java VM System variable to point to that file:
93 * -Dxacml.properties=/opt/app/xacml/etc/xacml.pdp.properties
95 * Or if you only want to change one or two properties, simply set the Java VM System variable for that property.
97 * -Dxacml.rest.pdp.register=false
102 description = "Implements the XACML PDP RESTful API and client PAP API.",
103 urlPatterns = { "/" },
106 @WebInitParam(name = "XACML_PROPERTIES_NAME", value = "xacml.pdp.properties", description = "The location of the PDP xacml.pdp.properties file holding configuration information.")
108 public class XACMLPdpServlet extends HttpServlet implements Runnable {
109 private static final long serialVersionUID = 1L;
110 private static final String DEFAULT_MAX_CONTENT_LENGTH = "999999999"; //32767
112 // Our application debug log
114 private static final Log logger = LogFactory.getLog(XACMLPdpServlet.class);
116 // This logger is specifically only for Xacml requests and their corresponding response.
117 // It's output ideally should be sent to a separate file from the application logger.
119 private static final Log requestLogger = LogFactory.getLog("xacml.request");
122 private static final Log auditLogger = LogFactory.getLog("auditLogger");
124 private static final PdpRestMonitor monitor = PdpRestMonitor.singleton;
127 // This thread may getting invoked on startup, to let the PAP know
128 // that we are up and running.
130 private Thread registerThread = null;
131 private XACMLPdpRegisterThread registerRunnable = null;
133 // This is our PDP engine pointer. There is a synchronized lock used
134 // for access to the pointer. In case we are servicing PEP requests while
135 // an update is occurring from the PAP.
137 private PDPEngine pdpEngine = null;
138 private static final Object pdpEngineLock = new Object();
140 // This is our PDP's status. What policies are loaded (or not) and
141 // what PIP configurations are loaded (or not).
142 // There is a synchronized lock used for access to the object.
144 private static volatile StdPDPStatus status = new StdPDPStatus();
145 private static final Object pdpStatusLock = new Object();
147 private static final String ENVIORNMENT_HEADER = "Environment";
148 private static String environment = null;
150 // Queue of PUT requests
152 public static class PutRequest {
153 public Properties policyProperties = null;
154 public Properties pipConfigProperties = null;
156 PutRequest(Properties policies, Properties pips) {
157 this.policyProperties = policies;
158 this.pipConfigProperties = pips;
161 public static volatile BlockingQueue<PutRequest> queue = null;
162 // For notification Delay.
163 private static int notificationDelay = 0;
164 public static int getNotificationDelay(){
165 return XACMLPdpServlet.notificationDelay;
168 private static String pdpResourceName;
169 private static String dependencyGroups = null;
170 private static String[] dependencyNodes = null;
173 // This is our configuration thread that attempts to load
174 // a new configuration request.
176 private Thread configThread = null;
177 private volatile boolean configThreadTerminate = false;
178 private ECOMPLoggingContext baseLoggingContext = null;
179 private IntegrityMonitor im;
181 * Default constructor.
183 public XACMLPdpServlet() {
187 * @see Servlet#init(ServletConfig)
189 public void init(ServletConfig config) throws ServletException {
193 XACMLRest.xacmlInit(config);
194 // Load the Notification Delay.
196 XACMLPdpServlet.notificationDelay = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_NOTIFICATION_DELAY));
198 logger.info("Notification Delay Not set. Keeping it 0 as default.");
201 int queueSize = 5; // Set default Queue Size here.
202 queueSize = Integer.parseInt(XACMLProperties.getProperty("REQUEST_BUFFER_SIZE",String.valueOf(queueSize)));
203 queue = new LinkedBlockingQueue<PutRequest>(queueSize);
204 // Load our engine - this will use the latest configuration
205 // that was saved to disk and set our initial status object.
207 PDPEngine engine = XACMLPdpLoader.loadEngine(XACMLPdpServlet.status, null, null);
208 if (engine != null) {
209 synchronized(pdpEngineLock) {
216 baseLoggingContext = new ECOMPLoggingContext();
217 // fixed data that will be the same in all logging output goes here
219 String hostname = InetAddress.getLocalHost().getCanonicalHostName();
220 baseLoggingContext.setServer(hostname);
221 } catch (UnknownHostException e) {
222 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Unable to get hostname for logging");
225 Properties properties;
227 properties = XACMLProperties.getProperties();
228 } catch (IOException e) {
229 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e,
230 "Error loading properties with: XACMLProperties.getProperties()");
231 throw new ServletException(e.getMessage(), e.getCause());
234 pdpResourceName = properties.getProperty(XACMLRestProperties.PDP_RESOURCE_NAME);
235 if(pdpResourceName == null){
236 PolicyLogger.error(MessageCodes.MISS_PROPERTY_ERROR, XACMLRestProperties.PDP_RESOURCE_NAME, "xacml.pdp");
237 throw new ServletException("pdpResourceName is null");
240 dependencyGroups = properties.getProperty(IntegrityMonitorProperties.DEPENDENCY_GROUPS);
241 if(dependencyGroups == null){
242 PolicyLogger.error(MessageCodes.MISS_PROPERTY_ERROR, IntegrityMonitorProperties.DEPENDENCY_GROUPS, "xacml.pdp");
243 throw new ServletException("dependency_groups is null");
245 // dependency_groups is a semicolon-delimited list of groups, and
246 // each group is a comma-separated list of nodes. For our purposes
247 // we just need a list of dependencies without regard to grouping,
248 // so split the list into nodes separated by either comma or semicolon.
249 dependencyNodes = dependencyGroups.split("[;,]");
250 for (int i = 0 ; i < dependencyNodes.length ; i++){
251 dependencyNodes[i] = dependencyNodes[i].trim();
255 // Create an IntegrityMonitor
257 logger.info("Creating IntegrityMonitor");
258 im = IntegrityMonitor.getInstance(pdpResourceName, properties);
259 } catch (Exception e) {
260 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "Failed to create IntegrityMonitor");
261 throw new ServletException(e);
264 environment = XACMLProperties.getProperty("ENVIRONMENT", "DEVL");
266 // Kick off our thread to register with the PAP servlet.
268 if (Boolean.parseBoolean(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_REGISTER))) {
269 this.registerRunnable = new XACMLPdpRegisterThread(baseLoggingContext);
270 this.registerThread = new Thread(this.registerRunnable);
271 this.registerThread.start();
274 // This is our thread that manages incoming configuration
277 this.configThread = new Thread(this);
278 this.configThread.start();
282 * @see Servlet#destroy()
284 public void destroy() {
286 logger.info("Destroying....");
288 // Make sure the register thread is not running
290 if (this.registerRunnable != null) {
292 this.registerRunnable.terminate();
293 if (this.registerThread != null) {
294 this.registerThread.interrupt();
295 this.registerThread.join();
297 } catch (InterruptedException e) {
298 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
299 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "");
303 // Make sure the configure thread is not running
305 this.configThreadTerminate = true;
307 this.configThread.interrupt();
308 this.configThread.join();
309 } catch (InterruptedException e) {
310 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
311 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "");
313 logger.info("Destroyed.");
317 * PUT - The PAP engine sends configuration information using HTTP PUT request.
319 * One parameter is expected:
321 * config=[policy|pip|all]
323 * policy - Expect a properties file that contains updated lists of the root and referenced policies that the PDP should
324 * be using for PEP requests.
326 * Specifically should AT LEAST contain the following properties:
328 * xacml.referencedPolicies
330 * In addition, any relevant information needed by the PDP to load or retrieve the policies to store in its cache.
333 * xacml.rootPolicies=PolicyA.1, PolicyB.1
335 * PolicyA.1.url=http://localhost:9090/PAP?id=b2d7b86d-d8f1-4adf-ba9d-b68b2a90bee1&version=1
336 * PolicyB.1.url=http://localhost:9090/PAP/id=be962404-27f6-41d8-9521-5acb7f0238be&version=1
338 * xacml.referencedPolicies=RefPolicyC.1, RefPolicyD.1
340 * RefPolicyC.1.url=http://localhost:9090/PAP?id=foobar&version=1
341 * RefPolicyD.1.url=http://localhost:9090/PAP/id=example&version=1
343 * pip - Expect a properties file that contain PIP engine configuration properties.
345 * Specifically should AT LEAST the following property:
348 * In addition, any relevant information needed by the PDP to load and configure the PIPs.
351 * xacml.pip.engines=foo,bar
353 * foo.classname=com.foo
358 * bar.classname=com.bar
361 * all - Expect ALL new configuration properties for the PDP
363 * @see HttpServlet#doPut(HttpServletRequest request, HttpServletResponse response)
365 protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
366 ECOMPLoggingContext loggingContext = ECOMPLoggingUtils.getLoggingContextForRequest(request, baseLoggingContext);
367 loggingContext.transactionStarted();
368 if ((loggingContext.getRequestID() == null) || (loggingContext.getRequestID() == "")){
369 UUID requestID = UUID.randomUUID();
370 loggingContext.setRequestID(requestID.toString());
371 PolicyLogger.info("requestID not provided in call to XACMLPdpSrvlet (doPut) so we generated one");
373 PolicyLogger.info("requestID was provided in call to XACMLPdpSrvlet (doPut)");
375 loggingContext.metricStarted();
376 loggingContext.metricEnded();
377 PolicyLogger.metrics("Metric example posted here - 1 of 2");
378 loggingContext.metricStarted();
379 loggingContext.metricEnded();
380 PolicyLogger.metrics("Metric example posted here - 2 of 2");
382 // Dump our request out
384 if (logger.isDebugEnabled()) {
385 XACMLRest.dumpRequest(request);
389 im.startTransaction();
391 catch (AdministrativeStateException | StandbyStatusException e) {
392 String message = e.toString();
393 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
394 loggingContext.transactionEnded();
395 PolicyLogger.audit("Transaction Failed - See Error.log");
396 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
400 // What is being PUT?
402 String cache = request.getParameter("cache");
404 // Should be a list of policy and pip configurations in Java properties format
406 if (cache != null && request.getContentType().equals("text/x-java-properties")) {
407 loggingContext.setServiceName("PDP.putConfig");
408 if (request.getContentLength() > Integer.parseInt(XACMLProperties.getProperty("MAX_CONTENT_LENGTH", DEFAULT_MAX_CONTENT_LENGTH))) {
409 String message = "Content-Length larger than server will accept.";
410 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
411 loggingContext.transactionEnded();
412 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
413 PolicyLogger.audit("Transaction Failed - See Error.log");
414 response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
418 this.doPutConfig(cache, request, response, loggingContext);
419 loggingContext.transactionEnded();
420 PolicyLogger.audit("Transaction ended");
424 String message = "Invalid cache: '" + cache + "' or content-type: '" + request.getContentType() + "'";
425 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message);
426 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
427 loggingContext.transactionEnded();
428 PolicyLogger.audit("Transaction Failed - See Error.log");
429 response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
435 protected void doPutConfig(String config, HttpServletRequest request, HttpServletResponse response, ECOMPLoggingContext loggingContext) throws ServletException, IOException {
437 // prevent multiple configuration changes from stacking up
438 if (XACMLPdpServlet.queue.remainingCapacity() <= 0) {
439 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Queue capacity reached");
440 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Queue capacity reached");
441 loggingContext.transactionEnded();
442 PolicyLogger.audit("Transaction Failed - See Error.log");
443 response.sendError(HttpServletResponse.SC_CONFLICT, "Multiple configuration changes waiting processing.");
447 // Read the properties data into an object.
449 Properties newProperties = new Properties();
450 newProperties.load(request.getInputStream());
451 // should have something in the request
452 if (newProperties.size() == 0) {
453 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No properties in PUT");
454 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No properties in PUT");
455 loggingContext.transactionEnded();
456 PolicyLogger.audit("Transaction Failed - See Error.log");
457 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT must contain at least one property");
461 // Which set of properties are they sending us? Whatever they send gets
462 // put on the queue (if there is room).
463 // For audit logging purposes, we consider the transaction done once the
464 // the request gets put on the queue.
466 if (config.equals("policies")) {
467 newProperties = XACMLProperties.getPolicyProperties(newProperties, true);
468 if (newProperties.size() == 0) {
469 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No policy properties in PUT");
470 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No policy properties in PUT");
471 loggingContext.transactionEnded();
472 PolicyLogger.audit("Transaction Failed - See Error.log");
473 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=policies must contain at least one policy property");
476 XACMLPdpServlet.queue.offer(new PutRequest(newProperties, null));
477 loggingContext.transactionEnded();
478 auditLogger.info("Success");
479 PolicyLogger.audit("Success");
480 } else if (config.equals("pips")) {
481 newProperties = XACMLProperties.getPipProperties(newProperties);
482 if (newProperties.size() == 0) {
483 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No pips properties in PUT");
484 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No pips properties in PUT");
485 loggingContext.transactionEnded();
486 PolicyLogger.audit("Transaction Failed - See Error.log");
487 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=pips must contain at least one pip property");
490 XACMLPdpServlet.queue.offer(new PutRequest(null, newProperties));
491 loggingContext.transactionEnded();
492 auditLogger.info("Success");
493 PolicyLogger.audit("Success");
494 } else if (config.equals("all")) {
495 Properties newPolicyProperties = XACMLProperties.getPolicyProperties(newProperties, true);
496 if (newPolicyProperties.size() == 0) {
497 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No policy properties in PUT");
498 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No policy properties in PUT");
499 loggingContext.transactionEnded();
500 PolicyLogger.audit("Transaction Failed - See Error.log");
501 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=all must contain at least one policy property");
504 Properties newPipProperties = XACMLProperties.getPipProperties(newProperties);
505 if (newPipProperties.size() == 0) {
506 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No pips properties in PUT");
507 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No pips properties in PUT");
508 loggingContext.transactionEnded();
509 PolicyLogger.audit("Transaction Failed - See Error.log");
510 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=all must contain at least one pip property");
513 XACMLPdpServlet.queue.offer(new PutRequest(newPolicyProperties, newPipProperties));
514 loggingContext.transactionEnded();
515 auditLogger.info("Success");
516 PolicyLogger.audit("Success");
521 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Invalid config value: " + config);
522 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "Invalid config value: " + config);
523 loggingContext.transactionEnded();
524 PolicyLogger.audit("Transaction Failed - See Error.log");
525 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Config must be one of 'policies', 'pips', 'all'");
528 } catch (Exception e) {
529 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Failed to process new configuration.", e);
530 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "Failed to process new configuration");
531 loggingContext.transactionEnded();
532 PolicyLogger.audit("Transaction Failed - See Error.log");
533 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
540 * Parameters: type=hb|config|Status
542 * 1. HeartBeat Status
544 * OK - All Policies are Loaded, All PIPs are Loaded
545 * LOADING_IN_PROGRESS - Currently loading a new policy set/pip configuration
546 * LAST_UPDATE_FAILED - Need to track the items that failed during last update
547 * LOAD_FAILURE - ??? Need to determine what information is sent and how
550 * return the StdPDPStatus object in the Response content
553 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
555 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
556 ECOMPLoggingContext loggingContext = ECOMPLoggingUtils.getLoggingContextForRequest(request, baseLoggingContext);
557 loggingContext.transactionStarted();
558 if ((loggingContext.getRequestID() == null) || (loggingContext.getRequestID() == "")){
559 UUID requestID = UUID.randomUUID();
560 loggingContext.setRequestID(requestID.toString());
561 PolicyLogger.info("requestID not provided in call to XACMLPdpSrvlet (doGet) so we generated one");
563 PolicyLogger.info("requestID was provided in call to XACMLPdpSrvlet (doGet)");
565 loggingContext.metricStarted();
566 loggingContext.metricEnded();
567 PolicyLogger.metrics("Metric example posted here - 1 of 2");
568 loggingContext.metricStarted();
569 loggingContext.metricEnded();
570 PolicyLogger.metrics("Metric example posted here - 2 of 2");
572 XACMLRest.dumpRequest(request);
574 String pathInfo = request.getRequestURI();
575 if (pathInfo != null){
576 // health check from Global Site Selector (iDNS).
577 // DO NOT do a im.startTransaction for the test request
578 if (pathInfo.equals("/pdp/test")) {
579 loggingContext.setServiceName("iDNS:PDP.test");
582 //If we make it this far, all is well
583 String message = "GET:/pdp/test called and PDP " + pdpResourceName + " is OK";
584 PolicyLogger.debug(message);
585 loggingContext.transactionEnded();
586 PolicyLogger.audit("Success");
587 response.setStatus(HttpServletResponse.SC_OK);
589 } catch (ForwardProgressException fpe){
590 //No forward progress is being made
591 String message = "GET:/pdp/test called and PDP " + pdpResourceName + " is not making forward progress."
592 + " Exception Message: " + fpe.getMessage();
593 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
594 loggingContext.transactionEnded();
595 PolicyLogger.audit("Transaction Failed - See Error.log");
596 // PolicyLogger.audit(MessageCodes.ERROR_SYSTEM_ERROR, message );
597 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
599 }catch (AdministrativeStateException ase){
600 //Administrative State is locked
601 String message = "GET:/pdp/test called and PDP " + pdpResourceName + " Administrative State is LOCKED "
602 + " Exception Message: " + ase.getMessage();
603 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
604 loggingContext.transactionEnded();
605 PolicyLogger.audit("Transaction Failed - See Error.log");
606 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
608 }catch (StandbyStatusException sse){
609 //Administrative State is locked
610 String message = "GET:/pdp/test called and PDP " + pdpResourceName + " Standby Status is NOT PROVIDING SERVICE "
611 + " Exception Message: " + sse.getMessage();
612 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
613 loggingContext.transactionEnded();
614 PolicyLogger.audit("Transaction Failed - See Error.log");
615 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
617 } catch (Exception e) {
618 //A subsystem is not making progress or is not responding
619 String eMsg = e.getMessage();
621 eMsg = "No Exception Message";
623 String message = "GET:/pdp/test called and PDP " + pdpResourceName + " has had a subsystem failure."
624 + " Exception Message: " + eMsg;
625 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
626 //Get the specific list of subsystems that failed
627 String failedNodeList = null;
628 for(String node : dependencyNodes){
629 if(eMsg.contains(node)){
630 if(failedNodeList == null){
631 failedNodeList = node;
633 failedNodeList = failedNodeList.concat(","+node);
637 if(failedNodeList == null){
638 failedNodeList = "UnknownSubSystem";
640 response.addHeader("X-ECOMP-SubsystemFailure", failedNodeList);
641 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
642 loggingContext.transactionEnded();
643 PolicyLogger.audit("Transaction Failed - See Error.log");
650 im.startTransaction();
652 catch (AdministrativeStateException | StandbyStatusException e) {
653 String message = e.toString();
654 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
655 loggingContext.transactionEnded();
656 PolicyLogger.audit("Transaction Failed - See Error.log");
657 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
661 // What are they requesting?
663 boolean returnHB = false;
664 response.setHeader("Cache-Control", "no-cache");
665 String type = request.getParameter("type");
666 // type might be null, so use equals on string constants
667 if ("config".equals(type)) {
668 loggingContext.setServiceName("PDP.getConfig");
669 response.setContentType("text/x-java-properties");
671 String lists = XACMLProperties.PROP_ROOTPOLICIES + "=" + XACMLProperties.getProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
672 lists = lists + "\n" + XACMLProperties.PROP_REFERENCEDPOLICIES + "=" + XACMLProperties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "") + "\n";
673 try (InputStream listInputStream = new ByteArrayInputStream(lists.getBytes());
674 InputStream pipInputStream = Files.newInputStream(XACMLPdpLoader.getPIPConfig());
675 OutputStream os = response.getOutputStream()) {
676 IOUtils.copy(listInputStream, os);
677 IOUtils.copy(pipInputStream, os);
679 loggingContext.transactionEnded();
680 auditLogger.info("Success");
681 PolicyLogger.audit("Success");
682 response.setStatus(HttpServletResponse.SC_OK);
683 } catch (Exception e) {
684 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Failed to copy property file", e);
685 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "Failed to copy property file");
686 loggingContext.transactionEnded();
687 PolicyLogger.audit("Transaction Failed - See Error.log");
688 response.sendError(400, "Failed to copy Property file");
691 } else if ("hb".equals(type)) {
693 response.setStatus(HttpServletResponse.SC_NO_CONTENT);
695 } else if ("Status".equals(type)) {
696 loggingContext.setServiceName("PDP.getStatus");
697 // convert response object to JSON and include in the response
698 synchronized(pdpStatusLock) {
699 ObjectMapper mapper = new ObjectMapper();
700 mapper.writeValue(response.getOutputStream(), status);
702 response.setStatus(HttpServletResponse.SC_OK);
703 loggingContext.transactionEnded();
704 auditLogger.info("Success");
705 PolicyLogger.audit("Success");
708 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Invalid type value: " + type);
709 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "Invalid type value: " + type);
710 loggingContext.transactionEnded();
711 PolicyLogger.audit("Transaction Failed - See Error.log");
712 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "type not 'config' or 'hb'");
715 synchronized(pdpStatusLock) {
716 response.addHeader(XACMLRestProperties.PROP_PDP_HTTP_HEADER_HB, status.getStatus().toString());
719 loggingContext.transactionEnded();
720 PolicyLogger.audit("Transaction Ended");
726 * POST - We expect XACML requests to be posted by PEP applications. They can be in the form of XML or JSON according
727 * to the XACML 3.0 Specifications for both.
730 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
732 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
734 ECOMPLoggingContext loggingContext = ECOMPLoggingUtils.getLoggingContextForRequest(request, baseLoggingContext);
735 loggingContext.transactionStarted();
736 loggingContext.setServiceName("PDP.decide");
737 if ((loggingContext.getRequestID() == null) || (loggingContext.getRequestID() == "")){
738 UUID requestID = UUID.randomUUID();
739 loggingContext.setRequestID(requestID.toString());
740 PolicyLogger.info("requestID not provided in call to XACMLPdpSrvlet (doPost) so we generated one");
742 PolicyLogger.info("requestID was provided in call to XACMLPdpSrvlet (doPost)");
744 loggingContext.metricStarted();
745 loggingContext.metricEnded();
746 PolicyLogger.metrics("Metric example posted here - 1 of 2");
747 loggingContext.metricStarted();
748 loggingContext.metricEnded();
749 PolicyLogger.metrics("Metric example posted here - 2 of 2");
750 monitor.pdpEvaluationAttempts();
753 im.startTransaction();
755 catch (AdministrativeStateException | StandbyStatusException e) {
756 String message = e.toString();
757 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
758 loggingContext.transactionEnded();
759 PolicyLogger.audit("Transaction Failed - See Error.log");
760 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
764 // no point in doing any work if we know from the get-go that we cannot do anything with the request
766 if (status.getLoadedRootPolicies().size() == 0) {
767 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Request from PEP at " + request.getRequestURI() + " for service when PDP has No Root Policies loaded");
768 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, "Request from PEP at " + request.getRequestURI() + " for service when PDP has No Root Policies loaded");
769 loggingContext.transactionEnded();
770 PolicyLogger.audit("Transaction Failed - See Error.log");
771 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
776 XACMLRest.dumpRequest(request);
778 // Set our no-cache header
780 response.setHeader("Cache-Control", "no-cache");
782 // They must send a Content-Type
784 if (request.getContentType() == null) {
785 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Must specify a Content-Type");
786 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "Must specify a Content-Type");
787 loggingContext.transactionEnded();
788 PolicyLogger.audit("Transaction Failed - See Error.log");
789 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "no content-type given");
794 // Limit the Content-Length to something reasonable
796 if (request.getContentLength() > Integer.parseInt(XACMLProperties.getProperty("MAX_CONTENT_LENGTH", "32767"))) {
797 String message = "Content-Length larger than server will accept.";
798 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
799 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
800 loggingContext.transactionEnded();
801 PolicyLogger.audit("Transaction Failed - See Error.log");
802 response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
806 if (request.getContentLength() <= 0) {
807 String message = "Content-Length is negative";
808 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
809 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
810 loggingContext.transactionEnded();
811 PolicyLogger.audit("Transaction Failed - See Error.log");
812 response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
816 ContentType contentType = null;
818 contentType = ContentType.parse(request.getContentType());
820 catch (Exception e) {
821 String message = "Parsing Content-Type: " + request.getContentType() + ", error=" + e.getMessage();
822 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message, e);
823 loggingContext.transactionEnded();
824 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, message);
825 PolicyLogger.audit("Transaction Failed - See Error.log");
826 response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
831 // What exactly did they send us?
833 String incomingRequestString = null;
834 Request pdpRequest = null;
835 if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType()) ||
836 contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
837 contentType.getMimeType().equalsIgnoreCase("application/xacml+xml") ) {
839 // Read in the string
841 StringBuilder buffer = new StringBuilder();
842 BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
844 while((line = reader.readLine()) != null){
847 incomingRequestString = buffer.toString();
848 logger.info(incomingRequestString);
850 // Parse into a request
853 if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
854 pdpRequest = JSONRequest.load(incomingRequestString);
855 } else if ( contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
856 contentType.getMimeType().equalsIgnoreCase("application/xacml+xml")) {
857 pdpRequest = DOMRequest.load(incomingRequestString);
861 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Could not parse request", e);
862 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "Could not parse request");
863 loggingContext.transactionEnded();
864 PolicyLogger.audit("Transaction Failed - See Error.log");
865 response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
870 String message = "unsupported content type" + request.getContentType();
871 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
872 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
873 loggingContext.transactionEnded();
874 PolicyLogger.audit("Transaction Failed - See Error.log");
875 response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
880 // Did we successfully get and parse a request?
882 if (pdpRequest == null || pdpRequest.getRequestAttributes() == null || pdpRequest.getRequestAttributes().size() <= 0) {
883 String message = "Zero Attributes found in the request";
884 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
885 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
886 loggingContext.transactionEnded();
887 PolicyLogger.audit("Transaction Failed - See Error.log");
888 response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
897 // Authenticating the Request here.
899 if(!authorizeRequest(request, pdpRequest)){
900 String message = "PEP not Authorized for making this Request!! \n Contact Administrator for this Scope. ";
901 logger.error(XACMLErrorConstants.ERROR_PERMISSIONS + message );
902 PolicyLogger.error(MessageCodes.ERROR_PERMISSIONS, message);
903 loggingContext.transactionEnded();
904 PolicyLogger.audit("Transaction Failed - See Error.log");
905 response.sendError(HttpServletResponse.SC_FORBIDDEN, message);
910 // Get the pointer to the PDP Engine
912 PDPEngine myEngine = null;
913 synchronized(pdpEngineLock) {
914 myEngine = this.pdpEngine;
916 if (myEngine == null) {
917 String message = "No engine loaded.";
918 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message);
919 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
920 loggingContext.transactionEnded();
921 PolicyLogger.audit("Transaction Failed - See Error.log");
922 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
927 // Send the request and save the response
929 long lTimeStart, lTimeEnd;
930 Response pdpResponse = null;
932 //TODO - Make this unnecessary
933 //TODO It seems that the PDP Engine is not thread-safe, so when a configuration change occurs in the middle of processing
934 //TODO a PEP Request, that Request fails (it throws a NullPointerException in the decide() method).
935 //TODO Using synchronize will slow down processing of PEP requests, possibly by a significant amount.
936 //TODO Since configuration changes are rare, it would be A Very Good Thing if we could eliminate this sychronized block.
938 //TODO This problem was found by starting one PDP then
939 //TODO RestLoadTest switching between 2 configurations, 1 second apart
940 //TODO both configurations contain the datarouter policy
941 //TODO both configurations already have all policies cached in the PDPs config directory
942 //TODO RestLoadTest started with the Datarouter test requests, 5 threads, no interval
943 //TODO With that configuration this code (without the synchronized) throws a NullPointerException
944 //TODO within a few seconds.
946 synchronized(pdpEngineLock) {
947 myEngine = this.pdpEngine;
949 PolicyList.clearPolicyList();
950 lTimeStart = System.currentTimeMillis();
951 pdpResponse = myEngine.decide(pdpRequest);
952 lTimeEnd = System.currentTimeMillis();
953 } catch (PDPException e) {
954 String message = "Exception during decide: " + e.getMessage();
955 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message);
956 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
957 loggingContext.transactionEnded();
958 PolicyLogger.audit("Transaction Failed - See Error.log");
959 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
964 monitor.computeLatency(lTimeEnd - lTimeStart);
965 requestLogger.info(lTimeStart + "=" + incomingRequestString);
966 for(String policy : PolicyList.getpolicyList()){
967 monitor.policyCountAdd(policy, 1);
971 logger.info("PolicyID triggered in Request: " + PolicyList.getpolicyList());
973 //need to go through the list and find out if the value is unique and then add it other wise
974 // monitor.policyCountAdd(PolicyList.getpolicyList(), 1);
976 if (logger.isDebugEnabled()) {
977 logger.debug("Request time: " + (lTimeEnd - lTimeStart) + "ms");
980 // Convert Response to appropriate Content-Type
982 if (pdpResponse == null) {
983 requestLogger.info(lTimeStart + "=" + "{}");
984 throw new Exception("Failed to get response from PDP engine.");
987 // Set our content-type
989 response.setContentType(contentType.getMimeType());
991 // Convert the PDP response object to a String to
992 // return to our caller as well as dump to our loggers.
994 String outgoingResponseString = "";
995 if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
997 // Get it as a String. This is not very efficient but we need to log our
998 // results for auditing.
1000 outgoingResponseString = JSONResponse.toString(pdpResponse, logger.isDebugEnabled());
1001 if (logger.isDebugEnabled()) {
1002 logger.debug(outgoingResponseString);
1004 // Get rid of whitespace
1006 outgoingResponseString = JSONResponse.toString(pdpResponse, false);
1008 } else if ( contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
1009 contentType.getMimeType().equalsIgnoreCase("application/xacml+xml")) {
1011 // Get it as a String. This is not very efficient but we need to log our
1012 // results for auditing.
1014 outgoingResponseString = DOMResponse.toString(pdpResponse, logger.isDebugEnabled());
1015 if (logger.isDebugEnabled()) {
1016 logger.debug(outgoingResponseString);
1018 // Get rid of whitespace
1020 outgoingResponseString = DOMResponse.toString(pdpResponse, false);
1023 // adding the jmx values for NA, Permit and Deny
1025 if (outgoingResponseString.contains("NotApplicable") || outgoingResponseString.contains("Decision not a Permit")){
1026 monitor.pdpEvaluationNA();
1029 if (outgoingResponseString.contains("Permit") && !outgoingResponseString.contains("Decision not a Permit")){
1030 monitor.pdpEvaluationPermit();
1033 if (outgoingResponseString.contains("Deny")){
1034 monitor.pdpEvaluationDeny();
1037 // lTimeStart is used as an ID within the requestLogger to match up
1038 // request's with responses.
1040 requestLogger.info(lTimeStart + "=" + outgoingResponseString);
1041 response.getWriter().print(outgoingResponseString);
1043 catch (Exception e) {
1044 String message = "Exception executing request: " + e;
1045 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message, e);
1046 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, message);
1047 loggingContext.transactionEnded();
1048 PolicyLogger.audit("Transaction Failed - See Error.log");
1049 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
1053 monitor.pdpEvaluationSuccess();
1054 response.setStatus(HttpServletResponse.SC_OK);
1056 loggingContext.transactionEnded();
1057 auditLogger.info("Success");
1058 PolicyLogger.audit("Success");
1063 * Added for Authorizing the PEP Requests for Environment check.
1065 private boolean authorizeRequest(HttpServletRequest request, Request pepRequest) {
1066 if(request instanceof HttpServletRequest) {
1067 // Get the client Credentials from the Request header.
1068 HttpServletRequest httpServletRequest = (HttpServletRequest) request;
1069 String clientCredentials = httpServletRequest.getHeader(ENVIORNMENT_HEADER);
1070 if(clientCredentials!=null && clientCredentials.equalsIgnoreCase(environment)){
1083 // Keep running until we are told to terminate
1086 // variable not used, but constructor has needed side-effects so don't remove:
1087 ECOMPLoggingContext loggingContext = new ECOMPLoggingContext(baseLoggingContext);
1088 while (! this.configThreadTerminate) {
1089 PutRequest request = XACMLPdpServlet.queue.take();
1090 StdPDPStatus newStatus = new StdPDPStatus();
1092 //TODO - This is related to the problem discussed in the doPost() method about the PDPEngine not being thread-safe.
1093 //TODO See that discussion, and when the PDPEngine is made thread-safe it should be ok to move the loadEngine out of
1094 //TODO the synchronized block.
1095 //TODO However, since configuration changes should be rare we may not care about changing this.
1096 PDPEngine newEngine = null;
1097 synchronized(pdpStatusLock) {
1098 XACMLPdpServlet.status.setStatus(Status.UPDATING_CONFIGURATION);
1099 newEngine = XACMLPdpLoader.loadEngine(newStatus, request.policyProperties, request.pipConfigProperties);
1101 // PDPEngine newEngine = XACMLPdpLoader.loadEngine(newStatus, request.policyProperties, request.pipConfigProperties);
1102 if (newEngine != null) {
1103 synchronized(XACMLPdpServlet.pdpEngineLock) {
1104 this.pdpEngine = newEngine;
1106 logger.info("Saving configuration.");
1107 if (request.policyProperties != null) {
1108 try (OutputStream os = Files.newOutputStream(XACMLPdpLoader.getPDPPolicyCache())) {
1109 request.policyProperties.store(os, "");
1112 if (request.pipConfigProperties != null) {
1113 try (OutputStream os = Files.newOutputStream(XACMLPdpLoader.getPIPConfig())) {
1114 request.pipConfigProperties.store(os, "");
1117 newStatus.setStatus(Status.UP_TO_DATE);
1118 } catch (Exception e) {
1119 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to store new properties.");
1120 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Failed to store new properties");
1121 newStatus.setStatus(Status.LOAD_ERRORS);
1122 newStatus.addLoadWarning("Unable to save configuration: " + e.getMessage());
1126 newStatus.setStatus(Status.LAST_UPDATE_FAILED);
1128 synchronized(pdpStatusLock) {
1129 XACMLPdpServlet.status.set(newStatus);
1132 } catch (InterruptedException e) {
1133 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "interrupted");
1134 PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, "interrupted");