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.std;
 
  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;
 
  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.HashMap;
 
  41 import java.util.List;
 
  43 import java.util.Properties;
 
  45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
 
  47 import org.apache.commons.lang3.tuple.Pair;
 
  48 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 
  49 import org.onap.policy.models.decisions.concepts.DecisionResponse;
 
  50 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 
  51 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
 
  52 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
 
  53 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
 
  54 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
 
  55 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
 
  56 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
 
  57 import org.slf4j.Logger;
 
  58 import org.slf4j.LoggerFactory;
 
  60 public abstract class StdXacmlApplicationServiceProvider implements XacmlApplicationServiceProvider {
 
  62     private static final Logger LOGGER = LoggerFactory.getLogger(StdXacmlApplicationServiceProvider.class);
 
  63     private Path pathForData = null;
 
  64     private Properties pdpProperties = null;
 
  65     private PDPEngine pdpEngine = null;
 
  66     private Map<ToscaPolicy, Path> mapLoadedPolicies = new HashMap<>();
 
  68     public StdXacmlApplicationServiceProvider() {
 
  73     public String applicationName() {
 
  74         return "Please Override";
 
  78     public List<String> actionDecisionsSupported() {
 
  79         return Collections.emptyList();
 
  83     public void initialize(Path pathForData) throws XacmlApplicationException {
 
  87         this.pathForData = pathForData;
 
  88         LOGGER.info("New Path is {}", this.pathForData.toAbsolutePath());
 
  90         // Ensure properties exist
 
  92         Path propertiesPath = XacmlPolicyUtils.getPropertiesPath(pathForData);
 
  93         if (! propertiesPath.toFile().exists()) {
 
  94             LOGGER.info("Copying src/main/resources/xacml.properties to path");
 
  96             // Properties do not exist, by default we will copy ours over
 
  97             // from src/main/resources
 
 100                 Files.copy(Paths.get("src/main/resources/xacml.properties"), propertiesPath);
 
 101             } catch (IOException e) {
 
 102                 throw new XacmlApplicationException("Failed to copy xacml.propertis", e);
 
 106         // Look for and load the properties object
 
 109             pdpProperties = XacmlPolicyUtils.loadXacmlProperties(XacmlPolicyUtils.getPropertiesPath(pathForData));
 
 110             LOGGER.debug("{}", pdpProperties);
 
 111         } catch (IOException e) {
 
 112             throw new XacmlApplicationException("Failed to load xacml.propertis", e);
 
 117         createEngine(pdpProperties);
 
 121     public List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
 
 122         throw new UnsupportedOperationException("Please override and implement supportedPolicyTypes");
 
 126     public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
 
 127         throw new UnsupportedOperationException("Please override and implement canSupportPolicyType");
 
 131     public synchronized boolean loadPolicy(ToscaPolicy toscaPolicy) {
 
 134             // Convert the policies first
 
 136             PolicyType xacmlPolicy = this.getTranslator(toscaPolicy.getType())
 
 137                 .convertPolicy(toscaPolicy);
 
 138             if (xacmlPolicy == null) {
 
 139                 throw new ToscaPolicyConversionException("Failed to convert policy");
 
 142             // Create a copy of the properties object
 
 144             Properties newProperties = this.getProperties();
 
 146             // Construct the filename
 
 148             Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(xacmlPolicy, this.getDataPath());
 
 150             // Write the policy to disk
 
 151             // Maybe check for an error
 
 153             XACMLPolicyWriter.writePolicyFile(refPath, xacmlPolicy);
 
 154             if (LOGGER.isDebugEnabled()) {
 
 155                 LOGGER.debug("Xacml Policy is {}{}", System.lineSeparator(), new String(Files.readAllBytes(refPath)));
 
 158             // Add root policy to properties object
 
 160             XacmlPolicyUtils.addRootPolicy(newProperties, refPath);
 
 162             // Write the properties to disk
 
 164             XacmlPolicyUtils.storeXacmlProperties(newProperties,
 
 165                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
 
 169             this.createEngine(newProperties);
 
 171             // Save the properties
 
 173             this.pdpProperties = newProperties;
 
 177             this.mapLoadedPolicies.put(toscaPolicy, refPath);
 
 178         } catch (IOException | ToscaPolicyConversionException e) {
 
 179             LOGGER.error("Failed to loadPolicies {}", e);
 
 186     public synchronized boolean unloadPolicy(ToscaPolicy toscaPolicy) throws XacmlApplicationException {
 
 188         // Find it in our map
 
 190         Path refPolicy = this.mapLoadedPolicies.get(toscaPolicy);
 
 191         if (refPolicy == null) {
 
 192             LOGGER.error("Failed to find ToscaPolicy {} in our map size {}", toscaPolicy.getMetadata(),
 
 193                     this.mapLoadedPolicies.size());
 
 197         // Create a copy of the properties object
 
 199         Properties newProperties = this.getProperties();
 
 201         // Remove it from the properties
 
 203         XacmlPolicyUtils.removeRootPolicy(newProperties, refPolicy);
 
 205         // We can delete the file
 
 208             Files.delete(refPolicy);
 
 209         } catch (IOException e) {
 
 210             LOGGER.error("Failed to delete policy {} from disk {}", toscaPolicy.getMetadata(),
 
 211                     refPolicy.toAbsolutePath().toString(), e);
 
 214         // Write the properties to disk
 
 217             XacmlPolicyUtils.storeXacmlProperties(newProperties,
 
 218                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
 
 219         } catch (IOException e) {
 
 220             LOGGER.error("Failed to save the properties to disk {}", newProperties);
 
 225         this.createEngine(newProperties);
 
 227         // Save the properties
 
 229         this.pdpProperties = newProperties;
 
 233         if (this.mapLoadedPolicies.remove(toscaPolicy) == null) {
 
 234             LOGGER.error("Failed to remove toscaPolicy {} from internal map size {}", toscaPolicy.getMetadata(),
 
 235                     this.mapLoadedPolicies.size());
 
 238         // Not sure if any of the errors above warrant returning false
 
 244     public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request) {
 
 246         // Convert to a XacmlRequest
 
 248         Request xacmlRequest = this.getTranslator().convertRequest(request);
 
 250         // Now get a decision
 
 252         Response xacmlResponse = this.xacmlDecision(xacmlRequest);
 
 254         // Convert to a DecisionResponse
 
 256         return Pair.of(this.getTranslator().convertResponse(xacmlResponse), xacmlResponse);
 
 259     protected abstract ToscaPolicyTranslator getTranslator(String type);
 
 261     protected ToscaPolicyTranslator getTranslator() {
 
 262         return this.getTranslator("");
 
 265     protected synchronized PDPEngine getEngine() {
 
 266         return this.pdpEngine;
 
 269     protected synchronized Properties getProperties() {
 
 270         Properties newProperties = new Properties();
 
 271         newProperties.putAll(pdpProperties);
 
 272         return newProperties;
 
 275     protected synchronized Path getDataPath() {
 
 280      * Load properties from given file.
 
 282      * @throws IOException If unable to read file
 
 284     protected synchronized Properties loadXacmlProperties() throws IOException {
 
 285         LOGGER.debug("Loading xacml properties {}", pathForData);
 
 286         try (InputStream is = Files.newInputStream(pathForData)) {
 
 287             Properties properties = new Properties();
 
 294      * Stores the XACML Properties to the given file location.
 
 296      * @throws IOException If unable to store the file.
 
 298     protected synchronized void storeXacmlProperties() throws IOException {
 
 299         try (OutputStream os = Files.newOutputStream(pathForData)) {
 
 300             String strComments = "#";
 
 301             pdpProperties.store(os, strComments);
 
 306      * Appends 'xacml.properties' to a root Path object
 
 308      * @return Path to rootPath/xacml.properties file
 
 310     protected synchronized Path getPropertiesPath() {
 
 311         return Paths.get(pathForData.toAbsolutePath().toString(), "xacml.properties");
 
 315      * Creates an instance of PDP engine given the Properties object.
 
 317     protected synchronized void createEngine(Properties properties) {
 
 319         // Now initialize the XACML PDP Engine
 
 322             PDPEngineFactory factory = PDPEngineFactory.newInstance();
 
 323             PDPEngine engine = factory.newEngine(properties);
 
 324             if (engine != null) {
 
 325                 this.pdpEngine = engine;
 
 327         } catch (FactoryException e) {
 
 328             LOGGER.error("Failed to create XACML PDP Engine {}", e);
 
 333      * Make a decision call.
 
 335      * @param request Incoming request object
 
 336      * @return Response object
 
 338     protected synchronized Response xacmlDecision(Request request) {
 
 340         // This is what we need to return
 
 342         Response response = null;
 
 346         long timeStart = System.currentTimeMillis();
 
 348             response = this.pdpEngine.decide(request);
 
 349         } catch (PDPException e) {
 
 350             LOGGER.error("Xacml PDP Engine failed {}", e);
 
 353             // Track the end of timing
 
 355             long timeEnd = System.currentTimeMillis();
 
 356             LOGGER.info("Elapsed Time: {}ms", (timeEnd - timeStart));