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 2011/10/21 11:38:37 UTC
svn commit: r1187257 - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/
main/java/org/apache/jackrabbit/core/config/
main/java/org/apache/jackrabbit/core/security/user/
main/java/org/apache/jackrabbit/core/security/user/a...
Author: angela
Date: Fri Oct 21 09:38:37 2011
New Revision: 1187257
URL: http://svn.apache.org/viewvc?rev=1187257&view=rev
Log:
JCR-3118 : Configurable actions upon authorizable creation and removal
Added:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AccessControlAction.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AuthorizableAction.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/ClearMembershipAction.java
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/UserManagerConfig.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/SecurityConfigTest.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java Fri Oct 21 09:38:37 2011
@@ -63,6 +63,7 @@ import org.apache.jackrabbit.core.securi
import org.apache.jackrabbit.core.security.principal.ProviderRegistryImpl;
import org.apache.jackrabbit.core.security.user.MembershipCache;
import org.apache.jackrabbit.core.security.user.UserManagerImpl;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -427,19 +428,20 @@ public class DefaultSecurityManager impl
}
/**
- * @param workspaceName
+ * @param workspaceName The name of the target workspace.
* @return The system user manager. Since this implementation stores users
* in a dedicated workspace the system user manager is the same for all
* sessions irrespective of the workspace.
+ * @throws javax.jcr.RepositoryException If an error occurs.
*/
protected UserManager getSystemUserManager(String workspaceName) throws RepositoryException {
return systemUserManager;
}
/**
- * @param session
- * @return
- * @throws RepositoryException
+ * @param session The session for which to retrieve the membership cache.
+ * @return The membership cache.
+ * @throws RepositoryException If an error occurs.
*/
protected MembershipCache getMembershipCache(SessionImpl session) throws RepositoryException {
if (session == systemSession || session instanceof SystemSession) {
@@ -474,14 +476,18 @@ public class DefaultSecurityManager impl
Properties.class,
MembershipCache.class};
um = (UserManagerImpl) umc.getUserManager(UserManagerImpl.class,
- paramTypes, (SessionImpl) session, adminId, params,
- getMembershipCache(session));
+ paramTypes, session, adminId, params, getMembershipCache(session));
// TODO: should we make sure the implementation doesn't allow
// TODO: to change the autosave behavior? since the user manager
// TODO: writes to a separate workspace this would cause troubles.
} else {
um = new UserManagerImpl(session, adminId, params, getMembershipCache(session));
}
+
+ if (umc != null && !(session instanceof SystemSession)) {
+ AuthorizableAction[] actions = umc.getAuthorizableActions();
+ um.setAuthorizableActions(actions);
+ }
return um;
}
@@ -592,7 +598,7 @@ public class DefaultSecurityManager impl
* Make sure the system users (admin and anonymous) exist.
*
* @param userManager Manager to create users/groups.
- * @param session
+ * @param session The editing session.
* @param adminId UserID of the administrator.
* @param anonymousId UserID of the anonymous user.
* @throws RepositoryException If an error occurs.
@@ -602,11 +608,11 @@ public class DefaultSecurityManager impl
String adminId,
String anonymousId) throws RepositoryException {
- Authorizable admin = null;
+ Authorizable admin;
if (adminId != null) {
admin = userManager.getAuthorizable(adminId);
if (admin == null) {
- admin = userManager.createUser(adminId, adminId);
+ userManager.createUser(adminId, adminId);
if (!userManager.isAutoSave()) {
session.save();
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java Fri Oct 21 09:38:37 2011
@@ -29,6 +29,7 @@ import org.apache.jackrabbit.core.securi
import org.apache.jackrabbit.core.security.user.MembershipCache;
import org.apache.jackrabbit.core.security.user.UserPerWorkspaceUserManager;
import org.apache.jackrabbit.core.security.user.UserManagerImpl;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
import javax.jcr.Credentials;
import javax.jcr.Repository;
@@ -219,7 +220,8 @@ public class UserPerWorkspaceSecurityMan
protected UserManagerImpl createUserManager(SessionImpl session) throws RepositoryException {
UserManagerConfig umc = getConfig().getUserManagerConfig();
Properties params = (umc == null) ? null : umc.getParameters();
-
+
+ UserManagerImpl umgr;
// in contrast to the DefaultSecurityManager users are not retrieved
// from a dedicated workspace: the system session of each workspace must
// get a system user manager that asserts the existence of the admin user.
@@ -229,11 +231,17 @@ public class UserPerWorkspaceSecurityMan
String.class,
Properties.class,
MembershipCache.class};
- return (UserPerWorkspaceUserManager) umc.getUserManager(UserPerWorkspaceUserManager.class,
- paramTypes, (SessionImpl) session, adminId, params, getMembershipCache(session));
+ umgr = (UserPerWorkspaceUserManager) umc.getUserManager(UserPerWorkspaceUserManager.class,
+ paramTypes, session, adminId, params, getMembershipCache(session));
} else {
- return new UserPerWorkspaceUserManager(session, adminId, params, getMembershipCache(session));
+ umgr = new UserPerWorkspaceUserManager(session, adminId, params, getMembershipCache(session));
+ }
+
+ if (umc != null && !(session instanceof SystemSession)) {
+ AuthorizableAction[] actions = umc.getAuthorizableActions();
+ umgr.setAuthorizableActions(actions);
}
+ return umgr;
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java Fri Oct 21 09:38:37 2011
@@ -32,6 +32,8 @@ import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Properties;
/**
@@ -350,6 +352,37 @@ public class ConfigurationParser {
}
/**
+ * Returns the named child of the given parent element.
+ *
+ * @param parent parent element
+ * @param name name of the child element
+ * @param required indicates if the child element is required
+ * @return named child element, or <code>null</code> if not found and
+ * <code>required</code> is <code>false</code>.
+ * @throws ConfigurationException if the child element is not found and
+ * <code>required</code> is <code>true</code>;
+ * or if more than one element with this name exists.
+ */
+ protected Element[] getElements(Element parent, String name, boolean required)
+ throws ConfigurationException {
+ NodeList children = parent.getChildNodes();
+ List<Element> found = new ArrayList<Element>();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE
+ && name.equals(child.getNodeName())) {
+ found.add((Element) child);
+ }
+ }
+ if (required && found.isEmpty()) {
+ throw new ConfigurationException(
+ "Configuration element " + name + " not found in "
+ + parent.getNodeName() + ".");
+ }
+ return found.toArray(new Element[found.size()]);
+ }
+
+ /**
* Returns the value of the named attribute of the given element.
*
* @param element element
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java Fri Oct 21 09:38:37 2011
@@ -193,6 +193,12 @@ public class RepositoryConfigurationPars
private static final String AC_PROVIDER_ELEMENT = "AccessControlProvider";
/**
+ * Optional configuration elements with the user manager configuration.
+ * @see org.apache.jackrabbit.core.security.user.action.AuthorizableAction
+ */
+ private static final String AUTHORIZABLE_ACTION = "AuthorizableAction";
+
+ /**
* The repositories {@link ConnectionFactory}.
*/
protected final ConnectionFactory connectionFactory;
@@ -419,7 +425,12 @@ public class RepositoryConfigurationPars
UserManagerConfig umc = null;
element = getElement(smElement, USER_MANAGER_ELEMENT, false);
if (element != null) {
- umc = new UserManagerConfig(parseBeanConfig(smElement, USER_MANAGER_ELEMENT));
+ Element[] acElements = getElements(element, AUTHORIZABLE_ACTION, false);
+ BeanConfig[] aaConfig = new BeanConfig[acElements.length];
+ for (int i = 0; i < acElements.length; i++) {
+ aaConfig[i] = parseBeanConfig(acElements[i]);
+ }
+ umc = new UserManagerConfig(parseBeanConfig(element), aaConfig);
}
BeanConfig uidcc = null;
@@ -531,7 +542,8 @@ public class RepositoryConfigurationPars
* Parse workspace config.
*
* @param root root element of the workspace configuration
- *
+ * @return The workspace configuration
+ * @throws ConfigurationException
* @see #parseWorkspaceConfig(InputSource)
*/
protected WorkspaceConfig parseWorkspaceConfig(Element root)
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/UserManagerConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/UserManagerConfig.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/UserManagerConfig.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/UserManagerConfig.java Fri Oct 21 09:38:37 2011
@@ -16,11 +16,14 @@
*/
package org.apache.jackrabbit.core.config;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.jackrabbit.api.security.user.UserManager;
import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
/**
* User manager configuration. This bean configuration class is used to
@@ -39,9 +42,16 @@ public class UserManagerConfig extends B
private Constructor<?> constr;
+ private final BeanConfig[] actionConfig;
+
public UserManagerConfig(BeanConfig config) {
+ this(config, null);
+ }
+
+ public UserManagerConfig(BeanConfig config, BeanConfig[] actionConfig) {
super(config);
setValidate(false); // omit validation of the config properties
+ this.actionConfig = actionConfig;
}
/**
@@ -89,4 +99,17 @@ public class UserManagerConfig extends B
throw new ConfigurationException("Invalid UserManager implementation '" + getClassName() + "'.", e);
}
}
+
+ public AuthorizableAction[] getAuthorizableActions() throws ConfigurationException {
+ if (actionConfig == null || actionConfig.length == 0) {
+ return new AuthorizableAction[0];
+ } else {
+ List<AuthorizableAction> actions = new ArrayList<AuthorizableAction>(actionConfig.length);
+ for (BeanConfig c : actionConfig) {
+ AuthorizableAction action = c.newInstance(AuthorizableAction.class);
+ actions.add(action);
+ }
+ return actions.toArray(new AuthorizableAction[actions.size()]);
+ }
+ }
}
\ No newline at end of file
Modified: 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=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java Fri Oct 21 09:38:37 2011
@@ -266,6 +266,7 @@ abstract class AuthorizableImpl implemen
throw new RepositoryException("The administrator cannot be removed.");
}
Session s = getSession();
+ userManager.onRemove(this);
node.remove();
if (userManager.isAutoSave()) {
s.save();
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java Fri Oct 21 09:38:37 2011
@@ -31,6 +31,7 @@ import org.apache.jackrabbit.core.Sessio
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.security.principal.EveryonePrincipal;
import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
import org.apache.jackrabbit.core.session.SessionOperation;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
@@ -256,9 +257,20 @@ public class UserManagerImpl extends Pro
*/
private final int groupMembershipSplitSize;
+ /**
+ * The membership cache.
+ */
private final MembershipCache membershipCache;
/**
+ * Authorizable actions that will all be executed upon creation and removal
+ * of authorizables in the order they are contained in the array.<p/>
+ * Note, that if {@link #isAutoSave() autosave} is turned on, the configured
+ * actions are executed before persisting the creation or removal.
+ */
+ private AuthorizableAction[] authorizableActions = new AuthorizableAction[0];
+
+ /**
* Create a new <code>UserManager</code> with the default configuration.
*
* @param session The editing/reading session.
@@ -380,6 +392,18 @@ public class UserManagerImpl extends Pro
return groupMembershipSplitSize;
}
+ /**
+ * Set the authorizable actions that will be invoked upon authorizable
+ * creation and removal.
+ *
+ * @param authorizableActions An array of authorizable actions.
+ */
+ public void setAuthorizableActions(AuthorizableAction[] authorizableActions) {
+ if (authorizableActions != null) {
+ this.authorizableActions = authorizableActions;
+ }
+ }
+
//--------------------------------------------------------< UserManager >---
/**
* @see UserManager#getAuthorizable(String)
@@ -535,6 +559,7 @@ public class UserManagerImpl extends Pro
setProperty(userNode, P_PASSWORD, getValue(UserImpl.buildPasswordValue(password)), true);
User user = createUser(userNode);
+ onCreate(user);
if (isAutoSave()) {
session.save();
}
@@ -616,6 +641,7 @@ public class UserManagerImpl extends Pro
}
Group group = createGroup(groupNode);
+ onCreate(group);
if (isAutoSave()) {
session.save();
}
@@ -1004,6 +1030,35 @@ public class UserManagerImpl extends Pro
return n;
}
+ //--------------------------------------------------------------------------
+ /**
+ * Let the configured <code>AuthorizableAction</code>s perform additional
+ * tasks associated with the creation of the new authorizable before the
+ * corresponding new node is persisted.
+ *
+ * @param authorizable The new authorizable.
+ * @throws RepositoryException If an exception occurs.
+ */
+ void onCreate(Authorizable authorizable) throws RepositoryException {
+ for (AuthorizableAction action : authorizableActions) {
+ action.onCreate(authorizable, session);
+ }
+ }
+
+ /**
+ * Let the configured <code>AuthorizableAction</code>s perform any clean
+ * up tasks related to the authorizable removal (before the corresponding
+ * node gets removed).
+ *
+ * @param authorizable The authorizable to be removed.
+ * @throws RepositoryException If an exception occurs.
+ */
+ void onRemove(Authorizable authorizable) throws RepositoryException {
+ for (AuthorizableAction action : authorizableActions) {
+ action.onRemove(authorizable, session);
+ }
+ }
+
//----------------------------------------------------< SessionListener >---
/**
* @see SessionListener#loggingOut(org.apache.jackrabbit.core.SessionImpl)
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AccessControlAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AccessControlAction.java?rev=1187257&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AccessControlAction.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AccessControlAction.java Fri Oct 21 09:38:37 2011
@@ -0,0 +1,156 @@
+/*
+ *
+ * * 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.action;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.core.security.principal.UnknownPrincipal;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <code>AccessControlAction</code>
+ */
+public class AccessControlAction implements AuthorizableAction {
+
+ /**
+ * logger instance
+ */
+ private static final Logger log = LoggerFactory.getLogger(AccessControlAction.class);
+
+ private String[] groupPrivilegeNames = new String[0];
+ private String[] userPrivilegeNames = new String[0];
+
+ /**
+ * Create a new instance.
+ */
+ public AccessControlAction() {}
+
+ //-------------------------------------------------< AuthorizableAction >---
+ /**
+ * @see AuthorizableAction#onCreate(org.apache.jackrabbit.api.security.user.Authorizable, javax.jcr.Session)
+ */
+ public void onCreate(Authorizable authorizable, Session session) throws RepositoryException {
+ Node aNode;
+ String path = authorizable.getPath();
+
+ JackrabbitAccessControlList acl = null;
+ AccessControlManager acMgr = session.getAccessControlManager();
+ for (AccessControlPolicyIterator it = acMgr.getApplicablePolicies(path); it.hasNext();) {
+ AccessControlPolicy plc = it.nextAccessControlPolicy();
+ if (plc instanceof JackrabbitAccessControlList) {
+ acl = (JackrabbitAccessControlList) plc;
+ break;
+ }
+ }
+
+ if (acl == null) {
+ log.warn("Cannot process AccessControlAction: no applicable ACL at " + path);
+ } else {
+ // setup acl according to configuration.
+ Principal principal = new UnknownPrincipal(authorizable.getPrincipal().getName());
+ boolean modified = false;
+ if (authorizable.isGroup()) {
+ // new authorizable is a Group
+ if (groupPrivilegeNames.length > 0) {
+ modified = acl.addAccessControlEntry(principal, getPrivileges(groupPrivilegeNames, acMgr));
+ }
+ } else {
+ // new authorizable is a User
+ if (userPrivilegeNames.length > 0) {
+ modified = acl.addAccessControlEntry(principal, getPrivileges(userPrivilegeNames, acMgr));
+ }
+ }
+ if (modified) {
+ acMgr.setPolicy(path, acl);
+ }
+ }
+ }
+
+ /**
+ * @see AuthorizableAction#onRemove(org.apache.jackrabbit.api.security.user.Authorizable, javax.jcr.Session)
+ */
+ public void onRemove(Authorizable authorizable, Session session) throws RepositoryException {
+ // nothing to do.
+ }
+
+ //--------------------------------------------------------< Bean Config >---
+
+ public void setGroupPrivilegeNames(String privilegeNames) {
+ if (privilegeNames != null && privilegeNames.length() > 0) {
+ groupPrivilegeNames = split(privilegeNames);
+ }
+
+ }
+
+ public void setUserPrivilegeNames(String privilegeNames) {
+ if (privilegeNames != null && privilegeNames.length() > 0) {
+ userPrivilegeNames = split(privilegeNames);
+ }
+ }
+
+ //------------------------------------------------------------< private >---
+ /**
+ * Retrieve privileges for the specified privilege names.
+ *
+ * @param privNames
+ * @param acMgr
+ * @return Array of <code>Privilege</code>
+ * @throws javax.jcr.RepositoryException If a privilege name cannot be
+ * resolved to a valid privilege.
+ */
+ private static Privilege[] getPrivileges(String[] privNames, AccessControlManager acMgr) throws RepositoryException {
+ if (privNames == null || privNames.length == 0) {
+ return new Privilege[0];
+ }
+ Privilege[] privileges = new Privilege[privNames.length];
+ for (int i = 0; i < privNames.length; i++) {
+ privileges[i] = acMgr.privilegeFromName(privNames[i]);
+ }
+ return privileges;
+ }
+
+ /**
+ *
+ * @param configParam
+ * @return
+ */
+ private static String[] split(String configParam) {
+ List<String> nameList = new ArrayList<String>();
+ for (String pn : Text.explode(configParam, ',', false)) {
+ String privName = pn.trim();
+ if (privName.length() > 0) {
+ nameList.add(privName);
+ }
+ }
+ return nameList.toArray(new String[nameList.size()]);
+ }
+}
\ No newline at end of file
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AuthorizableAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AuthorizableAction.java?rev=1187257&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AuthorizableAction.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/AuthorizableAction.java Fri Oct 21 09:38:37 2011
@@ -0,0 +1,54 @@
+/*
+ *
+ * * 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.action;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+/**
+ * <code>AuthorizableAction</code>...
+ */
+public interface AuthorizableAction {
+
+ /**
+ * Allows to add application specific modifications associated with the
+ * creation of a new authorizable. Note, that this method is called
+ * <strong>before</strong> any <code>Session.save</code> call.
+ *
+ * @param authorizable The new authorizable that has not yet been persisted;
+ * e.g. the associated node is still 'NEW'.
+ * @param session The editing session associated with the user manager.
+ * @throws RepositoryException If an error occurs.
+ */
+ void onCreate(Authorizable authorizable, Session session) throws RepositoryException;
+
+ /**
+ * Allows to add application specific behavior associated with the removal
+ * of an authorizable. Note, that this method is called <strong>before</strong>
+ * {@link Authorizable#remove} is executed (and persisted); thus the
+ * target authorizable still exists.
+ *
+ * @param authorizable The authorizable to be removed.
+ * @param session The editing session associated with the user manager.
+ * @throws RepositoryException If an error occurs.
+ */
+ void onRemove(Authorizable authorizable, Session session) throws RepositoryException;
+}
\ No newline at end of file
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/ClearMembershipAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/ClearMembershipAction.java?rev=1187257&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/ClearMembershipAction.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/action/ClearMembershipAction.java Fri Oct 21 09:38:37 2011
@@ -0,0 +1,62 @@
+/*
+ *
+ * * 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.action;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import java.util.Iterator;
+
+/**
+ * <code>ClearMembershipAction</code>...
+ */
+public class ClearMembershipAction implements AuthorizableAction {
+
+ /**
+ * logger instance
+ */
+ private static final Logger log = LoggerFactory.getLogger(ClearMembershipAction.class);
+
+ /**
+ * Create a new instance.
+ */
+ public ClearMembershipAction() {}
+
+ //-------------------------------------------------< AuthorizableAction >---
+ /**
+ * @see AuthorizableAction#onCreate(org.apache.jackrabbit.api.security.user.Authorizable, javax.jcr.Session)
+ */
+ public void onCreate(Authorizable authorizable, Session session) throws RepositoryException {
+ // nothing to do
+ }
+
+ /**
+ * @see AuthorizableAction#onRemove(org.apache.jackrabbit.api.security.user.Authorizable, javax.jcr.Session)
+ */
+ public void onRemove(Authorizable authorizable, Session session) throws RepositoryException {
+ Iterator<Group> membership = authorizable.declaredMemberOf();
+ while (membership.hasNext()) {
+ membership.next().removeMember(authorizable);
+ }
+ }
+}
\ No newline at end of file
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/SecurityConfigTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/SecurityConfigTest.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/SecurityConfigTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/SecurityConfigTest.java Fri Oct 21 09:38:37 2011
@@ -29,6 +29,7 @@ import org.apache.jackrabbit.core.securi
import org.apache.jackrabbit.core.security.authentication.DefaultLoginModule;
import org.apache.jackrabbit.core.security.simple.SimpleAccessManager;
import org.apache.jackrabbit.core.security.simple.SimpleSecurityManager;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal;
import org.apache.jackrabbit.api.security.user.UserManager;
@@ -207,6 +208,30 @@ public class SecurityConfigTest extends
assertTrue(um.isAutoSave());
// changing autosave behavior must succeed.
um.autoSave(false);
+
+ // test authorizable-action configuration
+ xml = parseXML(new InputSource(new StringReader(USER_MANAGER_CONFIG_WITH_ACTIONS)), true);
+ umc = parser.parseSecurityConfig(xml).getSecurityManagerConfig().getUserManagerConfig();
+ AuthorizableAction[] actions = umc.getAuthorizableActions();
+ assertEquals(2, actions.length);
+
+ xml = parseXML(new InputSource(new StringReader(USER_MANAGER_CONFIG_WITH_INVALID_ACTIONS)), true);
+ umc = parser.parseSecurityConfig(xml).getSecurityManagerConfig().getUserManagerConfig();
+ try {
+ actions = umc.getAuthorizableActions();
+ fail("Invalid configuration - must fail");
+ } catch (ConfigurationException e) {
+ // success
+ }
+
+ xml = parseXML(new InputSource(new StringReader(USER_MANAGER_CONFIG_WITH_INVALID_ACTIONS_2)), true);
+ umc = parser.parseSecurityConfig(xml).getSecurityManagerConfig().getUserManagerConfig();
+ try {
+ actions = umc.getAuthorizableActions();
+ fail("Invalid configuration - must fail");
+ } catch (ConfigurationException e) {
+ // success
+ }
}
/**
@@ -356,6 +381,42 @@ public class SecurityConfigTest extends
" </SecurityManager>" +
" </Security>";
+ private static final String USER_MANAGER_CONFIG_WITH_ACTIONS =
+ " <Security appName=\"Jackrabbit\">" +
+ " <SecurityManager class=\"org.apache.jackrabbit.core.DefaultSecurityManager\" workspaceName=\"security\">" +
+ " <UserManager class=\"org.apache.jackrabbit.core.security.user.UserManagerImpl\">" +
+ " <AuthorizableAction class=\"org.apache.jackrabbit.core.security.user.action.AccessControlAction\">" +
+ " <param name=\"groupPrivilegeNames\" value=\"jcr:read, jcr:write\"/>" +
+ " <param name=\"userPrivilegeNames\" value=\" jcr:read , jcr:readAccessControl \"/>" +
+ " </AuthorizableAction>" +
+ " <AuthorizableAction class=\"org.apache.jackrabbit.core.security.user.action.ClearMembershipAction\"/>" +
+ " </UserManager>" +
+ " <UserIdClass class=\"org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal\"/>" +
+ " </SecurityManager>" +
+ " </Security>";
+
+ private static final String USER_MANAGER_CONFIG_WITH_INVALID_ACTIONS =
+ " <Security appName=\"Jackrabbit\">" +
+ " <SecurityManager class=\"org.apache.jackrabbit.core.DefaultSecurityManager\" workspaceName=\"security\">" +
+ " <UserManager class=\"org.apache.jackrabbit.core.security.user.UserManagerImpl\">" +
+ " <AuthorizableAction class=\"org.apache.jackrabbit.core.security.user.action.NonExistingAction\"/>" +
+ " </UserManager>" +
+ " <UserIdClass class=\"org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal\"/>" +
+ " </SecurityManager>" +
+ " </Security>";
+
+ private static final String USER_MANAGER_CONFIG_WITH_INVALID_ACTIONS_2 =
+ " <Security appName=\"Jackrabbit\">" +
+ " <SecurityManager class=\"org.apache.jackrabbit.core.DefaultSecurityManager\" workspaceName=\"security\">" +
+ " <UserManager class=\"org.apache.jackrabbit.core.security.user.UserManagerImpl\">" +
+ " <AuthorizableAction class=\"org.apache.jackrabbit.core.security.user.action.AccessControlAction\">" +
+ " <param name=\"invalidParam\" value=\"any value\"/>" +
+ " </AuthorizableAction>" +
+ " </UserManager>" +
+ " <UserIdClass class=\"org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal\"/>" +
+ " </SecurityManager>" +
+ " </Security>";
+
private static final String PRINCIPAL_PROVIDER_CONFIG =
" <Security appName=\"Jackrabbit\">" +
" <SecurityManager class=\"org.apache.jackrabbit.core.DefaultSecurityManager\" workspaceName=\"security\">" +
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java?rev=1187257&r1=1187256&r2=1187257&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java Fri Oct 21 09:38:37 2011
@@ -25,6 +25,9 @@ import org.apache.jackrabbit.api.securit
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.security.TestPrincipal;
import org.apache.jackrabbit.core.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.core.security.user.action.AccessControlAction;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
+import org.apache.jackrabbit.core.security.user.action.ClearMembershipAction;
import org.apache.jackrabbit.test.NotExecutableException;
import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
@@ -32,8 +35,13 @@ import javax.jcr.Credentials;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
+import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.Node;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
import java.security.Principal;
import java.util.HashMap;
import java.util.Iterator;
@@ -854,4 +862,105 @@ public class UserManagerImplTest extends
}
}
}
+
+ public void testAccessControlAction() throws Exception {
+ UserManagerImpl impl = (UserManagerImpl) userMgr;
+
+ AccessControlAction action = new AccessControlAction();
+ action.setUserPrivilegeNames("jcr:all");
+ action.setGroupPrivilegeNames("jcr:read");
+ AuthorizableAction[] testActions = new AuthorizableAction[] {action};
+
+ User u = null;
+ Group gr = null;
+ try {
+ impl.setAuthorizableActions(testActions);
+ String uid = getTestPrincipal().getName();
+ u = impl.createUser(uid, buildPassword(uid));
+ save(superuser);
+ assertAcAction(u, impl);
+
+ String grId = getTestPrincipal().getName();
+ gr = impl.createGroup(grId);
+ save(superuser);
+ assertAcAction(gr, impl);
+ } catch (UnsupportedRepositoryOperationException e) {
+ throw new NotExecutableException(e.getMessage());
+ } finally {
+ impl.setAuthorizableActions(new AuthorizableAction[0]);
+ if (u != null) {
+ u.remove();
+ }
+ if (gr != null) {
+ gr.remove();
+ }
+ save(superuser);
+ }
+ }
+
+ private static void assertAcAction(Authorizable a, UserManagerImpl umgr) throws RepositoryException, NotExecutableException {
+ Session s = umgr.getSession();
+ AccessControlManager acMgr = s.getAccessControlManager();
+ boolean hasACL = false;
+ AccessControlPolicyIterator it = acMgr.getApplicablePolicies("/");
+ while (it.hasNext()) {
+ if (it.nextAccessControlPolicy() instanceof AccessControlList) {
+ hasACL = true;
+ break;
+ }
+ }
+
+ if (!hasACL) {
+ for (AccessControlPolicy p : acMgr.getPolicies("/")) {
+ if (p instanceof AccessControlList) {
+ hasACL = true;
+ break;
+ }
+ }
+ }
+
+ if (!hasACL) {
+ throw new NotExecutableException("No ACLs in workspace containing users.");
+ }
+
+ String path = a.getPath();
+ assertEquals(1, acMgr.getPolicies(path).length);
+ assertTrue(acMgr.getPolicies(path)[0] instanceof AccessControlList);
+ }
+
+ public void testClearMembershipAction() throws Exception {
+ UserManagerImpl impl = (UserManagerImpl) userMgr;
+
+ AuthorizableAction[] testActions = new AuthorizableAction[] {new ClearMembershipAction()};
+
+ User u = null;
+ Group gr = null;
+ try {
+ impl.setAuthorizableActions(testActions);
+ String uid = getTestPrincipal().getName();
+ u = impl.createUser(uid, buildPassword(uid));
+
+ String grId = getTestPrincipal().getName();
+ gr = impl.createGroup(grId);
+ gr.addMember(u);
+
+ save(superuser);
+
+ assertTrue(gr.isMember(u));
+
+ u.remove();
+ u = null;
+
+ assertFalse(gr.isMember(u));
+ } finally {
+ impl.setAuthorizableActions(new AuthorizableAction[0]);
+ if (u != null) {
+ u.remove();
+ }
+ if (gr != null) {
+ gr.remove();
+ }
+ save(superuser);
+ }
+ }
}