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 2009/10/22 19:26:39 UTC

svn commit: r828791 [1/8] - in /jackrabbit/trunk: jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ jackrabbi...

Author: angela
Date: Thu Oct 22 17:26:37 2009
New Revision: 828791

URL: http://svn.apache.org/viewvc?rev=828791&view=rev
Log:
JCR-2313 - Improvements to user management (2) [work in progress] 
-> see issue for details

JCR-2333 - ItemImpl#validateTransientItems: Incomplete validation of mandatory child item
-> patch2

JCR-2195 - Provide possibility to import protected items using Session/Workspace import functionality
-> deal with reference properties
-> make import handlers configurable
-> add userimporter

JCR-171 - Make the extraction of Session UserIDs from Subjects configurable
-> extend SecurityManagerConfig and retrieve uid from principal name if configured
     class is present in the subject

JCR-2351 - Make Authorizable.setProperty more noisy in case of failure

JCR-2331 - Configurable DefaultPolicy replacing Initialization within the ACProvider
-> initial steps. remove code that relies on the default-init
-> add TODOs

JCR-2291 - Issues with compiled permissions of ACL provider
-> remove code searching for DENY-read entries in case of default initialization of ac entries

and here and there minor improvement, usage of generics etc....

Added:
    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/ImportConfig.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/UserImporter.java   (contents, props changed)
      - copied, changed from r818472, jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserPerWorkspaceUserManager.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManagerTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NodeCreationTest.java
      - copied, changed from r818472, jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/IdResolverTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java
Removed:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlEntryIterator.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/IdResolverTest.java
Modified:
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.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/SecurityManagerConfig.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/JackrabbitSecurityManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/WorkspaceAccessManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/DefaultPrincipalProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/ProviderRegistryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleSecurityManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleWorkspaceAccessManager.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/GroupImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/ReferenceChangeTracker.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/GroupTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/ImpersonationTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/NestedGroupTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerCreateGroupTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerCreateUserTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/NodeImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.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/config/WorkspaceConfigTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractEvaluationTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractVersionManagementTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/AbstractWriteTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/WriteTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/combined/WriteTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/principalbased/WriteTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/principal/DefaultPrincipalProviderTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AdministratorTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/GroupAdministratorTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/ImpersonationImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/IndexNodeResolverTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NodeResolverTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NotUserAdministratorTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/TestAll.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/TraversingNodeResolverTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserAdministratorTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/AccessControlImporterTest.java

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java Thu Oct 22 17:26:37 2009
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.api.security.user;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
 import java.security.Principal;
 import java.util.Iterator;
 
@@ -49,9 +50,9 @@
     /**
      * Get the Authorizable by its id.
      *
-     * @param id
+     * @param id The user or group id.
      * @return Authorizable or <code>null</code>, if not present.
-     * @throws RepositoryException
+     * @throws RepositoryException If an error occurs.
      * @see Authorizable#getID()
      */
     Authorizable getAuthorizable(String id) throws RepositoryException;
@@ -61,7 +62,7 @@
      *
      * @param principal
      * @return Authorizable or <code>null</code>, if not present.
-     * @throws RepositoryException
+     * @throws RepositoryException If an error occurs.
      */
     Authorizable getAuthorizable(Principal principal) throws RepositoryException;
 
@@ -74,10 +75,10 @@
      * @param value
      * @return All <code>Authorizable</code>s that have a property with the given
      * name exactly matching the given value.
-     * @throws RepositoryException
+     * @throws RepositoryException If an error occurs.
      * @see Authorizable#getProperty(String)
      */
-    Iterator findAuthorizables(String propertyName, String value) throws RepositoryException;
+    Iterator<Authorizable> findAuthorizables(String propertyName, String value) throws RepositoryException;
 
     /**
      * Returns all <code>Authorizable</code>s that have
@@ -94,10 +95,10 @@
      * <li>{@link #SEARCH_TYPE_GROUP}</li>
      * <li>{@link #SEARCH_TYPE_USER}</li>
      * </ul>
-     * @return
-     * @throws RepositoryException
+     * @return An iterator of <code>Authorizable</code>.
+     * @throws RepositoryException If an error occurs.
      */
-    Iterator findAuthorizables(String propertyName, String value, int searchType) throws RepositoryException;
+    Iterator<Authorizable> findAuthorizables(String propertyName, String value, int searchType) throws RepositoryException;
 
     /**
      * Creates an User for the given userID / password pair; neither of the
@@ -106,7 +107,7 @@
      * the specified userID is equal to the principal name and the intermediate
      * path is <code>null</code>.
      *
-     * @param userID
+     * @param userID The id of the new user.
      * @param password The initial password of this user.
      * @return The new <code>User</code>.
      * @throws AuthorizableExistsException in case the given userID is already
@@ -163,4 +164,35 @@
      * @throws RepositoryException If another error occurs.
      */
     Group createGroup(Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException;
+
+    /**
+     * If any write operations executed through the User API are automatically
+     * persisted this method returns <code>true</code>. In this case there are
+     * no pending transient changes left and there is no need to explicitely call
+     * {@link javax.jcr.Session#save()}. If this method returns <code>false</code>
+     * any changes must be completed by an extra save call on the
+     * <code>Session</code> associated with this <code>UserManager</code>.
+     *
+     * @return <code>true</code> if changes are automatically persisted;
+     * <code>false</code> if changes made through this API (including method
+     * calls on  {@link Authorizable} and subclasses are only transient and
+     * must be persisted using {@link javax.jcr.Session#save()}.
+     * @see #autoSave(boolean)
+     */
+    boolean isAutoSave();
+
+    /**
+     * Changes the auto save behavior of this <code>UserManager</code>.
+     * <p/>
+     * Note, that this shouldn't be allowed in cases where the associated session
+     * is different from the original session accessing the user manager.
+     *
+     * @param enable If <code>true</code> changes made through this API will
+     * be automatically saved; otherwise an explict call to
+     * {@link javax.jcr.Session#save()} is required in order to persist changes.
+     * @throws UnsupportedRepositoryOperationException If the implementation
+     * does not allow to change the auto save behavior.
+     * @throws RepositoryException If some other error occurs.
+     */
+    void autoSave(boolean enable) throws UnsupportedRepositoryOperationException, RepositoryException;
 }

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=828791&r1=828790&r2=828791&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 Thu Oct 22 17:26:37 2009
@@ -37,13 +37,14 @@
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.core.config.AccessManagerConfig;
-import org.apache.jackrabbit.core.config.BeanConfig;
 import org.apache.jackrabbit.core.config.LoginModuleConfig;
 import org.apache.jackrabbit.core.config.SecurityConfig;
 import org.apache.jackrabbit.core.config.SecurityManagerConfig;
 import org.apache.jackrabbit.core.config.WorkspaceConfig;
 import org.apache.jackrabbit.core.config.WorkspaceSecurityConfig;
+import org.apache.jackrabbit.core.config.UserManagerConfig;
 import org.apache.jackrabbit.core.security.AMContext;
 import org.apache.jackrabbit.core.security.AccessManager;
 import org.apache.jackrabbit.core.security.DefaultAccessManager;
@@ -94,9 +95,9 @@
     private RepositoryImpl repository;
 
     /**
-     * session on the system workspace.
+     * System session.
      */
-    private SystemSession securitySession;
+    private SystemSession systemSession;
 
     /**
      * System user manager. Implementation needed here for the DefaultPrincipalProvider.
@@ -104,11 +105,6 @@
     private UserManager systemUserManager;
 
     /**
-     * System Sessions PrincipalMangager used for internal access to Principals
-     */
-    private PrincipalManager systemPrincipalManager;
-
-    /**
      * The user id of the administrator. The value is retrieved from
      * configuration. If the config entry is missing a default id is used (see
      * {@link SecurityConstants#ADMIN_ID}).
@@ -120,7 +116,7 @@
      * configuration. If the config entry is missing a default id is used (see
      * {@link SecurityConstants#ANONYMOUS_ID}).
      */
-    private String anonymousId;
+    protected String anonymousId;
 
     /**
      * Contains the access control providers per workspace.
@@ -164,7 +160,7 @@
             throw new RepositoryException("SystemSession expected");
         }
 
-        securitySession = (SystemSession) systemSession;
+        this.systemSession = (SystemSession) systemSession;
         this.repository = (RepositoryImpl) repository;
 
         SecurityConfig config = this.repository.getConfig().getSecurityConfig();
@@ -204,12 +200,12 @@
         }
 
         // create the system userManager and make sure the system-users exist.
-        systemUserManager = createUserManager(securitySession);
-        createSystemUsers(systemUserManager, adminId, anonymousId);
+        systemUserManager = createUserManager(this.systemSession);
+        createSystemUsers(systemUserManager, this.systemSession, adminId, anonymousId);
 
         // init default ac-provider-factory
         acProviderFactory = new AccessControlProviderFactoryImpl();
-        acProviderFactory.init(securitySession);
+        acProviderFactory.init(this.systemSession);
 
         // create the workspace access manager
         SecurityManagerConfig smc = config.getSecurityManagerConfig();
@@ -218,14 +214,13 @@
         } else {
             // fallback -> the default implementation
             log.debug("No WorkspaceAccessManager configured; using default.");
-            workspaceAccessManager = new WorkspaceAccessManagerImpl();
+            workspaceAccessManager = createDefaultWorkspaceAccessManager();
         }
-        workspaceAccessManager.init(securitySession);
+        workspaceAccessManager.init(this.systemSession);
 
         // initialize principal-provider registry
         // 1) create default
-        PrincipalProvider defaultPP = new DefaultPrincipalProvider(securitySession, (UserManagerImpl) systemUserManager);
-        defaultPP.init(new Properties());
+        PrincipalProvider defaultPP = createDefaultPrincipalProvider();
         // 2) create registry instance
         principalProviderRegistry = new ProviderRegistryImpl(defaultPP);
         // 3) register all configured principal providers.
@@ -233,35 +228,10 @@
             principalProviderRegistry.registerProvider(props);
         }
 
-        // create the principal manager for the security workspace
-        systemPrincipalManager = new PrincipalManagerImpl(securitySession, principalProviderRegistry.getProviders());
-
         initialized = true;
     }
 
     /**
-     * Creates a {@link UserManagerImpl} for the given session. May be overridden
-     * to return a custom implementation.
-     *
-     * @param session session
-     * @return user manager
-     * @throws RepositoryException if an error occurs
-     */
-    protected UserManagerImpl createUserManager(SessionImpl session) throws RepositoryException {
-        BeanConfig umc = repository.getConfig().getSecurityConfig().getSecurityManagerConfig().getUserManagerConfig();
-        Properties config = null;
-        if (umc != null) {
-            // TODO: deal with other user manager implementations.
-            String clName = umc.getClassName();
-            if (clName != null && !(UserManagerImpl.class.getName().equals(clName) || clName.length() == 0)) {
-                log.warn("Unsupported custom UserManager implementation: '" + clName + "' -> Ignored.");
-            }
-            config = umc.getParameters();
-        }
-        return new UserManagerImpl(session, adminId, config);
-    }
-
-    /**
      * @see JackrabbitSecurityManager#dispose(String)
      */
     public void dispose(String workspaceName) {
@@ -323,11 +293,9 @@
      */
     public PrincipalManager getPrincipalManager(Session session) throws RepositoryException {
         checkInitialized();
-        if (session == securitySession) {
-            return systemPrincipalManager;
-        } else if (session instanceof SessionImpl) {
+        if (session instanceof SessionImpl) {
             SessionImpl sImpl = (SessionImpl) session;
-            return new PrincipalManagerImpl(sImpl, principalProviderRegistry.getProviders());
+            return createPrincipalManager(sImpl);
         } else {
             throw new RepositoryException("Internal error: SessionImpl expected.");
         }
@@ -338,10 +306,10 @@
      */
     public UserManager getUserManager(Session session) throws RepositoryException {
         checkInitialized();
-        if (session == securitySession) {
+        if (session == systemSession) {
             return systemUserManager;
         } else if (session instanceof SessionImpl) {
-            String workspaceName = securitySession.getWorkspace().getName();
+            String workspaceName = systemSession.getWorkspace().getName();
             try {
                 SessionImpl sImpl = (SessionImpl) session;
                 UserManagerImpl uMgr;
@@ -362,63 +330,212 @@
     }
 
     /**
-     * @see JackrabbitSecurityManager#getUserID(Subject)
+     * @see JackrabbitSecurityManager#getUserID(javax.security.auth.Subject, String)
      */
-    public String getUserID(Subject subject) throws RepositoryException {
+    public String getUserID(Subject subject, String workspaceName) throws RepositoryException {
         checkInitialized();
+
         /* shortcut if the subject contains the AdminPrincipal in which case
            the userID is already known. */
         if (!subject.getPrincipals(AdminPrincipal.class).isEmpty()) {
             return adminId;
         }
+        /* if there is a configure principal class that should be used to
+           determine the UserID -> try this one. */
+        Class cl = getConfig().getUserIdClass();
+        if (cl != null) {
+            Set<Principal> s = subject.getPrincipals(cl);
+            if (!s.isEmpty()) {
+                for (Principal p : s) {
+                    if (!(p instanceof java.security.acl.Group)) {
+                        return p.getName();
+                    }
+                }
+                // all principals found with the given p-Class were Group principals
+                log.debug("Only Group principals found with class '" + cl.getName() + "' -> Not used for UserID.");
+            } else {
+                log.debug("No principal found with class '" + cl.getName() + "'.");
+            }
+        }
+
         /*
-         Retrieve userID from the subject.
+         Fallback szenario to retrieve userID from the subject:
          Since the subject may contain multiple principals and the principal
-         name must not be equals to the UserID by definition, the userID
-         may either be obtained from the login-credentials or from the
-         user manager. in the latter case the set of principals present with
-         the specified subject is used to search for the user.
+         name may not be equals to the UserID, the id is retrieved by
+         searching for the corresponding authorizable and if this doesn't
+         succeed an attempt is made to obtained it from the login-credentials.
         */
         String uid = null;
-        // try simple access to userID over SimpleCredentials first.
-        Iterator<SimpleCredentials> creds = subject.getPublicCredentials(
-                SimpleCredentials.class).iterator();
-        if (creds.hasNext()) {
-            SimpleCredentials sc = creds.next();
-            uid = sc.getUserID();
-        } else {
-            // no SimpleCredentials: retrieve authorizables corresponding to
-            // a non-group principal. the first one present is used to determine
-            // the userID.
+
+        // first try to retrieve an authorizable corresponding to
+        // a non-group principal. the first one present is used
+        // to determine the userID.
+        try {
+            UserManager umgr = getSystemUserManager(workspaceName);
             for (Principal p : subject.getPrincipals()) {
                 if (!(p instanceof Group)) {
-                    Authorizable authorz = systemUserManager.getAuthorizable(p);
+                    Authorizable authorz = umgr.getAuthorizable(p);
                     if (authorz != null && !authorz.isGroup()) {
                         uid = authorz.getID();
                         break;
                     }
                 }
             }
+        } catch (RepositoryException e) {
+            // failed to access userid via user manager -> use fallback 2.
+            log.error("Unexpected error while retrieving UserID.", e);
+        }
+
+        // 2. if no matching user is found try simple access to userID over
+        // SimpleCredentials.
+        if (uid == null) {
+            Iterator<SimpleCredentials> creds = subject.getPublicCredentials(
+                    SimpleCredentials.class).iterator();
+            if (creds.hasNext()) {
+                SimpleCredentials sc = creds.next();
+                uid = sc.getUserID();
+            }
         }
+
         return uid;
     }
 
     /**
      * Creates an AuthContext for the given {@link Credentials} and
-     * {@link Subject}.<br>
+     * {@link Subject}. The workspace name is ignored and users are
+     * stored and retrieved from a specific (separate) workspace.<br>
      * This includes selection of application specific LoginModules and
      * initialization 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)
+    public AuthContext getAuthContext(Credentials creds, Subject subject, String workspaceName)
             throws RepositoryException {
         checkInitialized();
-        return authContextProvider.getAuthContext(creds, subject, securitySession,
-                principalProviderRegistry, adminId, anonymousId);
+        return getAuthContextProvider().getAuthContext(creds, subject, systemSession,
+                getPrincipalProviderRegistry(), adminId, anonymousId);
+    }
+
+    //----------------------------------------------------------< protected >---    
+    /**
+     * @return The <code>SecurityManagerConfig</code> configured for the
+     * repository this manager has been created for.
+     */
+    protected SecurityManagerConfig getConfig() {
+        return repository.getConfig().getSecurityConfig().getSecurityManagerConfig();
+    }   
+
+    /**
+     * @param workspaceName
+     * @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.
+     */
+    protected UserManager getSystemUserManager(String workspaceName) throws RepositoryException {
+        return systemUserManager;
     }
 
+    /**
+     * Creates a {@link UserManagerImpl} for the given session. May be overridden
+     * to return a custom implementation.
+     *
+     * @param session session
+     * @return user manager
+     * @throws RepositoryException if an error occurs
+     */
+    protected UserManagerImpl createUserManager(SessionImpl session) throws RepositoryException {
+        UserManagerConfig umc = getConfig().getUserManagerConfig();
+        Properties params = (umc == null) ? null : umc.getParameters();
+
+        // since users are stored in and retrieved from a dedicated workspace
+        // only the system session assigned with that workspace will get the
+        // system user manager (special implementation that asserts the existance
+        // of the admin user).
+        if (session == systemSession) {
+            return new SystemUserManager(systemSession, params);
+        } else {
+            UserManagerImpl um;
+            if (umc != null) {
+                Class<?>[] paramTypes = new Class[] { SessionImpl.class, String.class, Properties.class };
+                um = (UserManagerImpl) umc.getUserManager(UserManagerImpl.class, paramTypes, (SessionImpl) session, adminId, params);
+                // 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);
+            }
+            return um;
+        }
+    }
+
+    /**
+     * @param session The session used to create the principal manager.
+     * @return A new instance of PrincipalManagerImpl
+     * @throws javax.jcr.RepositoryException If an error occurs.
+     */
+    protected PrincipalManager createPrincipalManager(SessionImpl session) throws RepositoryException {
+        return new PrincipalManagerImpl(session, getPrincipalProviderRegistry().getProviders());
+    }
+
+    /**
+     * @return A nwe instance of WorkspaceAccessManagerImpl to be used as
+     * default workspace access manager if the configuration doesn't specify one.
+     */
+    protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
+        return new WorkspaceAccessManagerImpl();
+    }
+
+    /**
+     * Creates the default principal provider used to create the
+     * {@link PrincipalProviderRegistry}.
+     * 
+     * @return An new instance of <code>DefaultPrincipalProvider</code>.
+     * @throws RepositoryException If an error occurs.
+     */
+    protected PrincipalProvider createDefaultPrincipalProvider() throws RepositoryException {
+        PrincipalProvider defaultPP = new DefaultPrincipalProvider(this.systemSession, (UserManagerImpl) systemUserManager);
+        defaultPP.init(new Properties());
+        return defaultPP;
+    }
+
+    /**
+     * @return The PrincipalProviderRegistry created during initialization.
+     */
+    protected PrincipalProviderRegistry getPrincipalProviderRegistry() {
+        return principalProviderRegistry;
+    }
+
+    /**
+     * @return The AuthContextProvider created during initialization.
+     */
+    protected AuthContextProvider getAuthContextProvider() {
+        return authContextProvider;
+    }
+
+    /**
+     * Throws <code>IllegalStateException</code> if this manager hasn't been
+     * initialized.
+     */
+    protected void checkInitialized() {
+        if (!initialized) {
+            throw new IllegalStateException("Not initialized");
+        }
+    }
+
+    /**
+     * @return The system session used to initialize this SecurityManager.
+     */
+    protected Session getSystemSession() {
+        return systemSession;
+    }
+
+    /**
+     * @return The repository used to initialize this SecurityManager.
+     */
+    protected Repository getRepository() {
+        return repository;
+    }
     //--------------------------------------------------------------------------
     /**
      * Returns the access control provider for the specified
@@ -455,59 +572,77 @@
      * configured (or default) adminID is member of this user-group.
      *
      * @param userManager Manager to create users/groups.
+     * @param session
      * @param adminId UserID of the administrator.
      * @param anonymousId UserID of the anonymous user.
      * @throws RepositoryException If an error occurs.
      */
-    private static void createSystemUsers(UserManager userManager,
-                                          String adminId,
-                                          String anonymousId) throws RepositoryException {
-        Principal pr = new PrincipalImpl(SecurityConstants.ADMINISTRATORS_NAME);
-        Group admins = (Group) userManager.getAuthorizable(pr);
-        if (admins == null) {
-            admins = userManager.createGroup(new PrincipalImpl(SecurityConstants.ADMINISTRATORS_NAME));
-            log.debug("...created administrators group with name '"+SecurityConstants.ADMINISTRATORS_NAME+"'");
-        }
+    static void createSystemUsers(UserManager userManager,
+                                  SystemSession session,
+                                  String adminId,
+                                  String anonymousId) throws RepositoryException {
 
+        Authorizable admin = null;
         if (adminId != null) {
-            Authorizable admin = userManager.getAuthorizable(adminId);
+            admin = userManager.getAuthorizable(adminId);
             if (admin == null) {
                 admin = userManager.createUser(adminId, adminId);
-                log.info("...created admin-user with id \'" + adminId + "\' ...");
-                admins.addMember(admin);
-                log.info("...added admin \'" + adminId + "\' as member of the administrators group.");
+                if (!userManager.isAutoSave()) {
+                    session.save();
+                }
+                log.info("... created admin-user with id \'" + adminId + "\' ...");
+            }
+        }
+
+        // assume administrators groupID and principalName are the same.
+        // and avoid retrieving group by principal.
+        Group admins = (Group) userManager.getAuthorizable(SecurityConstants.ADMINISTRATORS_NAME);
+        if (admins == null) {
+            admins = userManager.createGroup(new PrincipalImpl(SecurityConstants.ADMINISTRATORS_NAME));
+            if (!userManager.isAutoSave()) {
+                session.save();
+            }
+            log.info("... created administrators group with name '"+SecurityConstants.ADMINISTRATORS_NAME+"'");
+        }
+
+        try {
+            if (admins != null && admins.addMember(admin)) {
+                if (!userManager.isAutoSave()) {
+                    session.save();
+                }
+                log.info("... added admin '" + adminId + "' as member of the administrators group.");
             }
+        } catch (RepositoryException e) {
+            // administrator has full permissions anyway. just log a
+            // warning and ignore the error.
+            log.warn("Unexpected error while adding admin to the administrators group", e);
         }
 
         if (anonymousId != null) {
             Authorizable anonymous = userManager.getAuthorizable(anonymousId);
             if (anonymous == null) {
                 userManager.createUser(anonymousId, "");
-                log.info("...created anonymous-user with id \'" + anonymousId + "\' ...");
+                if (!userManager.isAutoSave()) {
+                    session.save();
+                }
+                log.info("... created anonymous-user with id \'" + anonymousId + "\' ...");
             }
         }
     }
 
-    private void checkInitialized() {
-        if (!initialized) {
-            throw new IllegalStateException("Not initialized");
-        }
-    }
-
     //------------------------------------------------------< inner classes >---
     /**
      * <code>WorkspaceAccessManager</code> that upon {@link #grants(Set principals, String)}
      * evaluates if access to the root node of a workspace with the specified
      * name is granted.
      */
-    private class WorkspaceAccessManagerImpl implements SecurityConstants, WorkspaceAccessManager {
+    private final class WorkspaceAccessManagerImpl implements SecurityConstants, WorkspaceAccessManager {
 
         //-----------------------------------------< WorkspaceAccessManager >---
         /**
          * {@inheritDoc}
-         * @param securitySession
          */
-        public void init(Session securitySession) throws RepositoryException {
+        public void init(Session systemSession) throws RepositoryException {
             // nothing to do here.
         }
 
@@ -526,4 +661,39 @@
             return prov.canAccessRoot(principals);
         }
     }
+
+    /**
+     * System user manager that (re) creates the admin user in case it doesn't
+     * exist yet (upon initial startup) or has been deleted.
+     */
+    protected final class  SystemUserManager extends UserManagerImpl {
+
+        private final SystemSession session;
+        private String adminPw;
+
+        protected SystemUserManager(SystemSession session, Properties config) throws RepositoryException {
+            super(session, adminId, config);
+            this.session = session;
+            adminPw = adminId; // The default value as defined upon #createSystemUsers
+        }
+
+        @Override
+        public Authorizable getAuthorizable(String id) throws RepositoryException {
+            Authorizable a = super.getAuthorizable(id);
+            if (a == null && adminId.equals(id)) {
+                log.info("Admin user does not exist.");
+                a = createAdmin(adminId, adminPw);
+            }
+            return a;
+        }
+
+        private User createAdmin(String adminId, String pw) throws RepositoryException {
+            User admin = createUser(adminId, pw);
+            if (!isAutoSave()) {
+                session.save();
+            }
+            log.info("... created admin user with id \'" + adminId + "\' and default pw.");
+            return admin;
+        }
+    }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java Thu Oct 22 17:26:37 2009
@@ -47,6 +47,7 @@
 
 import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
 import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
@@ -425,11 +426,10 @@
                 if (nodeState.getStatus() == ItemState.STATUS_NEW
                         || !nodeState.getNodeTypeName().equals(
                             ((NodeState) nodeState.getOverlayedState()).getNodeTypeName())) {
-                    NodeType[] nta = nodeDef.getRequiredPrimaryTypes();
-                    for (int i = 0; i < nta.length; i++) {
-                        NodeTypeImpl ntReq = (NodeTypeImpl) nta[i];
-                        if (!(pnt.getQName().equals(ntReq.getQName())
-                                || pnt.isDerivedFrom(ntReq.getQName()))) {
+                    for (NodeType ntReq : nodeDef.getRequiredPrimaryTypes()) {
+                        Name ntName = ((NodeTypeImpl) ntReq).getQName();
+                        if (!(pnt.getQName().equals(ntName)
+                                || pnt.isDerivedFrom(ntName))) {
                             /**
                              * the transient node's primary node type does not
                              * satisfy the 'required primary types' constraint
@@ -443,9 +443,7 @@
                 }
 
                 // mandatory child properties
-                QPropertyDefinition[] pda = ent.getMandatoryPropDefs();
-                for (int i = 0; i < pda.length; i++) {
-                    QPropertyDefinition pd = pda[i];
+                for (QPropertyDefinition pd : ent.getMandatoryPropDefs()) {
                     if (pd.getDeclaringNodeType().equals(NameConstants.MIX_VERSIONABLE)
                             || pd.getDeclaringNodeType().equals(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
                         /**
@@ -455,24 +453,52 @@
                          */
                         continue;
                     }
-                    if (!nodeState.hasPropertyName(pd.getName())) {
-                        String msg = itemMgr.safeGetJCRPath(id)
+                    String msg = itemMgr.safeGetJCRPath(id)
                                 + ": mandatory property " + pd.getName()
                                 + " does not exist";
+                    if (!nodeState.hasPropertyName(pd.getName())) {
                         log.debug(msg);
                         throw new ConstraintViolationException(msg);
+                    } else {
+                        /*
+                        there exists a property with the mandatory-name.
+                        make sure the property really has the expected mandatory
+                        property definition (and not another non-mandatory def,
+                        such as e.g. multivalued residual instead of single-value
+                        mandatory, named def).
+                        */
+                        PropertyId pi = new PropertyId(nodeState.getNodeId(), pd.getName());
+                        ItemData childData = itemMgr.getItemData(pi, null, false);
+                        if (!childData.getDefinition().isMandatory()) {
+                            throw new ConstraintViolationException(msg);
+                        }
                     }
                 }
                 // mandatory child nodes
-                QItemDefinition[] cnda = ent.getMandatoryNodeDefs();
-                for (int i = 0; i < cnda.length; i++) {
-                    QItemDefinition cnd = cnda[i];
-                    if (!nodeState.hasChildNodeEntry(cnd.getName())) {
-                        String msg = itemMgr.safeGetJCRPath(id)
+                for (QItemDefinition cnd : ent.getMandatoryNodeDefs()) {
+                    String msg = itemMgr.safeGetJCRPath(id)
                                 + ": mandatory child node " + cnd.getName()
                                 + " does not exist";
+                    if (!nodeState.hasChildNodeEntry(cnd.getName())) {                      
                         log.debug(msg);
                         throw new ConstraintViolationException(msg);
+                    } else {
+                        /*
+                        there exists a child node with the mandatory-name.
+                        make sure the node really has the expected mandatory
+                        node definition.
+                        */
+                        boolean hasMandatoryChild = false;
+                        for (ChildNodeEntry cne : nodeState.getChildNodeEntries(cnd.getName())) {
+                            ItemData childData = itemMgr.getItemData(cne.getId(), null, false);
+                            if (childData.getDefinition().isMandatory()) {
+                                hasMandatoryChild = true;
+                                break;
+                            }
+                        }
+                        if (!hasMandatoryChild) {
+                            throw new ConstraintViolationException(msg);
+                        }
                     }
                 }
             } else {
@@ -509,11 +535,11 @@
                         if (constraints.length > 0
                                 && (propDef.getRequiredType() == PropertyType.REFERENCE
                                     || propDef.getRequiredType() == PropertyType.WEAKREFERENCE)) {
-                            for (int i = 0; i < values.length; i++) {
+                            for (InternalValue internalV : values) {
                                 boolean satisfied = false;
                                 String constraintViolationMsg = null;
                                 try {
-                                    NodeId targetId = values[i].getNodeId();
+                                    NodeId targetId = internalV.getNodeId();
                                     if (propDef.getRequiredType() == PropertyType.WEAKREFERENCE
                                         && !itemMgr.itemExists(targetId)) {
                                         // target of weakref doesn;t exist, skip
@@ -524,14 +550,13 @@
                                      * constraints are OR-ed, i.e. at least one
                                      * has to be satisfied
                                      */
-                                    for (int j = 0; j < constraints.length; j++) {
+                                    for (String constrNtName : constraints) {
                                         /**
                                          * a [WEAK]REFERENCE value constraint specifies
                                          * the name of the required node type of
                                          * the target node
                                          */
-                                        String ntName = constraints[j];
-                                        if (targetNode.isNodeType(ntName)) {
+                                        if (targetNode.isNodeType(constrNtName)) {
                                             satisfied = true;
                                             break;
                                         }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java Thu Oct 22 17:26:37 2009
@@ -356,7 +356,7 @@
      *                               read the said item
      * @throws RepositoryException   if another error occurs
      */
-    private ItemData getItemData(ItemId itemId, Path path, boolean permissionCheck)
+    ItemData getItemData(ItemId itemId, Path path, boolean permissionCheck)
             throws ItemNotFoundException, AccessDeniedException,
             RepositoryException {
         ItemData data = retrieveItem(itemId);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Thu Oct 22 17:26:37 2009
@@ -520,16 +520,14 @@
         thisState.addChildNodeEntry(name, nodeState.getNodeId());
 
         // add 'auto-create' properties defined in node type
-        PropertyDefinition[] pda = nodeType.getAutoCreatedPropertyDefinitions();
-        for (int i = 0; i < pda.length; i++) {
-            PropertyDefinitionImpl pd = (PropertyDefinitionImpl) pda[i];
+        for (PropertyDefinition aPda : nodeType.getAutoCreatedPropertyDefinitions()) {
+            PropertyDefinitionImpl pd = (PropertyDefinitionImpl) aPda;
             node.createChildProperty(pd.unwrap().getName(), pd.getRequiredType(), pd);
         }
 
         // recursively add 'auto-create' child nodes defined in node type
-        NodeDefinition[] nda = nodeType.getAutoCreatedNodeDefinitions();
-        for (int i = 0; i < nda.length; i++) {
-            NodeDefinitionImpl nd = (NodeDefinitionImpl) nda[i];
+        for (NodeDefinition aNda : nodeType.getAutoCreatedNodeDefinitions()) {
+            NodeDefinitionImpl nd = (NodeDefinitionImpl) aNda;
             node.createChildNode(nd.unwrap().getName(), (NodeTypeImpl) nd.getDefaultPrimaryType(), null);
         }
 
@@ -918,9 +916,8 @@
             setMixinTypesProperty(mixins);
 
             // add 'auto-create' properties defined in mixin type
-            PropertyDefinition[] pda = mixin.getAutoCreatedPropertyDefinitions();
-            for (int i = 0; i < pda.length; i++) {
-                PropertyDefinitionImpl pd = (PropertyDefinitionImpl) pda[i];
+            for (PropertyDefinition aPda : mixin.getAutoCreatedPropertyDefinitions()) {
+                PropertyDefinitionImpl pd = (PropertyDefinitionImpl) aPda;
                 // make sure that the property is not already defined by primary type
                 // or existing mixin's
                 NodeTypeImpl declaringNT = (NodeTypeImpl) pd.getDeclaringNodeType();
@@ -930,9 +927,8 @@
             }
 
             // recursively add 'auto-create' child nodes defined in mixin type
-            NodeDefinition[] nda = mixin.getAutoCreatedNodeDefinitions();
-            for (int i = 0; i < nda.length; i++) {
-                NodeDefinitionImpl nd = (NodeDefinitionImpl) nda[i];
+            for (NodeDefinition aNda : mixin.getAutoCreatedNodeDefinitions()) {
+                NodeDefinitionImpl nd = (NodeDefinitionImpl) aNda;
                 // make sure that the child node is not already defined by primary type
                 // or existing mixin's
                 NodeTypeImpl declaringNT = (NodeTypeImpl) nd.getDeclaringNodeType();
@@ -1786,8 +1782,8 @@
         // create new child node
         NodeImpl node = addNode(nodeName, nodeTypeName, id);
         if (mixinNames != null) {
-            for (int i = 0; i < mixinNames.length; i++) {
-                node.addMixin(mixinNames[i]);
+            for (Name mixinName : mixinNames) {
+                node.addMixin(mixinName);
             }
         }
 
@@ -3409,7 +3405,7 @@
         if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
             return PropertyIteratorAdapter.EMPTY;
         }
-        
+
         try {
             StringBuilder stmt = new StringBuilder();
             stmt.append("//*[@").append(ISO9075.encode(name));

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Thu Oct 22 17:26:37 2009
@@ -19,7 +19,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.StringReader;
@@ -33,7 +32,6 @@
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.Iterator;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -1065,7 +1063,7 @@
         } else {
             log.debug("Found preauthenticated Subject, try to extend authentication");
             // login either using JAAS or custom LoginModule
-            AuthContext authCtx = getSecurityManager().getAuthContext(null, subject);
+            AuthContext authCtx = getSecurityManager().getAuthContext(null, subject, workspaceName);
             try {
                 authCtx.login();
                 s = createSession(authCtx, workspaceName);
@@ -1320,8 +1318,8 @@
         // now set customized repository descriptor values (if any exist)
         Properties props = getCustomRepositoryDescriptors();
         if (props != null) {
-            for (Iterator it = props.keySet().iterator(); it.hasNext();) {
-                String key = (String) it.next();
+            for (Object o : props.keySet()) {
+                String key = (String) o;
                 setDescriptor(key, props.getProperty(key));
             }
         }
@@ -1462,16 +1460,15 @@
                 }
             }
             // not preauthenticated -> try login with credentials
-            AuthContext authCtx = getSecurityManager().getAuthContext(credentials, new Subject());
+            AuthContext authCtx = getSecurityManager().getAuthContext(credentials, new Subject(), workspaceName);
             authCtx.login();
 
             // create session, and add SimpleCredentials attributes (JCR-1932)
             SessionImpl session = createSession(authCtx, workspaceName);
             if (credentials instanceof SimpleCredentials) {
                 SimpleCredentials sc = (SimpleCredentials) credentials;
-                String[] names = sc.getAttributeNames();
-                for (int i = 0; i < names.length; i++) {
-                    session.setAttribute(names[i], sc.getAttribute(names[i]));
+                for (String name : sc.getAttributeNames()) {
+                    session.setAttribute(name, sc.getAttribute(name));
                 }
             }
             return session;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Thu Oct 22 17:26:37 2009
@@ -50,8 +50,6 @@
 import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
 import org.apache.jackrabbit.core.xml.ImportHandler;
 import org.apache.jackrabbit.core.xml.SessionImporter;
-import org.apache.jackrabbit.core.xml.AccessControlImporter;
-import org.apache.jackrabbit.core.xml.ProtectedNodeImporter;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
@@ -86,7 +84,6 @@
 import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.ValueFactory;
 import javax.jcr.Workspace;
-import javax.jcr.ImportUUIDBehavior;
 import javax.jcr.lock.Lock;
 import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.ConstraintViolationException;
@@ -280,7 +277,7 @@
         this.rep = rep;
         this.subject = subject;
 
-        userId = retrieveUserId(subject);
+        userId = retrieveUserId(subject, wspConfig.getName());
 
         namePathResolver = new DefaultNamePathResolver(this, this, true);
         ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), this, rep.getDataStore());
@@ -300,8 +297,8 @@
      *
      * @return the userID.
      */
-    protected String retrieveUserId(Subject subject) throws RepositoryException {
-        return rep.getSecurityManager().getUserID(subject);
+    protected String retrieveUserId(Subject subject, String workspaceName) throws RepositoryException {
+        return rep.getSecurityManager().getUserID(subject, workspaceName);
     }
 
     /**
@@ -1166,9 +1163,7 @@
                 ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
         getValidator().checkModify(parent, options, Permission.NONE);
 
-        // TODO: make configurable
-        ProtectedNodeImporter pi = new AccessControlImporter(this, this, false, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
-        SessionImporter importer = new SessionImporter(parent, this, uuidBehavior, pi, null);
+        SessionImporter importer = new SessionImporter(parent, this, uuidBehavior, wsp.getConfig().getImportConfig());
         return new ImportHandler(importer, this);
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java Thu Oct 22 17:26:37 2009
@@ -81,7 +81,7 @@
      *
      * @return the name of <code>SystemPrincipal</code>.
      */
-    protected String retrieveUserId(Subject subject) throws RepositoryException {
+    protected String retrieveUserId(Subject subject, String workspaceName) throws RepositoryException {
         return new SystemPrincipal().getName();
     }
 

Added: 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=828791&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java Thu Oct 22 17:26:37 2009
@@ -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;
+
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.core.config.UserManagerConfig;
+import org.apache.jackrabbit.core.security.authentication.AuthContext;
+import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
+import org.apache.jackrabbit.core.security.principal.DefaultPrincipalProvider;
+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.apache.jackrabbit.core.security.simple.SimpleWorkspaceAccessManager;
+import org.apache.jackrabbit.core.security.user.UserPerWorkspaceUserManager;
+import org.apache.jackrabbit.core.security.user.UserManagerImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Derived security manager implementation that expects that users information
+ * is present in each workspace instead of having a single, dedicated
+ * "security-workspace" that provides user information. Consequently, the
+ * UserManager used to retrieve and manipulate user content is always
+ * bound to the <code>Session</code> passed to {@link #getUserManager(Session)}.
+ * <p/> In addition the default (user-based) principal provider created by
+ * {@link org.apache.jackrabbit.core.DefaultSecurityManager}
+ * cannot be used to retrieve principals. Instead this implementation keeps
+ * a distinct pp-registry for each workspace.
+ * </p>
+ * NOTE: While this security manager asserts that a minimal set of system
+ * users (admin, administrators group and anonymous) is present in each workspace
+ * it doesn't make any attempt to set or define the access permissions on the
+ * tree containing user related information. 
+ */
+public class UserPerWorkspaceSecurityManager extends DefaultSecurityManager {
+
+    /**
+     * the default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(UserPerWorkspaceSecurityManager.class);
+
+    private final Map<String, PrincipalProviderRegistry> ppRegistries = new HashMap();
+
+    /**
+     * List of workspace names for which {@link #createSystemUsers} has already
+     * been called.
+     */
+    private final List<String> systemUsersInitialized = new ArrayList();
+
+    private PrincipalProviderRegistry getPrincipalProviderRegistry(SessionImpl s) throws RepositoryException {
+        String wspName = s.getWorkspace().getName();
+        PrincipalProviderRegistry p = ppRegistries.get(wspName);
+        if (p == null) {
+            SystemSession systemSession;
+            if (s instanceof SystemSession) {
+                systemSession = (SystemSession) s;
+            } else {
+                RepositoryImpl repo = (RepositoryImpl) getRepository();
+                systemSession = repo.getSystemSession(wspName);
+                // TODO: review again... this workaround is used in several places.
+                repo.onSessionCreated(systemSession);
+            }
+
+            PrincipalProvider defaultPP = new DefaultPrincipalProvider(systemSession, (UserManagerImpl) getUserManager(systemSession));
+            defaultPP.init(new Properties());
+            
+            p = new WorkspaceBasedPrincipalProviderRegistry(defaultPP);
+            ppRegistries.put(wspName, p);
+        }
+        return p;
+    }
+
+    //------------------------------------------< JackrabbitSecurityManager >---
+    /**
+     * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#init(Repository, Session)
+     */
+    @Override
+    public void init(Repository repository, Session systemSession) throws RepositoryException {
+        super.init(repository, systemSession);
+
+        systemUsersInitialized.add(systemSession.getWorkspace().getName());
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#dispose(String)
+     */
+    @Override
+    public void dispose(String workspaceName) {
+        super.dispose(workspaceName);
+        synchronized (ppRegistries) {
+            PrincipalProviderRegistry reg = ppRegistries.remove(workspaceName);
+            if (reg != null) {
+                reg.getDefault().close();
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#close()
+     */
+    @Override
+    public void close() {
+        super.close();
+        synchronized (ppRegistries) {
+            for (PrincipalProviderRegistry registry : ppRegistries.values()) {
+                registry.getDefault().close();
+            }
+            ppRegistries.clear();
+        }
+    }
+
+    /**
+     * As this implementation expectes that users information in present in
+     * every workspace, the UserManager is always created with the given
+     * session.
+     * 
+     * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#getUserManager(javax.jcr.Session)
+     */
+    @Override
+    public UserManager getUserManager(Session session) throws RepositoryException {
+        checkInitialized();                    
+        if (session == getSystemSession()) {
+            return super.getUserManager(session);
+        } else if (session instanceof SessionImpl) {
+            UserManager uMgr = createUserManager((SessionImpl) session);
+            // Since users are not stored in a dedicated security workspace:
+            // make sure the system users are present. this is always the case
+            // for the configured security-workspace (or if missing the default
+            // workspace) but not for other workspaces.
+            // However, the check is only executed if the given session is a
+            // SystemSession (see also #getPrincipalProviderRegistry(Session)
+            // that initializes a SystemSession based UserManager for each workspace).
+            String wspName = session.getWorkspace().getName();
+            if (session instanceof SystemSession && !systemUsersInitialized.contains(wspName)) {
+                createSystemUsers(uMgr, (SystemSession) session, adminId, anonymousId);
+                systemUsersInitialized.add(wspName);
+            }
+            return uMgr;
+        } else {
+            throw new RepositoryException("Internal error: SessionImpl expected.");
+        }
+    }
+
+    /**
+     * Creates an AuthContext for the given {@link javax.jcr.Credentials} and
+     * {@link javax.security.auth.Subject}.<br>
+     * This includes selection of application specific LoginModules and
+     * initialization with credentials and Session to System-Workspace
+     *
+     * @return an {@link org.apache.jackrabbit.core.security.authentication.AuthContext} for the given Credentials, Subject
+     * @throws javax.jcr.RepositoryException in other exceptional repository states
+     */
+    @Override
+    public AuthContext getAuthContext(Credentials creds, Subject subject, String workspaceName)
+            throws RepositoryException {
+        checkInitialized();
+        SystemSession systemSession = ((RepositoryImpl) getRepository()).getSystemSession(workspaceName);
+        return getAuthContextProvider().getAuthContext(creds, subject, systemSession,
+                getPrincipalProviderRegistry(systemSession), adminId, anonymousId);
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Always returns <code>null</code>. The default principal provider is
+     * workspace depending as users are expected to exist in every workspace.
+     * 
+     * @return <code>null</code>
+     * @throws RepositoryException
+     */
+    @Override
+    protected PrincipalProvider createDefaultPrincipalProvider() throws RepositoryException {
+        return null;
+    }
+
+    @Override
+    protected UserManager getSystemUserManager(String workspaceName) throws RepositoryException {
+        if (workspaceName.equals(getSystemSession().getWorkspace().getName())) {
+            return super.getSystemUserManager(workspaceName);
+        } else {
+            return ((RepositoryImpl) getRepository()).getWorkspaceInfo(workspaceName).getSystemSession().getUserManager();
+        }
+    }
+
+    /**
+     * Creates a new instanceof <code>TransientChangeUserManagerImpl</code>.
+     * 
+     * @param session session
+     * @return an instanceof <code>TransientChangeUserManagerImpl</code>
+     * @throws RepositoryException
+     */
+    @Override
+    protected UserManagerImpl createUserManager(SessionImpl session) throws RepositoryException {
+        UserManagerConfig umc = getConfig().getUserManagerConfig();
+        Properties params = (umc == null) ? null : umc.getParameters();
+        
+        // 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 existance of the admin user.
+        if (session instanceof SystemSession) {
+            return new SystemUserManager((SystemSession) session, params);
+        } else {
+            if (umc != null) {
+                Class<?>[] paramTypes = new Class[] { SessionImpl.class, String.class, Properties.class };
+                return (UserPerWorkspaceUserManager) umc.getUserManager(UserPerWorkspaceUserManager.class, paramTypes, (SessionImpl) session, adminId, params);
+            } else {
+                return new UserPerWorkspaceUserManager(session, adminId, params);
+            }
+        }
+    }
+
+    /**
+     * @param session Session for the principal manager must be created.
+     * @return A new instance of PrincipalManagerImpl. Note that this implementation
+     * uses a workspace specific principal provider registry, that retrieves
+     * the configured providers from the registry obtained throug
+     * {@link #getPrincipalProviderRegistry()} but has a workspace specific
+     * default provider.
+     * @throws RepositoryException
+     */
+    @Override
+    protected PrincipalManager createPrincipalManager(SessionImpl session) throws RepositoryException {
+        return new PrincipalManagerImpl(session, getPrincipalProviderRegistry(session).getProviders());
+    }
+
+    /**
+     * Returns a new instance of <code>SimpleWorkspaceAccessManager</code>, since
+     * with the <code>DefaultLoginModule</code> the existance of the user
+     * is checked in order to successfully complete the login. Since with this
+     * SecurityManager users are stored separately in each workspace, a user
+     * may only login to a workspace if the corresponding user node exists.
+     * Consequently a lazy workspace access manager is sufficient.<p/>
+     *
+     * If this SecurityManager is used with a distict <code>LoginModule</code>
+     * implementation, the {@link org.apache.jackrabbit.core.config.SecurityManagerConfig#getWorkspaceAccessConfig() configuration}
+     * for <code>WorkspaceAccessManager</code> should be adjusted as well.
+     *
+     * @return An new instance of {@link SimpleWorkspaceAccessManager}.
+     */
+    @Override
+    protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
+        return new WorkspaceAccessManagerImpl();
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Workaround to get a default (user-based) principal provider depending
+     * on the workspace beeing accessed. This is required for this security
+     * manager as users aren't stored in a single, dedicated workspace.
+     */
+    private final class WorkspaceBasedPrincipalProviderRegistry implements PrincipalProviderRegistry {
+
+        private final PrincipalProvider defaultPrincipalProvider;
+
+        public WorkspaceBasedPrincipalProviderRegistry(PrincipalProvider defaultPrincipalProvider) {
+            this.defaultPrincipalProvider = defaultPrincipalProvider;
+        }
+
+        public PrincipalProvider registerProvider(Properties configuration) throws RepositoryException {
+            throw new UnsupportedOperationException();
+        }
+
+        public PrincipalProvider getDefault() {
+            return defaultPrincipalProvider;
+        }
+
+        public PrincipalProvider getProvider(String className) {
+            PrincipalProvider p = getPrincipalProviderRegistry().getProvider(className);
+            if (p == null && defaultPrincipalProvider.getClass().getName().equals(className)) {
+                p = defaultPrincipalProvider;
+            }
+            return p;
+        }
+
+        public PrincipalProvider[] getProviders() {
+            List<PrincipalProvider> l = new ArrayList();
+            l.addAll(Arrays.asList(getPrincipalProviderRegistry().getProviders()));
+            l.add(defaultPrincipalProvider);
+            return l.toArray(new PrincipalProvider[l.size()]);
+        }
+    }
+
+    private final class WorkspaceAccessManagerImpl extends SimpleWorkspaceAccessManager {
+        @Override
+        public boolean grants(Set<Principal> principals, String workspaceName) throws RepositoryException {
+            if (!(Arrays.asList(((RepositoryImpl) getRepository()).getWorkspaceNames())).contains(workspaceName)) {
+                return false;
+            } else {
+                return super.grants(principals, workspaceName);
+            }
+        }
+    }
+}
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java Thu Oct 22 17:26:37 2009
@@ -835,7 +835,7 @@
         }
 
         Importer importer = new WorkspaceImporter(parentPath, this,
-                rep.getNodeTypeRegistry(), uuidBehavior);
+                rep.getNodeTypeRegistry(), uuidBehavior, wspConfig.getImportConfig());
         return new ImportHandler(importer, session);
     }
 

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ImportConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ImportConfig.java?rev=828791&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ImportConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ImportConfig.java Thu Oct 22 17:26:37 2009
@@ -0,0 +1,84 @@
+/*
+ * 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.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.xml.ProtectedNodeImporter;
+import org.apache.jackrabbit.core.xml.ProtectedPropertyImporter;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * <code>XmlImportConfig</code>...
+ */
+public class ImportConfig {
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(ImportConfig.class);
+
+    private final List<BeanConfig> protectedNodeImporters;
+    private final List<BeanConfig> protectedPropertyImporters;
+
+    public ImportConfig() {
+        protectedNodeImporters = Collections.emptyList();
+        protectedPropertyImporters = Collections.emptyList();
+    }
+
+    public ImportConfig(List<BeanConfig> protectedNodeImporters, List<BeanConfig> protectedPropertyImporters) {
+        this.protectedNodeImporters = protectedNodeImporters;
+        this.protectedPropertyImporters = protectedPropertyImporters;
+    }
+
+    public List<ProtectedNodeImporter> getProtectedNodeImporters() {
+        List<ProtectedNodeImporter> pnis = new ArrayList();
+        for (BeanConfig bc : protectedNodeImporters) {
+            try {
+                Object o = bc.newInstance();
+                if (o instanceof ProtectedNodeImporter) {
+                    pnis.add((ProtectedNodeImporter) o);
+                } else {
+                    log.warn("Invalid configuration entry: " + bc.getClassName() +" does not implement ProtectedNodeImporter.");                    
+                }
+            } catch (ConfigurationException e) {
+                log.warn(e.getMessage());
+            }
+        }
+        return pnis;
+    }
+
+    public List<ProtectedPropertyImporter> getProtectedPropertyImporters() {
+        List<ProtectedPropertyImporter> ppis = new ArrayList();
+        for (BeanConfig bc : protectedPropertyImporters) {
+            try {
+                Object o = bc.newInstance();
+                if (o instanceof ProtectedPropertyImporter) {
+                    ppis.add((ProtectedPropertyImporter) o);
+                } else {
+                    log.warn("Invalid configuration entry: " + bc.getClassName() +" does not implement ProtectedPropertyImporter.");
+                }
+            } catch (ConfigurationException e) {
+                log.warn(e.getMessage());
+            }
+        }
+        return ppis;
+    }
+}
\ No newline at end of file

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=828791&r1=828790&r2=828791&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 Thu Oct 22 17:26:37 2009
@@ -46,6 +46,8 @@
 import java.io.IOException;
 import java.util.Properties;
 import java.util.UUID;
+import java.util.List;
+import java.util.ArrayList;
 
 import javax.jcr.RepositoryException;
 
@@ -181,6 +183,19 @@
     private static final String AC_PROVIDER_ELEMENT = "AccessControlProvider";
 
     /**
+     * Element specifying the class of principals used to retrieve the userID
+     * in the 'class' attribute.
+     */
+    private static final String USERID_CLASS = "UserIdClass";
+
+    /**
+     * Name of the optional XmlImport config entry inside the workspace configuration.
+     */
+    private static final String IMPORT_ELEMENT = "Import";
+    private static final String IMPORT_PNI_ELEMENT = "ProtectedNodeImporter";
+    private static final String IMPORT_PPI_ELEMENT = "ProtectedPropertyImporter";
+
+    /**
      * Name of the cluster node id file.
      */
     private static final String CLUSTER_NODE_ID_FILE = "cluster_node.id";
@@ -348,12 +363,19 @@
                 wac = parseBeanConfig(smElement, WORKSPACE_ACCESS_ELEMENT);
             }
 
-            BeanConfig umc = null;
+            UserManagerConfig umc = null;
             element = getElement(smElement, USER_MANAGER_ELEMENT, false);
             if (element != null) {
-                umc = parseBeanConfig(smElement, USER_MANAGER_ELEMENT);
+                umc = new UserManagerConfig(parseBeanConfig(smElement, USER_MANAGER_ELEMENT));
+            }
+
+            BeanConfig uidcc = null;
+            element = getElement(smElement, USERID_CLASS, false);
+            if (element != null) {
+                uidcc = parseBeanConfig(element);
             }
-            return new SecurityManagerConfig(bc, wspAttr, wac, umc);
+
+            return new SecurityManagerConfig(bc, wspAttr, wac, umc, uidcc);
         } else {
             return null;
         }
@@ -443,7 +465,6 @@
      * @return workspace configuration
      * @throws ConfigurationException if the configuration is broken
      * @see #parseBeanConfig(Element, String)
-     * @see #parseSearchConfig(Element)
      * @see #parseWorkspaceSecurityConfig(Element)
      */
     public WorkspaceConfig parseWorkspaceConfig(InputSource xml)
@@ -472,7 +493,7 @@
 
         // Clustered attribute
         boolean clustered = Boolean.valueOf(
-                getAttribute(root, CLUSTERED_ATTRIBUTE, "true")).booleanValue();
+                getAttribute(root, CLUSTERED_ATTRIBUTE, "true"));
 
         // Create a temporary parser that contains the ${wsp.name} variable
         Properties tmpVariables = (Properties) getVariables().clone();
@@ -496,9 +517,12 @@
         // workspace specific security configuration
         WorkspaceSecurityConfig workspaceSecurityConfig = tmpParser.parseWorkspaceSecurityConfig(root);
 
+        // optinal config for import handling
+        ImportConfig importConfig = tmpParser.parseImportConfig(root);
+
         return new WorkspaceConfig(
                 home, name, clustered, fsf, pmc, qhf,
-                ismLockingFactory, workspaceSecurityConfig);
+                ismLockingFactory, workspaceSecurityConfig, importConfig);
     }
 
     /**
@@ -597,6 +621,49 @@
     }
 
     /**
+     * Read the optional XmlImport Element of Workspace's configuration. It uses
+     * the following format:
+     * <pre>
+     *   &lt;XmlImport&gt;
+     *     &lt;ProtectedNodeImporter class="..." (optional)&gt;
+     *     &lt;ProtectedNodeImporter class="..." (optional)&gt;
+     *     ...
+     *     &lt;ProtectedPropertyImporter class="..." (optional)&gt;
+     *   &lt;/XmlImport&gt;
+     * </pre>
+     *
+     * @param parent Workspace-Root-Element
+     * @return a new <code>XmlImportConfig</code>
+     * @throws ConfigurationException
+     */
+    public ImportConfig parseImportConfig(Element parent) throws ConfigurationException {
+        List<BeanConfig> protectedNodeImporters = new ArrayList();
+        List<BeanConfig> protectedPropertyImporters = new ArrayList();
+
+        Element element = getElement(parent, IMPORT_ELEMENT, false);
+        if (element != null) {
+            NodeList children = element.getChildNodes();
+            for (int i = 0; i < children.getLength(); i++) {
+                Node child = children.item(i);
+                if (child.getNodeType() == Node.ELEMENT_NODE) {
+                    if (IMPORT_PNI_ELEMENT.equals(child.getNodeName())) {
+                        String className = getAttribute((Element) child, CLASS_ATTRIBUTE);
+                        BeanConfig bc = new BeanConfig(className, parseParameters((Element) child));
+                        bc.setValidate(false);
+                        protectedNodeImporters.add(bc);
+                    } else if (IMPORT_PPI_ELEMENT.equals(child.getNodeName())) {
+                        String className = getAttribute((Element) child, CLASS_ATTRIBUTE);
+                        BeanConfig bc = new BeanConfig(className, parseParameters((Element) child));
+                        bc.setValidate(false);
+                        protectedPropertyImporters.add(bc);
+                    } // else: some other entry -> ignore.
+                }
+            }
+        }
+        return new ImportConfig(protectedNodeImporters, protectedPropertyImporters);
+    }
+
+    /**
      * Returns an ISM locking factory that creates {@link ISMLocking} instances
      * based on the given configuration. ISM locking configuration uses the
      * following format:

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java Thu Oct 22 17:26:37 2009
@@ -16,6 +16,9 @@
  */
 package org.apache.jackrabbit.core.config;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Security manager configuration. This bean configuration class
  * is used to create configured security manager objects.
@@ -27,9 +30,19 @@
  */
 public class SecurityManagerConfig extends BeanConfig {
 
+    /**
+     * the default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(SecurityManagerConfig.class);
+
     private final String workspaceName;
     private final BeanConfig workspaceAccessConfig;
-    private final BeanConfig userManagerConfig;
+    private final UserManagerConfig userManagerConfig;
+
+    /**
+     * Optional class used to retrieve userID from the subject.
+     */
+    private final Class uidClass;
 
     /**
      * Creates an security manager configuration object from the
@@ -41,7 +54,7 @@
      */
     public SecurityManagerConfig(BeanConfig config, String workspaceName,
                                  BeanConfig workspaceAccessConfig) {
-        this(config, workspaceName, workspaceAccessConfig, null);
+        this(config, workspaceName, workspaceAccessConfig, null, null);
     }
 
     /**
@@ -55,11 +68,21 @@
      */
     public SecurityManagerConfig(BeanConfig config, String workspaceName,
                                  BeanConfig workspaceAccessConfig,
-                                 BeanConfig userManagerConfig) {
+                                 UserManagerConfig userManagerConfig,
+                                 BeanConfig uidClassConfig) {
         super(config);
         this.workspaceName = workspaceName;
         this.workspaceAccessConfig = workspaceAccessConfig;
         this.userManagerConfig = userManagerConfig;
+        Class cl = null;
+        if (uidClassConfig != null) {
+            try {
+                cl = Class.forName(uidClassConfig.getClassName(), true, uidClassConfig.getClassLoader());
+            } catch (ClassNotFoundException e) {
+                log.error("Configured bean implementation class " + uidClassConfig.getClassName() + " was not found -> Ignoring UserIdClass element.", e);
+            }
+        }
+        this.uidClass = cl;
     }
 
     /**
@@ -86,7 +109,16 @@
      * May be <code>null</code> if the configuration entry is missing (i.e.
      * the system default should be used).
      */
-    public BeanConfig getUserManagerConfig() {
+    public UserManagerConfig getUserManagerConfig() {
         return userManagerConfig;
     }
+    
+    /**
+     * @return Class which is used to retrieve the UserID from the Subject.
+     * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#getUserID(javax.security.auth.Subject, String) 
+     * @see javax.security.auth.Subject#getPrincipals(Class)
+     */
+    public Class getUserIdClass() {
+        return uidClass;
+    }
 }