From ceedb19bb1b6a67b5ab154e4c230169f7ef431ad Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 24 Nov 2010 18:32:32 +0100 Subject: [PATCH] use PermissionFilter for mercurial repositories --- .../api/rest/resources/HgConfigResource.java | 2 - .../scm/repository/HgRepositoryHandler.java | 51 +++++--- .../main/java/sonia/scm/web/HgCGIServlet.java | 109 ++++++++++++++++++ .../sonia/scm/web/HgPermissionFilter.java | 108 +++++++++++++++++ .../java/sonia/scm/web/HgServletModule.java | 12 +- .../src/main/resources/sonia/scm/hgweb.cgi | 7 +- .../sonia/scm/web/cgi/AbstractCGIServlet.java | 11 +- 7 files changed, 278 insertions(+), 22 deletions(-) create mode 100644 plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java index 13675aa0af..de7a3986e1 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/api/rest/resources/HgConfigResource.java @@ -46,8 +46,6 @@ import sonia.scm.web.HgWebConfigWriter; import java.io.IOException; -import javax.servlet.ServletContext; - import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java index 5da06c30ee..d09008afd4 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java @@ -310,6 +310,44 @@ public class HgRepositoryHandler extends AbstractRepositoryHandler return repositories; } + /** + * Method description + * + * + * @param repositoryname + * + * @return + */ + public Repository getByName(String repositoryname) + { + Repository repository = null; + + for (Repository r : getAll()) + { + if (r.getName().equals(repositoryname)) + { + repository = r; + + break; + } + } + + return repository; + } + + /** + * Method description + * + * + * @param repository + * + * @return + */ + public File getDirectory(Repository repository) + { + return new File(config.getRepositoryDirectory(), repository.getName()); + } + /** * Method description * @@ -534,19 +572,6 @@ public class HgRepositoryHandler extends AbstractRepositoryHandler return new File(config.getRepositoryDirectory(), id); } - /** - * Method description - * - * - * @param repository - * - * @return - */ - private File getDirectory(Repository repository) - { - return new File(config.getRepositoryDirectory(), repository.getName()); - } - /** * Method description * diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 1470ed18ab..b03b5f3c29 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -29,19 +29,28 @@ * */ + + package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- +import com.google.inject.Inject; import com.google.inject.Singleton; +import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.repository.Repository; import sonia.scm.web.cgi.AbstractCGIServlet; +import sonia.scm.web.cgi.EnvList; //~--- JDK imports ------------------------------------------------------------ import java.io.File; import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -53,9 +62,33 @@ import javax.servlet.http.HttpServletRequest; public class HgCGIServlet extends AbstractCGIServlet { + /** Field description */ + public static final String ENV_REPOSITORY_NAME = "REPO_NAME"; + + /** Field description */ + public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH"; + /** Field description */ private static final long serialVersionUID = -3492811300905099810L; + /** Field description */ + public static final Pattern PATTERN_REPOSITORYNAME = + Pattern.compile("/[^/]+/([^/]+)(?:/.*)?"); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handler + */ + @Inject + public HgCGIServlet(HgRepositoryHandler handler) + { + this.handler = handler; + } + //~--- methods -------------------------------------------------------------- /** @@ -71,6 +104,39 @@ public class HgCGIServlet extends AbstractCGIServlet super.init(); } + /** + * Method description + * + * + * @param request + * @param baseEnvironment + * + * @return + * + * @throws ServletException + */ + @Override + protected EnvList createRequestEnvironment(HttpServletRequest request, + EnvList baseEnvironment) + throws ServletException + { + EnvList list = new EnvList(baseEnvironment); + Repository repository = getRepository(request); + + if (repository == null) + { + throw new ServletException("repository not found"); + } + + String name = repository.getName(); + File directory = handler.getDirectory(repository); + + list.set(ENV_REPOSITORY_PATH, directory.getAbsolutePath()); + list.set(ENV_REPOSITORY_NAME, name); + + return list; + } + //~--- get methods ---------------------------------------------------------- /** @@ -91,8 +157,51 @@ public class HgCGIServlet extends AbstractCGIServlet return command; } + /** + * Method description + * + * + * @param request + * + * @return + */ + protected Repository getRepository(HttpServletRequest request) + { + Repository repository = null; + String uri = request.getRequestURI(); + + uri = uri.substring(request.getContextPath().length()); + + Matcher m = PATTERN_REPOSITORYNAME.matcher(uri); + + if (m.matches()) + { + String repositoryname = m.group(1); + + repository = getRepository(repositoryname); + } + + return repository; + } + + /** + * Method description + * + * + * @param repositoryname + * + * @return + */ + private Repository getRepository(String repositoryname) + { + return handler.getByName(repositoryname); + } + //~--- fields --------------------------------------------------------------- /** Field description */ private File command; + + /** Field description */ + private HgRepositoryHandler handler; } diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java new file mode 100644 index 0000000000..18ddfba451 --- /dev/null +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.web; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.repository.Repository; +import sonia.scm.web.filter.PermissionFilter; +import sonia.scm.web.security.SecurityContext; + +//~--- JDK imports ------------------------------------------------------------ + +import javax.servlet.http.HttpServletRequest; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +public class HgPermissionFilter extends PermissionFilter +{ + + /** + * Constructs ... + * + * + * @param securityContextProvider + * @param handler + */ + @Inject + public HgPermissionFilter(Provider securityContextProvider, + HgRepositoryHandler handler) + { + super(securityContextProvider); + this.handler = handler; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param name + * + * @return + */ + @Override + protected Repository getRepository(String name) + { + return handler.getByName(name); + } + + /** + * Method description + * + * + * @param request + * + * @return + */ + @Override + protected boolean isWriteRequest(HttpServletRequest request) + { + return !request.getMethod().equalsIgnoreCase("GET"); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private HgRepositoryHandler handler; +} diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java index f4109fa2f6..2371d8639f 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- @@ -44,6 +46,11 @@ import sonia.scm.web.filter.BasicAuthenticationFilter; public class HgServletModule extends ServletModule { + /** Field description */ + public static final String MAPPING_HG = "/hg/*"; + + //~--- methods -------------------------------------------------------------- + /** * Method description * @@ -51,7 +58,8 @@ public class HgServletModule extends ServletModule @Override protected void configureServlets() { - filter("/hg/*").through(BasicAuthenticationFilter.class); - serve("/hg/*").with(HgCGIServlet.class); + filter(MAPPING_HG).through(BasicAuthenticationFilter.class); + filter(MAPPING_HG).through(HgPermissionFilter.class); + serve(MAPPING_HG).with(HgCGIServlet.class); } } diff --git a/plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.cgi b/plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.cgi index 3052701157..7ee814bbaf 100644 --- a/plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.cgi +++ b/plugins/scm-hg-plugin/src/main/resources/sonia/scm/hgweb.cgi @@ -1,6 +1,9 @@ #!/usr/bin/env ${python} -config = "${config}" + +import os +repositoryPath = os.environ['SCM_REPOSITORY_PATH'] + from mercurial import demandimport; demandimport.enable() from mercurial.hgweb import hgweb, wsgicgi -application = hgweb(config) +application = hgweb(repositoryPath) wsgicgi.launch(application) diff --git a/scm-web-api/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java b/scm-web-api/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java index 167043077e..2b4e8ec8b8 100644 --- a/scm-web-api/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java +++ b/scm-web-api/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.web.cgi; //~--- JDK imports ------------------------------------------------------------ @@ -125,13 +127,16 @@ public abstract class AbstractCGIServlet extends HttpServlet * Method description * * + * + * @param request * @param baseEnvironment * * @return * * @throws ServletException */ - protected EnvList createRequestEnvironment(EnvList baseEnvironment) + protected EnvList createRequestEnvironment(HttpServletRequest request, + EnvList baseEnvironment) throws ServletException { return new EnvList(baseEnvironment); @@ -151,8 +156,8 @@ public abstract class AbstractCGIServlet extends HttpServlet protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - cgiRunner.exec(createRequestEnvironment(baseEnvironment), getCommand(req), - req.getPathInfo(), req, resp); + cgiRunner.exec(createRequestEnvironment(req, baseEnvironment), + getCommand(req), req.getPathInfo(), req, resp); } //~--- get methods ----------------------------------------------------------