2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2019 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.
 
  19  * SPDX-License-Identifier: Apache-2.0
 
  20  * ============LICENSE_END=========================================================
 
  23 package org.onap.policy.pdp.xacml.application.common;
 
  25 import com.att.research.xacml.api.Identifier;
 
  26 import com.att.research.xacml.util.XACMLProperties;
 
  29 import java.io.FileInputStream;
 
  30 import java.io.FileOutputStream;
 
  31 import java.io.IOException;
 
  32 import java.io.InputStream;
 
  33 import java.io.OutputStream;
 
  34 import java.nio.file.Files;
 
  35 import java.nio.file.Path;
 
  36 import java.nio.file.Paths;
 
  37 import java.util.Map.Entry;
 
  38 import java.util.Properties;
 
  40 import java.util.StringJoiner;
 
  41 import java.util.stream.Collectors;
 
  43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.IdReferenceType;
 
  44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
 
  45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
 
  46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
 
  47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
 
  49 import org.slf4j.Logger;
 
  50 import org.slf4j.LoggerFactory;
 
  52 public class XacmlPolicyUtils {
 
  54     private static final Logger LOGGER = LoggerFactory.getLogger(XacmlPolicyUtils.class);
 
  55     private static final String DOT_FILE_SUFFIX = ".file";
 
  56     private static final String NOT_FOUND_MESSAGE = "NOT FOUND";
 
  58     private XacmlPolicyUtils() {
 
  63      * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
 
  64      * will also be an empty Target created. You can easily override that if need be.
 
  66      * @param policyId Policy Id
 
  67      * @param policyCombiningAlgorithm Policy Combining Algorithm
 
  68      * @return PolicySetType object
 
  70     public static PolicySetType createEmptyPolicySet(String policyId, Identifier policyCombiningAlgorithm) {
 
  71         PolicySetType policy = new PolicySetType();
 
  72         policy.setPolicySetId(policyId);
 
  73         policy.setPolicyCombiningAlgId(policyCombiningAlgorithm.stringValue());
 
  74         policy.setTarget(new TargetType());
 
  79      * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
 
  80      * will also be an empty Target created. You can easily override that if need be.
 
  82      * @param policyId Policy Id
 
  83      * @param ruleCombiningAlgorithm Rule Combining Algorithm
 
  84      * @return PolicyType object
 
  86     public static PolicyType createEmptyPolicy(String policyId, Identifier ruleCombiningAlgorithm) {
 
  87         PolicyType policy = new PolicyType();
 
  88         policy.setPolicyId(policyId);
 
  89         policy.setRuleCombiningAlgId(ruleCombiningAlgorithm.stringValue());
 
  90         policy.setTarget(new TargetType());
 
  95      * This method adds a list of PolicyType objects to a root PolicySetType as
 
  96      * referenced policies.
 
  98      * @param rootPolicy Root PolicySet being updated
 
  99      * @param referencedPolicies A list of PolicyType being added as a references
 
 100      * @return the rootPolicy PolicySet object
 
 102     public static PolicySetType addPoliciesToXacmlRootPolicy(PolicySetType rootPolicy,
 
 103             PolicyType... referencedPolicies) {
 
 104         ObjectFactory factory = new ObjectFactory();
 
 106         // Iterate each policy
 
 108         for (PolicyType referencedPolicy : referencedPolicies) {
 
 109             IdReferenceType reference = new IdReferenceType();
 
 110             reference.setValue(referencedPolicy.getPolicyId());
 
 114             rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicyIdReference(reference));
 
 117         // Return the updated object
 
 123      * This method updates a root PolicySetType by adding in a PolicyType as a reference.
 
 125      * @param rootPolicy Root PolicySet being updated
 
 126      * @param referencedPolicySets A list of PolicySetType being added as a references
 
 127      * @return the rootPolicy PolicySet object
 
 129     public static PolicySetType addPolicySetsToXacmlRootPolicy(PolicySetType rootPolicy,
 
 130             PolicySetType... referencedPolicySets) {
 
 131         ObjectFactory factory = new ObjectFactory();
 
 133         // Iterate each policy
 
 135         for (PolicySetType referencedPolicySet : referencedPolicySets) {
 
 136             IdReferenceType reference = new IdReferenceType();
 
 137             reference.setValue(referencedPolicySet.getPolicySetId());
 
 141             rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicySetIdReference(reference));
 
 144         // Return the updated object
 
 150      * Adds in the root policy to the PDP properties object.
 
 152      * @param properties Input properties
 
 153      * @param rootPolicyPath Path to the root policy file
 
 154      * @return Properties object
 
 156     public static Properties addRootPolicy(Properties properties, Path rootPolicyPath) {
 
 158         // Get the current set of referenced policy ids
 
 160         Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
 
 162         // Construct a unique id
 
 166             String refId = "root" + id;
 
 167             if (rootPolicies.contains(refId)) {
 
 170                 rootPolicies.add(refId);
 
 171                 properties.put(refId + DOT_FILE_SUFFIX, rootPolicyPath.toAbsolutePath().toString());
 
 176         // Set the new comma separated list
 
 178         properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES,
 
 179                 rootPolicies.stream().collect(Collectors.joining(",")));
 
 184      * Adds in the referenced policy to the PDP properties object.
 
 186      * @param properties Input properties
 
 187      * @param refPolicyPath Path to the referenced policy file
 
 188      * @return Properties object
 
 190     public static Properties addReferencedPolicy(Properties properties, Path refPolicyPath) {
 
 192         // Get the current set of referenced policy ids
 
 194         Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
 
 196         // Construct a unique id
 
 200             String refId = "ref" + id;
 
 201             if (referencedPolicies.contains(refId)) {
 
 204                 referencedPolicies.add(refId);
 
 205                 properties.put(refId + DOT_FILE_SUFFIX, refPolicyPath.toAbsolutePath().toString());
 
 210         // Set the new comma separated list
 
 212         properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES,
 
 213                 referencedPolicies.stream().collect(Collectors.joining(",")));
 
 218      * Removes a referenced policy from the Properties object. Both in the line
 
 219      * that identifies the policy and the .file property that points to the path.
 
 221      * @param properties Input Properties object to remove
 
 222      * @param refPolicyPath The policy file path
 
 223      * @return Properties object
 
 225     public static Properties removeReferencedPolicy(Properties properties, Path refPolicyPath) {
 
 227         // Get the current set of referenced policy ids
 
 229         StringJoiner join = new StringJoiner(",");
 
 230         boolean found = false;
 
 231         Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
 
 232         for (String refPolicy : referencedPolicies) {
 
 233             String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
 
 235             // If the key and value match, then it will return true
 
 237             if (properties.remove(refPolicyFile, refPolicyPath.toString())) {
 
 239                 // Record that we actually removed it
 
 254             // Now update the list of referenced properties
 
 256             properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, join.toString());
 
 262      * Does a debug dump of referenced and root policy values.
 
 264      * @param properties Input Properties object
 
 265      * @param logger Logger object to use
 
 267     public static void debugDumpPolicyProperties(Properties properties, Logger logger) {
 
 269         // I hate surrounding this all with an if, but by
 
 270         // doing so I clear sonar issues with passing System.lineSeparator()
 
 273         if (logger.isDebugEnabled()) {
 
 275             // Get the current set of referenced policy ids
 
 277             Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
 
 278             logger.debug("Root Policies: {}", properties.getProperty(XACMLProperties.PROP_ROOTPOLICIES));
 
 279             for (String root : rootPolicies) {
 
 280                 logger.debug("{}", properties.getProperty(root + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
 
 283             // Get the current set of referenced policy ids
 
 285             Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
 
 286             logger.debug("Referenced Policies: {}", properties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES));
 
 287             for (String ref : referencedPolicies) {
 
 288                 logger.debug("{}", properties.getProperty(ref + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
 
 294      * Constructs a unique policy filename for a given policy.
 
 296      * <P>It could be dangerous to use policy-id and policy-version if the user
 
 297      * gives us an invalid policy-id and policy-versions.
 
 299      * <P>Should we append a UUID also to guarantee uniqueness?
 
 301      * <P>How do we track that in case we need to know what policies we have loaded?
 
 303      * @param policy PolicyType object
 
 304      * @param path Path for policy
 
 305      * @return Path unique file path for the Policy
 
 307     public static Path constructUniquePolicyFilename(PolicyType policy, Path path) {
 
 310         // Can it be possible to produce an invalid filename?
 
 311         // Should we insert a UUID
 
 313         String filename = policy.getPolicyId() + "_" + policy.getVersion() + ".xml";
 
 315         // Construct the Path
 
 317         return Paths.get(path.toAbsolutePath().toString(), filename);
 
 321      * Load properties from given file.
 
 323      * @throws IOException If unable to read file
 
 325     public static Properties loadXacmlProperties(Path propertyPath) throws IOException {
 
 326         LOGGER.debug("Loading xacml properties {}", propertyPath);
 
 327         try (InputStream is = Files.newInputStream(propertyPath)) {
 
 328             Properties properties = new Properties();
 
 330             if (LOGGER.isDebugEnabled()) {
 
 331                 LOGGER.debug("Loaded xacml properties {} {}", System.lineSeparator(), properties);
 
 333                 // It would be nice to sort this first
 
 335                 properties.list(System.out);
 
 336                 for (Entry<Object, Object> entrySet : properties.entrySet()) {
 
 337                     LOGGER.debug("{} -> {}", entrySet.getKey(), entrySet.getValue());
 
 345      * Stores the XACML Properties to the given file location.
 
 347      * @throws IOException If unable to store the file.
 
 349     public static void storeXacmlProperties(Properties properties, Path propertyPath) throws IOException {
 
 350         if (LOGGER.isDebugEnabled()) {
 
 351             LOGGER.debug("Storing xacml properties {} {} {}", properties, System.lineSeparator(), propertyPath);
 
 352             properties.list(System.out);
 
 354         try (OutputStream os = Files.newOutputStream(propertyPath)) {
 
 355             String strComments = "#";
 
 356             properties.store(os, strComments);
 
 361      * Appends 'xacml.properties' to a root Path object
 
 363      * @param rootPath Root Path object
 
 364      * @return Path to rootPath/xacml.properties file
 
 366     public static Path getPropertiesPath(Path rootPath) {
 
 367         return Paths.get(rootPath.toAbsolutePath().toString(), "xacml.properties");
 
 370     public interface FileCreator {
 
 371         public File createAFile(String filename) throws IOException;
 
 376      * Copies a xacml.properties file to another location and all the policies defined within it.
 
 378      * @param propertiesPath Path to an existing properties file
 
 379      * @param properties Properties object
 
 380      * @param creator A callback that can create files. Allows JUnit test to pass Temporary folder
 
 381      * @return File object that points to new Properties file
 
 382      * @throws IOException Could not read/write files
 
 384     public static File copyXacmlPropertiesContents(String propertiesPath, Properties properties,
 
 385             FileCreator creator) throws IOException {
 
 387         // Open the properties file
 
 389         try (InputStream is = new FileInputStream(propertiesPath)) {
 
 391             // Load in the properties
 
 395             // Now we create a new xacml.properties in the temporary folder location
 
 397             File propertiesFile = creator.createAFile("xacml.properties");
 
 399             // Iterate through any root policies defined
 
 401             for (String root : XACMLProperties.getRootPolicyIDs(properties)) {
 
 405                 Path rootPath = Paths.get(properties.getProperty(root + DOT_FILE_SUFFIX));
 
 406                 LOGGER.debug("Root file {} {}", rootPath, rootPath.getFileName());
 
 408                 // Construct new path for the root policy
 
 410                 File newRootPath = creator.createAFile(rootPath.getFileName().toString());
 
 412                 // Copy the policy file to the temporary folder
 
 414                 com.google.common.io.Files.copy(rootPath.toFile(), newRootPath);
 
 416                 // Change the properties object to point to where the new policy is
 
 417                 // in the temporary folder
 
 419                 properties.setProperty(root + DOT_FILE_SUFFIX, newRootPath.getAbsolutePath());
 
 422             // Iterate through any referenced policies defined
 
 424             for (String referenced : XACMLProperties.getReferencedPolicyIDs(properties)) {
 
 428                 Path refPath = Paths.get(properties.getProperty(referenced + DOT_FILE_SUFFIX));
 
 429                 LOGGER.debug("Referenced file {} {}", refPath, refPath.getFileName());
 
 431                 // Construct new path for the root policy
 
 433                 File newReferencedPath = creator.createAFile(refPath.getFileName().toString());
 
 435                 // Copy the policy file to the temporary folder
 
 437                 com.google.common.io.Files.copy(refPath.toFile(), newReferencedPath);
 
 439                 // Change the properties object to point to where the new policy is
 
 440                 // in the temporary folder
 
 442                 properties.setProperty(referenced + DOT_FILE_SUFFIX, newReferencedPath.getAbsolutePath());
 
 445             // Save the new properties file to the temporary folder
 
 447             try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) {
 
 448                 properties.store(os, "");
 
 451             // Return the new path to the properties folder
 
 453             return propertiesFile;