/* * 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.user; import java.util.Collections; import java.util.Set; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.jackrabbit.api.security.user.UserManager; import org.apache.jackrabbit.commons.predicate.Predicate; import org.apache.jackrabbit.core.NodeImpl; import org.apache.jackrabbit.core.nodetype.NodeTypeImpl; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.Path; import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; import org.apache.jackrabbit.util.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Resolver: searches for user and/or groups stored in Nodes of a {@link javax.jcr.Workspace} * which match a certain criteria */ abstract class NodeResolver { private static Logger log = LoggerFactory.getLogger(NodeResolver.class); private final Session session; private final NamePathResolver resolver; private String userSearchRoot = UserConstants.USERS_PATH; private String groupSearchRoot = UserConstants.GROUPS_PATH; private String authorizableSearchRoot = UserConstants.AUTHORIZABLES_PATH; /** * Create a new <code>NodeResolver</code>. * * @param session to use for repository access * @param resolver The NamePathResolver used to convert {@link org.apache.jackrabbit.spi.Name} * and {@link org.apache.jackrabbit.spi.Path} to JCR names/path. */ NodeResolver(Session session, NamePathResolver resolver) { this.session = session; this.resolver = resolver; } void setSearchRoots(String userSearchRoot, String groupSearchRoot) { this.userSearchRoot = userSearchRoot; this.groupSearchRoot = groupSearchRoot; authorizableSearchRoot = userSearchRoot; while (!Text.isDescendant(authorizableSearchRoot, groupSearchRoot)) { authorizableSearchRoot = Text.getRelativeParent(authorizableSearchRoot, 1); } } /** * Get the first node that matches <code>ntName</code> and whose name * exactly matches the given <code>nodeName</code>. * * @param nodeName Name of the node to find. * @param ntName Node type name of the node to find. * @return A matching node or <code>null</code>. * @throws RepositoryException If an error occurs. */ public abstract Node findNode(Name nodeName, Name ntName) throws RepositoryException; /** * Get the first node that matches <code>ntName</code> and has a * property whose value exactly matches the given value. Same as * {@link #findNodes(Set,String,Name,boolean,long)} but returning a single node or <code>null</code>. * * @param propertyName Name of the property to find. * @param value Value of the property to find. * @param ntName Name of the parent node's node type. * @return The first node that matches the specified node type name and has * a property with the given propertyName that exactly matches the given * value or <code>null</code>. * @throws RepositoryException If an error occurs. */ public abstract Node findNode(Name propertyName, String value, Name ntName) throws RepositoryException; /** * Search for Nodes which contain an exact match for the given value in * their property as indicated by the propertyName argument.<br> * Same as {@link #findNodes(Set,String,Name,boolean,long)}; where * the maxSize parameters is set to {@link Long#MAX_VALUE)}. * * @param propertyName Name of the property to be searched. * @param value Value to be matched. * @param ntName Name of the parent node's node type. * @param exact If <code>true</code> value has to match exactly. * @return matching nodes (or an empty iterator if no match was found). * @throws RepositoryException If an error occurs. */ public NodeIterator findNodes(Name propertyName, String value, Name ntName, boolean exact) throws RepositoryException { return findNodes(Collections.singleton(propertyName), value, ntName, exact, Long.MAX_VALUE); } /** * Search nodes. Take the arguments as search criteria. * The queried value has to be a string fragment of one of the Properties * contained in the given set. And the node have to be of a requested nodetype * * @param propertyNames Names of the property to be searched. * @param value The value to find. * @param ntName NodeType the hits have to have * @param exact if <code>true</code> match must be exact * @param maxSize maximal number of results to search for. * @return matching nodes (or an empty iterator if no match was found). * @throws RepositoryException If an error occurs. */ public abstract NodeIterator findNodes(Set<Name> propertyNames, String value, Name ntName, boolean exact, long maxSize) throws RepositoryException; /** * Search all properties underneath an authorizable of the specified type * that match the specified value and relative path. If the relative path * consists of a single name element the path constraint is omitted. * * @param relPath * @param value * @param authorizableType * @param exact * @param maxSize * @return * @throws RepositoryException */ public abstract NodeIterator findNodes(Path relPath, String value, int authorizableType, boolean exact, long maxSize) throws RepositoryException; /** * @return Session this instance has been constructed with. */ Session getSession() { return session; } /** * @return The <code>NamePathResolver</code>. */ NamePathResolver getNamePathResolver() { return resolver; } /** * @param ntName Any of the following node type names: * {@link UserConstants#NT_REP_USER}, {@link UserConstants#NT_REP_GROUP} or * {@link UserConstants#NT_REP_AUTHORIZABLE}. * @return The path of search root for the specified node type name. */ String getSearchRoot(Name ntName) { String searchRoot; if (UserConstants.NT_REP_USER.equals(ntName)) { searchRoot = userSearchRoot; } else if (UserConstants.NT_REP_GROUP.equals(ntName)) { searchRoot = groupSearchRoot; } else { searchRoot = authorizableSearchRoot; } return searchRoot; } /** * @param authorizableType * @return The path of search root for the specified authorizable type. */ String getSearchRoot(int authorizableType) { switch (authorizableType) { case UserManager.SEARCH_TYPE_USER: return userSearchRoot; case UserManager.SEARCH_TYPE_GROUP: return groupSearchRoot; default: return authorizableSearchRoot; } } /** * * @param authorizableType * @param exact If exact is true, the predicate only evaluates to true if the * passed node is of the required authorizable node type. Otherwise, all * ancestors are taken into account as well. * @return a new AuthorizableTypePredicate instance. */ AuthorizableTypePredicate getAuthorizableTypePredicate(int authorizableType, boolean exact) { return new AuthorizableTypePredicate(authorizableType, exact); } //-------------------------------------------------------------------------- /** * */ static class AuthorizableTypePredicate implements Predicate { private final int authorizableType; private final boolean exact; private AuthorizableTypePredicate(int authorizableType, boolean exact) { this.authorizableType = authorizableType; this.exact = exact; } /** * @see Predicate#evaluate(Object) */ public boolean evaluate(Object object) { if (object instanceof NodeImpl) { Node n = getAuthorizableNode((NodeImpl) object); return n != null; } return false; } Node getAuthorizableNode(NodeImpl n) { try { if (matches(n)) { return n; } if (!exact) { // walk up the node hierarchy to verify it is a child node // of an authorizable node of the expected type. while (n.getDepth() > 0) { n = (NodeImpl) n.getParent(); if (matches(n)) { return n; } } } } catch (RepositoryException e) { log.debug(e.getMessage()); } return null; } private boolean matches(NodeImpl result) throws RepositoryException { Name ntName = ((NodeTypeImpl) result.getPrimaryNodeType()).getQName(); switch (authorizableType) { case UserManager.SEARCH_TYPE_GROUP: return UserConstants.NT_REP_GROUP.equals(ntName); case UserManager.SEARCH_TYPE_USER: return UserConstants.NT_REP_USER.equals(ntName); default: return UserConstants.NT_REP_USER.equals(ntName) || UserConstants.NT_REP_GROUP.equals(ntName); } } } }