blob: abb899045ea9e85890da74ac2795385f5d59adf8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
*/
/*
* AT&T - PROPRIETARY
* THIS FILE CONTAINS PROPRIETARY INFORMATION OF
* AT&T AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN
* ACCORDANCE WITH APPLICABLE AGREEMENTS.
*
* Copyright (c) 2013 AT&T Knowledge Ventures
* Unpublished and Not for Publication
* All Rights Reserved
*/
package org.apache.openaz.xacml.pdp;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.openaz.xacml.api.AttributeCategory;
import org.apache.openaz.xacml.api.Decision;
import org.apache.openaz.xacml.api.Request;
import org.apache.openaz.xacml.api.Response;
import org.apache.openaz.xacml.api.Result;
import org.apache.openaz.xacml.api.Status;
import org.apache.openaz.xacml.api.XACML3;
import org.apache.openaz.xacml.api.pdp.PDPEngine;
import org.apache.openaz.xacml.api.pdp.PDPException;
import org.apache.openaz.xacml.api.pdp.ScopeResolver;
import org.apache.openaz.xacml.api.trace.TraceEngine;
import org.apache.openaz.xacml.api.trace.TraceEngineFactory;
import org.apache.openaz.xacml.api.trace.Traceable;
import org.apache.openaz.xacml.pdp.eval.EvaluationContext;
import org.apache.openaz.xacml.pdp.eval.EvaluationContextFactory;
import org.apache.openaz.xacml.pdp.eval.EvaluationException;
import org.apache.openaz.xacml.pdp.policy.PolicyDef;
import org.apache.openaz.xacml.pdp.policy.PolicyFinderResult;
import org.apache.openaz.xacml.std.StdIndividualDecisionRequestGenerator;
import org.apache.openaz.xacml.std.StdMutableResponse;
import org.apache.openaz.xacml.std.StdMutableResult;
import org.apache.openaz.xacml.std.StdResult;
import org.apache.openaz.xacml.std.StdStatus;
import org.apache.openaz.xacml.std.StdStatusCode;
import org.apache.openaz.xacml.std.trace.StdTraceEvent;
import org.apache.openaz.xacml.util.FactoryException;
/**
* ATTPDPEngine implements the {@link org.apache.openaz.xacml.api.pdp.PDPEngine} interface using the XACML 3.0
* specification.
*/
public class OpenAZPDPEngine implements PDPEngine, Traceable {
private static final Status STATUS_ADVICE_NA = new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR,
"Advice not allowed in combined decision");
private static final Status STATUS_OBLIGATIONS_NA = new StdStatus(
StdStatusCode.STATUS_CODE_PROCESSING_ERROR,
"Obligations not allowed in combined decision");
private static final Status STATUS_COMBINE_FAILED = new StdStatus(
StdStatusCode.STATUS_CODE_PROCESSING_ERROR,
"Individual decisions do not match");
private static final Result RESULT_ECTX_NULL = new StdMutableResult(
new StdStatus(
StdStatusCode.STATUS_CODE_PROCESSING_ERROR,
"Null EvaluationContext"));
/*
* These are the profiles that this reference implementation of the PDP engine supports
*/
private static final Set<URI> PROFILES = new HashSet<URI>();
static {
PROFILES.add(XACML3.ID_PROFILE_MULTIPLE_COMBINED_DECISION.getUri());
PROFILES.add(XACML3.ID_PROFILE_MULTIPLE_REFERENCE.getUri());
PROFILES.add(XACML3.ID_PROFILE_MULTIPLE_REPEATED_ATTRIBUTE_CATEGORIES.getUri());
PROFILES.add(XACML3.ID_PROFILE_MULTIPLE_SCOPE.getUri());
PROFILES.add(XACML3.ID_PROFILE_MULTIPLE_XPATH_EXPRESSION.getUri());
}
private EvaluationContextFactory evaluationContextFactory;
private Decision defaultDecision = Decision.INDETERMINATE;
private ScopeResolver scopeResolver;
private TraceEngine traceEngine;
private Log logger = LogFactory.getLog(this.getClass());
protected TraceEngine getTraceEngine() {
if (this.traceEngine == null) {
synchronized (this) {
if (this.traceEngine == null) {
try {
this.traceEngine = TraceEngineFactory.newInstance().getTraceEngine();
} catch (FactoryException ex) {
this.logger.error("FactoryException creating TraceEngine instance: " + ex.toString(),
ex);
throw new IllegalStateException("FactoryException creating TraceEngine instance", ex);
}
}
}
}
return this.traceEngine;
}
public OpenAZPDPEngine(EvaluationContextFactory evaluationContextFactoryIn, ScopeResolver scopeResolverIn) {
this.evaluationContextFactory = evaluationContextFactoryIn;
this.scopeResolver = scopeResolverIn;
}
public OpenAZPDPEngine(EvaluationContextFactory evaluationContextFactoryIn, Decision defaultDecisionIn,
ScopeResolver scopeResolverIn) {
this(evaluationContextFactoryIn, scopeResolverIn);
this.defaultDecision = defaultDecisionIn;
}
protected Result processRequest(EvaluationContext evaluationContext) {
try {
PolicyFinderResult<PolicyDef> policyFinderResult = evaluationContext.getRootPolicyDef();
if (policyFinderResult.getStatus() != null && !policyFinderResult.getStatus().isOk()) {
return new StdMutableResult(policyFinderResult.getStatus());
}
PolicyDef policyDefRoot = policyFinderResult.getPolicyDef();
if (policyDefRoot == null) {
switch (this.defaultDecision) {
case DENY:
case NOTAPPLICABLE:
case PERMIT:
return new StdMutableResult(this.defaultDecision,
new StdStatus(StdStatusCode.STATUS_CODE_OK,
"No applicable policy"));
case INDETERMINATE:
case INDETERMINATE_DENY:
case INDETERMINATE_DENYPERMIT:
case INDETERMINATE_PERMIT:
return new StdMutableResult(this.defaultDecision,
new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR,
"No applicable policy"));
}
}
Result result = policyDefRoot.evaluate(evaluationContext);
if (result.getStatus().isOk()) {
Collection<AttributeCategory> listRequestAttributesIncludeInResult = evaluationContext
.getRequest().getRequestAttributesIncludedInResult();
if (listRequestAttributesIncludeInResult != null
&& listRequestAttributesIncludeInResult.size() > 0) {
StdMutableResult stdMutableResult = new StdMutableResult(result);
stdMutableResult.addAttributeCategories(listRequestAttributesIncludeInResult);
result = new StdResult(stdMutableResult);
}
}
return result;
} catch (EvaluationException ex) {
return new StdMutableResult(new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR,
ex.getMessage()));
}
}
@Override
public Response decide(Request pepRequest) throws PDPException {
/*
* Validate the request
*/
TraceEngine traceEngineThis = this.getTraceEngine();
if (traceEngineThis.isTracing()) {
traceEngineThis.trace(new StdTraceEvent<Request>("Input Request", this, pepRequest));
}
Status statusRequest = pepRequest.getStatus();
if (statusRequest != null && !statusRequest.isOk()) {
return new StdMutableResponse(statusRequest);
}
/*
* Split the original request up into individual decision requests
*/
StdIndividualDecisionRequestGenerator stdIndividualDecisionRequestGenerator = new StdIndividualDecisionRequestGenerator(
this.scopeResolver,
pepRequest);
/*
* Determine if we are combining multiple results into a single result
*/
boolean bCombineResults = pepRequest.getCombinedDecision();
StdMutableResult stdResultCombined = null;
/*
* Iterate over all of the individual decision requests and process them, combining them into the
* final response
*/
StdMutableResponse stdResponse = new StdMutableResponse();
Iterator<Request> iterRequestsIndividualDecision = stdIndividualDecisionRequestGenerator
.getIndividualDecisionRequests();
if (iterRequestsIndividualDecision == null || !iterRequestsIndividualDecision.hasNext()) {
return new StdMutableResponse(new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR,
"No individual decision requests"));
}
while (iterRequestsIndividualDecision.hasNext()) {
Request requestIndividualDecision = iterRequestsIndividualDecision.next();
if (traceEngineThis.isTracing()) {
traceEngineThis.trace(new StdTraceEvent<Request>("Individual Request", this,
requestIndividualDecision));
}
Result resultIndividualDecision = null;
if (requestIndividualDecision.getStatus() != null
&& !requestIndividualDecision.getStatus().isOk()) {
resultIndividualDecision = new StdMutableResult(requestIndividualDecision.getStatus());
} else {
EvaluationContext evaluationContext = this.evaluationContextFactory
.getEvaluationContext(requestIndividualDecision);
if (evaluationContext == null) {
resultIndividualDecision = RESULT_ECTX_NULL;
} else {
resultIndividualDecision = this.processRequest(evaluationContext);
}
}
assert resultIndividualDecision != null;
if (traceEngineThis.isTracing()) {
traceEngineThis.trace(new StdTraceEvent<Result>("Individual Result", this,
resultIndividualDecision));
}
if (bCombineResults) {
Decision decision = resultIndividualDecision.getDecision();
Status status = resultIndividualDecision.getStatus();
if (resultIndividualDecision.getAssociatedAdvice().size() > 0) {
decision = Decision.INDETERMINATE;
status = STATUS_ADVICE_NA;
} else if (resultIndividualDecision.getObligations().size() > 0) {
decision = Decision.INDETERMINATE;
status = STATUS_OBLIGATIONS_NA;
}
if (stdResultCombined == null) {
stdResultCombined = new StdMutableResult(decision, status);
} else {
if (stdResultCombined.getDecision() != resultIndividualDecision.getDecision()) {
stdResultCombined.setDecision(Decision.INDETERMINATE);
stdResultCombined.setStatus(STATUS_COMBINE_FAILED);
}
}
stdResultCombined.addPolicyIdentifiers(resultIndividualDecision.getPolicyIdentifiers());
stdResultCombined.addPolicySetIdentifiers(resultIndividualDecision.getPolicySetIdentifiers());
stdResultCombined.addAttributeCategories(resultIndividualDecision.getAttributes());
if (traceEngineThis.isTracing()) {
traceEngineThis.trace(new StdTraceEvent<Result>("Combined result", this,
stdResultCombined));
}
} else {
stdResponse.add(resultIndividualDecision);
}
}
if (bCombineResults) {
stdResponse.add(stdResultCombined);
}
return stdResponse;
}
@Override
public Collection<URI> getProfiles() {
return Collections.unmodifiableCollection(PROFILES);
}
@Override
public boolean hasProfile(URI uriProfile) {
return PROFILES.contains(uriProfile);
}
@Override
public String getTraceId() {
return this.getClass().getCanonicalName();
}
@Override
public Traceable getCause() {
return null;
}
}