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);
56 public static final String XACML_PROPERTY_FILE = "xacml.properties";
57 public static final String LINE_SEPARATOR = System.lineSeparator();
59 private static final String DOT_FILE_SUFFIX = ".file";
60 private static final String NOT_FOUND_MESSAGE = "NOT FOUND";
62 private XacmlPolicyUtils() {
67 * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
68 * will also be an empty Target created. You can easily override that if need be.
70 * @param policyId Policy Id
71 * @param policyCombiningAlgorithm Policy Combining Algorithm
72 * @return PolicySetType object
74 public static PolicySetType createEmptyPolicySet(String policyId, Identifier policyCombiningAlgorithm) {
75 PolicySetType policy = new PolicySetType();
76 policy.setPolicySetId(policyId);
77 policy.setPolicyCombiningAlgId(policyCombiningAlgorithm.stringValue());
78 policy.setTarget(new TargetType());
83 * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
84 * will also be an empty Target created. You can easily override that if need be.
86 * @param policyId Policy Id
87 * @param ruleCombiningAlgorithm Rule Combining Algorithm
88 * @return PolicyType object
90 public static PolicyType createEmptyPolicy(String policyId, Identifier ruleCombiningAlgorithm) {
91 PolicyType policy = new PolicyType();
92 policy.setPolicyId(policyId);
93 policy.setRuleCombiningAlgId(ruleCombiningAlgorithm.stringValue());
94 policy.setTarget(new TargetType());
99 * This method adds a list of PolicyType objects to a root PolicySetType as
100 * referenced policies.
102 * @param rootPolicy Root PolicySet being updated
103 * @param referencedPolicies A list of PolicyType being added as a references
104 * @return the rootPolicy PolicySet object
106 public static PolicySetType addPoliciesToXacmlRootPolicy(PolicySetType rootPolicy,
107 PolicyType... referencedPolicies) {
108 ObjectFactory factory = new ObjectFactory();
110 // Iterate each policy
112 for (PolicyType referencedPolicy : referencedPolicies) {
113 IdReferenceType reference = new IdReferenceType();
114 reference.setValue(referencedPolicy.getPolicyId());
118 rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicyIdReference(reference));
121 // Return the updated object
127 * This method updates a root PolicySetType by adding in a PolicyType as a reference.
129 * @param rootPolicy Root PolicySet being updated
130 * @param referencedPolicySets A list of PolicySetType being added as a references
131 * @return the rootPolicy PolicySet object
133 public static PolicySetType addPolicySetsToXacmlRootPolicy(PolicySetType rootPolicy,
134 PolicySetType... referencedPolicySets) {
135 ObjectFactory factory = new ObjectFactory();
137 // Iterate each policy
139 for (PolicySetType referencedPolicySet : referencedPolicySets) {
140 IdReferenceType reference = new IdReferenceType();
141 reference.setValue(referencedPolicySet.getPolicySetId());
145 rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicySetIdReference(reference));
148 // Return the updated object
154 * Adds in the root policy to the PDP properties object.
156 * @param properties Input properties
157 * @param rootPolicyPath Path to the root policy file
158 * @return Properties object
160 public static Properties addRootPolicy(Properties properties, Path rootPolicyPath) {
162 // Get the current set of referenced policy ids
164 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
166 // Construct a unique id
170 String refId = "root" + id;
171 if (rootPolicies.contains(refId)) {
174 rootPolicies.add(refId);
175 properties.put(refId + DOT_FILE_SUFFIX, rootPolicyPath.toAbsolutePath().toString());
180 // Set the new comma separated list
182 properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES,
183 rootPolicies.stream().collect(Collectors.joining(",")));
188 * Adds in the referenced policy to the PDP properties object.
190 * @param properties Input properties
191 * @param refPolicyPath Path to the referenced policy file
192 * @return Properties object
194 public static Properties addReferencedPolicy(Properties properties, Path refPolicyPath) {
196 // Get the current set of referenced policy ids
198 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
200 // Construct a unique id
204 String refId = "ref" + id;
205 if (referencedPolicies.contains(refId)) {
208 referencedPolicies.add(refId);
209 properties.put(refId + DOT_FILE_SUFFIX, refPolicyPath.toAbsolutePath().toString());
214 // Set the new comma separated list
216 properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES,
217 referencedPolicies.stream().collect(Collectors.joining(",")));
222 * Removes a root policy from the Properties object. Both in the line
223 * that identifies the policy and the .file property that points to the path.
225 * @param properties Input Properties object to remove
226 * @param rootPolicyPath The policy file path
227 * @return Properties object
229 public static Properties removeRootPolicy(Properties properties, Path rootPolicyPath) {
231 // Get the current set of referenced policy ids
233 StringJoiner join = new StringJoiner(",");
234 boolean found = false;
235 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
236 for (String refPolicy : rootPolicies) {
237 String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
239 // If the key and value match, then it will return true
241 if (properties.remove(refPolicyFile, rootPolicyPath.toString())) {
243 // Record that we actually removed it
258 // Now update the list of referenced properties
260 properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, join.toString());
266 * Removes a referenced policy from the Properties object. Both in the line
267 * that identifies the policy and the .file property that points to the path.
269 * @param properties Input Properties object to remove
270 * @param refPolicyPath The policy file path
271 * @return Properties object
273 public static Properties removeReferencedPolicy(Properties properties, Path refPolicyPath) {
275 // Get the current set of referenced policy ids
277 StringJoiner join = new StringJoiner(",");
278 boolean found = false;
279 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
280 for (String refPolicy : referencedPolicies) {
281 String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
283 // If the key and value match, then it will return true
285 if (properties.remove(refPolicyFile, refPolicyPath.toString())) {
287 // Record that we actually removed it
302 // Now update the list of referenced properties
304 properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, join.toString());
310 * Does a debug dump of referenced and root policy values.
312 * @param properties Input Properties object
313 * @param logger Logger object to use
315 public static void debugDumpPolicyProperties(Properties properties, Logger logger) {
317 // I hate surrounding this all with an if, but by
318 // doing so I clear sonar issues with passing System.lineSeparator()
321 if (logger.isDebugEnabled()) {
323 // Get the current set of referenced policy ids
325 Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
326 logger.debug("Root Policies: {}", properties.getProperty(XACMLProperties.PROP_ROOTPOLICIES));
327 for (String root : rootPolicies) {
328 logger.debug("{}", properties.getProperty(root + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
331 // Get the current set of referenced policy ids
333 Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
334 logger.debug("Referenced Policies: {}", properties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES));
335 for (String ref : referencedPolicies) {
336 logger.debug("{}", properties.getProperty(ref + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
342 * Constructs a unique policy filename for a given policy.
344 * <P>It could be dangerous to use policy-id and policy-version if the user
345 * gives us an invalid policy-id and policy-versions.
347 * <P>Should we append a UUID also to guarantee uniqueness?
349 * <P>How do we track that in case we need to know what policies we have loaded?
351 * @param policy PolicyType object
352 * @param path Path for policy
353 * @return Path unique file path for the Policy
355 public static Path constructUniquePolicyFilename(PolicyType policy, Path path) {
358 // Can it be possible to produce an invalid filename?
359 // Should we insert a UUID
361 String filename = policy.getPolicyId() + "_" + policy.getVersion() + ".xml";
363 // Construct the Path
365 return Paths.get(path.toAbsolutePath().toString(), filename);
369 * Load properties from given file.
371 * @throws IOException If unable to read file
373 public static Properties loadXacmlProperties(Path propertyPath) throws IOException {
374 LOGGER.info("Loading xacml properties {}", propertyPath);
375 try (InputStream is = Files.newInputStream(propertyPath)) {
376 Properties properties = new Properties();
378 if (LOGGER.isInfoEnabled()) {
379 LOGGER.info("Loaded xacml properties {} {}", XacmlPolicyUtils.LINE_SEPARATOR, properties);
380 for (Entry<Object, Object> entrySet : properties.entrySet()) {
381 LOGGER.info("{} -> {}", entrySet.getKey(), entrySet.getValue());
389 * Stores the XACML Properties to the given file location.
391 * @throws IOException If unable to store the file.
393 public static void storeXacmlProperties(Properties properties, Path propertyPath) throws IOException {
394 LOGGER.info("Storing xacml properties {} {} {}", properties, XacmlPolicyUtils.LINE_SEPARATOR, propertyPath);
395 try (OutputStream os = Files.newOutputStream(propertyPath)) {
396 String strComments = "#";
397 properties.store(os, strComments);
402 * Appends 'xacml.properties' to a root Path object
404 * @param rootPath Root Path object
405 * @return Path to rootPath/xacml.properties file
407 public static Path getPropertiesPath(Path rootPath) {
408 return Paths.get(rootPath.toAbsolutePath().toString(), XACML_PROPERTY_FILE);
412 public interface FileCreator {
413 public File createAFile(String filename) throws IOException;
418 * Copies a xacml.properties file to another location and all the policies defined within it.
420 * @param propertiesPath Path to an existing properties file
421 * @param properties Properties object
422 * @param creator A callback that can create files. Allows JUnit test to pass Temporary folder
423 * @return File object that points to new Properties file
424 * @throws IOException Could not read/write files
426 public static File copyXacmlPropertiesContents(String propertiesPath, Properties properties,
427 FileCreator creator) throws IOException {
429 // Open the properties file
431 try (InputStream is = new FileInputStream(propertiesPath)) {
433 // Load in the properties
437 // Now we create a new xacml.properties in the temporary folder location
439 File propertiesFile = creator.createAFile(XACML_PROPERTY_FILE);
441 // Iterate through any root policies defined
443 for (String root : XACMLProperties.getRootPolicyIDs(properties)) {
447 Path rootPath = Paths.get(properties.getProperty(root + DOT_FILE_SUFFIX));
448 LOGGER.info("Root file {} {}", rootPath, rootPath.getFileName());
450 // Construct new path for the root policy
452 File newRootPath = creator.createAFile(rootPath.getFileName().toString());
454 // Copy the policy file to the temporary folder
456 com.google.common.io.Files.copy(rootPath.toFile(), newRootPath);
458 // Change the properties object to point to where the new policy is
459 // in the temporary folder
461 properties.setProperty(root + DOT_FILE_SUFFIX, newRootPath.getAbsolutePath());
464 // Iterate through any referenced policies defined
466 for (String referenced : XACMLProperties.getReferencedPolicyIDs(properties)) {
470 Path refPath = Paths.get(properties.getProperty(referenced + DOT_FILE_SUFFIX));
471 LOGGER.info("Referenced file {} {}", refPath, refPath.getFileName());
473 // Construct new path for the root policy
475 File newReferencedPath = creator.createAFile(refPath.getFileName().toString());
477 // Copy the policy file to the temporary folder
479 com.google.common.io.Files.copy(refPath.toFile(), newReferencedPath);
481 // Change the properties object to point to where the new policy is
482 // in the temporary folder
484 properties.setProperty(referenced + DOT_FILE_SUFFIX, newReferencedPath.getAbsolutePath());
487 // Save the new properties file to the temporary folder
489 try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) {
490 properties.store(os, "");
493 // Return the new path to the properties folder
495 return propertiesFile;