7f85d2f09f7cd1d784b3631ccffae1f9ea998c50
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / std / StdXacmlApplicationServiceProvider.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.std;
24
25 import com.att.research.xacml.api.Request;
26 import com.att.research.xacml.api.Response;
27 import com.att.research.xacml.api.pdp.PDPEngine;
28 import com.att.research.xacml.api.pdp.PDPEngineFactory;
29 import com.att.research.xacml.api.pdp.PDPException;
30 import com.att.research.xacml.util.FactoryException;
31 import com.att.research.xacml.util.XACMLPolicyWriter;
32
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.nio.file.Paths;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Properties;
42
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
44
45 import org.onap.policy.models.decisions.concepts.DecisionRequest;
46 import org.onap.policy.models.decisions.concepts.DecisionResponse;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
49 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
50 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
51 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
52 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
53 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 public abstract class StdXacmlApplicationServiceProvider implements XacmlApplicationServiceProvider {
58
59     private static final Logger LOGGER = LoggerFactory.getLogger(StdXacmlApplicationServiceProvider.class);
60     private Path pathForData = null;
61     private Properties pdpProperties = null;
62     private PDPEngine pdpEngine = null;
63
64     public StdXacmlApplicationServiceProvider() {
65         super();
66     }
67
68     @Override
69     public String applicationName() {
70         return "Please Override";
71     }
72
73     @Override
74     public List<String> actionDecisionsSupported() {
75         return Collections.emptyList();
76     }
77
78     @Override
79     public void initialize(Path pathForData) throws XacmlApplicationException {
80         //
81         // Save our path
82         //
83         this.pathForData = pathForData;
84         LOGGER.info("New Path is {}", this.pathForData.toAbsolutePath());
85         //
86         // Ensure properties exist
87         //
88         Path propertiesPath = XacmlPolicyUtils.getPropertiesPath(pathForData);
89         if (! propertiesPath.toFile().exists()) {
90             LOGGER.info("Copying src/main/resources/xacml.properties to path");
91             //
92             // Properties do not exist, by default we will copy ours over
93             // from src/main/resources
94             //
95             try {
96                 Files.copy(Paths.get("src/main/resources/xacml.properties"), propertiesPath);
97             } catch (IOException e) {
98                 throw new XacmlApplicationException("Failed to copy xacml.propertis", e);
99             }
100         }
101         //
102         // Look for and load the properties object
103         //
104         try {
105             pdpProperties = XacmlPolicyUtils.loadXacmlProperties(XacmlPolicyUtils.getPropertiesPath(pathForData));
106             LOGGER.debug("{}", pdpProperties);
107         } catch (IOException e) {
108             throw new XacmlApplicationException("Failed to load xacml.propertis", e);
109         }
110         //
111         // Create an engine
112         //
113         createEngine(pdpProperties);
114     }
115
116     @Override
117     public List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
118         return Collections.emptyList();
119     }
120
121     @Override
122     public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
123         throw new UnsupportedOperationException("Please override and implement canSupportPolicyType");
124     }
125
126     @Override
127     public synchronized void loadPolicy(ToscaPolicy toscaPolicy) {
128         try {
129             //
130             // Convert the policies first
131             //
132             PolicyType xacmlPolicy = this.getTranslator().convertPolicy(toscaPolicy);
133             if (xacmlPolicy == null) {
134                 throw new ToscaPolicyConversionException("Failed to convert policy");
135             }
136             //
137             // Create a copy of the properties object
138             //
139             Properties newProperties = this.getProperties();
140             //
141             // Construct the filename
142             //
143             Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(xacmlPolicy, this.getDataPath());
144             //
145             // Write the policy to disk
146             // Maybe check for an error
147             //
148             XACMLPolicyWriter.writePolicyFile(refPath, xacmlPolicy);
149             if (LOGGER.isDebugEnabled()) {
150                 LOGGER.debug("Xacml Policy is {}{}", System.lineSeparator(), new String(Files.readAllBytes(refPath)));
151             }
152             //
153             // Add root policy to properties object
154             //
155             XacmlPolicyUtils.addRootPolicy(newProperties, refPath);
156             //
157             // Write the properties to disk
158             //
159             XacmlPolicyUtils.storeXacmlProperties(newProperties,
160                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
161             //
162             // Reload the engine
163             //
164             this.createEngine(newProperties);
165             //
166             // Save the properties
167             //
168             this.pdpProperties = newProperties;
169         } catch (IOException | ToscaPolicyConversionException e) {
170             LOGGER.error("Failed to loadPolicies {}", e);
171         }
172     }
173
174     @Override
175     public synchronized DecisionResponse makeDecision(DecisionRequest request) {
176         //
177         // Convert to a XacmlRequest
178         //
179         Request xacmlRequest = this.getTranslator().convertRequest(request);
180         //
181         // Now get a decision
182         //
183         Response xacmlResponse = this.xacmlDecision(xacmlRequest);
184         //
185         // Convert to a DecisionResponse
186         //
187         return this.getTranslator().convertResponse(xacmlResponse);
188     }
189
190
191     protected abstract ToscaPolicyTranslator getTranslator();
192
193     protected synchronized PDPEngine getEngine() {
194         return this.pdpEngine;
195     }
196
197     protected synchronized Properties getProperties() {
198         Properties newProperties = new Properties();
199         newProperties.putAll(pdpProperties);
200         return newProperties;
201     }
202
203     protected synchronized Path getDataPath() {
204         return pathForData;
205     }
206
207     /**
208      * Load properties from given file.
209      *
210      * @throws IOException If unable to read file
211      */
212     protected synchronized Properties loadXacmlProperties() throws IOException {
213         LOGGER.debug("Loading xacml properties {}", pathForData);
214         try (InputStream is = Files.newInputStream(pathForData)) {
215             Properties properties = new Properties();
216             properties.load(is);
217             return properties;
218         }
219     }
220
221     /**
222      * Stores the XACML Properties to the given file location.
223      *
224      * @throws IOException If unable to store the file.
225      */
226     protected synchronized void storeXacmlProperties() throws IOException {
227         try (OutputStream os = Files.newOutputStream(pathForData)) {
228             String strComments = "#";
229             pdpProperties.store(os, strComments);
230         }
231     }
232
233     /**
234      * Appends 'xacml.properties' to a root Path object
235      *
236      * @return Path to rootPath/xacml.properties file
237      */
238     protected synchronized Path getPropertiesPath() {
239         return Paths.get(pathForData.toAbsolutePath().toString(), "xacml.properties");
240     }
241
242     /**
243      * Creates an instance of PDP engine given the Properties object.
244      */
245     protected synchronized void createEngine(Properties properties) {
246         //
247         // Now initialize the XACML PDP Engine
248         //
249         try {
250             PDPEngineFactory factory = PDPEngineFactory.newInstance();
251             PDPEngine engine = factory.newEngine(properties);
252             if (engine != null) {
253                 this.pdpEngine = engine;
254 //                this.pdpProperties = new Properties(properties);
255             }
256         } catch (FactoryException e) {
257             LOGGER.error("Failed to create XACML PDP Engine {}", e);
258         }
259     }
260
261     /**
262      * Make a decision call.
263      *
264      * @param request Incoming request object
265      * @return Response object
266      */
267     protected synchronized Response xacmlDecision(Request request) {
268         //
269         // This is what we need to return
270         //
271         Response response = null;
272         //
273         // Track some timing
274         //
275         long timeStart = System.currentTimeMillis();
276         try {
277             response = this.pdpEngine.decide(request);
278         } catch (PDPException e) {
279             LOGGER.error("Xacml PDP Engine failed {}", e);
280         } finally {
281             //
282             // Track the end of timing
283             //
284             long timeEnd = System.currentTimeMillis();
285             LOGGER.info("Elapsed Time: {}ms", (timeEnd - timeStart));
286         }
287         return response;
288     }
289
290 }