From 2c847e0855b316c162c9fd31456fdf8e338a5dba Mon Sep 17 00:00:00 2001 From: Pamela Dragosh Date: Fri, 22 Mar 2019 14:12:52 -0400 Subject: Adding optimization application finish guard Created Optimization application and created a translator for it. The translator makes an assumption that OOF wants to query on policyScope and policyType properties. Rearranged some of the test code for re-usability. Guard policies are now creating for frequency limiter and min max. Probably could use some clean up. Upgraded to xacml 2.0.1 to include a fix for handling null attribute values. Added some code to test missing values. Issue-ID: POLICY-1273 Change-Id: Ia3dbfa992bbe0cbb5aa294c38aa2aff430a3230a Signed-off-by: Pamela Dragosh --- .../common/OnapPolicyFinderFactory.java | 53 ++- .../xacml/application/common/ToscaDictionary.java | 64 ++++ .../xacml/application/common/XacmlPolicyUtils.java | 129 ++++++- .../common/std/StdCombinedPolicyRequest.java | 87 +++-- .../std/StdCombinedPolicyResultsTranslator.java | 75 ++-- .../common/std/StdMatchablePolicyRequest.java | 141 ++++++++ .../common/std/StdMatchableTranslator.java | 400 +++++++++++++++++++++ .../common/std/StdMetadataTranslator.java | 110 ------ 8 files changed, 880 insertions(+), 179 deletions(-) create mode 100644 applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java create mode 100644 applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java delete mode 100644 applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java (limited to 'applications/common/src') diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java index 7da455c0..66352010 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java @@ -20,16 +20,24 @@ package org.onap.policy.pdp.xacml.application.common; +import com.att.research.xacml.std.IdentifierImpl; import com.att.research.xacml.std.StdStatusCode; +import com.att.research.xacml.std.StdVersion; import com.att.research.xacml.std.dom.DOMStructureException; import com.att.research.xacml.util.FactoryException; import com.att.research.xacml.util.XACMLProperties; +import com.att.research.xacmlatt.pdp.policy.CombiningAlgorithm; +import com.att.research.xacmlatt.pdp.policy.CombiningAlgorithmFactory; import com.att.research.xacmlatt.pdp.policy.Policy; import com.att.research.xacmlatt.pdp.policy.PolicyDef; import com.att.research.xacmlatt.pdp.policy.PolicyFinder; import com.att.research.xacmlatt.pdp.policy.PolicyFinderFactory; +import com.att.research.xacmlatt.pdp.policy.PolicySet; +import com.att.research.xacmlatt.pdp.policy.PolicySetChild; +import com.att.research.xacmlatt.pdp.policy.Target; import com.att.research.xacmlatt.pdp.policy.dom.DOMPolicyDef; import com.att.research.xacmlatt.pdp.std.StdPolicyFinder; +import com.att.research.xacmlatt.pdp.util.ATTPDPProperties; import com.google.common.base.Splitter; import com.google.common.base.Strings; @@ -43,6 +51,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; +import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -212,7 +221,49 @@ public class OnapPolicyFinderFactory extends PolicyFinderFactory { protected synchronized void init() { if (this.needsInit) { logger.debug("Initializing OnapPolicyFinderFactory Properties "); - this.rootPolicies = this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES); + + // + // Check for property that combines root policies into one policyset + // + String combiningAlgorithm = properties.getProperty( + ATTPDPProperties.PROP_POLICYFINDERFACTORY_COMBINEROOTPOLICIES); + if (combiningAlgorithm != null) { + try { + logger.info("Combining root policies with {}", combiningAlgorithm); + // + // Find the combining algorithm + // + CombiningAlgorithm algorithm = CombiningAlgorithmFactory.newInstance() + .getPolicyCombiningAlgorithm(new IdentifierImpl(combiningAlgorithm)); + // + // Create our root policy + // + PolicySet root = new PolicySet(); + root.setIdentifier(new IdentifierImpl(UUID.randomUUID().toString())); + root.setVersion(StdVersion.newInstance("1.0")); + root.setTarget(new Target()); + // + // Set the algorithm + // + root.setPolicyCombiningAlgorithm(algorithm); + // + // Load all our root policies + // + for (PolicyDef policy : this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES)) { + root.addChild(policy); + } + // + // Set this policy as the root + // + this.rootPolicies = new ArrayList<>(); + this.rootPolicies.add(root); + } catch (Exception e) { + logger.error("Failed to load Combining Algorithm Factory: {}", e.getLocalizedMessage()); + } + } else { + logger.info("Loading root policies"); + this.rootPolicies = this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES); + } this.referencedPolicies = this.getPolicyDefs(XACMLProperties.PROP_REFERENCEDPOLICIES); logger.debug("Root Policies: {}", this.rootPolicies.size()); logger.debug("Referenced Policies: {}", this.referencedPolicies.size()); diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java index 352e51d8..0dcafa00 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java @@ -43,6 +43,68 @@ public final class ToscaDictionary { public static final Identifier ID_RESOURCE_POLICY_TYPE_VERSION = new IdentifierImpl(URN_ONAP, "policy-type-version"); + /* + * These ID's are for identifying Subjects + */ + + public static final Identifier ID_SUBJECT_ONAP_NAME = + XACML3.ID_SUBJECT_SUBJECT_ID; + + public static final Identifier ID_SUBJECT_ONAP_COMPONENT = + new IdentifierImpl(URN_ONAP, "onap-component"); + + public static final Identifier ID_SUBJECT_ONAP_INSTANCE = + new IdentifierImpl(URN_ONAP, "onap-instance"); + + /* + * These 2 ID's are for Optimization policies + */ + + public static final Identifier ID_RESOURCE_POLICY_SCOPE_PROPERTY = + new IdentifierImpl(URN_ONAP, "policy-scope-property"); + + public static final Identifier ID_RESOURCE_POLICY_TYPE_PROPERTY = + new IdentifierImpl(URN_ONAP, "policy-type-property"); + + /* + * These ID's are for Legacy Guard Policies + */ + public static final Identifier ID_RESOURCE_GUARD_ACTOR = + new IdentifierImpl(URN_ONAP, "guard:actor:actor-id"); + public static final Identifier ID_RESOURCE_GUARD_RECIPE = + new IdentifierImpl(URN_ONAP, "guard:operation:operation-id"); + public static final Identifier ID_RESOURCE_GUARD_CLNAME = + new IdentifierImpl(URN_ONAP, "guard:clname:clname-id"); + public static final Identifier ID_RESOURCE_GUARD_TARGETID = + new IdentifierImpl(URN_ONAP, "guard:target:target-id"); + public static final Identifier ID_SUBJECT_GUARD_REQUESTID = + new IdentifierImpl(URN_ONAP, "guard:request:request-id"); + public static final Identifier ID_RESOURCE_GUARD_VFCOUNT = + new IdentifierImpl(URN_ONAP, "guard:target:vf-count"); + public static final Identifier ID_RESOURCE_GUARD_MIN = + new IdentifierImpl(URN_ONAP, "guard:target:min"); + public static final Identifier ID_RESOURCE_GUARD_MAX = + new IdentifierImpl(URN_ONAP, "guard:target:max"); + + /* + * This id specifically for guard is provided by the + * operational history database PIP. + */ + public static final Identifier ID_RESOURCE_GUARD_OPERATIONCOUNT = + new IdentifierImpl(URN_ONAP, "guard:operation:operation-count"); + + /* + * This id is specifically for advice returned from guard + */ + public static final Identifier ID_ADVICE_GUARD = + new IdentifierImpl(URN_ONAP, "guard:advice"); + public static final Identifier ID_ADVICE_GUARD_REQUESTID = + new IdentifierImpl(URN_ONAP, "guard:advice:request-id"); + + /* + * Obligation specific ID's + */ + public static final Identifier ID_OBLIGATION_REST_BODY = new IdentifierImpl(URN_ONAP, "rest:body"); @@ -61,6 +123,8 @@ public final class ToscaDictionary { public static final Identifier ID_OBLIGATION_MONITORING_ISSUER = new IdentifierImpl(URN_ONAP, "issuer:monitoring"); + + private ToscaDictionary() { super(); } diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java index ca327b90..46742af9 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java @@ -23,11 +23,11 @@ package org.onap.policy.pdp.xacml.application.common; import com.att.research.xacml.api.Identifier; -import com.att.research.xacml.api.pdp.PDPEngine; -import com.att.research.xacml.api.pdp.PDPEngineFactory; -import com.att.research.xacml.util.FactoryException; import com.att.research.xacml.util.XACMLProperties; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -145,6 +145,40 @@ public class XacmlPolicyUtils { return rootPolicy; } + /** + * Adds in the root policy to the PDP properties object. + * + * @param properties Input properties + * @param rootPolicyPath Path to the root policy file + * @return Properties object + */ + public static Properties addRootPolicy(Properties properties, Path rootPolicyPath) { + // + // Get the current set of referenced policy ids + // + Set rootPolicies = XACMLProperties.getRootPolicyIDs(properties); + // + // Construct a unique id + // + int id = 1; + while (true) { + String refId = "ref" + id; + if (rootPolicies.contains(refId)) { + id++; + } else { + rootPolicies.add(refId); + properties.put(refId + DOT_FILE_SUFFIX, rootPolicyPath.toAbsolutePath().toString()); + break; + } + } + // + // Set the new comma separated list + // + properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, + rootPolicies.stream().collect(Collectors.joining(","))); + return properties; + } + /** * Adds in the referenced policy to the PDP properties object. * @@ -318,23 +352,90 @@ public class XacmlPolicyUtils { return Paths.get(rootPath.toAbsolutePath().toString(), "xacml.properties"); } + public interface FileCreator { + public File createAFile(String filename) throws IOException; + + } /** - * Creates an instance of PDP engine given the Properties object. + * Copies a xacml.properties file to another location and all the policies defined within it. * - * @param properties Incoming Properties object - * @return PDPEngine instance or null if failed + * @param propertiesPath Path to an existing properties file + * @param properties Properties object + * @param creator A callback that can create files. Allows JUnit test to pass Temporary folder + * @return File object that points to new Properties file + * @throws IOException Could not read/write files */ - public static PDPEngine createEngine(Properties properties) { + public static File copyXacmlPropertiesContents(String propertiesPath, Properties properties, + FileCreator creator) throws IOException { // - // Now initialize the XACML PDP Engine + // Open the properties file // - try { - PDPEngineFactory factory = PDPEngineFactory.newInstance(); - return factory.newEngine(properties); - } catch (FactoryException e) { - LOGGER.error("Failed to create XACML PDP Engine {}", e); + try (InputStream is = new FileInputStream(propertiesPath)) { + // + // Load in the properties + // + properties.load(is); + // + // Now we create a new xacml.properties in the temporary folder location + // + File propertiesFile = creator.createAFile("xacml.properties"); + // + // Iterate through any root policies defined + // + for (String root : XACMLProperties.getRootPolicyIDs(properties)) { + // + // Get a file + // + Path rootPath = Paths.get(properties.getProperty(root + DOT_FILE_SUFFIX)); + LOGGER.debug("Root file {} {}", rootPath, rootPath.getFileName()); + // + // Construct new path for the root policy + // + File newRootPath = creator.createAFile(rootPath.getFileName().toString()); + // + // Copy the policy file to the temporary folder + // + com.google.common.io.Files.copy(rootPath.toFile(), newRootPath); + // + // Change the properties object to point to where the new policy is + // in the temporary folder + // + properties.setProperty(root + DOT_FILE_SUFFIX, newRootPath.getAbsolutePath()); + } + // + // Iterate through any referenced policies defined + // + for (String referenced : XACMLProperties.getReferencedPolicyIDs(properties)) { + // + // Get a file + // + Path refPath = Paths.get(properties.getProperty(referenced + DOT_FILE_SUFFIX)); + LOGGER.debug("Referenced file {} {}", refPath, refPath.getFileName()); + // + // Construct new path for the root policy + // + File newReferencedPath = creator.createAFile(refPath.getFileName().toString()); + // + // Copy the policy file to the temporary folder + // + com.google.common.io.Files.copy(refPath.toFile(), newReferencedPath); + // + // Change the properties object to point to where the new policy is + // in the temporary folder + // + properties.setProperty(referenced + DOT_FILE_SUFFIX, newReferencedPath.getAbsolutePath()); + } + // + // Save the new properties file to the temporary folder + // + try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) { + properties.store(os, ""); + } + // + // Return the new path to the properties folder + // + return propertiesFile; } - return null; } } diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java index 3914ba60..3038b651 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java @@ -27,27 +27,41 @@ import com.att.research.xacml.std.annotations.XACMLRequest; import com.att.research.xacml.std.annotations.XACMLResource; import com.att.research.xacml.std.annotations.XACMLSubject; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.Map.Entry; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + import org.onap.policy.models.decisions.concepts.DecisionRequest; +@Getter +@Setter +@ToString @XACMLRequest(ReturnPolicyIdList = true) public class StdCombinedPolicyRequest { - public StdCombinedPolicyRequest() { - super(); - } - @XACMLSubject(includeInResults = true) - String onapName = "DCAE"; + private String onapName; - @XACMLResource(includeInResults = true) - String resource = "onap.policies.Monitoring"; + @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true) + private String onapComponent; + + @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true) + private String onapInstance; @XACMLAction() - String action = "configure"; + private String action; + + @XACMLResource(includeInResults = true) + private Collection resource = new ArrayList<>(); + public StdCombinedPolicyRequest() { + super(); + } /** * Parses the DecisionRequest into a MonitoringRequest. @@ -55,30 +69,57 @@ public class StdCombinedPolicyRequest { * @param decisionRequest Input DecisionRequest * @return MonitoringRequest */ + @SuppressWarnings({"unchecked", "rawtypes"}) public static StdCombinedPolicyRequest createInstance(DecisionRequest decisionRequest) { + // + // Create our request object + // StdCombinedPolicyRequest request = new StdCombinedPolicyRequest(); + // + // Add the subject attributes + // request.onapName = decisionRequest.getOnapName(); + request.onapComponent = decisionRequest.getOnapComponent(); + request.onapInstance = decisionRequest.getOnapInstance(); + // + // Add the action attribute + // request.action = decisionRequest.getAction(); - + // + // Add the resource attributes + // Map resources = decisionRequest.getResource(); - for (Entry entry : resources.entrySet()) { - if ("policy-id".equals(entry.getKey())) { - // - // TODO handle lists of policies - // - request.resource = entry.getValue().toString(); + for (Entry entrySet : resources.entrySet()) { + if ("policy-id".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyIds(request, (Collection) entrySet.getValue()); + } else if (entrySet.getValue() instanceof String) { + request.resource.add(entrySet.getValue().toString()); + } continue; } - if ("policy-type".equals(entry.getKey())) { - // - // TODO handle lists of policies - // - request.resource = entry.getValue().toString(); + if ("policy-type".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyTypes(request, (Collection) entrySet.getValue()); + } else if (entrySet.getValue() instanceof String) { + request.resource.add(entrySet.getValue().toString()); + } } } - // - // TODO handle a bad incoming request. Do that here? - // + return request; + } + + private static StdCombinedPolicyRequest addPolicyIds(StdCombinedPolicyRequest request, Collection ids) { + for (Object id : ids) { + request.resource.add(id.toString()); + } + return request; + } + + private static StdCombinedPolicyRequest addPolicyTypes(StdCombinedPolicyRequest request, Collection types) { + for (Object type : types) { + request.resource.add(type.toString()); + } return request; } } diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java index b39c2e60..16798379 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java @@ -37,6 +37,7 @@ import com.google.gson.Gson; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -144,40 +145,55 @@ public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator // // Go through obligations // - for (Obligation obligation : xacmlResult.getObligations()) { - LOGGER.debug("Obligation: {}", obligation); - for (AttributeAssignment assignment : obligation.getAttributeAssignments()) { - LOGGER.debug("Attribute Assignment: {}", assignment); - // - // We care about the content attribute - // - if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS - .equals(assignment.getAttributeId())) { - // - // The contents are in Json form - // - Object stringContents = assignment.getAttributeValue().getValue(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents); - } - // - // Let's parse it into a map using Gson - // - Gson gson = new Gson(); - @SuppressWarnings("unchecked") - Map result = gson.fromJson(stringContents.toString() ,Map.class); - decisionResponse.getPolicies().add(result); - } - } - } - } else { - decisionResponse.setErrorMessage("A better error message"); + scanObligations(xacmlResult.getObligations(), decisionResponse); + } + if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) { + // + // There is no policy + // + decisionResponse.setPolicies(new ArrayList<>()); + } + if (xacmlResult.getDecision() == Decision.DENY + || xacmlResult.getDecision() == Decision.INDETERMINATE) { + // + // TODO we have to return an ErrorResponse object instead + // + decisionResponse.setStatus("A better error message"); } } return decisionResponse; } + protected void scanObligations(Collection obligations, DecisionResponse decisionResponse) { + for (Obligation obligation : obligations) { + LOGGER.debug("Obligation: {}", obligation); + for (AttributeAssignment assignment : obligation.getAttributeAssignments()) { + LOGGER.debug("Attribute Assignment: {}", assignment); + // + // We care about the content attribute + // + if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS + .equals(assignment.getAttributeId())) { + // + // The contents are in Json form + // + Object stringContents = assignment.getAttributeValue().getValue(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents); + } + // + // Let's parse it into a map using Gson + // + Gson gson = new Gson(); + @SuppressWarnings("unchecked") + Map result = gson.fromJson(stringContents.toString() ,Map.class); + decisionResponse.getPolicies().add(result); + } + } + } + } + @SuppressWarnings("unchecked") protected PolicyType convertPolicy(Entry entrySet) throws ToscaPolicyConversionException { // @@ -211,9 +227,6 @@ public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator // // Generate the TargetType // - // - // There should be a metadata section - // if (! policyDefinition.containsKey("type")) { throw new ToscaPolicyConversionException(policyName + " missing type value"); } diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java new file mode 100644 index 00000000..086d21db --- /dev/null +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdp.xacml.application.common.std; + +import com.att.research.xacml.std.annotations.XACMLAction; +import com.att.research.xacml.std.annotations.XACMLRequest; +import com.att.research.xacml.std.annotations.XACMLResource; +import com.att.research.xacml.std.annotations.XACMLSubject; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import org.onap.policy.models.decisions.concepts.DecisionRequest; + +@Getter +@Setter +@ToString +@XACMLRequest(ReturnPolicyIdList = true) +public class StdMatchablePolicyRequest { + + @XACMLSubject(includeInResults = true) + private String onapName; + + @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true) + private String onapComponent; + + @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true) + private String onapInstance; + + @XACMLAction() + private String action; + + // + // Unfortunately the annotations won't take an object.toString() + // So I could not use the ToscaDictionary class to put these id's + // into the annotations. + // + @XACMLResource(attributeId = "urn:org:onap:policy-scope-property", includeInResults = true) + Collection policyScopes = new ArrayList<>(); + + @XACMLResource(attributeId = "urn:org:onap:policy-type-property", includeInResults = true) + Collection policyTypes = new ArrayList<>(); + + public StdMatchablePolicyRequest() { + super(); + } + + /** + * Parses the DecisionRequest into a MonitoringRequest. + * + * @param decisionRequest Input DecisionRequest + * @return MonitoringRequest + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static StdMatchablePolicyRequest createInstance(DecisionRequest decisionRequest) { + // + // Create our request object + // + StdMatchablePolicyRequest request = new StdMatchablePolicyRequest(); + // + // Add the subject attributes + // + request.onapName = decisionRequest.getOnapName(); + request.onapComponent = decisionRequest.getOnapComponent(); + request.onapInstance = decisionRequest.getOnapInstance(); + // + // Add the action attribute + // + request.action = decisionRequest.getAction(); + // + // Add the resource attributes + // + Map resources = decisionRequest.getResource(); + for (Entry entrySet : resources.entrySet()) { + // + // Making an assumption that these two fields are matchable. + // Its possible we may have to load the policy type model + // and use that to find the fields that are matchable. + // + if ("policyScope".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyScopes(request, (Collection) entrySet.getValue()); + } else if (entrySet.getValue() instanceof String) { + request.policyScopes.add(entrySet.getValue().toString()); + } + continue; + } + if ("policyType".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyTypes(request, (Collection) entrySet.getValue()); + } + if (entrySet.getValue() instanceof String) { + request.policyTypes.add(entrySet.getValue().toString()); + } + } + } + return request; + } + + private static StdMatchablePolicyRequest addPolicyScopes(StdMatchablePolicyRequest request, + Collection scopes) { + for (Object scope : scopes) { + request.policyScopes.add(scope.toString()); + } + return request; + } + + private static StdMatchablePolicyRequest addPolicyTypes(StdMatchablePolicyRequest request, + Collection types) { + for (Object type : types) { + request.policyTypes.add(type.toString()); + } + return request; + } +} diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java new file mode 100644 index 00000000..8550b12e --- /dev/null +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java @@ -0,0 +1,400 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdp.xacml.application.common.std; + +import com.att.research.xacml.api.AttributeAssignment; +import com.att.research.xacml.api.DataTypeException; +import com.att.research.xacml.api.Decision; +import com.att.research.xacml.api.Identifier; +import com.att.research.xacml.api.Obligation; +import com.att.research.xacml.api.Request; +import com.att.research.xacml.api.Response; +import com.att.research.xacml.api.Result; +import com.att.research.xacml.api.XACML3; +import com.att.research.xacml.std.annotations.RequestParser; +import com.att.research.xacml.util.XACMLPolicyWriter; +import com.google.gson.Gson; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType; + +import org.json.JSONObject; +import org.onap.policy.models.decisions.concepts.DecisionRequest; +import org.onap.policy.models.decisions.concepts.DecisionResponse; +import org.onap.policy.pdp.xacml.application.common.ToscaDictionary; +import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException; +import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator; +import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StdMatchableTranslator implements ToscaPolicyTranslator { + + private static final Logger LOGGER = LoggerFactory.getLogger(StdMatchableTranslator.class); + + public StdMatchableTranslator() { + super(); + } + + @SuppressWarnings("unchecked") + @Override + public List scanAndConvertPolicies(Map toscaObject) + throws ToscaPolicyConversionException { + // + // Our return object + // + List scannedPolicies = new ArrayList<>(); + // + // Iterate each of the Policies + // + List policies = (List) toscaObject.get("policies"); + for (Object policyObject : policies) { + // + // Get the contents + // + LOGGER.debug("Found policy {}", policyObject.getClass()); + Map policyContents = (Map) policyObject; + for (Entry entrySet : policyContents.entrySet()) { + LOGGER.debug("Entry set {}", entrySet); + // + // Convert this policy + // + PolicyType policy = this.convertPolicy(entrySet); + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + XACMLPolicyWriter.writePolicyFile(os, policy); + LOGGER.debug("{}", os); + } catch (IOException e) { + LOGGER.error("Failed to convert {}", e); + } + // + // Convert and add in the new policy + // + scannedPolicies.add(policy); + } + } + + return scannedPolicies; + } + + @Override + public Request convertRequest(DecisionRequest request) { + LOGGER.debug("Converting Request {}", request); + try { + return RequestParser.parseRequest(StdMatchablePolicyRequest.createInstance(request)); + } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) { + LOGGER.error("Failed to convert DecisionRequest: {}", e); + } + // + // TODO throw exception + // + return null; + } + + @Override + public DecisionResponse convertResponse(Response xacmlResponse) { + LOGGER.debug("Converting Response {}", xacmlResponse); + DecisionResponse decisionResponse = new DecisionResponse(); + // + // Iterate through all the results + // + for (Result xacmlResult : xacmlResponse.getResults()) { + // + // Check the result + // + if (xacmlResult.getDecision() == Decision.PERMIT) { + // + // Setup policies + // + decisionResponse.setPolicies(new ArrayList<>()); + // + // Go through obligations + // + scanObligations(xacmlResult.getObligations(), decisionResponse); + } + if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) { + // + // There is no policy + // + decisionResponse.setPolicies(new ArrayList<>()); + } + if (xacmlResult.getDecision() == Decision.DENY + || xacmlResult.getDecision() == Decision.INDETERMINATE) { + // + // TODO we have to return an ErrorResponse object instead + // + decisionResponse.setStatus("A better error message"); + } + } + + return decisionResponse; + } + + protected void scanObligations(Collection obligations, DecisionResponse decisionResponse) { + for (Obligation obligation : obligations) { + LOGGER.debug("Obligation: {}", obligation); + for (AttributeAssignment assignment : obligation.getAttributeAssignments()) { + LOGGER.debug("Attribute Assignment: {}", assignment); + // + // We care about the content attribute + // + if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS + .equals(assignment.getAttributeId())) { + // + // The contents are in Json form + // + Object stringContents = assignment.getAttributeValue().getValue(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents); + } + // + // Let's parse it into a map using Gson + // + Gson gson = new Gson(); + @SuppressWarnings("unchecked") + Map result = gson.fromJson(stringContents.toString() ,Map.class); + decisionResponse.getPolicies().add(result); + } + } + } + + } + + @SuppressWarnings("unchecked") + protected PolicyType convertPolicy(Entry entrySet) throws ToscaPolicyConversionException { + // + // Policy name should be at the root + // + String policyName = entrySet.getKey(); + Map policyDefinition = (Map) entrySet.getValue(); + // + // Set it as the policy ID + // + PolicyType newPolicyType = new PolicyType(); + newPolicyType.setPolicyId(policyName); + // + // Optional description + // + if (policyDefinition.containsKey("description")) { + newPolicyType.setDescription(policyDefinition.get("description").toString()); + } + // + // There should be a metadata section + // + if (! policyDefinition.containsKey("metadata")) { + throw new ToscaPolicyConversionException(policyName + " missing metadata section"); + } + this.fillMetadataSection(newPolicyType, + (Map) policyDefinition.get("metadata")); + // + // Set the combining rule + // + newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue()); + // + // Generate the TargetType + // + if (! policyDefinition.containsKey("properties")) { + throw new ToscaPolicyConversionException(policyName + " missing properties section"); + } + policyDefinition.get("properties"); + newPolicyType.setTarget(generateTargetType((Map) policyDefinition.get("properties"))); + // + // Now create the Permit Rule + // No target since the policy has a target + // With obligations. + // + RuleType rule = new RuleType(); + rule.setDescription("Default is to PERMIT if the policy matches."); + rule.setRuleId(policyName + ":rule"); + rule.setEffect(EffectType.PERMIT); + rule.setTarget(new TargetType()); + // + // Now represent the policy as Json + // + JSONObject jsonObligation = new JSONObject(); + jsonObligation.put(policyName, policyDefinition); + addObligation(rule, jsonObligation); + // + // Add the rule to the policy + // + newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule); + // + // Return our new policy + // + return newPolicyType; + } + + /** + * From the TOSCA metadata section, pull in values that are needed into the XACML policy. + * + * @param policy Policy Object to store the metadata + * @param metadata The Metadata TOSCA Map + * @return Same Policy Object + * @throws ToscaPolicyConversionException If there is something missing from the metadata + */ + protected PolicyType fillMetadataSection(PolicyType policy, + Map metadata) throws ToscaPolicyConversionException { + if (! metadata.containsKey("policy-id")) { + throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id"); + } else { + // + // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field + // + } + if (! metadata.containsKey("policy-version")) { + throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version"); + } else { + // + // Add in the Policy Version + // + policy.setVersion(metadata.get("policy-version").toString()); + } + return policy; + } + + /** + * For generating target type, we are making an assumption that the + * policyScope and policyType are the fields that OOF wants to match on. + * + *

In the future, we would need to receive the Policy Type specification + * from the PAP so we can dynamically see which fields are matchable. + * + *

Note: I am making an assumption that the matchable fields are what + * the OOF wants to query a policy on. + * + * @param properties Properties section of policy + * @return TargetType object + */ + @SuppressWarnings("unchecked") + protected TargetType generateTargetType(Map properties) { + TargetType targetType = new TargetType(); + // + // Iterate the properties + // + for (Entry entrySet : properties.entrySet()) { + // + // Find policyScope and policyType + // + if (entrySet.getKey().equals("policyScope")) { + LOGGER.debug("Found policyScope: {}", entrySet.getValue()); + if (entrySet.getValue() instanceof Collection) { + targetType.getAnyOf().add(generateMatches((Collection) entrySet.getValue(), + ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY)); + } else if (entrySet.getValue() instanceof String) { + targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()), + ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY)); + } + } + if (entrySet.getKey().equals("policyType")) { + LOGGER.debug("Found policyType: {}", entrySet.getValue()); + if (entrySet.getValue() instanceof Collection) { + targetType.getAnyOf().add(generateMatches((Collection) entrySet.getValue(), + ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY)); + } else if (entrySet.getValue() instanceof String) { + targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()), + ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY)); + } + } + } + + return targetType; + } + + protected AnyOfType generateMatches(Collection matchables, Identifier attributeId) { + // + // This is our outer AnyOf - which is an OR + // + AnyOfType anyOf = new AnyOfType(); + for (Object matchable : matchables) { + // + // Create a match for this + // + MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator( + XACML3.ID_FUNCTION_STRING_EQUAL, + matchable.toString(), + XACML3.ID_DATATYPE_STRING, + attributeId, + XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE); + // + // Now create an anyOf (OR) + // + anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match)); + } + return anyOf; + } + + protected RuleType addObligation(RuleType rule, JSONObject jsonPolicy) { + // + // Convert the YAML Policy to JSON Object + // + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("JSON Optimization Policy {}{}", System.lineSeparator(), jsonPolicy); + } + // + // Create an AttributeValue for it + // + AttributeValueType value = new AttributeValueType(); + value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue()); + value.getContent().add(jsonPolicy.toString()); + // + // Create our AttributeAssignmentExpression where we will + // store the contents of the policy in JSON format. + // + AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType(); + expressionType.setAttributeId(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS.stringValue()); + ObjectFactory factory = new ObjectFactory(); + expressionType.setExpression(factory.createAttributeValue(value)); + // + // Create an ObligationExpression for it + // + ObligationExpressionType obligation = new ObligationExpressionType(); + obligation.setFulfillOn(EffectType.PERMIT); + obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue()); + obligation.getAttributeAssignmentExpression().add(expressionType); + // + // Now we can add it into the rule + // + ObligationExpressionsType obligations = new ObligationExpressionsType(); + obligations.getObligationExpression().add(obligation); + rule.setObligationExpressions(obligations); + return rule; + } + +} diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java deleted file mode 100644 index 11651f4f..00000000 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java +++ /dev/null @@ -1,110 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.pdp.xacml.application.common.std; - -import com.att.research.xacml.api.Request; -import com.att.research.xacml.api.Response; -import com.att.research.xacml.util.XACMLPolicyWriter; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; - -import org.onap.policy.models.decisions.concepts.DecisionRequest; -import org.onap.policy.models.decisions.concepts.DecisionResponse; -import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException; -import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class StdMetadataTranslator implements ToscaPolicyTranslator { - - private static final Logger LOGGER = LoggerFactory.getLogger(StdMetadataTranslator.class); - - public StdMetadataTranslator() { - super(); - } - - @SuppressWarnings("unchecked") - @Override - public List scanAndConvertPolicies(Map toscaObject) - throws ToscaPolicyConversionException { - // - // Our return object - // - List scannedPolicies = new ArrayList<>(); - // - // Iterate each of the Policies - // - List policies = (List) toscaObject.get("policies"); - for (Object policyObject : policies) { - // - // Get the contents - // - LOGGER.debug("Found policy {}", policyObject.getClass()); - Map policyContents = (Map) policyObject; - for (Entry entrySet : policyContents.entrySet()) { - LOGGER.debug("Entry set {}", entrySet); - // - // Convert this policy - // - PolicyType policy = this.convertPolicy(entrySet); - try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { - XACMLPolicyWriter.writePolicyFile(os, policy); - LOGGER.debug("{}", os); - } catch (IOException e) { - LOGGER.error("Failed to convert {}", e); - } - // - // Convert and add in the new policy - // - scannedPolicies.add(policy); - } - } - - return scannedPolicies; - } - - @Override - public Request convertRequest(DecisionRequest request) { - // TODO Auto-generated method stub - return null; - } - - @Override - public DecisionResponse convertResponse(Response xacmlResponse) { - // TODO Auto-generated method stub - return null; - } - - private PolicyType convertPolicy(Entry entrySet) throws ToscaPolicyConversionException { - - return null; - } - -} -- cgit 1.2.3-korg