/*-
* ============LICENSE_START=======================================================
* ONAP-XACML
* ================================================================================
* Copyright (C) 2017-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.
* ============LICENSE_END=========================================================
*/
package org.onap.policy.xacml.util;
import com.att.research.xacml.api.AttributeAssignment;
import com.att.research.xacml.std.IdentifierImpl;
import com.att.research.xacml.std.StdAttribute;
import com.att.research.xacml.std.StdAttributeAssignment;
import com.att.research.xacml.std.StdAttributeValue;
import com.att.research.xacml.std.StdMutableAdvice;
import com.att.research.xacml.std.StdMutableObligation;
import com.att.research.xacml.util.XACMLPolicyScanner.Callback;
import com.att.research.xacml.util.XACMLPolicyScanner.CallbackResult;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
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.AttributeAssignmentExpressionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeSelectorType;
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.MatchType;
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.PolicySetType;
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 oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableDefinitionType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.onap.policy.common.logging.eelf.MessageCodes;
import org.onap.policy.common.logging.eelf.PolicyLogger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* class XACMLPolicyScanner.
*
*
This class traverses the hierarchy of a XACML 3.0 policy. You can optionally pass a Callback class
* and override any desired methods to retrieve information from a policy.
*
*
*/
public class XACMLPolicyScanner {
private static final Log logger = LogFactory.getLog(XACMLPolicyScanner.class);
private Object policyObject = null;
private Callback callback = null;
/**
* constructor.
*
* @param filename Path
* @param callback Callback
*/
public XACMLPolicyScanner(Path filename, Callback callback) {
try (InputStream is = Files.newInputStream(filename)) {
this.policyObject = XACMLPolicyScanner.readPolicy(is);
} catch (IOException e) {
PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyScanner", "Failed to read policy");
}
this.callback = callback;
}
/**
* Constructor.
*
* @param filename InputStream
* @param callback Callback
*/
public XACMLPolicyScanner(InputStream filename, Callback callback) {
try (InputStream is = filename) {
this.policyObject = XACMLPolicyScanner.readPolicy(is);
} catch (IOException e) {
PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyScanner", "Failed to read policy");
}
this.callback = callback;
}
public XACMLPolicyScanner(PolicySetType policySet, Callback callback) {
this.policyObject = policySet;
this.callback = callback;
}
public XACMLPolicyScanner(PolicySetType policySet) {
this(policySet, null);
}
public XACMLPolicyScanner(PolicyType policy, Callback callback) {
this.policyObject = policy;
this.callback = callback;
}
public XACMLPolicyScanner(PolicyType policy) {
this(policy, null);
}
/**
* Sets the callback interface to be used.
*
* @param cb Callback object
*/
public void setCallback(Callback cb) {
this.callback = cb;
}
/**
* Saves the given callback object then calls the scan() method.
*
* @param cb Callback object
* @return
*/
public Object scan(Callback cb) {
this.callback = cb;
return this.scan();
}
/**
* This begins the scanning of the contained object.
*
* @return - The PolicySet/Policy that was scanned.
*/
public Object scan() {
if (this.policyObject == null) {
return null;
}
if (this.callback != null && this.callback.onBeginScan(this.policyObject) == CallbackResult.STOP) {
return this.policyObject;
}
if (this.policyObject instanceof PolicyType) {
this.scanPolicy(null, (PolicyType) this.policyObject);
} else if (this.policyObject instanceof PolicySetType) {
this.scanPolicySet(null, (PolicySetType) this.policyObject);
} else {
PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW + "Unknown class type: "
+ this.policyObject.getClass().getCanonicalName());
}
if (this.callback != null) {
this.callback.onFinishScan(this.policyObject);
}
return this.policyObject;
}
/**
* This performs the scan of a PolicySet.
*
* @param parent - Its parent PolicySet. Can be null if this is the root.
* @param policySet - The PolicySet object.
* @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
*/
protected CallbackResult scanPolicySet(PolicySetType parent, PolicySetType policySet) {
if (logger.isTraceEnabled()) {
logger.trace("scanning policy set: " + policySet.getPolicySetId() + " " + policySet.getDescription());
}
if (this.callback != null && this.callback.onPreVisitPolicySet(parent, policySet) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
//
// Scan its info
//
if (this.scanTarget(policySet, policySet.getTarget()) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
if (this.scanObligations(policySet, policySet.getObligationExpressions()) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
if (this.scanAdvice(policySet, policySet.getAdviceExpressions()) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
//
// Iterate the policy sets and/or policies
//
List> list = policySet.getPolicySetOrPolicyOrPolicySetIdReference();
for (JAXBElement> element : list) {
if ("PolicySet".equals(element.getName().getLocalPart())
&& this.scanPolicySet(policySet, (PolicySetType) element.getValue()) == CallbackResult.STOP) {
return CallbackResult.STOP;
} else if ("Policy".equals(element.getName().getLocalPart())
&& this.scanPolicy(policySet, (PolicyType) element.getValue()) == CallbackResult.STOP) {
return CallbackResult.STOP;
} else {
logger.warn("generating policy sets found unsupported element: " + element.getName().getNamespaceURI());
}
}
if (this.callback != null && this.callback.onPostVisitPolicySet(parent, policySet) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
return CallbackResult.CONTINUE;
}
/**
* This performs scanning of the Policy object.
*
* @param parent - The parent PolicySet of the policy. This can be null if this is a root Policy.
* @param policy - The policy being scanned.
* @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
*/
protected CallbackResult scanPolicy(PolicySetType parent, PolicyType policy) {
if (logger.isTraceEnabled()) {
logger.trace("scanning policy: " + policy.getPolicyId() + " " + policy.getDescription());
}
if (this.callback != null && this.callback.onPreVisitPolicy(parent, policy) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
//
// Scan its info
//
if (this.scanTarget(policy, policy.getTarget()) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
if (this.scanVariables(policy,
policy.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition()) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
if (this.scanObligations(policy, policy.getObligationExpressions()) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
if (this.scanAdvice(policy, policy.getAdviceExpressions()) == CallbackResult.STOP) {
return CallbackResult.STOP;
}
//
// Iterate the rules
//
List