Improve Jackrabbit security
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 20 Mar 2011 18:09:50 +0000 (18:09 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 20 Mar 2011 18:09:50 +0000 (18:09 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4325 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

39 files changed:
demo/argeo-node-ui.product
demo/log4j.properties
eclipse/runtime/org.argeo.eclipse.ui.jcr/src/main/java/org/argeo/eclipse/ui/jcr/commands/InitUserHome.java [deleted file]
gis/runtime/org.argeo.gis.geotools/src/main/java/org/argeo/geotools/jcr/GeoJcrIndex.java
security/modules/org.argeo.security.dao.jackrabbit/META-INF/MANIFEST.MF
security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml
security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml
security/modules/org.argeo.security.dao.ldap/META-INF/MANIFEST.MF
security/modules/org.argeo.security.dao.ldap/META-INF/spring/jcr.xml [deleted file]
security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-jcr.xml [new file with mode: 0644]
security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-osgi.xml
security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml
security/modules/org.argeo.security.dao.ldap/ldap.properties
security/modules/org.argeo.security.services/META-INF/spring/osgi.xml
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/CurrentUserDao.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/SystemExecutionService.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/CurrentUserDaoJcr.java [new file with mode: 0644]
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationToken.java
security/runtime/org.argeo.security.jackrabbit/pom.xml
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoAccessManager.java
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/applicationContext.xml
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/security.xml
server/modules/org.argeo.node.repo.jackrabbit/META-INF/MANIFEST.MF
server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo-osgi.xml
server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo.xml
server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml
server/plugins/org.argeo.jcr.ui.explorer/plugin.xml
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/CachingSessionProvider.java [deleted file]
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/JcrRemotingHandlerMapping.java
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java
server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/MultipleRepositoryHandlerMapping.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoTypes.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java

index 820f999c779a30b9ca7feb67688f50fa097c6106..8082cfce14a0c80ce483305f8bded7e53ca1ef87 100644 (file)
@@ -8,7 +8,7 @@
 
    <launcherArgs>
       <programArgs>-console -clean</programArgs>
-      <vmArgs>-Dlog4j.configuration=&quot;file:${system_property:user.home}/dev/src/commons/demo/log4j.properties&quot;</vmArgs>
+      <vmArgs>-Dlog4j.configuration=&quot;file:${system_property:user.home}/dev/src/commons/demo/log4j.properties&quot; -Dorg.argeo.security.ui.initialPerspective=org.argeo.jcr.ui.explorer.perspective</vmArgs>
       <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts</vmArgsMac>
    </launcherArgs>
 
       <plugin id="org.argeo.eclipse.ui"/>
       <plugin id="org.argeo.eclipse.ui.jcr"/>
       <plugin id="org.argeo.eclipse.ui.rcp"/>
-      <plugin id="org.argeo.infra.core" fragment=""/>
+      <plugin id="org.argeo.infra.core"/>
       <plugin id="org.argeo.infra.security.services" fragment="true"/>
       <plugin id="org.argeo.jcr.ui.explorer"/>
       <plugin id="org.argeo.node.repo.jackrabbit"/>
       <plugin id="org.argeo.security.core"/>
+      <plugin id="org.argeo.security.dao.jackrabbit"/>
       <plugin id="org.argeo.security.equinox"/>
       <plugin id="org.argeo.security.jackrabbit" fragment="true"/>
       <plugin id="org.argeo.security.ldap"/>
-      <plugin id="org.argeo.security.manager.ldap"/>
+      <plugin id="org.argeo.security.manager.ldap" fragment=""/>
       <plugin id="org.argeo.security.services"/>
       <plugin id="org.argeo.security.ui"/>
       <plugin id="org.argeo.security.ui.rcp"/>
 
    <configurations>
       <plugin id="org.argeo.node.repo.jackrabbit" autoStart="true" startLevel="0" />
-      <plugin id="org.argeo.security.manager.ldap" autoStart="true" startLevel="0" />
+      <plugin id="org.argeo.security.dao.jackrabbit" autoStart="true" startLevel="0" />
       <plugin id="org.argeo.security.services" autoStart="true" startLevel="0" />
-      <plugin id="org.argeo.server.ads.server" autoStart="false" startLevel="0" />
       <plugin id="org.springframework.osgi.extender" autoStart="true" startLevel="0" />
    </configurations>
 
index 8a89a4aa3b7c8c24b8499ae72b7687e7bbc13762..1e5895edf0c2ba1eaf06d09dd836a03853ddacea 100644 (file)
@@ -2,7 +2,9 @@ log4j.rootLogger=WARN, console
 
 ## Levels
 log4j.logger.org.argeo=DEBUG
-log4j.logger.org.springframework.security=DEBUG
+log4j.logger.org.argeo.jackrabbit.remote.ExtendedDispatcherServlet=WARN
+
+log4j.logger.org.springframework.security=WARN
 
 log4j.logger.org.apache.catalina=INFO
 log4j.logger.org.apache.coyote=INFO
diff --git a/eclipse/runtime/org.argeo.eclipse.ui.jcr/src/main/java/org/argeo/eclipse/ui/jcr/commands/InitUserHome.java b/eclipse/runtime/org.argeo.eclipse.ui.jcr/src/main/java/org/argeo/eclipse/ui/jcr/commands/InitUserHome.java
deleted file mode 100644 (file)
index 6bc5dff..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.argeo.eclipse.ui.jcr.commands;
-
-import javax.jcr.Node;
-import javax.jcr.Session;
-
-import org.argeo.eclipse.ui.dialogs.Error;
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.ArgeoTypes;
-import org.eclipse.core.commands.AbstractHandler;
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-
-/** Init the user home directory within the node */
-public class InitUserHome extends AbstractHandler {
-       private Session session;
-
-       private String defaultHome = "home";
-
-       public Object execute(ExecutionEvent event) throws ExecutionException {
-               String userID = "<not yet logged in>";
-               try {
-                       userID = session.getUserID();
-                       Node rootNode = session.getRootNode();
-                       Node homeNode;
-                       if (!rootNode.hasNode(defaultHome)) {
-                               homeNode = rootNode.addNode(defaultHome, ArgeoTypes.ARGEO_HOME);
-                       } else {
-                               homeNode = rootNode.getNode(defaultHome);
-                       }
-
-                       if (!homeNode.hasNode(userID)) {
-                               Node userHome = homeNode.addNode(userID);
-                               userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
-                               userHome.setProperty(ArgeoNames.ARGEO_USER_ID, userID);
-                       }
-                       session.save();
-               } catch (Exception e) {
-                       Error.show("Cannot initialize home for user '" + userID + "'", e);
-               }
-               return null;
-       }
-
-       public void setSession(Session session) {
-               this.session = session;
-       }
-
-}
index a1175abc72a384daec388dc3618623a7eb6c84a7..75c1b81ad745b30e2e9ddc85ee3fc38393e50653 100644 (file)
@@ -7,6 +7,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 import javax.jcr.Node;
 import javax.jcr.Property;
@@ -53,7 +54,7 @@ public class GeoJcrIndex implements EventListener, GisNames, GisTypes {
 
        private DataStore dataStore;
        private Session session;
-       private SystemExecutionService systemExecutionService;
+       private Executor systemExecutionService;
 
        /** The key is the workspace */
        private Map<String, FeatureStore<SimpleFeatureType, SimpleFeature>> geoJcrIndexes = Collections
@@ -63,7 +64,7 @@ public class GeoJcrIndex implements EventListener, GisNames, GisTypes {
        private FilterFactory2 ff = new FilterFactoryImpl();
 
        public void init() {
-               systemExecutionService.executeAsSystem(new Runnable() {
+               systemExecutionService.execute(new Runnable() {
                        public void run() {
                                initGeoJcrIndex();
                        }
@@ -102,7 +103,7 @@ public class GeoJcrIndex implements EventListener, GisNames, GisTypes {
                final Set<FeatureId> toRemove = new HashSet<FeatureId>();
 
                // execute with system authentication so that JCR can be read
-               systemExecutionService.executeAsSystem(new Runnable() {
+               systemExecutionService.execute(new Runnable() {
                        public void run() {
                                while (events.hasNext()) {
                                        Event event = events.nextEvent();
@@ -292,7 +293,7 @@ public class GeoJcrIndex implements EventListener, GisNames, GisTypes {
        }
 
        public void setSystemExecutionService(
-                       SystemExecutionService systemExecutionService) {
+                       Executor systemExecutionService) {
                this.systemExecutionService = systemExecutionService;
        }
 
index 437eb0ec021d36a575ab3f879a4495c0ac8139ed..51a6ca2316c2ca66c06c1bf79ffddb0e51bf96fa 100644 (file)
@@ -1,4 +1,8 @@
-Bundle-SymbolicName: org.argeo.security.dao.ldap
+Bundle-SymbolicName: org.argeo.security.dao.jackrabbit
 Bundle-Version: 0.2.3.SNAPSHOT
 Import-Package: javax.jcr;version="[2.0.0,3.0.0)",
+ org.argeo.security,
+ org.argeo.security.jackrabbit.providers,
+ org.argeo.security.jcr,
+ org.springframework.security.providers;specification-version="2.0.6.RELEASE"
 Bundle-Name: Security DAO Jackrabbit
index 6e511014b7233c5756a4554c669936b775f97f33..0c2706d03016170316510f3c18d1735083c4f27f 100644 (file)
        http://www.springframework.org/schema/util/spring-util-2.5.xsd">\r
 \r
        <!-- REFERENCE -->\r
-       <reference id="repositoryFactoryRef" interface="javax.jcr.RepositoryFactory"\r
+       <reference id="repositoryFactory" interface="javax.jcr.RepositoryFactory"\r
                cardinality="0..1">\r
                <listener ref="jcrAuthenticationProvider" bind-method="register"\r
                        unbind-method="unregister" />\r
        </reference>\r
-       <reference id="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
 \r
        <!-- SERVICES -->\r
        <service ref="jcrAuthenticationProvider"\r
                interface="org.springframework.security.providers.AuthenticationProvider" />\r
+       <service ref="jcrCurrentUserDao" interface="org.argeo.security.CurrentUserDao" />\r
 \r
 </beans:beans>
\ No newline at end of file
index ca84bb90c84f03b3d8dc3c384a61f2241fcfd605..43f8520a7051923eec4e1c42ec0d415c4001eaa9 100644 (file)
@@ -3,11 +3,8 @@
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
-
        <bean id="jcrAuthenticationProvider"
                class="org.argeo.security.jackrabbit.providers.JackrabbitAuthenticationProvider" />
 
-       <bean id="repositoryFactory" class="org.argeo.jackrabbit.JackrabbitRepositoryFactory">
-       </bean>
-
+       <bean id="jcrCurrentUserDao" class="org.argeo.security.jcr.CurrentUserDaoJcr" />
 </beans>
\ No newline at end of file
index d377808d80685b8fd24c4184df59520bb86626bd..24e756417dcfbb0ab04c10b9b160bef29c644ff3 100644 (file)
@@ -19,4 +19,4 @@ Import-Package: com.sun.jndi.ldap;resolution:=optional,
  org.springframework.security.providers.ldap.authenticator,
  org.springframework.security.userdetails,
  org.springframework.security.userdetails.ldap
-Bundle-Name: Security Manager LDAP
+Bundle-Name: Security DAO LDAP
diff --git a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/jcr.xml b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/jcr.xml
deleted file mode 100644 (file)
index 2a0a08c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:security="http://www.springframework.org/schema/security"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-               http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
-               http://www.springframework.org/schema/security
-               http://www.springframework.org/schema/security/spring-security-2.0.4.xsd
-               http://www.springframework.org/schema/util
-               http://www.springframework.org/schema/util/spring-util-2.5.xsd">
-
-
-       <bean id="jcrUserDetailsContextMapper" class="org.argeo.security.ldap.jcr.JcrUserDetailsContextMapper">
-               <property name="systemExecutionService" ref="systemExecutionService" />
-               <property name="propertyToAttributes">
-                       <map>
-                               <entry value="cn">
-                                       <key>
-                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_DISPLAY_NAME" />
-                                       </key>
-                               </entry>
-                               <entry value="givenName">
-                                       <key>
-                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_FIRST_NAME" />
-                                       </key>
-                               </entry>
-                               <entry value="sn">
-                                       <key>
-                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_LAST_NAME" />
-                                       </key>
-                               </entry>
-                               <entry value="mail">
-                                       <key>
-                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_PRIMARY_EMAIL" />
-                                       </key>
-                               </entry>
-                               <entry value="o">
-                                       <key>
-                                               <util:constant
-                                                       static-field="org.argeo.jcr.ArgeoNames.ARGEO_PRIMARY_ORGANIZATION" />
-                                       </key>
-                               </entry>
-                       </map>
-               </property>
-
-       </bean>
-</beans>
diff --git a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-jcr.xml b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-jcr.xml
new file mode 100644 (file)
index 0000000..794ac01
--- /dev/null
@@ -0,0 +1,53 @@
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:security="http://www.springframework.org/schema/security"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+               http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+               http://www.springframework.org/schema/security
+               http://www.springframework.org/schema/security/spring-security-2.0.4.xsd
+               http://www.springframework.org/schema/util
+               http://www.springframework.org/schema/util/spring-util-2.5.xsd">
+
+       <bean id="jcrUserDetailsContextMapper" class="org.argeo.security.ldap.jcr.JcrUserDetailsContextMapper">
+               <property name="homeBasePath" value="/home" />
+               <property name="usernameAttribute" value="${argeo.ldap.usernameAttribute}" />
+               <property name="passwordAttribute" value="${argeo.ldap.passwordAttribute}" />
+               <property name="userClasses">
+                       <list>
+                               <value>${argeo.ldap.userClass}</value>
+                       </list>
+               </property>
+               <property name="systemExecutor" ref="systemExecutionService" />
+               <property name="propertyToAttributes">
+                       <map>
+                               <entry value="cn">
+                                       <key>
+                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_DISPLAY_NAME" />
+                                       </key>
+                               </entry>
+                               <entry value="givenName">
+                                       <key>
+                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_FIRST_NAME" />
+                                       </key>
+                               </entry>
+                               <entry value="sn">
+                                       <key>
+                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_LAST_NAME" />
+                                       </key>
+                               </entry>
+                               <entry value="mail">
+                                       <key>
+                                               <util:constant static-field="org.argeo.jcr.ArgeoNames.ARGEO_PRIMARY_EMAIL" />
+                                       </key>
+                               </entry>
+                               <entry value="o">
+                                       <key>
+                                               <util:constant
+                                                       static-field="org.argeo.jcr.ArgeoNames.ARGEO_PRIMARY_ORGANIZATION" />
+                                       </key>
+                               </entry>
+                       </map>
+               </property>
+
+       </bean>
+</beans>
index b09aabfe47624cdf952caf48cbf6d3923e7e6eee..67ad8981705ae694a12392ef173ae224b5aa2438 100644 (file)
        <reference id="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
 \r
        <!-- SERVICES -->\r
-       <service ref="authenticationProvider"\r
+       <service ref="ldapAuthenticationProvider"\r
                interface="org.springframework.security.providers.AuthenticationProvider"\r
                context-class-loader="service-provider" />\r
+               \r
        <service ref="securityDao" interface="org.argeo.security.CurrentUserDao"\r
                context-class-loader="service-provider" />\r
        <service ref="securityDao" interface="org.argeo.security.UserAdminDao"\r
index 7a2ae9d7f4d7908515bcd37f121c12786b3761f4..72de115ca04cda85b2b41381d5277b807721748c 100644 (file)
@@ -25,7 +25,7 @@
        </bean>
 
        <!-- AUTHENTICATION -->
-       <bean id="authenticationProvider"
+       <bean id="ldapAuthenticationProvider"
                class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
                <constructor-arg ref="passwordComparisonAuthenticator" />
                <constructor-arg ref="authoritiesPopulator" />
                                <value><![CDATA[${argeo.ldap.usernameAttribute}={0},${argeo.ldap.userBase}]]></value>
                        </list>
                </property>
+               <property name="passwordAttributeName" value="${argeo.ldap.passwordAttribute}" />
                <property name="passwordEncoder" ref="passwordEncoder" />
        </bean>
 
        <!-- USER DETAILS -->
        <bean id="securityDao" class="org.argeo.security.ldap.ArgeoSecurityDaoLdap">
                <constructor-arg ref="contextSource" />
-
                <property name="userBase" value="${argeo.ldap.userBase}" />
                <property name="usernameAttribute" value="${argeo.ldap.usernameAttribute}" />
                <property name="groupClasses">
@@ -60,7 +60,6 @@
                <property name="groupMemberAttribute" value="${argeo.ldap.groupMemberAttribute}" />
                <property name="defaultRole" value="${argeo.security.defaultRole}" />
                <property name="rolePrefix" value="${argeo.security.rolePrefix}" />
-
                <property name="passwordEncoder" ref="passwordEncoder" />
                <property name="usernameMapper" ref="usernameMapper" />
                <property name="userDetailsManager" ref="userDetailsManager" />
index 66eb37b43e8610a77a05bfd4acd7f0cfe22e5c3e..bd6c9159263b4041013b65844ce832e8cd50804d 100644 (file)
@@ -4,12 +4,17 @@ argeo.security.rolePrefix=ROLE_
 argeo.ldap.rootdn=dc=demo,dc=argeo,dc=org
 argeo.ldap.protocol=ldap
 argeo.ldap.host=localhost
+# default are for Apache Directory Server
 argeo.ldap.port=10389
 argeo.ldap.manager.userdn=uid=admin,ou=system
 argeo.ldap.manager.password=secret
 
+# USER
+argeo.ldap.userClass=inetOrgPerson
 argeo.ldap.userBase=ou=People
 argeo.ldap.usernameAttribute=uid
+argeo.ldap.passwordAttribute=userPassword
+# ROLES
 argeo.ldap.groupClass=groupOfNames
 argeo.ldap.groupBase=ou=Roles
 argeo.ldap.groupRoleAttribute=cn
index f83086a2b51653401a0ca1a55bfc77d2da1be3bc..6c21dbd2601a5551e5138599283008ec04874805 100644 (file)
@@ -7,6 +7,9 @@
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
 \r
        <!-- REFERENCES -->\r
+       <!-- Cardinality is 0, in order to let a bundle providing the DAO while \r
+               depending on the system execution service. The dependency will then have \r
+               been satisfied when the first user tries to log-in. -->\r
        <reference id="currentUserDao" interface="org.argeo.security.CurrentUserDao"\r
                cardinality="0..1" />\r
 \r
index 6e5b4ec3c8079f0646bc846aa83bf0715a7d0568..736b0bafd7fad3df5cbc3c52859d272b515b574a 100644 (file)
@@ -22,6 +22,7 @@ package org.argeo.security;
 public interface CurrentUserDao {
        public void updateCurrentUserPassword(String oldPassword, String newPassword);
 
+       @Deprecated
        public String getDefaultRole();
 
 }
index f5ef357c04b1201d1a8dbc64d9005e213ba9bc60..eba5d49d9a1794de14bc0d1b6c4badf5fba689d2 100644 (file)
@@ -1,18 +1,22 @@
 package org.argeo.security;
 
+import java.util.concurrent.Executor;
+
 import org.springframework.core.task.TaskExecutor;
 
 /**
  * Allows to execute code authenticated as a system user (that is not a real
- * person)
+ * person). The {@link Executor} interface interface is not used directly in
+ * order to allow future extension of this interface and to simplify its
+ * publication (e.g. as an OSGi service) and interception. Support for Spring's
+ * {@link TaskExecutor} will be dropped when upgrading to Spring 3, since it is
+ * only to ensure compatibility with versions of Java before 1.5.
  */
-public interface SystemExecutionService {
+public interface SystemExecutionService extends Executor, TaskExecutor {
        /**
         * Executes this Runnable within a system authenticated context.
         * Implementations should make sure that this method is properly secured via
         * Java permissions since it could access to everything without credentials.
         */
-       public void executeAsSystem(Runnable runnable);
-       
-       public TaskExecutor createSystemAuthenticatedTaskExecutor();
+       public void execute(Runnable runnable);
 }
index 01d760f12befc1ce88fa38eb37c4d308505c6a49..08ef6428ad925f9cc19db8ffece144002df41218 100644 (file)
@@ -8,11 +8,12 @@ import org.springframework.security.AuthenticationManager;
 import org.springframework.security.context.SecurityContext;
 import org.springframework.security.context.SecurityContextHolder;
 
-public class KeyBasedSystemExecutionService implements SystemExecutionService {
+public class KeyBasedSystemExecutionService implements SystemExecutionService,
+               TaskExecutor {
        private AuthenticationManager authenticationManager;
        private String systemAuthenticationKey;
 
-       public void executeAsSystem(Runnable runnable) {
+       public void execute(Runnable runnable) {
                wrapWithSystemAuthentication(runnable).run();
        }
 
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/CurrentUserDaoJcr.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/CurrentUserDaoJcr.java
new file mode 100644 (file)
index 0000000..0c8cc33
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.security.jcr;
+
+import org.argeo.security.CurrentUserDao;
+
+public class CurrentUserDaoJcr implements CurrentUserDao {
+       private String defaultRole= "ROLE_USER";
+
+       public void updateCurrentUserPassword(String oldPassword, String newPassword) {
+               throw new UnsupportedOperationException(
+                               "Updating passwords is not supported");
+       }
+
+       public String getDefaultRole() {
+               return defaultRole;
+       }
+
+       public void setDefaultRole(String defaultRole) {
+               this.defaultRole = defaultRole;
+       }
+
+}
index bfa51f5b12d11049d1aa7d33e6174e076fb7b6a8..b7680ad1b338eea1600e9e3e98ee4ff0a91caae0 100644 (file)
@@ -12,34 +12,20 @@ import javax.jcr.SimpleCredentials;
 
 import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoJcrConstants;
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.ArgeoTypes;
+import org.argeo.jcr.JcrUtils;
 import org.argeo.security.SiteAuthenticationToken;
 import org.springframework.security.Authentication;
 import org.springframework.security.AuthenticationException;
 import org.springframework.security.GrantedAuthority;
 import org.springframework.security.GrantedAuthorityImpl;
 import org.springframework.security.providers.AuthenticationProvider;
+import org.springframework.security.userdetails.UserDetails;
 
 /** Connects to a JCR repository and delegate authentication to it. */
 public class JcrAuthenticationProvider implements AuthenticationProvider {
-       private RepositoryFactory repositoryFactory;
-       private final String defaultHome;
-       private final String userRole;
-
-       public JcrAuthenticationProvider() {
-               this("ROLE_USER", "home");
-       }
+       public final static String ROLE_REMOTE_JCR_AUTHENTICATED = "ROLE_REMOTE_JCR_AUTHENTICATED";
 
-       public JcrAuthenticationProvider(String userRole) {
-               this(userRole, "home");
-       }
-
-       public JcrAuthenticationProvider(String defaultHome, String userRole) {
-               super();
-               this.defaultHome = defaultHome;
-               this.userRole = userRole;
-       }
+       private RepositoryFactory repositoryFactory;
 
        public Authentication authenticate(Authentication authentication)
                        throws AuthenticationException {
@@ -67,53 +53,50 @@ public class JcrAuthenticationProvider implements AuthenticationProvider {
                                session = repository.login(sp);
                        else
                                session = repository.login(sp, workspace);
-                       Node userHome = getUserHome(session);
+                       Node userHome = JcrUtils.getUserHome(session);
+                       if (userHome == null)
+                               throw new ArgeoException("No home found for user "
+                                               + session.getUserID());
                        GrantedAuthority[] authorities = {};
-                       return new JcrAuthenticationToken(siteAuth.getPrincipal(),
-                                       siteAuth.getCredentials(), authorities, url, userHome);
+                       JcrAuthenticationToken authen = new JcrAuthenticationToken(
+                                       siteAuth.getPrincipal(), siteAuth.getCredentials(),
+                                       authorities, url, userHome);
+                       authen.setDetails(getUserDetails(userHome, authen));
+                       return authen;
                } catch (RepositoryException e) {
                        throw new ArgeoException(
                                        "Unexpected exception when authenticating to " + url, e);
                }
        }
 
+       /**
+        * By default, assigns only the role {@value #ROLE_REMOTE_JCR_AUTHENTICATED}
+        * . Should typically be overridden in order to assign more relevant roles.
+        */
        protected GrantedAuthority[] getGrantedAuthorities(Session session) {
-               return new GrantedAuthority[] { new GrantedAuthorityImpl(userRole) };
-       }
-
-       @SuppressWarnings("rawtypes")
-       public boolean supports(Class authentication) {
-               return SiteAuthenticationToken.class.isAssignableFrom(authentication);
+               return new GrantedAuthority[] { new GrantedAuthorityImpl(
+                               ROLE_REMOTE_JCR_AUTHENTICATED) };
        }
 
-       protected Node getUserHome(Session session) {
-               String userID = "<not yet logged in>";
+       /** Builds user details based on the authentication and the user home. */
+       protected UserDetails getUserDetails(Node userHome,
+                       JcrAuthenticationToken authen) {
                try {
-                       userID = session.getUserID();
-                       Node rootNode = session.getRootNode();
-                       Node homeNode;
-                       if (!rootNode.hasNode(defaultHome)) {
-                               homeNode = rootNode.addNode(defaultHome, ArgeoTypes.ARGEO_HOME);
-                       } else {
-                               homeNode = rootNode.getNode(defaultHome);
-                       }
-
-                       Node userHome;
-                       if (!homeNode.hasNode(userID)) {
-                               userHome = homeNode.addNode(userID);
-                               userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
-                               userHome.setProperty(ArgeoNames.ARGEO_USER_ID, userID);
-                       } else {
-                               userHome = homeNode.getNode(userID);
-                       }
-                       session.save();
-                       return userHome;
+                       // TODO: loads enabled, locked, etc. from the home node.
+                       return new JcrUserDetails(userHome.getPath(), authen.getPrincipal()
+                                       .toString(), authen.getCredentials().toString(), true,
+                                       true, true, true, authen.getAuthorities());
                } catch (Exception e) {
-                       throw new ArgeoException("Cannot initialize home for user '"
-                                       + userID + "'", e);
+                       throw new ArgeoException("Cannot get user details for " + userHome,
+                                       e);
                }
        }
 
+       @SuppressWarnings("rawtypes")
+       public boolean supports(Class authentication) {
+               return SiteAuthenticationToken.class.isAssignableFrom(authentication);
+       }
+
        public void register(RepositoryFactory repositoryFactory,
                        Map<String, String> parameters) {
                this.repositoryFactory = repositoryFactory;
@@ -123,13 +106,4 @@ public class JcrAuthenticationProvider implements AuthenticationProvider {
                        Map<String, String> parameters) {
                this.repositoryFactory = null;
        }
-
-       public String getDefaultHome() {
-               return defaultHome;
-       }
-
-       public String getUserRole() {
-               return userRole;
-       }
-
 }
index 865508317e9a12d68b9476a30783a64904bb8db5..27b7ee85b174a222300c79c36d9f260dffe9369d 100644 (file)
@@ -2,33 +2,63 @@ package org.argeo.security.jcr;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 
 import org.argeo.ArgeoException;
 import org.argeo.security.SiteAuthenticationToken;
 import org.springframework.security.GrantedAuthority;
 
+/** An authenticated authentication based on a JCR session. */
 public class JcrAuthenticationToken extends SiteAuthenticationToken {
        private static final long serialVersionUID = -2736830165315486169L;
-       private final transient Node userHome;
+
+       private final transient Session session;
+       private final String userHomePath;
 
        public JcrAuthenticationToken(Object principal, Object credentials,
                        GrantedAuthority[] authorities, String url, Node userHome) {
                super(principal, credentials, authorities, url,
                                extractWorkspace(userHome));
-               this.userHome = userHome;
+               try {
+                       this.session = userHome.getSession();
+                       this.userHomePath = userHome.getPath();
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot extract path from " + userHome, e);
+               }
        }
 
        private static String extractWorkspace(Node userHome) {
                try {
                        return userHome.getSession().getWorkspace().getName();
                } catch (RepositoryException e) {
-                       throw new ArgeoException("Cannot extract workspace of " + userHome,
-                                       e);
+                       throw new ArgeoException("Cannot extract workspace from "
+                                       + userHome, e);
                }
        }
 
-       public Node getUserHome() {
-               return userHome;
+       /** The path to the authenticated user home node. */
+       public String getUserHomePath() {
+               return userHomePath;
+       }
+
+       /** The session used to create this authentication. */
+       public Session getSession() {
+               return session;
+       }
+
+       @Override
+       public boolean isAuthenticated() {
+               if (session == null || !session.isLive())
+                       setAuthenticated(false);
+               return super.isAuthenticated();
+       }
+
+       @Override
+       public void setAuthenticated(boolean isAuthenticated)
+                       throws IllegalArgumentException {
+               super.setAuthenticated(isAuthenticated);
+               if (!isAuthenticated && session != null)
+                       session.logout();
        }
 
 }
index b676aef80ca0e77f10587deabfbe95152f607b25..2c74d3ccdfdba089cf54e1667e4c6035bb8b2155 100644 (file)
@@ -31,6 +31,7 @@
                                        <instructions>
                                                <Fragment-Host>org.argeo.dep.osgi.jackrabbit</Fragment-Host>
                                                <Export-Package>org.argeo.security.jackrabbit.*</Export-Package>
+                                               <Import-Package>*,org.springframework.core</Import-Package>
                                        </instructions>
                                </configuration>
                        </plugin>
index 4403def106991b16d1532359b616b5c0cd9949ec..b29606318297750081356bb6f679e215262f6b48 100644 (file)
@@ -1,8 +1,16 @@
 package org.argeo.security.jackrabbit;
 
+import javax.jcr.RepositoryException;
+
 import org.apache.jackrabbit.core.security.DefaultAccessManager;
 
 /** Intermediary class in order to have a consistent naming in config files. */
 public class ArgeoAccessManager extends DefaultAccessManager {
 
+       @Override
+       public boolean canAccess(String workspaceName) throws RepositoryException {
+               // TODO Auto-generated method stub
+               return super.canAccess(workspaceName);
+       }
+
 }
index a3a6d42d6ee85f43969205bd7fdca6a13c38e301..e5b83e3169d2afa3df0f675190d16fe69123d345 100644 (file)
@@ -1,11 +1,13 @@
 package org.argeo.security.jackrabbit;
 
+import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 import javax.security.auth.Subject;
 
 import org.apache.commons.logging.Log;
@@ -14,7 +16,11 @@ import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.core.DefaultSecurityManager;
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.security.AnonymousPrincipal;
+import org.apache.jackrabbit.core.security.SecurityConstants;
 import org.apache.jackrabbit.core.security.SystemPrincipal;
+import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
 import org.argeo.ArgeoException;
 import org.springframework.security.Authentication;
 import org.springframework.security.GrantedAuthority;
@@ -71,10 +77,54 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                                group.removeMember(user);
                }
 
-               if (log.isDebugEnabled())
-                       log.debug("Spring and Jackrabbit Security synchronized for user "
+               if (log.isTraceEnabled())
+                       log.trace("Spring and Jackrabbit Security synchronized for user "
                                        + userId + " in " + (System.currentTimeMillis() - begin)
                                        + " ms");
                return userId;
        }
+
+       @Override
+       protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
+               WorkspaceAccessManager wam = super
+                               .createDefaultWorkspaceAccessManager();
+               return new ArgeoWorkspaceAccessManagerImpl(wam);
+       }
+
+       private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants,
+                       WorkspaceAccessManager {
+               private final WorkspaceAccessManager wam;
+               private String defaultWorkspace;
+
+               public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) {
+                       super();
+                       this.wam = wam;
+               }
+
+               public void init(Session systemSession) throws RepositoryException {
+                       wam.init(systemSession);
+                       defaultWorkspace = ((RepositoryImpl) getRepository()).getConfig()
+                                       .getDefaultWorkspaceName();
+               }
+
+               public void close() throws RepositoryException {
+               }
+
+               public boolean grants(Set<Principal> principals, String workspaceName)
+                               throws RepositoryException {
+                       // anonymous has access to the default workspace (required for
+                       // remoting which does a default login when initializing the
+                       // repository)
+                       Boolean anonymous = false;
+                       for (Principal principal : principals)
+                               if (principal instanceof AnonymousPrincipal)
+                                       anonymous = true;
+
+                       if (anonymous && workspaceName.equals(defaultWorkspace))
+                               return true;
+                       else
+                               return wam.grants(principals, workspaceName);
+               }
+       }
+
 }
index 86c788a448e5188f8afd6902188e955b492bf2fb..2d9fb1c1adf05cecf42a85c3137602d2b70d4163 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.security.ldap.jcr;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 import javax.jcr.Node;
 import javax.jcr.Repository;
@@ -15,8 +16,8 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.security.SystemExecutionService;
 import org.argeo.security.jcr.JcrUserDetails;
 import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DirContextOperations;
@@ -29,64 +30,100 @@ import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
  * checks of which values should be mandatory should be performed at a higher
  * level.
  */
-public class JcrUserDetailsContextMapper implements UserDetailsContextMapper {
+public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
+               ArgeoNames {
        private final static Log log = LogFactory
                        .getLog(JcrUserDetailsContextMapper.class);
 
+       private String usernameAttribute;
+       private String passwordAttribute;
+       private String homeBasePath;
+       private String[] userClasses;
+
        private Map<String, String> propertyToAttributes = new HashMap<String, String>();
-       private SystemExecutionService systemExecutionService;
-       private String homeBasePath = "/home";
+       private Executor systemExecutor;
        private RepositoryFactory repositoryFactory;
 
        public UserDetails mapUserFromContext(final DirContextOperations ctx,
                        final String username, GrantedAuthority[] authorities) {
                if (repositoryFactory == null)
                        throw new ArgeoException("No JCR repository factory registered");
-               final String userHomePath = usernameToHomePath(username);
-               systemExecutionService.executeAsSystem(new Runnable() {
+               final StringBuffer userHomePathT = new StringBuffer("");
+               systemExecutor.execute(new Runnable() {
                        public void run() {
-                               Session session = null;
-                               try {
-                                       Repository nodeRepo = JcrUtils.getRepositoryByAlias(
-                                                       repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
-                                       session = nodeRepo.login();
-                                       Node userProfile = JcrUtils.mkdirs(session, userHomePath
-                                                       + '/' + ArgeoNames.ARGEO_USER_PROFILE);
-                                       for (String jcrProperty : propertyToAttributes.keySet())
-                                               ldapToJcr(userProfile, jcrProperty, ctx);
-                                       session.save();
-                                       if (log.isDebugEnabled())
-                                               log.debug("Mapped " + ctx.getDn() + " to "
-                                                               + userProfile);
-                               } catch (RepositoryException e) {
-                                       throw new ArgeoException("Cannot synchronize JCR and LDAP",
-                                                       e);
-                               } finally {
-                                       session.logout();
-                               }
+                               String userHomepath = mapLdapToJcr(username, ctx);
+                               userHomePathT.append(userHomepath);
                        }
                });
 
                // password
-               byte[] arr = (byte[]) ctx.getAttributeSortedStringSet("userPassword")
-                               .first();
-               JcrUserDetails userDetails = new JcrUserDetails(userHomePath, username,
-                               new String(arr), true, true, true, true, authorities);
+               byte[] arr = (byte[]) ctx
+                               .getAttributeSortedStringSet(passwordAttribute).first();
+               JcrUserDetails userDetails = new JcrUserDetails(
+                               userHomePathT.toString(), username, new String(arr), true,
+                               true, true, true, authorities);
+               // erase password
                Arrays.fill(arr, (byte) 0);
                return userDetails;
        }
 
+       /** @return path to the user home node */
+       protected String mapLdapToJcr(String username, DirContextOperations ctx) {
+               Session session = null;
+               try {
+                       Repository nodeRepo = JcrUtils.getRepositoryByAlias(
+                                       repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
+                       session = nodeRepo.login();
+                       Node userHome = JcrUtils.getUserHome(session, username);
+                       if (userHome == null)
+                               userHome = createUserHome(session, username);
+                       String userHomePath = userHome.getPath();
+                       Node userProfile = userHome.hasNode(ARGEO_USER_PROFILE) ? userHome
+                                       .getNode(ARGEO_USER_PROFILE) : userHome
+                                       .addNode(ARGEO_USER_PROFILE);
+                       for (String jcrProperty : propertyToAttributes.keySet())
+                               ldapToJcr(userProfile, jcrProperty, ctx);
+                       session.save();
+                       if (log.isDebugEnabled())
+                               log.debug("Mapped " + ctx.getDn() + " to " + userProfile);
+                       return userHomePath;
+               } catch (RepositoryException e) {
+                       JcrUtils.discardQuietly(session);
+                       throw new ArgeoException("Cannot synchronize JCR and LDAP", e);
+               } finally {
+                       session.logout();
+               }
+       }
+
+       protected Node createUserHome(Session session, String username) {
+               try {
+                       Node userHome = JcrUtils.mkdirs(session,
+                                       usernameToHomePath(username));
+                       userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+                       userHome.setProperty(ARGEO_USER_ID, username);
+                       return userHome;
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot create home node for user "
+                                       + username, e);
+               }
+       }
+
+       protected String usernameToHomePath(String username) {
+               return homeBasePath + '/' + JcrUtils.firstCharsToPath(username, 2)
+                               + '/' + username;
+       }
+
        public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) {
                if (!(user instanceof JcrUserDetails))
                        throw new ArgeoException("Unsupported user details: "
                                        + user.getClass());
 
-               ctx.setAttributeValues("objectClass", new String[] { "inetOrgPerson" });
-               ctx.setAttributeValue("uid", user.getUsername());
-               ctx.setAttributeValue("userPassword", user.getPassword());
+               ctx.setAttributeValues("objectClass", userClasses);
+               ctx.setAttributeValue(usernameAttribute, user.getUsername());
+               ctx.setAttributeValue(passwordAttribute, user.getPassword());
 
                final JcrUserDetails jcrUserDetails = (JcrUserDetails) user;
-               systemExecutionService.executeAsSystem(new Runnable() {
+               systemExecutor.execute(new Runnable() {
                        public void run() {
                                Session session = null;
                                try {
@@ -94,9 +131,7 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper {
                                                        repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
                                        session = nodeRepo.login();
                                        Node userProfile = session.getNode(jcrUserDetails
-                                                       .getHomePath()
-                                                       + '/'
-                                                       + ArgeoNames.ARGEO_USER_PROFILE);
+                                                       .getHomePath() + '/' + ARGEO_USER_PROFILE);
                                        for (String jcrProperty : propertyToAttributes.keySet())
                                                jcrToLdap(userProfile, jcrProperty, ctx);
                                        if (log.isDebugEnabled())
@@ -112,11 +147,6 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper {
                });
        }
 
-       protected String usernameToHomePath(String username) {
-               return homeBasePath + '/' + JcrUtils.firstCharsToPath(username, 2)
-                               + '/' + username;
-       }
-
        protected void ldapToJcr(Node userProfile, String jcrProperty,
                        DirContextOperations ctx) {
                try {
@@ -163,9 +193,8 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper {
                this.propertyToAttributes = propertyToAttributes;
        }
 
-       public void setSystemExecutionService(
-                       SystemExecutionService systemExecutionService) {
-               this.systemExecutionService = systemExecutionService;
+       public void setSystemExecutor(Executor systemExecutor) {
+               this.systemExecutor = systemExecutor;
        }
 
        public void setHomeBasePath(String homeBasePath) {
@@ -181,4 +210,17 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper {
                        Map<String, String> parameters) {
                this.repositoryFactory = null;
        }
+
+       public void setUsernameAttribute(String usernameAttribute) {
+               this.usernameAttribute = usernameAttribute;
+       }
+
+       public void setPasswordAttribute(String passwordAttribute) {
+               this.passwordAttribute = passwordAttribute;
+       }
+
+       public void setUserClasses(String[] userClasses) {
+               this.userClasses = userClasses;
+       }
+
 }
index 42db5686a5808d4693f55c80a271fa32c6e8831c..faf8e94b8899512e60cd99c669bee288f739a7a8 100644 (file)
        <bean id="sessionProvider" scope="session" init-method="init"
                destroy-method="dispose" class="org.argeo.jackrabbit.remote.SimpleSessionProvider">
                <aop:scoped-proxy proxy-target-class="false" />
+<!--           <property name="credentials"> -->
+<!--                   <bean class="javax.jcr.SimpleCredentials"> -->
+<!--                           <constructor-arg value="root" /> -->
+<!--                           <constructor-arg value="demo" /> -->
+<!--                   </bean> -->
+<!--           </property> -->
        </bean>
 
        <bean id="osivInterceptor" class="org.argeo.jcr.mvc.OpenSessionInViewJcrInterceptor">
index caba1aa9f72a61392c3f11f4a05f642f05bb4ace..2627b75830e6111619308b9afa3501fafb25dc69 100644 (file)
@@ -14,7 +14,7 @@
                <security:intercept-url pattern="/**"
                        access="ROLE_USER,ROLE_ADMIN,ROLE_ANONYMOUS" />
                <security:http-basic />
-               <security:anonymous />
+               <security:anonymous username="anonymous" />
        </security:http>
 
        <!-- LDAP -->
index 1131a38612e2a3424ad93e53f40067d6051ca063..c7a1e006c3db6956fe6b627f3326126899f9b76a 100644 (file)
@@ -10,9 +10,7 @@ Import-Package: com.mysql.jdbc;version="[5.0.0,6.0.0)";resolution:=optional,
  org.apache.xalan.processor,
  org.argeo.jackrabbit,
  org.argeo.jcr,
- org.argeo.security.jackrabbit.providers,
- org.argeo.security.jcr,
+ org.argeo.security,
  org.h2;version="[1.0.0,2.0.0)";resolution:=optional,
  org.postgresql;version="[8.0.0,9.0.0)";resolution:=optional,
- org.springframework.beans.factory.config,
- org.springframework.security.providers;version="2.0.6.RELEASE"
+ org.springframework.beans.factory.config
index 0cced08e3eb79513d105b2b1ab10fd09eb96422c..2b8d18a54ad60e7c1c2351b87c5eb5327bb78060 100644 (file)
        http://www.springframework.org/schema/util/spring-util-2.5.xsd">\r
 \r
        <!-- REFERENCE -->\r
-       <reference id="repositoryFactoryRef" interface="javax.jcr.RepositoryFactory"\r
-               cardinality="0..1">\r
-               <listener ref="jcrAuthenticationProvider" bind-method="register"\r
-                       unbind-method="unregister" />\r
-       </reference>\r
        <list id="repositories" interface="javax.jcr.Repository"\r
                cardinality="0..N">\r
                <listener ref="repositoryFactory" bind-method="register"\r
                        unbind-method="unregister" />\r
        </list>\r
+       <reference id="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
 \r
        <!-- SERVICES -->\r
        <service ref="repositoryFactory" interface="javax.jcr.RepositoryFactory" />\r
@@ -45,8 +41,4 @@
                        </beans:entry>\r
                </service-properties>\r
        </service>\r
-\r
-       <service ref="jcrAuthenticationProvider"\r
-               interface="org.springframework.security.providers.AuthenticationProvider" />\r
-\r
 </beans:beans>
\ No newline at end of file
index ec8574efe5d7fb9244ed97ea2bdc2b28ba29df91..f228d9da75849b2c5dd567e6d94c8213ee53ab79 100644 (file)
@@ -26,6 +26,7 @@
                                <value>classpath:/org/argeo/jcr/argeo.cnd</value>
                        </list>
                </property>
+               <property name="systemExecutor" ref="systemExecutionService" />
        </bean>
 
        <bean id="nodeJcrSession" class="org.argeo.jcr.ThreadBoundJcrSessionFactory">
                <property name="workspace" value="${argeo.node.repo.workspace}" />
        </bean>
 
-       <bean id="jcrAuthenticationProvider"
-               class="org.argeo.security.jackrabbit.providers.JackrabbitAuthenticationProvider" />
-
-       <bean id="repositoryFactory" class="org.argeo.jackrabbit.JackrabbitRepositoryFactory">
-       </bean>
+       <bean id="repositoryFactory" class="org.argeo.jackrabbit.JackrabbitRepositoryFactory"/>
 
 </beans>
\ No newline at end of file
index c1c1f19b96ead0ac1d7a353a41f43be0b1eef149..0a9a4bb611a2c52ebae5344fb991c3d9abe387c0 100644 (file)
@@ -22,9 +22,4 @@
 
        <bean id="importFileSystem" class="org.argeo.eclipse.ui.jcr.commands.ImportFileSystem"
                scope="prototype" />
-
-       <bean id="initUserHome" class="org.argeo.eclipse.ui.jcr.commands.InitUserHome"
-               scope="prototype">
-               <property name="session" ref="nodeJcrSession" />
-       </bean>
 </beans>
index c1a1d6b154b99a2c7fccd601b51a8ab7f8f3abb9..2a8d80a897ae75a9fb6ca75a8e5b8b8b829aa57c 100644 (file)
         id="org.argeo.jcr.ui.explorer.addFileFolder"
         name="Add file folder...">
   </command>
-  <command
-        defaultHandler="org.argeo.eclipse.spring.SpringCommandHandler"
-        id="org.argeo.jcr.ui.explorer.initUserHome"
-        name="Initialize user home">
-  </command>
   <command
         defaultHandler="org.argeo.eclipse.spring.SpringCommandHandler"
         id="org.argeo.jcr.ui.explorer.refresh"
index 2dcb1a9cf911f0569ebd79e0d51ca6e1e0f00fa1..67126362b5bd8437285eaa79510e105bd3d0ded3 100644 (file)
@@ -20,11 +20,13 @@ import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.Executor;
 
 import javax.jcr.Credentials;
 import javax.jcr.LoginException;
@@ -39,7 +41,6 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.api.JackrabbitRepository;
-import org.apache.jackrabbit.commons.JcrUtils;
 import org.apache.jackrabbit.commons.NamespaceHelper;
 import org.apache.jackrabbit.commons.cnd.CndImporter;
 import org.apache.jackrabbit.core.RepositoryImpl;
@@ -48,6 +49,7 @@ import org.apache.jackrabbit.core.config.RepositoryConfig;
 import org.apache.jackrabbit.core.config.RepositoryConfigurationParser;
 import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
 import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.ResourceLoaderAware;
@@ -75,7 +77,6 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean,
        private ResourceLoader resourceLoader;
 
        /** Node type definitions in CND format */
-       private List<byte[]> cnds = new ArrayList<byte[]>();
        private List<String> cndFiles = new ArrayList<String>();
 
        /** Namespaces to register: key is prefix, value namespace */
@@ -83,59 +84,101 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean,
 
        private Boolean autocreateWorkspaces = false;
 
-       public void afterPropertiesSet() throws Exception {
-               // Load cnds as resources
-               for (String resUrl : cndFiles) {
-                       Resource res = resourceLoader.getResource(resUrl);
-                       byte[] arr = IOUtils.toByteArray(res.getInputStream());
-                       cnds.add(arr);
-               }
+       private Executor systemExecutor;
 
+       public void afterPropertiesSet() throws Exception {
+               // remote repository
                if (uri != null && !uri.trim().equals("")) {
                        Map<String, String> params = new HashMap<String, String>();
-                       params.put(JcrUtils.REPOSITORY_URI, uri);
+                       params.put(org.apache.jackrabbit.commons.JcrUtils.REPOSITORY_URI,
+                                       uri);
                        repository = new Jcr2davRepositoryFactory().getRepository(params);
                        if (repository == null)
                                throw new ArgeoException("Remote Davex repository " + uri
                                                + " not found");
                        log.info("Initialized Jackrabbit repository " + repository
                                        + " from uri " + uri);
-               } else {
-                       if (inMemory && homeDirectory.exists()) {
-                               FileUtils.deleteDirectory(homeDirectory);
-                               log.warn("Deleted Jackrabbit home directory " + homeDirectory);
-                       }
+                       // do not perform further initialization since we assume that the
+                       // remote repository has been properly configured
+                       return;
+               }
 
-                       RepositoryConfig config;
-                       InputStream in = configuration.getInputStream();
-                       InputStream propsIn = null;
-                       try {
-                               Properties vars = new Properties();
-                               if (variables != null) {
-                                       propsIn = variables.getInputStream();
-                                       vars.load(propsIn);
-                               }
-                               // override with system properties
-                               vars.putAll(System.getProperties());
-                               vars.put(
-                                               RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE,
-                                               homeDirectory.getCanonicalPath());
-                               config = RepositoryConfig.create(new InputSource(in), vars);
-                       } catch (Exception e) {
-                               throw new RuntimeException("Cannot read configuration", e);
-                       } finally {
-                               IOUtils.closeQuietly(in);
-                               IOUtils.closeQuietly(propsIn);
+               // local repository
+               if (inMemory && homeDirectory.exists()) {
+                       FileUtils.deleteDirectory(homeDirectory);
+                       log.warn("Deleted Jackrabbit home directory " + homeDirectory);
+               }
+
+               RepositoryConfig config;
+               InputStream in = configuration.getInputStream();
+               InputStream propsIn = null;
+               try {
+                       Properties vars = new Properties();
+                       if (variables != null) {
+                               propsIn = variables.getInputStream();
+                               vars.load(propsIn);
                        }
+                       // override with system properties
+                       vars.putAll(System.getProperties());
+                       vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE,
+                                       homeDirectory.getCanonicalPath());
+                       config = RepositoryConfig.create(new InputSource(in), vars);
+               } catch (Exception e) {
+                       throw new RuntimeException("Cannot read configuration", e);
+               } finally {
+                       IOUtils.closeQuietly(in);
+                       IOUtils.closeQuietly(propsIn);
+               }
 
-                       if (inMemory)
-                               repository = new TransientRepository(config);
-                       else
-                               repository = RepositoryImpl.create(config);
+               if (inMemory)
+                       repository = new TransientRepository(config);
+               else
+                       repository = RepositoryImpl.create(config);
 
-                       log.info("Initialized Jackrabbit repository " + repository + " in "
-                                       + homeDirectory + " with config " + configuration);
+               importNodeTypeDefinitions(repository);
+
+               log.info("Initialized Jackrabbit repository " + repository + " in "
+                               + homeDirectory + " with config " + configuration);
+       }
+
+       /**
+        * Import declared node type definitions, trying to update them if they have
+        * changed. In case of failures an error will be logged but no exception
+        * will be thrown.
+        */
+       protected void importNodeTypeDefinitions(final Repository repository) {
+               if (systemExecutor == null) {
+                       log.warn("No system executor found");
+                       return;
                }
+
+               systemExecutor.execute(new Runnable() {
+                       public void run() {
+                               Reader reader = null;
+                               Session session = null;
+                               try {
+                                       session = repository.login();
+                                       // Load cnds as resources
+                                       for (String resUrl : cndFiles) {
+                                               Resource res = resourceLoader.getResource(resUrl);
+                                               byte[] arr = IOUtils.toByteArray(res.getInputStream());
+                                               reader = new InputStreamReader(
+                                                               new ByteArrayInputStream(arr));
+                                               CndImporter.registerNodeTypes(reader, session, true);
+                                       }
+                                       session.save();
+                               } catch (Exception e) {
+                                       log.error(
+                                                       "Cannot import node type definitions " + cndFiles,
+                                                       e);
+                                       JcrUtils.discardQuietly(session);
+                               } finally {
+                                       IOUtils.closeQuietly(reader);
+                                       JcrUtils.logoutQuietly(session);
+                               }
+                       }
+               });
+
        }
 
        public void destroy() throws Exception {
@@ -220,10 +263,6 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean,
                try {
                        NamespaceHelper namespaceHelper = new NamespaceHelper(session);
                        namespaceHelper.registerNamespaces(namespaces);
-
-                       for (byte[] arr : cnds)
-                               CndImporter.registerNodeTypes(new InputStreamReader(
-                                               new ByteArrayInputStream(arr)), session, true);
                } catch (Exception e) {
                        throw new ArgeoException("Cannot process new session", e);
                }
@@ -292,4 +331,8 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean,
                this.uri = uri;
        }
 
+       public void setSystemExecutor(Executor systemExecutor) {
+               this.systemExecutor = systemExecutor;
+       }
+
 }
diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/CachingSessionProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/CachingSessionProvider.java
deleted file mode 100644 (file)
index 422623c..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.argeo.jackrabbit.remote;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Credentials;
-import javax.jcr.LoginException;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.jackrabbit.server.SessionProvider;
-
-public class CachingSessionProvider implements SessionProvider {
-       private static final String JCR_SESSIONS_ATTRIBUTE = "jcrSessions";
-
-       private final static Log log = LogFactory
-                       .getLog(CachingSessionProvider.class);
-
-       private Credentials credentials = null;
-
-       public CachingSessionProvider() {
-       }
-
-       public CachingSessionProvider(Credentials credentials) {
-               this.credentials = credentials;
-       }
-
-       @SuppressWarnings("unchecked")
-       public Session getSession(HttpServletRequest request, Repository rep,
-                       String workspace) throws LoginException, ServletException,
-                       RepositoryException {
-               HttpSession httpSession = request.getSession();
-
-               if (httpSession.getAttribute(JCR_SESSIONS_ATTRIBUTE) == null) {
-                       httpSession
-                                       .setAttribute(JCR_SESSIONS_ATTRIBUTE, Collections
-                                                       .synchronizedMap(new HashMap<String, Session>()));
-               }
-               Map<String, Session> sessions = (Map<String, Session>) httpSession
-                               .getAttribute(JCR_SESSIONS_ATTRIBUTE);
-               if (!sessions.containsKey(workspace)) {
-                       Session session = rep.login(credentials, workspace);
-                       sessions.put(workspace, session);
-                       return session;
-               } else {
-                       Session session = sessions.get(workspace);
-                       if (!session.isLive()) {
-                               sessions.remove(workspace);
-                               session = rep.login(credentials, workspace);
-                               sessions.put(workspace, session);
-                       }
-                       return session;
-               }
-       }
-
-       public void releaseSession(Session session) {
-               if (log.isDebugEnabled())
-                       log.debug("Releasing JCR session " + session);
-               // session.logout();
-               // FIXME: find a way to log out when the HTTP session is expired
-       }
-
-}
index 39dbf7f678067351288dfda7708c18737d1333c3..ec1d96ea30dc0b8ead6cf3999d899cb788c71405 100644 (file)
@@ -34,6 +34,7 @@ public class ExtendedDispatcherServlet extends DispatcherServlet {
        protected void service(HttpServletRequest request,
                        HttpServletResponse response) throws ServletException,
                        java.io.IOException {
+
                // see http://forum.springsource.org/showthread.php?t=53472
                try {
                        if (log.isTraceEnabled())
index 41c1a753708409b21a5533819a0756c91dd6b8bd..100c91ad1be8b9c52255e4715e615d3fa3e53ca4 100644 (file)
@@ -7,6 +7,7 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 
 public class JcrRemotingHandlerMapping extends AbstractJackrabbitHandlerMapping {
+
        protected HttpServlet createServlet(Repository repository, String pathPrefix)
                        throws ServletException {
                JcrRemotingServlet servlet = new JcrRemotingServlet(repository,
index eab7451db741471555979486f55a974f3bf3333c..294f3289a39a74890e9183c0b7cbe063f0779188 100644 (file)
@@ -5,7 +5,6 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.jcr.Credentials;
 import javax.jcr.LoginException;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
@@ -27,22 +26,19 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
 
        private transient Map<String, Session> sessions;
 
-       private Credentials credentials = null;
-
        public Session getSession(HttpServletRequest request, Repository rep,
                        String workspace) throws LoginException, ServletException,
                        RepositoryException {
-
-               // since sessions is transient it can be restored from the session
+               // since sessions is transient it can't be restored from the session
                if (sessions == null)
                        sessions = Collections
                                        .synchronizedMap(new HashMap<String, Session>());
 
                if (!sessions.containsKey(workspace)) {
                        try {
-                               Session session = rep.login(credentials, workspace);
-                               if (log.isDebugEnabled())
-                                       log.debug("User " + session.getUserID() + " logged into "
+                               Session session = rep.login(null, workspace);
+                               if (log.isTraceEnabled())
+                                       log.trace("User " + session.getUserID() + " logged into "
                                                        + request.getServletPath());
                                sessions.put(workspace, session);
                                return session;
@@ -53,7 +49,7 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
                        Session session = sessions.get(workspace);
                        if (!session.isLive()) {
                                sessions.remove(workspace);
-                               session = rep.login(credentials, workspace);
+                               session = rep.login(null, workspace);
                                sessions.put(workspace, session);
                        }
                        return session;
index 10bb8b570ad8762aa5f40532b87718a9b93722cf..16ecdd89ecff8de8b5fda232a33ad74124015060 100644 (file)
@@ -58,7 +58,8 @@ public abstract class MultipleRepositoryHandlerMapping implements
                }
                HttpServlet remotingServlet = (HttpServlet) applicationContext
                                .getBean(beanName);
-               return new HandlerExecutionChain(remotingServlet);
+               HandlerExecutionChain hec = new HandlerExecutionChain(remotingServlet);
+               return hec;
        }
 
        /** The repository name is the first part of the path info */
@@ -120,5 +121,4 @@ public abstract class MultipleRepositoryHandlerMapping implements
                        return initParameters.keys();
                }
        }
-
 }
index c8eaa6691ab8093a9438b01e103c2171969ff259..dec1a2875f60292b842712e43e115c387b68a596 100644 (file)
@@ -3,6 +3,5 @@ package org.argeo.jcr;
 /** JCR types in the http://www.argeo.org/argeo namespace */
 public interface ArgeoTypes {
        public final static String ARGEO_LINK = "argeo:link";
-       public final static String ARGEO_HOME = "argeo:home";
        public final static String ARGEO_USER_HOME = "argeo:userHome";
 }
index ad6ca0eddb10dd32d95eba289cd8c42bd4435c77..72b94fbcd0590baef6c4b30049282dd61cdc0ae0 100644 (file)
@@ -44,6 +44,11 @@ import javax.jcr.Value;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryResult;
+import javax.jcr.query.qom.Constraint;
+import javax.jcr.query.qom.DynamicOperand;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+import javax.jcr.query.qom.Selector;
+import javax.jcr.query.qom.StaticOperand;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -53,6 +58,10 @@ import org.argeo.ArgeoException;
 public class JcrUtils implements ArgeoJcrConstants {
        private final static Log log = LogFactory.getLog(JcrUtils.class);
 
+       /** Prevents instantiation */
+       private JcrUtils() {
+       }
+
        /**
         * Queries one single node.
         * 
@@ -613,4 +622,63 @@ public class JcrUtils implements ArgeoJcrConstants {
                                                        + uri, e);
                }
        }
+
+       /**
+        * Discards the current changes in a session by calling
+        * {@link Session#refresh(boolean)} with <code>false</code>, only logging
+        * potential errors when doing so. To be used typically in a catch block.
+        */
+       public static void discardQuietly(Session session) {
+               try {
+                       if (session != null)
+                               session.refresh(false);
+               } catch (RepositoryException e) {
+                       log.warn("Cannot quietly discard session " + session + ": "
+                                       + e.getMessage());
+               }
+       }
+
+       /** Logs out the session, not throwing any exception, even if it is null. */
+       public static void logoutQuietly(Session session) {
+               if (session != null)
+                       session.logout();
+       }
+
+       /** Returns the home node of the session user or null if none was found. */
+       public static Node getUserHome(Session session) {
+               String userID = session.getUserID();
+               return getUserHome(session, userID);
+       }
+
+       /**
+        * Returns the home node of the session user or null if none was found.
+        * 
+        * @param session
+        *            the session to use in order to perform the search, this can be
+        *            a session with a different user ID than the one searched,
+        *            typically when a system or admin session is used.
+        * @param userID
+        *            the id of the user
+        */
+       public static Node getUserHome(Session session, String userID) {
+               try {
+                       QueryObjectModelFactory qomf = session.getWorkspace()
+                                       .getQueryManager().getQOMFactory();
+
+                       // query the user home for this user id
+                       Selector userHomeSel = qomf.selector(ArgeoTypes.ARGEO_USER_HOME,
+                                       "userHome");
+                       DynamicOperand userIdDop = qomf.propertyValue("userHome",
+                                       ArgeoNames.ARGEO_USER_ID);
+                       StaticOperand userIdSop = qomf.literal(session.getValueFactory()
+                                       .createValue(userID));
+                       Constraint constraint = qomf.comparison(userIdDop,
+                                       QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop);
+                       Query query = qomf.createQuery(userHomeSel, constraint, null, null);
+                       Node userHome = JcrUtils.querySingleNode(query);
+                       return userHome;
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot find home for user " + userID, e);
+               }
+       }
 }