Merge "Fixed the Policy GUI Editor tab right click issue."
[policy/engine.git] / ONAP-REST / src / main / java / org / onap / policy / rest / XacmlRest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-REST
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Modified Copyright (C) 2018 Samsung Electronics Co., Ltd.
7  * Modifications Copyright (C) 2019 Nordix Foundation.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.rest;
24
25 import com.att.research.xacml.util.XACMLProperties;
26
27 import java.io.IOException;
28 import java.util.Enumeration;
29 import java.util.Map;
30 import java.util.Properties;
31 import java.util.Set;
32
33 import javax.servlet.ServletConfig;
34 import javax.servlet.http.HttpServletRequest;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.onap.policy.common.logging.eelf.MessageCodes;
39 import org.onap.policy.common.logging.eelf.PolicyLogger;
40
41 /**
42  * This static class is used by both the PDP and PAP servlet's. It contains some common static functions and objects
43  * used by both the servlet's.
44  *
45  *
46  */
47 public class XacmlRest {
48     private static final Log logger = LogFactory.getLog(XacmlRest.class);
49     private static Properties restProperties = new Properties();
50
51     private XacmlRest() {
52         // Empty constructor
53     }
54
55     /**
56      * This must be called during servlet initialization. It sets up the xacml.?.properties file as a system property.
57      * If the System property is already set, then it does not do anything. This allows the developer to specify their
58      * own xacml.properties file to be used. They can 1) modify the default properties that comes with the project, or
59      * 2) change the WebInitParam annotation, or 3) specify an alternative path in the web.xml, or 4) set the Java
60      * System property to point to their xacml.properties file.
61      *
62      * <p>The recommended way of overriding the default xacml.properties file is using a Java System property:
63      * -Dxacml.properties=/opt/app/xacml/etc/xacml.admin.properties
64      *
65      * <p>This way one does not change any actual code or files in the project and can leave the defaults alone.
66      *
67      * @param config - The servlet config file passed from the javax servlet init() function
68      */
69     public static void xacmlInit(ServletConfig config) {
70         //
71         // Get the XACML Properties File parameter first
72         //
73         String propFile = config.getInitParameter("XACML_PROPERTIES_NAME");
74         if (propFile != null) {
75             //
76             // Look for system override
77             //
78             String xacmlPropertiesName = System.getProperty(XACMLProperties.XACML_PROPERTIES_NAME);
79             logger.info("\n\n" + xacmlPropertiesName + "\n" + XACMLProperties.XACML_PROPERTIES_NAME);
80             if (xacmlPropertiesName == null) {
81                 //
82                 // Set it to our servlet default
83                 //
84                 if (logger.isDebugEnabled()) {
85                     logger.debug("Using Servlet Config Property for XACML_PROPERTIES_NAME:" + propFile);
86                 }
87                 System.setProperty(XACMLProperties.XACML_PROPERTIES_NAME, propFile);
88             } else {
89                 if (logger.isDebugEnabled()) {
90                     logger.debug("Using System Property for XACML_PROPERTIES_NAME:" + xacmlPropertiesName);
91                 }
92             }
93         }
94         //
95         // Setup the remaining properties
96         //
97         Enumeration<String> params = config.getInitParameterNames();
98         while (params.hasMoreElements()) {
99             String param = params.nextElement();
100             if (!"XACML_PROPERTIES_NAME".equals(param)) {
101                 String value = config.getInitParameter(param);
102                 PolicyLogger.info(param + "=" + config.getInitParameter(param));
103                 restProperties.setProperty(param, value);
104             }
105         }
106     }
107
108     /**
109      * Reset's the XACMLProperties internal properties object so we start in a fresh environment. Then adds back in our
110      * Servlet init properties that were passed in the javax Servlet init() call.
111      *
112      * <p>This function is primarily used when a new configuration is passed in and the PDP servlet needs to load a new
113      * PDP engine instance.
114      *
115      * @param pipProperties - PIP configuration properties
116      * @param policyProperties - Policy configuration properties
117      */
118     public static void loadXacmlProperties(Properties policyProperties, Properties pipProperties) {
119         try {
120             //
121             // Start fresh
122             //
123             XACMLProperties.reloadProperties();
124             //
125             // Now load our init properties
126             //
127             XACMLProperties.getProperties().putAll(XacmlRest.restProperties);
128             //
129             // Load our policy properties
130             //
131             if (policyProperties != null) {
132                 XACMLProperties.getProperties().putAll(policyProperties);
133             }
134             //
135             // Load our pip config properties
136             //
137             if (pipProperties != null) {
138                 XACMLProperties.getProperties().putAll(pipProperties);
139             }
140         } catch (IOException e) {
141             PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e,
142                     "Failed to put init properties into Xacml properties");
143         }
144         //
145         // Dump them
146         //
147         if (logger.isDebugEnabled()) {
148             try {
149                 logger.debug(XACMLProperties.getProperties().toString());
150             } catch (IOException e) {
151                 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "Cannot dump properties");
152             }
153         }
154     }
155
156     /**
157      * Helper routine to dump the HTTP servlet request being serviced. Primarily for debugging.
158      *
159      * @param request - Servlet request (from a POST/GET/PUT/etc.)
160      */
161     public static void dumpRequest(HttpServletRequest request) {
162         if (!logger.isDebugEnabled()) {
163             return;
164         }
165
166         // special-case for receiving heartbeat - don't need to repeatedly output all of the information in multiple
167         // lines
168         if ("GET".equals(request.getMethod()) && "hb".equals(request.getParameter("type"))) {
169             PolicyLogger.debug("GET type=hb : heartbeat received");
170             return;
171         }
172
173         dumpRequestHeadersAttributesContextPath(request);
174
175         dumpRequestBody(request);
176     }
177
178     /**
179      * Dump the headers, attributes, and context path of the request.
180      *
181      * @param request the request to dump
182      */
183     private static void dumpRequestHeadersAttributesContextPath(HttpServletRequest request) {
184         logger.debug(request.getMethod() + ":" + request.getRemoteAddr() + " " + request.getRemoteHost() + " "
185                 + request.getRemotePort());
186         logger.debug(request.getLocalAddr() + " " + request.getLocalName() + " " + request.getLocalPort());
187         Enumeration<String> en = request.getHeaderNames();
188         logger.debug("Headers:");
189         while (en.hasMoreElements()) {
190             String element = en.nextElement();
191             Enumeration<String> values = request.getHeaders(element);
192             while (values.hasMoreElements()) {
193                 String value = values.nextElement();
194                 logger.debug(element + ":" + value);
195             }
196         }
197         logger.debug("Attributes:");
198         en = request.getAttributeNames();
199         while (en.hasMoreElements()) {
200             String element = en.nextElement();
201             logger.debug(element + ":" + request.getAttribute(element));
202         }
203         logger.debug("ContextPath: " + request.getContextPath());
204     }
205
206
207     /**
208      * Dump the body of the request.
209      *
210      * @param request the request to act on
211      */
212     private static void dumpRequestBody(HttpServletRequest request) {
213         if ("PUT".equals(request.getMethod()) || "POST".equals(request.getMethod())) {
214             // POST and PUT are allowed to have parameters in the content, but in our usage the parameters are always in
215             // the Query string.
216             // More importantly, there are cases where the POST and PUT content is NOT parameters (e.g. it might contain
217             // a Policy file).
218             // Unfortunately the request.getParameterMap method reads the content to see if there are any parameters,
219             // and once the content is read it cannot be read again.
220             // Thus for PUT and POST we must avoid reading the content here so that the main code can read it.
221             logger.debug("Query String:" + request.getQueryString());
222             try {
223                 if (request.getInputStream() == null) {
224                     logger.debug("Content: No content inputStream");
225                 } else {
226                     logger.debug("Content available: " + request.getInputStream().available());
227                 }
228             } catch (Exception e) {
229                 logger.debug("Content: inputStream exception: " + e.getMessage() + ";  (May not be relevant)" + e);
230             }
231         } else {
232             logger.debug("Parameters:");
233             Map<String, String[]> params = request.getParameterMap();
234             Set<String> keys = params.keySet();
235             for (String key : keys) {
236                 String[] values = params.get(key);
237                 logger.debug(key + "(" + values.length + "): " + (values.length > 0 ? values[0] : ""));
238             }
239         }
240         logger.debug("Request URL:" + request.getRequestURL());
241     }
242 }