You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2008/03/19 14:57:11 UTC
svn commit: r638834 [9/14] - in /jackrabbit/trunk:
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/
jackr...
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleSecurityManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleSecurityManager.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleSecurityManager.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleSecurityManager.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,321 @@
+/*
+ * 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.simple;
+
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.config.AccessManagerConfig;
+import org.apache.jackrabbit.core.config.LoginModuleConfig;
+import org.apache.jackrabbit.core.config.SecurityConfig;
+import org.apache.jackrabbit.core.security.AMContext;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.AnonymousPrincipal;
+import org.apache.jackrabbit.core.security.JackrabbitSecurityManager;
+import org.apache.jackrabbit.core.security.UserPrincipal;
+import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.core.security.principal.PrincipalIteratorAdapter;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.core.security.authentication.AuthContext;
+import org.apache.jackrabbit.core.security.authentication.AuthContextProvider;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.apache.jackrabbit.core.security.principal.ProviderRegistryImpl;
+import org.apache.jackrabbit.core.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.core.security.principal.PrincipalManagerImpl;
+import org.apache.jackrabbit.core.security.principal.PrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * <code>SimpleSecurityManager</code>: simple implementation ignoring both
+ * configuration entries for 'principalProvider' and for 'workspaceAccessManager'.
+ * The AccessManager is initialized using
+ * {@link AccessManager#init(org.apache.jackrabbit.core.security.AMContext)}.
+ */
+public class SimpleSecurityManager implements JackrabbitSecurityManager {
+
+ private static Logger log = LoggerFactory.getLogger(SimpleSecurityManager.class);
+
+ private boolean initialized;
+
+ private SecurityConfig config;
+
+ /**
+ * session on the system workspace.
+ */
+ private Session systemSession;
+
+ /**
+ * the principal provider registry
+ */
+ private PrincipalProviderRegistry principalProviderRegistry;
+
+ /**
+ * factory for login-context {@see Repository#login())
+ */
+ private AuthContextProvider authCtxProvider;
+
+ private String adminID;
+ private String anonymID;
+
+ //------------------------------------------< JackrabbitSecurityManager >---
+ public void init(Repository repository, Session systemSession) throws RepositoryException {
+ if (initialized) {
+ throw new IllegalStateException("already initialized");
+ }
+ if (!(repository instanceof RepositoryImpl)) {
+ throw new RepositoryException("RepositoryImpl expected");
+ }
+
+ this.systemSession = systemSession;
+ config = ((RepositoryImpl) repository).getConfig().getSecurityConfig();
+
+ // read the LoginModule configuration
+ LoginModuleConfig loginModConf = config.getLoginModuleConfig();
+ authCtxProvider = new AuthContextProvider(config.getAppName(), loginModConf);
+ if (authCtxProvider.isJAAS()) {
+ log.info("init: using JAAS LoginModule configuration for " + config.getAppName());
+ } else if (authCtxProvider.isLocal()) {
+ log.info("init: using Repository LoginModule configuration for " + config.getAppName());
+ } else {
+ String msg = "No valid LoginModule configuriation for " + config.getAppName();
+ log.error(msg);
+ throw new RepositoryException(msg);
+ }
+
+ Properties[] moduleConfig = authCtxProvider.getModuleConfig();
+
+ // retrieve default-ids (admin and anomymous) from login-module-configuration.
+ for (int i = 0; i < moduleConfig.length; i++) {
+ if (moduleConfig[i].containsKey(LoginModuleConfig.PARAM_ADMIN_ID)) {
+ adminID = moduleConfig[i].getProperty(LoginModuleConfig.PARAM_ADMIN_ID);
+ }
+ if (moduleConfig[i].containsKey(LoginModuleConfig.PARAM_ANONYMOUS_ID)) {
+ anonymID = moduleConfig[i].getProperty(LoginModuleConfig.PARAM_ANONYMOUS_ID, null);
+ }
+ }
+ // most simple principal provider registry, that does not read anything
+ // from configuration
+ PrincipalProvider principalProvider = new SimplePrincipalProvider();
+ // skip init of provider (nop)
+ principalProviderRegistry = new ProviderRegistryImpl(principalProvider);
+ // register all configured principal providers.
+ for (int i = 0; i < moduleConfig.length; i++) {
+ principalProviderRegistry.registerProvider(moduleConfig[i]);
+ }
+
+ initialized = true;
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#dispose(String)
+ */
+ public void dispose(String workspaceName) {
+ checkInitialized();
+ // nop
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#close()
+ */
+ public void close() {
+ checkInitialized();
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getSecurityConfig()
+ */
+ public SecurityConfig getSecurityConfig() throws RepositoryException {
+ return config;
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getAccessManager(Session,AMContext)
+ */
+ public AccessManager getAccessManager(Session session, AMContext amContext) throws RepositoryException {
+ checkInitialized();
+ try {
+ AccessManagerConfig amc = config.getAccessManagerConfig();
+ AccessManager accessMgr;
+ if (amc == null) {
+ accessMgr = new SimpleAccessManager();
+ } else {
+ accessMgr = (AccessManager) amc.newInstance();
+ }
+ accessMgr.init(amContext);
+ return accessMgr;
+ } catch (AccessDeniedException ade) {
+ // re-throw
+ throw ade;
+ } catch (Exception e) {
+ // wrap in RepositoryException
+ String msg = "failed to instantiate AccessManager implementation: " + SimpleAccessManager.class.getName();
+ log.error(msg, e);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getPrincipalManager(Session)
+ */
+ public synchronized PrincipalManager getPrincipalManager(Session session)
+ throws RepositoryException {
+ checkInitialized();
+ if (session instanceof SessionImpl) {
+ SessionImpl sImpl = ((SessionImpl)session);
+ return new PrincipalManagerImpl(sImpl, principalProviderRegistry.getProviders());
+ } else {
+ throw new RepositoryException("Internal error: SessionImpl expected.");
+ }
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getUserManager(Session)
+ */
+ public UserManager getUserManager(Session session) throws RepositoryException {
+ checkInitialized();
+ throw new UnsupportedRepositoryOperationException("UserManager not supported.");
+ }
+
+ /**
+ * Creates an AuthContext for the given {@link Credentials} and
+ * {@link Subject}.<br>
+ * This includes selection of applicatoin specific LoginModules and
+ * initalization with credentials and Session to System-Workspace
+ *
+ * @return an {@link AuthContext} for the given Credentials, Subject
+ * @throws RepositoryException in other exceptional repository states
+ */
+ public AuthContext getAuthContext(Credentials creds, Subject subject)
+ throws RepositoryException {
+ checkInitialized();
+ return authCtxProvider.getAuthContext(creds, subject, systemSession, principalProviderRegistry);
+ }
+
+ //--------------------------------------------------------------------------
+ private void checkInitialized() {
+ if (!initialized) {
+ throw new IllegalStateException("Not initialized");
+ }
+ }
+
+ /**
+ * Simple Principal provider
+ */
+ private class SimplePrincipalProvider implements PrincipalProvider {
+
+ private final Map principals = new HashMap();
+
+ private SimplePrincipalProvider() {
+ if (adminID != null) {
+ principals.put(adminID, new AdminPrincipal(adminID));
+ }
+ if (anonymID != null) {
+ principals.put(anonymID, new AnonymousPrincipal());
+ }
+ EveryonePrincipal everyone = EveryonePrincipal.getInstance();
+ principals.put(everyone.getName(), everyone);
+
+ }
+
+ public boolean hasPrincipal(String principalName) {
+ return true;
+ }
+
+ public Principal getPrincipal(String principalName) {
+ if (principals.containsKey(principalName)) {
+ return (Principal) principals.get(principalName);
+ } else {
+ return new UserPrincipal(principalName);
+ }
+ }
+
+ public PrincipalIterator findPrincipals(String simpleFilter) {
+ return findPrincipals(simpleFilter, PrincipalManager.SEARCH_TYPE_ALL);
+ }
+
+ public PrincipalIterator findPrincipals(String simpleFilter, int searchType) {
+ Principal p = getPrincipal(simpleFilter);
+ if (p == null) {
+ return PrincipalIteratorAdapter.EMPTY;
+ } else if (p instanceof Group && searchType == PrincipalManager.SEARCH_TYPE_NOT_GROUP ||
+ !(p instanceof Group) && searchType == PrincipalManager.SEARCH_TYPE_GROUP) {
+ return PrincipalIteratorAdapter.EMPTY;
+ } else {
+ return new PrincipalIteratorAdapter(Collections.singletonList(p));
+ }
+ }
+
+ public PrincipalIterator getPrincipals(int searchType) {
+ PrincipalIterator it;
+ switch (searchType) {
+ case PrincipalManager.SEARCH_TYPE_GROUP:
+ it = new PrincipalIteratorAdapter(Collections.singletonList(EveryonePrincipal.getInstance()));
+ break;
+ case PrincipalManager.SEARCH_TYPE_NOT_GROUP:
+ Set set = new HashSet(principals.values());
+ set.remove(EveryonePrincipal.getInstance());
+ it = new PrincipalIteratorAdapter(set);
+ break;
+ case PrincipalManager.SEARCH_TYPE_ALL:
+ it = new PrincipalIteratorAdapter(principals.values());
+ break;
+ // no default
+ default:
+ throw new IllegalArgumentException("Unknown search type " + searchType);
+ }
+ return it;
+ }
+
+ public PrincipalIterator getGroupMembership(Principal principal) {
+ if (principal instanceof EveryonePrincipal) {
+ return PrincipalIteratorAdapter.EMPTY;
+ } else {
+ return new PrincipalIteratorAdapter(Collections.singletonList(EveryonePrincipal.getInstance()));
+ }
+ }
+
+ public void init(Properties options) {
+ // nothing to do
+ }
+
+ public void close() {
+ // nothing to do
+ }
+
+ public boolean canReadPrincipal(Session session, Principal principal) {
+ return true;
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleSecurityManager.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleSecurityManager.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,338 @@
+/*
+ * 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 org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.PropertyImpl;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.core.security.principal.ItemBasedPrincipal;
+import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.core.security.principal.PrincipalIteratorAdapter;
+import org.apache.jackrabbit.spi.Name;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.ConstraintViolationException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * AuthorizableImpl
+ */
+abstract class AuthorizableImpl implements Authorizable, UserConstants {
+
+ static final Logger log = LoggerFactory.getLogger(AuthorizableImpl.class);
+
+ final UserManagerImpl userManager;
+ private final NodeImpl node;
+
+ /**
+ * @param node the Authorizable is persisted to.
+ * @param userManager UserManager that created this Authorizable.
+ * @throws RepositoryException
+ */
+ protected AuthorizableImpl(NodeImpl node, UserManagerImpl userManager)
+ throws RepositoryException {
+ if (!node.isNodeType(NT_REP_AUTHORIZABLE)) {
+ throw new IllegalArgumentException("Node argument of NodeType " + NT_REP_AUTHORIZABLE + " required");
+ }
+ this.node = node;
+ this.userManager = userManager;
+ }
+
+ //-------------------------------------------------------< Authorizable >---
+ /**
+ * @see Authorizable#getPrincipals()
+ */
+ public PrincipalIterator getPrincipals() throws RepositoryException {
+ Collection coll = new ArrayList();
+ // the first element is the main principal of this user.
+ coll.add(getPrincipal());
+ // in addition add all referees.
+ PrincipalManager prMgr = getSession().getPrincipalManager();
+ for (Iterator it = getRefereeValues().iterator(); it.hasNext();) {
+ String refName = ((Value) it.next()).getString();
+ if (prMgr.hasPrincipal(refName)) {
+ coll.add(prMgr.getPrincipal(refName));
+ } else {
+ log.warn("Principal "+ refName +" unknown to PrincipalManager.");
+ coll.add(new PrincipalImpl(refName));
+ }
+ }
+ return new PrincipalIteratorAdapter(coll);
+ }
+
+ /**
+ * @see Authorizable#addReferee(Principal)
+ */
+ public synchronized boolean addReferee(Principal principal) throws RepositoryException {
+ String principalName = principal.getName();
+ Value princValue = getSession().getValueFactory().createValue(principalName);
+
+ List refereeValues = getRefereeValues();
+ if (refereeValues.contains(princValue) || getPrincipal().getName().equals(principalName)) {
+ return false;
+ }
+ if (userManager.hasAuthorizableOrReferee(principal)) {
+ throw new AuthorizableExistsException("Another authorizable already represented by or refeering to " + principalName);
+ }
+ refereeValues.add(princValue);
+
+ userManager.setProtectedProperty(node, P_REFEREES, (Value[]) refereeValues.toArray(new Value[refereeValues.size()]));
+ return true;
+ }
+
+ /**
+ * @see Authorizable#removeReferee(Principal)
+ */
+ public synchronized boolean removeReferee(Principal principal) throws RepositoryException {
+ Value princValue = getSession().getValueFactory().createValue(principal.getName());
+ List existingValues = getRefereeValues();
+
+ if (existingValues.remove(princValue)) {
+ PropertyImpl prop = node.getProperty(P_REFEREES);
+ if (existingValues.isEmpty()) {
+ userManager.removeProtectedItem(prop, node);
+ } else {
+ userManager.setProtectedProperty(node, P_REFEREES, (Value[]) existingValues.toArray(new Value[existingValues.size()]));
+ }
+ return true;
+ }
+
+ // specified principal was not referee of this authorizable.
+ return false;
+ }
+
+ /**
+ * @see Authorizable#memberOf()
+ */
+ public Iterator memberOf() throws RepositoryException {
+ // TODO: replace by weak-refs
+ PropertyIterator itr = node.getReferences();
+ Collection tmp = new HashSet((int) itr.getSize());
+ while (itr.hasNext()) {
+ NodeImpl groupNode = (NodeImpl) itr.nextProperty().getParent();
+ if (groupNode.isNodeType(NT_REP_GROUP)) {
+ Group group = GroupImpl.create(groupNode, userManager);
+ tmp.add(group);
+ }
+ }
+ return tmp.iterator();
+ }
+
+ /**
+ * Tests if a Value exists for a property at the given name.
+ *
+ * @param name
+ * @return
+ * @throws javax.jcr.RepositoryException
+ * @see #getProperty(String)
+ */
+ public boolean hasProperty(String name) throws RepositoryException {
+ return node.hasProperty(name);
+ }
+
+ /**
+ * @param name
+ * @return the value or <code>null</code> if no value exists for the given name
+ * @throws javax.jcr.RepositoryException
+ * @see #hasProperty(String)
+ * @see Authorizable#getProperty(String)
+ */
+ public Value[] getProperty(String name) throws RepositoryException {
+ if (hasProperty(name)) {
+ Property prop = node.getProperty(name);
+ if (prop.getDefinition().isMultiple()) {
+ return prop.getValues();
+ } else {
+ return new Value[] {prop.getValue()};
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets the Value for the given name. If a value existed, it is replaced,
+ * if not it is created.
+ *
+ * @param name
+ * @param value
+ * @see Authorizable#setProperty(String, Value)
+ */
+ public synchronized void setProperty(String name, Value value) throws RepositoryException {
+ checkProtectedProperty(getSession().getQName(name));
+ try {
+ node.setProperty(name, value);
+ node.save();
+ } catch (RepositoryException e) {
+ log.warn("Failed to set Property " + name + " for Authorizable " + getID());
+ node.refresh(false);
+ throw e;
+ }
+ }
+
+ /**
+ * Sets the Value[] for the given name. If a value existed, it is replaced,
+ * if not it is created.
+ *
+ * @param name
+ * @param values
+ * @see Authorizable#setProperty(String, Value[])
+ */
+ public synchronized void setProperty(String name, Value[] values) throws RepositoryException {
+ checkProtectedProperty(getSession().getQName(name));
+ try {
+ node.setProperty(name, values);
+ node.save();
+ } catch (RepositoryException e) {
+ log.warn("Failed to set Property " + name + " for Authorizable " + getID());
+ node.refresh(false);
+ throw e;
+ }
+ }
+ /**
+ * @see Authorizable#removeProperty(String)
+ */
+ public synchronized boolean removeProperty(String name) throws RepositoryException {
+ checkProtectedProperty(getSession().getQName(name));
+ try {
+ if (node.hasProperty(name)) {
+ // 'node' is protected -> use setValue instead of Property.remove()
+ Property p = node.getProperty(name);
+ if (p.getDefinition().isMultiple()) {
+ p.setValue((Value[]) null);
+ } else {
+ p.setValue((Value) null);
+ }
+ node.save();
+ return true;
+ } else {
+ return false;
+ }
+ } catch (RepositoryException e) {
+ log.warn("Failed to remove Property " + name + " from Authorizable " + getID());
+ node.refresh(false);
+ throw e;
+ }
+ }
+
+ /**
+ * @see Authorizable#remove()
+ */
+ public synchronized void remove() throws RepositoryException {
+ // TODO: ev. remove group-memberships first?
+ userManager.removeProtectedItem(node, node.getParent());
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ * @return node The underlying <code>Node</code> object.
+ */
+ NodeImpl getNode() throws RepositoryException {
+ return node;
+ }
+
+ SessionImpl getSession() throws RepositoryException {
+ return (SessionImpl) node.getSession();
+ }
+
+ String getPrincipalName() throws RepositoryException {
+ // principal name is mandatory property -> no check required.
+ return node.getProperty(P_PRINCIPAL_NAME).getString();
+ }
+
+ /**
+ * Check if the property to be modified/removed is one of the following that
+ * has a special meaning and must be altered using this user API:
+ * <ul>
+ * <li>rep:principalName</li>
+ * <li>rep:userId</li>
+ * <li>rep:referees</li>
+ * <li>rep:members</li>
+ * <li>rep:impersonators</li>
+ * </ul>
+ * Basically these properties are marked 'protected' in their property
+ * definition. This method is a simple utility in order to save the
+ * extra effort to modify the props just to find out later that they
+ * are in fact protected.
+ *
+ * @param pName
+ * @throws RepositoryException
+ */
+ private void checkProtectedProperty(Name pName) throws RepositoryException {
+ if (P_PRINCIPAL_NAME.equals(pName) || P_USERID.equals(pName)
+ || P_REFEREES.equals(pName) || P_MEMBERS.equals(pName)
+ || P_IMPERSONATORS.equals(pName)) {
+ throw new ConstraintViolationException("Attempt to modify protected property " + getSession().getJCRName(pName) + " of an Authorizable.");
+ }
+ }
+
+ private List getRefereeValues() throws RepositoryException {
+ List principalNames = new ArrayList();
+ if (node.hasProperty(P_REFEREES)) {
+ try {
+ Value[] refProp = node.getProperty(P_REFEREES).getValues();
+ for (int i = 0; i < refProp.length; i++) {
+ principalNames.add(refProp[i]);
+ }
+ } catch (PathNotFoundException e) {
+ // ignore. should never occur.
+ }
+ }
+ return principalNames;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ *
+ */
+ class NodeBasedPrincipal extends PrincipalImpl implements ItemBasedPrincipal {
+
+ /**
+ * @param name for the principal
+ */
+ NodeBasedPrincipal(String name) {
+ super(name);
+ }
+
+ //---------------------------------------------< ItemBasedPrincipal >---
+ /**
+ * Method revealing the path to the Node that represents the
+ * Authorizable this principal is created for.
+ *
+ * @return
+ * @see ItemBasedPrincipal#getPath()
+ */
+ public String getPath() throws RepositoryException {
+ return node.getPath();
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,386 @@
+/*
+ * 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 org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.PropertyImpl;
+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.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * GroupImpl...
+ */
+class GroupImpl extends AuthorizableImpl implements Group {
+
+ private static final Logger log = LoggerFactory.getLogger(GroupImpl.class);
+
+ private Principal principal = null;
+
+ private GroupImpl(NodeImpl node, UserManagerImpl userManager) throws RepositoryException {
+ super(node, userManager);
+ }
+
+ static Group create(NodeImpl node, UserManagerImpl userManager) throws RepositoryException {
+ if (node == null || !node.isNodeType(NT_REP_GROUP)) {
+ throw new IllegalArgumentException();
+ }
+ if(!Text.isDescendant(GROUPS_PATH, node.getPath())) {
+ throw new IllegalArgumentException("Group has to be within the Group Path");
+ }
+ return new GroupImpl(node, userManager);
+ }
+
+
+ //-------------------------------------------------------< Authorizable >---
+ /**
+ * Returns the name of the node that defines this <code>Group</code>, that
+ * has been used taking the principal name as hint.
+ *
+ * @return name of the node that defines this <code>Group</code>.
+ * @see Authorizable#getID()
+ */
+ public String getID() throws RepositoryException {
+ return getNode().getName();
+ }
+
+ /**
+ * @see Authorizable#isGroup()
+ */
+ public boolean isGroup() {
+ return true;
+ }
+
+ /**
+ * @see Authorizable#getPrincipal()
+ */
+ public Principal getPrincipal() throws RepositoryException {
+ if (principal == null) {
+ principal = new NodeBasedGroup(getPrincipalName());
+ }
+ return principal;
+ }
+
+ //--------------------------------------------------------------< Group >---
+ /**
+ * @see Group#getMembers()
+ */
+ public Iterator getMembers() throws RepositoryException {
+ return new MemberIterator(memberUUIDs().iterator());
+ }
+
+ /**
+ * @see Group#isMember(Authorizable)
+ */
+ public boolean isMember(Authorizable authorizable) throws RepositoryException {
+ if (authorizable == null || !(authorizable instanceof AuthorizableImpl)) {
+ return false;
+ } else {
+ AuthorizableImpl impl = (AuthorizableImpl) authorizable;
+ String uuid = impl.getNode().getUUID();
+ return memberUUIDs().contains(uuid);
+ }
+ }
+
+ /**
+ * @see Group#addMember(Authorizable)
+ */
+ public boolean addMember(Authorizable authorizable) throws RepositoryException {
+ if (authorizable == null || !(authorizable instanceof AuthorizableImpl)
+ || isMember(authorizable)) {
+ return false;
+ }
+ if (isCyclicMembership(authorizable)) {
+ log.warn("Attempt to create circular group membership.");
+ return false;
+ }
+
+ Node memberNode = ((AuthorizableImpl) authorizable).getNode();
+ if (memberNode.isSame(getNode())) {
+ String msg = "Attempt to add a Group as member of itself (" + getID() + ").";
+ log.warn(msg);
+ return false;
+ }
+
+ Value[] values;
+ // TODO: replace by weak-refs
+ Value added = getSession().getValueFactory().createValue(memberNode);
+ NodeImpl node = getNode();
+ if (node.hasProperty(P_MEMBERS)) {
+ Value[] old = node.getProperty(P_MEMBERS).getValues();
+ values = new Value[old.length + 1];
+ System.arraycopy(old, 0, values, 0, old.length);
+ } else {
+ values = new Value[1];
+ }
+ values[values.length - 1] = added;
+ userManager.setProtectedProperty(node, P_MEMBERS, values);
+ return true;
+ }
+
+ /**
+ * @see Group#removeMember(Authorizable)
+ */
+ public boolean removeMember(Authorizable authorizable) throws RepositoryException {
+ if (!isMember(authorizable) || !(authorizable instanceof AuthorizableImpl)) {
+ return false;
+ }
+ NodeImpl node = getNode();
+ if (!node.hasProperty(P_MEMBERS)) {
+ log.debug("Group has no members -> cannot remove member " + authorizable.getID());
+ return false;
+ }
+
+ Value toRemove = getSession().getValueFactory().createValue(((AuthorizableImpl)authorizable).getNode());
+
+ PropertyImpl property = node.getProperty(P_MEMBERS);
+ List valList = new ArrayList(Arrays.asList(property.getValues()));
+
+ if (valList.remove(toRemove)) {
+ try {
+ if (valList.isEmpty()) {
+ userManager.removeProtectedItem(property, node);
+ } else {
+ Value[] values = (Value[]) valList.toArray(new Value[valList.size()]);
+ userManager.setProtectedProperty(node, P_MEMBERS, values);
+ }
+ return true;
+ } catch (RepositoryException e) {
+ // modification failed -> revert all pending changes.
+ node.refresh(false);
+ throw e;
+ }
+ } else {
+ // nothing changed
+ log.debug("Authorizable " + authorizable.getID() + " was not member of " + getID());
+ return false;
+ }
+ }
+
+ //--------------------------------------------------------------------------
+
+ /**
+ *
+ * @return
+ * @throws RepositoryException
+ */
+ private Collection memberUUIDs() throws RepositoryException {
+ Collection tmp = new HashSet();
+ if (getNode().hasProperty(P_MEMBERS)) {
+ Property prop = getNode().getProperty(P_MEMBERS);
+ Value[] val = prop.getValues();
+ for (int i = 0; i < val.length; i++) {
+ tmp.add(val[i].getString());
+ }
+ }
+ return tmp;
+ }
+
+ /**
+ * Since {@link #isMember(Authorizable)} only detects the declared
+ * members of this group, this methods is used to avoid cyclic membership
+ * declarations.
+ *
+ * @param newMember
+ * @return true if the 'newMember' is a group and 'this' is an declared or
+ * inherited member of it.
+ */
+ private boolean isCyclicMembership(Authorizable newMember) throws RepositoryException {
+ boolean cyclic = false;
+ if (newMember.isGroup()) {
+ Group gr = (Group) newMember;
+ cyclic = gr.isMember(this);
+ if (!cyclic) {
+ PrincipalManager pmgr = getSession().getPrincipalManager();
+ for (Iterator it = pmgr.getGroupMembership(getPrincipal());
+ it.hasNext() && !cyclic;) {
+ cyclic = newMember.getPrincipal().equals(it.next());
+ }
+ }
+ }
+ return cyclic;
+ }
+
+ //------------------------------------------------------< inner classes >---
+ private class MemberIterator implements Iterator {
+
+ private final Iterator ids;
+ private Authorizable next;
+
+ private MemberIterator(Iterator ids) {
+ this.ids = ids;
+ next = seekNext();
+ }
+
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ public Object next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+
+ Authorizable n = next;
+ next = seekNext();
+ return n;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ private Authorizable seekNext() {
+ Authorizable auth = null;
+ while (auth == null && ids.hasNext()) {
+ String uuid = (String) ids.next();
+ try {
+ NodeImpl mem = (NodeImpl) getSession().getNodeByUUID(uuid);
+ if (mem.isNodeType(NT_REP_GROUP)) {
+ auth = create(mem, userManager);
+ } else {
+ auth = UserImpl.create(mem, userManager);
+ }
+ } catch (RepositoryException e) {
+ log.warn("Internal error while building next member.", e.getMessage());
+ // ignore and try next
+ }
+ }
+ return auth;
+ }
+ }
+
+ /**
+ *
+ */
+ private class NodeBasedGroup extends NodeBasedPrincipal implements java.security.acl.Group {
+
+ private Set members;
+
+ private NodeBasedGroup(String name) {
+ super(name);
+ }
+
+ //----------------------------------------------------------< Group >---
+ /**
+ * @return Always <code>false</code>. Group membership must be edited
+ * using the enclosing <code>GroupImpl</code> object.
+ * @see java.security.acl.Group#addMember(Principal)
+ */
+ public boolean addMember(Principal user) {
+ return false;
+ }
+
+ /**
+ * Returns true, if the given <code>Principal</code> is represented by
+ * a Authorizable, that is a member of the underlying UserGroup.
+ *
+ * @see java.security.acl.Group#isMember(Principal)
+ */
+ public boolean isMember(Principal member) {
+ Collection members = getMembers();
+ if (members.contains(member)) {
+ // shortcut.
+ return true;
+ }
+
+ // test if member of a member-group
+ for (Iterator it = members.iterator(); it.hasNext();) {
+ Principal p = (Principal) it.next();
+ if (p instanceof java.security.acl.Group &&
+ ((java.security.acl.Group) p).isMember(member)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return Always <code>false</code>. Group membership must be edited
+ * using the enclosing <code>GroupImpl</code> object.
+ *
+ * @see java.security.acl.Group#isMember(Principal)
+ */
+ public boolean removeMember(Principal user) {
+ return false;
+ }
+
+ /**
+ * Return all principals that refer to every member of the underlying
+ * user group.
+ *
+ * @see java.security.acl.Group#members()
+ */
+ public Enumeration members() {
+ return Collections.enumeration(getMembers());
+ }
+
+ //---------------------------------------------------< Serializable >---
+ /**
+ * implement the writeObject method to assert initalization of all members
+ * before serialization.
+ *
+ * @param stream
+ * @throws IOException
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ getMembers();
+ stream.defaultWriteObject();
+ }
+
+ //----------------------------------------------------------------------
+ private Collection getMembers() {
+ if (members == null) {
+ members = new HashSet();
+ try {
+ for (Iterator it = GroupImpl.this.getMembers(); it.hasNext();) {
+ Authorizable authrz = (Authorizable) it.next();
+ // TODO: check again. only add main principal, since
+ // 'referees' belong to a different provider and should
+ // not be exposed here
+ members.add(authrz.getPrincipal());
+ }
+ } catch (RepositoryException e) {
+ // should not occur.
+ log.error("Unable to retrieve Group members.");
+ }
+ }
+ return members;
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,209 @@
+/*
+ * 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 org.apache.jackrabbit.core.security.SystemPrincipal;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Impersonation;
+import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.principal.NoSuchPrincipalException;
+import org.apache.jackrabbit.core.security.principal.PrincipalIteratorAdapter;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.PropertyImpl;
+import org.apache.jackrabbit.value.StringValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * ImpersonationImpl
+ */
+class ImpersonationImpl implements Impersonation, UserConstants {
+
+ private static final Logger log = LoggerFactory.getLogger(ImpersonationImpl.class);
+
+ private final UserImpl user;
+ private final UserManagerImpl userManager;
+
+ ImpersonationImpl(UserImpl user, UserManagerImpl userManager) throws RepositoryException {
+ this.user = user;
+ this.userManager = userManager;
+ }
+
+ //------------------------------------------------------< Impersonation >---
+ /**
+ * @see Impersonation#getImpersonators()
+ */
+ public PrincipalIterator getImpersonators() throws RepositoryException {
+ Set impersonators = getImpersonatorNames();
+ if (impersonators.isEmpty()) {
+ return PrincipalIteratorAdapter.EMPTY;
+ } else {
+ final PrincipalManager pMgr = user.getSession().getPrincipalManager();
+
+ Set s = new HashSet();
+ for (Iterator it = impersonators.iterator(); it.hasNext();) {
+ String pName = it.next().toString();
+ Principal p = null;
+ if (pMgr.hasPrincipal(pName)) {
+ try {
+ p = pMgr.getPrincipal(pName);
+ } catch (NoSuchPrincipalException e) {
+ // should never get here.
+ }
+ }
+ if (p == null) {
+ log.debug("Impersonator " + pName + " does not correspond to a known Principal.");
+ p = new PrincipalImpl(pName);
+ }
+ s.add(p);
+
+ }
+ return new PrincipalIteratorAdapter(s);
+ }
+ }
+
+ /**
+ * @see Impersonation#grantImpersonation(Principal)
+ */
+ public synchronized boolean grantImpersonation(Principal principal) throws RepositoryException {
+ if (principal instanceof AdminPrincipal || principal instanceof SystemPrincipal) {
+ log.debug("Admin and System principal are already granted impersonation.");
+ return false;
+ }
+
+ // make sure the given principals belong to an existing authorizable
+ Authorizable auth = user.userManager.getAuthorizable(principal);
+ if (auth == null || auth.isGroup()) {
+ // TODO: check again if this assumption is correct...
+ log.debug("Cannot grant impersonation to a principal that is a Group " +
+ "or an unknown Authorizable.");
+ return false;
+ }
+
+ String pName = principal.getName();
+ // make sure user does not impersonate himself
+ for (PrincipalIterator it = user.getPrincipals(); it.hasNext();) {
+ Principal p = it.nextPrincipal();
+ if (p.getName().equals(pName)) {
+ log.debug("Cannot grant impersonation to oneself.");
+ return false;
+ }
+ }
+
+ boolean granted = false;
+ Set impersonators = getImpersonatorNames();
+ if (impersonators.add(pName)) {
+ updateImpersonatorNames(impersonators);
+ granted = true;
+ }
+ return granted;
+ }
+
+ /**
+ * @see Impersonation#revokeImpersonation(Principal)
+ */
+ public synchronized boolean revokeImpersonation(Principal principal) throws RepositoryException {
+ if (principal instanceof AdminPrincipal || principal instanceof SystemPrincipal) {
+ log.debug("Admin and System principal are always granted impersonation.");
+ return false;
+ }
+
+ boolean revoked = false;
+ String pName = principal.getName();
+
+ Set impersonators = getImpersonatorNames();
+ if (impersonators.remove(pName)) {
+ updateImpersonatorNames(impersonators);
+ revoked = true;
+ }
+ return revoked;
+ }
+
+ /**
+ * @see Impersonation#allows(Subject)
+ */
+ public boolean allows(Subject subject) throws RepositoryException {
+ if (subject == null) {
+ return false;
+ }
+ //shortcut admin/system -> always allowed
+ if (!subject.getPrincipals(AdminPrincipal.class).isEmpty()
+ || !subject.getPrincipals(SystemPrincipal.class).isEmpty()) {
+ return true;
+ }
+
+ Set principalNames = new HashSet();
+ for (Iterator it = subject.getPrincipals().iterator(); it.hasNext();) {
+ principalNames.add(((Principal) it.next()).getName());
+ }
+
+ boolean allows = false;
+ try {
+ Set impersonators = getImpersonatorNames();
+ allows = impersonators.removeAll(principalNames);
+ } catch (RepositoryException e) {
+ // should never get here
+ log.debug(e.getMessage());
+ }
+ return allows;
+ }
+
+ //------------------------------------------------------------< private >---
+
+ private Set getImpersonatorNames() throws RepositoryException {
+ Set princNames = new HashSet();
+ if (user.getNode().hasProperty(P_IMPERSONATORS)) {
+ Value[] vs = user.getNode().getProperty(P_IMPERSONATORS).getValues();
+ for (int i = 0; i < vs.length; i++) {
+ princNames.add(vs[i].getString());
+ }
+ }
+ return princNames;
+ }
+
+ private void updateImpersonatorNames(Set principalNames) throws RepositoryException {
+ NodeImpl userNode = user.getNode();
+ try {
+ String[] pNames = (String[]) principalNames.toArray(new String[principalNames.size()]);
+ if (pNames.length == 0) {
+ PropertyImpl prop = userNode.getProperty(P_IMPERSONATORS);
+ userManager.removeProtectedItem(prop, userNode);
+ } else {
+ Value[] values = new Value[pNames.length];
+ for (int i = 0; i < pNames.length; i++) {
+ values[i] = new StringValue(pNames[i]);
+ }
+ userManager.setProtectedProperty(userNode, P_IMPERSONATORS, values);
+ }
+ } catch (RepositoryException e) {
+ // revert pending changes
+ userNode.refresh(false);
+ throw e;
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,113 @@
+/*
+ * 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 org.apache.jackrabbit.util.ISO9075;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.core.SessionImpl;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Collections;
+
+/**
+ *
+ */
+class IndexNodeResolver extends NodeResolver {
+
+ private final QueryManager queryManager;
+
+ IndexNodeResolver(SessionImpl session)
+ throws RepositoryException {
+ super(session);
+ queryManager = session.getWorkspace().getQueryManager();
+ }
+
+ //-------------------------------------------------------< NodeResolver >---
+ /**
+ * @inheritDoc
+ */
+ public Node findNode(Name propertyName, String value, Name ntName) throws RepositoryException {
+ Query query = buildQuery(value, Collections.singleton(propertyName), ntName, true, 1);
+ NodeIterator res = query.execute().getNodes();
+ if (res.hasNext()) {
+ return res.nextNode();
+ }
+ return null;
+ }
+
+ /**
+ * 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
+ * @param value
+ * @param ntName NodeType the hits have to have
+ * @param exact if <code>true</code> match must be exact
+ * @return
+ * @throws javax.jcr.RepositoryException
+ */
+ public NodeIterator findNodes(Set propertyNames, String value, Name ntName,
+ boolean exact, long maxSize) throws RepositoryException {
+ Query query = buildQuery(value, propertyNames, ntName, exact, maxSize);
+ return query.execute().getNodes();
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ *
+ * @param value
+ * @param props
+ * @param ntName
+ * @param exact
+ * @param maxSize Currently ignored!
+ * @return
+ * @throws RepositoryException
+ */
+ private Query buildQuery(String value, Set props, Name ntName,
+ boolean exact, long maxSize)
+ throws RepositoryException {
+ // TODO: include maxSize in query statement.
+ StringBuffer stmt = new StringBuffer("/jcr:root");
+ stmt.append(getSearchRoot(ntName));
+ stmt.append("//element(*,");
+ stmt.append(getSession().getJCRName(ntName));
+ stmt.append(")[");
+
+ int i = 0;
+ Iterator itr = props.iterator();
+ while (itr.hasNext()) {
+ stmt.append((exact) ? "@" : "jcr:like(@");
+ String pName = getSession().getJCRName((Name) itr.next());
+ stmt.append(ISO9075.encode(pName));
+ stmt.append((exact) ? "='" : ",'%");
+ stmt.append(value);
+ stmt.append((exact) ? "'" : "%')");
+ if (++i < props.size()) {
+ stmt.append(" or ");
+ }
+ }
+ stmt.append("]");
+ return queryManager.createQuery(stmt.toString(), Query.XPATH);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,121 @@
+/*
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.spi.Name;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Resolver: searches for Principals stored in Nodes of a {@link javax.jcr.Workspace}
+ * which match a certain criteria<p>
+ * The principalNames are assumed to be stored in properties.
+ */
+abstract class NodeResolver {
+
+ private static final Logger log = LoggerFactory.getLogger(NodeResolver.class);
+
+ private final SessionImpl session;
+
+ /**
+ * Create a new <code>NodeResolver</code>.
+ *
+ * @param session;
+ * @throws RepositoryException if instanciation fails
+ */
+ NodeResolver(SessionImpl session)
+ throws RepositoryException {
+
+ this.session = session;
+ }
+
+ /**
+ * 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
+ * @param value
+ * @param ntName
+ * @return The first node that has a property with the given propertyName that
+ * exactly matches the given value or <code>null</code>.
+ * @throws RepositoryException
+ */
+ 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 property to be searched
+ * @param value value to be matched
+ * @param ntName
+ * @param exact if <code>true</code> value has to match exactly
+ * @return matching nodes (or an empty iterator if no match was found).
+ */
+ 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 cirteria.
+ * 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
+ * @param value
+ * @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
+ * @throws RepositoryException
+ */
+ public abstract NodeIterator findNodes(Set propertyNames, String value, Name ntName,
+ boolean exact, long maxSize)
+ throws RepositoryException;
+
+ /**
+ * @return Session this instance has been constructed with
+ */
+ SessionImpl getSession() {
+ return session;
+ }
+
+ String getSearchRoot(Name ntName) {
+ String searchRoot;
+ if (UserConstants.NT_REP_USER.equals(ntName)) {
+ searchRoot = UserConstants.USERS_PATH;
+ } else if (UserConstants.NT_REP_GROUP.equals(ntName)) {
+ searchRoot = UserConstants.GROUPS_PATH;
+ } else {
+ searchRoot = UserConstants.AUTHORIZABLES_PATH;
+ }
+ return searchRoot;
+ }
+}
+
+
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/TraversingNodeResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/TraversingNodeResolver.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/TraversingNodeResolver.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/TraversingNodeResolver.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,176 @@
+/*
+ * 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 org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.spi.Name;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Collections;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ *
+ */
+class TraversingNodeResolver extends NodeResolver {
+
+ private static final Logger log = LoggerFactory.getLogger(TraversingNodeResolver.class);
+
+ /**
+ * Additonally to the NodeType-Argument the resolvers searched is narrowed
+ * by indicating a Path to an {@link javax.jcr.Item} as start for the search
+ *
+ * @param session to use for repository access
+ */
+ TraversingNodeResolver(SessionImpl session) throws RepositoryException {
+ super(session);
+ }
+
+ //-------------------------------------------------------< NodeResolver >---
+ /**
+ * @inheritDoc
+ */
+ public Node findNode(Name propertyName, String value, Name ntName) throws RepositoryException {
+ try {
+ Node root = (Node) getSession().getItem(getSearchRoot(ntName));
+ NodeIterator nodes = collectNodes(value, Collections.singleton(propertyName), ntName,
+ root.getNodes(), true, 1);
+ if (nodes.hasNext()) {
+ return nodes.nextNode();
+ }
+ } catch (PathNotFoundException e) {
+ log.warn("Error while searching for node having a property " + propertyName + " with value " + value);
+ }
+
+ return null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public NodeIterator findNodes(Set propertyNames, String value, Name ntName,
+ boolean exact, long maxSize) throws RepositoryException {
+
+ NodeImpl root = (NodeImpl) getSession().getItem(getSearchRoot(ntName));
+ return collectNodes(value, propertyNames, ntName, root.getNodes(), exact, maxSize);
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ * searches the given value in the range of the given NodeIterator.
+ * recurses unitll all matching values in all configured props are found.
+ *
+ * @param value the value to be found in the nodes
+ * @param props property to be searched, or null if {@link javax.jcr.Item#getName()}
+ * @param ntName to filter search
+ * @param nodes range of nodes and descendants to be searched
+ * @param exact if set to true the value has to match exactly else a
+ * substring is searched
+ * @param maxSize
+ */
+ private NodeIterator collectNodes(String value, Set props, Name ntName,
+ NodeIterator nodes, boolean exact,
+ long maxSize) {
+ Set matches = new HashSet();
+ collectNodes(value, props, ntName, nodes, matches, exact, maxSize);
+ return new NodeIteratorAdapter(matches);
+ }
+
+ /**
+ * searches the given value in the range of the given NodeIterator.
+ * recurses unitll all matching values in all configured properties are found.
+ *
+ * @param value the value to be found in the nodes
+ * @param propertyNames property to be searched, or null if {@link javax.jcr.Item#getName()}
+ * @param nodeTypeName name of nodetypes to search
+ * @param itr range of nodes and descendants to be searched
+ * @param matches Set of found matches to append results
+ * @param exact if set to true the value has to match exact
+ * @param maxSize
+ */
+ private void collectNodes(String value, Set propertyNames,
+ Name nodeTypeName, NodeIterator itr,
+ Set matches, boolean exact, long maxSize) {
+ while (itr.hasNext()) {
+ NodeImpl node = (NodeImpl) itr.nextNode();
+ try {
+ if (matches(node, nodeTypeName, propertyNames, value, exact)) {
+ matches.add(node);
+ maxSize--;
+ }
+ if (node.hasNodes() && maxSize > 0) {
+ collectNodes(value, propertyNames, nodeTypeName,
+ node.getNodes(), matches, exact, maxSize);
+ }
+ } catch (RepositoryException e) {
+ log.warn("failed to access Node at " + e);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param node
+ * @param nodeTypeName
+ * @param propertyNames
+ * @param value
+ * @param exact
+ * @return
+ * @throws RepositoryException
+ */
+ private boolean matches(NodeImpl node, Name nodeTypeName,
+ Collection propertyNames, String value,
+ boolean exact) throws RepositoryException {
+
+ boolean match = false;
+ if (node.isNodeType(nodeTypeName)) {
+ try {
+ if (propertyNames.isEmpty()) {
+ match = (exact) ? node.getName().equals(value) :
+ node.getName().matches(".*"+value+".*");
+ } else {
+ Iterator pItr = propertyNames.iterator();
+ while (!match && pItr.hasNext()) {
+ Name propertyName = (Name) pItr.next();
+ if (node.hasProperty(propertyName)) {
+ String toMatch = node.getProperty(propertyName).getString();
+ match = (exact) ?
+ toMatch.equals(value) :
+ toMatch.matches(".*"+value+".*");
+ }
+ }
+ }
+ } catch (PatternSyntaxException pe) {
+ log.debug("couldn't search for {}, pattern invalid: {}",
+ value, pe.getMessage());
+ }
+ }
+ return match;
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/TraversingNodeResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/TraversingNodeResolver.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url