Optimize remoting
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 8 Nov 2012 14:17:22 +0000 (14:17 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 8 Nov 2012 14:17:22 +0000 (14:17 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@5745 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

demo/log4j.properties
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/security-filters.xml
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/web.xml
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java
server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/MultipleRepositoryHandlerMapping.java

index 537803d1977abd600a7999896c4282c825bac272..75b2a8bb7a502c75f69855b34e0a3b39f7af85be 100644 (file)
@@ -6,8 +6,8 @@ log4j.logger.org.argeo.jackrabbit.remote.ExtendedDispatcherServlet=WARN
 log4j.logger.org.argeo.server.webextender.TomcatDeployer=WARN
 
 log4j.logger.org.springframework.security=DEBUG
-log4j.logger.org.apache.commons.exec=DEBUG
-log4j.logger.org.apache.jackrabbit.server.jcr=DEBUG
+#log4j.logger.org.apache.commons.exec=DEBUG
+#log4j.logger.org.apache.jackrabbit.server.jcr=DEBUG
 
 log4j.logger.org.apache.catalina=INFO
 log4j.logger.org.apache.coyote=INFO
index 0195436f46cbff0979a1a9a042ed9ace712c78b6..578997a1b04e8c1ed70b02392dbb33bf946072e3 100644 (file)
@@ -6,22 +6,54 @@
        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">
 
-       <bean id="springSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
+       <bean id="filterChain.davex" parent="filterChain.template">
                <sec:filter-chain-map path-type="ant">
-                       <sec:filter-chain pattern="/files/**"
-                               filters="session,x509,basic,exception,interceptor" />
-                       <sec:filter-chain pattern="/jcr/*/*/**"
-                               filters="session,x509,basic,exception,interceptor" />
+                       <sec:filter-chain pattern="/*/*/*/**"
+                               filters="session,x509,basic,exception" />
                        <!-- For some reason the first level listing workspaces must be public -->
-                       <sec:filter-chain pattern="/jcr/*/"
-                               filters="anonymous,exception,interceptorPublic" />
-                       <sec:filter-chain pattern="/public/**"
-                               filters="anonymous,exception,interceptorPublic" />
-                       <sec:filter-chain pattern="/pub/**"
-                               filters="anonymous,exception,interceptorPublic" />
-                       <sec:filter-chain pattern="/j_spring_security_logout"
-                               filters="logout,exception" />
+                       <sec:filter-chain pattern="/*/*/"
+                               filters="anonymous,exception" />
                </sec:filter-chain-map>
+       </bean>
+
+       <bean id="filterChain.private" parent="filterChain.template">
+               <sec:filter-chain-map path-type="ant">
+                       <sec:filter-chain pattern="/**"
+                               filters="session,x509,basic,exception" />
+               </sec:filter-chain-map>
+       </bean>
+
+       <bean id="filterChain.public" parent="filterChain.template">
+               <sec:filter-chain-map path-type="ant">
+                       <sec:filter-chain pattern="/**"
+                               filters="anonymous,exception" />
+               </sec:filter-chain-map>
+       </bean>
+
+       <!-- <bean id="springSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy"> -->
+       <!-- <sec:filter-chain-map path-type="ant"> -->
+       <!-- <sec:filter-chain pattern="/files/**" -->
+       <!-- filters="session,x509,basic,exception,interceptor" /> -->
+       <!-- <sec:filter-chain pattern="/jcr/*/*/**" -->
+       <!-- filters="session,x509,basic,exception,interceptor" /> -->
+       <!-- <sec:filter-chain pattern="/jcr/*/" -->
+       <!-- filters="anonymous,exception,interceptorPublic" /> -->
+       <!-- <sec:filter-chain pattern="/public/**" -->
+       <!-- filters="anonymous,exception,interceptorPublic" /> -->
+       <!-- <sec:filter-chain pattern="/pub/**" -->
+       <!-- filters="anonymous,exception,interceptorPublic" /> -->
+       <!-- <sec:filter-chain pattern="/j_spring_security_logout" -->
+       <!-- filters="logout,exception" /> -->
+       <!-- </sec:filter-chain-map> -->
+       <!-- <property name="matcher"> -->
+       <!-- <bean class="org.springframework.security.util.AntUrlPathMatcher"> -->
+       <!-- <constructor-arg value="false" /> -->
+       <!-- </bean> -->
+       <!-- </property> -->
+       <!-- </bean> -->
+
+       <bean id="filterChain.template" abstract="true"
+               class="org.springframework.security.util.FilterChainProxy">
                <property name="matcher">
                        <bean class="org.springframework.security.util.AntUrlPathMatcher">
                                <!-- Do not convert to lower case -->
                        </bean>
                </property>
        </bean>
-
+       
        <!-- The actual authorization checks (called last, but first here for ease 
                of configuration) -->
-       <bean id="interceptor" parent="filterInvocationInterceptorTemplate">
-               <property name="objectDefinitionSource">
-                       <value>
-                               PATTERN_TYPE_APACHE_ANT
-                               /**=ROLE_USER,ROLE_ADMIN
-                       </value>
-               </property>
-       </bean>
-       <bean id="interceptorPublic" parent="filterInvocationInterceptorTemplate">
-               <property name="objectDefinitionSource">
-                       <value>
-                               PATTERN_TYPE_APACHE_ANT
-                               /**=IS_AUTHENTICATED_ANONYMOUSLY
-                       </value>
-               </property>
-       </bean>
+<!--   <bean id="interceptor" parent="filterInvocationInterceptorTemplate"> -->
+<!--           <property name="objectDefinitionSource"> -->
+<!--                   <value> -->
+<!--                           PATTERN_TYPE_APACHE_ANT -->
+<!--                           /**=ROLE_USER,ROLE_ADMIN -->
+<!--                   </value> -->
+<!--           </property> -->
+<!--   </bean> -->
+<!--   <bean id="interceptorPublic" parent="filterInvocationInterceptorTemplate"> -->
+<!--           <property name="objectDefinitionSource"> -->
+<!--                   <value> -->
+<!--                           PATTERN_TYPE_APACHE_ANT -->
+<!--                           /**=IS_AUTHENTICATED_ANONYMOUSLY -->
+<!--                   </value> -->
+<!--           </property> -->
+<!--   </bean> -->
 
        <bean id="x509"
                class="org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter">
 
        <!-- Processes logouts, removing both session informations and the remember-me 
                cookie from the browser -->
-       <bean id="logout" class="org.springframework.security.ui.logout.LogoutFilter">
-               <constructor-arg value="/webdav/node/main" />
-               <!-- URL redirected to after logout -->
-               <constructor-arg>
-                       <list>
-                               <!-- <ref bean="rememberMeServices" /> -->
-                               <bean
-                                       class="org.springframework.security.ui.logout.SecurityContextLogoutHandler" />
-                       </list>
-               </constructor-arg>
-       </bean>
-
-       <!-- Use the remember me cookie to authenticate <bean id="rememberMe" class="org.springframework.security.ui.rememberme.RememberMeProcessingFilter"> 
-               <property name="authenticationManager" ref="authenticationManager" /> <property 
-               name="rememberMeServices" ref="rememberMeServices" /> </bean> <bean id="rememberMeServices" 
-               class="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices"> 
-               <property name="userDetailsService" ref="userDetailsService" /> <property 
-               name="key" value="${argeo.security.systemKey}" /> <property name="tokenValiditySeconds" 
-               value="${argeo.jcr.webapp.rememberMeValidity}" /> <property name="alwaysRemember" 
-               value="true" /> </bean> -->
+<!--   <bean id="logout" class="org.springframework.security.ui.logout.LogoutFilter"> -->
+<!--           <constructor-arg value="/webdav/node/main" /> -->
+<!--           <constructor-arg> -->
+<!--                   <list> -->
+<!--                           <bean -->
+<!--                                   class="org.springframework.security.ui.logout.SecurityContextLogoutHandler" /> -->
+<!--                   </list> -->
+<!--           </constructor-arg> -->
+<!--   </bean> -->
 
        <!-- Basic authentication -->
        <bean id="basic"
                <property name="authenticationEntryPoint">
                        <ref local="basicProcessingFilterEntryPoint" />
                </property>
-               <!-- <property name="rememberMeServices" ref="rememberMeServices" /> -->
        </bean>
 
        <!-- Activate basic auth when needed -->
                </property>
                <property name="accessDeniedHandler">
                        <bean class="org.springframework.security.ui.AccessDeniedHandlerImpl">
-                               <property name="errorPage" value="/accessDenied.jsp" />
+<!--                           <property name="errorPage" value="/accessDenied.jsp" /> -->
                        </bean>
                </property>
        </bean>
 
        <!-- Template for authorization checks -->
-       <bean id="filterInvocationInterceptorTemplate" abstract="true"
-               class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
-               <property name="authenticationManager" ref="authenticationManager" />
-               <property name="accessDecisionManager">
-                       <bean class="org.springframework.security.vote.AffirmativeBased">
-                               <property name="allowIfAllAbstainDecisions" value="false" />
-                               <property name="decisionVoters">
-                                       <list>
-                                               <bean class="org.springframework.security.vote.RoleVoter" />
-                                               <bean class="org.springframework.security.vote.AuthenticatedVoter" />
-                                       </list>
-                               </property>
-                       </bean>
-               </property>
-       </bean>
+<!--   <bean id="filterInvocationInterceptorTemplate" abstract="true" -->
+<!--           class="org.springframework.security.intercept.web.FilterSecurityInterceptor"> -->
+<!--           <property name="authenticationManager" ref="authenticationManager" /> -->
+<!--           <property name="accessDecisionManager"> -->
+<!--                   <bean class="org.springframework.security.vote.AffirmativeBased"> -->
+<!--                           <property name="allowIfAllAbstainDecisions" value="false" /> -->
+<!--                           <property name="decisionVoters"> -->
+<!--                                   <list> -->
+<!--                                           <bean class="org.springframework.security.vote.RoleVoter" /> -->
+<!--                                           <bean class="org.springframework.security.vote.AuthenticatedVoter" /> -->
+<!--                                   </list> -->
+<!--                           </property> -->
+<!--                   </bean> -->
+<!--           </property> -->
+<!--   </bean> -->
 </beans>
\ No newline at end of file
index 04cf5eb2df924c4f5342a22a3c2181ffa420346d..a1876b306385c906cec5e6ebb1495cc8cd0118f5 100644 (file)
 
        <!-- Security -->
        <filter>
-               <filter-name>springSecurityFilterChain</filter-name>
+               <filter-name>filterChain.davex</filter-name>
                <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
+       <filter-mapping>
+               <filter-name>filterChain.davex</filter-name>
+               <url-pattern>/jcr/*</url-pattern>
+       </filter-mapping>
+
+       <filter>
+               <filter-name>filterChain.private</filter-name>
+               <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+       </filter>
+       <filter-mapping>
+               <filter-name>filterChain.private</filter-name>
+               <url-pattern>/files/*</url-pattern>
+       </filter-mapping>
 
+       <filter>
+               <filter-name>filterChain.public</filter-name>
+               <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+       </filter>
        <filter-mapping>
-               <filter-name>springSecurityFilterChain</filter-name>
-               <url-pattern>/*</url-pattern>
+               <filter-name>filterChain.public</filter-name>
+               <url-pattern>/pub/*</url-pattern>
        </filter-mapping>
+       <filter-mapping>
+               <filter-name>filterChain.public</filter-name>
+               <url-pattern>/public/*</url-pattern>
+       </filter-mapping>
+
 </web-app>
index 125aff8a31050670f8ecbaba05222cdca89a0f80..e321bfac3b5994c7a4c02dca2ac705697f604380 100644 (file)
@@ -16,7 +16,6 @@
 package org.argeo.jackrabbit.remote;
 
 import java.io.Serializable;
-import java.util.List;
 
 import javax.jcr.LoginException;
 import javax.jcr.Repository;
@@ -30,7 +29,9 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.server.SessionProvider;
 import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.jcr.JcrUtils;
+import org.springframework.security.Authentication;
 import org.springframework.security.context.SecurityContextHolder;
 
 /**
@@ -48,17 +49,22 @@ public class ScopedSessionProvider implements SessionProvider, Serializable {
        private transient String currentWorkspaceName = null;
        private transient String currentJcrUser = null;
 
+       // private transient String anonymousUserId = "anonymous";
+
        public Session getSession(HttpServletRequest request, Repository rep,
                        String workspace) throws LoginException, ServletException,
                        RepositoryException {
 
-               String springUser = SecurityContextHolder.getContext()
-                               .getAuthentication().getName();
+               Authentication authentication = SecurityContextHolder.getContext()
+                               .getAuthentication();
+               if (authentication == null)
+                       throw new ArgeoException(
+                                       "Request not authenticated by Spring Security");
+               String springUser = authentication.getName();
 
                // HTTP
-               String pathInfo = request.getPathInfo();
-               List<String> tokens = JcrUtils.tokenize(pathInfo);
-               String httpRepository = tokens.get(0);
+               String requestJcrRepository = (String) request
+                               .getAttribute(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS);
 
                // HTTP session
                if (httpSession != null
@@ -68,43 +74,46 @@ public class ScopedSessionProvider implements SessionProvider, Serializable {
                if (httpSession == null)
                        httpSession = request.getSession();
 
+               // Initializes current values
                if (currentRepositoryName == null)
-                       currentRepositoryName = httpRepository;
+                       currentRepositoryName = requestJcrRepository;
                if (currentWorkspaceName == null)
                        currentWorkspaceName = workspace;
                if (currentJcrUser == null)
                        currentJcrUser = springUser;
 
+               // logout if there was a change in session coordinates
                if (jcrSession != null)
-                       if (!currentRepositoryName.equals(httpRepository)) {
+                       if (!currentRepositoryName.equals(requestJcrRepository)) {
                                if (log.isDebugEnabled())
-                                       log.debug(getHttpSessionId() + " Changed from repository "
-                                                       + currentRepositoryName + " to " + httpRepository
-                                                       + ", logging out.");
+                                       log.debug(getHttpSessionId() + " Changed from repository '"
+                                                       + currentRepositoryName + "' to '"
+                                                       + requestJcrRepository
+                                                       + "', logging out cached JCR session.");
                                logout();
                        } else if (!currentWorkspaceName.equals(workspace)) {
                                if (log.isDebugEnabled())
-                                       log.debug(getHttpSessionId() + " Changed from workspace "
-                                                       + currentWorkspaceName + " to " + workspace
-                                                       + ", logging out.");
+                                       log.debug(getHttpSessionId() + " Changed from workspace '"
+                                                       + currentWorkspaceName + "' to '" + workspace
+                                                       + "', logging out cached JCR session.");
                                logout();
                        } else if (!currentJcrUser.equals(springUser)) {
                                if (log.isDebugEnabled())
-                                       log.debug(getHttpSessionId() + " Changed from user "
-                                                       + currentJcrUser + " to " + springUser
-                                                       + ", logging out.");
+                                       log.debug(getHttpSessionId() + " Changed from user '"
+                                                       + currentJcrUser + "' to '" + springUser
+                                                       + "', logging out cached JCR session.");
                                logout();
                        }
 
-               // JCR session
+               // login if needed
                if (jcrSession == null)
                        try {
                                Session session = login(rep, workspace);
                                if (!session.getUserID().equals(springUser))
-                                       throw new ArgeoException("HTTP user '" + springUser
-                                                       + "' not in line with JCR user '"
+                                       throw new ArgeoException("Spring Security user '"
+                                                       + springUser + "' not in line with JCR user '"
                                                        + session.getUserID() + "'");
-                               currentRepositoryName = httpRepository;
+                               currentRepositoryName = requestJcrRepository;
                                // do not use workspace variable which may be null
                                currentWorkspaceName = session.getWorkspace().getName();
                                currentJcrUser = session.getUserID();
@@ -115,8 +124,9 @@ public class ScopedSessionProvider implements SessionProvider, Serializable {
                                throw new ArgeoException("Cannot open session to workspace "
                                                + workspace, e);
                        }
-               else
-                       return jcrSession;
+
+               // returns cached session
+               return jcrSession;
        }
 
        protected Session login(Repository repository, String workspace)
@@ -131,8 +141,8 @@ public class ScopedSessionProvider implements SessionProvider, Serializable {
        }
 
        public void releaseSession(Session session) {
-               if (log.isDebugEnabled())
-                       log.debug(getHttpSessionId() + " Releasing JCR session " + session);
+               if (log.isTraceEnabled())
+                       log.trace(getHttpSessionId() + " Releasing JCR session " + session);
        }
 
        protected void logout() {
@@ -149,9 +159,11 @@ public class ScopedSessionProvider implements SessionProvider, Serializable {
 
        public void destroy() {
                logout();
-               if (log.isDebugEnabled())
-                       log.debug(getHttpSessionId()
-                                       + " Cleaned up provider for web session ");
+               if (getHttpSessionId() != null)
+                       if (log.isDebugEnabled())
+                               log.debug(getHttpSessionId()
+                                               + " Cleaned up provider for web session ");
                httpSession = null;
        }
-}
\ No newline at end of file
+
+}
index 4f0649b2f5a3be7796f7efec9ea8183c2b58bde0..917ad94f718981b972bd5692a701ab1f62df83f3 100644 (file)
@@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.jcr.RepositoryRegister;
 import org.springframework.beans.BeansException;
@@ -77,13 +78,15 @@ public abstract class MultipleRepositoryHandlerMapping implements
                if ((tokens.size() == 1 || tokens.size() == 2)
                                && request.getMethod().equals(MKCOL))
                        return null;
-               String repositoryName = extractRepositoryName(tokens);
-               String pathPrefix = request.getServletPath() + '/' + repositoryName;
+               String repositoryAlias = extractRepositoryName(tokens);
+               request.setAttribute(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS,
+                               repositoryAlias);
+               String pathPrefix = request.getServletPath() + '/' + repositoryAlias;
                String beanName = pathPrefix;
 
                if (!applicationContext.containsBean(beanName)) {
                        Repository repository = repositoryRegister.getRepositories().get(
-                                       repositoryName);
+                                       repositoryAlias);
                        HttpServlet servlet = createServlet(repository, pathPrefix);
                        applicationContext.getBeanFactory().registerSingleton(beanName,
                                        servlet);