</dependency>
<!-- Default JCR repositories configurations -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.node.repo.jackrabbit</artifactId>
- <version>2.1.13-SNAPSHOT</version>
- </dependency>
+ <!-- <dependency> -->
+ <!-- <groupId>org.argeo.commons</groupId> -->
+ <!-- <artifactId>org.argeo.node.repo.jackrabbit</artifactId> -->
+ <!-- <version>2.1.13-SNAPSHOT</version> -->
+ <!-- </dependency> -->
<!-- OSGi Boot (and Equinox) -->
<dependency>
</dependency>
<!-- Security (Jackrabbit) -->
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.security.dao.jackrabbit</artifactId>
- <version>2.1.13-SNAPSHOT</version>
- </dependency>
+ <!-- <dependency> -->
+ <!-- <groupId>org.argeo.commons</groupId> -->
+ <!-- <artifactId>org.argeo.security.dao.jackrabbit</artifactId> -->
+ <!-- <version>2.1.13-SNAPSHOT</version> -->
+ <!-- </dependency> -->
</dependencies>
<profiles>
<profile>
--- /dev/null
+package org.argeo.cms.internal.kernel;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/** Abstract base class for http filters. */
+abstract class HttpFilter implements Filter {
+ protected abstract void doFilter(HttpSession httpSession,
+ HttpServletRequest request, HttpServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException;
+
+ @Override
+ public void doFilter(ServletRequest servletRequest,
+ ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ doFilter(request.getSession(), request,
+ (HttpServletResponse) servletResponse, filterChain);
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ @Override
+ public void init(FilterConfig arg0) throws ServletException {
+ }
+
+}
private final BundleContext bundleContext;
private JackrabbitNode node;
- private OsgiJackrabbitRepositoryFactory repositoryFactory;
+ private RepositoryFactory repositoryFactory;
private NodeSecurity nodeSecurity;
- private NodeHttpFilter httpFilter;
+ private NodeHttp nodeHttp;
Kernel(BundleContext bundleContext) {
this.bundleContext = bundleContext;
node = new JackrabbitNode(bundleContext);
repositoryFactory = new OsgiJackrabbitRepositoryFactory();
nodeSecurity = new NodeSecurity(bundleContext, node);
- httpFilter = new NodeHttpFilter(bundleContext, nodeSecurity);
+ nodeHttp = new NodeHttp(bundleContext, node, nodeSecurity);
// Publish services to OSGi register
nodeSecurity.publish();
node.publish();
bundleContext.registerService(RepositoryFactory.class,
repositoryFactory, null);
- httpFilter.publish();
+ nodeHttp.publish();
} catch (Exception e) {
log.error("Cannot initialize Argeo CMS", e);
throw new ArgeoException("Cannot initialize", e);
void destroy() {
long begin = System.currentTimeMillis();
- httpFilter = null;
+ nodeHttp = null;
nodeSecurity.destroy();
node.destroy();
final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd",
"/org/argeo/cms/cms.cnd" };
-
+
// Security
final static String DEFAULT_SECURITY_KEY = "argeo";
+ final static String ANONYMOUS_USER = "anonymous";
+ final static String ADMIN_USER = "root";
+
+ // Roles
+ final static String ROLE_USER = "ROLE_USER";
+ final static String ROLE_ADMIN = "ROLE_ADMIN";
+ final static String ROLE_ANONYMOUS = "ROLE_ANONYMOUS";
+
+ // DAV
+ final static String WEBDAV_CONFIG = "/org/argeo/cms/internal/kernel/webdav-config.xml";
+ final static String PATH_WEBDAV_PUBLIC = "/data/public";
+ final static String PATH_WEBDAV_PRIVATE = "/data/files";
+ final static String PATH_REMOTING_PUBLIC = "/data/pub";
+ final static String PATH_REMOTING_PRIVATE = "/data/jcr";
+ final static String PATH_WORKBENCH_PUBLIC = "/ui/public";
}
import java.io.File;
import java.io.IOException;
+import java.util.Collections;
import java.util.Dictionary;
+import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.List;
import java.util.Properties;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
import org.argeo.cms.CmsException;
import org.osgi.framework.BundleContext;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
-class KernelUtils {
+class KernelUtils implements KernelConstants {
final static String OSGI_INSTANCE_AREA = "osgi.instance.area";
static Dictionary<String, ?> asDictionary(Properties props) {
return hashtable;
}
- static Dictionary<String, ?> asDictionary(ClassLoader cl,
- String resource) {
+ static Dictionary<String, ?> asDictionary(ClassLoader cl, String resource) {
Properties props = new Properties();
try {
props.load(cl.getResourceAsStream(resource));
.substring("file:".length())).getAbsoluteFile();
}
+ // Security
+ static void anonymousLogin(AuthenticationManager authenticationManager) {
+ try {
+ List<SimpleGrantedAuthority> anonAuthorities = Collections
+ .singletonList(new SimpleGrantedAuthority(ROLE_ANONYMOUS));
+ UserDetails anonUser = new User(ANONYMOUS_USER, "", true, true,
+ true, true, anonAuthorities);
+ AnonymousAuthenticationToken anonToken = new AnonymousAuthenticationToken(
+ DEFAULT_SECURITY_KEY, anonUser, anonAuthorities);
+ Authentication authentication = authenticationManager
+ .authenticate(anonToken);
+ SecurityContextHolder.getContext()
+ .setAuthentication(authentication);
+ } catch (Exception e) {
+ throw new CmsException("Cannot authenticate", e);
+ }
+ }
+
+ // HTTP
+ static void logRequestHeaders(Log log, HttpServletRequest request) {
+ if (!log.isDebugEnabled())
+ return;
+ for (Enumeration<String> headerNames = request.getHeaderNames(); headerNames
+ .hasMoreElements();) {
+ String headerName = headerNames.nextElement();
+ Object headerValue = request.getHeader(headerName);
+ log.debug(headerName + ": " + headerValue);
+ }
+ }
+
private KernelUtils() {
}
--- /dev/null
+package org.argeo.cms.internal.kernel;
+
+import java.io.IOException;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.kernel.NodeHttp.AnonymousFilter;
+import org.argeo.cms.internal.kernel.NodeHttp.DavFilter;
+import org.argeo.jackrabbit.servlet.OpenInViewSessionProvider;
+import org.argeo.jackrabbit.servlet.RemotingServlet;
+import org.argeo.jackrabbit.servlet.WebdavServlet;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.eclipse.equinox.http.servlet.ExtendedHttpService;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.http.NamespaceException;
+import org.osgi.util.tracker.ServiceTracker;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * Intercepts and enriches http access, mainly focusing on security and
+ * transactionality.
+ */
+class NodeHttp implements KernelConstants, ArgeoJcrConstants {
+ private final static Log log = LogFactory.getLog(NodeHttp.class);
+
+ private final static String ATTR_AUTH = "auth";
+ private final static String HEADER_AUTHORIZATION = "Authorization";
+ private final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
+
+ static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
+
+ private final AuthenticationManager authenticationManager;
+ private final BundleContext bundleContext;
+ private ExtendedHttpService httpService;
+
+ // FIXME Make it more unique
+ private String httpAuthRealm = "Argeo";
+
+ // Filters
+ private final RootFilter rootFilter;
+
+ // remoting
+ private OpenInViewSessionProvider sessionProvider;
+ private WebdavServlet publicWebdavServlet;
+ private WebdavServlet privateWebdavServlet;
+ private RemotingServlet publicRemotingServlet;
+ private RemotingServlet privateRemotingServlet;
+
+ NodeHttp(BundleContext bundleContext, JackrabbitNode node,
+ NodeSecurity authenticationManager) {
+ this.bundleContext = bundleContext;
+ this.authenticationManager = authenticationManager;
+
+ // Equinox dependency
+ ServiceTracker<ExtendedHttpService, ExtendedHttpService> st = new ServiceTracker<ExtendedHttpService, ExtendedHttpService>(
+ bundleContext, ExtendedHttpService.class, null);
+ st.open();
+ try {
+ httpService = st.waitForService(1000);
+ } catch (InterruptedException e) {
+ httpService = null;
+ }
+
+ if (httpService == null)
+ throw new CmsException("Could not find "
+ + ExtendedHttpService.class + " service.");
+
+ // Filters
+ rootFilter = new RootFilter();
+
+ // DAV
+ sessionProvider = new OpenInViewSessionProvider();
+ publicWebdavServlet = new WebdavServlet(node, sessionProvider);
+ privateWebdavServlet = new WebdavServlet(node, sessionProvider);
+ publicRemotingServlet = new RemotingServlet(node, sessionProvider);
+ privateRemotingServlet = new RemotingServlet(node, sessionProvider);
+ }
+
+ void publish() {
+ try {
+ registerWebdavServlet(PATH_WEBDAV_PUBLIC, ALIAS_NODE, true,
+ publicWebdavServlet);
+ registerWebdavServlet(PATH_WEBDAV_PRIVATE, ALIAS_NODE, false,
+ privateWebdavServlet);
+ registerRemotingServlet(PATH_REMOTING_PUBLIC, ALIAS_NODE, true,
+ publicRemotingServlet);
+ registerRemotingServlet(PATH_REMOTING_PRIVATE, ALIAS_NODE, false,
+ privateRemotingServlet);
+
+ // httpService.registerFilter("/", rootFilter, null, null);
+ } catch (Exception e) {
+ throw new CmsException("Cannot publish HTTP services to OSGi", e);
+ }
+ }
+
+ private void registerWebdavServlet(String pathPrefix, String alias,
+ Boolean anonymous, WebdavServlet webdavServlet)
+ throws NamespaceException, ServletException {
+ String path = pathPrefix + "/" + alias;
+ Properties initParameters = new Properties();
+ initParameters.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG,
+ KernelConstants.WEBDAV_CONFIG);
+ initParameters.setProperty(
+ WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
+ httpService.registerFilter(path, anonymous ? new AnonymousFilter()
+ : new DavFilter(), null, null);
+ // Cast to servlet because of a weird behaviour in Eclipse
+ httpService.registerServlet(path, (Servlet) webdavServlet,
+ initParameters, null);
+ }
+
+ private void registerRemotingServlet(String pathPrefix, String alias,
+ Boolean anonymous, RemotingServlet remotingServlet)
+ throws NamespaceException, ServletException {
+ String path = pathPrefix + "/" + alias;
+ Properties initParameters = new Properties();
+ initParameters.setProperty(
+ RemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
+
+ // Looks like a bug in Jackrabbit remoting init
+ initParameters.setProperty(RemotingServlet.INIT_PARAM_HOME,
+ KernelUtils.getOsgiInstanceDir(bundleContext)
+ + "/tmp/jackrabbit");
+ initParameters.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY,
+ "remoting");
+ // Cast to servlet because of a weird behaviour in Eclipse
+ httpService.registerFilter(path, anonymous ? new AnonymousFilter()
+ : new DavFilter(), null, null);
+ httpService.registerServlet(path, (Servlet) remotingServlet,
+ initParameters, null);
+ }
+
+ private Boolean isSessionAuthenticated(HttpSession httpSession) {
+ SecurityContext contextFromSession = (SecurityContext) httpSession
+ .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
+ return contextFromSession != null;
+ }
+
+ private void requestBasicAuth(HttpSession httpSession,
+ HttpServletResponse response) {
+ response.setStatus(401);
+ response.setHeader(HEADER_WWW_AUTHENTICATE, "basic realm=\""
+ + httpAuthRealm + "\"");
+ httpSession.setAttribute(ATTR_AUTH, Boolean.TRUE);
+ }
+
+ private UsernamePasswordAuthenticationToken basicAuth(String authHeader) {
+ if (authHeader != null) {
+ StringTokenizer st = new StringTokenizer(authHeader);
+ if (st.hasMoreTokens()) {
+ String basic = st.nextToken();
+ if (basic.equalsIgnoreCase("Basic")) {
+ try {
+ String credentials = new String(Base64.decodeBase64(st
+ .nextToken()), "UTF-8");
+ log.debug("Credentials: " + credentials);
+ int p = credentials.indexOf(":");
+ if (p != -1) {
+ String login = credentials.substring(0, p).trim();
+ String password = credentials.substring(p + 1)
+ .trim();
+
+ return new UsernamePasswordAuthenticationToken(
+ login, password);
+ } else {
+ throw new CmsException(
+ "Invalid authentication token");
+ }
+ } catch (Exception e) {
+ throw new CmsException(
+ "Couldn't retrieve authentication", e);
+ }
+ }
+ }
+ }
+ throw new CmsException("Couldn't retrieve authentication");
+ }
+
+ /** Intercepts all requests. Authenticates. */
+ class RootFilter extends HttpFilter {
+
+ @Override
+ public void doFilter(HttpSession httpSession,
+ HttpServletRequest request, HttpServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+
+ // Authenticate from session
+ if (isSessionAuthenticated(httpSession)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // TODO Kerberos
+
+ // TODO Certificate
+
+ // Process basic auth
+ String basicAuth = request.getHeader(HEADER_AUTHORIZATION);
+ if (basicAuth != null) {
+ UsernamePasswordAuthenticationToken token = basicAuth(basicAuth);
+ Authentication auth = authenticationManager.authenticate(token);
+ SecurityContextHolder.getContext().setAuthentication(auth);
+ httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
+ SecurityContextHolder.getContext());
+ httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE);
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ Boolean doBasicAuth = true;
+ if (doBasicAuth) {
+ requestBasicAuth(httpSession, response);
+ // skip filter chain
+ return;
+ }
+
+ // TODO Login page
+
+ // Anonymous
+ KernelUtils.anonymousLogin(authenticationManager);
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ /** Intercepts all requests. Authenticates. */
+ class AnonymousFilter extends HttpFilter {
+ @Override
+ public void doFilter(HttpSession httpSession,
+ HttpServletRequest request, HttpServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+
+ // Authenticate from session
+ if (isSessionAuthenticated(httpSession)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ KernelUtils.anonymousLogin(authenticationManager);
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ /** Intercepts all requests. Authenticates. */
+ class DavFilter extends HttpFilter {
+
+ @Override
+ public void doFilter(HttpSession httpSession,
+ HttpServletRequest request, HttpServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+
+ // Authenticate from session
+ if (isSessionAuthenticated(httpSession)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // Process basic auth
+ String basicAuth = request.getHeader(HEADER_AUTHORIZATION);
+ if (basicAuth != null) {
+ UsernamePasswordAuthenticationToken token = basicAuth(basicAuth);
+ Authentication auth = authenticationManager.authenticate(token);
+ SecurityContextHolder.getContext().setAuthentication(auth);
+ httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
+ SecurityContextHolder.getContext());
+ httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE);
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ requestBasicAuth(httpSession, response);
+ }
+ }
+
+}
+++ /dev/null
-package org.argeo.cms.internal.kernel;
-
-import java.io.IOException;
-import java.util.StringTokenizer;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.eclipse.equinox.http.servlet.ExtendedHttpService;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.http.HttpContext;
-import org.osgi.util.tracker.ServiceTracker;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
-
-class NodeHttpFilter implements Filter {
- private final static Log log = LogFactory.getLog(NodeHttpFilter.class);
-
- private final static String ATTR_AUTH = "auth";
- private final static String HEADER_AUTHORIZATION = "Authorization";
-
- static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
-
- private ExtendedHttpService httpService;
- private final AuthenticationManager authenticationManager;
-
- private Boolean basicAuthEnabled = false;
-
- NodeHttpFilter(BundleContext bundleContext,
- AuthenticationManager authenticationManager) {
- this.authenticationManager = authenticationManager;
-
- // Equinox dependency
- ServiceTracker<ExtendedHttpService, ExtendedHttpService> st = new ServiceTracker<ExtendedHttpService, ExtendedHttpService>(
- bundleContext, ExtendedHttpService.class, null);
- st.open();
- try {
- httpService = st.waitForService(1000);
- } catch (InterruptedException e) {
- httpService = null;
- }
-
- if (httpService == null)
- throw new CmsException("Could not find "
- + ExtendedHttpService.class + " service.");
- }
-
- void publish() {
- try {
- HttpContext httpContext = httpService.createDefaultHttpContext();
- httpService.registerFilter("/", this, null, httpContext);
- } catch (Exception e) {
- throw new CmsException("Cannot register HTTP filter", e);
- }
- }
-
- @Override
- public void doFilter(ServletRequest servletRequest,
- ServletResponse servletResponse, FilterChain filterChain)
- throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) servletRequest;
- HttpSession httpSession = request.getSession();
-
- // Authenticate from session
- SecurityContext contextFromSession = (SecurityContext) httpSession
- .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
- if (contextFromSession != null) {
- filterChain.doFilter(servletRequest, servletResponse);
- return;
- }
-
- if (basicAuthEnabled) {
- // Basic auth
- String basicAuth = request.getHeader(HEADER_AUTHORIZATION);
-
- // for (Enumeration<String> headerNames = request.getHeaderNames();
- // headerNames
- // .hasMoreElements();) {
- // String headerName = headerNames.nextElement();
- // Object headerValue = request.getHeader(headerName);
- // log.debug(headerName + ": " + headerValue);
- // }
-
- if (basicAuth == null) {
- HttpServletResponse response = (HttpServletResponse) servletResponse;
- response.setStatus(401);
- response.setHeader("WWW-Authenticate", "basic realm=\"Auth ("
- + httpSession.getCreationTime() + ")\"");
- httpSession.setAttribute(ATTR_AUTH, Boolean.TRUE);
- return;
- } else {
- UsernamePasswordAuthenticationToken token = basicAuth(basicAuth);
- Authentication auth = authenticationManager.authenticate(token);
- SecurityContextHolder.getContext().setAuthentication(auth);
- httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
- SecurityContextHolder.getContext());
- httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE);
- }
- }
- // Assume authentication has been done and continue
- filterChain.doFilter(servletRequest, servletResponse);
- }
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
-
- @Override
- public void destroy() {
- }
-
- private UsernamePasswordAuthenticationToken basicAuth(String authHeader) {
- if (authHeader != null) {
- StringTokenizer st = new StringTokenizer(authHeader);
- if (st.hasMoreTokens()) {
- String basic = st.nextToken();
- if (basic.equalsIgnoreCase("Basic")) {
- try {
- String credentials = new String(Base64.decodeBase64(st
- .nextToken()), "UTF-8");
- log.debug("Credentials: " + credentials);
- int p = credentials.indexOf(":");
- if (p != -1) {
- String login = credentials.substring(0, p).trim();
- String password = credentials.substring(p + 1)
- .trim();
-
- return new UsernamePasswordAuthenticationToken(
- login, password);
- } else {
- throw new CmsException(
- "Invalid authentication token");
- }
- } catch (Exception e) {
- throw new CmsException(
- "Couldn't retrieve authentication", e);
- }
- }
- }
- }
- throw new CmsException("Couldn't retrieve authentication");
- }
-
-}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<!--
+<!DOCTYPE config [
+ <!ELEMENT config (iomanager , propertymanager, (collection | noncollection)? , filter?, mimetypeproperties?) >
+
+ <!ELEMENT iomanager (class, iohandler*) >
+ <!ELEMENT iohandler (class) >
+
+ <!ELEMENT propertymanager (class, propertyhandler*) >
+ <!ELEMENT propertyhandler (class) >
+
+ <!ELEMENT collection (nodetypes) >
+ <!ELEMENT noncollection (nodetypes) >
+
+ <!ELEMENT filter (class, namespaces?, nodetypes?) >
+
+ <!ELEMENT class >
+ <!ATTLIST class
+ name CDATA #REQUIRED
+ >
+ <!ELEMENT namespaces (prefix | uri)* >
+ <!ELEMENT prefix (CDATA) >
+ <!ELEMENT uri (CDATA) >
+
+ <!ELEMENT nodetypes (nodetype)* >
+ <!ELEMENT nodetype (CDATA) >
+
+ <!ELEMENT mimetypeproperties (mimemapping*, defaultmimetype) >
+
+ <!ELEMENT mimemapping >
+ <!ATTLIST mimemapping
+ extension CDATA #REQUIRED
+ mimetype CDATA #REQUIRED
+ >
+
+ <!ELEMENT defaultmimetype (CDATA) >
+]>
+-->
+
+<config>
+ <!--
+ Defines the IOManager implementation that is responsible for passing
+ import/export request to the individual IO-handlers.
+ -->
+ <iomanager>
+ <!-- class element defines the manager to be used. The specified class
+ must implement the IOManager interface.
+ Note, that the handlers are being added and called in the order
+ they appear in the configuration.
+ -->
+ <class name="org.apache.jackrabbit.server.io.IOManagerImpl" />
+ <iohandler>
+ <class name="org.apache.jackrabbit.server.io.VersionHandler" />
+ </iohandler>
+ <iohandler>
+ <class name="org.apache.jackrabbit.server.io.VersionHistoryHandler" />
+ </iohandler>
+<!-- <iohandler> -->
+<!-- <class name="org.apache.jackrabbit.server.io.ZipHandler" /> -->
+<!-- </iohandler> -->
+<!-- <iohandler> -->
+<!-- <class name="org.apache.jackrabbit.server.io.XmlHandler" /> -->
+<!-- </iohandler> -->
+ <iohandler>
+ <class name="org.apache.jackrabbit.server.io.DirListingExportHandler" />
+ </iohandler>
+ <iohandler>
+ <class name="org.apache.jackrabbit.server.io.DefaultHandler" />
+ </iohandler>
+ </iomanager>
+ <!--
+ Example config for iomanager that populates its list of handlers with
+ default values. Therefore the 'iohandler' elements are omited.
+ -->
+ <!--
+ <iomanager>
+ <class name="org.apache.jackrabbit.server.io.DefaultIOManager" />
+ </iomanager>
+ -->
+ <!--
+ Defines the PropertyManager implementation that is responsible for export
+ and import of resource properties.
+ -->
+ <propertymanager>
+ <!-- class element defines the manager to be used. The specified class
+ must implement the PropertyManager interface.
+ Note, that the handlers are being added and called in the order
+ they appear in the configuration.
+ -->
+ <class name="org.apache.jackrabbit.server.io.PropertyManagerImpl" />
+ <propertyhandler>
+ <class name="org.apache.jackrabbit.server.io.VersionHandler" />
+ </propertyhandler>
+ <propertyhandler>
+ <class name="org.apache.jackrabbit.server.io.VersionHistoryHandler" />
+ </propertyhandler>
+<!-- <propertyhandler> -->
+<!-- <class name="org.apache.jackrabbit.server.io.ZipHandler" /> -->
+<!-- </propertyhandler> -->
+<!-- <propertyhandler> -->
+<!-- <class name="org.apache.jackrabbit.server.io.XmlHandler" /> -->
+<!-- </propertyhandler> -->
+ <propertyhandler>
+ <class name="org.apache.jackrabbit.server.io.DefaultHandler" />
+ </propertyhandler>
+ </propertymanager>
+ <!--
+ Define nodetypes, that should never by displayed as 'collection'
+ -->
+ <noncollection>
+ <nodetypes>
+ <nodetype>nt:file</nodetype>
+ <nodetype>nt:resource</nodetype>
+ </nodetypes>
+ </noncollection>
+ <!--
+ Example: Defines nodetypes, that should always be displayed as 'collection'.
+ -->
+ <!--
+ <collection>
+ <nodetypes>
+ <nodetype>nt:folder</nodetype>
+ <nodetype>rep:root</nodetype>
+ </nodetypes>
+ </collection>
+ -->
+ <!--
+ Filter that allows to prevent certain items from being displayed.
+ Please note, that this has an effect on PROPFIND calls only and does not
+ provide limited access to those items matching any of the filters.
+
+ However specifying a filter may cause problems with PUT or MKCOL if the
+ resource to be created is being filtered out, thus resulting in inconsistent
+ responses (e.g. PUT followed by PROPFIND on parent).
+ -->
+ <filter>
+ <!-- class element defines the resource filter to be used. The specified class
+ must implement the ItemFilter interface -->
+ <class name="org.apache.jackrabbit.webdav.simple.DefaultItemFilter" />
+ <!--
+ Nodetype names to be used to filter child nodes.
+ A child node can be filtered if the declaring nodetype of its definition
+ is one of the nodetype names specified in the nodetypes Element.
+ E.g. defining 'rep:root' as filtered nodetype whould result in jcr:system
+ being hidden but no other child node of the root node, since those
+ are defined by the nodetype nt:unstructered.
+ -->
+ <!--
+ <nodetypes>
+ <nodetype>rep:root</nodetype>
+ </nodetypes>
+ -->
+ <!--
+ Namespace prefixes or uris. Items having a name that matches any of the
+ entries will be filtered.
+ -->
+ <namespaces>
+ <prefix>rep</prefix>
+ <prefix>jcr</prefix>
+ <!--
+ <uri>internal</uri>
+ <uri>http://www.jcp.org/jcr/1.0</uri>
+ -->
+ </namespaces>
+ </filter>
+
+ <!--
+ Optional 'mimetypeproperties' element.
+ It defines additional or replaces existing mappings for the MimeResolver
+ instance created by the ResourceConfig.
+ The default mappings are defined in org.apache.jackrabbit.server.io.mimetypes.properties.
+ If the default mime type defined by MimeResolver is 'application/octet-stream'.
+ -->
+ <!--
+ <mimetypeproperties>
+ <mimemapping extension="rtf" mimetype="application/rtf" />
+ <mimemapping extension="ott" mimetype="application/vnd.oasis.opendocument.text-template" />
+ <defaultmimetype>text/html</defaultmimetype>
+ </mimetypeproperties>
+ -->
+</config>
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.security.jcr.jackrabbit;
+
+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 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.ArgeoJcrConstants;
+import org.argeo.jcr.JcrUtils;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * 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 static final 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;
+ private transient String currentJcrUser = null;
+
+ // private transient String anonymousUserId = "anonymous";
+
+ public Session getSession(HttpServletRequest request, Repository rep,
+ String workspace) throws LoginException, ServletException,
+ RepositoryException {
+
+ Authentication authentication = SecurityContextHolder.getContext()
+ .getAuthentication();
+ if (authentication == null)
+ throw new ArgeoException(
+ "Request not authenticated by Spring Security");
+ String springUser = authentication.getName();
+
+ // HTTP
+ String requestJcrRepository = (String) request
+ .getAttribute(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS);
+
+ // 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();
+
+ // Initializes current values
+ if (currentRepositoryName == null)
+ 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(requestJcrRepository)) {
+ if (log.isDebugEnabled())
+ 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 cached JCR session.");
+ logout();
+ } else if (!currentJcrUser.equals(springUser)) {
+ if (log.isDebugEnabled())
+ log.debug(getHttpSessionId() + " Changed from user '"
+ + currentJcrUser + "' to '" + springUser
+ + "', logging out cached JCR session.");
+ logout();
+ }
+
+ // login if needed
+ if (jcrSession == null)
+ try {
+ Session session = login(rep, workspace);
+ if (!session.getUserID().equals(springUser)) {
+ JcrUtils.logoutQuietly(session);
+ throw new ArgeoException("Spring Security user '"
+ + springUser + "' not in line with JCR user '"
+ + session.getUserID() + "'");
+ }
+ currentRepositoryName = requestJcrRepository;
+ // do not use workspace variable which may be null
+ currentWorkspaceName = session.getWorkspace().getName();
+ currentJcrUser = session.getUserID();
+
+ jcrSession = session;
+ return jcrSession;
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot open session to workspace "
+ + workspace, e);
+ }
+
+ // returns cached session
+ 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 void logout() {
+ JcrUtils.logoutQuietly(jcrSession);
+ jcrSession = null;
+ }
+
+ protected final String getHttpSessionId() {
+ return httpSession != null ? httpSession.getId() : "<null>";
+ }
+
+ public void init() {
+ }
+
+ public void destroy() {
+ logout();
+ if (getHttpSessionId() != null)
+ if (log.isDebugEnabled())
+ log.debug(getHttpSessionId()
+ + " Cleaned up provider for web session ");
+ httpSession = null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.servlet;
+
+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.isTraceEnabled())
+ log.trace("Login to workspace "
+ + (workspace == null ? "<default>" : workspace)
+ + " in web session " + request.getSession().getId());
+ return repository.login(workspace);
+ }
+
+ public void releaseSession(Session session) {
+ JcrUtils.logoutQuietly(session);
+ if (log.isTraceEnabled())
+ log.trace("Logged out remote JCR session " + session);
+ }
+
+ public void init() {
+ }
+
+ public void destroy() {
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.servlet;
+
+import javax.jcr.Repository;
+
+import org.apache.jackrabbit.server.SessionProvider;
+import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
+
+/** Provides remote access to a JCR repository */
+public class RemotingServlet extends JcrRemotingServlet {
+ public final static String INIT_PARAM_RESOURCE_PATH_PREFIX = JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX;
+ public final static String INIT_PARAM_HOME = JcrRemotingServlet.INIT_PARAM_HOME;
+ public final static String INIT_PARAM_TMP_DIRECTORY = JcrRemotingServlet.INIT_PARAM_TMP_DIRECTORY;
+
+ private static final long serialVersionUID = 3131835511468341309L;
+
+ private final Repository repository;
+ private final SessionProvider sessionProvider;
+
+ public RemotingServlet(Repository repository,
+ SessionProvider sessionProvider) {
+ this.repository = repository;
+ this.sessionProvider = sessionProvider;
+ }
+
+ @Override
+ protected Repository getRepository() {
+ return repository;
+ }
+
+ @Override
+ protected SessionProvider getSessionProvider() {
+ return sessionProvider;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.servlet;
+
+import java.io.IOException;
+
+import javax.jcr.Repository;
+import javax.servlet.ServletException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.server.SessionProvider;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavResource;
+import org.apache.jackrabbit.webdav.WebdavRequest;
+import org.apache.jackrabbit.webdav.WebdavResponse;
+import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
+
+/** WebDav servlet whose repository is injected */
+public class WebdavServlet extends SimpleWebdavServlet {
+ public final static String INIT_PARAM_RESOURCE_CONFIG = SimpleWebdavServlet.INIT_PARAM_RESOURCE_CONFIG;
+ public final static String INIT_PARAM_RESOURCE_PATH_PREFIX = SimpleWebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX;
+
+ private static final long serialVersionUID = -369787931175177080L;
+
+ private final static Log log = LogFactory.getLog(WebdavServlet.class);
+
+ private final Repository repository;
+
+ public WebdavServlet(Repository repository, SessionProvider sessionProvider) {
+ this.repository = repository;
+ setSessionProvider(sessionProvider);
+ }
+
+ public Repository getRepository() {
+ return repository;
+ }
+
+ @Override
+ protected boolean execute(WebdavRequest request, WebdavResponse response,
+ int method, DavResource resource) throws ServletException,
+ IOException, DavException {
+ if (log.isTraceEnabled())
+ log.trace(request.getMethod() + "\t" + request.getPathInfo());
+ boolean res = super.execute(request, response, method, resource);
+ return res;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.jcr.proxy;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+
+/** Wraps a proxy via HTTP */
+public class ResourceProxyServlet extends HttpServlet {
+ private static final long serialVersionUID = -8886549549223155801L;
+
+ private final static Log log = LogFactory
+ .getLog(ResourceProxyServlet.class);
+
+ private ResourceProxy proxy;
+
+ private String contentTypeCharset = "UTF-8";
+
+ @Override
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ String path = request.getPathInfo();
+
+ if (log.isTraceEnabled()) {
+ log.trace("path=" + path);
+ log.trace("UserPrincipal = " + request.getUserPrincipal().getName());
+ log.trace("SessionID = " + request.getSession().getId());
+ log.trace("ContextPath = " + request.getContextPath());
+ log.trace("ServletPath = " + request.getServletPath());
+ log.trace("PathInfo = " + request.getPathInfo());
+ log.trace("Method = " + request.getMethod());
+ log.trace("User-Agent = " + request.getHeader("User-Agent"));
+ }
+
+ Node node = null;
+ try {
+ node = proxy.proxy(path);
+ if (node == null)
+ response.sendError(404);
+ else
+ processResponse(node, response);
+ } finally {
+ if (node != null)
+ try {
+ JcrUtils.logoutQuietly(node.getSession());
+ } catch (RepositoryException e) {
+ // silent
+ }
+ }
+
+ }
+
+ /** Retrieve the content of the node. */
+ protected void processResponse(Node node, HttpServletResponse response) {
+ Binary binary = null;
+ InputStream in = null;
+ try {
+ String fileName = node.getName();
+ String ext = FilenameUtils.getExtension(fileName);
+
+ // TODO use a more generic / standard approach
+ // see http://svn.apache.org/viewvc/tomcat/trunk/conf/web.xml
+ String contentType;
+ if ("xml".equals(ext))
+ contentType = "text/xml;charset=" + contentTypeCharset;
+ else if ("jar".equals(ext))
+ contentType = "application/java-archive";
+ else if ("zip".equals(ext))
+ contentType = "application/zip";
+ else if ("gz".equals(ext))
+ contentType = "application/x-gzip";
+ else if ("bz2".equals(ext))
+ contentType = "application/x-bzip2";
+ else if ("tar".equals(ext))
+ contentType = "application/x-tar";
+ else if ("rpm".equals(ext))
+ contentType = "application/x-redhat-package-manager";
+ else
+ contentType = "application/octet-stream";
+ contentType = contentType + ";name=\"" + fileName + "\"";
+ response.setHeader("Content-Disposition", "attachment; filename=\""
+ + fileName + "\"");
+ response.setHeader("Expires", "0");
+ response.setHeader("Cache-Control", "no-cache, must-revalidate");
+ response.setHeader("Pragma", "no-cache");
+
+ response.setContentType(contentType);
+
+ try {
+ binary = node.getNode(Property.JCR_CONTENT)
+ .getProperty(Property.JCR_DATA).getBinary();
+ } catch (PathNotFoundException e) {
+ log.error("Node " + node + " as no data under content");
+ throw e;
+ }
+ in = binary.getStream();
+ IOUtils.copy(in, response.getOutputStream());
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot download " + node, e);
+ } finally {
+ IOUtils.closeQuietly(in);
+ JcrUtils.closeQuietly(binary);
+ }
+ }
+
+ public void setProxy(ResourceProxy resourceProxy) {
+ this.proxy = resourceProxy;
+ }
+
+}
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.argeo.commons</groupId>
<artifactId>argeo-commons</artifactId>
<module>org.argeo.security.auth.ldap</module>
<module>org.argeo.security.dao.ldap</module>
<module>org.argeo.security.dao.cli</module>
- <module>org.argeo.security.dao.jackrabbit</module>
+ <!-- <module>org.argeo.security.dao.jackrabbit</module> -->
<!-- Server -->
<module>org.argeo.server.core</module>
- <module>org.argeo.server.jcr.mvc</module>
+ <!-- <module>org.argeo.server.jcr.mvc</module> -->
<module>org.argeo.server.jackrabbit</module>
<!-- Eclipse -->
<module>org.argeo.eclipse.ui</module>
<module>org.argeo.eclipse.ui.rap</module>
<!-- Argeo Node -->
- <module>org.argeo.node.repo.jackrabbit</module>
+ <!-- <module>org.argeo.node.repo.jackrabbit</module> -->
<module>org.argeo.cms</module>
<!-- Workbench -->
<module>org.argeo.eclipse.ui.workbench</module>