2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019-2020 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.XACMLPolicyWriter;
27 import com.att.research.xacml.util.XACMLProperties;
30 import java.io.FileInputStream;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.OutputStream;
35 import java.nio.file.Files;
36 import java.nio.file.Path;
37 import java.nio.file.Paths;
38 import java.util.Map.Entry;
39 import java.util.Properties;
41 import java.util.StringJoiner;
42 import java.util.stream.Collectors;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.IdReferenceType;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public class XacmlPolicyUtils {
55 private static final Logger LOGGER = LoggerFactory.getLogger(XacmlPolicyUtils.class);
57 public static final String XACML_PROPERTY_FILE = "xacml.properties";
58 public static final String LINE_SEPARATOR = System.lineSeparator();
60 private static final String DOT_FILE_SUFFIX = ".file";
61 private static final String NOT_FOUND_MESSAGE = "NOT FOUND";
63 private XacmlPolicyUtils() {
68 * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
69 * will also be an empty Target created. You can easily override that if need be.
71 * @param policyId Policy Id
72 * @param policyCombiningAlgorithm Policy Combining Algorithm
73 * @return PolicySetType object
75 public static PolicySetType createEmptyPolicySet(String policyId, Identifier policyCombiningAlgorithm) {
76 PolicySetType policy = new PolicySetType();
77 policy.setPolicySetId(policyId);
78 policy.setPolicyCombiningAlgId(policyCombiningAlgorithm.stringValue());
79 policy.setTarget(new TargetType());
84 * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
85 * will also be an empty Target created. You can easily override that if need be.
87 * @param policyId Policy Id
88 * @param ruleCombiningAlgorithm Rule Combining Algorithm
89 * @return PolicyType object
91 public static PolicyType createEmptyPolicy(String policyId, Identifier ruleCombiningAlgorithm) {
92 PolicyType policy = new PolicyType();
93 policy.setPolicyId(policyId);
94 policy.setRuleCombiningAlgId(ruleCombiningAlgorithm.stringValue());
95 policy.setTarget(new TargetType());
100 * This method adds a list of PolicyType objects to a root PolicySetType as
101 * referenced policies.
103 * @param rootPolicy Root PolicySet being updated
104 * @param referencedPolicies A list of PolicyType being added as a references
105 * @return the rootPolicy PolicySet object
107 public static PolicySetType addPoliciesToXacmlRootPolicy(PolicySetType rootPolicy,
108 PolicyType... referencedPolicies) {
109 ObjectFactory factory = new ObjectFactory();
111 // Iterate each policy
113 for (PolicyType referencedPolicy : referencedPolicies) {
114 IdReferenceType reference = new IdReferenceType();
115 reference.setValue(referencedPolicy.getPolicyId());
119 rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicyIdReference(reference));
122 // Return the updated object
128 * This method updates a root PolicySetType by adding in a PolicyType as a reference.
130 * @param rootPolicy Root PolicySet being updated
131 * @param referencedPolicySets A list of PolicySetType being added as a references
132 * @return the rootPolicy PolicySet object
134 public static PolicySetType addPolicySetsToXacmlRootPolicy(PolicySetType rootPolicy,
135 PolicySetType... referencedPolicySets) {
136 ObjectFactory factory = new ObjectFactory();
138 // Iterate each policy
140 for (PolicySetType referencedPolicySet : referencedPolicySets) {
141 IdReferenceType reference = new IdReferenceType();
142 reference.setValue(referencedPolicySet.getPolicySetId());
146 rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicySetIdReference(reference));
149 // Return the updated object
155 * Adds in the root policy to the PDP properties object.
157 * @param properties Input properties
158 * @param rootPolicyPath Path to the root policy file
159 * @return Properties object
161 public static Properties addRootPolicy(Properties properties, Path rootPolicyPath) {
163 // Get the current set of referenced policy ids
165 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
167 // Construct a unique id
171 String refId = "root" + id;
172 if (rootPolicies.contains(refId)) {
175 rootPolicies.add(refId);
176 properties.put(refId + DOT_FILE_SUFFIX, rootPolicyPath.toAbsolutePath().toString());
181 // Set the new comma separated list
183 properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES,
184 rootPolicies.stream().collect(Collectors.joining(",")));
189 * Adds in the referenced policy to the PDP properties object.
191 * @param properties Input properties
192 * @param refPolicyPath Path to the referenced policy file
193 * @return Properties object
195 public static Properties addReferencedPolicy(Properties properties, Path refPolicyPath) {
197 // Get the current set of referenced policy ids
199 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
201 // Construct a unique id
205 String refId = "ref" + id;
206 if (referencedPolicies.contains(refId)) {
209 referencedPolicies.add(refId);
210 properties.put(refId + DOT_FILE_SUFFIX, refPolicyPath.toAbsolutePath().toString());
215 // Set the new comma separated list
217 properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES,
218 referencedPolicies.stream().collect(Collectors.joining(",")));
223 * Removes a root policy from the Properties object. Both in the line
224 * that identifies the policy and the .file property that points to the path.
226 * @param properties Input Properties object to remove
227 * @param rootPolicyPath The policy file path
228 * @return Properties object
230 public static Properties removeRootPolicy(Properties properties, Path rootPolicyPath) {
232 // Get the current set of referenced policy ids
234 StringJoiner join = new StringJoiner(",");
235 boolean found = false;
236 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
237 for (String refPolicy : rootPolicies) {
238 String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
240 // If the key and value match, then it will return true
242 if (properties.remove(refPolicyFile, rootPolicyPath.toString())) {
244 // Record that we actually removed it
259 // Now update the list of referenced properties
261 properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, join.toString());
267 * Removes a referenced policy from the Properties object. Both in the line
268 * that identifies the policy and the .file property that points to the path.
270 * @param properties Input Properties object to remove
271 * @param refPolicyPath The policy file path
272 * @return Properties object
274 public static Properties removeReferencedPolicy(Properties properties, Path refPolicyPath) {
276 // Get the current set of referenced policy ids
278 StringJoiner join = new StringJoiner(",");
279 boolean found = false;
280 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
281 for (String refPolicy : referencedPolicies) {
282 String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
284 // If the key and value match, then it will return true
286 if (properties.remove(refPolicyFile, refPolicyPath.toString())) {
288 // Record that we actually removed it
303 // Now update the list of referenced properties
305 properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, join.toString());
311 * Does a debug dump of referenced and root policy values.
313 * @param properties Input Properties object
314 * @param logger Logger object to use
316 public static void debugDumpPolicyProperties(Properties properties, Logger logger) {
318 // I hate surrounding this all with an if, but by
319 // doing so I clear sonar issues with passing System.lineSeparator()
322 if (logger.isDebugEnabled()) {
324 // Get the current set of referenced policy ids
326 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
327 logger.debug("Root Policies: {}", properties.getProperty(XACMLProperties.PROP_ROOTPOLICIES));
328 for (String root : rootPolicies) {
329 logger.debug("{}", properties.getProperty(root + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
332 // Get the current set of referenced policy ids
334 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
335 logger.debug("Referenced Policies: {}", properties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES));
336 for (String ref : referencedPolicies) {
337 logger.debug("{}", properties.getProperty(ref + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
343 * Constructs a unique policy filename for a given policy.
345 * <P>It could be dangerous to use policy-id and policy-version if the user
346 * gives us an invalid policy-id and policy-versions.
348 * <P>Should we append a UUID also to guarantee uniqueness?
350 * <P>How do we track that in case we need to know what policies we have loaded?
352 * @param policy PolicyType object
353 * @param path Path for policy
354 * @return Path unique file path for the Policy
356 public static Path constructUniquePolicyFilename(Object policy, Path path) {
359 if (policy instanceof PolicyType) {
360 id = ((PolicyType) policy).getPolicyId();
361 version = ((PolicyType) policy).getVersion();
362 } else if (policy instanceof PolicySetType) {
363 id = ((PolicySetType) policy).getPolicySetId();
364 version = ((PolicySetType) policy).getVersion();
366 throw new IllegalArgumentException("Must pass a PolicyType or PolicySetType");
370 // Can it be possible to produce an invalid filename?
371 // Should we insert a UUID
373 String filename = id + "_" + version + ".xml";
375 // Construct the Path
377 return Paths.get(path.toAbsolutePath().toString(), filename);
381 * Load properties from given file.
383 * @throws IOException If unable to read file
385 public static Properties loadXacmlProperties(Path propertyPath) throws IOException {
386 LOGGER.info("Loading xacml properties {}", propertyPath);
387 try (InputStream is = Files.newInputStream(propertyPath)) {
388 Properties properties = new Properties();
390 if (LOGGER.isInfoEnabled()) {
391 LOGGER.info("Loaded xacml properties {} {}", XacmlPolicyUtils.LINE_SEPARATOR, properties);
392 for (Entry<Object, Object> entrySet : properties.entrySet()) {
393 LOGGER.info("{} -> {}", entrySet.getKey(), entrySet.getValue());
401 * Stores the XACML Properties to the given file location.
403 * @throws IOException If unable to store the file.
405 public static void storeXacmlProperties(Properties properties, Path propertyPath) throws IOException {
406 LOGGER.info("Storing xacml properties {} {} {}", properties, XacmlPolicyUtils.LINE_SEPARATOR, propertyPath);
407 try (OutputStream os = Files.newOutputStream(propertyPath)) {
408 String strComments = "#";
409 properties.store(os, strComments);
414 * Appends 'xacml.properties' to a root Path object
416 * @param rootPath Root Path object
417 * @return Path to rootPath/xacml.properties file
419 public static Path getPropertiesPath(Path rootPath) {
420 return Paths.get(rootPath.toAbsolutePath().toString(), XACML_PROPERTY_FILE);
424 public interface FileCreator {
425 public File createAFile(String filename) throws IOException;
430 * Copies a xacml.properties file to another location and all the policies defined within it.
432 * @param propertiesPath Path to an existing properties file
433 * @param properties Properties object
434 * @param creator A callback that can create files. Allows JUnit test to pass Temporary folder
435 * @return File object that points to new Properties file
436 * @throws IOException Could not read/write files
438 public static File copyXacmlPropertiesContents(String propertiesPath, Properties properties,
439 FileCreator creator) throws IOException {
441 // Open the properties file
443 try (InputStream is = new FileInputStream(propertiesPath)) {
445 // Load in the properties
449 // Now we create a new xacml.properties in the temporary folder location
451 File propertiesFile = creator.createAFile(XACML_PROPERTY_FILE);
453 // Iterate through any root policies defined
455 for (String root : XACMLProperties.getRootPolicyIDs(properties)) {
459 Path rootPath = Paths.get(properties.getProperty(root + DOT_FILE_SUFFIX));
460 LOGGER.info("Root file {} {}", rootPath, rootPath.getFileName());
462 // Construct new path for the root policy
464 File newRootPath = creator.createAFile(rootPath.getFileName().toString());
466 // Copy the policy file to the temporary folder
468 com.google.common.io.Files.copy(rootPath.toFile(), newRootPath);
470 // Change the properties object to point to where the new policy is
471 // in the temporary folder
473 properties.setProperty(root + DOT_FILE_SUFFIX, newRootPath.getAbsolutePath());
476 // Iterate through any referenced policies defined
478 for (String referenced : XACMLProperties.getReferencedPolicyIDs(properties)) {
482 Path refPath = Paths.get(properties.getProperty(referenced + DOT_FILE_SUFFIX));
483 LOGGER.info("Referenced file {} {}", refPath, refPath.getFileName());
485 // Construct new path for the root policy
487 File newReferencedPath = creator.createAFile(refPath.getFileName().toString());
489 // Copy the policy file to the temporary folder
491 com.google.common.io.Files.copy(refPath.toFile(), newReferencedPath);
493 // Change the properties object to point to where the new policy is
494 // in the temporary folder
496 properties.setProperty(referenced + DOT_FILE_SUFFIX, newReferencedPath.getAbsolutePath());
499 // Save the new properties file to the temporary folder
501 try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) {
502 properties.store(os, "");
505 // Return the new path to the properties folder
507 return propertiesFile;
512 * Wraps the call to XACMLPolicyWriter.
514 * @param path Path to file to be written to.
515 * @param policy PolicyType or PolicySetType
516 * @return Path - the same path passed in most likely from XACMLPolicyWriter. Or NULL if an error occurs.
518 public static Path writePolicyFile(Path path, Object policy) {
519 if (policy instanceof PolicyType) {
520 return XACMLPolicyWriter.writePolicyFile(path, (PolicyType) policy);
521 } else if (policy instanceof PolicySetType) {
522 return XACMLPolicyWriter.writePolicyFile(path, (PolicySetType) policy);
524 throw new IllegalArgumentException("Expecting PolicyType or PolicySetType");