diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 6e59470c5e..69ff0a83f5 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -6,7 +6,6 @@ import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; import sonia.scm.repository.api.ScmProtocolProvider; -import sonia.scm.web.filter.PermissionFilter; import javax.inject.Provider; import javax.servlet.ServletConfig; @@ -24,16 +23,14 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP private static final Logger logger = LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); private final Provider delegateProvider; - private final Provider permissionFilterProvider; private final Provider uriInfoStore; private final ScmConfiguration scmConfiguration; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { this.delegateProvider = delegateProvider; - this.permissionFilterProvider = permissionFilterProvider; this.uriInfoStore = uriInfoStore; this.scmConfiguration = scmConfiguration; } @@ -89,11 +86,7 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP } } - permissionFilterProvider.get().executeIfPermitted( - request, - response, - repository, - () -> delegateProvider.get().service(request, response, repository)); + delegateProvider.get().service(request, response, repository); } } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java index 991728e72c..3793d4b935 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java @@ -4,6 +4,7 @@ import com.google.inject.Inject; import sonia.scm.util.Decorators; import javax.inject.Provider; +import java.util.List; import java.util.Set; import static java.util.stream.Collectors.toList; @@ -21,7 +22,11 @@ public abstract class ScmProviderHttpServletProvider implements Provider d.handlesScmType(type)).collect(toList())); + return Decorators.decorate(getRootServlet(), getDecoratorsForType()); + } + + private List getDecoratorsForType() { + return decoratorFactories.stream().filter(d -> d.handlesScmType(type)).collect(toList()); } protected abstract ScmProviderHttpServlet getRootServlet(); diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index a01875fed0..328494a626 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -42,6 +42,8 @@ import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryPermissions; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecorator; import sonia.scm.security.Role; import sonia.scm.security.ScmSecurityException; import sonia.scm.util.HttpUtil; @@ -56,7 +58,7 @@ import java.io.IOException; * * @author Sebastian Sdorra */ -public abstract class PermissionFilter +public abstract class PermissionFilter extends ScmProviderHttpServletDecorator { /** the logger for PermissionFilter */ @@ -72,8 +74,9 @@ public abstract class PermissionFilter * * @since 1.21 */ - protected PermissionFilter(ScmConfiguration configuration) + protected PermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { + super(delegate); this.configuration = configuration; } @@ -102,8 +105,9 @@ public abstract class PermissionFilter * @throws IOException * @throws ServletException */ - public void executeIfPermitted(HttpServletRequest request, - HttpServletResponse response, Repository repository, ContinuationServlet continuation) + @Override + public void service(HttpServletRequest request, + HttpServletResponse response, Repository repository) throws IOException, ServletException { Subject subject = SecurityUtils.getSubject(); @@ -118,7 +122,7 @@ public abstract class PermissionFilter getActionAsString(writeRequest), repository.getName(), getUserName(subject)); - continuation.doService(); + super.service(request, response, repository); } else { @@ -258,9 +262,4 @@ public abstract class PermissionFilter /** scm-manager global configuration */ private final ScmConfiguration configuration; - - @FunctionalInterface - public interface ContinuationServlet { - void doService() throws ServletException, IOException; - } } diff --git a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java index 6d01232fe3..8c910f92a9 100644 --- a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java @@ -5,13 +5,11 @@ import com.google.inject.util.Providers; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; -import org.mockito.stubbing.Answer; import org.mockito.stubbing.OngoingStubbing; import sonia.scm.api.v2.resources.ScmPathInfo; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; -import sonia.scm.web.filter.PermissionFilter; import javax.inject.Provider; import javax.servlet.ServletConfig; @@ -22,12 +20,7 @@ import java.io.IOException; import java.net.URI; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -40,8 +33,6 @@ public class InitializingHttpScmProtocolWrapperTest { @Mock private ScmProviderHttpServlet delegateServlet; @Mock - private PermissionFilter permissionFilter; - @Mock private ScmPathInfoStore pathInfoStore; @Mock private ScmConfiguration scmConfiguration; @@ -62,7 +53,7 @@ public class InitializingHttpScmProtocolWrapperTest { pathInfoStoreProvider = mock(Provider.class); when(pathInfoStoreProvider.get()).thenReturn(pathInfoStore); - wrapper = new InitializingHttpScmProtocolWrapper(Providers.of(this.delegateServlet), Providers.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) { + wrapper = new InitializingHttpScmProtocolWrapper(Providers.of(this.delegateServlet), pathInfoStoreProvider, scmConfiguration) { @Override public String getType() { return "git"; @@ -98,8 +89,6 @@ public class InitializingHttpScmProtocolWrapperTest { @Test public void shouldInitializeAndDelegateRequestThroughFilter() throws ServletException, IOException { - doAnswer(proceedInvocation()). - when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); httpScmProtocol.serve(request, response, servletConfig); @@ -108,21 +97,8 @@ public class InitializingHttpScmProtocolWrapperTest { verify(delegateServlet).service(request, response, REPOSITORY); } - @Test - public void shouldNotDelegateRequestWhenFilterBlocks() throws ServletException, IOException { - doNothing(). - when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); - HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); - - httpScmProtocol.serve(request, response, servletConfig); - - verify(delegateServlet, never()).service(request, response, REPOSITORY); - } - @Test public void shouldInitializeOnlyOnce() throws ServletException, IOException { - doAnswer(proceedInvocation()). - when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); httpScmProtocol.serve(request, response, servletConfig); @@ -137,13 +113,6 @@ public class InitializingHttpScmProtocolWrapperTest { HttpScmProtocol httpScmProtocol = wrapper.get(new Repository("", "other", "space", "name")); } - private Answer proceedInvocation() { - return invocation -> { - ((PermissionFilter.ContinuationServlet) invocation.getArgument(3)).doService(); - return null; - }; - } - private OngoingStubbing mockSetPathInfo() { return when(pathInfoStore.get()).thenReturn(() -> URI.create("http://example.com/scm/api/rest/")); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java index e183555b3b..e38f26a309 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -34,11 +34,11 @@ package sonia.scm.web; import com.google.common.annotations.VisibleForTesting; -import com.google.inject.Inject; import org.eclipse.jgit.http.server.GitSmartHttpTools; import sonia.scm.ClientMessages; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.GitUtil; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -70,9 +70,8 @@ public class GitPermissionFilter extends PermissionFilter * * @param configuration scm main configuration */ - @Inject - public GitPermissionFilter(ScmConfiguration configuration) { - super(configuration); + public GitPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { + super(configuration, delegate); } @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java new file mode 100644 index 0000000000..4ef76bdea1 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java @@ -0,0 +1,29 @@ +package sonia.scm.web; + +import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; + +import javax.inject.Inject; + +@Extension +public class GitPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory { + + private final ScmConfiguration configuration; + + @Inject + public GitPermissionFilterFactory(ScmConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public boolean handlesScmType(String type) { + return "git".equals(type); + } + + @Override + public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { + return new GitPermissionFilter(configuration, delegate); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index 2924a27915..073969ce91 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -14,8 +14,8 @@ import javax.inject.Singleton; @Extension public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public GitScmProtocolProviderWrapper(@Git Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { - super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); + public GitScmProtocolProviderWrapper(@Git Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, uriInfoStore, scmConfiguration); } @Override diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java index 8e7ff3d954..831402261b 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java @@ -5,6 +5,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.util.HttpUtil; import javax.servlet.ServletOutputStream; @@ -28,7 +29,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class GitPermissionFilterTest { - private final GitPermissionFilter permissionFilter = new GitPermissionFilter(new ScmConfiguration()); + private final GitPermissionFilter permissionFilter = new GitPermissionFilter(new ScmConfiguration(), mock(ScmProviderHttpServlet.class)); @Mock private HttpServletResponse response; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java index a2dccb30c9..7f92cc0357 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -34,8 +34,8 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; -import com.google.inject.Inject; import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -51,10 +51,9 @@ public class HgPermissionFilter extends PermissionFilter private static final Set READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE"); - @Inject - public HgPermissionFilter(ScmConfiguration configuration) + public HgPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { - super(configuration); + super(configuration, delegate); } @Override diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java new file mode 100644 index 0000000000..584a8113ab --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java @@ -0,0 +1,29 @@ +package sonia.scm.web; + +import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; + +import javax.inject.Inject; + +@Extension +public class HgPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory { + + private final ScmConfiguration configuration; + + @Inject + public HgPermissionFilterFactory(ScmConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public boolean handlesScmType(String type) { + return "hg".equals(type); + } + + @Override + public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { + return new HgPermissionFilter(configuration, delegate); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index 1d75e63332..fcd80a880c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -14,8 +14,8 @@ import javax.inject.Singleton; @Extension public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public HgScmProtocolProviderWrapper(@Hg Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { - super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); + public HgScmProtocolProviderWrapper(@Hg Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, uriInfoStore, scmConfiguration); } @Override diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java index 8918b8fa90..2c0a1e65ff 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java @@ -34,11 +34,11 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; -import com.google.inject.Inject; import sonia.scm.ClientMessages; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.ScmSvnErrorCode; import sonia.scm.repository.SvnUtil; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -65,10 +65,9 @@ public class SvnPermissionFilter extends PermissionFilter * * @param configuration */ - @Inject - public SvnPermissionFilter(ScmConfiguration configuration) + public SvnPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { - super(configuration); + super(configuration, delegate); } //~--- methods -------------------------------------------------------------- diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java new file mode 100644 index 0000000000..cd4a7600aa --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java @@ -0,0 +1,29 @@ +package sonia.scm.web; + +import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; + +import javax.inject.Inject; + +@Extension +public class SvnPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory { + + private final ScmConfiguration configuration; + + @Inject + public SvnPermissionFilterFactory(ScmConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public boolean handlesScmType(String type) { + return "svn".equals(type); + } + + @Override + public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { + return new SvnPermissionFilter(configuration, delegate); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index ed47791793..dbb8d5a84d 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -26,8 +26,8 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr } @Inject - public SvnScmProtocolProviderWrapper(@Svn Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { - super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); + public SvnScmProtocolProviderWrapper(@Svn Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, uriInfoStore, scmConfiguration); } @Override