aboutsummaryrefslogtreecommitdiffstats
path: root/ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/XACMLPdpServlet.java
diff options
context:
space:
mode:
Diffstat (limited to 'ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/XACMLPdpServlet.java')
-rw-r--r--ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/XACMLPdpServlet.java1138
1 files changed, 1138 insertions, 0 deletions
diff --git a/ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/XACMLPdpServlet.java b/ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/XACMLPdpServlet.java
new file mode 100644
index 000000000..963fcd127
--- /dev/null
+++ b/ECOMP-PDP-REST/src/main/java/org/openecomp/policy/pdp/rest/XACMLPdpServlet.java
@@ -0,0 +1,1138 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-PDP-REST
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.pdp.rest;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.util.Properties;
+import java.util.UUID;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebInitParam;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.entity.ContentType;
+import org.openecomp.policy.pdp.rest.jmx.PdpRestMonitor;
+import org.openecomp.policy.rest.XACMLRest;
+import org.openecomp.policy.rest.XACMLRestProperties;
+import org.openecomp.policy.common.logging.ECOMPLoggingContext;
+import org.openecomp.policy.common.logging.ECOMPLoggingUtils;
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.eelf.PolicyLogger;
+import org.openecomp.policy.common.im.AdministrativeStateException;
+import org.openecomp.policy.common.im.ForwardProgressException;
+import org.openecomp.policy.common.im.IntegrityMonitor;
+import org.openecomp.policy.common.im.IntegrityMonitorProperties;
+import org.openecomp.policy.common.im.StandbyStatusException;
+
+import com.att.research.xacml.api.Request;
+import com.att.research.xacml.api.Response;
+import org.openecomp.policy.xacml.api.XACMLErrorConstants;
+import com.att.research.xacml.api.pap.PDPStatus.Status;
+import com.att.research.xacml.api.pdp.PDPEngine;
+import com.att.research.xacml.api.pdp.PDPException;
+import com.att.research.xacml.std.dom.DOMRequest;
+import com.att.research.xacml.std.dom.DOMResponse;
+import com.att.research.xacml.std.json.JSONRequest;
+import com.att.research.xacml.std.json.JSONResponse;
+import com.att.research.xacml.util.XACMLProperties;
+import org.openecomp.policy.xacml.pdp.std.functions.PolicyList;
+import org.openecomp.policy.xacml.std.pap.StdPDPStatus;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Servlet implementation class XacmlPdpServlet
+ *
+ * This is an implementation of the XACML 3.0 RESTful Interface with added features to support
+ * simple PAP RESTful API for policy publishing and PIP configuration changes.
+ *
+ * If you are running this the first time, then we recommend you look at the xacml.pdp.properties file.
+ * This properties file has all the default parameter settings. If you are running the servlet as is,
+ * then we recommend setting up you're container to run it on port 8080 with context "/pdp". Wherever
+ * the default working directory is set to, a "config" directory will be created that holds the policy
+ * and pip cache. This setting is located in the xacml.pdp.properties file.
+ *
+ * When you are ready to customize, you can create a separate xacml.pdp.properties on you're local file
+ * system and setup the parameters as you wish. Just set the Java VM System variable to point to that file:
+ *
+ * -Dxacml.properties=/opt/app/xacml/etc/xacml.pdp.properties
+ *
+ * Or if you only want to change one or two properties, simply set the Java VM System variable for that property.
+ *
+ * -Dxacml.rest.pdp.register=false
+ *
+ *
+ */
+@WebServlet(
+ description = "Implements the XACML PDP RESTful API and client PAP API.",
+ urlPatterns = { "/" },
+ loadOnStartup=1,
+ initParams = {
+ @WebInitParam(name = "XACML_PROPERTIES_NAME", value = "xacml.pdp.properties", description = "The location of the PDP xacml.pdp.properties file holding configuration information.")
+ })
+public class XACMLPdpServlet extends HttpServlet implements Runnable {
+ private static final long serialVersionUID = 1L;
+ private static final String DEFAULT_MAX_CONTENT_LENGTH = "999999999"; //32767
+ //
+ // Our application debug log
+ //
+ private static final Log logger = LogFactory.getLog(XACMLPdpServlet.class);
+ //
+ // This logger is specifically only for Xacml requests and their corresponding response.
+ // It's output ideally should be sent to a separate file from the application logger.
+ //
+ private static final Log requestLogger = LogFactory.getLog("xacml.request");
+ //
+ // audit logger
+ private static final Log auditLogger = LogFactory.getLog("auditLogger");
+
+ private static final PdpRestMonitor monitor = PdpRestMonitor.singleton;
+
+ //
+ // This thread may getting invoked on startup, to let the PAP know
+ // that we are up and running.
+ //
+ private Thread registerThread = null;
+ private XACMLPdpRegisterThread registerRunnable = null;
+ //
+ // This is our PDP engine pointer. There is a synchronized lock used
+ // for access to the pointer. In case we are servicing PEP requests while
+ // an update is occurring from the PAP.
+ //
+ private PDPEngine pdpEngine = null;
+ private static final Object pdpEngineLock = new Object();
+ //
+ // This is our PDP's status. What policies are loaded (or not) and
+ // what PIP configurations are loaded (or not).
+ // There is a synchronized lock used for access to the object.
+ //
+ private static volatile StdPDPStatus status = new StdPDPStatus();
+ private static final Object pdpStatusLock = new Object();
+
+ private static final String ENVIORNMENT_HEADER = "Environment";
+ private static String environment = null;
+ //
+ // Queue of PUT requests
+ //
+ public static class PutRequest {
+ public Properties policyProperties = null;
+ public Properties pipConfigProperties = null;
+
+ PutRequest(Properties policies, Properties pips) {
+ this.policyProperties = policies;
+ this.pipConfigProperties = pips;
+ }
+ }
+ public static volatile BlockingQueue<PutRequest> queue = null;
+ // For notification Delay.
+ private static int notificationDelay = 0;
+ public static int getNotificationDelay(){
+ return XACMLPdpServlet.notificationDelay;
+ }
+
+ private static String pdpResourceName;
+ private static String dependencyGroups = null;
+ private static String[] dependencyNodes = null;
+
+ //
+ // This is our configuration thread that attempts to load
+ // a new configuration request.
+ //
+ private Thread configThread = null;
+ private volatile boolean configThreadTerminate = false;
+ private ECOMPLoggingContext baseLoggingContext = null;
+ private IntegrityMonitor im;
+ /**
+ * Default constructor.
+ */
+ public XACMLPdpServlet() {
+ }
+
+ /**
+ * @see Servlet#init(ServletConfig)
+ */
+ public void init(ServletConfig config) throws ServletException {
+ //
+ // Initialize
+ //
+ XACMLRest.xacmlInit(config);
+ // Load the Notification Delay.
+ try{
+ XACMLPdpServlet.notificationDelay = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_NOTIFICATION_DELAY));
+ }catch(Exception e){
+ logger.info("Notification Delay Not set. Keeping it 0 as default.");
+ }
+ // Load Queue size.
+ int queueSize = 5; // Set default Queue Size here.
+ queueSize = Integer.parseInt(XACMLProperties.getProperty("REQUEST_BUFFER_SIZE",String.valueOf(queueSize)));
+ queue = new LinkedBlockingQueue<PutRequest>(queueSize);
+ // Load our engine - this will use the latest configuration
+ // that was saved to disk and set our initial status object.
+ //
+ PDPEngine engine = XACMLPdpLoader.loadEngine(XACMLPdpServlet.status, null, null);
+ if (engine != null) {
+ synchronized(pdpEngineLock) {
+ pdpEngine = engine;
+ }
+ }
+ //
+ // Logging stuff....
+ //
+ baseLoggingContext = new ECOMPLoggingContext();
+ // fixed data that will be the same in all logging output goes here
+ try {
+ String hostname = InetAddress.getLocalHost().getCanonicalHostName();
+ baseLoggingContext.setServer(hostname);
+ } catch (UnknownHostException e) {
+ logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Unable to get hostname for logging");
+ }
+
+ Properties properties;
+ try {
+ properties = XACMLProperties.getProperties();
+ } catch (IOException e) {
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e,
+ "Error loading properties with: XACMLProperties.getProperties()");
+ throw new ServletException(e.getMessage(), e.getCause());
+ }
+
+ pdpResourceName = properties.getProperty(XACMLRestProperties.PDP_RESOURCE_NAME);
+ if(pdpResourceName == null){
+ PolicyLogger.error(MessageCodes.MISS_PROPERTY_ERROR, XACMLRestProperties.PDP_RESOURCE_NAME, "xacml.pdp");
+ throw new ServletException("pdpResourceName is null");
+ }
+
+ dependencyGroups = properties.getProperty(IntegrityMonitorProperties.DEPENDENCY_GROUPS);
+ if(dependencyGroups == null){
+ PolicyLogger.error(MessageCodes.MISS_PROPERTY_ERROR, IntegrityMonitorProperties.DEPENDENCY_GROUPS, "xacml.pdp");
+ throw new ServletException("dependency_groups is null");
+ }
+ // dependency_groups is a semicolon-delimited list of groups, and
+ // each group is a comma-separated list of nodes. For our purposes
+ // we just need a list of dependencies without regard to grouping,
+ // so split the list into nodes separated by either comma or semicolon.
+ dependencyNodes = dependencyGroups.split("[;,]");
+ for (int i = 0 ; i < dependencyNodes.length ; i++){
+ dependencyNodes[i] = dependencyNodes[i].trim();
+ }
+
+
+ // Create an IntegrityMonitor
+ try {
+ logger.info("Creating IntegrityMonitor");
+ im = IntegrityMonitor.getInstance(pdpResourceName, properties);
+ } catch (Exception e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "Failed to create IntegrityMonitor");
+ throw new ServletException(e);
+ }
+
+ environment = XACMLProperties.getProperty("ENVIRONMENT", "DEVL");
+ //
+ // Kick off our thread to register with the PAP servlet.
+ //
+ if (Boolean.parseBoolean(XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_REGISTER))) {
+ this.registerRunnable = new XACMLPdpRegisterThread(baseLoggingContext);
+ this.registerThread = new Thread(this.registerRunnable);
+ this.registerThread.start();
+ }
+ //
+ // This is our thread that manages incoming configuration
+ // changes.
+ //
+ this.configThread = new Thread(this);
+ this.configThread.start();
+ }
+
+ /**
+ * @see Servlet#destroy()
+ */
+ public void destroy() {
+ super.destroy();
+ logger.info("Destroying....");
+ //
+ // Make sure the register thread is not running
+ //
+ if (this.registerRunnable != null) {
+ try {
+ this.registerRunnable.terminate();
+ if (this.registerThread != null) {
+ this.registerThread.interrupt();
+ this.registerThread.join();
+ }
+ } catch (InterruptedException e) {
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "");
+ }
+ }
+ //
+ // Make sure the configure thread is not running
+ //
+ this.configThreadTerminate = true;
+ try {
+ this.configThread.interrupt();
+ this.configThread.join();
+ } catch (InterruptedException e) {
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "");
+ }
+ logger.info("Destroyed.");
+ }
+
+ /**
+ * PUT - The PAP engine sends configuration information using HTTP PUT request.
+ *
+ * One parameter is expected:
+ *
+ * config=[policy|pip|all]
+ *
+ * policy - Expect a properties file that contains updated lists of the root and referenced policies that the PDP should
+ * be using for PEP requests.
+ *
+ * Specifically should AT LEAST contain the following properties:
+ * xacml.rootPolicies
+ * xacml.referencedPolicies
+ *
+ * In addition, any relevant information needed by the PDP to load or retrieve the policies to store in its cache.
+ *
+ * EXAMPLE:
+ * xacml.rootPolicies=PolicyA.1, PolicyB.1
+ *
+ * PolicyA.1.url=http://localhost:9090/PAP?id=b2d7b86d-d8f1-4adf-ba9d-b68b2a90bee1&version=1
+ * PolicyB.1.url=http://localhost:9090/PAP/id=be962404-27f6-41d8-9521-5acb7f0238be&version=1
+ *
+ * xacml.referencedPolicies=RefPolicyC.1, RefPolicyD.1
+ *
+ * RefPolicyC.1.url=http://localhost:9090/PAP?id=foobar&version=1
+ * RefPolicyD.1.url=http://localhost:9090/PAP/id=example&version=1
+ *
+ * pip - Expect a properties file that contain PIP engine configuration properties.
+ *
+ * Specifically should AT LEAST the following property:
+ * xacml.pip.engines
+ *
+ * In addition, any relevant information needed by the PDP to load and configure the PIPs.
+ *
+ * EXAMPLE:
+ * xacml.pip.engines=foo,bar
+ *
+ * foo.classname=com.foo
+ * foo.sample=abc
+ * foo.example=xyz
+ * ......
+ *
+ * bar.classname=com.bar
+ * ......
+ *
+ * all - Expect ALL new configuration properties for the PDP
+ *
+ * @see HttpServlet#doPut(HttpServletRequest request, HttpServletResponse response)
+ */
+ protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ ECOMPLoggingContext loggingContext = ECOMPLoggingUtils.getLoggingContextForRequest(request, baseLoggingContext);
+ loggingContext.transactionStarted();
+ if ((loggingContext.getRequestID() == null) || (loggingContext.getRequestID() == "")){
+ UUID requestID = UUID.randomUUID();
+ loggingContext.setRequestID(requestID.toString());
+ PolicyLogger.info("requestID not provided in call to XACMLPdpSrvlet (doPut) so we generated one");
+ } else {
+ PolicyLogger.info("requestID was provided in call to XACMLPdpSrvlet (doPut)");
+ }
+ loggingContext.metricStarted();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("Metric example posted here - 1 of 2");
+ loggingContext.metricStarted();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("Metric example posted here - 2 of 2");
+ //
+ // Dump our request out
+ //
+ if (logger.isDebugEnabled()) {
+ XACMLRest.dumpRequest(request);
+ }
+
+ try {
+ im.startTransaction();
+ }
+ catch (AdministrativeStateException | StandbyStatusException e) {
+ String message = e.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ return;
+ }
+ //
+ // What is being PUT?
+ //
+ String cache = request.getParameter("cache");
+ //
+ // Should be a list of policy and pip configurations in Java properties format
+ //
+ if (cache != null && request.getContentType().equals("text/x-java-properties")) {
+ loggingContext.setServiceName("PDP.putConfig");
+ if (request.getContentLength() > Integer.parseInt(XACMLProperties.getProperty("MAX_CONTENT_LENGTH", DEFAULT_MAX_CONTENT_LENGTH))) {
+ String message = "Content-Length larger than server will accept.";
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
+ loggingContext.transactionEnded();
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+ im.endTransaction();
+ return;
+ }
+ this.doPutConfig(cache, request, response, loggingContext);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction ended");
+
+ im.endTransaction();
+ } else {
+ String message = "Invalid cache: '" + cache + "' or content-type: '" + request.getContentType() + "'";
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+ im.endTransaction();
+ return;
+ }
+ }
+
+ protected void doPutConfig(String config, HttpServletRequest request, HttpServletResponse response, ECOMPLoggingContext loggingContext) throws ServletException, IOException {
+ try {
+ // prevent multiple configuration changes from stacking up
+ if (XACMLPdpServlet.queue.remainingCapacity() <= 0) {
+ logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Queue capacity reached");
+ PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Queue capacity reached");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_CONFLICT, "Multiple configuration changes waiting processing.");
+ return;
+ }
+ //
+ // Read the properties data into an object.
+ //
+ Properties newProperties = new Properties();
+ newProperties.load(request.getInputStream());
+ // should have something in the request
+ if (newProperties.size() == 0) {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No properties in PUT");
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No properties in PUT");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT must contain at least one property");
+ return;
+ }
+ //
+ // Which set of properties are they sending us? Whatever they send gets
+ // put on the queue (if there is room).
+ // For audit logging purposes, we consider the transaction done once the
+ // the request gets put on the queue.
+ //
+ if (config.equals("policies")) {
+ newProperties = XACMLProperties.getPolicyProperties(newProperties, true);
+ if (newProperties.size() == 0) {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No policy properties in PUT");
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No policy properties in PUT");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=policies must contain at least one policy property");
+ return;
+ }
+ XACMLPdpServlet.queue.offer(new PutRequest(newProperties, null));
+ loggingContext.transactionEnded();
+ auditLogger.info("Success");
+ PolicyLogger.audit("Success");
+ } else if (config.equals("pips")) {
+ newProperties = XACMLProperties.getPipProperties(newProperties);
+ if (newProperties.size() == 0) {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No pips properties in PUT");
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No pips properties in PUT");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=pips must contain at least one pip property");
+ return;
+ }
+ XACMLPdpServlet.queue.offer(new PutRequest(null, newProperties));
+ loggingContext.transactionEnded();
+ auditLogger.info("Success");
+ PolicyLogger.audit("Success");
+ } else if (config.equals("all")) {
+ Properties newPolicyProperties = XACMLProperties.getPolicyProperties(newProperties, true);
+ if (newPolicyProperties.size() == 0) {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No policy properties in PUT");
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No policy properties in PUT");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=all must contain at least one policy property");
+ return;
+ }
+ Properties newPipProperties = XACMLProperties.getPipProperties(newProperties);
+ if (newPipProperties.size() == 0) {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "No pips properties in PUT");
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "No pips properties in PUT");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "PUT with cache=all must contain at least one pip property");
+ return;
+ }
+ XACMLPdpServlet.queue.offer(new PutRequest(newPolicyProperties, newPipProperties));
+ loggingContext.transactionEnded();
+ auditLogger.info("Success");
+ PolicyLogger.audit("Success");
+ } else {
+ //
+ // Invalid value
+ //
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Invalid config value: " + config);
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "Invalid config value: " + config);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Config must be one of 'policies', 'pips', 'all'");
+ return;
+ }
+ } catch (Exception e) {
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Failed to process new configuration.", e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "Failed to process new configuration");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+ return;
+ }
+
+ }
+
+ /**
+ * Parameters: type=hb|config|Status
+ *
+ * 1. HeartBeat Status
+ * HeartBeat
+ * OK - All Policies are Loaded, All PIPs are Loaded
+ * LOADING_IN_PROGRESS - Currently loading a new policy set/pip configuration
+ * LAST_UPDATE_FAILED - Need to track the items that failed during last update
+ * LOAD_FAILURE - ??? Need to determine what information is sent and how
+ * 2. Configuration
+ * 3. Status
+ * return the StdPDPStatus object in the Response content
+ *
+ *
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
+ */
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ ECOMPLoggingContext loggingContext = ECOMPLoggingUtils.getLoggingContextForRequest(request, baseLoggingContext);
+ loggingContext.transactionStarted();
+ if ((loggingContext.getRequestID() == null) || (loggingContext.getRequestID() == "")){
+ UUID requestID = UUID.randomUUID();
+ loggingContext.setRequestID(requestID.toString());
+ PolicyLogger.info("requestID not provided in call to XACMLPdpSrvlet (doGet) so we generated one");
+ } else {
+ PolicyLogger.info("requestID was provided in call to XACMLPdpSrvlet (doGet)");
+ }
+ loggingContext.metricStarted();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("Metric example posted here - 1 of 2");
+ loggingContext.metricStarted();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("Metric example posted here - 2 of 2");
+
+ XACMLRest.dumpRequest(request);
+
+ String pathInfo = request.getRequestURI();
+ if (pathInfo != null){
+ // health check from Global Site Selector (iDNS).
+ // DO NOT do a im.startTransaction for the test request
+ if (pathInfo.equals("/pdp/test")) {
+ loggingContext.setServiceName("iDNS:PDP.test");
+ try {
+ im.evaluateSanity();
+ //If we make it this far, all is well
+ String message = "GET:/pdp/test called and PDP " + pdpResourceName + " is OK";
+ PolicyLogger.debug(message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Success");
+ response.setStatus(HttpServletResponse.SC_OK);
+ return;
+ } catch (ForwardProgressException fpe){
+ //No forward progress is being made
+ String message = "GET:/pdp/test called and PDP " + pdpResourceName + " is not making forward progress."
+ + " Exception Message: " + fpe.getMessage();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ // PolicyLogger.audit(MessageCodes.ERROR_SYSTEM_ERROR, message );
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ return;
+ }catch (AdministrativeStateException ase){
+ //Administrative State is locked
+ String message = "GET:/pdp/test called and PDP " + pdpResourceName + " Administrative State is LOCKED "
+ + " Exception Message: " + ase.getMessage();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ return;
+ }catch (StandbyStatusException sse){
+ //Administrative State is locked
+ String message = "GET:/pdp/test called and PDP " + pdpResourceName + " Standby Status is NOT PROVIDING SERVICE "
+ + " Exception Message: " + sse.getMessage();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ return;
+ } catch (Exception e) {
+ //A subsystem is not making progress or is not responding
+ String eMsg = e.getMessage();
+ if(eMsg == null){
+ eMsg = "No Exception Message";
+ }
+ String message = "GET:/pdp/test called and PDP " + pdpResourceName + " has had a subsystem failure."
+ + " Exception Message: " + eMsg;
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message );
+ //Get the specific list of subsystems that failed
+ String failedNodeList = null;
+ for(String node : dependencyNodes){
+ if(eMsg.contains(node)){
+ if(failedNodeList == null){
+ failedNodeList = node;
+ }else{
+ failedNodeList = failedNodeList.concat(","+node);
+ }
+ }
+ }
+ if(failedNodeList == null){
+ failedNodeList = "UnknownSubSystem";
+ }
+ response.addHeader("X-ECOMP-SubsystemFailure", failedNodeList);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ return;
+ }
+ }
+ }
+
+ try {
+ im.startTransaction();
+ }
+ catch (AdministrativeStateException | StandbyStatusException e) {
+ String message = e.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ return;
+ }
+ //
+ // What are they requesting?
+ //
+ boolean returnHB = false;
+ response.setHeader("Cache-Control", "no-cache");
+ String type = request.getParameter("type");
+ // type might be null, so use equals on string constants
+ if ("config".equals(type)) {
+ loggingContext.setServiceName("PDP.getConfig");
+ response.setContentType("text/x-java-properties");
+ try {
+ String lists = XACMLProperties.PROP_ROOTPOLICIES + "=" + XACMLProperties.getProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
+ lists = lists + "\n" + XACMLProperties.PROP_REFERENCEDPOLICIES + "=" + XACMLProperties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "") + "\n";
+ try (InputStream listInputStream = new ByteArrayInputStream(lists.getBytes());
+ InputStream pipInputStream = Files.newInputStream(XACMLPdpLoader.getPIPConfig());
+ OutputStream os = response.getOutputStream()) {
+ IOUtils.copy(listInputStream, os);
+ IOUtils.copy(pipInputStream, os);
+ }
+ loggingContext.transactionEnded();
+ auditLogger.info("Success");
+ PolicyLogger.audit("Success");
+ response.setStatus(HttpServletResponse.SC_OK);
+ } catch (Exception e) {
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Failed to copy property file", e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "Failed to copy property file");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(400, "Failed to copy Property file");
+ }
+
+ } else if ("hb".equals(type)) {
+ returnHB = true;
+ response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+
+ } else if ("Status".equals(type)) {
+ loggingContext.setServiceName("PDP.getStatus");
+ // convert response object to JSON and include in the response
+ synchronized(pdpStatusLock) {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.writeValue(response.getOutputStream(), status);
+ }
+ response.setStatus(HttpServletResponse.SC_OK);
+ loggingContext.transactionEnded();
+ auditLogger.info("Success");
+ PolicyLogger.audit("Success");
+
+ } else {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Invalid type value: " + type);
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "Invalid type value: " + type);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "type not 'config' or 'hb'");
+ }
+ if (returnHB) {
+ synchronized(pdpStatusLock) {
+ response.addHeader(XACMLRestProperties.PROP_PDP_HTTP_HEADER_HB, status.getStatus().toString());
+ }
+ }
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Ended");
+ im.endTransaction();
+
+ }
+
+ /**
+ * POST - We expect XACML requests to be posted by PEP applications. They can be in the form of XML or JSON according
+ * to the XACML 3.0 Specifications for both.
+ *
+ *
+ * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+ */
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ ECOMPLoggingContext loggingContext = ECOMPLoggingUtils.getLoggingContextForRequest(request, baseLoggingContext);
+ loggingContext.transactionStarted();
+ loggingContext.setServiceName("PDP.decide");
+ if ((loggingContext.getRequestID() == null) || (loggingContext.getRequestID() == "")){
+ UUID requestID = UUID.randomUUID();
+ loggingContext.setRequestID(requestID.toString());
+ PolicyLogger.info("requestID not provided in call to XACMLPdpSrvlet (doPost) so we generated one");
+ } else {
+ PolicyLogger.info("requestID was provided in call to XACMLPdpSrvlet (doPost)");
+ }
+ loggingContext.metricStarted();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("Metric example posted here - 1 of 2");
+ loggingContext.metricStarted();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("Metric example posted here - 2 of 2");
+ monitor.pdpEvaluationAttempts();
+
+ try {
+ im.startTransaction();
+ }
+ catch (AdministrativeStateException | StandbyStatusException e) {
+ String message = e.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ return;
+ }
+ //
+ // no point in doing any work if we know from the get-go that we cannot do anything with the request
+ //
+ if (status.getLoadedRootPolicies().size() == 0) {
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Request from PEP at " + request.getRequestURI() + " for service when PDP has No Root Policies loaded");
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, "Request from PEP at " + request.getRequestURI() + " for service when PDP has No Root Policies loaded");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ im.endTransaction();
+ return;
+ }
+
+ XACMLRest.dumpRequest(request);
+ //
+ // Set our no-cache header
+ //
+ response.setHeader("Cache-Control", "no-cache");
+ //
+ // They must send a Content-Type
+ //
+ if (request.getContentType() == null) {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Must specify a Content-Type");
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, "Must specify a Content-Type");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "no content-type given");
+ im.endTransaction();
+ return;
+ }
+ //
+ // Limit the Content-Length to something reasonable
+ //
+ if (request.getContentLength() > Integer.parseInt(XACMLProperties.getProperty("MAX_CONTENT_LENGTH", "32767"))) {
+ String message = "Content-Length larger than server will accept.";
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+ im.endTransaction();
+ return;
+ }
+ if (request.getContentLength() <= 0) {
+ String message = "Content-Length is negative";
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+ im.endTransaction();
+ return;
+ }
+ ContentType contentType = null;
+ try {
+ contentType = ContentType.parse(request.getContentType());
+ }
+ catch (Exception e) {
+ String message = "Parsing Content-Type: " + request.getContentType() + ", error=" + e.getMessage();
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message, e);
+ loggingContext.transactionEnded();
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, message);
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+ im.endTransaction();
+ return;
+ }
+ //
+ // What exactly did they send us?
+ //
+ String incomingRequestString = null;
+ Request pdpRequest = null;
+ if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType()) ||
+ contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
+ contentType.getMimeType().equalsIgnoreCase("application/xacml+xml") ) {
+ //
+ // Read in the string
+ //
+ StringBuilder buffer = new StringBuilder();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
+ String line;
+ while((line = reader.readLine()) != null){
+ buffer.append(line);
+ }
+ incomingRequestString = buffer.toString();
+ logger.info(incomingRequestString);
+ //
+ // Parse into a request
+ //
+ try {
+ if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
+ pdpRequest = JSONRequest.load(incomingRequestString);
+ } else if ( contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
+ contentType.getMimeType().equalsIgnoreCase("application/xacml+xml")) {
+ pdpRequest = DOMRequest.load(incomingRequestString);
+ }
+ }
+ catch(Exception e) {
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Could not parse request", e);
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "Could not parse request");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
+ im.endTransaction();
+ return;
+ }
+ } else {
+ String message = "unsupported content type" + request.getContentType();
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+ im.endTransaction();
+ return;
+ }
+ //
+ // Did we successfully get and parse a request?
+ //
+ if (pdpRequest == null || pdpRequest.getRequestAttributes() == null || pdpRequest.getRequestAttributes().size() <= 0) {
+ String message = "Zero Attributes found in the request";
+ logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + message);
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+ im.endTransaction();
+ return;
+ }
+ //
+ // Run it
+ //
+ try {
+ //
+ // Authenticating the Request here.
+ //
+ if(!authorizeRequest(request, pdpRequest)){
+ String message = "PEP not Authorized for making this Request!! \n Contact Administrator for this Scope. ";
+ logger.error(XACMLErrorConstants.ERROR_PERMISSIONS + message );
+ PolicyLogger.error(MessageCodes.ERROR_PERMISSIONS, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, message);
+ im.endTransaction();
+ return;
+ }
+ //
+ // Get the pointer to the PDP Engine
+ //
+ PDPEngine myEngine = null;
+ synchronized(pdpEngineLock) {
+ myEngine = this.pdpEngine;
+ }
+ if (myEngine == null) {
+ String message = "No engine loaded.";
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ im.endTransaction();
+ return;
+ }
+ //
+ // Send the request and save the response
+ //
+ long lTimeStart, lTimeEnd;
+ Response pdpResponse = null;
+
+//TODO - Make this unnecessary
+//TODO It seems that the PDP Engine is not thread-safe, so when a configuration change occurs in the middle of processing
+//TODO a PEP Request, that Request fails (it throws a NullPointerException in the decide() method).
+//TODO Using synchronize will slow down processing of PEP requests, possibly by a significant amount.
+//TODO Since configuration changes are rare, it would be A Very Good Thing if we could eliminate this sychronized block.
+//TODO
+//TODO This problem was found by starting one PDP then
+//TODO RestLoadTest switching between 2 configurations, 1 second apart
+//TODO both configurations contain the datarouter policy
+//TODO both configurations already have all policies cached in the PDPs config directory
+//TODO RestLoadTest started with the Datarouter test requests, 5 threads, no interval
+//TODO With that configuration this code (without the synchronized) throws a NullPointerException
+//TODO within a few seconds.
+//
+synchronized(pdpEngineLock) {
+ myEngine = this.pdpEngine;
+ try {
+ PolicyList.clearPolicyList();
+ lTimeStart = System.currentTimeMillis();
+ pdpResponse = myEngine.decide(pdpRequest);
+ lTimeEnd = System.currentTimeMillis();
+ } catch (PDPException e) {
+ String message = "Exception during decide: " + e.getMessage();
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ im.endTransaction();
+ return;
+ }
+}
+ monitor.computeLatency(lTimeEnd - lTimeStart);
+ requestLogger.info(lTimeStart + "=" + incomingRequestString);
+ for(String policy : PolicyList.getpolicyList()){
+ monitor.policyCountAdd(policy, 1);
+ }
+
+
+ logger.info("PolicyID triggered in Request: " + PolicyList.getpolicyList());
+
+ //need to go through the list and find out if the value is unique and then add it other wise
+// monitor.policyCountAdd(PolicyList.getpolicyList(), 1);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Request time: " + (lTimeEnd - lTimeStart) + "ms");
+ }
+ //
+ // Convert Response to appropriate Content-Type
+ //
+ if (pdpResponse == null) {
+ requestLogger.info(lTimeStart + "=" + "{}");
+ throw new Exception("Failed to get response from PDP engine.");
+ }
+ //
+ // Set our content-type
+ //
+ response.setContentType(contentType.getMimeType());
+ //
+ // Convert the PDP response object to a String to
+ // return to our caller as well as dump to our loggers.
+ //
+ String outgoingResponseString = "";
+ if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
+ //
+ // Get it as a String. This is not very efficient but we need to log our
+ // results for auditing.
+ //
+ outgoingResponseString = JSONResponse.toString(pdpResponse, logger.isDebugEnabled());
+ if (logger.isDebugEnabled()) {
+ logger.debug(outgoingResponseString);
+ //
+ // Get rid of whitespace
+ //
+ outgoingResponseString = JSONResponse.toString(pdpResponse, false);
+ }
+ } else if ( contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
+ contentType.getMimeType().equalsIgnoreCase("application/xacml+xml")) {
+ //
+ // Get it as a String. This is not very efficient but we need to log our
+ // results for auditing.
+ //
+ outgoingResponseString = DOMResponse.toString(pdpResponse, logger.isDebugEnabled());
+ if (logger.isDebugEnabled()) {
+ logger.debug(outgoingResponseString);
+ //
+ // Get rid of whitespace
+ //
+ outgoingResponseString = DOMResponse.toString(pdpResponse, false);
+ }
+ }
+ // adding the jmx values for NA, Permit and Deny
+ //
+ if (outgoingResponseString.contains("NotApplicable") || outgoingResponseString.contains("Decision not a Permit")){
+ monitor.pdpEvaluationNA();
+ }
+
+ if (outgoingResponseString.contains("Permit") && !outgoingResponseString.contains("Decision not a Permit")){
+ monitor.pdpEvaluationPermit();
+ }
+
+ if (outgoingResponseString.contains("Deny")){
+ monitor.pdpEvaluationDeny();
+ }
+ //
+ // lTimeStart is used as an ID within the requestLogger to match up
+ // request's with responses.
+ //
+ requestLogger.info(lTimeStart + "=" + outgoingResponseString);
+ response.getWriter().print(outgoingResponseString);
+ }
+ catch (Exception e) {
+ String message = "Exception executing request: " + e;
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + message, e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ return;
+ }
+
+ monitor.pdpEvaluationSuccess();
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ loggingContext.transactionEnded();
+ auditLogger.info("Success");
+ PolicyLogger.audit("Success");
+
+}
+
+ /*
+ * Added for Authorizing the PEP Requests for Environment check.
+ */
+ private boolean authorizeRequest(HttpServletRequest request, Request pepRequest) {
+ if(request instanceof HttpServletRequest) {
+ // Get the client Credentials from the Request header.
+ HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+ String clientCredentials = httpServletRequest.getHeader(ENVIORNMENT_HEADER);
+ if(clientCredentials!=null && clientCredentials.equalsIgnoreCase(environment)){
+ return true;
+ }else{
+ return false;
+ }
+ }else{
+ return false;
+ }
+ }
+
+ @Override
+ public void run() {
+ //
+ // Keep running until we are told to terminate
+ //
+ try {
+ // variable not used, but constructor has needed side-effects so don't remove:
+ ECOMPLoggingContext loggingContext = new ECOMPLoggingContext(baseLoggingContext);
+ while (! this.configThreadTerminate) {
+ PutRequest request = XACMLPdpServlet.queue.take();
+ StdPDPStatus newStatus = new StdPDPStatus();
+
+//TODO - This is related to the problem discussed in the doPost() method about the PDPEngine not being thread-safe.
+//TODO See that discussion, and when the PDPEngine is made thread-safe it should be ok to move the loadEngine out of
+//TODO the synchronized block.
+//TODO However, since configuration changes should be rare we may not care about changing this.
+PDPEngine newEngine = null;
+ synchronized(pdpStatusLock) {
+ XACMLPdpServlet.status.setStatus(Status.UPDATING_CONFIGURATION);
+newEngine = XACMLPdpLoader.loadEngine(newStatus, request.policyProperties, request.pipConfigProperties);
+ }
+// PDPEngine newEngine = XACMLPdpLoader.loadEngine(newStatus, request.policyProperties, request.pipConfigProperties);
+ if (newEngine != null) {
+ synchronized(XACMLPdpServlet.pdpEngineLock) {
+ this.pdpEngine = newEngine;
+ try {
+ logger.info("Saving configuration.");
+ if (request.policyProperties != null) {
+ try (OutputStream os = Files.newOutputStream(XACMLPdpLoader.getPDPPolicyCache())) {
+ request.policyProperties.store(os, "");
+ }
+ }
+ if (request.pipConfigProperties != null) {
+ try (OutputStream os = Files.newOutputStream(XACMLPdpLoader.getPIPConfig())) {
+ request.pipConfigProperties.store(os, "");
+ }
+ }
+ newStatus.setStatus(Status.UP_TO_DATE);
+ } catch (Exception e) {
+ logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to store new properties.");
+ PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Failed to store new properties");
+ newStatus.setStatus(Status.LOAD_ERRORS);
+ newStatus.addLoadWarning("Unable to save configuration: " + e.getMessage());
+ }
+ }
+ } else {
+ newStatus.setStatus(Status.LAST_UPDATE_FAILED);
+ }
+ synchronized(pdpStatusLock) {
+ XACMLPdpServlet.status.set(newStatus);
+ }
+ }
+ } catch (InterruptedException e) {
+ logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "interrupted");
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, "interrupted");
+ }
+ }
+
+}