ca327b904b1548220bb0ec198817481938daaa8d
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / XacmlPolicyUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.pdp.xacml.application.common;
24
25 import com.att.research.xacml.api.Identifier;
26 import com.att.research.xacml.api.pdp.PDPEngine;
27 import com.att.research.xacml.api.pdp.PDPEngineFactory;
28 import com.att.research.xacml.util.FactoryException;
29 import com.att.research.xacml.util.XACMLProperties;
30
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.Properties;
38 import java.util.Set;
39 import java.util.StringJoiner;
40 import java.util.stream.Collectors;
41
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
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 public class XacmlPolicyUtils {
52
53     private static final Logger LOGGER = LoggerFactory.getLogger(XacmlPolicyUtils.class);
54     private static final String DOT_FILE_SUFFIX = ".file";
55     private static final String NOT_FOUND_MESSAGE = "NOT FOUND";
56
57     private XacmlPolicyUtils() {
58         super();
59     }
60
61     /**
62      * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
63      * will also be an empty Target created. You can easily override that if need be.
64      *
65      * @param policyId Policy Id
66      * @param policyCombiningAlgorithm Policy Combining Algorithm
67      * @return PolicySetType object
68      */
69     public static PolicySetType createEmptyPolicySet(String policyId, Identifier policyCombiningAlgorithm) {
70         PolicySetType policy = new PolicySetType();
71         policy.setPolicySetId(policyId);
72         policy.setPolicyCombiningAlgId(policyCombiningAlgorithm.stringValue());
73         policy.setTarget(new TargetType());
74         return policy;
75     }
76
77     /**
78      * Creates an empty PolicySetType object given the id and combining algorithm. Note,there
79      * will also be an empty Target created. You can easily override that if need be.
80      *
81      * @param policyId Policy Id
82      * @param ruleCombiningAlgorithm Rule Combining Algorithm
83      * @return PolicyType object
84      */
85     public static PolicyType createEmptyPolicy(String policyId, Identifier ruleCombiningAlgorithm) {
86         PolicyType policy = new PolicyType();
87         policy.setPolicyId(policyId);
88         policy.setRuleCombiningAlgId(ruleCombiningAlgorithm.stringValue());
89         policy.setTarget(new TargetType());
90         return policy;
91     }
92
93     /**
94      * This method adds a list of PolicyType objects to a root PolicySetType as
95      * referenced policies.
96      *
97      * @param rootPolicy Root PolicySet being updated
98      * @param referencedPolicies A list of PolicyType being added as a references
99      * @return the rootPolicy PolicySet object
100      */
101     public static PolicySetType addPoliciesToXacmlRootPolicy(PolicySetType rootPolicy,
102             PolicyType... referencedPolicies) {
103         ObjectFactory factory = new ObjectFactory();
104         //
105         // Iterate each policy
106         //
107         for (PolicyType referencedPolicy : referencedPolicies) {
108             IdReferenceType reference = new IdReferenceType();
109             reference.setValue(referencedPolicy.getPolicyId());
110             //
111             // Add it in
112             //
113             rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicyIdReference(reference));
114         }
115         //
116         // Return the updated object
117         //
118         return rootPolicy;
119     }
120
121     /**
122      * This method updates a root PolicySetType by adding in a PolicyType as a reference.
123      *
124      * @param rootPolicy Root PolicySet being updated
125      * @param referencedPolicySets A list of PolicySetType being added as a references
126      * @return the rootPolicy PolicySet object
127      */
128     public static PolicySetType addPolicySetsToXacmlRootPolicy(PolicySetType rootPolicy,
129             PolicySetType... referencedPolicySets) {
130         ObjectFactory factory = new ObjectFactory();
131         //
132         // Iterate each policy
133         //
134         for (PolicySetType referencedPolicySet : referencedPolicySets) {
135             IdReferenceType reference = new IdReferenceType();
136             reference.setValue(referencedPolicySet.getPolicySetId());
137             //
138             // Add it in
139             //
140             rootPolicy.getPolicySetOrPolicyOrPolicySetIdReference().add(factory.createPolicySetIdReference(reference));
141         }
142         //
143         // Return the updated object
144         //
145         return rootPolicy;
146     }
147
148     /**
149      * Adds in the referenced policy to the PDP properties object.
150      *
151      * @param properties Input properties
152      * @param refPolicyPath Path to the referenced policy file
153      * @return Properties object
154      */
155     public static Properties addReferencedPolicy(Properties properties, Path refPolicyPath) {
156         //
157         // Get the current set of referenced policy ids
158         //
159         Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
160         //
161         // Construct a unique id
162         //
163         int id = 1;
164         while (true) {
165             String refId = "ref" + id;
166             if (referencedPolicies.contains(refId)) {
167                 id++;
168             } else {
169                 referencedPolicies.add(refId);
170                 properties.put(refId + DOT_FILE_SUFFIX, refPolicyPath.toAbsolutePath().toString());
171                 break;
172             }
173         }
174         //
175         // Set the new comma separated list
176         //
177         properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES,
178                 referencedPolicies.stream().collect(Collectors.joining(",")));
179         return properties;
180     }
181
182     /**
183      * Removes a referenced policy from the Properties object. Both in the line
184      * that identifies the policy and the .file property that points to the path.
185      *
186      * @param properties Input Properties object to remove
187      * @param refPolicyPath The policy file path
188      * @return Properties object
189      */
190     public static Properties removeReferencedPolicy(Properties properties, Path refPolicyPath) {
191         //
192         // Get the current set of referenced policy ids
193         //
194         StringJoiner join = new StringJoiner(",");
195         boolean found = false;
196         Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
197         for (String refPolicy : referencedPolicies) {
198             String refPolicyFile = refPolicy + DOT_FILE_SUFFIX;
199             //
200             // If the key and value match, then it will return true
201             //
202             if (properties.remove(refPolicyFile, refPolicyPath.toString())) {
203                 //
204                 // Record that we actually removed it
205                 //
206                 found = true;
207             } else {
208                 //
209                 // Retain it
210                 //
211                 join.add(refPolicy);
212             }
213         }
214         //
215         // Did we remove it?
216         //
217         if (found) {
218             //
219             // Now update the list of referenced properties
220             //
221             properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, join.toString());
222         }
223         return properties;
224     }
225
226     /**
227      * Does a debug dump of referenced and root policy values.
228      *
229      * @param properties Input Properties object
230      * @param logger Logger object to use
231      */
232     public static void debugDumpPolicyProperties(Properties properties, Logger logger) {
233         //
234         // I hate surrounding this all with an if, but by
235         // doing so I clear sonar issues with passing System.lineSeparator()
236         // as an argument.
237         //
238         if (logger.isDebugEnabled()) {
239             //
240             // Get the current set of referenced policy ids
241             //
242             Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
243             logger.debug("Root Policies: {}", properties.getProperty(XACMLProperties.PROP_ROOTPOLICIES));
244             for (String root : rootPolicies) {
245                 logger.debug("{}", properties.getProperty(root + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
246             }
247             //
248             // Get the current set of referenced policy ids
249             //
250             Set<String> referencedPolicies = XACMLProperties.getReferencedPolicyIDs(properties);
251             logger.debug("Referenced Policies: {}", properties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES));
252             for (String ref : referencedPolicies) {
253                 logger.debug("{}", properties.getProperty(ref + DOT_FILE_SUFFIX, NOT_FOUND_MESSAGE));
254             }
255         }
256     }
257
258     /**
259      * Constructs a unique policy filename for a given policy.
260      *
261      * <P>It could be dangerous to use policy-id and policy-version if the user
262      * gives us an invalid policy-id and policy-versions.
263      *
264      * <P>Should we append a UUID also to guarantee uniqueness?
265      *
266      * <P>How do we track that in case we need to know what policies we have loaded?
267      *
268      * @param policy PolicyType object
269      * @param path Path for policy
270      * @return Path unique file path for the Policy
271      */
272     public static Path constructUniquePolicyFilename(PolicyType policy, Path path) {
273         //
274         //
275         // Can it be possible to produce an invalid filename?
276         // Should we insert a UUID
277         //
278         String filename = policy.getPolicyId() + "_" + policy.getVersion() + ".xml";
279         //
280         // Construct the Path
281         //
282         return Paths.get(path.toAbsolutePath().toString(), filename);
283     }
284
285     /**
286      * Load properties from given file.
287      *
288      * @throws IOException If unable to read file
289      */
290     public static Properties loadXacmlProperties(Path propertyPath) throws IOException {
291         LOGGER.debug("Loading xacml properties {}", propertyPath);
292         try (InputStream is = Files.newInputStream(propertyPath)) {
293             Properties properties = new Properties();
294             properties.load(is);
295             return properties;
296         }
297     }
298
299     /**
300      * Stores the XACML Properties to the given file location.
301      *
302      * @throws IOException If unable to store the file.
303      */
304     public static void storeXacmlProperties(Properties properties, Path propertyPath) throws IOException {
305         try (OutputStream os = Files.newOutputStream(propertyPath)) {
306             String strComments = "#";
307             properties.store(os, strComments);
308         }
309     }
310
311     /**
312      * Appends 'xacml.properties' to a root Path object
313      *
314      * @param rootPath Root Path object
315      * @return Path to rootPath/xacml.properties file
316      */
317     public static Path getPropertiesPath(Path rootPath) {
318         return Paths.get(rootPath.toAbsolutePath().toString(), "xacml.properties");
319     }
320
321
322     /**
323      * Creates an instance of PDP engine given the Properties object.
324      *
325      * @param properties Incoming Properties object
326      * @return PDPEngine instance or null if failed
327      */
328     public static PDPEngine createEngine(Properties properties) {
329         //
330         // Now initialize the XACML PDP Engine
331         //
332         try {
333             PDPEngineFactory factory = PDPEngineFactory.newInstance();
334             return factory.newEngine(properties);
335         } catch (FactoryException e) {
336             LOGGER.error("Failed to create XACML PDP Engine {}", e);
337         }
338         return null;
339     }
340 }