Replace static mercurial permission handling

Replace our own hg permission handling with the default hg permission which is controlled by the `web` config
This commit is contained in:
Eduard Heimbuch
2023-04-03 09:47:15 +02:00
committed by SCM-Manager
parent e679dac94d
commit 026ffa18fd
8 changed files with 53 additions and 418 deletions

View File

@@ -31,19 +31,19 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.HgEnvironmentBuilder;
import sonia.scm.repository.HgExtensions;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgConfigResolver;
import sonia.scm.repository.HgEnvironmentBuilder;
import sonia.scm.repository.HgExtensions;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryPermissions;
import sonia.scm.repository.RepositoryRequestListenerUtil;
import sonia.scm.repository.spi.ScmProviderHttpServlet;
import sonia.scm.web.cgi.CGIExecutor;
import sonia.scm.web.cgi.CGIExecutorFactory;
import javax.annotation.Nonnull;
import sonia.scm.web.cgi.EnvList;
import javax.annotation.Nonnull;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -147,12 +147,12 @@ public class HgCGIServlet extends HttpServlet implements ScmProviderHttpServlet
HgConfig config = configResolver.resolve(repository);
executor.setWorkDirectory(config.getDirectory());
executor.setArgs(createArgs(config));
executor.setArgs(createArgs(repository, config));
executor.execute(config.getHgBinary());
}
@Nonnull
private List<String> createArgs(HgConfig config) {
private List<String> createArgs(Repository repository, HgConfig config) {
List<String> args = new ArrayList<>();
config(args, "extensions.cgiserve", extension.getAbsolutePath());
@@ -160,9 +160,19 @@ public class HgCGIServlet extends HttpServlet implements ScmProviderHttpServlet
config(args, "hooks.pretxnchangegroup.scm", String.format("python:%s:pre_hook", hooks));
config(args, "hooks.changegroup.scm", String.format("python:%s:post_hook", hooks));
if (RepositoryPermissions.push(repository).isPermitted()) {
config(args, "web.allow_push", "*");
} else {
config(args, "web.deny_push", "*");
}
if(RepositoryPermissions.pull(repository).isPermitted()) {
config(args, "web.allow_read", "*");
} else {
config(args, "web.deny_read", "*");
}
config(args, "web.push_ssl", "false");
config(args, "web.allow_read", "*");
config(args, "web.allow_push", "*");
// enable experimental httppostargs protocol of mercurial
// Issue 970: https://goo.gl/poascp

View File

@@ -21,40 +21,34 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.Repository;
import sonia.scm.repository.spi.ScmProviderHttpServlet;
import sonia.scm.web.filter.PermissionFilter;
import sonia.scm.repository.HgRepositoryHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
/**
* Permission filter for mercurial repositories.
*
*
* @author Sebastian Sdorra
*/
public class HgPermissionFilter extends PermissionFilter
{
private static final Set<String> READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE");
public class HgPermissionFilter extends PermissionFilter {
private static final Set<String> READ_METHODS = Set.of("GET", "HEAD", "OPTIONS", "TRACE");
private final HgRepositoryHandler repositoryHandler;
public HgPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate, HgRepositoryHandler repositoryHandler)
{
public HgPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate, HgRepositoryHandler repositoryHandler) {
super(configuration, delegate);
this.repositoryHandler = repositoryHandler;
}
@@ -73,10 +67,9 @@ public class HgPermissionFilter extends PermissionFilter
}
@Override
public boolean isWriteRequest(HttpServletRequest request)
{
public boolean isWriteRequest(HttpServletRequest request) {
if (isHttpPostArgsEnabled()) {
return isHttpPostArgsWriteRequest(request);
return true;
}
return isDefaultWriteRequest(request);
}
@@ -85,14 +78,7 @@ public class HgPermissionFilter extends PermissionFilter
return repositoryHandler.getConfig().isEnableHttpPostArgs();
}
private boolean isHttpPostArgsWriteRequest(HttpServletRequest request) {
return WireProtocol.isWriteRequest(request);
}
private boolean isDefaultWriteRequest(HttpServletRequest request) {
if (READ_METHODS.contains(request.getMethod())) {
return WireProtocol.isWriteRequest(request);
}
return true;
return !READ_METHODS.contains(request.getMethod());
}
}

View File

@@ -24,7 +24,6 @@
package sonia.scm.web;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.plugin.Extension;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.spi.ScmProviderHttpServlet;
@@ -35,13 +34,9 @@ import javax.inject.Inject;
@Extension
public class HgPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory {
private final ScmConfiguration configuration;
private final HgRepositoryHandler repositoryHandler;
@Inject
public HgPermissionFilterFactory(ScmConfiguration configuration, HgRepositoryHandler repositoryHandler) {
this.configuration = configuration;
this.repositoryHandler = repositoryHandler;
public HgPermissionFilterFactory() {
// empty
}
@Override
@@ -51,6 +46,6 @@ public class HgPermissionFilterFactory implements ScmProviderHttpServletDecorato
@Override
public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) {
return new HgPermissionFilter(configuration, delegate,repositoryHandler);
return delegate;
}
}

View File

@@ -29,14 +29,20 @@ import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import sonia.scm.util.HttpUtil;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
/**
* WireProtocol provides methods for handling the mercurial wire protocol.
@@ -45,52 +51,9 @@ import java.util.*;
*/
public final class WireProtocol {
private static final Logger LOG = LoggerFactory.getLogger(WireProtocol.class);
private static final Set<String> READ_COMMANDS = ImmutableSet.of(
"batch", "between", "branchmap", "branches", "capabilities", "changegroup", "changegroupsubset", "clonebundles",
"getbundle", "heads", "hello", "listkeys", "lookup", "known", "stream_out",
// could not find lheads in the wireprotocol description but mercurial 4.5.2 uses it for clone
"lheads",
// For HG Evolve Extension
"evoext_obshashrange_v1"
);
private static final Set<String> WRITE_COMMANDS = ImmutableSet.of(
"pushkey", "unbundle"
);
private WireProtocol() {
}
/**
* Returns {@code true} if the request is a write request. The method will always return {@code true}, expect for the
* following cases:
*
* - no command was specified with the request (is required for the hgweb ui)
* - the command in the query string was found in the list of read request
* - if query string contains the batch command, then all commands specified in X-HgArg headers must be
* in the list of read requests
* - in case of enabled HttpPostArgs protocol and query string container the batch command, the header X-HgArgs-Post
* is read and the commands which are specified in the body from 0 to the value of X-HgArgs-Post must be in the list
* of read requests
*
* @param request http request
*
* @return {@code true} for write requests.
*/
public static boolean isWriteRequest(HttpServletRequest request) {
List<String> commands = commandsOf(request);
boolean write = isWriteRequest(commands);
LOG.trace("mercurial request {} is write: {}", commands, write);
return write;
}
@VisibleForTesting
static boolean isWriteRequest(List<String> commands) {
return !READ_COMMANDS.containsAll(commands);
}
@VisibleForTesting
static List<String> commandsOf(HttpServletRequest request) {
List<String> listOfCmds = Lists.newArrayList();
@@ -126,7 +89,7 @@ public final class WireProtocol {
byte[] bytes = hgRequest.getInputStream().readAndCapture(hgArgsPostSize);
// we use iso-8859-1 for encoding, because the post args are normally http headers which are using iso-8859-1
// see https://tools.ietf.org/html/rfc7230#section-3.2.4
String hgArgs = new String(bytes, Charsets.ISO_8859_1);
String hgArgs = new String(bytes, StandardCharsets.ISO_8859_1);
String decoded = decodeValue(hgArgs);
parseHgCommandHeader(listOfCmds, decoded);
} catch (IOException ex) {