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