001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.auth.xacml;
019
020import static org.fcrepo.kernel.modeshape.FedoraSessionImpl.getJcrSession;
021import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.isInternalNode;
022import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
023import static org.jboss.security.xacml.sunxacml.ctx.Status.STATUS_PROCESSING_ERROR;
024
025import java.util.HashMap;
026import java.util.HashSet;
027import java.util.Set;
028
029import javax.inject.Inject;
030import javax.jcr.Node;
031import javax.jcr.NodeIterator;
032import javax.jcr.RepositoryException;
033
034import org.fcrepo.http.commons.session.SessionFactory;
035import org.fcrepo.kernel.api.FedoraSession;
036
037import org.jboss.security.xacml.sunxacml.EvaluationCtx;
038import org.jboss.security.xacml.sunxacml.attr.AttributeValue;
039import org.jboss.security.xacml.sunxacml.finder.ResourceFinderModule;
040import org.jboss.security.xacml.sunxacml.finder.ResourceFinderResult;
041import org.springframework.stereotype.Component;
042
043
044/**
045 * Locates resources that are subordinate to a Fedora resource.
046 * @author Gregory Jansen
047 * @author Esme Cowles
048 */
049@Component("fedoraResourceFinderModule")
050public class FedoraResourceFinderModule extends ResourceFinderModule {
051
052    /**
053     * Fedora's ModeShape session factory.
054     */
055    @Inject
056    protected SessionFactory sessionFactory;
057
058    /*
059     * Does find child resources.
060     * @see org.jboss.security.xacml.sunxacml.finder.ResourceFinderModule#
061     * isChildSupported()
062     */
063    @Override
064    public final boolean isChildSupported() {
065        return true;
066    }
067
068    /*
069     * Does find descendant resources.
070     * @see org.jboss.security.xacml.sunxacml.finder.ResourceFinderModule#
071     * isDescendantSupported()
072     */
073    @Override
074    public final boolean isDescendantSupported() {
075        return true;
076    }
077
078    /*
079     * Finds ModeShape child resources based on parent ID and evaluation
080     * context.
081     * @see org.jboss.security.xacml.sunxacml.finder.ResourceFinderModule#
082     * findChildResources(org.jboss.security.xacml.sunxacml.attr.AttributeValue,
083     * org.jboss.security.xacml.sunxacml.EvaluationCtx)
084     */
085    @Override
086    public final ResourceFinderResult findChildResources(
087            final AttributeValue parentResourceId,
088            final EvaluationCtx context) {
089        return findChildren( parentResourceId, false );
090    }
091
092    /*
093     * Finds ModeShape descendant resources based on parent ID and evaluation
094     * context.
095     * @see org.jboss.security.xacml.sunxacml.finder.ResourceFinderModule#
096     * findDescendantResources
097     * (org.jboss.security.xacml.sunxacml.attr.AttributeValue,
098     * org.jboss.security.xacml.sunxacml.EvaluationCtx)
099     */
100    @Override
101    public final ResourceFinderResult findDescendantResources(
102            final AttributeValue parentResourceId,
103            final EvaluationCtx context) {
104        return findChildren( parentResourceId, true );
105    }
106
107    /**
108     * Find the child resources (or all descendant resources) of a path.
109     * @param parent Repository path to find children of.
110     * @param recurse If true, find all descenant resources, not just direct children.
111    **/
112    private ResourceFinderResult findChildren( final AttributeValue parent, final boolean recurse ) {
113        try {
114            final FedoraSession session = sessionFactory.getInternalSession();
115            final Node node = getJcrSession(session).getNode( parent.getValue().toString() );
116            final Set<String> children = new HashSet<>();
117            findChildren( node, children, recurse );
118            return new ResourceFinderResult( children );
119        } catch ( final RepositoryException ex ) {
120            final HashMap<AttributeValue, String> errors = new HashMap<>();
121            errors.put( parent, STATUS_PROCESSING_ERROR );
122            return new ResourceFinderResult( errors );
123        }
124    }
125
126    /**
127     * Find children of a node.
128     * @param node Repository node to find children of
129     * @param children Set to add child paths to
130     * @param If true, find all descendant paths, not just direct child paths
131    **/
132    private void findChildren( final Node node, final Set<String> children, final boolean recurse )
133        throws RepositoryException {
134        for ( final NodeIterator nodes = node.getNodes(); nodes.hasNext(); ) {
135            final Node child = nodes.nextNode();
136            if ( !isInternalNode.test(child) && !child.getName().equals(JCR_CONTENT) ) {
137
138                children.add( child.getPath() );
139
140                if ( recurse ) {
141                    findChildren( child, children, recurse );
142                }
143            }
144        }
145    }
146}