Add POC protocol servlet with delegate to git

This commit is contained in:
René Pfeuffer
2018-09-06 10:58:09 +02:00
parent c4b34752b4
commit be5c430bd2
10 changed files with 163 additions and 167 deletions

View File

@@ -135,7 +135,7 @@ public class ScmContextListener extends GuiceResteasyBootstrapServletContextList
moduleList.add(new EagerSingletonModule());
moduleList.add(ShiroWebModule.guiceFilterModule());
moduleList.add(new WebElementModule(pluginLoader));
moduleList.add(new ScmServletModule(context, pluginLoader, overrides, pluginLoader.getExtensionProcessor()));
moduleList.add(new ScmServletModule(context, pluginLoader, overrides));
moduleList.add(
new ScmSecurityModule(context, pluginLoader.getExtensionProcessor())
);

View File

@@ -56,17 +56,48 @@ import sonia.scm.group.xml.XmlGroupDAO;
import sonia.scm.io.DefaultFileSystem;
import sonia.scm.io.FileSystem;
import sonia.scm.net.SSLContextProvider;
import sonia.scm.net.ahc.*;
import sonia.scm.plugin.*;
import sonia.scm.repository.*;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.net.ahc.ContentTransformer;
import sonia.scm.net.ahc.DefaultAdvancedHttpClient;
import sonia.scm.net.ahc.JsonContentTransformer;
import sonia.scm.net.ahc.XmlContentTransformer;
import sonia.scm.plugin.DefaultPluginLoader;
import sonia.scm.plugin.DefaultPluginManager;
import sonia.scm.plugin.PluginLoader;
import sonia.scm.plugin.PluginManager;
import sonia.scm.repository.DefaultRepositoryManager;
import sonia.scm.repository.DefaultRepositoryProvider;
import sonia.scm.repository.HealthCheckContextListener;
import sonia.scm.repository.NamespaceStrategy;
import sonia.scm.repository.NamespaceStrategyProvider;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryManagerProvider;
import sonia.scm.repository.RepositoryProvider;
import sonia.scm.repository.api.HookContextFactory;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.repository.spi.HookEventFacade;
import sonia.scm.repository.xml.XmlRepositoryDAO;
import sonia.scm.schedule.QuartzScheduler;
import sonia.scm.schedule.Scheduler;
import sonia.scm.security.*;
import sonia.scm.store.*;
import sonia.scm.security.AuthorizationChangedEventProducer;
import sonia.scm.security.CipherHandler;
import sonia.scm.security.CipherUtil;
import sonia.scm.security.ConfigurableLoginAttemptHandler;
import sonia.scm.security.DefaultKeyGenerator;
import sonia.scm.security.DefaultSecuritySystem;
import sonia.scm.security.KeyGenerator;
import sonia.scm.security.LoginAttemptHandler;
import sonia.scm.security.SecuritySystem;
import sonia.scm.store.BlobStoreFactory;
import sonia.scm.store.ConfigurationEntryStoreFactory;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.store.DataStoreFactory;
import sonia.scm.store.FileBlobStoreFactory;
import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
import sonia.scm.store.JAXBConfigurationStoreFactory;
import sonia.scm.store.JAXBDataStoreFactory;
import sonia.scm.template.MustacheTemplateEngine;
import sonia.scm.template.TemplateEngine;
import sonia.scm.template.TemplateEngineFactory;
@@ -81,6 +112,7 @@ import sonia.scm.util.ScmConfigurationUtil;
import sonia.scm.web.UserAgentParser;
import sonia.scm.web.cgi.CGIExecutorFactory;
import sonia.scm.web.cgi.DefaultCGIExecutorFactory;
import sonia.scm.web.filter.AuthenticationFilter;
import sonia.scm.web.filter.LoggingFilter;
import sonia.scm.web.security.AdministrationContext;
import sonia.scm.web.security.DefaultAdministrationContext;
@@ -162,15 +194,12 @@ public class ScmServletModule extends ServletModule
* @param servletContext
* @param pluginLoader
* @param overrides
* @param extensionProcessor
*/
ScmServletModule(ServletContext servletContext,
DefaultPluginLoader pluginLoader, ClassOverrides overrides, ExtensionProcessor extensionProcessor)
ScmServletModule(ServletContext servletContext, DefaultPluginLoader pluginLoader, ClassOverrides overrides)
{
this.servletContext = servletContext;
this.pluginLoader = pluginLoader;
this.overrides = overrides;
this.extensionProcessor = extensionProcessor;
}
//~--- methods --------------------------------------------------------------
@@ -293,6 +322,8 @@ public class ScmServletModule extends ServletModule
bind(TemplateEngineFactory.class);
bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class);
filter("/repo/*").through(AuthenticationFilter.class);
// bind events
// bind(LastModifiedUpdateListener.class);
@@ -389,11 +420,6 @@ public class ScmServletModule extends ServletModule
/**
* Load ScmConfiguration with JAXB
*
*
* @param context
*
* @return
*/
private ScmConfiguration getScmConfiguration()
{
@@ -414,6 +440,4 @@ public class ScmServletModule extends ServletModule
/** Field description */
private final ServletContext servletContext;
private final ExtensionProcessor extensionProcessor;
}

View File

@@ -33,7 +33,7 @@ public class WebResourceServlet extends HttpServlet {
* TODO remove old protocol servlets and hook. Move /hook/hg to api?
*/
@VisibleForTesting
static final String PATTERN = "/(?!api/|git/|hg/|svn/|hook/).*";
static final String PATTERN = "/(?!api/|git/|hg/|svn/|hook/|repo/).*";
private static final Logger LOG = LoggerFactory.getLogger(WebResourceServlet.class);

View File

@@ -34,7 +34,6 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import com.github.sdorra.ssp.PermissionActionCheck;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.inject.Inject;
@@ -43,7 +42,6 @@ import org.apache.shiro.concurrent.SubjectAwareExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.AlreadyExistsException;
import sonia.scm.ArgumentIsInvalidException;
import sonia.scm.ConfigurationException;
import sonia.scm.HandlerEventType;
import sonia.scm.ManagerDaoAdapter;
@@ -332,52 +330,12 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
uri = uri.substring(1);
}
int typeSeparator = uri.indexOf(HttpUtil.SEPARATOR_PATH);
Repository repository = null;
if (typeSeparator > 0) {
String type = uri.substring(0, typeSeparator);
String namespace = uri.substring(0, uri.indexOf(HttpUtil.SEPARATOR_PATH));
String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1));
uri = uri.substring(typeSeparator + 1);
repository = getFromTypeAndUri(type, uri);
}
return repository;
}
private Repository getFromTypeAndUri(String type, String uri) {
if (Strings.isNullOrEmpty(type)) {
throw new ArgumentIsInvalidException("argument type is required");
}
if (Strings.isNullOrEmpty(uri)) {
throw new ArgumentIsInvalidException("argument uri is required");
}
// remove ;jsessionid, jetty bug?
uri = HttpUtil.removeMatrixParameter(uri);
Repository repository = null;
if (handlerMap.containsKey(type)) {
Collection<Repository> repositories = repositoryDAO.getAll();
PermissionActionCheck<Repository> check = RepositoryPermissions.read();
for (Repository r : repositories) {
if (repositoryMatcher.matches(r, type, uri)) {
check.check(r);
repository = r.clone();
break;
}
}
}
if ((repository == null) && logger.isDebugEnabled()) {
logger.debug("could not find repository with type {} and uri {}", type,
uri);
}
repository = get(new NamespaceAndName(namespace, name));
return repository;
}

View File

@@ -38,81 +38,31 @@ package sonia.scm.repository;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.servlet.RequestScoped;
import sonia.scm.security.ScmSecurityException;
//~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletRequest;
/**
*
* @author Sebastian Sdorra
*/
@RequestScoped
public class DefaultRepositoryProvider implements RepositoryProvider
{
//~--- JDK imports ------------------------------------------------------------
@RequestScoped
public class DefaultRepositoryProvider implements RepositoryProvider {
/** Field description */
public static final String ATTRIBUTE_NAME = "scm.request.repository";
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param requestProvider
* @param manager
*/
private final Provider<HttpServletRequest> requestProvider;
@Inject
public DefaultRepositoryProvider(
Provider<HttpServletRequest> requestProvider,
RepositoryManager manager)
{
public DefaultRepositoryProvider(Provider<HttpServletRequest> requestProvider) {
this.requestProvider = requestProvider;
this.manager = manager;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*
* @throws ScmSecurityException
*/
@Override
public Repository get() throws ScmSecurityException
{
Repository repository = null;
public Repository get() throws ScmSecurityException {
HttpServletRequest request = requestProvider.get();
if (request != null)
{
repository = (Repository) request.getAttribute(ATTRIBUTE_NAME);
if (repository == null)
{
repository = manager.getFromRequest(request);
if (repository != null)
{
request.setAttribute(ATTRIBUTE_NAME, repository);
}
}
if (request != null) {
return (Repository) request.getAttribute(ATTRIBUTE_NAME);
}
return repository;
throw new IllegalStateException("request not found");
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final RepositoryManager manager;
/** Field description */
private final Provider<HttpServletRequest> requestProvider;
}

View File

@@ -0,0 +1,86 @@
package sonia.scm.web.protocol;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import sonia.scm.PushStateDispatcher;
import sonia.scm.filter.WebElement;
import sonia.scm.repository.DefaultRepositoryProvider;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryProvider;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.repository.spi.HttpScmProtocol;
import sonia.scm.util.HttpUtil;
import sonia.scm.web.UserAgent;
import sonia.scm.web.UserAgentParser;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Singleton
@WebElement(value = HttpProtocolServlet.PATTERN)
@Slf4j
public class HttpProtocolServlet extends HttpServlet {
public static final String PATTERN = "/repo/*";
private final RepositoryProvider repositoryProvider;
private final RepositoryServiceFactory serviceFactory;
private final Provider<HttpServletRequest> requestProvider;
private final PushStateDispatcher dispatcher;
private final UserAgentParser userAgentParser;
@Inject
public HttpProtocolServlet(RepositoryProvider repositoryProvider, RepositoryServiceFactory serviceFactory, Provider<HttpServletRequest> requestProvider, PushStateDispatcher dispatcher, UserAgentParser userAgentParser) {
this.repositoryProvider = repositoryProvider;
this.serviceFactory = serviceFactory;
this.requestProvider = requestProvider;
this.dispatcher = dispatcher;
this.userAgentParser = userAgentParser;
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Subject subject = SecurityUtils.getSubject();
UserAgent userAgent = userAgentParser.parse(req);
if (userAgent.isBrowser()) {
log.trace("dispatch browser request for user agent {}", userAgent);
dispatcher.dispatch(req, resp, req.getRequestURI());
} else {
String pathInfo = req.getPathInfo();
NamespaceAndName namespaceAndName = fromUri(pathInfo);
try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) {
requestProvider.get().setAttribute(DefaultRepositoryProvider.ATTRIBUTE_NAME, repositoryService.getRepository());
HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class);
protocol.serve(req, resp);
} catch (RepositoryNotFoundException e) {
resp.setStatus(404);
}
}
}
private NamespaceAndName fromUri(String uri) {
if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) {
uri = uri.substring(1);
}
String namespace = uri.substring(0, uri.indexOf(HttpUtil.SEPARATOR_PATH));
String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1));
return new NamespaceAndName(namespace, name);
}
}