org.apache.openaz.xacml.pdp.std.StdPolicyFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.openaz.xacml.pdp.std.StdPolicyFinder.java

Source

/*
 *  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.
 *
 */

package org.apache.openaz.xacml.pdp.std;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.openaz.xacml.api.IdReferenceMatch;
import org.apache.openaz.xacml.api.Identifier;
import org.apache.openaz.xacml.api.Version;
import org.apache.openaz.xacml.pdp.eval.EvaluationContext;
import org.apache.openaz.xacml.pdp.eval.EvaluationException;
import org.apache.openaz.xacml.pdp.eval.MatchResult;
import org.apache.openaz.xacml.pdp.policy.Policy;
import org.apache.openaz.xacml.pdp.policy.PolicyDef;
import org.apache.openaz.xacml.pdp.policy.PolicyFinder;
import org.apache.openaz.xacml.pdp.policy.PolicyFinderResult;
import org.apache.openaz.xacml.pdp.policy.PolicySet;
import org.apache.openaz.xacml.pdp.policy.PolicySetChild;
import org.apache.openaz.xacml.pdp.policy.dom.DOMPolicyDef;
import org.apache.openaz.xacml.std.StdStatus;
import org.apache.openaz.xacml.std.StdStatusCode;

/**
 * StdPolicyFinder implements the {@link org.apache.openaz.xacml.pdp.policy.PolicyFinder} interface to look
 * up policies by their internal ID or an externally visible ID.
 */
public class StdPolicyFinder implements PolicyFinder {
    private static final PolicyFinderResult<PolicyDef> PFR_MULTIPLE = new StdPolicyFinderResult<PolicyDef>(
            new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, "Multiple applicable root policies"));
    private static final PolicyFinderResult<PolicyDef> PFR_NOT_FOUND = new StdPolicyFinderResult<PolicyDef>(
            new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, "No matching root policy found"));

    private static final PolicyFinderResult<Policy> PFR_POLICY_NOT_FOUND = new StdPolicyFinderResult<Policy>(
            new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, "No matching policy found"));
    private static final PolicyFinderResult<Policy> PFR_NOT_A_POLICY = new StdPolicyFinderResult<Policy>(
            new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, "Not a policy"));
    private static final PolicyFinderResult<PolicySet> PFR_POLICYSET_NOT_FOUND = new StdPolicyFinderResult<PolicySet>(
            new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, "No matching policy set found"));
    private static final PolicyFinderResult<PolicySet> PFR_NOT_A_POLICYSET = new StdPolicyFinderResult<PolicySet>(
            new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, "Not a policy set"));

    private Log logger = LogFactory.getLog(this.getClass());
    private List<PolicyDef> listRoots = new ArrayList<PolicyDef>();
    private Map<Identifier, List<PolicyDef>> mapPolicies = new HashMap<Identifier, List<PolicyDef>>();

    public static class StdPolicyFinderException extends Exception {
        private static final long serialVersionUID = -8969282995787463288L;

        public StdPolicyFinderException(String msg) {
            super(msg);
        }

        public StdPolicyFinderException(String msg, Throwable cause) {
            super(msg, cause);
        }
    }

    private void storeInPolicyMap(PolicyDef policyDef) {
        List<PolicyDef> listPolicyDefs = this.mapPolicies.get(policyDef.getIdentifier());
        if (listPolicyDefs == null) {
            listPolicyDefs = new ArrayList<PolicyDef>();
            this.mapPolicies.put(policyDef.getIdentifier(), listPolicyDefs);
        }
        listPolicyDefs.add(policyDef);
    }

    private <T extends PolicyDef> List<T> getFromPolicyMap(IdReferenceMatch idReferenceMatch,
            Class<T> classPolicyDef) {
        /*
         * Get all of the PolicyDefs for the Identifier in the reference match
         */
        List<PolicyDef> listPolicyDefForId = this.mapPolicies.get(idReferenceMatch.getId());
        if (listPolicyDefForId == null) {
            return null;
        }

        /*
         * Iterate over all of the PolicyDefs that were found and select only the ones that match the version
         * request and the isPolicySet
         */
        List<T> listPolicyDefMatches = null;
        Iterator<PolicyDef> iterPolicyDefs = listPolicyDefForId.iterator();
        while (iterPolicyDefs.hasNext()) {
            PolicyDef policyDef = iterPolicyDefs.next();
            if (classPolicyDef.isInstance(policyDef) && policyDef.matches(idReferenceMatch)) {
                if (listPolicyDefMatches == null) {
                    listPolicyDefMatches = new ArrayList<T>();
                }
                listPolicyDefMatches.add(classPolicyDef.cast(policyDef));
            }
        }

        return listPolicyDefMatches;
    }

    private <T extends PolicyDef> T getBestMatchN(List<T> matches) {
        T bestMatch = null;
        Version bestVersion = null;
        Iterator<T> iterMatches = matches.iterator();

        while (iterMatches.hasNext()) {
            T match = iterMatches.next();
            if (bestMatch == null) {
                bestMatch = match;
                bestVersion = match.getVersion();
            } else {
                Version matchVersion = match.getVersion();
                if (matchVersion != null && matchVersion.compareTo(bestVersion) > 0) {
                    bestMatch = match;
                    bestVersion = matchVersion;
                }
            }
        }
        return bestMatch;
    }

    private <T extends PolicyDef> T getBestMatch(List<T> matches) {
        switch (matches.size()) {
        case 0:
            return null;
        case 1:
            return matches.get(0);
        default:
            return this.getBestMatchN(matches);
        }
    }

    private PolicyDef loadPolicyDefFromURI(URI uri) throws StdPolicyFinderException {
        this.logger.info("Loading policy from URI " + uri.toString());
        URL url = null;
        try {
            url = uri.toURL();
            this.logger.debug("Loading policy from URL " + url.toString());
        } catch (MalformedURLException ex) {
            this.logger.debug("Unknown protocol for URI " + uri.toString());
            return null;
        }

        try (InputStream inputStream = url.openStream()) {
            return DOMPolicyDef.load(inputStream);
        } catch (Exception ex) {
            this.logger.error("Exception loading policy definition", ex);
            throw new StdPolicyFinderException(
                    "Exception loading policy def from \"" + uri.toString() + "\": " + ex.getMessage(), ex);
        }
    }

    /**
     * Looks up the given {@link org.apache.openaz.xacml.api.Identifier} in the map first. If not found, and
     * the <code>Identifier</code> contains a URL, then attempts to retrieve the document from the URL and
     * caches it.
     *
     * @param idReferenceMatch the <code>IdReferenceMatch</code> to look up
     * @return a <code>PolicyFinderResult</code> with the requested <code>Policy</code> or an error status
     */
    private PolicyFinderResult<Policy> lookupPolicyByIdentifier(IdReferenceMatch idReferenceMatch) {
        List<Policy> listCachedPolicies = this.getFromPolicyMap(idReferenceMatch, Policy.class);
        if (listCachedPolicies == null) {
            Identifier id = idReferenceMatch.getId();
            if (id != null) {
                URI uri = id.getUri();
                if (uri != null && uri.isAbsolute()) {
                    PolicyDef policyDef = null;
                    try {
                        policyDef = this.loadPolicyDefFromURI(uri);
                    } catch (StdPolicyFinderException ex) {
                        return new StdPolicyFinderResult<Policy>(
                                new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, ex.getMessage()));
                    }
                    if (policyDef != null) {
                        if (policyDef instanceof Policy) {
                            List<PolicyDef> listPolicyDefs = new ArrayList<PolicyDef>();
                            listPolicyDefs.add(policyDef);
                            this.mapPolicies.put(id, listPolicyDefs);
                            this.mapPolicies.put(policyDef.getIdentifier(), listPolicyDefs);
                            return new StdPolicyFinderResult<Policy>((Policy) policyDef);
                        } else {
                            return PFR_NOT_A_POLICY;
                        }
                    } else {
                        return PFR_POLICY_NOT_FOUND;
                    }
                }
            }
        }
        if (listCachedPolicies != null) {
            return new StdPolicyFinderResult<Policy>(this.getBestMatch(listCachedPolicies));
        } else {
            return PFR_POLICY_NOT_FOUND;
        }
    }

    /**
     * Looks up the given {@link org.apache.openaz.xacml.api.Identifier} in the map first. If not found, and
     * the <code>Identifier</code> contains a URL, then attempts to retrieve the document from the URL and
     * caches it.
     *
     * @param idReferenceMatch the <code>IdReferenceMatch</code> to look up
     * @return a <code>PolicyFinderResult</code> with the requested <code>PolicySet</code> or an error status
     */
    private PolicyFinderResult<PolicySet> lookupPolicySetByIdentifier(IdReferenceMatch idReferenceMatch) {
        List<PolicySet> listCachedPolicySets = this.getFromPolicyMap(idReferenceMatch, PolicySet.class);
        if (listCachedPolicySets == null) {
            Identifier id = idReferenceMatch.getId();
            if (id != null) {
                URI uri = id.getUri();
                if (uri != null && uri.isAbsolute()) {
                    PolicyDef policyDef = null;
                    try {
                        policyDef = this.loadPolicyDefFromURI(uri);
                    } catch (StdPolicyFinderException ex) {
                        return new StdPolicyFinderResult<PolicySet>(
                                new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, ex.getMessage()));
                    }
                    if (policyDef != null) {
                        if (policyDef instanceof PolicySet) {
                            List<PolicyDef> listPolicyDefs = new ArrayList<PolicyDef>();
                            listPolicyDefs.add(policyDef);
                            this.mapPolicies.put(id, listPolicyDefs);
                            this.mapPolicies.put(policyDef.getIdentifier(), listPolicyDefs);
                            return new StdPolicyFinderResult<PolicySet>((PolicySet) policyDef);
                        } else {
                            return PFR_NOT_A_POLICYSET;
                        }
                    } else {
                        return PFR_POLICYSET_NOT_FOUND;
                    }
                }
            }
        }
        if (listCachedPolicySets != null) {
            return new StdPolicyFinderResult<PolicySet>(this.getBestMatch(listCachedPolicySets));
        } else {
            return PFR_POLICYSET_NOT_FOUND;
        }
    }

    /**
     * Adds the given <code>PolicyDef</code> to the map of loaded <code>PolicyDef</code>s and adds its child
     * <code>PolicyDef</code>s recursively.
     *
     * @param policyDef the <code>PolicyDef</code> to add
     */
    private void updatePolicyMap(PolicyDef policyDef) {
        this.storeInPolicyMap(policyDef);
        if (policyDef instanceof PolicySet) {
            Iterator<PolicySetChild> iterChildren = ((PolicySet) policyDef).getChildren();
            if (iterChildren != null) {
                while (iterChildren.hasNext()) {
                    PolicySetChild policySetChild = iterChildren.next();
                    if (policySetChild instanceof PolicyDef) {
                        this.updatePolicyMap((PolicyDef) policySetChild);
                    }
                }
            }
        }
    }

    public StdPolicyFinder(Collection<PolicyDef> listRootPolicies, Collection<PolicyDef> referencedPolicyDefs) {
        if (listRootPolicies != null) {
            for (PolicyDef policyDef : listRootPolicies) {
                this.listRoots.add(policyDef);
                this.updatePolicyMap(policyDef);
            }
        }
        if (referencedPolicyDefs != null) {
            for (PolicyDef policyDef : referencedPolicyDefs) {
                this.storeInPolicyMap(policyDef);
            }
        }
    }

    /**
     * Creates a new <code>StdPolicyFinder</code> with the given <code>PolicyDef</code> as the root element.
     *
     * @param rootPolicyDef the <code>PolicyDef</code> acting as the root element
     */
    public StdPolicyFinder(PolicyDef rootPolicyDef, Collection<PolicyDef> referencedPolicyDefs) {
        if (rootPolicyDef != null) {
            this.listRoots.add(rootPolicyDef);
            this.updatePolicyMap(rootPolicyDef);
        }

        if (referencedPolicyDefs != null) {
            for (PolicyDef policyDef : referencedPolicyDefs) {
                this.storeInPolicyMap(policyDef);
            }
        }
    }

    @Override
    public PolicyFinderResult<PolicyDef> getRootPolicyDef(EvaluationContext evaluationContext) {
        PolicyDef policyDefFirstMatch = null;
        Iterator<PolicyDef> iterRootPolicies = this.listRoots.iterator();
        PolicyFinderResult<PolicyDef> firstIndeterminate = null;
        while (iterRootPolicies.hasNext()) {
            PolicyDef policyDef = iterRootPolicies.next();
            MatchResult matchResult = null;
            try {
                matchResult = policyDef.match(evaluationContext);
                switch (matchResult.getMatchCode()) {
                case INDETERMINATE:
                    if (firstIndeterminate == null) {
                        firstIndeterminate = new StdPolicyFinderResult<PolicyDef>(matchResult.getStatus());
                    }
                    break;
                case MATCH:
                    if (policyDefFirstMatch == null) {
                        policyDefFirstMatch = policyDef;
                    } else {
                        return PFR_MULTIPLE;
                    }
                    break;
                case NOMATCH:
                    break;
                }
            } catch (EvaluationException ex) {
                if (firstIndeterminate == null) {
                    firstIndeterminate = new StdPolicyFinderResult<PolicyDef>(
                            new StdStatus(StdStatusCode.STATUS_CODE_PROCESSING_ERROR, ex.getMessage()));
                }
            }
        }

        if (policyDefFirstMatch == null) {
            if (firstIndeterminate != null) {
                return firstIndeterminate;
            } else {
                return PFR_NOT_FOUND;
            }
        } else {
            return new StdPolicyFinderResult<PolicyDef>(policyDefFirstMatch);
        }
    }

    @Override
    public PolicyFinderResult<Policy> getPolicy(IdReferenceMatch idReferenceMatch) {
        return this.lookupPolicyByIdentifier(idReferenceMatch);
    }

    @Override
    public PolicyFinderResult<PolicySet> getPolicySet(IdReferenceMatch idReferenceMatch) {
        return this.lookupPolicySetByIdentifier(idReferenceMatch);
    }

    public void addReferencedPolicy(PolicyDef policyDef) {
        this.updatePolicyMap(policyDef);
    }
}