org.fcrepo.auth.xacml.FedoraPolicyFinderModule.java Source code

Java tutorial

Introduction

Here is the source code for org.fcrepo.auth.xacml.FedoraPolicyFinderModule.java

Source

/*
 * Licensed to DuraSpace under one or more contributor license agreements.
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership.
 *
 * DuraSpace 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.fcrepo.auth.xacml;

import static org.fcrepo.auth.xacml.URIConstants.POLICY_URI_PREFIX;
import static org.fcrepo.auth.xacml.URIConstants.XACML_POLICY_PROPERTY;
import static org.fcrepo.kernel.modeshape.FedoraSessionImpl.getJcrSession;
import static org.slf4j.LoggerFactory.getLogger;

import java.net.URI;

import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.fcrepo.http.commons.session.SessionFactory;
import org.fcrepo.kernel.api.FedoraSession;
import org.fcrepo.kernel.api.FedoraTypes;
import org.fcrepo.kernel.api.models.FedoraBinary;
import org.fcrepo.kernel.api.models.FedoraResource;
import org.fcrepo.kernel.api.services.BinaryService;
import org.fcrepo.kernel.api.services.NodeService;
import org.jboss.security.xacml.sunxacml.AbstractPolicy;
import org.jboss.security.xacml.sunxacml.EvaluationCtx;
import org.jboss.security.xacml.sunxacml.MatchResult;
import org.jboss.security.xacml.sunxacml.Policy;
import org.jboss.security.xacml.sunxacml.PolicyMetaData;
import org.jboss.security.xacml.sunxacml.PolicySet;
import org.jboss.security.xacml.sunxacml.VersionConstraints;
import org.jboss.security.xacml.sunxacml.attr.AttributeValue;
import org.jboss.security.xacml.sunxacml.cond.EvaluationResult;
import org.jboss.security.xacml.sunxacml.finder.PolicyFinder;
import org.jboss.security.xacml.sunxacml.finder.PolicyFinderModule;
import org.jboss.security.xacml.sunxacml.finder.PolicyFinderResult;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * Locates a policy in ModeShape by evaluation context or by URI.
 *
 * @author Gregory Jansen
 * @author bbpennel
 */
@Component("fedoraPolicyFinderModule")
public class FedoraPolicyFinderModule extends PolicyFinderModule {

    private static final Logger LOGGER = getLogger(FedoraPolicyFinderModule.class);

    @Inject
    private SessionFactory sessionFactory;

    @Inject
    private BinaryService binaryService;

    @Inject
    private NodeService nodeService;

    private PolicyFinder finder;

    /*
     * This policy finder can find by request context.
     * @see org.jboss.security.xacml.sunxacml.finder.PolicyFinderModule#
     * isRequestSupported()
     */
    @Override
    public final boolean isRequestSupported() {
        return true;
    }

    /*
     * This policy finder can find by reference (URI)
     * @see org.jboss.security.xacml.sunxacml.finder.PolicyFinderModule#
     * isIdReferenceSupported()
     */
    @Override
    public final boolean isIdReferenceSupported() {
        return true;
    }

    /**
     * Retrieves the policy from the given policy node
     *
     * @param policyBinary
     * @return
     */
    private AbstractPolicy getPolicy(final FedoraBinary policyBinary) {
        return loadPolicy(policyBinary);
    }

    /**
     * Creates a new policy or policy set object from the given policy node
     *
     * @param policyBinary
     * @return
     */
    private AbstractPolicy loadPolicy(final FedoraBinary policyBinary) {
        String policyName = "unparsed";
        try {
            // create the factory
            final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setIgnoringComments(true);
            factory.setNamespaceAware(true);
            factory.setValidating(false);

            final DocumentBuilder db = factory.newDocumentBuilder();

            // Parse the policy content
            final Document doc = db.parse(policyBinary.getContent());

            // handle the policy, if it's a known type
            final Element root = doc.getDocumentElement();
            final String name = root.getTagName();

            policyName = PolicyUtil.getID(doc);
            if (name.equals("Policy")) {
                return Policy.getInstance(root);
            } else if (name.equals("PolicySet")) {
                return PolicySet.getInstance(root, finder);
            } else {
                // this isn't a root type that we know how to handle
                throw new Exception("Unknown root document type: " + name);
            }
        } catch (final Exception e) {
            LOGGER.error("Unable to parse policy from {}", policyName, e);
        }

        // a default fall-through in the case of an error
        return null;
    }

    /*
     * Find a policy in ModeShape that is appropriate for the evaluation
     * context.
     * @see
     * org.jboss.security.xacml.sunxacml.finder.PolicyFinderModule#findPolicy
     * (org.jboss.security.xacml.sunxacml.EvaluationCtx)
     */
    @Override
    public final PolicyFinderResult findPolicy(final EvaluationCtx context) {
        final EvaluationResult ridEvalRes = context.getResourceAttribute(
                URI.create("http://www.w3.org/2001/XMLSchema#string"), URIConstants.ATTRIBUTEID_RESOURCE_ID, null);
        final AttributeValue resourceIdAttValue = ridEvalRes.getAttributeValue();
        String path = resourceIdAttValue.getValue().toString();

        LOGGER.debug("Finding policy for resource: {}", path);

        if ("".equals(path.trim())) {
            path = "/";
        }

        try {
            final FedoraSession internalSession = sessionFactory.getInternalSession();

            // Walk up the hierarchy to find the first node with a policy assigned
            Node nodeWithPolicy = PolicyUtil.getFirstRealNode(path, getJcrSession(internalSession));
            while (nodeWithPolicy != null && !nodeWithPolicy.hasProperty(XACML_POLICY_PROPERTY)) {
                nodeWithPolicy = nodeWithPolicy.getParent();
            }

            // This should never happen, as PolicyUtil.getFirstRealNode() at least returns the root node.
            if (null == nodeWithPolicy) {
                LOGGER.warn("No policy found for: {}!", path);
                return new PolicyFinderResult();
            }

            final Property prop = nodeWithPolicy.getProperty(XACML_POLICY_PROPERTY);

            final FedoraBinary policyBinary;
            final FedoraResource resource = nodeService.find(internalSession, prop.getNode().getPath());
            if (resource.hasType(FedoraTypes.FEDORA_NON_RDF_SOURCE_DESCRIPTION)) {
                policyBinary = binaryService.findOrCreate(internalSession, resource.getPath());

            } else {
                LOGGER.warn("Policy Binary not found for: {}", path);
                return new PolicyFinderResult();
            }

            if (policyBinary == null) {
                LOGGER.warn("Policy binary for path: {} was null!", nodeWithPolicy.getPath());
                return new PolicyFinderResult();
            }

            final AbstractPolicy policy = getPolicy(policyBinary);

            // Evaluate if the policy targets match the current context
            final MatchResult match = policy.match(context);
            final int result = match.getResult();

            if (result == MatchResult.INDETERMINATE) {
                return new PolicyFinderResult(match.getStatus());
            }

            // Found a good policy, return it
            if (result == MatchResult.MATCH) {
                return new PolicyFinderResult(policy);
            }

            return new PolicyFinderResult();
        } catch (final RepositoryException e) {
            LOGGER.warn("Failed to retrieve a policy for {}", e, path);
            return new PolicyFinderResult();
        }
    }

    /*
     * Find a policy in ModeShape by reference URI.
     * @see
     * org.jboss.security.xacml.sunxacml.finder.PolicyFinderModule#findPolicy
     * (java.net.URI, int, org.jboss.security.xacml.sunxacml.VersionConstraints,
     * org.jboss.security.xacml.sunxacml.PolicyMetaData)
     */
    @Override
    public final PolicyFinderResult findPolicy(final URI idReference, final int type,
            final VersionConstraints constraints, final PolicyMetaData parentMetaData) {
        final String id = idReference.toString();
        if (!id.startsWith(POLICY_URI_PREFIX)) {
            LOGGER.warn("Policy reference must begin with {}, but was {}", POLICY_URI_PREFIX, id);
            return new PolicyFinderResult();
        }

        final String path = PolicyUtil.getPathForId(id);
        final FedoraSession internalSession = sessionFactory.getInternalSession();

        final FedoraBinary policyBinary;
        final FedoraResource resource = nodeService.find(internalSession, path);
        if (resource.hasType(FedoraTypes.FEDORA_NON_RDF_SOURCE_DESCRIPTION)) {
            policyBinary = binaryService.findOrCreate(internalSession, resource.getPath());

        } else {
            LOGGER.warn("Policy Binary not found for: {}", path);
            return new PolicyFinderResult();
        }

        final AbstractPolicy policy = getPolicy(policyBinary);

        return new PolicyFinderResult(policy);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.jboss.security.xacml.sunxacml.finder.PolicyFinderModule#init(org.
     * jboss.security.xacml.sunxacml.finder.PolicyFinder)
     */
    @Override
    public void init(final PolicyFinder finder) {
        this.finder = finder;
    }

}