From 3ff30fc87c733541ee27246e7cc3fecc52efde0c Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 3 Nov 2012 20:37:16 +0000 Subject: [PATCH] Improve remoting git-svn-id: https://svn.argeo.org/commons/trunk@5690 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../WEB-INF/applicationContext.xml | 18 +-- .../WEB-INF/remoting-servlet.xml | 2 +- .../WEB-INF/web.xml | 8 +- .../WEB-INF/webdav-servlet.xml | 2 +- .../remote/OpenInViewSessionProvider.java | 69 ++++++++++ .../remote/ScopedSessionProvider.java | 127 ++++++++++++++++++ .../remote/SimpleSessionProvider.java | 54 +++++--- .../src/main/java/org/argeo/jcr/JcrUtils.java | 14 +- .../argeo/jcr/security/JcrAuthorizations.java | 51 ++++++- 9 files changed, 309 insertions(+), 36 deletions(-) create mode 100644 server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java create mode 100644 server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java diff --git a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/applicationContext.xml b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/applicationContext.xml index d8b5a33dc..f3335b8ab 100644 --- a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/applicationContext.xml +++ b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/applicationContext.xml @@ -16,15 +16,17 @@ - - - + + + + - - - + + + + diff --git a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/remoting-servlet.xml b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/remoting-servlet.xml index d07eecede..e0a13f318 100644 --- a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/remoting-servlet.xml +++ b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/remoting-servlet.xml @@ -16,7 +16,7 @@ - + \ No newline at end of file diff --git a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/web.xml b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/web.xml index a017ce992..3f6db648a 100644 --- a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/web.xml +++ b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/web.xml @@ -5,6 +5,12 @@ Argeo Jackrabbit Webapp + + + 5 + + contextConfigLocation @@ -70,7 +76,7 @@ /public/* - + springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy diff --git a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/webdav-servlet.xml b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/webdav-servlet.xml index bddeb52a9..14b6dd1d5 100644 --- a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/webdav-servlet.xml +++ b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/webdav-servlet.xml @@ -15,7 +15,7 @@ - + \ No newline at end of file diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java new file mode 100644 index 000000000..eb83f6d2e --- /dev/null +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007-2012 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit.remote; + +import java.io.Serializable; + +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 org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.server.SessionProvider; +import org.argeo.jcr.JcrUtils; + +/** + * Implements an open session in view patter: a new JCR session is created for + * each request + */ +public class OpenInViewSessionProvider implements SessionProvider, Serializable { + private static final long serialVersionUID = 2270957712453841368L; + + private final static Log log = LogFactory + .getLog(OpenInViewSessionProvider.class); + + public Session getSession(HttpServletRequest request, Repository rep, + String workspace) throws LoginException, ServletException, + RepositoryException { + return login(request, rep, workspace); + } + + protected Session login(HttpServletRequest request, Repository repository, + String workspace) throws RepositoryException { + if (log.isDebugEnabled()) + log.debug("Login to workspace " + + (workspace == null ? "" : workspace) + + " in web session " + request.getSession().getId()); + return repository.login(workspace); + } + + public void releaseSession(Session session) { + JcrUtils.logoutQuietly(session); + if (log.isDebugEnabled()) + log.debug("Logged out remote JCR session " + session); + } + + public void init() { + } + + public void destroy() { + } + +} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java new file mode 100644 index 000000000..7b283a363 --- /dev/null +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2007-2012 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit.remote; + +import java.io.Serializable; +import java.util.List; + +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; +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; + +/** + * Session provider assuming a single workspace and a short life cycle, + * typically a Spring bean of scope (web) 'session'. + */ +public class ScopedSessionProvider implements SessionProvider, Serializable { + private static final long serialVersionUID = 6589775984177317058L; + private final static Log log = LogFactory + .getLog(ScopedSessionProvider.class); + + private transient HttpSession httpSession = null; + private transient Session jcrSession = null; + + private transient String currentRepositoryName = null; + private transient String currentWorkspaceName = null; + + public Session getSession(HttpServletRequest request, Repository rep, + String workspace) throws LoginException, ServletException, + RepositoryException { + + // HTTP session + if (httpSession != null + && !httpSession.getId().equals(request.getSession().getId())) + throw new ArgeoException( + "Only session scope is supported in this mode"); + if (httpSession == null) + httpSession = request.getSession(); + + if (currentWorkspaceName == null) + currentWorkspaceName = workspace; + + // TODO optimize + String pathInfo = request.getPathInfo(); + List tokens = JcrUtils.tokenize(pathInfo); + if (currentRepositoryName == null) + currentRepositoryName = tokens.get(0); + else if (!currentRepositoryName.equals(tokens.get(0)) + || !currentWorkspaceName.equals(workspace)) { + JcrUtils.logoutQuietly(jcrSession); + jcrSession = null; + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + + " Changed repository or workspace, logging out of " + + currentWorkspaceName); + } + + // JCR session + if (jcrSession == null) + try { + jcrSession = login(rep, workspace); + currentRepositoryName = tokens.get(0); + // do not use workspace variable which may be null + currentWorkspaceName = jcrSession.getWorkspace().getName(); + return jcrSession; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot open session to workspace " + + workspace, e); + } + else + return jcrSession; + } + + protected Session login(Repository repository, String workspace) + throws RepositoryException { + Session session = repository.login(workspace); + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + " User '" + session.getUserID() + + "' logged in workspace '" + + session.getWorkspace().getName() + "' of repository '" + + currentRepositoryName + "'"); + return session; + } + + public void releaseSession(Session session) { + if (log.isTraceEnabled()) + log.trace(getHttpSessionId() + " Releasing JCR session " + session); + } + + protected final String getHttpSessionId() { + return httpSession != null ? httpSession.getId() : ""; + } + + public void init() { + } + + public void destroy() { + JcrUtils.logoutQuietly(jcrSession); + jcrSession = null; + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + + " Cleaned up provider for web session "); + httpSession = null; + } +} \ No newline at end of file diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java index 11edfe947..21c9941bd 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java @@ -47,7 +47,11 @@ import org.argeo.jcr.UserJcrUtils; /** * Implements an open session in view patter: a new JCR session is created for * each request + * + * @deprecated use {@link ScopedSessionProvider} or + * {@link OpenInViewSessionProvider} */ +@Deprecated public class SimpleSessionProvider implements SessionProvider, Serializable { private static final long serialVersionUID = 2270957712453841368L; @@ -60,17 +64,25 @@ public class SimpleSessionProvider implements SessionProvider, Serializable { private String defaultWorkspace = "default"; + private String webSessionId = null; + public Session getSession(HttpServletRequest request, Repository rep, String workspace) throws LoginException, ServletException, RepositoryException { if (openSessionInView) { - JackrabbitSession session = (JackrabbitSession) rep - .login(workspace); + JackrabbitSession session = (JackrabbitSession) login(request, rep, + workspace); if (session.getWorkspace().getName().equals(defaultWorkspace)) writeRemoteRoles(session); return session; } else { + if (webSessionId != null + && !webSessionId.equals(request.getSession().getId())) + throw new ArgeoException( + "Only session scope is supported in this mode"); + webSessionId = request.getSession().getId(); + // since sessions is transient it can't be restored from the session if (sessions == null) sessions = Collections @@ -78,8 +90,11 @@ public class SimpleSessionProvider implements SessionProvider, Serializable { if (!sessions.containsKey(workspace)) { try { - JackrabbitSession session = (JackrabbitSession) rep.login( - null, workspace); + // JackrabbitSession session = (JackrabbitSession) + // rep.login( + // null, workspace); + JackrabbitSession session = (JackrabbitSession) login( + request, rep, workspace); if (session.getWorkspace().getName() .equals(defaultWorkspace)) writeRemoteRoles(session); @@ -95,7 +110,7 @@ public class SimpleSessionProvider implements SessionProvider, Serializable { Session session = sessions.get(workspace); if (!session.isLive()) { sessions.remove(workspace); - session = rep.login(null, workspace); + session = login(request, rep, workspace); sessions.put(workspace, session); } return session; @@ -103,6 +118,15 @@ public class SimpleSessionProvider implements SessionProvider, Serializable { } } + protected Session login(HttpServletRequest request, Repository repository, + String workspace) throws RepositoryException { + if (log.isDebugEnabled()) + log.debug("Login to workspace " + + (workspace == null ? "" : workspace) + + " in web session " + request.getSession().getId()); + return repository.login(workspace); + } + protected void writeRemoteRoles(JackrabbitSession session) throws RepositoryException { // FIXME better deal w/ non node repo @@ -153,26 +177,26 @@ public class SimpleSessionProvider implements SessionProvider, Serializable { if (log.isTraceEnabled()) log.trace("Releasing JCR session " + session); if (openSessionInView) { - if (session.isLive()) { - session.logout(); - if (log.isTraceEnabled()) - log.trace("Logged out remote JCR session " + session); - } + JcrUtils.logoutQuietly(session); + if (log.isDebugEnabled()) + log.debug("Logged out remote JCR session " + session); } } public void init() { + if (log.isDebugEnabled()) + log.debug("Init session provider for web session " + webSessionId); } public void destroy() { + if (log.isDebugEnabled()) + log.debug("Destroy session provider for web session " + + webSessionId); + if (sessions != null) for (String workspace : sessions.keySet()) { Session session = sessions.get(workspace); - if (session.isLive()) { - session.logout(); - if (log.isDebugEnabled()) - log.debug("Logged out remote JCR session " + session); - } + JcrUtils.logoutQuietly(session); } } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index 9f3d761ca..0a2377b61 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -1252,13 +1252,13 @@ public class JcrUtils implements ArgeoJcrConstants { acl.addAccessControlEntry(principal, privs.toArray(new Privilege[privs.size()])); acm.setPolicy(path, acl); - if (log.isDebugEnabled()) { - StringBuffer privBuf = new StringBuffer(); - for (Privilege priv : privs) - privBuf.append(priv.getName()); - log.debug("Added privileges " + privBuf + " to " + principal - + " on " + path); - } +// if (log.isTraceEnabled()) { +// StringBuffer privBuf = new StringBuffer(); +// for (Privilege priv : privs) +// privBuf.append(priv.getName()); +// log.trace("Added privileges " + privBuf + " to " + principal +// + " on " + path); +// } session.refresh(true); session.save(); } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/JcrAuthorizations.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/JcrAuthorizations.java index eb9da5fea..14ac2bc34 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/JcrAuthorizations.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/JcrAuthorizations.java @@ -40,6 +40,8 @@ public class JcrAuthorizations implements Runnable { private Repository repository; private String workspace = null; + private String securityWorkspace = "security"; + /** * key := privilege1,privilege2/path/to/node
* value := group1,group2,user1 @@ -47,6 +49,37 @@ public class JcrAuthorizations implements Runnable { private Map principalPrivileges = new HashMap(); public void run() { + String currentWorkspace = workspace; + Session session = null; + try { + if (workspace != null && workspace.equals("*")) { + session = repository.login(); + String[] workspaces = session.getWorkspace() + .getAccessibleWorkspaceNames(); + JcrUtils.logoutQuietly(session); + for (String wksp : workspaces) { + currentWorkspace = wksp; + if (currentWorkspace.equals(securityWorkspace)) + continue; + session = repository.login(currentWorkspace); + initAuthorizations(session); + JcrUtils.logoutQuietly(session); + } + } else { + session = repository.login(workspace); + initAuthorizations(session); + } + } catch (Exception e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException( + "Cannot set authorizations " + principalPrivileges + + " on workspace " + currentWorkspace, e); + } finally { + JcrUtils.logoutQuietly(session); + } + } + + protected void processWorkspace(String workspace) { Session session = null; try { session = repository.login(workspace); @@ -94,12 +127,20 @@ public class JcrAuthorizations implements Runnable { Principal principal = getOrCreatePrincipal(session, principalName); JcrUtils.addPrivileges(session, path, principal, privs); + if (log.isDebugEnabled()) { + StringBuffer privBuf = new StringBuffer(); + for (Privilege priv : privs) + privBuf.append(priv.getName()); + log.debug("Added privileges " + privBuf + " to " + + principal.getName() + " on " + path + " in '" + + session.getWorkspace().getName() + "'"); + } } } - if (log.isDebugEnabled()) - log.debug("All authorizations applied on workspace " - + session.getWorkspace().getName()); + // if (log.isDebugEnabled()) + // log.debug("JCR authorizations applied on '" + // + session.getWorkspace().getName() + "'"); } /** @@ -176,4 +217,8 @@ public class JcrAuthorizations implements Runnable { this.workspace = workspace; } + public void setSecurityWorkspace(String securityWorkspace) { + this.securityWorkspace = securityWorkspace; + } + } -- 2.30.2