Package org.apache.jackrabbit.core.security.principal

Source Code of org.apache.jackrabbit.core.security.principal.DefaultPrincipalProvider$PrincipalIteratorImpl

/*
* 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.jackrabbit.core.security.principal;

import org.apache.commons.collections.iterators.IteratorChain;
import org.apache.commons.collections.map.LRUMap;
import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.security.SystemPrincipal;
import org.apache.jackrabbit.core.security.user.UserManagerImpl;
import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.security.auth.Subject;
import java.security.Principal;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
* Provides principals for the users contained within the Repository.<p/>
* Each {@link Authorizable} accessible via {@link UserManager}
* is respected and the provider serves {@link Authorizable#getPrincipal()
* Principal}s retrieved from those <code>Authorizable</code> objects.
* <p/>
* In addition this provider exposes the <i>everyone</i> principal, which has no
* content (user/group) represention.
*/
public class DefaultPrincipalProvider extends AbstractPrincipalProvider implements EventListener {

    /**
     * the default logger
     */
    private static Logger log = LoggerFactory.getLogger(DefaultPrincipalProvider.class);

    /**
     * a cache for group memberships: maps principal-name to a set of principals
     * representing the members.
     */
    private final Map<String, Set<Principal>> membershipCache;

    /**
     * Principal-Base of this Provider
     */
    private final UserManagerImpl userManager;

    private final EveryonePrincipal everyonePrincipal;

    private final String pMembers;
    private final String pPrincipalName;

    /**
     * Creates a new DefaultPrincipalProvider reading the principals from the
     * storage below the given security root node.
     *
     * @param securitySession for repository access.
     * @param userManager Used to retrieve the principals.
     * @throws RepositoryException if an error accessing the repository occurs.
     */
    public DefaultPrincipalProvider(Session securitySession,
                                    UserManagerImpl userManager) throws RepositoryException {

        this.userManager = userManager;
        everyonePrincipal = EveryonePrincipal.getInstance();
        membershipCache = new LRUMap();

        // listen to modifications of group-membership
        String[] ntNames = new String[1];
        if (securitySession instanceof SessionImpl) {
            NameResolver resolver = (SessionImpl) securitySession;
            ntNames[0] = resolver.getJCRName(UserManagerImpl.NT_REP_GROUP);
            pMembers = resolver.getJCRName(UserManagerImpl.P_MEMBERS);
            pPrincipalName = resolver.getJCRName(UserManagerImpl.P_PRINCIPAL_NAME);
        } else {
            ntNames[0] = "rep:Group";
            pMembers = "rep:members";
            pPrincipalName = "rep:principalName";
        }

        String groupPath = userManager.getGroupsPath();
        securitySession.getWorkspace().getObservationManager().addEventListener(this,
                Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED,
                groupPath,
                true,
                null,
                ntNames,
                false);
    }

    //------------------------------------------< AbstractPrincipalProvider >---
    /**
     * {@inheritDoc}
     * <p/>
     * This implementation uses the user and node resolver to find the
     * appropriate nodes.
     */
    protected Principal providePrincipal(String principalName) {
        // check for 'everyone'
        if (everyonePrincipal.getName().equals(principalName)) {
            return everyonePrincipal;
        }
        try {
            Principal principal = new PrincipalImpl(principalName);
            Authorizable ath = userManager.getAuthorizable(principal);
            if (ath != null) {
                return ath.getPrincipal();
            }
        } catch (RepositoryException e) {
            log.error("Failed to access Authorizable for Principal " + principalName, e);
        }
        return null;
    }

    //--------------------------------------------------< PrincipalProvider >---
    /**
     * @see PrincipalProvider#findPrincipals(String)
     */
    public PrincipalIterator findPrincipals(String simpleFilter) {
        return findPrincipals(simpleFilter, PrincipalManager.SEARCH_TYPE_ALL);
    }

    /**
     * @see PrincipalProvider#findPrincipals(String, int)
     */
    public PrincipalIterator findPrincipals(String simpleFilter, int searchType) {
        checkInitialized();
        switch (searchType) {
            case PrincipalManager.SEARCH_TYPE_GROUP:
                return findGroupPrincipals(simpleFilter);
            case PrincipalManager.SEARCH_TYPE_NOT_GROUP:
                return findUserPrincipals(simpleFilter);
            case PrincipalManager.SEARCH_TYPE_ALL:
                PrincipalIterator[] its = new PrincipalIterator[] {
                        findUserPrincipals(simpleFilter),
                        findGroupPrincipals(simpleFilter)
                };
                return new PrincipalIteratorAdapter(new IteratorChain(its));
            default:
                throw new IllegalArgumentException("Invalid searchType");
        }
    }

    /**
     * @see PrincipalProvider#getPrincipals(int)
     * @param searchType Any of the following search types:
     * <ul>
     * <li>{@link PrincipalManager#SEARCH_TYPE_GROUP}</li>
     * <li>{@link PrincipalManager#SEARCH_TYPE_NOT_GROUP}</li>
     * <li>{@link PrincipalManager#SEARCH_TYPE_ALL}</li>
     * </ul>
     * @see PrincipalProvider#getPrincipals(int)
     */
    public PrincipalIterator getPrincipals(int searchType) {
        return findPrincipals(null, searchType);
    }

    /**
     * @see PrincipalProvider#getGroupMembership(Principal)
     */
    public PrincipalIterator getGroupMembership(Principal userPrincipal) {
        checkInitialized();
        Set<Principal> mship;
        synchronized (membershipCache) {
            mship = membershipCache.get(userPrincipal.getName());
            if (mship == null) {
                // recursively collect group membership
                mship = collectGroupMembership(userPrincipal);

                // make sure everyone-group is not missing
                if (!mship.contains(everyonePrincipal) && everyonePrincipal.isMember(userPrincipal)) {
                    mship.add(everyonePrincipal);
                }
                membershipCache.put(userPrincipal.getName(), mship);
            }
        }
        return new PrincipalIteratorAdapter(mship);

    }

    /**
     * @see PrincipalProvider#close()
     */
    public synchronized void close() {
        super.close();
        membershipCache.clear();
    }

    /**
     * @see PrincipalProvider#canReadPrincipal(javax.jcr.Session,java.security.Principal)
     */
    public boolean canReadPrincipal(Session session, Principal principal) {
        checkInitialized();
        // check if the session can read the user/group associated with the
        // given principal
        if (session instanceof SessionImpl) {
            SessionImpl sImpl = (SessionImpl) session;
            Subject subject = sImpl.getSubject();
            if (!subject.getPrincipals(SystemPrincipal.class).isEmpty()
                    || !subject.getPrincipals(AdminPrincipal.class).isEmpty()) {
                return true;
            }
            try {
                UserManager umgr = sImpl.getUserManager();
                return umgr.getAuthorizable(principal) != null;
            } catch (RepositoryException e) {
                // ignore and return false
            }
        }
        return false;
    }

    //------------------------------------------------------< EventListener >---
    /**
     * @see EventListener#onEvent(EventIterator)
     */
    public void onEvent(EventIterator eventIterator) {
        // superclass: flush all cached
        clearCache();

        // membership cache:
        while (eventIterator.hasNext()) {
            Event ev = eventIterator.nextEvent();
            int type = ev.getType();
            if (type == Event.PROPERTY_ADDED || type == Event.PROPERTY_CHANGED
                    || type == Event.PROPERTY_REMOVED) {
                try {
                    if (pMembers.equals(Text.getName(ev.getPath()))) {
                        synchronized (membershipCache) {
                            membershipCache.clear();
                        }
                        break;
                    }
                } catch (RepositoryException e) {
                    // should never get here
                    log.warn(e.getMessage());
                }
            }
        }
    }

    //--------------------------------------------------------------------------
    /**
     * Recursively collect all Group-principals the specified principal is
     * member of.
     *
     * @param princ Principal for which the group membership will be collected.
     * @return all Group principals the specified <code>princ</code> is member of
     * including inherited membership.
     */
    private Set<Principal> collectGroupMembership(Principal princ) {
        final Set<Principal> membership = new LinkedHashSet<Principal>();
            try {
                final Authorizable auth = userManager.getAuthorizable(princ);
                if (auth != null) {
                    addToCache(princ);
                    Iterator<Group> itr = auth.memberOf();
                    while (itr.hasNext()) {
                        Group group = itr.next();
                        Principal gp = group.getPrincipal();
                        addToCache(gp);
                        membership.add(gp);
                    }
                } else {
                    log.debug("Cannot find authorizable for principal " + princ.getName());
                }
            } catch (RepositoryException e) {
                log.warn("Failed to determine membership for " + princ.getName(), e.getMessage());
            }
        return membership;
    }

    /**
     * @param simpleFilter Principal name or fragment.
     * @return An iterator over the main principals of the authorizables found
     * by the user manager.
     */
    private PrincipalIterator findUserPrincipals(String simpleFilter) {
        synchronized (userManager) {
            try {
                Iterator<Authorizable> itr = userManager.findAuthorizables(pPrincipalName, simpleFilter, UserManager.SEARCH_TYPE_USER);
                return new PrincipalIteratorImpl(itr, false);
            } catch (RepositoryException e) {
                log.error("Error while searching user principals.", e);
                return PrincipalIteratorAdapter.EMPTY;
            }
        }
    }

    /**
     * @param simpleFilter Principal name or fragment.
     * @return An iterator over the main principals of the authorizables found
     * by the user manager.
     */
    private PrincipalIterator findGroupPrincipals(final String simpleFilter) {
        synchronized (userManager) {
            try {
                Iterator<Authorizable> itr = userManager.findAuthorizables(pPrincipalName, simpleFilter, UserManager.SEARCH_TYPE_GROUP);

                // everyone will not be found by the user manager -> extra test
                boolean addEveryone = everyonePrincipal.getName().matches(".*"+simpleFilter+".*");
                return new PrincipalIteratorImpl(itr, addEveryone);

            } catch (RepositoryException e) {
                log.error("Error while searching group principals.", e);
                return PrincipalIteratorAdapter.EMPTY;
            }
        }
    }

    //--------------------------------------------------------< inner class >---
    /**
     * Extension of AbstractPrincipalIterator that retrieves the next
     * principal from the iterator over authorizables by calling
     * {@link Authorizable#getPrincipal()}.
     */
    private class PrincipalIteratorImpl extends AbstractPrincipalIterator {

        private final Iterator<Authorizable> authorizableItr;
        private boolean addEveryone;

        private PrincipalIteratorImpl(Iterator<Authorizable> authorizableItr, boolean addEveryone) {
            this.authorizableItr = authorizableItr;
            this.addEveryone = addEveryone;

            next = seekNext();
        }

        /**
         * @see org.apache.jackrabbit.core.security.principal.AbstractPrincipalIterator#seekNext()
         */
        protected Principal seekNext() {
            while (authorizableItr.hasNext()) {
                try {
                    Principal p = authorizableItr.next().getPrincipal();
                    addToCache(p);
                    return p;
                } catch (RepositoryException e) {
                    // should never get here
                    log.warn("Error while retrieving principal from group -> skip.");
                }
            }

            if (addEveryone) {
                addEveryone = false; // make sure iteration stops
                return everyonePrincipal;
            } else {
                // end of iteration reached
                return null;
            }
        }
    }
}
TOP

Related Classes of org.apache.jackrabbit.core.security.principal.DefaultPrincipalProvider$PrincipalIteratorImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.