diff options
Diffstat (limited to 'applications/guard/src/main')
3 files changed, 939 insertions, 4 deletions
diff --git a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java index 18385239..1b12fca8 100644 --- a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java +++ b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java @@ -24,19 +24,23 @@ package org.onap.policy.xacml.pdp.application.guard; import com.att.research.xacml.api.Request; import com.att.research.xacml.api.Response; +import com.att.research.xacml.util.XACMLPolicyWriter; import com.google.common.collect.Lists; +import java.io.IOException; +import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; 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.std.StdMetadataTranslator; +import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils; import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,7 +56,7 @@ public class GuardPdpApplication extends StdXacmlApplicationServiceProvider { private static final Logger LOGGER = LoggerFactory.getLogger(GuardPdpApplication.class); private static final String STRING_VERSION100 = "1.0.0"; private Map<String, String> supportedPolicyTypes = new HashMap<>(); - private StdMetadataTranslator translator = new StdMetadataTranslator(); + private LegacyGuardTranslator translator = new LegacyGuardTranslator(); /** Constructor. * @@ -103,9 +107,37 @@ public class GuardPdpApplication extends StdXacmlApplicationServiceProvider { throw new ToscaPolicyConversionException("Converted 0 policies"); } // - // TODO update properties, save to disk, etc. + // Create a copy of the properties object // - } catch (ToscaPolicyConversionException e) { + Properties newProperties = this.getProperties(); + // + // Iterate through the policies + // + for (PolicyType newPolicy : listPolicies) { + // + // Construct the filename + // + Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(newPolicy, this.getDataPath()); + // + // Write the policy to disk + // Maybe check for an error + // + XACMLPolicyWriter.writePolicyFile(refPath, newPolicy); + // + // Add root policy to properties object + // + XacmlPolicyUtils.addRootPolicy(newProperties, refPath); + } + // + // Write the properties to disk + // + XacmlPolicyUtils.storeXacmlProperties(newProperties, + XacmlPolicyUtils.getPropertiesPath(this.getDataPath())); + // + // Reload the engine + // + this.createEngine(newProperties); + } catch (IOException | ToscaPolicyConversionException e) { LOGGER.error("Failed to loadPolicies {}", e); } } diff --git a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardPolicyRequest.java b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardPolicyRequest.java new file mode 100644 index 00000000..0b5b5675 --- /dev/null +++ b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardPolicyRequest.java @@ -0,0 +1,163 @@ +/*- + * ============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.xacml.pdp.application.guard; + +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.Map; + +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 LegacyGuardPolicyRequest { + + private static final String STR_GUARD = "guard"; + + @XACMLSubject(includeInResults = true) + private String onapName; + + @XACMLSubject(includeInResults = true, attributeId = "urn:org:onap:onap-component") + private String onapComponent; + + @XACMLSubject(includeInResults = true, attributeId = "urn:org:onap:onap-instance") + private String onapInstance; + + @XACMLSubject(includeInResults = true, attributeId = "urn:org:onap:guard:request:request-id") + private String requestId; + + @XACMLAction + private String action = STR_GUARD; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:clname:clname-id") + private String clnameId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:actor:actor-id") + private String actorId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:operation:operation-id") + private String operationId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:target-id") + private String targetId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:vf-count") + private Integer vfCount; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:min") + private Integer min; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:max") + private Integer max; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:operation:operation-count") + private Integer operationCount; + + public LegacyGuardPolicyRequest() { + super(); + } + + /** + * Parses the DecisionRequest into a StdMetadataPolicyRequest. + * + * @param decisionRequest Input DecisionRequest + * @return StdMetadataPolicyRequest + */ + @SuppressWarnings("unchecked") + public static LegacyGuardPolicyRequest createInstance(DecisionRequest decisionRequest) { + // + // Create our return object + // + LegacyGuardPolicyRequest request = new LegacyGuardPolicyRequest(); + // + // Add the subject attributes + // + request.onapName = decisionRequest.getOnapName(); + request.onapComponent = decisionRequest.getOnapComponent(); + request.onapInstance = decisionRequest.getOnapInstance(); + request.requestId = decisionRequest.getRequestId(); + // + // Now pull from the resources + // + Map<String, Object> resources = decisionRequest.getResource(); + // + // Just in case nothing is in there + // + if (resources == null || resources.isEmpty() || ! resources.containsKey(STR_GUARD)) { + // + // Perhaps we throw an exception and then caller + // can put together a response + // + return request; + } + Map<String, Object> guard = (Map<String, Object>) resources.get(STR_GUARD); + if (guard == null || guard.isEmpty()) { + // + // again, same problem throw an exception? + // + return request; + } + // + // Find our fields + // + if (guard.containsKey("actor")) { + request.actorId = guard.get("actor").toString(); + } + if (guard.containsKey("recipe")) { + request.operationId = guard.get("recipe").toString(); + } + if (guard.containsKey("clname")) { + request.clnameId = guard.get("clname").toString(); + } + if (guard.containsKey("targets")) { + request.targetId = guard.get("targets").toString(); + } + if (guard.containsKey("vfCount")) { + request.vfCount = Integer.decode(guard.get("vfCount").toString()); + } + if (guard.containsKey("min")) { + request.min = Integer.decode(guard.get("min").toString()); + } + if (guard.containsKey("max")) { + request.max = Integer.decode(guard.get("max").toString()); + } + // + // TODO - remove this when the PIP is hooked up + // + if (guard.containsKey("operationCount")) { + request.operationCount = Integer.decode(guard.get("operationCount").toString()); + } + + return request; + } + +} diff --git a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardTranslator.java b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardTranslator.java new file mode 100644 index 00000000..81340b4d --- /dev/null +++ b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardTranslator.java @@ -0,0 +1,740 @@ +/*- + * ============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.xacml.pdp.application.guard; + +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.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 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; + +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType; +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.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.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 LegacyGuardTranslator implements ToscaPolicyTranslator { + + private static final Logger LOGGER = LoggerFactory.getLogger(LegacyGuardTranslator.class); + + private static final String FIELD_POLICIES = "policies"; + private static final String FIELD_TOPOLOGY_TEMPLATE = "topology_template"; + private static final String FIELD_GUARD_ACTIVE_START = "guardActiveStart"; + private static final String FIELD_GUARD_ACTIVE_END = "guardActiveEnd"; + + public LegacyGuardTranslator() { + super(); + } + + @SuppressWarnings("unchecked") + @Override + public List<PolicyType> scanAndConvertPolicies(Map<String, Object> toscaObject) + throws ToscaPolicyConversionException { + // + // Our return object + // + List<PolicyType> scannedPolicies = new ArrayList<>(); + // + // Find the Policies + // + List<Object> policies; + + if (toscaObject.containsKey(FIELD_POLICIES)) { + policies = (List<Object>) toscaObject.get(FIELD_POLICIES); + } else if (toscaObject.containsKey(FIELD_TOPOLOGY_TEMPLATE)) { + Map<String, Object> topologyTemplate = (Map<String, Object>) toscaObject.get(FIELD_TOPOLOGY_TEMPLATE); + if (topologyTemplate.containsKey(FIELD_POLICIES)) { + policies = (List<Object>) topologyTemplate.get(FIELD_POLICIES); + } else { + LOGGER.warn("topologyTemplate does not contain policies"); + return scannedPolicies; + } + } else { + LOGGER.warn("Failed to find policies or topologyTemplate"); + return scannedPolicies; + } + // + // Iterate each of the Policies + // + for (Object policyObject : policies) { + // + // Get the contents + // + LOGGER.debug("Found policy {}", policyObject.getClass()); + Map<String, Object> policyContents = (Map<String, Object>) policyObject; + for (Entry<String, Object> entrySet : policyContents.entrySet()) { + LOGGER.debug("Entry set {}", entrySet); + // + // Convert this policy + // + PolicyType policy = this.convertPolicy(entrySet); + if (policy == null) { + // + // Somehow there wasn't enough information to create + // a policy + // + LOGGER.debug("Failed to convert policy"); + continue; + } + // + // Debug dump this + // + 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(LegacyGuardPolicyRequest.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) { + // + // Just simply return a Permit response + // + decisionResponse.setStatus(Decision.PERMIT.toString()); + } + if (xacmlResult.getDecision() == Decision.DENY) { + // + // Just simply return a Deny response + // + decisionResponse.setStatus(Decision.DENY.toString()); + } + if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) { + // + // There is no guard policy, so we return a permit + // + decisionResponse.setStatus(Decision.PERMIT.toString()); + } + } + + return decisionResponse; + } + + @SuppressWarnings("unchecked") + private PolicyType convertPolicy(Entry<String, Object> entrySet) throws ToscaPolicyConversionException { + // + // Policy name should be at the root + // + String policyName = entrySet.getKey(); + Map<String, Object> policyDefinition = (Map<String, Object>) 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<String, Object>) policyDefinition.get("metadata")); + // + // Set the combining rule + // + newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue()); + // + // Generate the TargetType + // + if (! policyDefinition.containsKey("properties")) { + throw new ToscaPolicyConversionException(policyName + " missing properties section"); + } + newPolicyType.setTarget(this.generateTargetType((Map<String, Object>) policyDefinition.get("properties"))); + // + // Now create the Permit Rule + // + RuleType rule = generatePermitRule(policyName, policyDefinition.get("type").toString(), + (Map<String, Object>) policyDefinition.get("properties")); + // + // Check if we were able to create the rule + // + if (rule == null) { + LOGGER.warn("Failed to create rule"); + return null; + } + // + // 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<String, Object> 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; + } + + protected TargetType generateTargetType(Map<String, Object> properties) { + // + // Go through potential properties + // + AllOfType allOf = new AllOfType(); + if (properties.containsKey("actor")) { + addMatch(allOf, properties.get("actor"), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR); + } + if (properties.containsKey("recipe")) { + addMatch(allOf, properties.get("recipe"), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE); + } + if (properties.containsKey("targets")) { + addMatch(allOf, properties.get("targets"), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID); + } + if (properties.containsKey("clname")) { + addMatch(allOf, properties.get("clname"), ToscaDictionary.ID_RESOURCE_GUARD_CLNAME); + } + if (properties.containsKey("targets")) { + addMatch(allOf, properties.get("targets"), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID); + } + // + // Create target + // + TargetType target = new TargetType(); + AnyOfType anyOf = new AnyOfType(); + anyOf.getAllOf().add(allOf); + target.getAnyOf().add(anyOf); + return target; + } + + private static AllOfType addMatch(AllOfType allOf, Object value, Identifier attributeId) { + if (value instanceof String) { + if (".*".equals(value.toString())) { + // + // There's no point to even have a match + // + return allOf; + } else { + // + // Exact match + // + MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator( + XACML3.ID_FUNCTION_STRING_EQUAL, + value, + XACML3.ID_DATATYPE_STRING, + attributeId, + XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE); + + allOf.getMatch().add(match); + } + return allOf; + } + if (value instanceof Collection) { + // + // TODO support a collection of that attribute + // + } + return allOf; + } + + private static RuleType generatePermitRule(String policyName, String policyType, Map<String, Object> properties) { + // + // Now determine which policy type we are generating + // + if ("onap.policies.controlloop.guard.FrequencyLimiter".equals(policyType)) { + return generateFrequencyPermit(policyName, properties); + } else if ("onap.policies.controlloop.guard.MinMax".equals(policyType)) { + return generateMinMaxPermit(policyName, properties); + } + return null; + } + + private static RuleType generateFrequencyPermit(String policyName, Map<String, Object> properties) { + // + // See if its possible to generate a count + // + Integer limit = null; + if (properties.containsKey("limit")) { + limit = Integer.decode(properties.get("limit").toString()); + } + if (limit == null) { + LOGGER.debug("Must have a limit value for frequency guard policy to be created"); + return null; + } + // + // Get the properties that are common among guards + // + String timeWindow = null; + if (properties.containsKey("timeWindow")) { + timeWindow = properties.get("timeWindow").toString(); + } + String timeUnits = null; + if (properties.containsKey("timeUnits")) { + timeUnits = properties.get("timeUnits").toString(); + } + String guardActiveStart = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) { + guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString(); + } + String guardActiveEnd = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) { + guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString(); + } + // + // Generate the time in range + // + final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd); + // + // Generate a count + // + final ApplyType countCheck = generateCountCheck(limit, timeWindow, timeUnits); + // + // Now combine into an And + // + ApplyType applyAnd = new ApplyType(); + applyAnd.setDescription("return true if all the apply's are true."); + applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue()); + applyAnd.getExpression().add(new ObjectFactory().createApply(timeRange)); + applyAnd.getExpression().add(new ObjectFactory().createApply(countCheck)); + // + // And create an outer negation of the And + // + ApplyType applyNot = new ApplyType(); + applyNot.setDescription("Negate the and"); + applyNot.setFunctionId(XACML3.ID_FUNCTION_NOT.stringValue()); + applyNot.getExpression().add(new ObjectFactory().createApply(applyAnd)); + + // + // Create our condition + // + final ConditionType condition = new ConditionType(); + condition.setExpression(new ObjectFactory().createApply(applyNot)); + + // + // Now we can create our rule + // + RuleType permit = new RuleType(); + permit.setDescription("Default is to PERMIT if the policy matches."); + permit.setRuleId(policyName + ":rule"); + permit.setEffect(EffectType.PERMIT); + permit.setTarget(new TargetType()); + // + // Add the condition + // + permit.setCondition(condition); + // + // TODO Add the advice - Is the request id needed to be returned? + // + // permit.setAdviceExpressions(adviceExpressions); + // + // Done + // + return permit; + } + + private static RuleType generateMinMaxPermit(String policyName, Map<String, Object> properties) { + // + // Get the properties that are common among guards + // + String guardActiveStart = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) { + guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString(); + } + String guardActiveEnd = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) { + guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString(); + } + // + // Generate the time in range + // + final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd); + // + // See if its possible to generate a count + // + Integer min = null; + if (properties.containsKey("min")) { + min = Integer.decode(properties.get("min").toString()); + } + Integer max = null; + if (properties.containsKey("max")) { + max = Integer.decode(properties.get("max").toString()); + } + final ApplyType minApply = generateMinCheck(min); + final ApplyType maxApply = generateMaxCheck(max); + // + // Make sure we have at least something to check here, + // otherwise there really is no point to this policy. + // + if (timeRange == null && minApply == null && maxApply == null) { + return null; + } + // + // Create our rule + // + RuleType permit = new RuleType(); + permit.setDescription("Default is to PERMIT if the policy matches."); + permit.setRuleId(policyName + ":rule"); + permit.setEffect(EffectType.PERMIT); + permit.setTarget(new TargetType()); + // + // Create our condition + // + final ConditionType condition = new ConditionType(); + // + // Check if we have all the fields (this can be a little + // ugly) but the ultimate goal is to simplify the policy + // condition to only check for necessary attributes. + // + ObjectFactory factory = new ObjectFactory(); + if (timeRange != null && minApply != null && maxApply != null) { + // + // All 3 must apply + // + ApplyType applyAnd = new ApplyType(); + applyAnd.setDescription("return true if all the apply's are true."); + applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue()); + applyAnd.getExpression().add(factory.createApply(timeRange)); + applyAnd.getExpression().add(factory.createApply(minApply)); + applyAnd.getExpression().add(factory.createApply(maxApply)); + // + // Add into the condition + // + condition.setExpression(factory.createApply(applyAnd)); + } else { + // + // At least one of these applies is null. We need at least + // two to require the And apply. Otherwise there is no need + // for an outer And apply as the single condition can work + // on its own. + // + if (timeRange != null && minApply == null && maxApply == null) { + // + // Only the time range check is necessary + // + condition.setExpression(factory.createApply(timeRange)); + } else if (timeRange == null && minApply != null && maxApply == null) { + // + // Only the min check is necessary + // + condition.setExpression(factory.createApply(minApply)); + } else if (timeRange == null && minApply == null) { + // + // Only the max check is necessary + // + condition.setExpression(factory.createApply(maxApply)); + } else { + // + // Ok we will need an outer And and have at least the + // time range and either min or max check + // + ApplyType applyAnd = new ApplyType(); + applyAnd.setDescription("return true if all the apply's are true."); + applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue()); + if (timeRange != null) { + applyAnd.getExpression().add(factory.createApply(timeRange)); + } + if (minApply != null) { + applyAnd.getExpression().add(factory.createApply(minApply)); + } + if (maxApply != null) { + applyAnd.getExpression().add(factory.createApply(maxApply)); + } + // + // Add into the condition + // + condition.setExpression(factory.createApply(applyAnd)); + } + } + // + // Add the condition + // + permit.setCondition(condition); + // + // TODO Add the advice - Is the request id needed to be returned? + // + // permit.setAdviceExpressions(adviceExpressions); + // + // Done + // + return permit; + } + + private static ApplyType generateTimeInRange(String start, String end) { + if (start == null || end == null) { + LOGGER.warn("Missing time range start {} end {}", start, end); + return null; + } + if (start.isEmpty() || end.isEmpty()) { + LOGGER.warn("Empty time range start {} end {}", start, end); + return null; + } + + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(XACML3.ID_ENVIRONMENT_CURRENT_TIME.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_TIME.stringValue()); + + AttributeValueType valueStart = new AttributeValueType(); + valueStart.setDataType(XACML3.ID_DATATYPE_TIME.stringValue()); + valueStart.getContent().add(start); + + AttributeValueType valueEnd = new AttributeValueType(); + valueEnd.setDataType(XACML3.ID_DATATYPE_TIME.stringValue()); + valueEnd.getContent().add(end); + + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the current time"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_TIME_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyTimeInRange = new ApplyType(); + applyTimeInRange.setDescription("return true if current time is in range."); + applyTimeInRange.setFunctionId(XACML3.ID_FUNCTION_TIME_IN_RANGE.stringValue()); + applyTimeInRange.getExpression().add(factory.createApply(applyOneAndOnly)); + applyTimeInRange.getExpression().add(factory.createAttributeValue(valueStart)); + applyTimeInRange.getExpression().add(factory.createAttributeValue(valueEnd)); + + return applyTimeInRange; + } + + private static ApplyType generateCountCheck(Integer limit, String timeWindow, String timeUnits) { + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // TODO Add this back in when the operational database PIP is configured. + // The issuer indicates that the PIP will be providing this attribute during + // the decision making. + // + // Right now I am faking the count value by re-using the request-id field + // + //String issuer = "org:onap:xacml:guard:historydb:tw:" + timeWindow + ":" + timeUnits; + //designator.setIssuer(issuer); + + AttributeValueType valueLimit = new AttributeValueType(); + valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // Yes really use toString(), the marshaller will + // throw an exception if this is an integer object + // and not a string. + // + valueLimit.getContent().add(limit.toString()); + + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the limit"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyGreaterThanEqual = new ApplyType(); + applyGreaterThanEqual.setDescription("return true if current count is greater than or equal."); + applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_GREATER_THAN_OR_EQUAL.stringValue()); + applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly)); + applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit)); + + return applyGreaterThanEqual; + } + + private static ApplyType generateMinCheck(Integer min) { + if (min == null) { + return null; + } + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // + // + AttributeValueType valueLimit = new AttributeValueType(); + valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // Yes really use toString(), the marshaller will + // throw an exception if this is an integer object + // and not a string. + // + valueLimit.getContent().add(min.toString()); + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the min"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyGreaterThanEqual = new ApplyType(); + applyGreaterThanEqual.setDescription("return true if current count is greater than or equal."); + applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_GREATER_THAN_OR_EQUAL.stringValue()); + applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly)); + applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit)); + + return applyGreaterThanEqual; + } + + private static ApplyType generateMaxCheck(Integer max) { + if (max == null) { + return null; + } + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // + // + AttributeValueType valueLimit = new AttributeValueType(); + valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // Yes really use toString(), the marshaller will + // throw an exception if this is an integer object + // and not a string. + // + valueLimit.getContent().add(max.toString()); + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the min"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyGreaterThanEqual = new ApplyType(); + applyGreaterThanEqual.setDescription("return true if current count is less than or equal."); + applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN_OR_EQUAL.stringValue()); + applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly)); + applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit)); + + return applyGreaterThanEqual; + } + + private static AdviceExpressionsType generateRequestIdAdvice() { + AdviceExpressionType adviceExpression = new AdviceExpressionType(); + adviceExpression.setAppliesTo(EffectType.PERMIT); + adviceExpression.setAdviceId(ToscaDictionary.ID_ADVICE_GUARD.stringValue()); + + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_SUBJECT_GUARD_REQUESTID.stringValue()); + designator.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue()); + + AttributeAssignmentExpressionType assignment = new AttributeAssignmentExpressionType(); + assignment.setAttributeId(ToscaDictionary.ID_ADVICE_GUARD_REQUESTID.stringValue()); + assignment.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue()); + assignment.setExpression(new ObjectFactory().createAttributeDesignator(designator)); + + adviceExpression.getAttributeAssignmentExpression().add(assignment); + + AdviceExpressionsType adviceExpressions = new AdviceExpressionsType(); + adviceExpressions.getAdviceExpression().add(adviceExpression); + + return adviceExpressions; + } +} |