- fixed #19 (again): vault-specific prefix is now handled by the servlet context instead of jackrabbit.

- simplified webdav locator, as workspaces and pathPrefixes are not relevant to jackrabbit any longer
This commit is contained in:
Sebastian Stenzel
2015-01-22 21:48:52 +01:00
parent 9fd271ad7b
commit 432beb2a17
3 changed files with 148 additions and 41 deletions
@@ -20,6 +20,7 @@ import org.cryptomator.webdav.jackrabbit.WebDavServlet;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.LifeCycle;
@@ -39,7 +40,7 @@ public final class WebDavServer {
private static final WebDavServer INSTANCE = new WebDavServer();
private final Server server;
private final ServerConnector localConnector;
private final ServletContextHandler servletContext;
private final ContextHandlerCollection servletCollection;
public static WebDavServer getInstance() {
return INSTANCE;
@@ -51,10 +52,9 @@ public final class WebDavServer {
server = new Server(tp);
localConnector = new ServerConnector(server);
localConnector.setHost(LOCALHOST);
servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContext.setContextPath("/");
servletCollection = new ContextHandlerCollection();
server.setConnectors(new Connector[] {localConnector});
server.setHandler(servletContext);
server.setHandler(servletCollection);
}
public synchronized void start() {
@@ -87,22 +87,22 @@ public final class WebDavServer {
try {
final URI uri = new URI(null, null, localConnector.getHost(), localConnector.getLocalPort(), "/" + UUID.randomUUID().toString(), null, null);
final String pathPrefix = uri.getRawPath() + "/";
final String pathSpec = pathPrefix + "*";
final ServletHolder servlet = getWebDavServletHolder(workDir.toString(), pathPrefix, checkFileIntegrity, cryptor);
servletContext.addServlet(servlet, pathSpec);
final ServletContextHandler servletContext = new ServletContextHandler(servletCollection, uri.getRawPath(), ServletContextHandler.SESSIONS);
final ServletHolder servlet = getWebDavServletHolder(workDir.toString(), checkFileIntegrity, cryptor);
servletContext.addServlet(servlet, "/*");
LOG.info("{} available on http:{}", workDir, uri.getRawSchemeSpecificPart());
return new ServletLifeCycleAdapter(servlet, uri);
servletCollection.mapContexts();
LOG.debug("{} available on http:{}", workDir, uri.getRawSchemeSpecificPart());
return new ServletLifeCycleAdapter(servletContext, uri);
} catch (URISyntaxException e) {
throw new IllegalStateException("Invalid hard-coded URI components.", e);
}
}
private ServletHolder getWebDavServletHolder(final String workDir, final String contextPath, final boolean checkFileIntegrity, final Cryptor cryptor) {
private ServletHolder getWebDavServletHolder(final String workDir, final boolean checkFileIntegrity, final Cryptor cryptor) {
final ServletHolder result = new ServletHolder("Cryptomator-WebDAV-Servlet", new WebDavServlet(cryptor));
result.setInitParameter(WebDavServlet.CFG_FS_ROOT, workDir);
result.setInitParameter(WebDavServlet.CFG_HTTP_ROOT, contextPath);
result.setInitParameter(WebDavServlet.CFG_CHECK_FILE_INTEGRITY, Boolean.toString(checkFileIntegrity));
return result;
}
@@ -15,31 +15,59 @@ import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import org.apache.commons.collections4.BidiMap;
import org.apache.jackrabbit.webdav.AbstractLocatorFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.jackrabbit.webdav.DavLocatorFactory;
import org.apache.jackrabbit.webdav.DavResourceLocator;
import org.apache.jackrabbit.webdav.util.EncodeUtil;
import org.cryptomator.crypto.Cryptor;
import org.cryptomator.crypto.CryptorIOSupport;
import org.cryptomator.crypto.SensitiveDataSwipeListener;
class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveDataSwipeListener, CryptorIOSupport {
class DavLocatorFactoryImpl implements DavLocatorFactory, SensitiveDataSwipeListener, CryptorIOSupport {
private static final int MAX_CACHED_PATHS = 10000;
private final Path fsRoot;
private final Cryptor cryptor;
private final BidiMap<String, String> pathCache = new BidiLRUMap<>(MAX_CACHED_PATHS); // <decryptedPath, encryptedPath>
DavLocatorFactoryImpl(String fsRoot, String httpRoot, Cryptor cryptor) {
super(httpRoot);
DavLocatorFactoryImpl(String fsRoot, Cryptor cryptor) {
this.fsRoot = FileSystems.getDefault().getPath(fsRoot);
this.cryptor = cryptor;
cryptor.addSensitiveDataSwipeListener(this);
}
/* DavLocatorFactory */
@Override
public DavResourceLocator createResourceLocator(String prefix, String href) {
final String fullPrefix = prefix.endsWith("/") ? prefix : prefix + "/";
final String relativeHref = StringUtils.removeStart(href, fullPrefix);
final String resourcePath = EncodeUtil.unescape(StringUtils.removeStart(relativeHref, "/"));
return new DavResourceLocatorImpl(fullPrefix, resourcePath);
}
@Override
public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
final String fullPrefix = prefix.endsWith("/") ? prefix : prefix + "/";
final String resourcePath = (isResourcePath) ? path : getResourcePath(path);
return new DavResourceLocatorImpl(fullPrefix, resourcePath);
}
@Override
public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
return createResourceLocator(prefix, workspacePath, resourcePath, true);
}
/* Encryption/Decryption */
/**
* @return Encrypted absolute paths on the file system.
*/
@Override
protected String getRepositoryPath(String resourcePath, String wspPath) {
private String getRepositoryPath(String resourcePath) {
String encryptedPath = pathCache.get(resourcePath);
if (encryptedPath == null) {
encryptedPath = encryptRepositoryPath(resourcePath);
@@ -59,8 +87,7 @@ class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveD
/**
* @return Decrypted path for use in URIs.
*/
@Override
protected String getResourcePath(String repositoryPath, String wspPath) {
private String getResourcePath(String repositoryPath) {
String decryptedPath = pathCache.getKey(repositoryPath);
if (decryptedPath == null) {
decryptedPath = decryptResourcePath(repositoryPath);
@@ -80,24 +107,7 @@ class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveD
}
}
@Override
public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
// we don't support workspaces
return super.createResourceLocator(prefix, "", path, isResourcePath);
}
@Override
public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
// we don't support workspaces
return super.createResourceLocator(prefix, "", resourcePath);
}
@Override
public void swipeSensitiveData() {
pathCache.clear();
}
/* Cryptor I/O Support */
/* CryptorIOSupport */
@Override
public void writePathSpecificMetadata(String encryptedPath, byte[] encryptedMetadata) throws IOException {
@@ -115,4 +125,103 @@ class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveD
}
}
/* SensitiveDataSwipeListener */
@Override
public void swipeSensitiveData() {
pathCache.clear();
}
/* Locator */
private class DavResourceLocatorImpl implements DavResourceLocator {
private final String prefix;
private final String resourcePath;
private DavResourceLocatorImpl(String prefix, String resourcePath) {
this.prefix = prefix;
this.resourcePath = resourcePath;
}
@Override
public String getPrefix() {
return prefix;
}
@Override
public String getResourcePath() {
return resourcePath;
}
@Override
public String getWorkspacePath() {
return isRootLocation() ? null : "";
}
@Override
public String getWorkspaceName() {
return getPrefix();
}
@Override
public boolean isSameWorkspace(DavResourceLocator locator) {
return (locator == null) ? false : isSameWorkspace(locator.getWorkspaceName());
}
@Override
public boolean isSameWorkspace(String workspaceName) {
return getWorkspaceName().equals(workspaceName);
}
@Override
public String getHref(boolean isCollection) {
final String href = getPrefix().concat(getResourcePath());
if (isCollection && !href.endsWith("/")) {
return href.concat("/");
} else if (!isCollection && href.endsWith("/")) {
return href.substring(0, href.length() - 1);
} else {
return href;
}
}
@Override
public boolean isRootLocation() {
return getResourcePath() == null;
}
@Override
public DavLocatorFactory getFactory() {
return DavLocatorFactoryImpl.this;
}
@Override
public String getRepositoryPath() {
return DavLocatorFactoryImpl.this.getRepositoryPath(getResourcePath());
}
@Override
public int hashCode() {
final HashCodeBuilder builder = new HashCodeBuilder();
builder.append(prefix);
builder.append(resourcePath);
return builder.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DavResourceLocatorImpl) {
final DavResourceLocatorImpl other = (DavResourceLocatorImpl) obj;
final EqualsBuilder builder = new EqualsBuilder();
builder.append(this.prefix, other.prefix);
builder.append(this.resourcePath, other.resourcePath);
return builder.isEquals();
} else {
return false;
}
}
}
}
@@ -23,7 +23,6 @@ public class WebDavServlet extends AbstractWebdavServlet {
private static final long serialVersionUID = 7965170007048673022L;
public static final String CFG_FS_ROOT = "cfg.fs.root";
public static final String CFG_HTTP_ROOT = "cfg.http.root";
public static final String CFG_CHECK_FILE_INTEGRITY = "cfg.checkFileIntegrity";
private DavSessionProvider davSessionProvider;
private DavLocatorFactory davLocatorFactory;
@@ -42,9 +41,8 @@ public class WebDavServlet extends AbstractWebdavServlet {
davSessionProvider = new DavSessionProviderImpl();
final String fsRoot = config.getInitParameter(CFG_FS_ROOT);
final String httpRoot = config.getInitParameter(CFG_HTTP_ROOT);
final boolean checkFileIntegrity = Boolean.parseBoolean(config.getInitParameter(CFG_CHECK_FILE_INTEGRITY));
this.davLocatorFactory = new DavLocatorFactoryImpl(fsRoot, httpRoot, cryptor);
this.davLocatorFactory = new DavLocatorFactoryImpl(fsRoot, cryptor);
this.davResourceFactory = new DavResourceFactoryImpl(cryptor, checkFileIntegrity);
}