From 04704460887c01cd9f829e15b8b0ec3cbba5ea85 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Tue, 14 May 2013 14:10:33 +0200 Subject: [PATCH] OO-606: add a minimal unit test for WebDAV based on the Grizzly Web Server --- .../services/webdav/SecureWebdavServlet.java | 127 +++++++++--------- .../commons/service/webdav/HttpPropFind.java | 57 ++++++++ .../service/webdav/WebDAVConnection.java | 105 +++++++++++++++ .../service/webdav/WebDAVTestCase.java | 119 ++++++++++++++++ .../java/org/olat/test/AllTestsJunit4.java | 1 + 5 files changed, 346 insertions(+), 63 deletions(-) create mode 100644 src/test/java/org/olat/core/commons/service/webdav/HttpPropFind.java create mode 100644 src/test/java/org/olat/core/commons/service/webdav/WebDAVConnection.java create mode 100644 src/test/java/org/olat/core/commons/service/webdav/WebDAVTestCase.java diff --git a/src/main/java/org/olat/core/commons/services/webdav/SecureWebdavServlet.java b/src/main/java/org/olat/core/commons/services/webdav/SecureWebdavServlet.java index c2b153ab673..dccdfd3870c 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/SecureWebdavServlet.java +++ b/src/main/java/org/olat/core/commons/services/webdav/SecureWebdavServlet.java @@ -297,71 +297,72 @@ public class SecureWebdavServlet /** * Handles the special WebDAV methods. */ - protected void secureService(HttpServletRequest req, HttpServletResponse resp) { - try { - String method = req.getMethod(); - String path = getRelativePath(req); - - // OLAT-6294 alsways set encoding to UTF-8, overwritten later when a resource is different - resp.setCharacterEncoding("UTF-8"); - if (debug > 0) { - log.debug("[" + method + "] " + path); - } - - // security check; response header will be set appropriately - // returns false if security check failed. - - if (webDAVManager == null) { - // is not initialized properly - return; - } - boolean authenticated = webDAVManager.handleAuthentication(req, resp); - if (!authenticated) { - return; - } - - if (method.equals(METHOD_PROPFIND)) { - doPropfind(req, resp); - } else if (method.equals(METHOD_PROPPATCH)) { - doProppatch(req, resp); - } else if (method.equals(METHOD_OPTIONS)) { - doOptions(req, resp); - } else if (method.equals(METHOD_MKCOL)) { - doMkcol(req, resp); - } else if (method.equals(METHOD_COPY)) { - doCopy(req, resp); - } else if (method.equals(METHOD_MOVE)) { - doMove(req, resp); - } else if (method.equals(METHOD_LOCK)) { - doLock(req, resp); - } else if (method.equals(METHOD_UNLOCK)) { - doUnlock(req, resp); - } else if (method.equals(METHOD_HEAD)) { - String decodedPath = URLDecoder.decode(path, "UTF-8"); - String headerCD = "attachment; filename=" + decodedPath.substring(decodedPath.lastIndexOf("/") + 1); - resp.setHeader("Content-Disposition", headerCD); - super.service(req, resp); - } else if (method.equals(METHOD_PUT)) { - doPut(req, resp); - } else if (method.equals(METHOD_DELETE)) { - doDelete(req, resp); - } else { - // DefaultServlet processing - super.service(req, resp); - } - } catch (Exception e) { - log.error("Exception in WebDAV request", e); - throw new OLATRuntimeException(this.getClass(), "Exception in SecureWebDavServlet.", e); - } catch (Error er) { - log.error("Error in WebDAV request", er); - throw new OLATRuntimeException(this.getClass(), "Error in SecureWebDavServlet.", er); - } catch (Throwable er) { - log.error("Throwable in WebDAV request", er); - throw new OLATRuntimeException(this.getClass(), "Throwable in SecureWebDavServlet.", er); - } + protected void secureService(HttpServletRequest req, HttpServletResponse resp) { + try { + String method = req.getMethod(); + String path = getRelativePath(req); + + // OLAT-6294 alsways set encoding to UTF-8, overwritten later when a + // resource is different + resp.setCharacterEncoding("UTF-8"); + if (debug > 0) { + log.debug("[" + method + "] " + path); + } + + // security check; response header will be set appropriately + // returns false if security check failed. + + if (webDAVManager == null) { + // is not initialized properly + return; + } + boolean authenticated = webDAVManager.handleAuthentication(req, resp); + if (!authenticated) { + return; + } + + if (method.equals(METHOD_PROPFIND)) { + doPropfind(req, resp); + } else if (method.equals(METHOD_PROPPATCH)) { + doProppatch(req, resp); + } else if (method.equals(METHOD_OPTIONS)) { + doOptions(req, resp); + } else if (method.equals(METHOD_MKCOL)) { + doMkcol(req, resp); + } else if (method.equals(METHOD_COPY)) { + doCopy(req, resp); + } else if (method.equals(METHOD_MOVE)) { + doMove(req, resp); + } else if (method.equals(METHOD_LOCK)) { + doLock(req, resp); + } else if (method.equals(METHOD_UNLOCK)) { + doUnlock(req, resp); + } else if (method.equals(METHOD_HEAD)) { + String decodedPath = URLDecoder.decode(path, "UTF-8"); + String headerCD = "attachment; filename=" + decodedPath.substring(decodedPath.lastIndexOf("/") + 1); + resp.setHeader("Content-Disposition", headerCD); + super.service(req, resp); + } else if (method.equals(METHOD_PUT)) { + doPut(req, resp); + } else if (method.equals(METHOD_DELETE)) { + doDelete(req, resp); + } else { + // DefaultServlet processing + super.service(req, resp); + } + } catch (Exception e) { + log.error("Exception in WebDAV request", e); + throw new OLATRuntimeException(this.getClass(), "Exception in SecureWebDavServlet.", e); + } catch (Error er) { + log.error("Error in WebDAV request", er); + throw new OLATRuntimeException(this.getClass(), "Error in SecureWebDavServlet.", er); + } catch (Throwable er) { + log.error("Throwable in WebDAV request", er); + throw new OLATRuntimeException(this.getClass(), "Throwable in SecureWebDavServlet.", er); + } } - ///////////////////////////////////////////// + ///////////////////////////////////////////// // Start of additions to Tomcat WebdavServlet ///////////////////////////////////////////// diff --git a/src/test/java/org/olat/core/commons/service/webdav/HttpPropFind.java b/src/test/java/org/olat/core/commons/service/webdav/HttpPropFind.java new file mode 100644 index 00000000000..2cb61bef420 --- /dev/null +++ b/src/test/java/org/olat/core/commons/service/webdav/HttpPropFind.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.service.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpRequestBase; + +/** + * + * Initial date: 14.05.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class HttpPropFind extends HttpRequestBase { + + public final static String METHOD_NAME = "PROPFIND"; + + public HttpPropFind() { + super(); + } + + public HttpPropFind(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpPropFind(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/core/commons/service/webdav/WebDAVConnection.java b/src/test/java/org/olat/core/commons/service/webdav/WebDAVConnection.java new file mode 100644 index 00000000000..f08ffe586ad --- /dev/null +++ b/src/test/java/org/olat/core/commons/service/webdav/WebDAVConnection.java @@ -0,0 +1,105 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * 12.10.2011 by frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.service.webdav; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CookieStore; +import org.apache.http.client.params.CookiePolicy; +import org.apache.http.client.params.HttpClientParams; +import org.apache.http.impl.client.DefaultHttpClient; +import org.olat.restapi.security.RestSecurityHelper; + +/** + * + * Description:<br> + * Manage a connection to the grizzly server used by the unit test + * with some helpers methods. + * + * <P> + * Initial Date: 20 déc. 2011 <br> + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class WebDAVConnection { + + private int port = WebDAVTestCase.PORT; + private String host = WebDAVTestCase.HOST; + private String protocol = WebDAVTestCase.PROTOCOL; + private String contextPath = WebDAVTestCase.CONTEXT_PATH; + + private final DefaultHttpClient httpclient; + + public WebDAVConnection() { + httpclient = new DefaultHttpClient(); + HttpClientParams.setCookiePolicy(httpclient.getParams(), CookiePolicy.RFC_2109); + } + + public CookieStore getCookieStore() { + return httpclient.getCookieStore(); + } + + public String getSecurityToken(HttpResponse response) { + if(response == null) return null; + + Header header = response.getFirstHeader(RestSecurityHelper.SEC_TOKEN); + return header == null ? null : header.getValue(); + } + + public void shutdown() { + httpclient.getConnectionManager().shutdown(); + } + + public void setCredentials(String username, String password) { + httpclient.getCredentialsProvider().setCredentials( + new AuthScope("localhost", port), + new UsernamePasswordCredentials(username, password)); + } + + public HttpResponse propfind(URI uri) throws IOException, URISyntaxException { + HttpPropFind propFind = new HttpPropFind(uri); + propFind.addHeader("Depth", "1"); + HttpResponse response = httpclient.execute(propFind); + return response; + } + + /** + * @return http://localhost:9997 + */ + public UriBuilder getBaseURI() throws URISyntaxException { + URI uri = new URI(protocol, null, host, port, null, null, null); + return UriBuilder.fromUri(uri); + } + + /** + * @return http://localhost:9997/webdav + */ + public UriBuilder getContextURI() throws URISyntaxException { + return getBaseURI().path(contextPath); + } +} diff --git a/src/test/java/org/olat/core/commons/service/webdav/WebDAVTestCase.java b/src/test/java/org/olat/core/commons/service/webdav/WebDAVTestCase.java new file mode 100644 index 00000000000..7d3254cad8d --- /dev/null +++ b/src/test/java/org/olat/core/commons/service/webdav/WebDAVTestCase.java @@ -0,0 +1,119 @@ +/** +* OLAT - Online Learning and Training<br> +* http://www.olat.org +* <p> +* Licensed under the Apache License, Version 2.0 (the "License"); <br> +* you may not use this file except in compliance with the License.<br> +* You may obtain a copy of the License at +* <p> +* http://www.apache.org/licenses/LICENSE-2.0 +* <p> +* Unless required by applicable law or agreed to in writing,<br> +* software distributed under the License is distributed on an "AS IS" BASIS, <br> +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> +* See the License for the specific language governing permissions and <br> +* limitations under the License. +* <p> +* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> +* University of Zurich, Switzerland. +* <hr> +* <a href="http://www.openolat.org"> +* OpenOLAT - Online Learning and Training</a><br> +* This file has been modified by the OpenOLAT community. Changes are licensed +* under the Apache 2.0 license as the original file. +* <p> +*/ + +package org.olat.core.commons.service.webdav; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.UUID; + +import javax.servlet.Servlet; + +import junit.framework.Assert; + +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; +import org.junit.BeforeClass; +import org.junit.Test; +import org.olat.core.commons.services.webdav.SecureWebdavServlet; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; + +import com.sun.grizzly.http.embed.GrizzlyWebServer; +import com.sun.grizzly.http.servlet.ServletAdapter; + +/** + * + * Description:<br> + * Abstract class which start and stop a grizzly server for every test + * + * <P> + * Initial Date: 14 apr. 2010 <br> + * @author srosse, stephane.rosse@frentix.com + */ +public class WebDAVTestCase extends OlatTestCase { + private static final OLog log = Tracing.createLoggerFor(WebDAVTestCase.class); + + public final static int PORT = 9997; + public final static String HOST = "localhost"; + public final static String PROTOCOL = "http"; + public final static String CONTEXT_PATH = "webdav"; + + private static GrizzlyWebServer webServer; + + @BeforeClass + public static void setUp() throws Exception { + try { + if(webServer == null) { + webServer = new GrizzlyWebServer(PORT); + webServer.useAsynchronousWrite(false); + ServletAdapter sa = new ServletAdapter(); + Servlet servletInstance = null; + try { + servletInstance = new SecureWebdavServlet(); + } catch (Exception ex) { + log.error("Cannot instantiate the Grizzly Servlet Container", ex); + } + sa.setServletInstance(servletInstance); + sa.addInitParameter("debug", "0"); + sa.addInitParameter("input", "32768"); + sa.addInitParameter("output", "32768"); + sa.addInitParameter("listings", "true"); + sa.addInitParameter("readonly", "false"); + sa.setContextPath("/" + CONTEXT_PATH); + webServer.addGrizzlyAdapter(sa, new String[]{""}); + + log.info("Starting the Grizzly Web Container for WebDAV..."); + webServer.start(); + } + } catch (IOException ex) { + log.error("Cannot start the Grizzly Web Container for WebDAV"); + } + } + + @Test + public void testPropFind() + throws IOException, URISyntaxException { + //create a user + Identity user = JunitTestHelper.createAndPersistIdentityAsUser("webdav-1-" + UUID.randomUUID().toString()); + + //list root content of its webdav folder + WebDAVConnection conn = new WebDAVConnection(); + conn.setCredentials(user.getName(), "A6B7C8"); + URI uri = conn.getContextURI().build(); + HttpResponse response = conn.propfind(uri); + assertEquals(207, response.getStatusLine().getStatusCode()); + + String xml = EntityUtils.toString(response.getEntity()); + Assert.assertTrue(xml.indexOf("/webdav/coursefolders/") > 0); + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index 304203c7287..ff445d9a846 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -77,6 +77,7 @@ import org.junit.runners.Suite; org.olat.commons.coordinate.cluster.jms.JMSTest.class,//ok org.olat.commons.coordinate.cluster.lock.LockTest.class,//ok org.olat.commons.coordinate.CoordinatorTest.class,//ok + org.olat.core.commons.service.webdav.WebDAVTestCase.class,//ok org.olat.admin.user.delete.service.UserDeletionManagerTest.class,//ok org.olat.group.test.BGRightManagerTest.class,//ok org.olat.group.test.BGAreaManagerTest.class,//ok -- GitLab