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;
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;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.IdReferenceType;
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 public class XacmlPolicyUtils {
52 private static final Logger LOGGER = LoggerFactory.getLogger(XacmlPolicyUtils.class);
54 public static final String XACML_PROPERTY_FILE = "xacml.properties";
55 public static final String LINE_SEPARATOR = System.lineSeparator();
57 private static final String DOT_FILE_SUFFIX = ".file";
58 private static final String NOT_FOUND_MESSAGE = "NOT FOUND";
60 private XacmlPolicyUtils() {
65 * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
66 * will also be an empty Target created. You can easily override that if need be.
68 * @param policyId Policy Id
69 * @param policyCombiningAlgorithm Policy Combining Algorithm
70 * @return PolicySetType object
72 public static PolicySetType createEmptyPolicySet(String policyId, Identifier policyCombiningAlgorithm) {
73 PolicySetType policy = new PolicySetType();
74 policy.setPolicySetId(policyId);
75 policy.setPolicyCombiningAlgId(policyCombiningAlgorithm.stringValue());
76 policy.setTarget(new TargetType());
81 * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
82 * will also be an empty Target created. You can easily override that if need be.
84 * @param policyId Policy Id
85 * @param ruleCombiningAlgorithm Rule Combining Algorithm
86 * @return PolicyType object
88 public static PolicyType createEmptyPolicy(String policyId, Identifier ruleCombiningAlgorithm) {
89 PolicyType policy = new PolicyType();
90 policy.setPolicyId(policyId);
91 policy.setRuleCombiningAlgId(ruleCombiningAlgorithm.stringValue());
92 policy.setTarget(new TargetType());
97 * This method adds a list of PolicyType objects to a root PolicySetType as
98 * referenced policies.
100 * @param rootPolicy Root PolicySet being updated
101 * @param referencedPolicies A list of PolicyType being added as a references
102 * @return the rootPolicy PolicySet object
104 public static PolicySetType addPoliciesToXacmlRootPolicy(PolicySetType rootPolicy,
105 PolicyType... referencedPolicies) {
106 ObjectFactory factory = new ObjectFactory();
108 // Iterate each policy
110 for (PolicyType referencedPolicy : referencedPolicies) {
111 IdReferenceType reference = new IdReferenceType();
112 reference.setValue(referencedPolicy.getPolicyId());
116 rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicyIdReference(reference));
119 // Return the updated object
125 * This method updates a root PolicySetType by adding in a PolicyType as a reference.
127 * @param rootPolicy Root PolicySet being updated
128 * @param referencedPolicySets A list of PolicySetType being added as a references
129 * @return the rootPolicy PolicySet object
131 public static PolicySetType addPolicySetsToXacmlRootPolicy(PolicySetType rootPolicy,
132 PolicySetType... referencedPolicySets) {
133 ObjectFactory factory = new ObjectFactory();
135 // Iterate each policy
137 for (PolicySetType referencedPolicySet : referencedPolicySets) {
138 IdReferenceType reference = new IdReferenceType();
139 reference.setValue(referencedPolicySet.getPolicySetId());
143 rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicySetIdReference(reference));
146 // Return the updated object
152 * Adds in the root policy to the PDP properties object.
154 * @param properties Input properties
155 * @param rootPolicyPath Path to the root policy file
156 * @return Properties object
158 public static Properties addRootPolicy(Properties properties, Path rootPolicyPath) {
160 // Get the current set of referenced policy ids
162 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
164 // Construct a unique id
168 String refId = "root" + id;
169 if (rootPolicies.contains(refId)) {
172 rootPolicies.add(refId);
173 properties.put(refId + DOT_FILE_SUFFIX, rootPolicyPath.toAbsolutePath().toString());
178 // Set the new comma separated list
180 properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES,
181 rootPolicies.stream().collect(Collectors.joining(",")));
186 * Adds in the referenced policy to the PDP properties object.
188 * @param properties Input properties
189 * @param refPolicyPath Path to the referenced policy file
190 * @return Properties object
192 public static Properties addReferencedPolicy(Properties properties, Path refPolicyPath) {
194 // Get the current set of referenced policy ids
196 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
198 // Construct a unique id
202 String refId = "ref" + id;
203 if (referencedPolicies.contains(refId)) {
206 referencedPolicies.add(refId);
207 properties.put(refId + DOT_FILE_SUFFIX, refPolicyPath.toAbsolutePath().toString());
212 // Set the new comma separated list
214 properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES,
215 referencedPolicies.stream().collect(Collectors.joining(",")));
220 * Removes a root policy from the Properties object. Both in the line
221 * that identifies the policy and the .file property that points to the path.
223 * @param properties Input Properties object to remove
224 * @param rootPolicyPath The policy file path
225 * @return Properties object
227 public static Properties removeRootPolicy(Properties properties, Path rootPolicyPath) {
229 // Get the current set of referenced policy ids
231 StringJoiner join = new StringJoiner(",");
232 boolean found = false;
233 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
234 for (String refPolicy : rootPolicies) {
235 String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
237 // If the key and value match, then it will return true
239 if (properties.remove(refPolicyFile, rootPolicyPath.toString())) {
241 // Record that we actually removed it
256 // Now update the list of referenced properties
258 properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, join.toString());
264 * Removes a referenced policy from the Properties object. Both in the line
265 * that identifies the policy and the .file property that points to the path.
267 * @param properties Input Properties object to remove
268 * @param refPolicyPath The policy file path
269 * @return Properties object
271 public static Properties removeReferencedPolicy(Properties properties, Path refPolicyPath) {
273 // Get the current set of referenced policy ids
275 StringJoiner join = new StringJoiner(",");
276 boolean found = false;
277 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
278 for (String refPolicy : referencedPolicies) {
279 String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
281 // If the key and value match, then it will return true
283 if (properties.remove(refPolicyFile, refPolicyPath.toString())) {
285 // Record that we actually removed it
300 // Now update the list of referenced properties
302 properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, join.toString());
308 * Does a debug dump of referenced and root policy values.
310 * @param properties Input Properties object
311 * @param logger Logger object to use
313 public static void debugDumpPolicyProperties(Properties properties, Logger logger) {
315 // I hate surrounding this all with an if, but by
316 // doing so I clear sonar issues with passing System.lineSeparator()
319 if (logger.isDebugEnabled()) {
321 // Get the current set of referenced policy ids
323 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
324 logger.debug("Root Policies: {}", properties.getProperty(XACMLProperties.PROP_ROOTPOLICIES));
325 for (String root : rootPolicies) {
326 logger.debug("{}", properties.getProperty(root + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
329 // Get the current set of referenced policy ids
331 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
332 logger.debug("Referenced Policies: {}", properties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES));
333 for (String ref : referencedPolicies) {
334 logger.debug("{}", properties.getProperty(ref + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
340 * Constructs a unique policy filename for a given policy.
342 * <P>It could be dangerous to use policy-id and policy-version if the user
343 * gives us an invalid policy-id and policy-versions.
345 * <P>Should we append a UUID also to guarantee uniqueness?
347 * <P>How do we track that in case we need to know what policies we have loaded?
349 * @param policy PolicyType object
350 * @param path Path for policy
351 * @return Path unique file path for the Policy
353 public static Path constructUniquePolicyFilename(Object policy, Path path) {
356 if (policy instanceof PolicyType) {
357 id = ((PolicyType) policy).getPolicyId();
358 version = ((PolicyType) policy).getVersion();
359 } else if (policy instanceof PolicySetType) {
360 id = ((PolicySetType) policy).getPolicySetId();
361 version = ((PolicySetType) policy).getVersion();
363 throw new IllegalArgumentException("Must pass a PolicyType or PolicySetType");
367 // Can it be possible to produce an invalid filename?
368 // Should we insert a UUID
370 String filename = id + "_" + version + ".xml";
372 // Construct the Path
374 return Paths.get(path.toAbsolutePath().toString(), filename);
378 * Load properties from given file.
380 * @throws IOException If unable to read file
382 public static Properties loadXacmlProperties(Path propertyPath) throws IOException {
383 LOGGER.info("Loading xacml properties {}", propertyPath);
384 try (InputStream is = Files.newInputStream(propertyPath)) {
385 Properties properties = new Properties();
387 if (LOGGER.isInfoEnabled()) {
388 LOGGER.info("Loaded xacml properties {} {}", XacmlPolicyUtils.LINE_SEPARATOR, properties);
389 for (Entry<Object, Object> entrySet : properties.entrySet()) {
390 LOGGER.info("{} -> {}", entrySet.getKey(), entrySet.getValue());
398 * Stores the XACML Properties to the given file location.
400 * @throws IOException If unable to store the file.
402 public static void storeXacmlProperties(Properties properties, Path propertyPath) throws IOException {
403 LOGGER.info("Storing xacml properties {} {} {}", properties, XacmlPolicyUtils.LINE_SEPARATOR, propertyPath);
404 try (OutputStream os = Files.newOutputStream(propertyPath)) {
405 String strComments = "#";
406 properties.store(os, strComments);
411 * Appends 'xacml.properties' to a root Path object
413 * @param rootPath Root Path object
414 * @return Path to rootPath/xacml.properties file
416 public static Path getPropertiesPath(Path rootPath) {
417 return Paths.get(rootPath.toAbsolutePath().toString(), XACML_PROPERTY_FILE);
421 public interface FileCreator {
422 public File createAFile(String filename) throws IOException;
427 * Copies a xacml.properties file to another location and all the policies defined within it.
429 * @param propertiesPath Path to an existing properties file
430 * @param properties Properties object
431 * @param creator A callback that can create files. Allows JUnit test to pass Temporary folder
432 * @return File object that points to new Properties file
433 * @throws IOException Could not read/write files
435 public static File copyXacmlPropertiesContents(String propertiesPath, Properties properties,
436 FileCreator creator) throws IOException {
438 // Open the properties file
440 try (InputStream is = new FileInputStream(propertiesPath)) {
442 // Load in the properties
446 // Now we create a new xacml.properties in the temporary folder location
448 File propertiesFile = creator.createAFile(XACML_PROPERTY_FILE);
450 // Iterate through any root policies defined
452 for (String root : XACMLProperties.getRootPolicyIDs(properties)) {
456 Path rootPath = Paths.get(properties.getProperty(root + DOT_FILE_SUFFIX));
457 LOGGER.info("Root file {} {}", rootPath, rootPath.getFileName());
459 // Construct new path for the root policy
461 File newRootPath = creator.createAFile(rootPath.getFileName().toString());
463 // Copy the policy file to the temporary folder
465 com.google.common.io.Files.copy(rootPath.toFile(), newRootPath);
467 // Change the properties object to point to where the new policy is
468 // in the temporary folder
470 properties.setProperty(root + DOT_FILE_SUFFIX, newRootPath.getAbsolutePath());
473 // Iterate through any referenced policies defined
475 for (String referenced : XACMLProperties.getReferencedPolicyIDs(properties)) {
479 Path refPath = Paths.get(properties.getProperty(referenced + DOT_FILE_SUFFIX));
480 LOGGER.info("Referenced file {} {}", refPath, refPath.getFileName());
482 // Construct new path for the root policy
484 File newReferencedPath = creator.createAFile(refPath.getFileName().toString());
486 // Copy the policy file to the temporary folder
488 com.google.common.io.Files.copy(refPath.toFile(), newReferencedPath);
490 // Change the properties object to point to where the new policy is
491 // in the temporary folder
493 properties.setProperty(referenced + DOT_FILE_SUFFIX, newReferencedPath.getAbsolutePath());
496 // Save the new properties file to the temporary folder
498 try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) {
499 properties.store(os, "");
502 // Return the new path to the properties folder
504 return propertiesFile;
509 * Wraps the call to XACMLPolicyWriter.
511 * @param path Path to file to be written to.
512 * @param policy PolicyType or PolicySetType
513 * @return Path - the same path passed in most likely from XACMLPolicyWriter. Or NULL if an error occurs.
515 public static Path writePolicyFile(Path path, Object policy) {
516 if (policy instanceof PolicyType) {
517 return XACMLPolicyWriter.writePolicyFile(path, (PolicyType) policy);
518 } else if (policy instanceof PolicySetType) {
519 return XACMLPolicyWriter.writePolicyFile(path, (PolicySetType) policy);
521 throw new IllegalArgumentException("Expecting PolicyType or PolicySetType");