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.FileOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.net.MalformedURLException;
30 import java.net.URLConnection;
31 import java.nio.charset.StandardCharsets;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.nio.file.Paths;
35 import java.util.Base64;
36 import java.util.ConcurrentModificationException;
37 import java.util.HashMap;
38 import java.util.Properties;
41 import org.apache.commons.io.IOUtils;
42 import org.openecomp.policy.pdp.rest.notifications.NotificationController;
43 import org.openecomp.policy.rest.XACMLRest;
44 import org.openecomp.policy.rest.XACMLRestProperties;
45 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
46 import org.openecomp.policy.common.logging.flexlogger.Logger;
48 import org.openecomp.policy.xacml.api.XACMLErrorConstants;
49 import com.att.research.xacml.api.pap.PAPException;
50 import com.att.research.xacml.api.pap.PDPStatus;
51 import com.att.research.xacml.api.pap.PDPStatus.Status;
52 import com.att.research.xacml.api.pdp.PDPEngine;
53 import com.att.research.xacml.api.pdp.PDPEngineFactory;
54 import com.att.research.xacml.api.pip.PIPEngine;
55 import com.att.research.xacml.api.pip.PIPException;
56 import com.att.research.xacml.api.pip.PIPFinder;
57 import com.att.research.xacml.api.pip.PIPFinderFactory;
58 import org.openecomp.policy.xacml.std.pap.StdPDPPIPConfig;
59 import org.openecomp.policy.xacml.std.pap.StdPDPPolicy;
60 import org.openecomp.policy.xacml.std.pap.StdPDPStatus;
61 import com.att.research.xacml.util.FactoryException;
62 import com.att.research.xacml.util.XACMLProperties;
63 import com.att.research.xacmlatt.pdp.policy.PolicyDef;
64 import com.att.research.xacmlatt.pdp.policy.dom.DOMPolicyDef;
65 import com.att.research.xacmlatt.pdp.std.StdPolicyFinderFactory;
66 import com.google.common.base.Splitter;
69 * Does the work for loading policy and PIP configurations sent from the PAP
75 public class XACMLPdpLoader {
76 private static final Logger logger = FlexLogger.getLogger(XACMLPdpLoader.class);
77 private static NotificationController notificationController = new NotificationController();
78 private static final Long notifyDelay = (long) XACMLPdpServlet.getNotificationDelay();
81 public static synchronized PDPEngine loadEngine(StdPDPStatus status,
82 Properties policyProperties, Properties pipProperties) {
83 logger.info("loadEngine: " + policyProperties + " " + pipProperties);
85 // First load our policies
89 // Were we given some properties?
91 if (policyProperties == null) {
93 // On init we have no incoming configuration, so just
94 // Load our current saved configuration
96 policyProperties = new Properties();
97 try (InputStream is = Files.newInputStream(getPDPPolicyCache())) {
98 policyProperties.load(is);
103 // Get our policy cache up-to-date
105 // Side effects of this include:
106 // - downloading of policies from remote locations, and
107 // - creating new "<PolicyId>.file" properties for files existing
110 XACMLPdpLoader.cachePolicies(policyProperties);
112 // Validate the policies
114 XACMLPdpLoader.validatePolicies(policyProperties, status);
115 if (logger.isDebugEnabled()) {
116 logger.debug("Status: " + status);
118 } catch (ConcurrentModificationException e) {
119 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e.getMessage());
120 // TODO:EELF Cleanup - Remove logger
121 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "");
122 } catch (Exception e) {
123 String error = "Failed to load Policy Cache properties file: "
125 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + error, e);
126 // TODO:EELF Cleanup - Remove logger
127 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, error);
128 status.addLoadError(error);
129 status.setStatus(PDPStatus.Status.LOAD_ERRORS);
132 // Load our PIP configuration
136 // Were we given some properties to use?
138 if (pipProperties == null) {
140 // Load our current saved configuration
142 pipProperties = new Properties();
143 try (InputStream is = Files.newInputStream(getPIPConfig())) {
144 pipProperties.load(is);
148 // Validate our PIP configurations
150 XACMLPdpLoader.validatePipConfiguration(pipProperties, status);
151 if (logger.isDebugEnabled()) {
152 logger.debug("Status: " + status);
154 } catch (Exception e) {
155 String error = "Failed to load/validate Pip Config properties file: "
157 logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + error, e);
158 // TODO:EELF Cleanup - Remove logger
159 //PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, error);
160 status.addLoadError(XACMLErrorConstants.ERROR_PROCESS_FLOW + error);
161 status.setStatus(PDPStatus.Status.LOAD_ERRORS);
164 // Were they validated?
166 if (status.getStatus() == Status.LOAD_ERRORS) {
167 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW +"there were load errors");
168 // TODO:EELF Cleanup - Remove logger
169 //PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE,"there were load errors");
173 // Reset our official properties the PDP factory
174 // uses to configure the PDP engine.
176 XACMLRest.loadXacmlProperties(policyProperties, pipProperties);
178 // Dump ALL our properties that we are trying to load
181 logger.info(XACMLProperties.getProperties().toString());
182 } catch (IOException e) {
183 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to get XACML Properties", e);
184 // TODO:EELF Cleanup - Remove logger
185 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "Failed to get XACML Properties");
188 // Now load the PDP engine
190 PDPEngineFactory factory = null;
191 PDPEngine engine = null;
193 factory = PDPEngineFactory.newInstance();
194 engine = factory.newEngine();
195 logger.info("Loaded new PDP engine.");
196 status.setStatus(Status.UP_TO_DATE);
197 } catch (FactoryException e) {
198 String error = "Failed to create new PDP Engine";
199 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR +error, e);
200 // TODO:EELF Cleanup - Remove logger
201 //PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, error);
202 status.addLoadError(error);
204 // Notification will be Sent Here.
209 private static HashMap<String, PolicyDef> policyContainer = null;
211 private static void sendNotification(){
212 Thread notify = new Thread(){
215 Thread.sleep(notifyDelay);
216 NotificationController.sendNotification();
218 logger.error(XACMLErrorConstants.ERROR_UNKNOWN + e);
219 // TODO:EELF Cleanup - Remove logger
220 //PolicyLogger.error(MessageCodes.ERROR_UNKNOWN, e, "");
227 public static synchronized void validatePolicies(Properties properties,
228 StdPDPStatus status) throws PAPException {
229 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
230 Set<String> refPolicies = XACMLProperties
231 .getReferencedPolicyIDs(properties);
232 policyContainer = new HashMap<String, PolicyDef>();
234 for (String id : rootPolicies) {
235 loadPolicy(properties, status, id, true);
237 // remember which policies were root policies
238 status.addAllLoadedRootPolicies(status.getLoadedPolicies());
240 for (String id : refPolicies) {
241 loadPolicy(properties, status, id, false);
243 logger.info("Loaded " + status.getLoadedPolicies().size()
244 + " policies, failed to load "
245 + status.getFailedPolicies().size() + " policies, "
246 + status.getLoadedRootPolicies().size() + " root policies");
247 // TODO Notification Controller is here..
248 notificationController.check(status, policyContainer);
249 if (status.getLoadedRootPolicies().size() == 0) {
250 logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW +"NO ROOT POLICIES LOADED!!! Cannot serve PEP Requests.");
251 status.addLoadWarning("NO ROOT POLICIES LOADED!!! Cannot serve PEP Requests.");
253 policyContainer.clear();
257 public static synchronized void loadPolicy(Properties properties,
258 StdPDPStatus status, String id, boolean isRoot) throws PAPException {
259 PolicyDef policy = null;
260 String location = null;
261 URI locationURI = null;
262 boolean isFile = false;
263 boolean rougeFile = false;
265 location = properties.getProperty(id + ".file");
266 if(location != null){
268 locationURI = Paths.get(location).toUri();
269 try (InputStream is = Files.newInputStream(Paths.get(location))) {
270 policy = DOMPolicyDef.load(is);
271 } catch (Exception e){
272 // This Happens if a any issue with the error policyFile. Lets remove it.
274 logger.error("Corrupted policy file, deleting: " + location);
275 Files.delete(Paths.get(location));
276 properties.remove(id + ".file");
278 } catch (IOException e1) {
283 if(location==null || rougeFile){
287 location = properties.getProperty(id + ".url");
288 if (location != null) {
293 boolean error= false;
296 PapUrlResolver papUrls = PapUrlResolver.getInstance();
297 while(papUrls.hasMoreUrls()){
298 String papID = papUrls.getUserId();
299 String papPass = papUrls.getPass();
300 Base64.Encoder encoder = Base64.getEncoder();
301 String encoding = encoder.encodeToString((papID+":"+papPass).getBytes(StandardCharsets.UTF_8));
302 locationURI = URI.create(papUrls.getUrl(PapUrlResolver.extractIdFromUrl(location)));
303 URL url = locationURI.toURL();
305 URLConnection urlConnection = null;
307 urlConnection = url.openConnection();
308 } catch (IOException e){
313 urlConnection.setRequestProperty(XACMLRestProperties.PROP_PDP_HTTP_HEADER_ID,
314 XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_ID));
315 urlConnection.setRequestProperty("Authorization", "Basic " + encoding);
317 // Now construct the output file name
319 Path outFile = Paths.get(getPDPConfig().toAbsolutePath()
324 try (FileOutputStream fos = new FileOutputStream(
326 IOUtils.copy(urlConnection.getInputStream(), fos);
327 } catch(IOException e){
336 try (InputStream fis = Files.newInputStream(outFile)) {
337 policy = DOMPolicyDef.load(fis);
340 logger.error("Corrupted policy file, deleting: " + location);
341 Files.delete(outFile);
345 } catch (IOException e1) {
352 properties.setProperty(id + ".file", outFile
353 .toAbsolutePath().toString());
357 }while(error && errorCount>2);
360 if (policy != null) {
361 status.addLoadedPolicy(new StdPDPPolicy(id, isRoot,
362 locationURI, properties));
363 logger.info("Loaded policy: " + policy.getIdentifier()
364 + " version: " + policy.getVersion().stringValue());
365 // Sending the policy objects to the Notification Controller.
366 policyContainer.put(id, policy);
368 String error = "Failed to load policy " + location;
369 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + error);
370 // TODO:EELF Cleanup - Remove logger
371 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, error);
372 status.setStatus(PDPStatus.Status.LOAD_ERRORS);
373 status.addLoadError(error);
374 status.addFailedPolicy(new StdPDPPolicy(id, isRoot));
376 } catch (Exception e) {
377 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW +"Failed to load policy '" + id + "' from location '"
378 + location + "'", e);
379 // TODO:EELF Cleanup - Remove logger
380 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "Failed to load policy '" + id + "' from location '"
381 // + location + "'");
382 status.setStatus(PDPStatus.Status.LOAD_ERRORS);
383 status.addFailedPolicy(new StdPDPPolicy(id, isRoot));
392 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Corrupted policy file, deleting: " + location);
393 // TODO:EELF Cleanup - Remove logger
394 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Corrupted policy file, deleting: " + location);
395 Files.delete(Paths.get(location));
397 } catch (IOException e1) {
398 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e1);
399 // TODO:EELF Cleanup - Remove logger
400 //PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e1, "");
403 //throw new PAPException("Failed to load policy '" + id + "' from location '" + location + "'");
407 public static synchronized void validatePipConfiguration(
408 Properties properties, StdPDPStatus status) throws PAPException {
410 PIPFinderFactory factory = PIPFinderFactory.newInstance(properties);
411 if (factory == null) {
412 throw new FactoryException(
413 "Could not create PIP Finder Factory: "
415 .getProperty(XACMLProperties.PROP_PIPFINDERFACTORY));
417 PIPFinder finder = factory.getFinder(properties);
419 // Check for this, although it should always return something
421 if (finder == null) {
422 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "pip finder factory returned a null engine.");
423 // TODO:EELF Cleanup - Remove logger
424 //PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, "pip finder factory returned a null engine.");
425 throw new PIPException("Could not create PIP Finder");
427 logger.info("Loaded PIP finder");
429 for (PIPEngine engine : finder.getPIPEngines()) {
430 logger.info("Configured PIP Engine: " + engine.getName());
431 StdPDPPIPConfig config = new StdPDPPIPConfig();
432 config.setName(engine.getName());
433 status.addLoadedPipConfig(config);
435 } catch (FactoryException | PIPException e) {
436 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "validate PIP configuration failed: "
437 + e.getLocalizedMessage());
438 // TODO:EELF Cleanup - Remove logger
439 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e.getLocalizedMessage(), "validate PIP configuration failed");
440 status.addLoadError(e.getLocalizedMessage());
441 status.setStatus(Status.LOAD_ERRORS);
442 throw new PAPException(e);
447 * Iterates the policies defined in the props object to ensure they are
448 * loaded locally. Policies are searched for in the following order: - see
449 * if the current properties has a "<PolicyID>.file" entry and that
450 * file exists in the local directory - if not, see if the file exists in
451 * the local directory; if so create a ".file" property for it. - if not,
452 * get the "<PolicyID>.url" property and try to GET the policy from
453 * that location (and set the ".file" property)
455 * If the ".file" property is created, then true is returned to tell the
456 * caller that the props object changed.
459 * @return true/false if anything was changed in the props object
460 * @throws PAPException
462 public static synchronized boolean cachePolicies(Properties props)
463 throws PAPException {
464 boolean changed = false;
465 String[] lists = new String[2];
466 lists[0] = props.getProperty(XACMLProperties.PROP_ROOTPOLICIES);
467 lists[1] = props.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES);
468 for (String list : lists) {
470 // Check for a null or empty parameter
472 if (list == null || list.length() == 0) {
475 Iterable<String> policies = Splitter.on(',').trimResults()
476 .omitEmptyStrings().split(list);
477 for (String policy : policies) {
478 boolean policyExists = false;
480 // First look for ".file" property and verify the file exists
481 String propLocation = props.getProperty(policy
482 + StdPolicyFinderFactory.PROP_FILE);
483 if (propLocation != null) {
487 policyExists = Files.exists(Paths.get(propLocation));
488 if (policyExists == false) {
489 logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Policy file " + policy + " expected at "
490 + propLocation + " does NOT exist.");
494 // If ".file" property does not exist, try looking for the local
496 // (it might exist without having a ".file" property set for it)
497 if (policyExists == false) {
499 // Now construct the output file name
501 Path outFile = Paths.get(getPDPConfig().toAbsolutePath()
502 .toString(), policy);
504 // Double check to see if we pulled it at some point
506 policyExists = Files.exists(outFile);
509 // Set the property so the PDP engine doesn't have
510 // to pull it from the URL but rather the FILE.
512 logger.info("Policy does exist: "
513 + outFile.toAbsolutePath().toString());
514 props.setProperty(policy
515 + StdPolicyFinderFactory.PROP_FILE, outFile
516 .toAbsolutePath().toString());
518 // Indicate that there were changes made to the
524 // File does not exist locally, so we need to get it
525 // from the location given in the ".url" property (which
529 // There better be a URL to retrieve it
531 propLocation = props.getProperty(policy
532 + StdPolicyFinderFactory.PROP_URL);
533 if (propLocation != null) {
537 PapUrlResolver papUrls = PapUrlResolver.getInstance();
538 while(papUrls.hasMoreUrls()){
539 String papID = papUrls.getUserId();
540 String papPass = papUrls.getPass();
541 Base64.Encoder encoder = Base64.getEncoder();
542 String encoding = encoder.encodeToString((papID+":"+papPass).getBytes(StandardCharsets.UTF_8));
548 url = new URL(papUrls.getUrl(PapUrlResolver.extractIdFromUrl(propLocation)));
549 logger.info("Pulling " + url.toString());
551 // Open the connection
553 URLConnection urlConnection = url.openConnection();
554 urlConnection.setRequestProperty(XACMLRestProperties.PROP_PDP_HTTP_HEADER_ID,
555 XACMLProperties.getProperty(XACMLRestProperties.PROP_PDP_ID));
556 urlConnection.setRequestProperty("Authorization", "Basic " + encoding);
560 try (InputStream is = urlConnection
562 OutputStream os = new FileOutputStream(
564 IOUtils.copy(is, os);
567 // Now save it in the properties as a .file
569 logger.info("Pulled policy: "
570 + outFile.toAbsolutePath().toString());
571 props.setProperty(policy
572 + StdPolicyFinderFactory.PROP_FILE,
573 outFile.toAbsolutePath().toString());
576 // Indicate that there were changes made to the
580 } catch (Exception e) {
582 if (e instanceof MalformedURLException) {
583 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Policy '"
585 + "' had bad URL in new configuration, URL='"
586 + propLocation + "'");
587 // TODO:EELF Cleanup - Remove logger
588 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Policy '"
590 // + "' had bad URL in new configuration, URL='"
591 // + propLocation + "'");
594 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Error while retrieving policy "
597 + url.toString() + ", e=" + e);
598 // TODO:EELF Cleanup - Remove logger
599 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "Error while retrieving policy "
602 // + url.toString());
608 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Policy " + policy
609 + " does NOT exist and does NOT have a URL");
610 // TODO:EELF Cleanup - Remove logger
611 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Policy " + policy
612 // + " does NOT exist and does NOT have a URL");
621 public static synchronized Path getPDPPolicyCache() throws PAPException {
622 Path config = getPDPConfig();
623 Path policyProperties = Paths.get(config.toAbsolutePath().toString(),
624 "xacml.policy.properties");
625 if (Files.notExists(policyProperties)) {
626 logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + policyProperties.toAbsolutePath().toString()
627 + " does NOT exist.");
629 // Try to create the file
632 Files.createFile(policyProperties);
633 } catch (IOException e) {
634 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to create policy properties file: "
635 + policyProperties.toAbsolutePath().toString());
636 // TODO:EELF Cleanup - Remove logger
637 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Failed to create policy properties file: "
638 // + policyProperties.toAbsolutePath().toString());
639 throw new PAPException(
640 "Failed to create policy properties file: "
641 + policyProperties.toAbsolutePath().toString());
644 return policyProperties;
647 public static synchronized Path getPIPConfig() throws PAPException {
648 Path config = getPDPConfig();
649 Path pipConfigProperties = Paths.get(
650 config.toAbsolutePath().toString(), "xacml.pip.properties");
651 if (Files.notExists(pipConfigProperties)) {
652 logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + pipConfigProperties.toAbsolutePath().toString()
653 + " does NOT exist.");
655 // Try to create the file
658 Files.createFile(pipConfigProperties);
659 } catch (IOException e) {
660 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to create pip properties file: "
661 + pipConfigProperties.toAbsolutePath().toString());
662 // TODO:EELF Cleanup - Remove logger
663 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, "Failed to create pip properties file: "
664 //+ pipConfigProperties.toAbsolutePath().toString());
665 throw new PAPException("Failed to create pip properties file: "
666 + pipConfigProperties.toAbsolutePath().toString());
669 return pipConfigProperties;
672 public static synchronized Path getPDPConfig() throws PAPException {
673 Path config = Paths.get(XACMLProperties
674 .getProperty(XACMLRestProperties.PROP_PDP_CONFIG));
675 if (Files.notExists(config)) {
676 logger.warn(XACMLErrorConstants.ERROR_PROCESS_FLOW + config.toAbsolutePath().toString() + " does NOT exist.");
678 // Try to create the directory
681 Files.createDirectories(config);
682 } catch (IOException e) {
683 logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to create config directory: "
684 + config.toAbsolutePath().toString(), e);
685 // TODO:EELF Cleanup - Remove logger
686 //PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "Failed to create config directory: "
687 //+ config.toAbsolutePath().toString());
688 throw new PAPException("Failed to create config directory: "
689 + config.toAbsolutePath().toString());