2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2021 Nordix Foundation.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
20 * SPDX-License-Identifier: Apache-2.0
21 * ============LICENSE_END=========================================================
24 package org.onap.policy.pdp.xacml.application.common.std;
26 import com.att.research.xacml.api.Request;
27 import com.att.research.xacml.api.Response;
28 import com.att.research.xacml.api.pdp.PDPEngine;
29 import com.att.research.xacml.api.pdp.PDPEngineFactory;
30 import com.att.research.xacml.api.pdp.PDPException;
31 import com.att.research.xacml.util.FactoryException;
32 import java.io.IOException;
33 import java.nio.charset.StandardCharsets;
34 import java.nio.file.Files;
35 import java.nio.file.Path;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.HashMap;
39 import java.util.List;
41 import java.util.Properties;
43 import org.apache.commons.lang3.tuple.Pair;
44 import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
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.ToscaConceptIdentifier;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
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;
57 public abstract class StdXacmlApplicationServiceProvider implements XacmlApplicationServiceProvider {
59 private static final Logger LOGGER = LoggerFactory.getLogger(StdXacmlApplicationServiceProvider.class);
61 protected String applicationName = "Please Override";
62 protected List<String> actions = Collections.emptyList();
63 protected List<ToscaConceptIdentifier> supportedPolicyTypes = new ArrayList<>();
65 private Path pathForData = null;
67 private BusTopicParams policyApiParameters;
68 private Properties pdpProperties = null;
69 private PDPEngine pdpEngine = null;
70 private Map<ToscaPolicy, Path> mapLoadedPolicies = new HashMap<>();
72 protected StdXacmlApplicationServiceProvider() {
77 public String applicationName() {
78 return applicationName;
82 public List<String> actionDecisionsSupported() {
87 public void initialize(Path pathForData, BusTopicParams policyApiParameters)
88 throws XacmlApplicationException {
92 this.pathForData = pathForData;
93 LOGGER.info("New Path is {}", this.pathForData.toAbsolutePath());
97 this.policyApiParameters = policyApiParameters;
99 // Look for and load the properties object
102 pdpProperties = XacmlPolicyUtils.loadXacmlProperties(XacmlPolicyUtils.getPropertiesPath(pathForData));
103 LOGGER.info("{}", pdpProperties);
104 } catch (IOException e) {
105 throw new XacmlApplicationException("Failed to load " + XacmlPolicyUtils.XACML_PROPERTY_FILE, e);
110 createEngine(pdpProperties);
114 public List<ToscaConceptIdentifier> supportedPolicyTypes() {
115 return supportedPolicyTypes;
119 public boolean canSupportPolicyType(ToscaConceptIdentifier policyTypeId) {
120 throw new UnsupportedOperationException("Please override and implement canSupportPolicyType");
124 public synchronized void loadPolicy(ToscaPolicy toscaPolicy) throws XacmlApplicationException {
127 // Convert the policies first
129 Object xacmlPolicy = this.getTranslator(toscaPolicy.getType()).convertPolicy(toscaPolicy);
130 if (xacmlPolicy == null) {
131 throw new ToscaPolicyConversionException("Failed to convert policy");
134 // Create a copy of the properties object
136 Properties newProperties = this.getProperties();
138 // Construct the filename
140 Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(xacmlPolicy, this.getDataPath());
142 // Write the policy to disk
143 // Maybe check for an error
145 if (XacmlPolicyUtils.writePolicyFile(refPath, xacmlPolicy) == null) {
146 throw new ToscaPolicyConversionException("Unable to writePolicyFile");
148 if (LOGGER.isInfoEnabled()) {
149 LOGGER.info("Xacml Policy is {}{}", XacmlPolicyUtils.LINE_SEPARATOR,
150 new String(Files.readAllBytes(refPath), StandardCharsets.UTF_8));
153 // Add root policy to properties object
155 XacmlPolicyUtils.addRootPolicy(newProperties, refPath);
157 // Write the properties to disk
159 XacmlPolicyUtils.storeXacmlProperties(newProperties,
160 XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
164 this.createEngine(newProperties);
166 // Save the properties
168 this.pdpProperties = newProperties;
172 this.mapLoadedPolicies.put(toscaPolicy, refPath);
173 } catch (IOException | ToscaPolicyConversionException e) {
174 throw new XacmlApplicationException("loadPolicy failed", e);
179 public synchronized boolean unloadPolicy(ToscaPolicy toscaPolicy) throws XacmlApplicationException {
181 // Find it in our map
183 Path refPolicy = this.mapLoadedPolicies.get(toscaPolicy);
184 if (refPolicy == null) {
185 LOGGER.error("Failed to find ToscaPolicy {} in our map size {}", toscaPolicy.getMetadata(),
186 this.mapLoadedPolicies.size());
190 // Create a copy of the properties object
192 Properties newProperties = this.getProperties();
194 // Remove it from the properties
196 XacmlPolicyUtils.removeRootPolicy(newProperties, refPolicy);
198 // We can delete the file
201 Files.delete(refPolicy);
202 } catch (IOException e) {
203 LOGGER.error("Failed to delete policy {} from disk {}", toscaPolicy.getMetadata(),
204 refPolicy.toAbsolutePath(), e);
207 // Write the properties to disk
210 XacmlPolicyUtils.storeXacmlProperties(newProperties,
211 XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
212 } catch (IOException e) {
213 LOGGER.error("Failed to save the properties to disk {}", newProperties, e);
218 this.createEngine(newProperties);
220 // Save the properties
222 this.pdpProperties = newProperties;
226 if (this.mapLoadedPolicies.remove(toscaPolicy) == null) {
227 LOGGER.error("Failed to remove toscaPolicy {} from internal map size {}", toscaPolicy.getMetadata(),
228 this.mapLoadedPolicies.size());
231 // Not sure if any of the errors above warrant returning false
237 public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request,
238 Map<String, String[]> requestQueryParams) {
240 // Convert to a XacmlRequest
242 Request xacmlRequest;
244 xacmlRequest = this.getTranslator().convertRequest(request);
245 } catch (ToscaPolicyConversionException e) {
246 LOGGER.error("Failed to convert request", e);
247 DecisionResponse response = new DecisionResponse();
248 response.setStatus("error");
249 response.setMessage(e.getLocalizedMessage());
250 return Pair.of(response, null);
253 // Now get a decision
255 Response xacmlResponse = this.xacmlDecision(xacmlRequest);
257 // Convert to a DecisionResponse
259 return Pair.of(this.getTranslator().convertResponse(xacmlResponse), xacmlResponse);
262 protected abstract ToscaPolicyTranslator getTranslator(String type);
264 protected ToscaPolicyTranslator getTranslator() {
265 return this.getTranslator("");
268 protected synchronized PDPEngine getEngine() {
269 return this.pdpEngine;
272 protected synchronized Properties getProperties() {
273 Properties newProperties = new Properties();
274 newProperties.putAll(pdpProperties);
275 return newProperties;
278 protected synchronized Path getDataPath() {
283 * Creates an instance of PDP engine given the Properties object.
285 protected synchronized void createEngine(Properties properties) {
287 // Now initialize the XACML PDP Engine
290 PDPEngineFactory factory = getPdpEngineFactory();
291 PDPEngine engine = factory.newEngine(properties);
292 if (engine != null) {
294 // If there is a previous engine have it shutdown.
296 this.destroyEngine();
300 this.pdpEngine = engine;
302 } catch (FactoryException e) {
303 LOGGER.error("Failed to create XACML PDP Engine", e);
307 protected synchronized void destroyEngine() {
308 if (this.pdpEngine == null) {
312 this.pdpEngine.shutdown();
313 } catch (Exception e) {
314 LOGGER.warn("Exception thrown when destroying XACML PDP engine.", e);
316 this.pdpEngine = null;
320 * Make a decision call.
322 * @param request Incoming request object
323 * @return Response object
325 protected synchronized Response xacmlDecision(Request request) {
327 // This is what we need to return
329 Response response = null;
333 long timeStart = System.currentTimeMillis();
335 response = this.pdpEngine.decide(request);
336 } catch (PDPException e) {
337 LOGGER.error("Xacml PDP Engine decide failed", e);
340 // Track the end of timing
342 long timeEnd = System.currentTimeMillis();
343 LOGGER.info("Elapsed Time: {}ms", (timeEnd - timeStart));
348 // these may be overridden by junit tests
350 protected PDPEngineFactory getPdpEngineFactory() throws FactoryException {
351 return PDPEngineFactory.newInstance();