From b17a23ddc8b138670ce241307a3c92a4030ed33b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 6 Jul 2017 10:13:11 +0200 Subject: [PATCH 001/178] added option to disallow non fast-forward git pushes --- .../java/sonia/scm/repository/GitConfig.java | 15 +- .../sonia/scm/web/GitReceivePackFactory.java | 76 +++--- .../main/resources/sonia/scm/git.config.js | 9 + .../scm/web/GitReceivePackFactoryTest.java | 117 +++++++++ .../sonia/scm/it/GitNonFastForwardITCase.java | 222 ++++++++++++++++++ 5 files changed, 390 insertions(+), 49 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitReceivePackFactoryTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/it/GitNonFastForwardITCase.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java index 80fe8907ac..26e49735eb 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfig.java @@ -51,9 +51,18 @@ public class GitConfig extends SimpleRepositoryConfig { @XmlElement(name = "gc-expression") private String gcExpression; - public String getGcExpression() - { + @XmlElement(name = "disallow-non-fast-forward") + private boolean nonFastForwardDisallowed; + + public String getGcExpression() { return gcExpression; } - + + public boolean isNonFastForwardDisallowed() { + return nonFastForwardDisallowed; + } + + public void setNonFastForwardDisallowed(boolean nonFastForwardDisallowed) { + this.nonFastForwardDisallowed = nonFastForwardDisallowed; + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitReceivePackFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitReceivePackFactory.java index 25bbe04cfc..5cb8007986 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitReceivePackFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitReceivePackFactory.java @@ -35,79 +35,63 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; - import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.ReceivePack; import org.eclipse.jgit.transport.resolver.ReceivePackFactory; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; - import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.spi.HookEventFacade; -//~--- JDK imports ------------------------------------------------------------ - import javax.servlet.http.HttpServletRequest; +//~--- JDK imports ------------------------------------------------------------ + /** + * GitReceivePackFactory creates {@link ReceivePack} objects and assigns the required + * Hook components. * * @author Sebastian Sdorra */ -public class GitReceivePackFactory - implements ReceivePackFactory +public class GitReceivePackFactory implements ReceivePackFactory { - /** - * Constructs ... - * - * - * - * @param hookEventFacade - * @param handler - */ + private final GitRepositoryHandler handler; + + private ReceivePackFactory wrapped; + + private final GitReceiveHook hook; + @Inject - public GitReceivePackFactory(HookEventFacade hookEventFacade, - GitRepositoryHandler handler) - { - hook = new GitReceiveHook(hookEventFacade, handler); + public GitReceivePackFactory(GitRepositoryHandler handler, HookEventFacade hookEventFacade) { + this.handler = handler; + this.hook = new GitReceiveHook(hookEventFacade, handler); + this.wrapped = new DefaultReceivePackFactory(); } - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param request - * @param repository - * - * @return - * - * @throws ServiceNotAuthorizedException - * @throws ServiceNotEnabledException - */ @Override public ReceivePack create(HttpServletRequest request, Repository repository) - throws ServiceNotEnabledException, ServiceNotAuthorizedException - { - ReceivePack rpack = defaultFactory.create(request, repository); + throws ServiceNotEnabledException, ServiceNotAuthorizedException { + ReceivePack receivePack = wrapped.create(request, repository); + receivePack.setAllowNonFastForwards(isNonFastForwardAllowed()); - rpack.setPreReceiveHook(hook); - rpack.setPostReceiveHook(hook); + receivePack.setPreReceiveHook(hook); + receivePack.setPostReceiveHook(hook); // apply collecting listener, to be able to check which commits are new - CollectingPackParserListener.set(rpack); + CollectingPackParserListener.set(receivePack); - return rpack; + return receivePack; } - //~--- fields --------------------------------------------------------------- + private boolean isNonFastForwardAllowed() { + return ! handler.getConfig().isNonFastForwardDisallowed(); + } - /** Field description */ - private DefaultReceivePackFactory defaultFactory = - new DefaultReceivePackFactory(); - - /** Field description */ - private GitReceiveHook hook; + @VisibleForTesting + void setWrapped(ReceivePackFactory wrapped) { + this.wrapped = wrapped; + } } diff --git a/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js index 9e038e4dee..b4cf4fdfc3 100644 --- a/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js +++ b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js @@ -37,6 +37,7 @@ Sonia.git.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, { titleText: 'Git Settings', repositoryDirectoryText: 'Repository directory', gcExpressionText: 'Git GC Cron Expression', + disallowNonFastForwardText: 'Disallow Non Fast-Forward', disabledText: 'Disabled', // helpTexts @@ -53,6 +54,8 @@ Sonia.git.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, { \n\

E.g.: To run the task on every sunday at two o\'clock in the morning: 0 0 2 ? * SUN

\n\

For more informations please have a look at Quartz CronTrigger

', + // TODO i18n + disallowNonFastForwardHelpText: 'Reject git pushes which are non fast-forward such as --force.', disabledHelpText: 'Enable or disable the Git plugin.\n\ Note you have to reload the page, after changing this value.', @@ -73,6 +76,12 @@ Sonia.git.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, { fieldLabel: this.gcExpressionText, helpText: this.gcExpressionHelpText, allowBlank : true + },{ + xtype: 'checkbox', + name: 'disallow-non-fast-forward', + fieldLabel: this.disallowNonFastForwardText, + inputValue: 'true', + helpText: this.disallowNonFastForwardHelpText },{ xtype: 'checkbox', name: 'disabled', diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitReceivePackFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitReceivePackFactoryTest.java new file mode 100644 index 0000000000..dc0822deba --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitReceivePackFactoryTest.java @@ -0,0 +1,117 @@ +/** + * 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; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.ReceivePack; +import org.eclipse.jgit.transport.resolver.ReceivePackFactory; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import sonia.scm.repository.GitConfig; +import sonia.scm.repository.GitRepositoryHandler; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.IOException; + +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + + +/** + * Unit tests for {@link GitReceivePackFactory}. + */ +@RunWith(MockitoJUnitRunner.class) +public class GitReceivePackFactoryTest { + + @Mock + private GitRepositoryHandler handler; + + private GitConfig config; + + @Mock + private ReceivePackFactory wrappedReceivePackFactory; + + private GitReceivePackFactory factory; + + @Mock + private HttpServletRequest request; + + private Repository repository; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void setUpObjectUnderTest() throws Exception { + this.repository = createRepositoryForTesting(); + + config = new GitConfig(); + when(handler.getConfig()).thenReturn(config); + + ReceivePack receivePack = new ReceivePack(repository); + when(wrappedReceivePackFactory.create(request, repository)).thenReturn(receivePack); + + factory = new GitReceivePackFactory(handler, null); + factory.setWrapped(wrappedReceivePackFactory); + } + + private Repository createRepositoryForTesting() throws GitAPIException, IOException { + File directory = temporaryFolder.newFolder(); + return Git.init().setDirectory(directory).call().getRepository(); + } + + @Test + public void testCreate() throws Exception { + ReceivePack receivePack = factory.create(request, repository); + assertThat(receivePack.getPackParserListener(), instanceOf(CollectingPackParserListener.class)); + assertThat(receivePack.getPreReceiveHook(), instanceOf(GitReceiveHook.class)); + assertThat(receivePack.getPostReceiveHook(), instanceOf(GitReceiveHook.class)); + assertTrue(receivePack.isAllowNonFastForwards()); + } + + @Test + public void testCreateWithDisabledNonFastForward() throws Exception { + config.setNonFastForwardDisallowed(true); + ReceivePack receivePack = factory.create(request, repository); + assertFalse(receivePack.isAllowNonFastForwards()); + } + +} diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitNonFastForwardITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitNonFastForwardITCase.java new file mode 100644 index 0000000000..351e9b7142 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/it/GitNonFastForwardITCase.java @@ -0,0 +1,222 @@ +/** + * 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.it; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import org.eclipse.jgit.api.CommitCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.PushResult; +import org.eclipse.jgit.transport.RemoteRefUpdate; +import org.eclipse.jgit.transport.RemoteRefUpdate.Status; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import sonia.scm.repository.GitConfig; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryTestData; +import sonia.scm.repository.client.api.RepositoryClientFactory; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static sonia.scm.it.IntegrationTestUtil.*; +import static sonia.scm.it.RepositoryITUtil.createRepository; +import static sonia.scm.it.RepositoryITUtil.deleteRepository; + +/** + * Integration Tests for Git with non fast-forward pushes. + */ +public class GitNonFastForwardITCase { + + private static final RepositoryClientFactory REPOSITORY_CLIENT_FACTORY = new RepositoryClientFactory(); + + private Client apiClient; + private Repository repository; + private File workingCopy; + private Git git; + + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + @Before + public void createAndCloneTestRepository() throws IOException, GitAPIException { + apiClient = createAdminClient(); + Repository testRepository = RepositoryTestData.createHeartOfGold("git"); + this.repository = createRepository(apiClient, testRepository); + this.workingCopy = tempFolder.newFolder(); + + String url = repository.createUrl(BASE_URL); + this.git = clone(url); + } + + @After + public void removeTestRepository() { + deleteRepository(apiClient, repository.getId()); + apiClient.destroy(); + } + + /** + * Ensures that the normal behaviour (non fast-forward is allowed), is restored after the tests are executed. + */ + @AfterClass + public static void allowNonFastForward() { + setNonFastForwardDisallowed(false); + } + + @Test + public void testGitPushAmendWithoutForce() throws IOException, GitAPIException { + setNonFastForwardDisallowed(false); + + addTestFileToWorkingCopyAndCommit("a"); + pushAndAssert(false, Status.OK); + + addTestFileToWorkingCopyAndCommitAmend("c"); + pushAndAssert(false, Status.REJECTED_NONFASTFORWARD); + } + + @Test + public void testGitPushAmendWithForce() throws IOException, GitAPIException { + setNonFastForwardDisallowed(false); + + addTestFileToWorkingCopyAndCommit("a"); + pushAndAssert(false, Status.OK); + + addTestFileToWorkingCopyAndCommitAmend("c"); + pushAndAssert(true, Status.OK); + } + + @Test + public void testGitPushAmendForceWithDisallowNonFastForward() throws GitAPIException, IOException { + setNonFastForwardDisallowed(true); + + addTestFileToWorkingCopyAndCommit("a"); + pushAndAssert(false, Status.OK); + + addTestFileToWorkingCopyAndCommitAmend("c"); + pushAndAssert(true, Status.REJECTED_OTHER_REASON); + + setNonFastForwardDisallowed(false); + } + + private CredentialsProvider createCredentialProvider() { + return new UsernamePasswordCredentialsProvider( + IntegrationTestUtil.ADMIN_USERNAME, IntegrationTestUtil.ADMIN_PASSWORD + ); + } + + private Git clone(String url) throws GitAPIException { + return Git.cloneRepository() + .setDirectory(workingCopy) + .setURI(url) + .setCredentialsProvider(createCredentialProvider()) + .call(); + } + + private void addTestFileToWorkingCopyAndCommit(String name) throws IOException, GitAPIException { + addTestFile(name); + prepareCommit() + .setMessage("added ".concat(name)) + .call(); + } + + private void addTestFile(String name) throws IOException, GitAPIException { + String filename = name.concat(".txt"); + Files.write(name, new File(workingCopy, filename), Charsets.UTF_8); + git.add().addFilepattern(filename).call(); + } + + private CommitCommand prepareCommit() { + return git.commit() + .setAuthor(IntegrationTestUtil.AUTHOR.getName(), IntegrationTestUtil.AUTHOR.getMail()); + } + + private void pushAndAssert(boolean force, Status expectedStatus) throws GitAPIException { + Iterable results = push(force); + assertStatus(results, expectedStatus); + } + + private Iterable push(boolean force) throws GitAPIException { + return git.push() + .setRemote("origin") + .add("master") + .setForce(force) + .setCredentialsProvider(createCredentialProvider()) + .call(); + } + + private void assertStatus(Iterable results, Status expectedStatus) { + for ( PushResult pushResult : results ) { + assertStatus(pushResult, expectedStatus); + } + } + + private void assertStatus(PushResult pushResult, Status expectedStatus) { + for ( RemoteRefUpdate remoteRefUpdate : pushResult.getRemoteUpdates() ) { + assertEquals(expectedStatus, remoteRefUpdate.getStatus()); + } + } + + private void addTestFileToWorkingCopyAndCommitAmend(String name) throws IOException, GitAPIException { + addTestFile(name); + prepareCommit() + .setMessage("amend commit, because of missing ".concat(name)) + .setAmend(true) + .call(); + } + + private static void setNonFastForwardDisallowed(boolean nonFastForwardDisallowed) { + Client adminClient = createAdminClient(); + try { + WebResource resource = createResource(adminClient, "config/repositories/git"); + GitConfig config = resource.get(GitConfig.class); + + assertNotNull(config); + config.setNonFastForwardDisallowed(nonFastForwardDisallowed); + + ClientResponse response = resource.post(ClientResponse.class, config); + assertNotNull(response); + assertEquals(201, response.getStatus()); + } finally { + adminClient.destroy(); + } + } + +} From 785e1b12a983e7bda627ca600268bf1fc69afa1a Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 7 Jul 2017 19:09:46 +0200 Subject: [PATCH 002/178] fixed update of git repositories with empty git default branch, see issue #903 --- .../scm-git-plugin/src/main/resources/sonia/scm/git.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js index b4cf4fdfc3..c15cef4444 100644 --- a/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js +++ b/scm-plugins/scm-git-plugin/src/main/resources/sonia/scm/git.config.js @@ -176,9 +176,9 @@ Sonia.git.GitSettingsFormPanel = Ext.extend(Sonia.repository.SettingsFormPanel, prepareUpdate: function(item) { if (item.defaultBranch) { var defaultBranch = item.defaultBranch; - delete item.defaultBranch; this.setDefaultBranch(item, defaultBranch); } + delete item.defaultBranch; } }); From f72648f646fc0ca229e2d1916e1e16a5f086b0ad Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 14 Aug 2017 16:04:30 +0200 Subject: [PATCH 003/178] fixes usage of named cache configurations, see issue #943 --- .../sonia/scm/cache/GuavaCacheManager.java | 19 +++++++--- .../scm/cache/GuavaCacheManagerTest.java | 38 ++++++++++++++++++- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/cache/GuavaCacheManager.java b/scm-webapp/src/main/java/sonia/scm/cache/GuavaCacheManager.java index fb112c0107..eb9f6d4891 100644 --- a/scm-webapp/src/main/java/sonia/scm/cache/GuavaCacheManager.java +++ b/scm-webapp/src/main/java/sonia/scm/cache/GuavaCacheManager.java @@ -78,15 +78,22 @@ public class GuavaCacheManager implements CacheManager, org.apache.shiro.cache.C protected GuavaCacheManager(GuavaCacheManagerConfiguration config) { defaultConfiguration = config.getDefaultCache(); - for (GuavaNamedCacheConfiguration ncc : config.getCaches()) { - logger.debug("create cache {} from configured configuration {}", ncc.getName(), ncc); - cacheMap.put(ncc.getName(), new CacheWithConfiguration( - GuavaCaches.create(defaultConfiguration, ncc.getName()), - defaultConfiguration) + for (GuavaNamedCacheConfiguration namedCacheConfiguration : config.getCaches()) { + logger.debug("create cache {} from configured configuration {}", + namedCacheConfiguration.getName(), namedCacheConfiguration ); + cacheMap.put(namedCacheConfiguration.getName(), createCacheWithConfiguration(namedCacheConfiguration)); } } + private CacheWithConfiguration createCacheWithConfiguration(GuavaNamedCacheConfiguration namedCacheConfiguration) { + return createCacheWithConfiguration(namedCacheConfiguration, namedCacheConfiguration.getName()); + } + + private CacheWithConfiguration createCacheWithConfiguration(GuavaCacheConfiguration configuration, String name) { + return new CacheWithConfiguration(GuavaCaches.create(configuration, name), configuration); + } + @Override public void close() throws IOException { logger.info("close guava cache manager"); @@ -110,7 +117,7 @@ public class GuavaCacheManager implements CacheManager, org.apache.shiro.cache.C "cache {} does not exists, creating a new instance from default configuration: {}", name, defaultConfiguration ); - cache = new CacheWithConfiguration(GuavaCaches.create(defaultConfiguration, name), defaultConfiguration); + cache = createCacheWithConfiguration(defaultConfiguration, name); cacheMap.put(name, cache); } diff --git a/scm-webapp/src/test/java/sonia/scm/cache/GuavaCacheManagerTest.java b/scm-webapp/src/test/java/sonia/scm/cache/GuavaCacheManagerTest.java index 3d91a56f40..be1848b303 100644 --- a/scm-webapp/src/test/java/sonia/scm/cache/GuavaCacheManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/cache/GuavaCacheManagerTest.java @@ -32,15 +32,33 @@ package sonia.scm.cache; +import com.google.common.collect.Lists; import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; /** * * @author Sebastian Sdorra */ +@RunWith(MockitoJUnitRunner.class) public class GuavaCacheManagerTest extends CacheManagerTestBase { + @Mock(answer = Answers.CALLS_REAL_METHODS) + private GuavaCacheConfiguration defaultConfiguration; + + @Mock(answer = Answers.CALLS_REAL_METHODS) + private GuavaNamedCacheConfiguration configuration; + /** * Method description * @@ -60,6 +78,24 @@ public class GuavaCacheManagerTest extends CacheManagerTestBase ((GuavaCache)c2).getWrappedCache() ); } - + + @Test + public void configuration() { + when(configuration.getName()).thenReturn("my-crazy-cache"); + when(configuration.getCopyStrategy()).thenReturn(CopyStrategy.READWRITE); + when(defaultConfiguration.getCopyStrategy()).thenReturn(CopyStrategy.READ); + + List configurations = Lists.newArrayList(configuration); + GuavaCacheManagerConfiguration managerConfiguration = new GuavaCacheManagerConfiguration(defaultConfiguration, configurations); + GuavaCacheManager guavaCacheManager = new GuavaCacheManager(managerConfiguration); + + // default cache + GuavaSecurityCache sorbotCache = guavaCacheManager.getCache("sorbot-cache"); + assertEquals(CopyStrategy.READ, sorbotCache.copyStrategy); + + // configured cache + GuavaSecurityCache crazyCache = guavaCacheManager.getCache("my-crazy-cache"); + assertEquals(CopyStrategy.READWRITE, crazyCache.copyStrategy); + } } From 14ee6ef0d6531514e9dd06f7ffb6eeffa5804f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Mon, 18 Sep 2017 12:30:20 +0000 Subject: [PATCH 004/178] prevent binary data in {extras} from interfering with UTF-8 decoding --- .../src/main/resources/sonia/scm/styles/changesets-eager.style | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style index 5c462fc459..e911bce7b2 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style @@ -1,5 +1,5 @@ header = "%{pattern}" -changeset = "{rev}:{node}{author}\n{date|hgdate}\n{branch}\n{parents}{join(extras,',')}\n{tags}{file_adds}{file_mods}{file_dels}\n{desc}\0" +changeset = "{rev}:{node}{author}\n{date|hgdate}\n{branch}\n{parents}close={if(get(extras, 'close'),1,0)}\n{tags}{file_adds}{file_mods}{file_dels}\n{desc}\0" tag = "t {tag}\n" file_add = "a {file_add}\n" file_mod = "m {file_mod}\n" From 77eea15417b8cf957f479a0cc6482b158ebbec70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Mon, 18 Sep 2017 12:34:50 +0000 Subject: [PATCH 005/178] oops... don't interpret "close=junk" as "close=1" --- .../src/main/resources/sonia/scm/styles/changesets-eager.style | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style index e911bce7b2..73b3ec694b 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style @@ -1,5 +1,5 @@ header = "%{pattern}" -changeset = "{rev}:{node}{author}\n{date|hgdate}\n{branch}\n{parents}close={if(get(extras, 'close'),1,0)}\n{tags}{file_adds}{file_mods}{file_dels}\n{desc}\0" +changeset = "{rev}:{node}{author}\n{date|hgdate}\n{branch}\n{parents}close={ifeq(get(extras, 'close'),1,1,0)}\n{tags}{file_adds}{file_mods}{file_dels}\n{desc}\0" tag = "t {tag}\n" file_add = "a {file_add}\n" file_mod = "m {file_mod}\n" From 241f41bb1c1bb63c7517f8b044f4b707d127b3ba Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 25 Oct 2017 14:21:38 +0200 Subject: [PATCH 006/178] update svnkit to version 1.9.0-scm1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e31fc9c77a..cbd36d28e0 100644 --- a/pom.xml +++ b/pom.xml @@ -425,7 +425,7 @@ v4.5.2.201704071617-r-scm1 - 1.8.15-scm1 + 1.9.0-scm1 15.0 From c75eb388d9fdd0db110238e1f2a2a6a91fc7df17 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 25 Oct 2017 15:02:28 +0200 Subject: [PATCH 007/178] update jgit to version v4.5.3.201708160445-r-scm1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cbd36d28e0..5f24b9c971 100644 --- a/pom.xml +++ b/pom.xml @@ -424,7 +424,7 @@ 1.3.0 - v4.5.2.201704071617-r-scm1 + v4.5.3.201708160445-r-scm1 1.9.0-scm1 From fd047c117094dd4114e6bfc2078536c4cb1d6719 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 2 Nov 2017 09:21:42 +0100 Subject: [PATCH 008/178] [maven-release-plugin] prepare release 1.55 --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-orientdb/pom.xml | 8 ++++---- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 24 ++++++++++++------------ support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 24 files changed, 76 insertions(+), 76 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index 86be4ebaed..ec44f15717 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm.maven scm-maven-plugins pom - 1.55-SNAPSHOT + 1.55 scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index da0c4192f0..09eafb1d25 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.55-SNAPSHOT + 1.55 sonia.scm.maven scm-maven-plugin - 1.55-SNAPSHOT + 1.55 maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 61cec4e20b..ff895ee8f2 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.55-SNAPSHOT + 1.55 sonia.scm.maven scm-plugin-archetype - 1.55-SNAPSHOT + 1.55 scm-plugin-archetype diff --git a/pom.xml b/pom.xml index 5f24b9c971..29f0f4a2c8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.55-SNAPSHOT + 1.55 The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - HEAD + 1.55 diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index d5264575e7..2647df0785 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm.clients scm-clients pom - 1.55-SNAPSHOT + 1.55 scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.55-SNAPSHOT + 1.55 shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 77a2be54a6..75d0bf4612 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.55-SNAPSHOT + 1.55 sonia.scm.clients scm-cli-client - 1.55-SNAPSHOT + 1.55 scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.55-SNAPSHOT + 1.55 diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index e002b8ff75..94c2458530 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.55-SNAPSHOT + 1.55 sonia.scm.clients scm-client-api jar - 1.55-SNAPSHOT + 1.55 scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 255232bc7b..73bbb7968a 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.55-SNAPSHOT + 1.55 sonia.scm.clients scm-client-impl jar - 1.55-SNAPSHOT + 1.55 scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.55-SNAPSHOT + 1.55 @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 3496d9ab01..9de00fdc3b 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.55-SNAPSHOT + 1.55 sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 scm-core diff --git a/scm-dao-orientdb/pom.xml b/scm-dao-orientdb/pom.xml index e89bb78811..4bb668c270 100644 --- a/scm-dao-orientdb/pom.xml +++ b/scm-dao-orientdb/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm scm-dao-orientdb - 1.55-SNAPSHOT + 1.55 scm-dao-orientdb @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 @@ -52,7 +52,7 @@ sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 test diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 79716b8b28..5b89e02908 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm scm-dao-xml - 1.55-SNAPSHOT + 1.55 scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index 1d3621b8ea..b3566a12ca 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.55-SNAPSHOT + 1.55 sonia.scm scm-plugin-backend war - 1.55-SNAPSHOT + 1.55 ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 4ef5f4bfbf..4ed96bb740 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm.plugins scm-plugins pom - 1.55-SNAPSHOT + 1.55 scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.55-SNAPSHOT + 1.55 process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 695bfba8fd..37e41bf951 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.55-SNAPSHOT + 1.55 sonia.scm.plugins scm-git-plugin - 1.55-SNAPSHOT + 1.55 scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index a9281ffb37..e5323432ea 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.55-SNAPSHOT + 1.55 sonia.scm.plugins scm-hg-plugin - 1.55-SNAPSHOT + 1.55 scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 555f50f3ed..ac05bf7aee 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.55-SNAPSHOT + 1.55 sonia.scm.plugins scm-svn-plugin - 1.55-SNAPSHOT + 1.55 scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index fd83551108..3c61624952 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm.samples scm-samples pom - 1.55-SNAPSHOT + 1.55 scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 71e7568e95..3a9fb18411 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.55-SNAPSHOT + 1.55 sonia.scm.sample scm-sample-auth - 1.55-SNAPSHOT + 1.55 scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 8afc4c768e..ffc8eb1171 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.55-SNAPSHOT + 1.55 sonia.scm.sample scm-sample-hello - 1.55-SNAPSHOT + 1.55 scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 diff --git a/scm-server/pom.xml b/scm-server/pom.xml index e2005c6fbe..365bddc038 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.55-SNAPSHOT + 1.55 sonia.scm scm-server - 1.55-SNAPSHOT + 1.55 scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 062e0f68f1..0a7c6f2047 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.55-SNAPSHOT + 1.55 sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 0d5629671c..ae0d5dffc7 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm scm-webapp war - 1.55-SNAPSHOT + 1.55 scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 sonia.scm scm-dao-xml - 1.55-SNAPSHOT + 1.55 sonia.scm.plugins scm-hg-plugin - 1.55-SNAPSHOT + 1.55 sonia.scm.plugins scm-svn-plugin - 1.55-SNAPSHOT + 1.55 sonia.scm.plugins scm-git-plugin - 1.55-SNAPSHOT + 1.55 @@ -285,7 +285,7 @@ sonia.scm scm-test - 1.55-SNAPSHOT + 1.55 test @@ -298,7 +298,7 @@ sonia.scm.plugins scm-git-plugin - 1.55-SNAPSHOT + 1.55 tests test @@ -306,7 +306,7 @@ sonia.scm.plugins scm-hg-plugin - 1.55-SNAPSHOT + 1.55 tests test @@ -314,7 +314,7 @@ sonia.scm.plugins scm-svn-plugin - 1.55-SNAPSHOT + 1.55 tests test @@ -558,7 +558,7 @@ sonia.scm scm-dao-orientdb - 1.55-SNAPSHOT + 1.55 diff --git a/support/pom.xml b/support/pom.xml index 3f770d8f3c..113345a8e4 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55-SNAPSHOT + 1.55 sonia.scm.support scm-support pom - 1.55-SNAPSHOT + 1.55 scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index 98eb9981c4..a2d0145870 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.55-SNAPSHOT + 1.55 sonia.scm scm-support-btrace - 1.55-SNAPSHOT + 1.55 jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.55-SNAPSHOT + 1.55 From cd9e07421c7a6432c13388db1081dfe66e6c94a8 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 2 Nov 2017 09:21:42 +0100 Subject: [PATCH 009/178] [maven-release-plugin] copy for tag 1.55 From 712c14f9107859dae3172da22a0e59db1619452d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 2 Nov 2017 09:21:42 +0100 Subject: [PATCH 010/178] [maven-release-plugin] prepare for next development iteration --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-orientdb/pom.xml | 8 ++++---- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 24 ++++++++++++------------ support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 24 files changed, 76 insertions(+), 76 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index ec44f15717..4a87db1f3f 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm.maven scm-maven-plugins pom - 1.55 + 1.56-SNAPSHOT scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 09eafb1d25..27cbcc990c 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.55 + 1.56-SNAPSHOT sonia.scm.maven scm-maven-plugin - 1.55 + 1.56-SNAPSHOT maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index ff895ee8f2..dae441ff10 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.55 + 1.56-SNAPSHOT sonia.scm.maven scm-plugin-archetype - 1.55 + 1.56-SNAPSHOT scm-plugin-archetype diff --git a/pom.xml b/pom.xml index 29f0f4a2c8..87a3ee5d95 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.55 + 1.56-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - 1.55 + HEAD diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 2647df0785..75f2ab16df 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm.clients scm-clients pom - 1.55 + 1.56-SNAPSHOT scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.55 + 1.56-SNAPSHOT shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 75d0bf4612..86f932cfb7 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.55 + 1.56-SNAPSHOT sonia.scm.clients scm-cli-client - 1.55 + 1.56-SNAPSHOT scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.55 + 1.56-SNAPSHOT diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index 94c2458530..83e7d3cd56 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.55 + 1.56-SNAPSHOT sonia.scm.clients scm-client-api jar - 1.55 + 1.56-SNAPSHOT scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 73bbb7968a..cfd2976f5a 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.55 + 1.56-SNAPSHOT sonia.scm.clients scm-client-impl jar - 1.55 + 1.56-SNAPSHOT scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.55 + 1.56-SNAPSHOT @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 9de00fdc3b..943bc636ad 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.55 + 1.56-SNAPSHOT sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT scm-core diff --git a/scm-dao-orientdb/pom.xml b/scm-dao-orientdb/pom.xml index 4bb668c270..a82df0638c 100644 --- a/scm-dao-orientdb/pom.xml +++ b/scm-dao-orientdb/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm scm-dao-orientdb - 1.55 + 1.56-SNAPSHOT scm-dao-orientdb @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT @@ -52,7 +52,7 @@ sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT test diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 5b89e02908..6199f7e630 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm scm-dao-xml - 1.55 + 1.56-SNAPSHOT scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index b3566a12ca..a8ff5f1bd6 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.55 + 1.56-SNAPSHOT sonia.scm scm-plugin-backend war - 1.55 + 1.56-SNAPSHOT ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 4ed96bb740..e626158205 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm.plugins scm-plugins pom - 1.55 + 1.56-SNAPSHOT scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.55 + 1.56-SNAPSHOT process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 37e41bf951..f79480f195 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.55 + 1.56-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.55 + 1.56-SNAPSHOT scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index e5323432ea..8a0c4a2364 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.55 + 1.56-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.55 + 1.56-SNAPSHOT scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index ac05bf7aee..70358bd4e7 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.55 + 1.56-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.55 + 1.56-SNAPSHOT scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 3c61624952..ddf81770e8 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm.samples scm-samples pom - 1.55 + 1.56-SNAPSHOT scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 3a9fb18411..72ebfa3e80 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.55 + 1.56-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.55 + 1.56-SNAPSHOT scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index ffc8eb1171..6c6720aec1 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.55 + 1.56-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.55 + 1.56-SNAPSHOT scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 365bddc038..69945271c7 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.55 + 1.56-SNAPSHOT sonia.scm scm-server - 1.55 + 1.56-SNAPSHOT scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 0a7c6f2047..989d3ef0b7 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.55 + 1.56-SNAPSHOT sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index ae0d5dffc7..a62edce4e1 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm scm-webapp war - 1.55 + 1.56-SNAPSHOT scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT sonia.scm scm-dao-xml - 1.55 + 1.56-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.55 + 1.56-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.55 + 1.56-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.55 + 1.56-SNAPSHOT @@ -285,7 +285,7 @@ sonia.scm scm-test - 1.55 + 1.56-SNAPSHOT test @@ -298,7 +298,7 @@ sonia.scm.plugins scm-git-plugin - 1.55 + 1.56-SNAPSHOT tests test @@ -306,7 +306,7 @@ sonia.scm.plugins scm-hg-plugin - 1.55 + 1.56-SNAPSHOT tests test @@ -314,7 +314,7 @@ sonia.scm.plugins scm-svn-plugin - 1.55 + 1.56-SNAPSHOT tests test @@ -558,7 +558,7 @@ sonia.scm scm-dao-orientdb - 1.55 + 1.56-SNAPSHOT diff --git a/support/pom.xml b/support/pom.xml index 113345a8e4..d2776bcb09 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.55 + 1.56-SNAPSHOT sonia.scm.support scm-support pom - 1.55 + 1.56-SNAPSHOT scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index a2d0145870..9f20f878bf 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.55 + 1.56-SNAPSHOT sonia.scm scm-support-btrace - 1.55 + 1.56-SNAPSHOT jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.55 + 1.56-SNAPSHOT From 5e6685260efd20b1c45b56d9205866fc37c090d9 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 19 Nov 2017 21:07:28 +0100 Subject: [PATCH 011/178] fix integer overflow of request with body larger than 4gb, see issue #953 --- .../sonia/scm/web/cgi/DefaultCGIExecutor.java | 58 +++++++++++-------- .../scm/web/cgi/DefaultCGIExecutorTest.java | 54 +++++++++++++++++ 2 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 scm-webapp/src/test/java/sonia/scm/web/cgi/DefaultCGIExecutorTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java index 3eaa684080..b442042480 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java +++ b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java @@ -35,6 +35,7 @@ package sonia.scm.web.cgi; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.common.io.ByteStreams; @@ -139,12 +140,6 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor apendOsEnvironment(env); } - // workaround for mercurial 2.1 - if (isContentLengthWorkaround()) - { - env.set(ENV_CONTENT_LENGTH, Integer.toString(request.getContentLength())); - } - if (workDirectory == null) { workDirectory = command.getParentFile(); @@ -304,26 +299,10 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor String uri = HttpUtil.removeMatrixParameter(request.getRequestURI()); String scriptName = uri.substring(0, uri.length() - pathInfo.length()); String scriptPath = context.getRealPath(scriptName); - int len = request.getContentLength(); EnvList env = new EnvList(); env.set(ENV_AUTH_TYPE, request.getAuthType()); - - /** - * Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined - * if there is no content, so we cannot put 0 or -1 in as per the - * Servlet API spec. - * - * see org.apache.catalina.servlets.CGIServlet - */ - if (len <= 0) - { - env.set(ENV_CONTENT_LENGTH, ""); - } - else - { - env.set(ENV_CONTENT_LENGTH, Integer.toString(len)); - } + env.set(ENV_CONTENT_LENGTH, createCGIContentLength(request, contentLengthWorkaround)); /** * Decode PATH_INFO @@ -383,6 +362,39 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor return env; } + /** + * Returns the content length as string in the cgi specific format. + * + * CGI spec says CONTENT_LENGTH must be NULL ("") or undefined + * if there is no content, so we cannot put 0 or -1 in as per the + * Servlet API spec. Some CGI applications require a content + * length environment variable, which is not null or empty + * (e.g. mercurial). For those application the disallowEmptyResults + * parameter should be used. + * + * @param disallowEmptyResults {@code true} to return -1 instead of an empty string + * + * @return content length as cgi specific string + */ + @VisibleForTesting + static String createCGIContentLength(HttpServletRequest request, boolean disallowEmptyResults) { + String cgiContentLength = disallowEmptyResults ? "-1" : ""; + + String contentLength = request.getHeader("Content-Length"); + if (!Strings.isNullOrEmpty(contentLength)) { + try { + long len = Long.parseLong(contentLength); + if (len > 0) { + cgiContentLength = String.valueOf(len); + } + } catch (NumberFormatException ex) { + logger.warn("received request with invalid content-length header value: {}", contentLength); + } + } + + return cgiContentLength; + } + /** * Method description * diff --git a/scm-webapp/src/test/java/sonia/scm/web/cgi/DefaultCGIExecutorTest.java b/scm-webapp/src/test/java/sonia/scm/web/cgi/DefaultCGIExecutorTest.java new file mode 100644 index 0000000000..29c7dea358 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/web/cgi/DefaultCGIExecutorTest.java @@ -0,0 +1,54 @@ +package sonia.scm.web.cgi; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import javax.servlet.http.HttpServletRequest; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +/** + * Unit tests for {@link DefaultCGIExecutor}. + */ +@RunWith(MockitoJUnitRunner.class) +public class DefaultCGIExecutorTest { + + @Mock + private HttpServletRequest request; + + @Test + public void testCreateCGIContentLength() { + when(request.getHeader("Content-Length")).thenReturn("42"); + assertEquals("42", DefaultCGIExecutor.createCGIContentLength(request, false)); + assertEquals("42", DefaultCGIExecutor.createCGIContentLength(request, true)); + } + + @Test + public void testCreateCGIContentLengthWithZeroLength() { + when(request.getHeader("Content-Length")).thenReturn("0"); + assertEquals("", DefaultCGIExecutor.createCGIContentLength(request, false)); + assertEquals("-1", DefaultCGIExecutor.createCGIContentLength(request, true)); + } + + @Test + public void testCreateCGIContentLengthWithoutContentLengthHeader() { + assertEquals("", DefaultCGIExecutor.createCGIContentLength(request, false)); + assertEquals("-1", DefaultCGIExecutor.createCGIContentLength(request, true)); + } + + @Test + public void testCreateCGIContentLengthWithLengthThatExeedsInteger() { + when(request.getHeader("Content-Length")).thenReturn("6314297259"); + assertEquals("6314297259", DefaultCGIExecutor.createCGIContentLength(request, false)); + } + + @Test + public void testCreateCGIContentLengthWithNonNumberHeader() { + when(request.getHeader("Content-Length")).thenReturn("abc"); + assertEquals("", DefaultCGIExecutor.createCGIContentLength(request, false)); + } + +} From 1b3e76e80902e0a2f3ddc3b3c4931a308e612d97 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 20 Nov 2017 17:01:10 +0100 Subject: [PATCH 012/178] close branch issue-953 From 2c5cd634b395aa7a2d6f997f9c0278fb622e351c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 15 Dec 2017 12:53:12 +0100 Subject: [PATCH 013/178] update svnkit to v1.9.0-scm2, to fix high cpu load after client connection abort. See Issue #939 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 87a3ee5d95..59be1739a0 100644 --- a/pom.xml +++ b/pom.xml @@ -423,9 +423,9 @@ 1.3.0 - + v4.5.3.201708160445-r-scm1 - 1.9.0-scm1 + 1.9.0-scm2 15.0 From 942cd5d190afcbb81fe86f0eff900530289ae33b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 15 Jan 2018 14:35:31 +0100 Subject: [PATCH 014/178] close branch issue-939 From f66221e5666b6f78f7de126f3ee352ba8f050bf2 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 15 Jan 2018 14:51:10 +0100 Subject: [PATCH 015/178] [maven-release-plugin] prepare release 1.56 --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-orientdb/pom.xml | 8 ++++---- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 24 ++++++++++++------------ support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 24 files changed, 76 insertions(+), 76 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index 4a87db1f3f..3469483fb6 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm.maven scm-maven-plugins pom - 1.56-SNAPSHOT + 1.56 scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 27cbcc990c..0e1b1b14b3 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.56-SNAPSHOT + 1.56 sonia.scm.maven scm-maven-plugin - 1.56-SNAPSHOT + 1.56 maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index dae441ff10..5f42c29187 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.56-SNAPSHOT + 1.56 sonia.scm.maven scm-plugin-archetype - 1.56-SNAPSHOT + 1.56 scm-plugin-archetype diff --git a/pom.xml b/pom.xml index 59be1739a0..46654071b7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.56-SNAPSHOT + 1.56 The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - HEAD + 1.56 diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 75f2ab16df..e6bc32ce2a 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm.clients scm-clients pom - 1.56-SNAPSHOT + 1.56 scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.56-SNAPSHOT + 1.56 shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 86f932cfb7..8622c2eb57 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.56-SNAPSHOT + 1.56 sonia.scm.clients scm-cli-client - 1.56-SNAPSHOT + 1.56 scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.56-SNAPSHOT + 1.56 diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index 83e7d3cd56..2258307116 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.56-SNAPSHOT + 1.56 sonia.scm.clients scm-client-api jar - 1.56-SNAPSHOT + 1.56 scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index cfd2976f5a..8e6512d90b 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.56-SNAPSHOT + 1.56 sonia.scm.clients scm-client-impl jar - 1.56-SNAPSHOT + 1.56 scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.56-SNAPSHOT + 1.56 @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 943bc636ad..8b75576551 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.56-SNAPSHOT + 1.56 sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 scm-core diff --git a/scm-dao-orientdb/pom.xml b/scm-dao-orientdb/pom.xml index a82df0638c..36bf7eb2d9 100644 --- a/scm-dao-orientdb/pom.xml +++ b/scm-dao-orientdb/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm scm-dao-orientdb - 1.56-SNAPSHOT + 1.56 scm-dao-orientdb @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 @@ -52,7 +52,7 @@ sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 test diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 6199f7e630..45a3c23557 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm scm-dao-xml - 1.56-SNAPSHOT + 1.56 scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index a8ff5f1bd6..1d6cfc527f 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.56-SNAPSHOT + 1.56 sonia.scm scm-plugin-backend war - 1.56-SNAPSHOT + 1.56 ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index e626158205..8922758bf1 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm.plugins scm-plugins pom - 1.56-SNAPSHOT + 1.56 scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.56-SNAPSHOT + 1.56 process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index f79480f195..45b67593da 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.56-SNAPSHOT + 1.56 sonia.scm.plugins scm-git-plugin - 1.56-SNAPSHOT + 1.56 scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 8a0c4a2364..1b3cea43e5 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.56-SNAPSHOT + 1.56 sonia.scm.plugins scm-hg-plugin - 1.56-SNAPSHOT + 1.56 scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 70358bd4e7..5a4512d3f0 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.56-SNAPSHOT + 1.56 sonia.scm.plugins scm-svn-plugin - 1.56-SNAPSHOT + 1.56 scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index ddf81770e8..1fff9e55e8 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm.samples scm-samples pom - 1.56-SNAPSHOT + 1.56 scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 72ebfa3e80..75aa38d045 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.56-SNAPSHOT + 1.56 sonia.scm.sample scm-sample-auth - 1.56-SNAPSHOT + 1.56 scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 6c6720aec1..ce559b808c 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.56-SNAPSHOT + 1.56 sonia.scm.sample scm-sample-hello - 1.56-SNAPSHOT + 1.56 scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 69945271c7..5c2eaeee2c 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.56-SNAPSHOT + 1.56 sonia.scm scm-server - 1.56-SNAPSHOT + 1.56 scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 989d3ef0b7..63ff7e8914 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.56-SNAPSHOT + 1.56 sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index a62edce4e1..93c83d643b 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm scm-webapp war - 1.56-SNAPSHOT + 1.56 scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 sonia.scm scm-dao-xml - 1.56-SNAPSHOT + 1.56 sonia.scm.plugins scm-hg-plugin - 1.56-SNAPSHOT + 1.56 sonia.scm.plugins scm-svn-plugin - 1.56-SNAPSHOT + 1.56 sonia.scm.plugins scm-git-plugin - 1.56-SNAPSHOT + 1.56 @@ -285,7 +285,7 @@ sonia.scm scm-test - 1.56-SNAPSHOT + 1.56 test @@ -298,7 +298,7 @@ sonia.scm.plugins scm-git-plugin - 1.56-SNAPSHOT + 1.56 tests test @@ -306,7 +306,7 @@ sonia.scm.plugins scm-hg-plugin - 1.56-SNAPSHOT + 1.56 tests test @@ -314,7 +314,7 @@ sonia.scm.plugins scm-svn-plugin - 1.56-SNAPSHOT + 1.56 tests test @@ -558,7 +558,7 @@ sonia.scm scm-dao-orientdb - 1.56-SNAPSHOT + 1.56 diff --git a/support/pom.xml b/support/pom.xml index d2776bcb09..fc7b4685ee 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56-SNAPSHOT + 1.56 sonia.scm.support scm-support pom - 1.56-SNAPSHOT + 1.56 scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index 9f20f878bf..cfe31439d8 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.56-SNAPSHOT + 1.56 sonia.scm scm-support-btrace - 1.56-SNAPSHOT + 1.56 jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.56-SNAPSHOT + 1.56 From f9a90508881cd8c21d3bf19da69fd24eb2a721e8 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 15 Jan 2018 14:51:11 +0100 Subject: [PATCH 016/178] [maven-release-plugin] copy for tag 1.56 From 0ff9b255c3fe32a47860ba58ec2b8ab7c51d797f Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 15 Jan 2018 14:51:11 +0100 Subject: [PATCH 017/178] [maven-release-plugin] prepare for next development iteration --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-orientdb/pom.xml | 8 ++++---- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 24 ++++++++++++------------ support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 24 files changed, 76 insertions(+), 76 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index 3469483fb6..c57712f36c 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm.maven scm-maven-plugins pom - 1.56 + 1.57-SNAPSHOT scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 0e1b1b14b3..09b02b5ddc 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.56 + 1.57-SNAPSHOT sonia.scm.maven scm-maven-plugin - 1.56 + 1.57-SNAPSHOT maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 5f42c29187..cfd9cb397a 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.56 + 1.57-SNAPSHOT sonia.scm.maven scm-plugin-archetype - 1.56 + 1.57-SNAPSHOT scm-plugin-archetype diff --git a/pom.xml b/pom.xml index 46654071b7..9b604a9bed 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.56 + 1.57-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - 1.56 + HEAD diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index e6bc32ce2a..ac6bc4cf8d 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm.clients scm-clients pom - 1.56 + 1.57-SNAPSHOT scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.56 + 1.57-SNAPSHOT shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 8622c2eb57..88f28abd34 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.56 + 1.57-SNAPSHOT sonia.scm.clients scm-cli-client - 1.56 + 1.57-SNAPSHOT scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.56 + 1.57-SNAPSHOT diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index 2258307116..fa15ca7f80 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.56 + 1.57-SNAPSHOT sonia.scm.clients scm-client-api jar - 1.56 + 1.57-SNAPSHOT scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 8e6512d90b..f64f8c4df3 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.56 + 1.57-SNAPSHOT sonia.scm.clients scm-client-impl jar - 1.56 + 1.57-SNAPSHOT scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.56 + 1.57-SNAPSHOT @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 8b75576551..84a0dfb909 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.56 + 1.57-SNAPSHOT sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT scm-core diff --git a/scm-dao-orientdb/pom.xml b/scm-dao-orientdb/pom.xml index 36bf7eb2d9..0bd256b5a7 100644 --- a/scm-dao-orientdb/pom.xml +++ b/scm-dao-orientdb/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm scm-dao-orientdb - 1.56 + 1.57-SNAPSHOT scm-dao-orientdb @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT @@ -52,7 +52,7 @@ sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT test diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 45a3c23557..55f94377ec 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm scm-dao-xml - 1.56 + 1.57-SNAPSHOT scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index 1d6cfc527f..d5dc4d16bc 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.56 + 1.57-SNAPSHOT sonia.scm scm-plugin-backend war - 1.56 + 1.57-SNAPSHOT ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 8922758bf1..af9d007ced 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm.plugins scm-plugins pom - 1.56 + 1.57-SNAPSHOT scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.56 + 1.57-SNAPSHOT process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 45b67593da..08411e9b61 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.56 + 1.57-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.56 + 1.57-SNAPSHOT scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 1b3cea43e5..d78d7d7dca 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.56 + 1.57-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.56 + 1.57-SNAPSHOT scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 5a4512d3f0..b2f5d180c7 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.56 + 1.57-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.56 + 1.57-SNAPSHOT scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 1fff9e55e8..f25c5d1ab6 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm.samples scm-samples pom - 1.56 + 1.57-SNAPSHOT scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 75aa38d045..c646497e3c 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.56 + 1.57-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.56 + 1.57-SNAPSHOT scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index ce559b808c..1f18d2bfb2 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.56 + 1.57-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.56 + 1.57-SNAPSHOT scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 5c2eaeee2c..6c486f36c2 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.56 + 1.57-SNAPSHOT sonia.scm scm-server - 1.56 + 1.57-SNAPSHOT scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 63ff7e8914..07f54c0249 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.56 + 1.57-SNAPSHOT sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 93c83d643b..524720b0ae 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm scm-webapp war - 1.56 + 1.57-SNAPSHOT scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT sonia.scm scm-dao-xml - 1.56 + 1.57-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.56 + 1.57-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.56 + 1.57-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.56 + 1.57-SNAPSHOT @@ -285,7 +285,7 @@ sonia.scm scm-test - 1.56 + 1.57-SNAPSHOT test @@ -298,7 +298,7 @@ sonia.scm.plugins scm-git-plugin - 1.56 + 1.57-SNAPSHOT tests test @@ -306,7 +306,7 @@ sonia.scm.plugins scm-hg-plugin - 1.56 + 1.57-SNAPSHOT tests test @@ -314,7 +314,7 @@ sonia.scm.plugins scm-svn-plugin - 1.56 + 1.57-SNAPSHOT tests test @@ -558,7 +558,7 @@ sonia.scm scm-dao-orientdb - 1.56 + 1.57-SNAPSHOT diff --git a/support/pom.xml b/support/pom.xml index fc7b4685ee..b531eb63f7 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.56 + 1.57-SNAPSHOT sonia.scm.support scm-support pom - 1.56 + 1.57-SNAPSHOT scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index cfe31439d8..26ca7cc43e 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.56 + 1.57-SNAPSHOT sonia.scm scm-support-btrace - 1.56 + 1.57-SNAPSHOT jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.56 + 1.57-SNAPSHOT From 9dd25b334a8059339eb30bdb46ad141fc9fe3e03 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 7 Feb 2018 11:24:53 +0100 Subject: [PATCH 018/178] treat update of a git tag as delete and create for hooks --- .../repository/api/GitHookTagProvider.java | 33 ++++++++++-- .../api/GitHookTagProviderTest.java | 54 ++++++++++++------- 2 files changed, 62 insertions(+), 25 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java index e7a75a0ff4..bcc2dc8a18 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java @@ -68,17 +68,40 @@ public class GitHookTagProvider implements HookTagProvider { if (Strings.isNullOrEmpty(tag)){ logger.debug("received ref name {} is not a tag", refName); - } else if (rc.getType() == ReceiveCommand.Type.CREATE) { - createdTagBuilder.add(new Tag(tag, GitUtil.getId(rc.getNewId()))); - } else if (rc.getType() == ReceiveCommand.Type.DELETE){ - deletedTagBuilder.add(new Tag(tag, GitUtil.getId(rc.getOldId()))); + } else if (isCreate(rc)) { + createdTagBuilder.add(createTagFromNewId(rc, tag)); + } else if (isDelete(rc)){ + deletedTagBuilder.add(createTagFromOldId(rc, tag)); + } else if (isUpdate(rc)) { + createdTagBuilder.add(createTagFromNewId(rc, tag)); + deletedTagBuilder.add(createTagFromOldId(rc, tag)); } } createdTags = createdTagBuilder.build(); deletedTags = deletedTagBuilder.build(); } - + + private Tag createTagFromNewId(ReceiveCommand rc, String tag) { + return new Tag(tag, GitUtil.getId(rc.getNewId())); + } + + private Tag createTagFromOldId(ReceiveCommand rc, String tag) { + return new Tag(tag, GitUtil.getId(rc.getOldId())); + } + + private boolean isUpdate(ReceiveCommand rc) { + return rc.getType() == ReceiveCommand.Type.UPDATE || rc.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD; + } + + private boolean isDelete(ReceiveCommand rc) { + return rc.getType() == ReceiveCommand.Type.DELETE; + } + + private boolean isCreate(ReceiveCommand rc) { + return rc.getType() == ReceiveCommand.Type.CREATE; + } + @Override public List getCreatedTags() { return createdTags; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java index 87e277b633..d18677885b 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java @@ -32,20 +32,23 @@ package sonia.scm.repository.api; import com.google.common.collect.Lists; -import java.util.List; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.transport.ReceiveCommand; -import org.junit.Test; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; -import static org.hamcrest.Matchers.*; import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.OngoingStubbing; import sonia.scm.repository.Tag; +import java.util.List; + +import static org.hamcrest.Matchers.empty; +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + /** * Unit tests for {@link GitHookTagProvider}. * @@ -54,6 +57,11 @@ import sonia.scm.repository.Tag; @RunWith(MockitoJUnitRunner.class) public class GitHookTagProviderTest { + private static final String ZERO = ObjectId.zeroId().getName(); + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Mock private ReceiveCommand command; @@ -73,7 +81,7 @@ public class GitHookTagProviderTest { @Test public void testGetCreatedTags() { String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/tags/1.0.0", revision); + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/tags/1.0.0", revision, ZERO); assertTag("1.0.0", revision, provider.getCreatedTags()); assertThat(provider.getDeletedTags(), empty()); @@ -85,7 +93,7 @@ public class GitHookTagProviderTest { @Test public void testGetDeletedTags() { String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - GitHookTagProvider provider = createProvider(ReceiveCommand.Type.DELETE, "refs/tags/1.0.0", revision); + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.DELETE, "refs/tags/1.0.0", ZERO, revision); assertThat(provider.getCreatedTags(), empty()); assertTag("1.0.0", revision, provider.getDeletedTags()); @@ -97,11 +105,24 @@ public class GitHookTagProviderTest { @Test public void testWithBranch(){ String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/heads/1.0.0", revision); + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/heads/1.0.0", revision, revision); assertThat(provider.getCreatedTags(), empty()); assertThat(provider.getDeletedTags(), empty()); } + + /** + * Tests {@link GitHookTagProvider} with update command. + */ + @Test + public void testUpdateTags() { + String newId = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; + String oldId = "e0f2be968b147ff7043684a7715d2fe852553db4"; + + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.UPDATE, "refs/tags/1.0.0", newId, oldId); + assertTag("1.0.0", newId, provider.getCreatedTags()); + assertTag("1.0.0", oldId, provider.getDeletedTags()); + } private void assertTag(String name, String revision, List tags){ assertNotNull(tags); @@ -112,19 +133,12 @@ public class GitHookTagProviderTest { assertEquals(revision, tag.getRevision()); } - private GitHookTagProvider createProvider(ReceiveCommand.Type type, String ref, String id){ - OngoingStubbing ongoing; - if (type == ReceiveCommand.Type.CREATE){ - ongoing = when(command.getNewId()); - } else { - ongoing = when(command.getOldId()); - } - ongoing.thenReturn(ObjectId.fromString(id)); - + private GitHookTagProvider createProvider(ReceiveCommand.Type type, String ref, String newId, String oldId){ + when(command.getNewId()).thenReturn(ObjectId.fromString(newId)); + when(command.getOldId()).thenReturn(ObjectId.fromString(oldId)); when(command.getType()).thenReturn(type); when(command.getRefName()).thenReturn(ref); - return new GitHookTagProvider(commands); } -} \ No newline at end of file +} From a8186a24926447807b4a75ef2f16c9cc9f701978 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 7 Feb 2018 15:19:20 +0100 Subject: [PATCH 019/178] update svnkit to version 1.9.0-scm3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9b604a9bed..d8ec7d24e5 100644 --- a/pom.xml +++ b/pom.xml @@ -425,7 +425,7 @@ v4.5.3.201708160445-r-scm1 - 1.9.0-scm2 + 1.9.0-scm3 15.0 From c216692eab43fa5fb32bc5a9c26b13e554648018 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 8 Feb 2018 22:36:54 +0100 Subject: [PATCH 020/178] #965 fixed handling of resources with spaces in its id --- .../it/JerseyGroupClientHandlerITCase.java | 25 ++++++- .../sonia/scm/url/RestModelUrlProvider.java | 4 +- .../scm/url/ModelUrlProviderTestBase.java | 4 +- .../scm/url/RestModelUrlProviderTestBase.java | 15 ++++ .../resources/AbstractManagerResource.java | 32 ++++----- .../AbstractManagerResourceTest.java | 71 +++++++++++++++++++ 6 files changed, 129 insertions(+), 22 deletions(-) create mode 100644 scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java diff --git a/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/JerseyGroupClientHandlerITCase.java b/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/JerseyGroupClientHandlerITCase.java index 0650564741..08899945ad 100644 --- a/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/JerseyGroupClientHandlerITCase.java +++ b/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/JerseyGroupClientHandlerITCase.java @@ -35,11 +35,14 @@ package sonia.scm.client.it; //~--- non-JDK imports -------------------------------------------------------- +import org.junit.Test; import sonia.scm.client.ClientHandler; +import sonia.scm.client.GroupClientHandler; import sonia.scm.client.JerseyClientSession; -import sonia.scm.client.it.AbstractClientHandlerTestBase.ModifyTest; import sonia.scm.group.Group; +import static sonia.scm.client.it.ClientTestUtil.createAdminSession; + /** * * @author Sebastian Sdorra @@ -99,4 +102,24 @@ public class JerseyGroupClientHandlerITCase { return new Group("xml", "group-" + number); } + + /** + * Tests crud operations with a group which name contains spaces. + * + * @see manager; + + @Test + public void testLocation() throws URISyntaxException { + URI base = new URI("https://scm.scm-manager.org/"); + + TestManagerResource resource = new TestManagerResource(manager); + when(uriInfo.getAbsolutePath()).thenReturn(base); + + URI uri = resource.location(uriInfo, "special-group"); + assertEquals(new URI("https://scm.scm-manager.org/groups/special-group"), uri); + } + + @Test + public void testLocationWithSpaces() throws URISyntaxException { + URI base = new URI("https://scm.scm-manager.org/"); + + TestManagerResource resource = new TestManagerResource(manager); + when(uriInfo.getAbsolutePath()).thenReturn(base); + + URI uri = resource.location(uriInfo, "Scm Special Group"); + assertEquals(new URI("https://scm.scm-manager.org/groups/Scm%20Special%20Group"), uri); + } + + private static class TestManagerResource extends AbstractManagerResource { + + private TestManagerResource(Manager manager) { + super(manager); + } + + @Override + protected GenericEntity> createGenericEntity(Collection items) { + return null; + } + + @Override + protected String getId(Group group) { + return group.getId(); + } + + @Override + protected String getPathPart() { + return "groups"; + } + } +} From 184b802992fe6791c3eea109fe37187f82be2db2 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 9 Feb 2018 07:59:17 +0100 Subject: [PATCH 021/178] close branch issue-965 From b64d41f3c95fcc0dba6d7e30d2b9bd06d90eac1a Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 9 Feb 2018 08:14:34 +0100 Subject: [PATCH 022/178] [maven-release-plugin] prepare release 1.57 --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-orientdb/pom.xml | 8 ++++---- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 24 ++++++++++++------------ support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 24 files changed, 76 insertions(+), 76 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index c57712f36c..e0222c1e3b 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm.maven scm-maven-plugins pom - 1.57-SNAPSHOT + 1.57 scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 09b02b5ddc..1b82cc2d25 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.57-SNAPSHOT + 1.57 sonia.scm.maven scm-maven-plugin - 1.57-SNAPSHOT + 1.57 maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index cfd9cb397a..e499a5670c 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.57-SNAPSHOT + 1.57 sonia.scm.maven scm-plugin-archetype - 1.57-SNAPSHOT + 1.57 scm-plugin-archetype diff --git a/pom.xml b/pom.xml index d8ec7d24e5..ec21f52813 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.57-SNAPSHOT + 1.57 The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - HEAD + 1.57 diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index ac6bc4cf8d..835186be15 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm.clients scm-clients pom - 1.57-SNAPSHOT + 1.57 scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.57-SNAPSHOT + 1.57 shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 88f28abd34..4a1d75c75d 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.57-SNAPSHOT + 1.57 sonia.scm.clients scm-cli-client - 1.57-SNAPSHOT + 1.57 scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.57-SNAPSHOT + 1.57 diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index fa15ca7f80..f3a091fc84 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.57-SNAPSHOT + 1.57 sonia.scm.clients scm-client-api jar - 1.57-SNAPSHOT + 1.57 scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index f64f8c4df3..222b1375ef 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.57-SNAPSHOT + 1.57 sonia.scm.clients scm-client-impl jar - 1.57-SNAPSHOT + 1.57 scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.57-SNAPSHOT + 1.57 @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 84a0dfb909..24a2897f31 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.57-SNAPSHOT + 1.57 sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 scm-core diff --git a/scm-dao-orientdb/pom.xml b/scm-dao-orientdb/pom.xml index 0bd256b5a7..b0c5cd275c 100644 --- a/scm-dao-orientdb/pom.xml +++ b/scm-dao-orientdb/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm scm-dao-orientdb - 1.57-SNAPSHOT + 1.57 scm-dao-orientdb @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 @@ -52,7 +52,7 @@ sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 test diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 55f94377ec..f7b223cfd8 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm scm-dao-xml - 1.57-SNAPSHOT + 1.57 scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index d5dc4d16bc..c287f16eec 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.57-SNAPSHOT + 1.57 sonia.scm scm-plugin-backend war - 1.57-SNAPSHOT + 1.57 ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index af9d007ced..5d4a8fd1ea 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm.plugins scm-plugins pom - 1.57-SNAPSHOT + 1.57 scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.57-SNAPSHOT + 1.57 process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 08411e9b61..6d47bfca08 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.57-SNAPSHOT + 1.57 sonia.scm.plugins scm-git-plugin - 1.57-SNAPSHOT + 1.57 scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index d78d7d7dca..dcd2dc5009 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.57-SNAPSHOT + 1.57 sonia.scm.plugins scm-hg-plugin - 1.57-SNAPSHOT + 1.57 scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index b2f5d180c7..363a7f223b 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.57-SNAPSHOT + 1.57 sonia.scm.plugins scm-svn-plugin - 1.57-SNAPSHOT + 1.57 scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index f25c5d1ab6..7c4017bfc8 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm.samples scm-samples pom - 1.57-SNAPSHOT + 1.57 scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index c646497e3c..40724f8d95 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.57-SNAPSHOT + 1.57 sonia.scm.sample scm-sample-auth - 1.57-SNAPSHOT + 1.57 scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 1f18d2bfb2..49c63d9653 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.57-SNAPSHOT + 1.57 sonia.scm.sample scm-sample-hello - 1.57-SNAPSHOT + 1.57 scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 6c486f36c2..7e5536b991 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.57-SNAPSHOT + 1.57 sonia.scm scm-server - 1.57-SNAPSHOT + 1.57 scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 07f54c0249..53d1ee0a6b 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.57-SNAPSHOT + 1.57 sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 524720b0ae..a58f8c3c3a 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm scm-webapp war - 1.57-SNAPSHOT + 1.57 scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 sonia.scm scm-dao-xml - 1.57-SNAPSHOT + 1.57 sonia.scm.plugins scm-hg-plugin - 1.57-SNAPSHOT + 1.57 sonia.scm.plugins scm-svn-plugin - 1.57-SNAPSHOT + 1.57 sonia.scm.plugins scm-git-plugin - 1.57-SNAPSHOT + 1.57 @@ -285,7 +285,7 @@ sonia.scm scm-test - 1.57-SNAPSHOT + 1.57 test @@ -298,7 +298,7 @@ sonia.scm.plugins scm-git-plugin - 1.57-SNAPSHOT + 1.57 tests test @@ -306,7 +306,7 @@ sonia.scm.plugins scm-hg-plugin - 1.57-SNAPSHOT + 1.57 tests test @@ -314,7 +314,7 @@ sonia.scm.plugins scm-svn-plugin - 1.57-SNAPSHOT + 1.57 tests test @@ -558,7 +558,7 @@ sonia.scm scm-dao-orientdb - 1.57-SNAPSHOT + 1.57 diff --git a/support/pom.xml b/support/pom.xml index b531eb63f7..6eecce15ee 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57-SNAPSHOT + 1.57 sonia.scm.support scm-support pom - 1.57-SNAPSHOT + 1.57 scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index 26ca7cc43e..d5ac090c27 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.57-SNAPSHOT + 1.57 sonia.scm scm-support-btrace - 1.57-SNAPSHOT + 1.57 jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.57-SNAPSHOT + 1.57 From c28824319762c7c818c4f09b37e73cfe688d38db Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 9 Feb 2018 08:14:34 +0100 Subject: [PATCH 023/178] [maven-release-plugin] copy for tag 1.57 From d21a28fa0b86506616438089dbf7525e52ccc7c2 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 9 Feb 2018 08:14:35 +0100 Subject: [PATCH 024/178] [maven-release-plugin] prepare for next development iteration --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-orientdb/pom.xml | 8 ++++---- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 24 ++++++++++++------------ support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 24 files changed, 76 insertions(+), 76 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index e0222c1e3b..d371d05c94 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm.maven scm-maven-plugins pom - 1.57 + 1.58-SNAPSHOT scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 1b82cc2d25..f6d85bf8cb 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.57 + 1.58-SNAPSHOT sonia.scm.maven scm-maven-plugin - 1.57 + 1.58-SNAPSHOT maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index e499a5670c..201664de81 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.57 + 1.58-SNAPSHOT sonia.scm.maven scm-plugin-archetype - 1.57 + 1.58-SNAPSHOT scm-plugin-archetype diff --git a/pom.xml b/pom.xml index ec21f52813..c888ababe8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.57 + 1.58-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - 1.57 + HEAD diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 835186be15..0e18675860 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm.clients scm-clients pom - 1.57 + 1.58-SNAPSHOT scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.57 + 1.58-SNAPSHOT shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 4a1d75c75d..1d26cee2b4 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.57 + 1.58-SNAPSHOT sonia.scm.clients scm-cli-client - 1.57 + 1.58-SNAPSHOT scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.57 + 1.58-SNAPSHOT diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index f3a091fc84..75ac3d81d7 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.57 + 1.58-SNAPSHOT sonia.scm.clients scm-client-api jar - 1.57 + 1.58-SNAPSHOT scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 222b1375ef..e97a96e380 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.57 + 1.58-SNAPSHOT sonia.scm.clients scm-client-impl jar - 1.57 + 1.58-SNAPSHOT scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.57 + 1.58-SNAPSHOT @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 24a2897f31..732c0fa4d6 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.57 + 1.58-SNAPSHOT sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT scm-core diff --git a/scm-dao-orientdb/pom.xml b/scm-dao-orientdb/pom.xml index b0c5cd275c..c708a12cba 100644 --- a/scm-dao-orientdb/pom.xml +++ b/scm-dao-orientdb/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm scm-dao-orientdb - 1.57 + 1.58-SNAPSHOT scm-dao-orientdb @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT @@ -52,7 +52,7 @@ sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT test diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index f7b223cfd8..a6f7898246 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm scm-dao-xml - 1.57 + 1.58-SNAPSHOT scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index c287f16eec..bc59a101a8 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.57 + 1.58-SNAPSHOT sonia.scm scm-plugin-backend war - 1.57 + 1.58-SNAPSHOT ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 5d4a8fd1ea..e11e11ebde 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm.plugins scm-plugins pom - 1.57 + 1.58-SNAPSHOT scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.57 + 1.58-SNAPSHOT process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 6d47bfca08..60c617cfd1 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.57 + 1.58-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.57 + 1.58-SNAPSHOT scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index dcd2dc5009..e4cfa7d6f2 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.57 + 1.58-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.57 + 1.58-SNAPSHOT scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 363a7f223b..0be176d42c 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.57 + 1.58-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.57 + 1.58-SNAPSHOT scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 7c4017bfc8..22e4b9cc04 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm.samples scm-samples pom - 1.57 + 1.58-SNAPSHOT scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 40724f8d95..05ec3fddd9 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.57 + 1.58-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.57 + 1.58-SNAPSHOT scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 49c63d9653..f896257930 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.57 + 1.58-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.57 + 1.58-SNAPSHOT scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 7e5536b991..50c77d05fd 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.57 + 1.58-SNAPSHOT sonia.scm scm-server - 1.57 + 1.58-SNAPSHOT scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 53d1ee0a6b..3f769f3367 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.57 + 1.58-SNAPSHOT sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index a58f8c3c3a..775b75525a 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm scm-webapp war - 1.57 + 1.58-SNAPSHOT scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT sonia.scm scm-dao-xml - 1.57 + 1.58-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.57 + 1.58-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.57 + 1.58-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.57 + 1.58-SNAPSHOT @@ -285,7 +285,7 @@ sonia.scm scm-test - 1.57 + 1.58-SNAPSHOT test @@ -298,7 +298,7 @@ sonia.scm.plugins scm-git-plugin - 1.57 + 1.58-SNAPSHOT tests test @@ -306,7 +306,7 @@ sonia.scm.plugins scm-hg-plugin - 1.57 + 1.58-SNAPSHOT tests test @@ -314,7 +314,7 @@ sonia.scm.plugins scm-svn-plugin - 1.57 + 1.58-SNAPSHOT tests test @@ -558,7 +558,7 @@ sonia.scm scm-dao-orientdb - 1.57 + 1.58-SNAPSHOT diff --git a/support/pom.xml b/support/pom.xml index 6eecce15ee..9db5842b99 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.57 + 1.58-SNAPSHOT sonia.scm.support scm-support pom - 1.57 + 1.58-SNAPSHOT scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index d5ac090c27..28b1febe75 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.57 + 1.58-SNAPSHOT sonia.scm scm-support-btrace - 1.57 + 1.58-SNAPSHOT jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.57 + 1.58-SNAPSHOT From 7d94b03a0430e98933b1bb9d6f82863adb1fa1f7 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 23 Feb 2018 08:44:22 +0100 Subject: [PATCH 025/178] #959 added option to disable ssl validation for scm mercurial hook --- .../main/java/sonia/scm/repository/HgConfig.java | 14 ++++++++++++++ .../src/main/java/sonia/scm/web/HgCGIServlet.java | 12 +++++++++++- .../src/main/resources/sonia/scm/hg.config.js | 13 ++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java index b9bd650925..ed336ff203 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java @@ -123,6 +123,10 @@ public class HgConfig extends SimpleRepositoryConfig return useOptimizedBytecode; } + public boolean isDisableHookSSLValidation() { + return disableHookSSLValidation; + } + /** * Method description * @@ -204,6 +208,10 @@ public class HgConfig extends SimpleRepositoryConfig this.useOptimizedBytecode = useOptimizedBytecode; } + public void setDisableHookSSLValidation(boolean disableHookSSLValidation) { + this.disableHookSSLValidation = disableHookSSLValidation; + } + //~--- fields --------------------------------------------------------------- /** Field description */ @@ -223,4 +231,10 @@ public class HgConfig extends SimpleRepositoryConfig /** Field description */ private boolean showRevisionInId = false; + + /** + * disable validation of ssl certificates for mercurial hook + * @see Issue 959 + */ + private boolean disableHookSSLValidation = false; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 4ba165c630..f6023dd0ae 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -63,6 +63,7 @@ import java.io.File; import java.io.IOException; import java.util.Enumeration; +import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -78,6 +79,8 @@ import javax.servlet.http.HttpSession; public class HgCGIServlet extends HttpServlet { + private static final String ENV_PYTHON_HTTPS_VERIFY = "PYTHONHTTPSVERIFY"; + /** Field description */ public static final String ENV_REPOSITORY_NAME = "REPO_NAME"; @@ -268,9 +271,16 @@ public class HgCGIServlet extends HttpServlet directory.getAbsolutePath()); // add hook environment + Map environment = executor.getEnvironment().asMutableMap(); + if (handler.getConfig().isDisableHookSSLValidation()) { + // disable ssl validation + // Issue 959: https://goo.gl/zH5eY8 + environment.put(ENV_PYTHON_HTTPS_VERIFY, "0"); + } + //J- HgEnvironment.prepareEnvironment( - executor.getEnvironment().asMutableMap(), + environment, handler, hookManager, request diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js index f8aa46e0a8..58a73ea8e9 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js @@ -46,6 +46,8 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { encodingText: 'Encoding', disabledText: 'Disabled', showRevisionInIdText: 'Show Revision', + // TODO: i18n + disableHookSSLValidationText: 'Disable SSL Validation on Hooks', // helpText hgBinaryHelpText: 'Location of Mercurial binary.', @@ -58,6 +60,9 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { Note you have to reload the page, after changing this value.', showRevisionInIdHelpText: 'Show revision as part of the node id. Note: \n\ You have to restart the ApplicationServer to affect cached changesets.', + // TODO: i18n + disableHookSSLValidationHelpText: 'Disables the validation of ssl certificates for the mercurial hook, which forwards the repository changes back to scm-manager. \n\ + This option should only be used, if SCM-Manager uses a self signed certificate.', initComponent: function(){ @@ -104,6 +109,12 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { fieldLabel: this.showRevisionInIdText, inputValue: 'true', helpText: this.showRevisionInIdHelpText + },{ + xtype: 'checkbox', + name: 'disableHookSSLValidation', + fieldLabel: this.disableHookSSLValidationText, + inputValue: 'true', + helpText: this.disableHookSSLValidationHelpText },{ xtype: 'checkbox', name: 'disabled', @@ -284,4 +295,4 @@ Ext.override(Sonia.repository.ChangesetViewerGrid, { return parents; } -}); \ No newline at end of file +}); From d8889298135e6f78b99204a89e585da63ea4fb48 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 9 Mar 2018 08:34:24 +0100 Subject: [PATCH 026/178] close branch issue-959 From e7dd54c1336a44c146e98c40585c6a2d469e82cc Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 29 Mar 2018 10:21:34 +0200 Subject: [PATCH 027/178] #970 added ngrep dumps for mercurial wire protocol and more realistic tests for isWriteRequest --- docs/mercurial/clone-empty.md | 74 +++++++ docs/mercurial/push-bookmark.md | 115 +++++++++++ .../push-multiple-branches-to-new.md | 165 ++++++++++++++++ docs/mercurial/push-multiple-branches.md | 181 ++++++++++++++++++ docs/mercurial/push-single-changeset.md | 146 ++++++++++++++ .../sonia/scm/web/HgPermissionFilterTest.java | 95 ++++++++- .../web/WireProtocolRequestMockFactory.java | 101 ++++++++++ 7 files changed, 872 insertions(+), 5 deletions(-) create mode 100644 docs/mercurial/clone-empty.md create mode 100644 docs/mercurial/push-bookmark.md create mode 100644 docs/mercurial/push-multiple-branches-to-new.md create mode 100644 docs/mercurial/push-multiple-branches.md create mode 100644 docs/mercurial/push-single-changeset.md create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java diff --git a/docs/mercurial/clone-empty.md b/docs/mercurial/clone-empty.md new file mode 100644 index 0000000000..810a297806 --- /dev/null +++ b/docs/mercurial/clone-empty.md @@ -0,0 +1,74 @@ +# Clone empty repository + +GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. +Accept-Encoding: identity. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1efk0qxy1dj5v133hev91zwsf4;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 130. +Server: Jetty(7.6.21.v20160908). +. +lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=bookmarks. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1rsxj8u1rq9wizawhyyxok2p5;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 0. +Server: Jetty(7.6.21.v20160908). + +GET /scm/hg/hgtest?cmd=batch HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: cmds=heads+%3Bknown+nodes%3D. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=ewyx4m53d8dajjsob6gxobne;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 42. +Server: Jetty(7.6.21.v20160908). + +0000000000000000000000000000000000000000 +; + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1o0hou15jtiywsywutf30qwm8;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 15. +Server: Jetty(7.6.21.v20160908). +. +publishing.True diff --git a/docs/mercurial/push-bookmark.md b/docs/mercurial/push-bookmark.md new file mode 100644 index 0000000000..110bd40cd5 --- /dev/null +++ b/docs/mercurial/push-bookmark.md @@ -0,0 +1,115 @@ +# Push bookmark + +GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. +Accept-Encoding: identity. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=7rq9vpp9svfm1sicq7h9vetmv;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 130. +Server: Jetty(7.6.21.v20160908). + +lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 + +GET /scm/hg/hgtest?cmd=batch HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +T 172.17.0.2:8080 -> 172.17.0.1:36576 [AP] +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1553csz4sf7scyvw8mqnqfirn;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 43. +Server: Jetty(7.6.21.v20160908). + +ef5993bb4abb32a0565c347844c6d939fc4f4b98 +;1 + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=11xa5u3nrmx8k1nar3sazg6jzh;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 15. +Server: Jetty(7.6.21.v20160908). + +publishing.True + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=bookmarks. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1p1uzcvfe1pvzh2buzo658rxw;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 0. +Server: Jetty(7.6.21.v20160908). + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1mhlj3ucfzdp6ifmzoua4zwit;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 15. +Server: Jetty(7.6.21.v20160908). + +publishing.True + +POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1. +Accept-Encoding: identity. +content-type: application/mercurial-0.1. +vary: X-HgArg-1. +x-hgarg-1: key=markone&namespace=bookmarks&new=ef5993bb4abb32a0565c347844c6d939fc4f4b98&old=. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +content-length: 0. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=s4vtagb303dv1xg809wnp7e8z;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 2. +Server: Jetty(7.6.21.v20160908). +. +1 diff --git a/docs/mercurial/push-multiple-branches-to-new.md b/docs/mercurial/push-multiple-branches-to-new.md new file mode 100644 index 0000000000..56c3a4504a --- /dev/null +++ b/docs/mercurial/push-multiple-branches-to-new.md @@ -0,0 +1,165 @@ +# Push multiple branches to new repository + +GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. +Accept-Encoding: identity. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1wu06ykfd4bcv1uv731y4hss2m;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 130. +Server: Jetty(7.6.21.v20160908). + +lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 + +GET /scm/hg/hgtest?cmd=batch HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1rajglvqx222g5nppcq3jdfk0;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 43. +Server: Jetty(7.6.21.v20160908). + +0000000000000000000000000000000000000000 +;0 + +GET /scm/hg/hgtest?cmd=known HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: nodes=c0ceccb3b2f0f5c977ff32b9337519e5f37942c2+187ddf37e237c370514487a0bb1a226f11a780b3+b5914611f84eae14543684b2721eec88b0edac12+8b63a323606f10c86b30465570c2574eb7a3a989. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=a5vykp1f0ga2186l8v3gu6lid;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 4. +Server: Jetty(7.6.21.v20160908). + +0000 + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=s8lpwqm4c2nqs9kwcg2ca6vm;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 15. +Server: Jetty(7.6.21.v20160908). + +publishing.True + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=bookmarks. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1d2qj3kynxlhvk31oli4kk7vf;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 0. +Server: Jetty(7.6.21.v20160908). + +POST /scm/hg/hgtest?cmd=unbundle HTTP/1.1. +Accept-Encoding: identity. +content-type: application/mercurial-0.1. +vary: X-HgArg-1. +x-hgarg-1: heads=686173686564+6768033e216468247bd031a0a2d9876d79818f8f. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +content-length: 913. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HG10GZx...oh.U......E.1.....2q.<...s.1.YK*e#..b..{....{..%A..... +,\.....Y.XV....Q/J......`Q/.z.{...<.7....r.s.~?.?..5.~`..?..........O.j.0.....Ih.....!@.P... ..a +;!y..cT...]q.8Zg=...<..,.tq.*.........l........';..w^...w...-......Co..Fs.HYg... +9.F#.P......1..;......D.H.9$@.^....r:E..18...H....3..h...-.=.6l......=q .)."Yg..p\...s@.#.H.*....c8&96..2.GjJ.`.J....r...=Q1..@R.3.o{q...|.......yq.k..,cY..:[... ...S.2...VYp..c5..&.SFR.............V.d..o..........,.. A..M....k...0_.LO1..1"4.;...B....5.9.".U.m.e......]\../p..;?C..W9.........n.~o..gW...Q;..$....S..X.CN.5I].H..!.@...U..J...L.lY.../.-...6.:.Q.'...>.e'..<#3........OL}.52ra[..g*Y:Y....w...=..Z\...S.......tz..;..mf...W......&yUN.r.......4...........`..F...nT..U9................_.~..?...BwzUN.r....B. + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=163487i0ayf9s1k2ng9e1azadj;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 102. +Server: Jetty(7.6.21.v20160908). + +1 +adding changesets +adding manifests +adding file changes +added 5 changesets with 3 changes to 3 files + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=a3i712yjss6t1xsxltnssq0tl;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 58. +Server: Jetty(7.6.21.v20160908). + +c0ceccb3b2f0f5c977ff32b9337519e5f37942c2.1 +publishing.True + +POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1. +Accept-Encoding: identity. +content-type: application/mercurial-0.1. +vary: X-HgArg-1. +x-hgarg-1: key=ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +content-length: 0. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=g8cavdze42d83knmuasrlg10;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 2. +Server: Jetty(7.6.21.v20160908). +. +1 diff --git a/docs/mercurial/push-multiple-branches.md b/docs/mercurial/push-multiple-branches.md new file mode 100644 index 0000000000..7d38542fde --- /dev/null +++ b/docs/mercurial/push-multiple-branches.md @@ -0,0 +1,181 @@ +# Push multiple branches + +GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. +Accept-Encoding: identity. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1mvm1rxg8333iib7754ksusxc;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 130. +Server: Jetty(7.6.21.v20160908). + +lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 + +GET /scm/hg/hgtest?cmd=batch HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=58p9y9vcnz5cjs22dtw8mpwk;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 43. +Server: Jetty(7.6.21.v20160908). + +c0ceccb3b2f0f5c977ff32b9337519e5f37942c2 +;0 + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=v5wfwj8k4t261dp6808cdouoa;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 15. +Server: Jetty(7.6.21.v20160908). + +publishing.True + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=bookmarks. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=3pgqytfhm4za1dco9p41j9yz5;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 0. +Server: Jetty(7.6.21.v20160908). + +GET /scm/hg/hgtest?cmd=branchmap HTTP/1.1. +Accept-Encoding: identity. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). +. + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1tiz6zf7ui54e1j3d4vouxig5m;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 48. +Server: Jetty(7.6.21.v20160908). + +default c0ceccb3b2f0f5c977ff32b9337519e5f37942c2 + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=bookmarks. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1augu4tc71xax1dit20dtxzkez;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 0. +Server: Jetty(7.6.21.v20160908). + +POST /scm/hg/hgtest?cmd=unbundle HTTP/1.1. +Accept-Encoding: identity. +content-type: application/mercurial-0.1. +vary: X-HgArg-1. +x-hgarg-1: heads=686173686564+95373ca7cd5371cb6c49bb755ee451d9ec585845. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +content-length: 746. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HG10GZx...]H.Q...z..r.,.Y..Bw.~..c.Z&...hf.:......e.XK.X,... +,2.E1.B+...(.B"."*..z1.*......M...........93..k|..I..<...h..J_.L.9>.h..@.....op..^.....#....;.*..W....T@....!..dY....jT..A0O6.}..S.2..JPU.O6...aa...rY.VOf9.....7Ukj.&..<...z...j......%}..Jc.8c....k.."9.&".I.P.\..$.At......0..1..g.2.)<..$.. E..dn#....#.Y$3...n...5....J.e.......SNHN.q.MD..4..."I..`PF..?GH1..F..uES..Rl$47.....a........D.1...87.k.t..D..O_.3..6'cN.w.M..|@E.).X!.h*....U.B.X.....h..$.`4... +-..O.:./..oWN.....3...x.L......_[..../..k.R$.x.2..kkv.\2R....4...@.2...1Q..T +..(..m....s.Uo.......{.d.....Y....TYO...S.Pl`a5. ."N$.@...b...qJ.l.).n...1..F.Zy.....&>v;.q.....Jy..X.?.;....>U..|.....d.Y.*.q...NR.3...h.T..x..,.]...p{.^S.S...~..`..q.\j{.oCI.............K.....l9n.s...... + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1e4fnqpncil9z1f7a2pya26nt7;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 102. +Server: Jetty(7.6.21.v20160908). + +1 +adding changesets +adding manifests +adding file changes +added 4 changesets with 2 changes to 2 files + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=f9hvrjssniym1qe33q0u8r2m8;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 101. +Server: Jetty(7.6.21.v20160908). + +b5914611f84eae14543684b2721eec88b0edac12.1 +187ddf37e237c370514487a0bb1a226f11a780b3.1 +publishing.True + +POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1. +Accept-Encoding: identity. +content-type: application/mercurial-0.1. +vary: X-HgArg-1. +x-hgarg-1: key=ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +content-length: 0. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=z5lrut6940a650sw6x9bls8a;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 2. +Server: Jetty(7.6.21.v20160908). + +1 diff --git a/docs/mercurial/push-single-changeset.md b/docs/mercurial/push-single-changeset.md new file mode 100644 index 0000000000..19b13c1dcd --- /dev/null +++ b/docs/mercurial/push-single-changeset.md @@ -0,0 +1,146 @@ +# Push single changeset + +GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. +Accept-Encoding: identity. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=18r2i2jsba46d14ncsmcjdhaem;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 130. +Server: Jetty(7.6.21.v20160908). + +lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 + +GET /scm/hg/hgtest?cmd=batch HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: cmds=heads+%3Bknown+nodes%3Dc0ceccb3b2f0f5c977ff32b9337519e5f37942c2. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=1fw0i0c5zpy281gfgha0f26git;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 43. +Server: Jetty(7.6.21.v20160908). + +0000000000000000000000000000000000000000 +;0 + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=dfa46uaqgf39w3jhk857oymu;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 15. +Server: Jetty(7.6.21.v20160908). + +publishing.True + +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=bookmarks. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=2sk1llvrsagg33xgmwyirfpi;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 0. +Server: Jetty(7.6.21.v20160908). + +POST /scm/hg/hgtest?cmd=unbundle HTTP/1.1. +Accept-Encoding: identity. +content-type: application/mercurial-0.1. +vary: X-HgArg-1. +x-hgarg-1: heads=686173686564+6768033e216468247bd031a0a2d9876d79818f8f. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +content-length: 261. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HG10GZx.c``8w.....>|=Y..h.q.....N.......%......Z....&&&.&...YZ.&.&[$.........$.%q..&%..d&.).....%*.....Y.....9z...v\..FF...... +..F..\.z%.%\\.)).) +.P[....D..[un..L).nc..q.m*.H.l#C...eZJ..YJ.Q.qR...e.aJ.EjjJ.AZ..A.Q..E.1.T.'D..C....7s.}..4G........3.S.mL.0.....zk + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=hlucs5utn1ifnpehqmjpt593;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 102. +Server: Jetty(7.6.21.v20160908). + +1 +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files + +T 172.17.0.1:33206 -> 172.17.0.2:8080 [AP] +GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1. +Accept-Encoding: identity. +vary: X-HgArg-1. +x-hgarg-1: namespace=phases. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=15xomlrxl8qja1cj47rjpqda0y;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 58. +Server: Jetty(7.6.21.v20160908). + +c0ceccb3b2f0f5c977ff32b9337519e5f37942c2.1 +publishing.True + +POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1. +Accept-Encoding: identity. +content-type: application/mercurial-0.1. +vary: X-HgArg-1. +x-hgarg-1: key=c0ceccb3b2f0f5c977ff32b9337519e5f37942c2&namespace=phases&new=0&old=1. +accept: application/mercurial-0.1. +authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=. +content-length: 0. +host: localhost:8080. +user-agent: mercurial/proto-1.0 (Mercurial 4.3.1). + +HTTP/1.1 200 OK. +Set-Cookie: JSESSIONID=5zrop5v8e661ipk12tvru525;Path=/scm. +Expires: Thu, 01 Jan 1970 00:00:00 GMT. +Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT. +Content-Type: application/mercurial-0.1. +Content-Length: 2. +Server: Jetty(7.6.21.v20160908). + +1 + diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java index 01e01cf302..05250c8cf9 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java @@ -39,6 +39,9 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import static org.mockito.Mockito.*; +import static sonia.scm.web.WireProtocolRequestMockFactory.CMDS_HEADS_KNOWN_NODES; +import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.*; + import org.mockito.runners.MockitoJUnitRunner; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.RepositoryProvider; @@ -51,15 +54,14 @@ import sonia.scm.repository.RepositoryProvider; @RunWith(MockitoJUnitRunner.class) public class HgPermissionFilterTest { - @Mock - private HttpServletRequest request; - @Mock private ScmConfiguration configuration; @Mock private RepositoryProvider repositoryProvider; - + + private WireProtocolRequestMockFactory wireProtocol = new WireProtocolRequestMockFactory("/scm/hg/repo"); + @InjectMocks private HgPermissionFilter filter; @@ -82,7 +84,90 @@ public class HgPermissionFilterTest { } private boolean isWriteRequest(String method) { + HttpServletRequest request = mock(HttpServletRequest.class); when(request.getMethod()).thenReturn(method); return filter.isWriteRequest(request); } -} \ No newline at end of file + + /** + * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a + * fresh clone of a repository. + */ + @Test + public void testIsWriteRequestWithClone() { + assertIsReadRequest(wireProtocol.capabilities()); + assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); + assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES)); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + } + + /** + * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a + * push of a single changeset. + */ + @Test + public void testIsWriteRequestWithSingleChangesetPush() { + assertIsReadRequest(wireProtocol.capabilities()); + assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2"))); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); + assertIsWriteRequest(wireProtocol.unbundle(261L, "686173686564+6768033e216468247bd031a0a2d9876d79818f8f")); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsWriteRequest(wireProtocol.pushkey("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2&namespace=phases&new=0&old=1")); + } + + /** + * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a + * push to a single changeset. + */ + @Test + public void testIsWriteRequestWithMultipleChangesetsPush() { + assertIsReadRequest(wireProtocol.capabilities()); + assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98"))); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); + assertIsReadRequest(wireProtocol.branchmap()); + assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); + assertIsWriteRequest(wireProtocol.unbundle(746L, "686173686564+95373ca7cd5371cb6c49bb755ee451d9ec585845")); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsWriteRequest(wireProtocol.pushkey("ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1")); + } + + /** + * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a + * push of multiple branches to a new repository. + */ + @Test + public void testIsWriteRequestWithMutlipleBranchesToNewRepositoryPush() { + assertIsReadRequest(wireProtocol.capabilities()); + assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98"))); + assertIsReadRequest(wireProtocol.known("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2+187ddf37e237c370514487a0bb1a226f11a780b3+b5914611f84eae14543684b2721eec88b0edac12+8b63a323606f10c86b30465570c2574eb7a3a989")); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); + assertIsWriteRequest(wireProtocol.unbundle(913L, "686173686564+6768033e216468247bd031a0a2d9876d79818f8f")); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsWriteRequest(wireProtocol.pushkey("ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1")); + } + + /** + * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a + * push of a bookmark. + */ + @Test + public void testIsWriteRequestWithBookmarkPush() { + assertIsReadRequest(wireProtocol.capabilities()); + assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98"))); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); + assertIsReadRequest(wireProtocol.listkeys(PHASES)); + assertIsWriteRequest(wireProtocol.pushkey("markone&namespace=bookmarks&new=ef5993bb4abb32a0565c347844c6d939fc4f4b98&old=")); + } + + private void assertIsReadRequest(HttpServletRequest request) { + assertFalse(filter.isWriteRequest(request)); + } + + private void assertIsWriteRequest(HttpServletRequest request) { + assertTrue(filter.isWriteRequest(request)); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java new file mode 100644 index 0000000000..3d2b6fab92 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java @@ -0,0 +1,101 @@ +package sonia.scm.web; + +import javax.servlet.http.HttpServletRequest; + +import java.util.Locale; + +import static org.mockito.Mockito.*; + +public class WireProtocolRequestMockFactory { + + public enum Namespace { + PHASES, BOOKMARKS; + } + + public static final String CMDS_HEADS_KNOWN_NODES = "heads+%3Bknown+nodes%3D"; + + private String repositoryPath; + + public WireProtocolRequestMockFactory(String repositoryPath) { + this.repositoryPath = repositoryPath; + } + + public HttpServletRequest capabilities() { + return base("GET", "?cmd=capabilities"); + } + + public HttpServletRequest listkeys(Namespace namespace) { + HttpServletRequest request = base("GET", "?cmd=capabilities"); + header(request, "vary", "X-HgArg-1"); + header(request, "x-hgarg-1", namespaceValue(namespace)); + return request; + } + + public HttpServletRequest branchmap() { + return base("GET", "?cmd=branchmap"); + } + + public HttpServletRequest batch(String... args) { + HttpServletRequest request = base("GET", "?cmd=batch"); + args(request, "cmds", args); + return request; + } + + public HttpServletRequest unbundle(long contentLength, String... heads) { + HttpServletRequest request = base("POST", "?cmd=unbundle"); + header(request, "Content-Length", String.valueOf(contentLength)); + args(request, "heads", heads); + return request; + } + + public HttpServletRequest pushkey(String... keys) { + HttpServletRequest request = base("POST", "?cmd=pushkey"); + args(request, "key", keys); + return request; + } + + public HttpServletRequest known(String... nodes) { + HttpServletRequest request = base("POST", "?cmd=pushkey"); + args(request, "nodes", nodes); + return request; + } + + private void args(HttpServletRequest request, String prefix, String[] values) { + StringBuilder vary = new StringBuilder(); + for ( int i=0; i0) { + vary.append(","); + } + vary.append("X-HgArg-" + (i+1)); + header(request, "X-HgArg-" + (i+1), prefix + "=" + values[i]); + } + header(request, "Vary", vary.toString()); + } + + private HttpServletRequest base(String method, String queryStringValue) { + HttpServletRequest request = mock(HttpServletRequest.class); + + when(request.getRequestURI()).thenReturn(repositoryPath); + when(request.getMethod()).thenReturn(method); + + queryString(request, queryStringValue); + + header(request, "Accept", "application/mercurial-0.1"); + header(request, "Accept-Encoding", "identity"); + header(request, "User-Agent", "mercurial/proto-1.0 (Mercurial 4.3.1)"); + return request; + } + + private void queryString(HttpServletRequest request, String queryString) { + when(request.getQueryString()).thenReturn(queryString); + } + + private void header(HttpServletRequest request, String header, String value) { + when(request.getHeader(header)).thenReturn(value); + } + + private String namespaceValue(Namespace namespace) { + return "namespace=" + namespace.toString().toLowerCase(Locale.ENGLISH); + } + +} From 3a9bc6828da2fd8ba30787cc1f10234350062e76 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 29 Mar 2018 19:58:52 +0200 Subject: [PATCH 028/178] use code blocks for request and response --- docs/mercurial/clone-empty.md | 2 ++ docs/mercurial/push-bookmark.md | 2 ++ docs/mercurial/push-multiple-branches-to-new.md | 2 ++ docs/mercurial/push-multiple-branches.md | 2 ++ docs/mercurial/push-single-changeset.md | 3 ++- 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/mercurial/clone-empty.md b/docs/mercurial/clone-empty.md index 810a297806..44a81de20c 100644 --- a/docs/mercurial/clone-empty.md +++ b/docs/mercurial/clone-empty.md @@ -1,5 +1,6 @@ # Clone empty repository +```http GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. Accept-Encoding: identity. accept: application/mercurial-0.1. @@ -72,3 +73,4 @@ Content-Length: 15. Server: Jetty(7.6.21.v20160908). . publishing.True +``` diff --git a/docs/mercurial/push-bookmark.md b/docs/mercurial/push-bookmark.md index 110bd40cd5..9ed591f9f4 100644 --- a/docs/mercurial/push-bookmark.md +++ b/docs/mercurial/push-bookmark.md @@ -1,5 +1,6 @@ # Push bookmark +```http GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. Accept-Encoding: identity. accept: application/mercurial-0.1. @@ -113,3 +114,4 @@ Content-Length: 2. Server: Jetty(7.6.21.v20160908). . 1 +``` diff --git a/docs/mercurial/push-multiple-branches-to-new.md b/docs/mercurial/push-multiple-branches-to-new.md index 56c3a4504a..734c479fef 100644 --- a/docs/mercurial/push-multiple-branches-to-new.md +++ b/docs/mercurial/push-multiple-branches-to-new.md @@ -1,5 +1,6 @@ # Push multiple branches to new repository +```http GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. Accept-Encoding: identity. accept: application/mercurial-0.1. @@ -163,3 +164,4 @@ Content-Length: 2. Server: Jetty(7.6.21.v20160908). . 1 +``` diff --git a/docs/mercurial/push-multiple-branches.md b/docs/mercurial/push-multiple-branches.md index 7d38542fde..5827cb0ceb 100644 --- a/docs/mercurial/push-multiple-branches.md +++ b/docs/mercurial/push-multiple-branches.md @@ -1,5 +1,6 @@ # Push multiple branches +```http GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. Accept-Encoding: identity. accept: application/mercurial-0.1. @@ -179,3 +180,4 @@ Content-Length: 2. Server: Jetty(7.6.21.v20160908). 1 +``` diff --git a/docs/mercurial/push-single-changeset.md b/docs/mercurial/push-single-changeset.md index 19b13c1dcd..499b4c21c3 100644 --- a/docs/mercurial/push-single-changeset.md +++ b/docs/mercurial/push-single-changeset.md @@ -1,5 +1,6 @@ # Push single changeset +```http GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1. Accept-Encoding: identity. accept: application/mercurial-0.1. @@ -143,4 +144,4 @@ Content-Length: 2. Server: Jetty(7.6.21.v20160908). 1 - +``` From 8aaa67cd6aff0d1f57fbafae316f5c8bf7ec7be3 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 29 Mar 2018 20:26:56 +0200 Subject: [PATCH 029/178] #970 inspect mercurial commands in order to detect write requests The HgPermissionFilter will now inspect the used mercurial command, of all requests which are using a read method like GET, HEAD, OPTIONS or TRACE and tread every one as write request, expect: - no command was specified with the request (this is required for the hgweb ui) - the command in the query string was found in the list of read commands - if query string contains the batch command, then all commands specified in X-HgArg headers must be in the list of read commands This change is required, in order to fix CVE-2018-1000132 for SCM-Manager. --- .../sonia/scm/web/HgPermissionFilter.java | 9 +- .../main/java/sonia/scm/web/WireProtocol.java | 192 ++++++++++++++++++ .../sonia/scm/web/HgPermissionFilterTest.java | 30 ++- .../web/WireProtocolRequestMockFactory.java | 31 ++- .../java/sonia/scm/web/WireProtocolTest.java | 162 +++++++++++++++ 5 files changed, 403 insertions(+), 21 deletions(-) create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java 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 6700ae3b8d..01fb21885e 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 @@ -51,13 +51,13 @@ import javax.servlet.http.HttpServletRequest; /** * Permission filter for mercurial repositories. - * + * * @author Sebastian Sdorra */ @Singleton public class HgPermissionFilter extends ProviderPermissionFilter { - + private static final Set READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE"); /** @@ -78,6 +78,9 @@ public class HgPermissionFilter extends ProviderPermissionFilter @Override protected boolean isWriteRequest(HttpServletRequest request) { - return !READ_METHODS.contains(request.getMethod()); + if (READ_METHODS.contains(request.getMethod())) { + return WireProtocol.isWriteRequest(request); + } + return true; } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java new file mode 100644 index 0000000000..bab3083445 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2018, 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; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.util.HttpUtil; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * WireProtocol provides methods for handling the mercurial wire protocol. + * + * @see Mercurial Wire Protocol + */ +public final class WireProtocol { + + private static final Logger LOG = LoggerFactory.getLogger(WireProtocol.class); + + private static final Set 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" + ); + + private static final Set 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 request + * + * @param request http request + * + * @return {@code true} for write requests. + */ + public static boolean isWriteRequest(HttpServletRequest request) { + List commands = commandsOf(request); + boolean write = isWriteRequest(commands); + LOG.trace("mercurial request {} is write: {}", commands, write); + return write; + } + + @VisibleForTesting + static boolean isWriteRequest(List commands) { + return !READ_COMMANDS.containsAll(commands); + } + + @VisibleForTesting + static List commandsOf(HttpServletRequest request) { + List listOfCmds = Lists.newArrayList(); + String cmd = getCommandFromQueryString(request); + if (cmd != null) { + listOfCmds.add(cmd); + if (isBatchCommand(cmd)) { + parseHgArgHeaders(request, listOfCmds); + } + } + return Collections.unmodifiableList(listOfCmds); + } + + private static void parseHgArgHeaders(HttpServletRequest request, List listOfCmds) { + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String header = (String) headerNames.nextElement(); + parseHgArgHeader(request, listOfCmds, header); + } + } + + private static void parseHgArgHeader(HttpServletRequest request, List listOfCmds, String header) { + if (isHgArgHeader(header)) { + String value = getHeaderDecoded(request, header); + if (isHgArgCommandHeader(value)) { + parseHgCommandHeader(listOfCmds, value); + } + } + } + + private static void parseHgCommandHeader(List listOfCmds, String value) { + String[] cmds = value.substring(5).split(";"); + for (String cmd : cmds ) { + String normalizedCmd = normalize(cmd); + int index = normalizedCmd.indexOf(' '); + if (index > 0) { + listOfCmds.add(normalizedCmd.substring(0, index)); + } else { + listOfCmds.add(normalizedCmd); + } + } + } + + private static String normalize(String cmd) { + return cmd.trim().toLowerCase(Locale.ENGLISH); + } + + private static boolean isHgArgCommandHeader(String value) { + return value.startsWith("cmds="); + } + + private static String getHeaderDecoded(HttpServletRequest request, String header) { + return HttpUtil.decode(Strings.nullToEmpty(request.getHeader(header))); + } + + private static boolean isHgArgHeader(String header) { + return header.toLowerCase(Locale.ENGLISH).startsWith("x-hgarg-"); + } + + private static boolean isBatchCommand(String cmd) { + return "batch".equalsIgnoreCase(cmd); + } + + private static String getCommandFromQueryString(HttpServletRequest request) { + // we can't use getParameter, because this would inspect the body for form parameters as well + Multimap queryParameterMap = createQueryParameterMap(request); + + Collection cmd = queryParameterMap.get("cmd"); + Preconditions.checkArgument(cmd.size() <= 1, "found more than one cmd query parameter"); + Iterator iterator = cmd.iterator(); + + String command = null; + if (iterator.hasNext()) { + command = iterator.next(); + } + return command; + } + + private static Multimap createQueryParameterMap(HttpServletRequest request) { + Multimap parameterMap = HashMultimap.create(); + + String queryString = request.getQueryString(); + if (!Strings.isNullOrEmpty(queryString)) { + + String[] parameters = queryString.split("&"); + for (String parameter : parameters) { + int index = parameter.indexOf('='); + if (index > 0) { + parameterMap.put(parameter.substring(0, index), parameter.substring(index + 1)); + } else { + parameterMap.put(parameter, "true"); + } + } + + } + + return parameterMap; + } +} diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java index 05250c8cf9..8319134078 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java @@ -1,10 +1,10 @@ /** * Copyright (c) 2014, 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, @@ -13,7 +13,7 @@ * 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 @@ -24,9 +24,9 @@ * 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; @@ -48,7 +48,7 @@ import sonia.scm.repository.RepositoryProvider; /** * Unit tests for {@link HgPermissionFilter}. - * + * * @author Sebastian Sdorra */ @RunWith(MockitoJUnitRunner.class) @@ -56,7 +56,7 @@ public class HgPermissionFilterTest { @Mock private ScmConfiguration configuration; - + @Mock private RepositoryProvider repositoryProvider; @@ -64,7 +64,7 @@ public class HgPermissionFilterTest { @InjectMocks private HgPermissionFilter filter; - + /** * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)}. */ @@ -75,7 +75,7 @@ public class HgPermissionFilterTest { assertFalse(isWriteRequest("HEAD")); assertFalse(isWriteRequest("TRACE")); assertFalse(isWriteRequest("OPTIONS")); - + // write methods assertTrue(isWriteRequest("POST")); assertTrue(isWriteRequest("PUT")); @@ -85,6 +85,7 @@ public class HgPermissionFilterTest { private boolean isWriteRequest(String method) { HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getQueryString()).thenReturn("cmd=capabilities"); when(request.getMethod()).thenReturn(method); return filter.isWriteRequest(request); } @@ -163,6 +164,17 @@ public class HgPermissionFilterTest { assertIsWriteRequest(wireProtocol.pushkey("markone&namespace=bookmarks&new=ef5993bb4abb32a0565c347844c6d939fc4f4b98&old=")); } + /** + * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a write request hidden in a batch GET + * request. + * + * @see Issue #970 + */ + @Test + public void testIsWriteRequestWithBookmarkPushInABatch() { + assertIsWriteRequest(wireProtocol.batch("pushkey key=markthree,namespace=bookmarks,new=187ddf37e237c370514487a0bb1a226f11a780b3,old=")); + } + private void assertIsReadRequest(HttpServletRequest request) { assertFalse(filter.isWriteRequest(request)); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java index 3d2b6fab92..d1f5124b3a 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java @@ -1,7 +1,11 @@ package sonia.scm.web; +import com.google.common.collect.Lists; + import javax.servlet.http.HttpServletRequest; +import java.util.Collections; +import java.util.List; import java.util.Locale; import static org.mockito.Mockito.*; @@ -21,55 +25,64 @@ public class WireProtocolRequestMockFactory { } public HttpServletRequest capabilities() { - return base("GET", "?cmd=capabilities"); + return base("GET", "cmd=capabilities"); } public HttpServletRequest listkeys(Namespace namespace) { - HttpServletRequest request = base("GET", "?cmd=capabilities"); + HttpServletRequest request = base("GET", "cmd=capabilities"); header(request, "vary", "X-HgArg-1"); header(request, "x-hgarg-1", namespaceValue(namespace)); return request; } public HttpServletRequest branchmap() { - return base("GET", "?cmd=branchmap"); + return base("GET", "cmd=branchmap"); } public HttpServletRequest batch(String... args) { - HttpServletRequest request = base("GET", "?cmd=batch"); + HttpServletRequest request = base("GET", "cmd=batch"); args(request, "cmds", args); return request; } public HttpServletRequest unbundle(long contentLength, String... heads) { - HttpServletRequest request = base("POST", "?cmd=unbundle"); + HttpServletRequest request = base("POST", "cmd=unbundle"); header(request, "Content-Length", String.valueOf(contentLength)); args(request, "heads", heads); return request; } public HttpServletRequest pushkey(String... keys) { - HttpServletRequest request = base("POST", "?cmd=pushkey"); + HttpServletRequest request = base("POST", "cmd=pushkey"); args(request, "key", keys); return request; } public HttpServletRequest known(String... nodes) { - HttpServletRequest request = base("POST", "?cmd=pushkey"); + HttpServletRequest request = base("GET", "cmd=known"); args(request, "nodes", nodes); return request; } private void args(HttpServletRequest request, String prefix, String[] values) { + List headers = Lists.newArrayList(); + StringBuilder vary = new StringBuilder(); for ( int i=0; i0) { vary.append(","); } - vary.append("X-HgArg-" + (i+1)); - header(request, "X-HgArg-" + (i+1), prefix + "=" + values[i]); + + vary.append(header); + headers.add(header); + + header(request, header, prefix + "=" + values[i]); } header(request, "Vary", vary.toString()); + + when(request.getHeaderNames()).thenReturn(Collections.enumeration(headers)); } private HttpServletRequest base(String method, String queryStringValue) { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java new file mode 100644 index 0000000000..860b6a6392 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java @@ -0,0 +1,162 @@ +/** + * Copyright (c) 2018, 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; + +import com.google.common.collect.Lists; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import javax.servlet.http.HttpServletRequest; + +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.Matchers.contains; +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +/** + * Unit tests for {@link WireProtocol}. + */ +@RunWith(MockitoJUnitRunner.class) +public class WireProtocolTest { + + @Mock + private HttpServletRequest request; + + @Test + public void testIsWriteRequestOnPost() { + assertIsWriteRequest("capabilities", "unbundle"); + } + + @Test + public void testIsWriteRequest() { + assertIsWriteRequest("unbundle"); + assertIsWriteRequest("capabilities", "unbundle"); + assertIsWriteRequest("capabilities", "postkeys"); + assertIsReadRequest(); + assertIsReadRequest("capabilities"); + assertIsReadRequest("capabilities", "branches", "branchmap"); + } + + private void assertIsWriteRequest(String... commands) { + List cmdList = Lists.newArrayList(commands); + assertTrue(WireProtocol.isWriteRequest(cmdList)); + } + + private void assertIsReadRequest(String... commands) { + List cmdList = Lists.newArrayList(commands); + assertFalse(WireProtocol.isWriteRequest(cmdList)); + } + + @Test + public void testGetCommandsOf() { + expectQueryCommand("capabilities", "cmd=capabilities"); + expectQueryCommand("unbundle", "cmd=unbundle"); + expectQueryCommand("unbundle", "prefix=stuff&cmd=unbundle"); + expectQueryCommand("unbundle", "cmd=unbundle&suffix=stuff"); + expectQueryCommand("unbundle", "prefix=stuff&cmd=unbundle&suffix=stuff"); + expectQueryCommand("unbundle", "bool=&cmd=unbundle"); + expectQueryCommand("unbundle", "bool&cmd=unbundle"); + expectQueryCommand("unbundle", "prefix=stu==ff&cmd=unbundle"); + } + + @Test + public void testGetCommandsOfWithBatch() { + prepareBatch("cmds=heads ;known nodes,ef5993bb4abb32a0565c347844c6d939fc4f4b98"); + List commands = WireProtocol.commandsOf(request); + assertThat(commands, contains("batch", "heads", "known")); + } + + @Test + public void testGetCommandsOfWithBatchEncoded() { + prepareBatch("cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98"); + List commands = WireProtocol.commandsOf(request); + assertThat(commands, contains("batch", "heads", "known")); + } + + @Test + public void testGetCommandsOfWithBatchAndMutlipleLines() { + prepareBatch( + "cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98", + "cmds=unbundle; postkeys", + "cmds= branchmap p1=r2,p2=r4; listkeys" + ); + List commands = WireProtocol.commandsOf(request); + assertThat(commands, contains("batch", "heads", "known", "unbundle", "postkeys", "branchmap", "listkeys")); + } + + private void prepareBatch(String... args) { + when(request.getQueryString()).thenReturn("cmd=batch"); + List headers = Lists.newArrayList(); + for (int i=0; i commands = WireProtocol.commandsOf(request); + assertEquals(1, commands.size()); + assertTrue(commands.contains(expected)); + } + +} From a34acd8ed469f2977615139874e7fa2f029ff226 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 29 Mar 2018 22:14:28 +0200 Subject: [PATCH 030/178] #970 added option to enable the experimental httppostargs protocol of mercurial --- .../java/sonia/scm/repository/HgConfig.java | 10 +++++++++ .../main/java/sonia/scm/web/HgCGIServlet.java | 8 ++++++- .../src/main/resources/sonia/scm/hg.config.js | 21 +++++++++++++------ .../main/resources/sonia/scm/python/hgweb.py | 17 +++++++++++---- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java index ed336ff203..2eb060cb66 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgConfig.java @@ -127,6 +127,10 @@ public class HgConfig extends SimpleRepositoryConfig return disableHookSSLValidation; } + public boolean isEnableHttpPostArgs() { + return enableHttpPostArgs; + } + /** * Method description * @@ -197,6 +201,10 @@ public class HgConfig extends SimpleRepositoryConfig this.showRevisionInId = showRevisionInId; } + public void setEnableHttpPostArgs(boolean enableHttpPostArgs) { + this.enableHttpPostArgs = enableHttpPostArgs; + } + /** * Method description * @@ -232,6 +240,8 @@ public class HgConfig extends SimpleRepositoryConfig /** Field description */ private boolean showRevisionInId = false; + private boolean enableHttpPostArgs = false; + /** * disable validation of ssl certificates for mercurial hook * @see Issue 959 diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index f6023dd0ae..1fb78161e0 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -87,6 +87,8 @@ public class HgCGIServlet extends HttpServlet /** Field description */ public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH"; + private static final String ENV_HTTP_POST_ARGS = "SCM_HTTP_POST_ARGS"; + /** Field description */ public static final String ENV_SESSION_PREFIX = "SCM_"; @@ -278,11 +280,15 @@ public class HgCGIServlet extends HttpServlet environment.put(ENV_PYTHON_HTTPS_VERIFY, "0"); } + // enable experimental httppostargs protocol of mercurial + // Issue 970: https://goo.gl/poascp + environment.put(ENV_HTTP_POST_ARGS, String.valueOf(handler.getConfig().isEnableHttpPostArgs())); + //J- HgEnvironment.prepareEnvironment( environment, handler, - hookManager, + hookManager, request ); //J+ diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js index 58a73ea8e9..f7b4f33240 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js @@ -48,6 +48,7 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { showRevisionInIdText: 'Show Revision', // TODO: i18n disableHookSSLValidationText: 'Disable SSL Validation on Hooks', + enableHttpPostArgsText: 'Enable HttpPostArgs Protocol', // helpText hgBinaryHelpText: 'Location of Mercurial binary.', @@ -63,6 +64,8 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { // TODO: i18n disableHookSSLValidationHelpText: 'Disables the validation of ssl certificates for the mercurial hook, which forwards the repository changes back to scm-manager. \n\ This option should only be used, if SCM-Manager uses a self signed certificate.', + // TODO explain it + enableHttpPostArgsHelpText: 'Enables the experimental HttpPostArgs Protocol.', initComponent: function(){ @@ -115,12 +118,18 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { fieldLabel: this.disableHookSSLValidationText, inputValue: 'true', helpText: this.disableHookSSLValidationHelpText + },{ + xtype: 'checkbox', + name: 'enableHttpPostArgs', + fieldLabel: this.enableHttpPostArgsText, + inputValue: 'true', + helpText: this.enableHttpPostArgsHelpText },{ xtype: 'checkbox', name: 'disabled', fieldLabel: this.disabledText, inputValue: 'true', - helpText: this.disabledHelpText + helpText: this.disabledHelpText },{ xtype: 'button', text: this.configWizardText, @@ -260,11 +269,11 @@ Sonia.repository.typeIcons['hg'] = 'resources/images/icons/16x16/mercurial.png'; // override ChangesetViewerGrid to render changeset id's with revisions Ext.override(Sonia.repository.ChangesetViewerGrid, { - + isMercurialRepository: function(){ return this.repository.type === 'hg'; }, - + getChangesetId: function(id, record){ if ( this.isMercurialRepository() ){ var rev = Sonia.util.getProperty(record.get('properties'), 'hg.rev'); @@ -274,7 +283,7 @@ Ext.override(Sonia.repository.ChangesetViewerGrid, { } return id; }, - + getParentIds: function(id, record){ var parents = record.get('parents'); if ( this.isMercurialRepository() ){ @@ -285,7 +294,7 @@ Ext.override(Sonia.repository.ChangesetViewerGrid, { parents[0] = rev + ':' + parents[0]; } if ( parents.length > 1 ){ - rev = Sonia.util.getProperty(properties, 'hg.p2.rev'); + rev = Sonia.util.getProperty(properties, 'hg.p2.rev'); if (rev){ parents[1] = rev + ':' + parents[1]; } @@ -294,5 +303,5 @@ Ext.override(Sonia.repository.ChangesetViewerGrid, { } return parents; } - + }); diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py index 66d5fadc3c..ff2869044d 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py @@ -31,12 +31,21 @@ import os -from mercurial import demandimport +from mercurial import demandimport, ui as uimod, hg from mercurial.hgweb import hgweb, wsgicgi -repositoryPath = os.environ['SCM_REPOSITORY_PATH'] - demandimport.enable() -application = hgweb(repositoryPath) +u = uimod.ui.load() + +# pass SCM_HTTP_POST_ARGS to enable experimental httppostargs protocol of mercurial +# SCM_HTTP_POST_ARGS is set by HgCGIServlet +# Issue 970: https://goo.gl/poascp +u.setconfig('experimental', 'httppostargs', os.environ['SCM_HTTP_POST_ARGS']) + +# open repository +# SCM_REPOSITORY_PATH contains the repository path and is set by HgCGIServlet +r = hg.repository(u, os.environ['SCM_REPOSITORY_PATH']) + +application = hgweb(r) wsgicgi.launch(application) From b43e406b765f6e67d828da608c8dad59e1a14f18 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 30 Mar 2018 11:20:22 +0200 Subject: [PATCH 031/178] #970 initial support of mercurials httppostargs protocol --- .../sonia/scm/web/HgPermissionFilter.java | 36 +++++++++--- .../sonia/scm/web/HgServletInputStream.java | 55 +++++++++++++++++++ .../java/sonia/scm/web/HgServletRequest.java | 31 +++++++++++ .../main/java/sonia/scm/web/WireProtocol.java | 48 ++++++++++++++-- .../sonia/scm/web/HgPermissionFilterTest.java | 48 +++++++++++++--- .../scm/web/HgServletInputStreamTest.java | 50 +++++++++++++++++ .../java/sonia/scm/web/WireProtocolTest.java | 32 ++++++++++- 7 files changed, 279 insertions(+), 21 deletions(-) create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletRequest.java create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java 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 01fb21885e..dde048a746 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 @@ -38,16 +38,17 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; import com.google.inject.Singleton; - import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.RepositoryProvider; import sonia.scm.web.filter.ProviderPermissionFilter; -//~--- JDK imports ------------------------------------------------------------ - -import java.util.Set; - +import javax.servlet.FilterChain; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; /** * Permission filter for mercurial repositories. @@ -60,6 +61,8 @@ public class HgPermissionFilter extends ProviderPermissionFilter private static final Set READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE"); + private final HgRepositoryHandler repositoryHandler; + /** * Constructs a new instance. * @@ -67,17 +70,36 @@ public class HgPermissionFilter extends ProviderPermissionFilter * @param repositoryProvider repository provider */ @Inject - public HgPermissionFilter(ScmConfiguration configuration, - RepositoryProvider repositoryProvider) + public HgPermissionFilter(ScmConfiguration configuration, RepositoryProvider repositoryProvider, HgRepositoryHandler repositoryHandler) { super(configuration, repositoryProvider); + this.repositoryHandler = repositoryHandler; } //~--- get methods ---------------------------------------------------------- + + @Override + protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { + HgServletRequest hgRequest = new HgServletRequest(request); + super.doFilter(hgRequest, response, chain); + // TODO closing stream in case of fire? + } + @Override protected boolean isWriteRequest(HttpServletRequest request) { + if (repositoryHandler.getConfig().isEnableHttpPostArgs()) { + return isHttpPostArgsWriteRequest(request); + } + return isDefaultWriteRequest(request); + } + + private boolean isHttpPostArgsWriteRequest(HttpServletRequest request) { + return WireProtocol.isWriteRequest(request); + } + + private boolean isDefaultWriteRequest(HttpServletRequest request) { if (READ_METHODS.contains(request.getMethod())) { return WireProtocol.isWriteRequest(request); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java new file mode 100644 index 0000000000..b0b2f8ef0d --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java @@ -0,0 +1,55 @@ +package sonia.scm.web; + +import com.google.common.base.Preconditions; + +import javax.servlet.ServletInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * HgServletInputStream is a wrapper around the original {@link ServletInputStream} and provides some extra + * functionality to support the mercurial client. + */ +public class HgServletInputStream extends ServletInputStream { + + private final ServletInputStream original; + private ByteArrayInputStream captured; + + HgServletInputStream(ServletInputStream original) { + this.original = original; + } + + /** + * Reads the given amount of bytes from the stream and captures them, if the {@link #read()} methods is called the + * captured bytes are returned before the rest of the stream. + * + * @param size amount of bytes to read + * + * @return byte array + * + * @throws IOException if the method is called twice + */ + public byte[] readAndCapture(int size) throws IOException { + Preconditions.checkState(captured == null, "readAndCapture can only be called once per request"); + + // TODO should we enforce a limit? to prevent OOM? + byte[] bytes = new byte[size]; + original.read(bytes); + captured = new ByteArrayInputStream(bytes); + + return bytes; + } + + @Override + public int read() throws IOException { + if (captured != null && captured.available() > 0) { + return captured.read(); + } + return original.read(); + } + + @Override + public void close() throws IOException { + original.close(); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletRequest.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletRequest.java new file mode 100644 index 0000000000..80251c140a --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletRequest.java @@ -0,0 +1,31 @@ +package sonia.scm.web; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.IOException; + +/** + * {@link HttpServletRequestWrapper} which adds some functionality in order to support the mercurial client. + */ +public final class HgServletRequest extends HttpServletRequestWrapper { + + private HgServletInputStream hgServletInputStream; + + /** + * Constructs a request object wrapping the given request. + * + * @param request + * @throws IllegalArgumentException if the request is null + */ + public HgServletRequest(HttpServletRequest request) { + super(request); + } + + @Override + public HgServletInputStream getInputStream() throws IOException { + if (hgServletInputStream == null) { + hgServletInputStream = new HgServletInputStream(super.getInputStream()); + } + return hgServletInputStream; + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java index bab3083445..8a411ead64 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java @@ -33,14 +33,17 @@ package sonia.scm.web; import com.google.common.annotations.VisibleForTesting; +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 sonia.scm.util.HttpUtil; import javax.servlet.http.HttpServletRequest; +import java.io.IOException; import java.util.*; /** @@ -73,7 +76,10 @@ public final class WireProtocol { * - 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 request + * 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 * @@ -94,16 +100,40 @@ public final class WireProtocol { @VisibleForTesting static List commandsOf(HttpServletRequest request) { List listOfCmds = Lists.newArrayList(); + String cmd = getCommandFromQueryString(request); if (cmd != null) { listOfCmds.add(cmd); if (isBatchCommand(cmd)) { parseHgArgHeaders(request, listOfCmds); + handleHttpPostArgs(request, listOfCmds); } } return Collections.unmodifiableList(listOfCmds); } + private static void handleHttpPostArgs(HttpServletRequest request, List listOfCmds) { + int hgArgsPostSize = request.getIntHeader("X-HgArgs-Post"); + if (hgArgsPostSize > 0) { + + if (request instanceof HgServletRequest) { + HgServletRequest hgRequest = (HgServletRequest) request; + + try { + byte[] bytes = hgRequest.getInputStream().readAndCapture(hgArgsPostSize); + String hgArgs = new String(bytes, Charsets.US_ASCII); + String decoded = decodeValue(hgArgs); + parseHgCommandHeader(listOfCmds, decoded); + } catch (IOException ex) { + throw Throwables.propagate(ex); + } + } else { + throw new IllegalArgumentException("could not process the httppostargs protocol without HgServletRequest"); + } + + } + } + private static void parseHgArgHeaders(HttpServletRequest request, List listOfCmds) { Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { @@ -115,9 +145,13 @@ public final class WireProtocol { private static void parseHgArgHeader(HttpServletRequest request, List listOfCmds, String header) { if (isHgArgHeader(header)) { String value = getHeaderDecoded(request, header); - if (isHgArgCommandHeader(value)) { - parseHgCommandHeader(listOfCmds, value); - } + parseHgArgValue(listOfCmds, value); + } + } + + private static void parseHgArgValue(List listOfCmds, String value) { + if (isHgArgCommandHeader(value)) { + parseHgCommandHeader(listOfCmds, value); } } @@ -143,7 +177,11 @@ public final class WireProtocol { } private static String getHeaderDecoded(HttpServletRequest request, String header) { - return HttpUtil.decode(Strings.nullToEmpty(request.getHeader(header))); + return decodeValue(request.getHeader(header)); + } + + private static String decodeValue(String value) { + return HttpUtil.decode(Strings.nullToEmpty(value)); } private static boolean isHgArgHeader(String header) { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java index 8319134078..f8aefb95d1 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java @@ -31,21 +31,27 @@ package sonia.scm.web; -import javax.servlet.http.HttpServletRequest; +import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.*; -import static sonia.scm.web.WireProtocolRequestMockFactory.CMDS_HEADS_KNOWN_NODES; -import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.*; - import org.mockito.runners.MockitoJUnitRunner; import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.RepositoryProvider; +import javax.servlet.http.HttpServletRequest; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static sonia.scm.web.WireProtocolRequestMockFactory.CMDS_HEADS_KNOWN_NODES; +import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.BOOKMARKS; +import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.PHASES; + /** * Unit tests for {@link HgPermissionFilter}. * @@ -60,11 +66,19 @@ public class HgPermissionFilterTest { @Mock private RepositoryProvider repositoryProvider; + @Mock + private HgRepositoryHandler hgRepositoryHandler; + private WireProtocolRequestMockFactory wireProtocol = new WireProtocolRequestMockFactory("/scm/hg/repo"); @InjectMocks private HgPermissionFilter filter; + @Before + public void setUp() { + when(hgRepositoryHandler.getConfig()).thenReturn(new HgConfig()); + } + /** * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)}. */ @@ -83,9 +97,27 @@ public class HgPermissionFilterTest { assertTrue(isWriteRequest("KA")); } + /** + * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with enabled httppostargs option. + */ + @Test + public void testIsWriteRequestWithEnabledHttpPostArgs() { + HgConfig config = new HgConfig(); + config.setEnableHttpPostArgs(true); + when(hgRepositoryHandler.getConfig()).thenReturn(config); + + assertFalse(isWriteRequest("POST")); + assertFalse(isWriteRequest("POST", "heads")); + assertTrue(isWriteRequest("POST", "unbundle")); + } + private boolean isWriteRequest(String method) { + return isWriteRequest(method, "capabilities"); + } + + private boolean isWriteRequest(String method, String command) { HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getQueryString()).thenReturn("cmd=capabilities"); + when(request.getQueryString()).thenReturn("cmd=" + command); when(request.getMethod()).thenReturn(method); return filter.isWriteRequest(request); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java new file mode 100644 index 0000000000..51b0a050fc --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java @@ -0,0 +1,50 @@ +package sonia.scm.web; + +import com.google.common.base.Charsets; +import com.google.common.io.ByteStreams; +import org.junit.Test; + +import javax.servlet.ServletInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +public class HgServletInputStreamTest { + + @Test + public void testReadAndCapture() throws IOException { + SampleServletInputStream original = new SampleServletInputStream("trillian.mcmillian@hitchhiker.com"); + HgServletInputStream hgServletInputStream = new HgServletInputStream(original); + + byte[] prefix = hgServletInputStream.readAndCapture(8); + assertEquals("trillian", new String(prefix, Charsets.US_ASCII)); + + byte[] wholeBytes = ByteStreams.toByteArray(hgServletInputStream); + assertEquals("trillian.mcmillian@hitchhiker.com", new String(wholeBytes, Charsets.US_ASCII)); + } + + @Test(expected = IllegalStateException.class) + public void testReadAndCaptureCalledTwice() throws IOException { + SampleServletInputStream original = new SampleServletInputStream("trillian.mcmillian@hitchhiker.com"); + HgServletInputStream hgServletInputStream = new HgServletInputStream(original); + + hgServletInputStream.readAndCapture(1); + hgServletInputStream.readAndCapture(1); + } + + private static class SampleServletInputStream extends ServletInputStream { + + private ByteArrayInputStream input; + + private SampleServletInputStream(String data) { + input = new ByteArrayInputStream(data.getBytes()); + } + + @Override + public int read() { + return input.read(); + } + } + +} diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java index 860b6a6392..519dadfd6c 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java @@ -32,14 +32,17 @@ package sonia.scm.web; +import com.google.common.base.Charsets; import com.google.common.collect.Lists; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; - +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.util.Collections; import java.util.List; @@ -93,6 +96,18 @@ public class WireProtocolTest { expectQueryCommand("unbundle", "prefix=stu==ff&cmd=unbundle"); } + @Test + public void testGetCommandsOfWithHgArgsPost() throws IOException { + when(request.getMethod()).thenReturn("POST"); + when(request.getQueryString()).thenReturn("cmd=batch"); + when(request.getIntHeader("X-HgArgs-Post")).thenReturn(29); + when(request.getHeaderNames()).thenReturn(Collections.enumeration(Lists.newArrayList("X-HgArgs-Post"))); + when(request.getInputStream()).thenReturn(new BufferedServletInputStream("cmds=lheads+%3Bknown+nodes%3D")); + + List commands = WireProtocol.commandsOf(new HgServletRequest(request)); + assertThat(commands, contains("batch", "lheads", "known")); + } + @Test public void testGetCommandsOfWithBatch() { prepareBatch("cmds=heads ;known nodes,ef5993bb4abb32a0565c347844c6d939fc4f4b98"); @@ -159,4 +174,19 @@ public class WireProtocolTest { assertTrue(commands.contains(expected)); } + private static class BufferedServletInputStream extends ServletInputStream { + + private ByteArrayInputStream input; + + BufferedServletInputStream(String content) { + this.input = new ByteArrayInputStream(content.getBytes(Charsets.US_ASCII)); + } + + @Override + public int read() { + return input.read(); + } + + } + } From 8047d360285248122cb8dbb5e13d19e617859b6d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Tue, 3 Apr 2018 11:00:16 +0200 Subject: [PATCH 032/178] #970 use iso-8859-1 for http post args instead of us-ascii --- .../main/java/sonia/scm/web/WireProtocol.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java index 8a411ead64..fb84692805 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java @@ -119,14 +119,7 @@ public final class WireProtocol { if (request instanceof HgServletRequest) { HgServletRequest hgRequest = (HgServletRequest) request; - try { - byte[] bytes = hgRequest.getInputStream().readAndCapture(hgArgsPostSize); - String hgArgs = new String(bytes, Charsets.US_ASCII); - String decoded = decodeValue(hgArgs); - parseHgCommandHeader(listOfCmds, decoded); - } catch (IOException ex) { - throw Throwables.propagate(ex); - } + parseHttpPostArgs(listOfCmds, hgArgsPostSize, hgRequest); } else { throw new IllegalArgumentException("could not process the httppostargs protocol without HgServletRequest"); } @@ -134,6 +127,19 @@ public final class WireProtocol { } } + private static void parseHttpPostArgs(List listOfCmds, int hgArgsPostSize, HgServletRequest hgRequest) { + try { + 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 decoded = decodeValue(hgArgs); + parseHgCommandHeader(listOfCmds, decoded); + } catch (IOException ex) { + throw Throwables.propagate(ex); + } + } + private static void parseHgArgHeaders(HttpServletRequest request, List listOfCmds) { Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { From acebd0f25e28955141a671a087deba7dd05bbcff Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Tue, 3 Apr 2018 11:14:05 +0200 Subject: [PATCH 033/178] #970 wrap requests only if http postargs is enabled --- .../sonia/scm/web/HgPermissionFilter.java | 19 ++++++++++++---- .../sonia/scm/web/HgPermissionFilterTest.java | 22 +++++++++++++++++-- 2 files changed, 35 insertions(+), 6 deletions(-) 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 dde048a746..955002928c 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 @@ -35,6 +35,7 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -81,20 +82,30 @@ public class HgPermissionFilter extends ProviderPermissionFilter @Override protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { - HgServletRequest hgRequest = new HgServletRequest(request); - super.doFilter(hgRequest, response, chain); - // TODO closing stream in case of fire? + super.doFilter(wrapRequestIfRequired(request), response, chain); + } + + @VisibleForTesting + HttpServletRequest wrapRequestIfRequired(HttpServletRequest request) { + if (isHttpPostArgsEnabled()) { + return new HgServletRequest(request); + } + return request; } @Override protected boolean isWriteRequest(HttpServletRequest request) { - if (repositoryHandler.getConfig().isEnableHttpPostArgs()) { + if (isHttpPostArgsEnabled()) { return isHttpPostArgsWriteRequest(request); } return isDefaultWriteRequest(request); } + private boolean isHttpPostArgsEnabled() { + return repositoryHandler.getConfig().isEnableHttpPostArgs(); + } + private boolean isHttpPostArgsWriteRequest(HttpServletRequest request) { return WireProtocol.isWriteRequest(request); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java index f8aefb95d1..bb6692ffce 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java @@ -44,8 +44,9 @@ import sonia.scm.repository.RepositoryProvider; import javax.servlet.http.HttpServletRequest; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static sonia.scm.web.WireProtocolRequestMockFactory.CMDS_HEADS_KNOWN_NODES; @@ -60,6 +61,9 @@ import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.PHASES; @RunWith(MockitoJUnitRunner.class) public class HgPermissionFilterTest { + @Mock + private HttpServletRequest request; + @Mock private ScmConfiguration configuration; @@ -79,6 +83,20 @@ public class HgPermissionFilterTest { when(hgRepositoryHandler.getConfig()).thenReturn(new HgConfig()); } + /** + * Tests {@link HgPermissionFilter#wrapRequestIfRequired(HttpServletRequest)}. + */ + @Test + public void testWrapRequestIfRequired() { + assertSame(request, filter.wrapRequestIfRequired(request)); + + HgConfig hgConfig = new HgConfig(); + hgConfig.setEnableHttpPostArgs(true); + when(hgRepositoryHandler.getConfig()).thenReturn(hgConfig); + + assertThat(filter.wrapRequestIfRequired(request), is(instanceOf(HgServletRequest.class))); + } + /** * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)}. */ From 3d401b93ea6fbed8d3bef13e6ad7e079ac3d993d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Tue, 3 Apr 2018 11:56:51 +0200 Subject: [PATCH 034/178] #970 added help text for enable httppostargs --- .../scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js index f7b4f33240..b10de4b422 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg.config.js @@ -65,7 +65,9 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, { disableHookSSLValidationHelpText: 'Disables the validation of ssl certificates for the mercurial hook, which forwards the repository changes back to scm-manager. \n\ This option should only be used, if SCM-Manager uses a self signed certificate.', // TODO explain it - enableHttpPostArgsHelpText: 'Enables the experimental HttpPostArgs Protocol.', + enableHttpPostArgsHelpText: 'Enables the experimental HttpPostArgs Protocol of mercurial.\n\ + The HttpPostArgs Protocol uses the body of post requests to send the meta information instead of http headers.\ + This helps to reduce the header size of mercurial requests. HttpPostArgs is supported since mercurial 3.8.', initComponent: function(){ From 473f3257a0c068ea5807f72a3e3b5306b82caa8b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 5 Apr 2018 18:44:42 +0200 Subject: [PATCH 035/178] close branch issue-970 From ff2afceb55c4362dbae252279ba3b8b5d87a4577 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 5 Apr 2018 19:48:04 +0200 Subject: [PATCH 036/178] update javahg to version 0.13 --- scm-plugins/scm-hg-plugin/pom.xml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index e4cfa7d6f2..0bced018e6 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -1,6 +1,6 @@ - + 4.0.0 @@ -24,11 +24,11 @@ ${servlet.version} provided - + com.aragost.javahg javahg - 0.8-scm1 + 0.13 com.google.guava @@ -47,12 +47,12 @@ - + - + - + com.mycila.maven-license-plugin maven-license-plugin @@ -71,7 +71,7 @@ true - + org.apache.maven.plugins maven-jar-plugin @@ -84,18 +84,18 @@ - + - + - + maven.scm-manager.org scm-manager release repository http://maven.scm-manager.org/nexus/content/groups/public - + false @@ -108,7 +108,7 @@ default https://oss.sonatype.org/content/groups/public/ - + - + From 8af69c4e99fee97a29e6abe502769d5534327fec Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 5 Apr 2018 19:56:15 +0200 Subject: [PATCH 037/178] update vulnerable dependencies commons-beanutils to 1.9.3 commons-collections to 3.2.2 httpclient to 4.5.5 slf4j to 1.7.25 logback to 1.2.3 jackson to 1.9.13 --- pom.xml | 74 ++++++++++++++++++++++++++++++++++++++++++++-- scm-core/pom.xml | 1 - scm-webapp/pom.xml | 11 ------- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index c888ababe8..e06cf4698e 100644 --- a/pom.xml +++ b/pom.xml @@ -387,6 +387,75 @@ + + + + + + + commons-beanutils + commons-beanutils + 1.9.3 + + + + commons-collections + commons-collections + 3.2.2 + + + + + + org.apache.httpcomponents + httpclient + 4.5.5 + + + + + + slf4j-api + org.slf4j + ${slf4j.version} + + + + ch.qos.logback + logback-classic + ${logback.version} + + + + + + + org.codehaus.jackson + jackson-core-asl + ${jackson.version} + + + + org.codehaus.jackson + jackson-mapper-asl + ${jackson.version} + + + + org.codehaus.jackson + jackson-jaxrs + ${jackson.version} + + + + org.codehaus.jackson + jackson-xc + ${jackson.version} + + + + + @@ -410,8 +479,8 @@ 4.12 - 1.7.22 - 1.1.10 + 1.7.25 + 1.2.3 2.5 3.0 1.19.4 @@ -419,6 +488,7 @@ 2.3.20 7.6.21.v20160908 7.6.16.v20140903 + 1.9.13 1.3.0 diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 732c0fa4d6..72c40c1f9a 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -30,7 +30,6 @@ slf4j-api org.slf4j - ${slf4j.version} diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 775b75525a..8c2d6379ae 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -136,7 +136,6 @@ ch.qos.logback logback-classic - ${logback.version} @@ -174,13 +173,11 @@ commons-beanutils commons-beanutils - 1.9.2 commons-collections commons-collections - 3.2.1 - - - org.apache.httpcomponents - httpclient - 4.2.6 - - From 528f7636341a40151f5b3701c59837db4e20ddbf Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 5 Apr 2018 20:35:48 +0200 Subject: [PATCH 038/178] removed never released scm-dao-orientdb module --- pom.xml | 1 - scm-dao-orientdb/pom.xml | 78 ---- .../scm/group/orientdb/GroupConverter.java | 180 --------- .../scm/group/orientdb/OrientDBGroupDAO.java | 112 ------ .../sonia/scm/orientdb/AbstractConverter.java | 198 ---------- .../orientdb/AbstractOrientDBModelDAO.java | 366 ------------------ .../scm/orientdb/ConnectionConfiguration.java | 282 -------------- .../scm/orientdb/ConnectionProvider.java | 296 -------------- .../java/sonia/scm/orientdb/Converter.java | 87 ----- .../sonia/scm/orientdb/OrientDBModule.java | 68 ---- .../OrientDBServletContextListener.java | 114 ------ .../java/sonia/scm/orientdb/OrientDBUtil.java | 295 -------------- .../orientdb/OrientDBRepositoryDAO.java | 182 --------- .../orientdb/PermissionConverter.java | 156 -------- .../orientdb/RepositoryConverter.java | 218 ----------- .../scm/store/orientdb/OrientDBStore.java | 222 ----------- .../store/orientdb/OrientDBStoreFactory.java | 162 -------- .../scm/user/orientdb/OrientDBUserDAO.java | 112 ------ .../scm/user/orientdb/UserConverter.java | 195 ---------- .../main/resources/META-INF/scm/override.xml | 58 --- .../scm/orientdb/server-configuration.xml | 52 --- 21 files changed, 3434 deletions(-) delete mode 100644 scm-dao-orientdb/pom.xml delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/GroupConverter.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/OrientDBGroupDAO.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractConverter.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractOrientDBModelDAO.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionConfiguration.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionProvider.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/Converter.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBModule.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBServletContextListener.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBUtil.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/OrientDBRepositoryDAO.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/PermissionConverter.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/RepositoryConverter.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStore.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStoreFactory.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/OrientDBUserDAO.java delete mode 100644 scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java delete mode 100644 scm-dao-orientdb/src/main/resources/META-INF/scm/override.xml delete mode 100644 scm-dao-orientdb/src/main/resources/sonia/scm/orientdb/server-configuration.xml diff --git a/pom.xml b/pom.xml index e06cf4698e..6e4b76b847 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,6 @@ scm-plugins scm-samples scm-dao-xml - scm-dao-orientdb scm-webapp scm-server scm-plugin-backend diff --git a/scm-dao-orientdb/pom.xml b/scm-dao-orientdb/pom.xml deleted file mode 100644 index c708a12cba..0000000000 --- a/scm-dao-orientdb/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - 4.0.0 - - - sonia.scm - scm - 1.58-SNAPSHOT - - - sonia.scm - scm-dao-orientdb - 1.58-SNAPSHOT - scm-dao-orientdb - - - - - javax.servlet - servlet-api - ${servlet.version} - provided - - - - sonia.scm - scm-core - 1.58-SNAPSHOT - - - - com.orientechnologies - orientdb-client - ${orientdb.version} - - - - com.orientechnologies - orientdb-server - ${orientdb.version} - - - com.orientechnologies - orientdb-client - - - - - - - - sonia.scm - scm-test - 1.58-SNAPSHOT - test - - - - - - 1.1.0 - - - - - - orientechnologies-repository - Orient Technologies Maven2 Repository - http://www.orientechnologies.com/listing/m2 - - true - - - - - - diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/GroupConverter.java b/scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/GroupConverter.java deleted file mode 100644 index e25ce9a327..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/GroupConverter.java +++ /dev/null @@ -1,180 +0,0 @@ -/** - * 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.group.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.metadata.schema.OClass; -import com.orientechnologies.orient.core.metadata.schema.OClass.INDEX_TYPE; -import com.orientechnologies.orient.core.metadata.schema.OSchema; -import com.orientechnologies.orient.core.metadata.schema.OType; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.group.Group; -import sonia.scm.orientdb.AbstractConverter; -import sonia.scm.orientdb.Converter; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; -import java.util.Map; - -/** - * - * @author Sebastian Sdorra - */ -public class GroupConverter extends AbstractConverter - implements Converter -{ - - /** Field description */ - public static final String DOCUMENT_CLASS = "Group"; - - /** Field description */ - public static final String FIELD_CREATIONDATE = "creationDate"; - - /** Field description */ - public static final String FIELD_DESCRIPTION = "description"; - - /** Field description */ - public static final String FIELD_MEMBERS = "members"; - - /** Field description */ - public static final String INDEX_ID = "groupId"; - - /** Field description */ - public static final GroupConverter INSTANCE = new GroupConverter(); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param group - * - * @return - */ - @Override - public ODocument convert(Group group) - { - ODocument doc = new ODocument(DOCUMENT_CLASS); - - return convert(doc, group); - } - - /** - * Method description - * - * - * @param doc - * @param group - * - * @return - */ - @Override - public ODocument convert(ODocument doc, Group group) - { - appendModelObjectFields(doc, group); - appendField(doc, FIELD_DESCRIPTION, group.getDescription()); - appendField(doc, FIELD_CREATIONDATE, group.getCreationDate(), OType.LONG); - appendField(doc, FIELD_MEMBERS, group.getMembers(), OType.EMBEDDEDLIST); - appendPropertiesField(doc, group); - - return doc; - } - - /** - * Method description - * - * - * @param doc - * - * @return - */ - @Override - public Group convert(ODocument doc) - { - Group group = new Group(); - - group.setName(getStringField(doc, FIELD_ID)); - group.setDescription(getStringField(doc, FIELD_DESCRIPTION)); - group.setType(getStringField(doc, FIELD_TYPE)); - group.setCreationDate(getLongField(doc, FIELD_CREATIONDATE)); - group.setLastModified(getLongField(doc, FIELD_LASTMODIFIED)); - - Map properties = doc.field(FIELD_PROPERTIES); - - group.setProperties(properties); - - List members = doc.field(FIELD_MEMBERS); - - group.setMembers(members); - - return group; - } - - /** - * Method description - * - * - * @param connection - */ - @Override - public void createShema(ODatabaseDocumentTx connection) - { - OSchema schema = connection.getMetadata().getSchema(); - OClass oclass = schema.getClass(DOCUMENT_CLASS); - - if (oclass == null) - { - oclass = schema.createClass(DOCUMENT_CLASS); - - // model properites - oclass.createProperty(FIELD_ID, OType.STRING); - oclass.createProperty(FIELD_TYPE, OType.STRING); - oclass.createProperty(FIELD_LASTMODIFIED, OType.LONG); - - // user properties - oclass.createProperty(FIELD_DESCRIPTION, OType.STRING); - oclass.createProperty(FIELD_CREATIONDATE, OType.LONG); - oclass.createProperty(FIELD_MEMBERS, OType.EMBEDDEDLIST); - oclass.createProperty(FIELD_PROPERTIES, OType.EMBEDDEDMAP); - - // indexes - oclass.createIndex(INDEX_ID, INDEX_TYPE.UNIQUE, FIELD_ID); - schema.save(); - } - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/OrientDBGroupDAO.java b/scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/OrientDBGroupDAO.java deleted file mode 100644 index 56f2187537..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/group/orientdb/OrientDBGroupDAO.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * 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.group.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; -import com.google.inject.Provider; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.group.Group; -import sonia.scm.group.GroupDAO; -import sonia.scm.orientdb.AbstractOrientDBModelDAO; -import sonia.scm.orientdb.OrientDBUtil; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - -/** - * - * @author Sebastian Sdorra - */ -public class OrientDBGroupDAO extends AbstractOrientDBModelDAO - implements GroupDAO -{ - - /** Field description */ - public static final String QUERY_ALL = "select from Group"; - - /** Field description */ - public static final String QUERY_SINGLE_BYID = - "select from Group where id = ?"; - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param connectionProvider - */ - @Inject - public OrientDBGroupDAO(Provider connectionProvider) - { - super(connectionProvider, GroupConverter.INSTANCE); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param connection - * - * @return - */ - @Override - protected List getAllDocuments(ODatabaseDocumentTx connection) - { - return OrientDBUtil.executeListResultQuery(connection, QUERY_ALL); - } - - /** - * Method description - * - * - * @param connection - * @param id - * - * @return - */ - @Override - protected ODocument getDocument(ODatabaseDocumentTx connection, String id) - { - return OrientDBUtil.executeSingleResultQuery(connection, QUERY_SINGLE_BYID, - id); - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractConverter.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractConverter.java deleted file mode 100644 index f811e56f20..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractConverter.java +++ /dev/null @@ -1,198 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.orientechnologies.orient.core.metadata.schema.OType; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.ModelObject; -import sonia.scm.PropertiesAware; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - -/** - * - * @author Sebastian Sdorra - */ -public abstract class AbstractConverter -{ - - /** Field description */ - public static final String FIELD_ID = "id"; - - /** Field description */ - public static final String FIELD_LASTMODIFIED = "lastModified"; - - /** Field description */ - public static final String FIELD_PROPERTIES = "properties"; - - /** Field description */ - public static final String FIELD_TYPE = "type"; - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param doc - * @param name - * @param value - */ - protected void appendField(ODocument doc, String name, Object value) - { - appendField(doc, name, value, null); - } - - /** - * Method description - * - * - * @param doc - * @param name - * @param value - * @param type - */ - protected void appendField(ODocument doc, String name, Object value, - OType type) - { - if (value != null) - { - if (type != null) - { - doc.field(name, value, type); - } - else - { - doc.field(name, value); - } - } - else if (doc.containsField(name)) - { - doc.removeField(name); - } - } - - /** - * Method description - * - * - * @param doc - * @param name - * @param converter - * @param list - * @param - */ - protected void appendListField(ODocument doc, String name, - Converter converter, List list) - { - List docs = OrientDBUtil.transformToDocuments(converter, list); - - appendField(doc, name, docs, OType.EMBEDDEDLIST); - } - - /** - * Method description - * - * - * @param doc - * @param model - */ - protected void appendModelObjectFields(ODocument doc, ModelObject model) - { - appendField(doc, FIELD_ID, model.getId()); - appendField(doc, FIELD_TYPE, model.getType()); - appendField(doc, FIELD_LASTMODIFIED, model.getLastModified(), OType.LONG); - } - - /** - * Method description - * - * - * @param doc - * @param object - */ - protected void appendPropertiesField(ODocument doc, PropertiesAware object) - { - appendField(doc, FIELD_PROPERTIES, object.getProperties(), - OType.EMBEDDEDMAP); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param doc - * @param name - * - * @return - */ - protected Boolean getBooleanField(ODocument doc, String name) - { - return doc.field(name); - } - - /** - * Method description - * - * - * @param doc - * @param name - * - * @return - */ - protected Long getLongField(ODocument doc, String name) - { - return doc.field(name); - } - - /** - * Method description - * - * - * @param doc - * @param name - * - * @return - */ - protected String getStringField(ODocument doc, String name) - { - return doc.field(name); - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractOrientDBModelDAO.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractOrientDBModelDAO.java deleted file mode 100644 index 2b9585cb77..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/AbstractOrientDBModelDAO.java +++ /dev/null @@ -1,366 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.collect.Lists; -import com.google.inject.Provider; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.GenericDAO; -import sonia.scm.ModelObject; -import sonia.scm.util.Util; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - -/** - * - * @author Sebastian Sdorra - * - * @param - */ -public abstract class AbstractOrientDBModelDAO - implements GenericDAO -{ - - /** Field description */ - public static final String TYPE = "orientdb"; - - /** - * the logger for AbstractOrientDBModelDAO - */ - private static final Logger logger = - LoggerFactory.getLogger(AbstractOrientDBModelDAO.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param connectionProvider - * @param converter - */ - public AbstractOrientDBModelDAO( - Provider connectionProvider, - Converter converter) - { - this.connectionProvider = connectionProvider; - this.converter = converter; - createShema(); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param connection - * - * @return - */ - protected abstract List getAllDocuments( - ODatabaseDocumentTx connection); - - /** - * Method description - * - * - * @param connection - * @param id - * - * @return - */ - protected abstract ODocument getDocument(ODatabaseDocumentTx connection, - String id); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * - * @param item - */ - @Override - public void add(T item) - { - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - ODocument doc = converter.convert(item); - - doc.save(); - } - finally - { - OrientDBUtil.close(connection); - } - } - - /** - * Method description - * - * - * - * @param item - * - * @return - */ - @Override - public boolean contains(T item) - { - return contains(item.getId()); - } - - /** - * Method description - * - * - * @param id - * - * @return - */ - @Override - public boolean contains(String id) - { - return get(id) != null; - } - - /** - * Method description - * - * - * @param item - */ - @Override - public void delete(T item) - { - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - ODocument doc = getDocument(connection, item.getId()); - - if (doc != null) - { - doc.delete(); - } - else if (logger.isErrorEnabled()) - { - logger.error("could not find document for delete"); - } - } - finally - { - OrientDBUtil.close(connection); - } - } - - /** - * Method description - * - * - * - * @param item - */ - @Override - public void modify(T item) - { - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - ODocument doc = getDocument(connection, item.getId()); - - if (doc != null) - { - doc = converter.convert(doc, item); - doc.save(); - } - else if (logger.isErrorEnabled()) - { - logger.error("could not find document for modify"); - } - } - finally - { - OrientDBUtil.close(connection); - } - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param id - * - * @return - */ - @Override - public T get(String id) - { - T item = null; - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - ODocument doc = getDocument(connection, id); - - if (doc != null) - { - item = converter.convert(doc); - } - } - finally - { - OrientDBUtil.close(connection); - } - - return item; - } - - /** - * Method description - * - * - * @return - */ - @Override - public List getAll() - { - List items = null; - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - List result = getAllDocuments(connection); - - if (Util.isNotEmpty(result)) - { - items = OrientDBUtil.transformToItems(converter, result); - } - else - { - items = Lists.newArrayList(); - } - } - finally - { - OrientDBUtil.close(connection); - } - - return items; - } - - /** - * Method description - * - * - * @return - */ - @Override - public Long getCreationTime() - { - - // TODO - return System.currentTimeMillis(); - } - - /** - * Method description - * - * - * @return - */ - @Override - public Long getLastModified() - { - - // TODO - return System.currentTimeMillis(); - } - - /** - * Method description - * - * - * @return - */ - @Override - public String getType() - { - return TYPE; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ - private void createShema() - { - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - converter.createShema(connection); - } - finally - { - OrientDBUtil.close(connection); - } - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - protected Provider connectionProvider; - - /** Field description */ - protected Converter converter; -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionConfiguration.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionConfiguration.java deleted file mode 100644 index e6eae1af0d..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionConfiguration.java +++ /dev/null @@ -1,282 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.base.Objects; - -//~--- JDK imports ------------------------------------------------------------ - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -/** - * - * @author Sebastian Sdorra - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "connection-configuration") -public class ConnectionConfiguration -{ - - /** - * Constructs ... - * - */ - public ConnectionConfiguration() {} - - /** - * Constructs ... - * - * - * @param url - * @param username - * @param password - */ - public ConnectionConfiguration(String url, String username, String password) - { - this.url = url; - this.username = username; - this.password = password; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param obj - * - * @return - */ - @Override - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - - if (getClass() != obj.getClass()) - { - return false; - } - - final ConnectionConfiguration other = (ConnectionConfiguration) obj; - - //J- - return Objects.equal(url, other.url) - && Objects.equal(username, other.username) - && Objects.equal(password, other.password) - && Objects.equal(minPoolSize, other.minPoolSize) - && Objects.equal(maxPoolSize, other.maxPoolSize); - //J+ - } - - /** - * Method description - * - * - * @return - */ - @Override - public int hashCode() - { - return Objects.hashCode(url, username, password, minPoolSize, maxPoolSize); - } - - /** - * Method description - * - * - * @return - */ - @Override - @SuppressWarnings("squid:S2068") - public String toString() - { - String pwd = null; - - if (password != null) - { - pwd = "xxx"; - } - - //J- - return Objects.toStringHelper(this) - .add("url", url) - .add("username", username) - .add("password", pwd) - .add("minPoolSize", minPoolSize) - .add("maxPoolSize", maxPoolSize) - .toString(); - //J+ - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - public int getMaxPoolSize() - { - return maxPoolSize; - } - - /** - * Method description - * - * - * @return - */ - public int getMinPoolSize() - { - return minPoolSize; - } - - /** - * Method description - * - * - * @return - */ - public String getPassword() - { - return password; - } - - /** - * Method description - * - * - * @return - */ - public String getUrl() - { - return url; - } - - /** - * Method description - * - * - * @return - */ - public String getUsername() - { - return username; - } - - //~--- set methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param maxPoolSize - */ - public void setMaxPoolSize(int maxPoolSize) - { - this.maxPoolSize = maxPoolSize; - } - - /** - * Method description - * - * - * @param minPoolSize - */ - public void setMinPoolSize(int minPoolSize) - { - this.minPoolSize = minPoolSize; - } - - /** - * Method description - * - * - * @param password - */ - public void setPassword(String password) - { - this.password = password; - } - - /** - * Method description - * - * - * @param url - */ - public void setUrl(String url) - { - this.url = url; - } - - /** - * Method description - * - * - * @param username - */ - public void setUsername(String username) - { - this.username = username; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - @XmlElement(name = "max-pool-size") - private int maxPoolSize = 10; - - /** Field description */ - @XmlElement(name = "min-pool-size") - private int minPoolSize = 2; - - /** Field description */ - private String password; - - /** Field description */ - private String url; - - /** Field description */ - private String username; -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionProvider.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionProvider.java deleted file mode 100644 index 65f8245f32..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/ConnectionProvider.java +++ /dev/null @@ -1,296 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.io.Resources; -import com.google.inject.Provider; -import com.google.inject.Singleton; - -import com.orientechnologies.orient.core.config.OGlobalConfiguration; -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentPool; -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.server.OServer; -import com.orientechnologies.orient.server.OServerMain; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.ConfigurationException; -import sonia.scm.SCMContext; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.Closeable; -import java.io.File; - -import java.net.URL; - -import java.nio.charset.Charset; - -import javax.xml.bind.JAXB; - -/** - * - * @author Sebastian Sdorra - */ -@Singleton -public class ConnectionProvider - implements Provider, Closeable -{ - - /** Field description */ - public static final String DEFAULT_DB_DIRECTORY = "db"; - - /** Field description */ - public static final String DEFAULT_DB_SHEME = "local:"; - - /** Field description */ - @SuppressWarnings("squid:S2068") - public static final String DEFAULT_PASSWORD = "admin"; - - /** Field description */ - public static final String DEFAULT_USERNAME = "admin"; - - /** Field description */ - public static final String EMBEDDED_CONFIGURATION = - "sonia/scm/orientdb/server-configuration.xml"; - - /** Field description */ - public static final String CONFIG_PATH_SERVER = - "config".concat(File.separator).concat("orientdb-server.xml"); - - /** Field description */ - public static final String CONFIG_PATH_CLIENT = - "config".concat(File.separator).concat("orientdb-client.xml"); - - /** - * the logger for ConnectionProvider - */ - private static final Logger logger = - LoggerFactory.getLogger(ConnectionProvider.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - public ConnectionProvider() - { - File file = new File(SCMContext.getContext().getBaseDirectory(), - CONFIG_PATH_CLIENT); - - if (file.exists()) - { - if (logger.isInfoEnabled()) - { - logger.info("read database configuration from file {}", file); - } - - init(JAXB.unmarshal(file, ConnectionConfiguration.class)); - } - else - { - try - { - File baseDirectory = SCMContext.getContext().getBaseDirectory(); - - // create connection configuration for embedded server - File directory = new File(baseDirectory, DEFAULT_DB_DIRECTORY); - - if (logger.isInfoEnabled()) - { - logger.info("create configuration for embedded database at {}", - directory); - } - - /** - * set oritentdb tuning option - * https://groups.google.com/forum/#!msg/orient-database/DrJ3zPY3oao/RQQayirg4mYJ - */ - OGlobalConfiguration.STORAGE_KEEP_OPEN.setValue(Boolean.FALSE); - OGlobalConfiguration.MVRBTREE_LAZY_UPDATES.setValue(1); - server = OServerMain.create(); - - URL configUrl = null; - File serverConfiguration = new File(baseDirectory, CONFIG_PATH_SERVER); - - if (serverConfiguration.exists()) - { - configUrl = serverConfiguration.toURI().toURL(); - } - else - { - configUrl = Resources.getResource(EMBEDDED_CONFIGURATION); - } - - if (logger.isInfoEnabled()) - { - logger.info("load orientdb server configuration from {}", configUrl); - } - - String config = Resources.toString(configUrl, Charset.defaultCharset()); - - server.startup(config); - server.activate(); - - String url = DEFAULT_DB_SHEME.concat(directory.getAbsolutePath()); - - if (!directory.exists()) - { - if (logger.isInfoEnabled()) - { - logger.info("create new database at {}", directory); - } - - ODatabaseDocumentTx connection = null; - - try - { - connection = new ODatabaseDocumentTx(url); - connection.create(); - } - finally - { - OrientDBUtil.close(connection); - } - } - - init(new ConnectionConfiguration(url, DEFAULT_USERNAME, - DEFAULT_PASSWORD)); - } - catch (Exception ex) - { - throw new ConfigurationException("could not start embedded database", - ex); - } - } - } - - /** - * Constructs ... - * - * - * @param configuration - */ - public ConnectionProvider(ConnectionConfiguration configuration) - { - init(configuration); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ - @Override - public void close() - { - if (connectionPool != null) - { - try - { - connectionPool.close(); - } - catch (Exception ex) - { - logger.error("could not close connection pool", ex); - } - } - - if (server != null) - { - try - { - server.shutdown(); - } - catch (Exception ex) - { - logger.error("shutdown of orientdb server failed", ex); - } - } - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - @Override - public ODatabaseDocumentTx get() - { - if (logger.isTraceEnabled()) - { - logger.trace("acquire new connection for database {}", - configuration.getUrl()); - } - - return connectionPool.acquire(configuration.getUrl(), - configuration.getUsername(), - configuration.getPassword()); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param configuration - */ - private void init(ConnectionConfiguration configuration) - { - this.configuration = configuration; - this.connectionPool = new ODatabaseDocumentPool(); - this.connectionPool.setup(configuration.getMinPoolSize(), - configuration.getMaxPoolSize()); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private ConnectionConfiguration configuration; - - /** Field description */ - private ODatabaseDocumentPool connectionPool; - - /** Field description */ - private OServer server; -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/Converter.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/Converter.java deleted file mode 100644 index 0575d47e5d..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/Converter.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.record.impl.ODocument; - -/** - * - * @author Sebastian Sdorra - * - * @param - */ -public interface Converter -{ - - /** - * Method description - * - * - * @param item - * - * @return - */ - public ODocument convert(T item); - - /** - * Method description - * - * - * @param doc - * @param item - * - * @return - */ - public ODocument convert(ODocument doc, T item); - - /** - * Method description - * - * - * @param doc - * - * @return - */ - public T convert(ODocument doc); - - /** - * Method description - * - * - * @param connection - */ - public void createShema(ODatabaseDocumentTx connection); -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBModule.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBModule.java deleted file mode 100644 index 57d4a14b9a..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBModule.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.AbstractModule; -import com.google.inject.multibindings.Multibinder; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; - -//~--- JDK imports ------------------------------------------------------------ - -import javax.servlet.ServletContextListener; - -/** - * - * @author Sebastian Sdorra - */ -public class OrientDBModule extends AbstractModule -{ - - /** - * Method description - * - */ - @Override - protected void configure() - { - bind(ODatabaseDocumentTx.class).toProvider(ConnectionProvider.class); - - Multibinder servletContextListenerBinder = - Multibinder.newSetBinder(binder(), ServletContextListener.class); - - servletContextListenerBinder.addBinding().to( - OrientDBServletContextListener.class); - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBServletContextListener.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBServletContextListener.java deleted file mode 100644 index 7dc5468be6..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBServletContextListener.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; -import com.google.inject.Singleton; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -//~--- JDK imports ------------------------------------------------------------ - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -/** - * - * @author Sebastian Sdorra - */ -@Singleton -public class OrientDBServletContextListener implements ServletContextListener -{ - - /** - * the logger for OrientDBServletContextListener - */ - private static final Logger logger = - LoggerFactory.getLogger(OrientDBServletContextListener.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param connectionProvider - */ - @Inject - public OrientDBServletContextListener(ConnectionProvider connectionProvider) - { - this.connectionProvider = connectionProvider; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param sce - */ - @Override - public void contextDestroyed(ServletContextEvent sce) - { - connectionProvider.close(); - - if (logger.isInfoEnabled()) - { - logger.info("orientdb context listener destroyed"); - } - } - - /** - * Method description - * - * - * @param sce - */ - @Override - public void contextInitialized(ServletContextEvent sce) - { - if (logger.isInfoEnabled()) - { - logger.info("orientdb context listener initialized"); - } - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private ConnectionProvider connectionProvider; -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBUtil.java b/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBUtil.java deleted file mode 100644 index 02ccb6066b..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/orientdb/OrientDBUtil.java +++ /dev/null @@ -1,295 +0,0 @@ -/** - * 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.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.base.Function; -import com.google.common.collect.Lists; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.record.impl.ODocument; -import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.util.Util; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - -/** - * - * @author Sebastian Sdorra - */ -public final class OrientDBUtil -{ - - /** Field description */ - public static final String FETCH_PLAN = "*:-1"; - - /** - * the logger for OrientDBUtil - */ - private static final Logger logger = - LoggerFactory.getLogger(OrientDBUtil.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - private OrientDBUtil() {} - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param connection - */ - public static void close(ODatabaseDocumentTx connection) - { - if (connection != null) - { - connection.close(); - } - } - - /** - * Method description - * - * - * @param connection - * @param query - * @param parameters - * - * @return - */ - public static List executeListResultQuery( - ODatabaseDocumentTx connection, String query, Object... parameters) - { - if (logger.isTraceEnabled()) - { - logger.trace("execute list result query '{}'", query); - } - - OSQLSynchQuery osqlQuery = new OSQLSynchQuery(query); - - osqlQuery.setFetchPlan(FETCH_PLAN); - - return connection.command(osqlQuery).execute(parameters); - } - - /** - * Method description - * - * - * @param connection - * @param query - * @param parameters - * - * @return - */ - public static ODocument executeSingleResultQuery( - ODatabaseDocumentTx connection, String query, Object... parameters) - { - if (logger.isTraceEnabled()) - { - logger.trace("execute single result query '{}'", query); - } - - ODocument result = null; - OSQLSynchQuery osqlQuery = new OSQLSynchQuery(query); - - osqlQuery.setFetchPlan(FETCH_PLAN); - - List resultList = - connection.command(osqlQuery).setLimit(1).execute(parameters); - - if (Util.isNotEmpty(resultList)) - { - result = resultList.get(0); - } - - return result; - } - - /** - * Method description - * - * - * @param converter - * @param items - * @param - * - * @return - */ - public static List transformToDocuments( - Converter converter, List items) - { - List docs = null; - - if (Util.isNotEmpty(items)) - { - docs = Lists.transform(items, new ItemConverterFunction(converter)); - } - - return docs; - } - - /** - * Method description - * - * - * @param converter - * @param docs - * @param - * - * @return - */ - public static List transformToItems(Converter converter, - List docs) - { - List items = null; - - if (Util.isNotEmpty(docs)) - { - items = Lists.transform(docs, - new DocumentConverterFunction(converter)); - } - - return items; - } - - //~--- inner classes -------------------------------------------------------- - - /** - * Class description - * - * - * @param - * - * @version Enter version here..., 12/03/12 - * @author Enter your name here... - */ - private static class DocumentConverterFunction - implements Function - { - - /** - * Constructs ... - * - * - * @param converter - */ - public DocumentConverterFunction(Converter converter) - { - this.converter = converter; - } - - //~--- methods ------------------------------------------------------------ - - /** - * Method description - * - * - * - * @param doc - * - * @return - */ - @Override - public T apply(ODocument doc) - { - return converter.convert(doc); - } - - //~--- fields ------------------------------------------------------------- - - /** Field description */ - private Converter converter; - } - - - /** - * Class description - * - * - * @param - * - * @version Enter version here..., 12/03/12 - * @author Enter your name here... - */ - private static class ItemConverterFunction - implements Function - { - - /** - * Constructs ... - * - * - * @param converter - */ - public ItemConverterFunction(Converter converter) - { - this.converter = converter; - } - - //~--- methods ------------------------------------------------------------ - - /** - * Method description - * - * - * @param f - * - * @return - */ - @Override - public ODocument apply(F f) - { - return converter.convert(f); - } - - //~--- fields ------------------------------------------------------------- - - /** Field description */ - private Converter converter; - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/OrientDBRepositoryDAO.java b/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/OrientDBRepositoryDAO.java deleted file mode 100644 index de013e8698..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/OrientDBRepositoryDAO.java +++ /dev/null @@ -1,182 +0,0 @@ -/** - * 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.repository.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; -import com.google.inject.Provider; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.orientdb.AbstractOrientDBModelDAO; -import sonia.scm.orientdb.OrientDBUtil; -import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryDAO; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - -/** - * - * @author Sebastian Sdorra - */ -public class OrientDBRepositoryDAO extends AbstractOrientDBModelDAO - implements RepositoryDAO -{ - - /** Field description */ - public static final String QUERY_ALL = "select from Repository"; - - /** Field description */ - public static final String QUERY_SINGLE_BYID = - "select from Repository where id = ?"; - - /** Field description */ - public static final String QUERY_SINGLE_BYTYPEANDNAME = - "select from Repository where type = ? and name = ?"; - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param connectionProvider - */ - @Inject - public OrientDBRepositoryDAO(Provider connectionProvider) - { - super(connectionProvider, RepositoryConverter.INSTANCE); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param type - * @param name - * - * @return - */ - @Override - public boolean contains(String type, String name) - { - return get(type, name) != null; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param type - * @param name - * - * @return - */ - @Override - public Repository get(String type, String name) - { - Repository repository = null; - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - ODocument doc = getDocument(connection, type, name); - - if (doc != null) - { - repository = converter.convert(doc); - } - } - finally - { - OrientDBUtil.close(connection); - } - - return repository; - } - - /** - * Method description - * - * - * @param connection - * - * @return - */ - @Override - protected List getAllDocuments(ODatabaseDocumentTx connection) - { - return OrientDBUtil.executeListResultQuery(connection, QUERY_ALL); - } - - /** - * Method description - * - * - * @param connection - * @param id - * - * @return - */ - @Override - protected ODocument getDocument(ODatabaseDocumentTx connection, String id) - { - return OrientDBUtil.executeSingleResultQuery(connection, QUERY_SINGLE_BYID, - id); - } - - /** - * Method description - * - * - * @param connection - * @param type - * @param name - * - * @return - */ - private ODocument getDocument(ODatabaseDocumentTx connection, String type, - String name) - { - return OrientDBUtil.executeSingleResultQuery(connection, - QUERY_SINGLE_BYTYPEANDNAME, type, name); - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/PermissionConverter.java b/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/PermissionConverter.java deleted file mode 100644 index 6e152b4d87..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/PermissionConverter.java +++ /dev/null @@ -1,156 +0,0 @@ -/** - * 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.repository.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.metadata.schema.OClass; -import com.orientechnologies.orient.core.metadata.schema.OSchema; -import com.orientechnologies.orient.core.metadata.schema.OType; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.orientdb.AbstractConverter; -import sonia.scm.orientdb.Converter; -import sonia.scm.repository.Permission; -import sonia.scm.repository.PermissionType; - -/** - * - * @author Sebastian Sdorra - */ -public class PermissionConverter extends AbstractConverter - implements Converter -{ - - /** Field description */ - public static final String DOCUMENT_CLASS = "Permission"; - - /** Field description */ - public static final String FIELD_GROUP = "group"; - - /** Field description */ - public static final String FIELD_NAME = "name"; - - /** Field description */ - public static final PermissionConverter INSTANCE = new PermissionConverter(); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param doc - * @param permission - * - * @return - */ - @Override - public ODocument convert(ODocument doc, Permission permission) - { - appendField(doc, FIELD_NAME, permission.getName()); - appendField(doc, FIELD_TYPE, permission.getType().toString()); - appendField(doc, FIELD_GROUP, permission.isGroupPermission(), - OType.BOOLEAN); - - return doc; - } - - /** - * Method description - * - * - * @param permission - * - * @return - */ - @Override - public ODocument convert(Permission permission) - { - ODocument doc = new ODocument(DOCUMENT_CLASS); - - convert(doc, permission); - - return doc; - } - - /** - * Method description - * - * - * @param doc - * - * @return - */ - @Override - public Permission convert(ODocument doc) - { - Permission permission = new Permission(); - - permission.setName(getStringField(doc, FIELD_NAME)); - - String typeString = doc.field(FIELD_TYPE); - - if (typeString != null) - { - permission.setType(PermissionType.valueOf(typeString)); - } - - permission.setGroupPermission(getBooleanField(doc, FIELD_GROUP)); - - return permission; - } - - /** - * Method description - * - * - * @param connection - */ - @Override - public void createShema(ODatabaseDocumentTx connection) - { - OSchema schema = connection.getMetadata().getSchema(); - OClass oclass = schema.getClass(DOCUMENT_CLASS); - - if (oclass == null) - { - oclass = schema.createClass(DOCUMENT_CLASS); - oclass.createProperty(FIELD_NAME, OType.STRING); - oclass.createProperty(FIELD_TYPE, OType.STRING); - oclass.createProperty(FIELD_GROUP, OType.BOOLEAN); - schema.save(); - } - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/RepositoryConverter.java b/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/RepositoryConverter.java deleted file mode 100644 index bd96ca3444..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/repository/orientdb/RepositoryConverter.java +++ /dev/null @@ -1,218 +0,0 @@ -/** - * 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.repository.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.metadata.schema.OClass; -import com.orientechnologies.orient.core.metadata.schema.OClass.INDEX_TYPE; -import com.orientechnologies.orient.core.metadata.schema.OSchema; -import com.orientechnologies.orient.core.metadata.schema.OType; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.orientdb.AbstractConverter; -import sonia.scm.orientdb.Converter; -import sonia.scm.orientdb.OrientDBUtil; -import sonia.scm.repository.Repository; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; -import java.util.Map; - -/** - * - * @author Sebastian Sdorra - */ -public class RepositoryConverter extends AbstractConverter - implements Converter -{ - - /** Field description */ - public static final String DOCUMENT_CLASS = "Repository"; - - /** Field description */ - public static final String FIELD_ARCHIVED = "archived"; - - /** Field description */ - public static final String FIELD_CONTACT = "contact"; - - /** Field description */ - public static final String FIELD_CREATIONDATE = "creationDate"; - - /** Field description */ - public static final String FIELD_DESCRIPTION = "description"; - - /** Field description */ - public static final String FIELD_NAME = "name"; - - /** Field description */ - public static final String FIELD_PERMISSIONS = "permissions"; - - /** Field description */ - public static final String FIELD_PUBLIC = "public"; - - /** Field description */ - public static final String INDEX_ID = "RepositoryId"; - - /** Field description */ - public static final String INDEX_TYPEANDNAME = "RepositoryTypeAndName"; - - /** Field description */ - public static final RepositoryConverter INSTANCE = new RepositoryConverter(); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param doc - * @param repository - * - * @return - */ - @Override - public ODocument convert(ODocument doc, Repository repository) - { - appendModelObjectFields(doc, repository); - appendField(doc, FIELD_NAME, repository.getName()); - appendField(doc, FIELD_CONTACT, repository.getContact()); - appendField(doc, FIELD_DESCRIPTION, repository.getDescription()); - appendField(doc, FIELD_PUBLIC, repository.isPublicReadable(), - OType.BOOLEAN); - appendField(doc, FIELD_ARCHIVED, repository.isArchived(), OType.BOOLEAN); - appendField(doc, FIELD_CREATIONDATE, repository.getCreationDate(), - OType.LONG); - appendPropertiesField(doc, repository); - appendListField(doc, FIELD_PERMISSIONS, PermissionConverter.INSTANCE, - repository.getPermissions()); - - return doc; - } - - /** - * Method description - * - * - * @param repository - * - * @return - */ - @Override - public ODocument convert(Repository repository) - { - ODocument doc = new ODocument(DOCUMENT_CLASS); - - convert(doc, repository); - - return doc; - } - - /** - * Method description - * - * - * @param doc - * - * @return - */ - @Override - public Repository convert(ODocument doc) - { - Repository repository = new Repository(); - - repository.setId(getStringField(doc, FIELD_ID)); - repository.setType(getStringField(doc, FIELD_TYPE)); - repository.setName(getStringField(doc, FIELD_NAME)); - repository.setContact(getStringField(doc, FIELD_CONTACT)); - repository.setDescription(getStringField(doc, FIELD_DESCRIPTION)); - repository.setPublicReadable(getBooleanField(doc, FIELD_PUBLIC)); - repository.setArchived(getBooleanField(doc, FIELD_ARCHIVED)); - repository.setLastModified(getLongField(doc, FIELD_LASTMODIFIED)); - repository.setCreationDate(getLongField(doc, FIELD_CREATIONDATE)); - - Map properties = doc.field(FIELD_PROPERTIES); - - repository.setProperties(properties); - - List permissions = doc.field(FIELD_PERMISSIONS); - - repository.setPermissions( - OrientDBUtil.transformToItems( - PermissionConverter.INSTANCE, permissions)); - - return repository; - } - - /** - * Method description - * - * - * @param connection - */ - @Override - public void createShema(ODatabaseDocumentTx connection) - { - OSchema schema = connection.getMetadata().getSchema(); - OClass oclass = schema.getClass(DOCUMENT_CLASS); - - if (oclass == null) - { - oclass = schema.createClass(DOCUMENT_CLASS); - - // model properites - oclass.createProperty(FIELD_ID, OType.STRING); - oclass.createProperty(FIELD_TYPE, OType.STRING); - oclass.createProperty(FIELD_LASTMODIFIED, OType.LONG); - - // repository properties - oclass.createProperty(FIELD_CONTACT, OType.STRING); - oclass.createProperty(FIELD_CREATIONDATE, OType.LONG); - oclass.createProperty(FIELD_DESCRIPTION, OType.STRING); - oclass.createProperty(FIELD_NAME, OType.STRING); - oclass.createProperty(FIELD_PERMISSIONS, OType.EMBEDDEDLIST); - oclass.createProperty(FIELD_PROPERTIES, OType.EMBEDDEDMAP); - oclass.createProperty(FIELD_PUBLIC, OType.BOOLEAN); - - // indexes - oclass.createIndex(INDEX_ID, INDEX_TYPE.UNIQUE, FIELD_ID); - oclass.createIndex(INDEX_TYPEANDNAME, INDEX_TYPE.UNIQUE, FIELD_NAME, - FIELD_TYPE); - schema.save(); - } - - PermissionConverter.INSTANCE.createShema(connection); - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStore.java b/scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStore.java deleted file mode 100644 index ff2d791114..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStore.java +++ /dev/null @@ -1,222 +0,0 @@ -/** - * 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.store.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Provider; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.orientdb.OrientDBUtil; -import sonia.scm.store.AbstractListenableStore; -import sonia.scm.util.Util; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.StringReader; -import java.io.StringWriter; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; - -/** - * - * @author Sebastian Sdorra - * - * @param - */ -public class OrientDBStore extends AbstractListenableStore -{ - - /** Field description */ - public static final String DOCUMENT_CLASS = "StoreObject"; - - /** Field description */ - public static final String FIELD_DATA = "data"; - - /** Field description */ - public static final String FIELD_NAME = "name"; - - /** Field description */ - public static final String FIELD_TYPE = "type"; - - /** Field description */ - public static final String INDEX_NAME = "StoreTypeAndName"; - - /** Field description */ - public static final String QUERY_STORE = - "select from StoreObject where name = ? and type = ?"; - - /** - * the logger for OrientDBStore - */ - private static final Logger logger = - LoggerFactory.getLogger(OrientDBStore.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param connectionProvider - * @param context - * @param type - * @param name - */ - public OrientDBStore(Provider connectionProvider, - JAXBContext context, Class type, String name) - { - this.connectionProvider = connectionProvider; - this.context = context; - this.type = type; - this.name = name; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - @Override - protected T readObject() - { - T result = null; - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - ODocument doc = getStoreDocument(connection); - - if (doc != null) - { - String data = doc.field(FIELD_DATA); - - if (Util.isNotEmpty(data)) - { - StringReader reader = new StringReader(data); - - result = (T) context.createUnmarshaller().unmarshal(reader); - } - } - } - catch (JAXBException ex) - { - logger.error("could not unmarshall object", ex); - } - finally - { - OrientDBUtil.close(connection); - } - - return result; - } - - /** - * Method description - * - * - * @param t - */ - @Override - protected void writeObject(T t) - { - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - ODocument doc = getStoreDocument(connection); - - if (doc == null) - { - doc = new ODocument(DOCUMENT_CLASS); - doc.field(FIELD_NAME, name); - doc.field(FIELD_TYPE, type.getName()); - } - - StringWriter buffer = new StringWriter(); - - context.createMarshaller().marshal(t, buffer); - doc.field(FIELD_DATA, buffer.toString()); - doc.save(); - fireEvent(t); - } - catch (JAXBException ex) - { - logger.error("could not marshall object", ex); - } - finally - { - OrientDBUtil.close(connection); - } - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param connection - * - * @return - */ - private ODocument getStoreDocument(ODatabaseDocumentTx connection) - { - return OrientDBUtil.executeSingleResultQuery(connection, QUERY_STORE, name, - type.getName()); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private Provider connectionProvider; - - /** Field description */ - private JAXBContext context; - - /** Field description */ - private String name; - - /** Field description */ - private Class type; -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStoreFactory.java b/scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStoreFactory.java deleted file mode 100644 index 7e8c58b308..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/store/orientdb/OrientDBStoreFactory.java +++ /dev/null @@ -1,162 +0,0 @@ -/** - * 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.store.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.Singleton; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.metadata.schema.OClass; -import com.orientechnologies.orient.core.metadata.schema.OClass.INDEX_TYPE; -import com.orientechnologies.orient.core.metadata.schema.OSchema; -import com.orientechnologies.orient.core.metadata.schema.OType; - -import sonia.scm.SCMContextProvider; -import sonia.scm.orientdb.OrientDBUtil; -import sonia.scm.store.ListenableStoreFactory; -import sonia.scm.util.AssertUtil; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; - -/** - * - * @author Sebastian Sdorra - */ -@Singleton -public class OrientDBStoreFactory implements ListenableStoreFactory -{ - - /** - * Constructs ... - * - * - * @param connectionProvider - */ - @Inject - public OrientDBStoreFactory(Provider connectionProvider) - { - this.connectionProvider = connectionProvider; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @throws IOException - */ - @Override - public void close() throws IOException - { - - // do nothing - } - - /** - * Method description - * - * - * @param context - */ - @Override - public void init(SCMContextProvider context) - { - ODatabaseDocumentTx connection = connectionProvider.get(); - - try - { - OSchema schema = connection.getMetadata().getSchema(); - OClass oclass = schema.getClass(OrientDBStore.DOCUMENT_CLASS); - - if (oclass == null) - { - oclass = schema.createClass(OrientDBStore.DOCUMENT_CLASS); - oclass.createProperty(OrientDBStore.FIELD_NAME, OType.STRING); - oclass.createProperty(OrientDBStore.FIELD_TYPE, OType.STRING); - oclass.createProperty(OrientDBStore.FIELD_DATA, OType.STRING); - oclass.createIndex(OrientDBStore.INDEX_NAME, INDEX_TYPE.UNIQUE, - OrientDBStore.FIELD_NAME, OrientDBStore.FIELD_TYPE); - schema.save(); - } - } - finally - { - OrientDBUtil.close(connection); - } - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param type - * @param name - * @param - * - * @return - */ - @Override - public OrientDBStore getStore(Class type, String name) - { - AssertUtil.assertIsNotNull(type); - AssertUtil.assertIsNotEmpty(name); - - try - { - return new OrientDBStore(connectionProvider, - JAXBContext.newInstance(type), type, name); - } - catch (JAXBException ex) - { - throw new RuntimeException( - "could not create jaxb context for ".concat(type.getName()), ex); - } - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private Provider connectionProvider; -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/OrientDBUserDAO.java b/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/OrientDBUserDAO.java deleted file mode 100644 index e2fdf0d59d..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/OrientDBUserDAO.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * 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.user.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; -import com.google.inject.Provider; - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.orientdb.AbstractOrientDBModelDAO; -import sonia.scm.orientdb.OrientDBUtil; -import sonia.scm.user.User; -import sonia.scm.user.UserDAO; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - -/** - * - * @author Sebastian Sdorra - */ -public class OrientDBUserDAO extends AbstractOrientDBModelDAO - implements UserDAO -{ - - /** Field description */ - public static final String QUERY_ALL = "select from User"; - - /** Field description */ - public static final String QUERY_SINGLE_BYID = - "select from User where id = ?"; - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param connectionProvider - */ - @Inject - public OrientDBUserDAO(Provider connectionProvider) - { - super(connectionProvider, UserConverter.INSTANCE); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param connection - * - * @return - */ - @Override - protected List getAllDocuments(ODatabaseDocumentTx connection) - { - return OrientDBUtil.executeListResultQuery(connection, QUERY_ALL); - } - - /** - * Method description - * - * - * @param connection - * @param id - * - * @return - */ - @Override - protected ODocument getDocument(ODatabaseDocumentTx connection, String id) - { - return OrientDBUtil.executeSingleResultQuery(connection, QUERY_SINGLE_BYID, - id); - } -} diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java b/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java deleted file mode 100644 index 9753f21a19..0000000000 --- a/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java +++ /dev/null @@ -1,195 +0,0 @@ -/** - * 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.user.orientdb; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; -import com.orientechnologies.orient.core.metadata.schema.OClass; -import com.orientechnologies.orient.core.metadata.schema.OClass.INDEX_TYPE; -import com.orientechnologies.orient.core.metadata.schema.OSchema; -import com.orientechnologies.orient.core.metadata.schema.OType; -import com.orientechnologies.orient.core.record.impl.ODocument; - -import sonia.scm.orientdb.AbstractConverter; -import sonia.scm.orientdb.Converter; -import sonia.scm.user.User; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.Map; - -/** - * - * @author Sebastian Sdorra - */ -public class UserConverter extends AbstractConverter implements Converter -{ - - /** Field description */ - public static final String DOCUMENT_CLASS = "User"; - - /** Field description */ - public static final String FIELD_ACTIVE = "active"; - - /** Field description */ - public static final String FIELD_ADMIN = "admin"; - - /** Field description */ - public static final String FIELD_CREATIONDATE = "creationDate"; - - /** Field description */ - public static final String FIELD_DISPLAYNAME = "displayName"; - - /** Field description */ - public static final String FIELD_MAIL = "mail"; - - /** Field description */ - @SuppressWarnings("squid:S2068") - public static final String FIELD_PASSWORD = "password"; - - /** Field description */ - public static final String INDEX_ID = "UserId"; - - /** Field description */ - public static final UserConverter INSTANCE = new UserConverter(); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param item - * - * @return - */ - @Override - public ODocument convert(User item) - { - ODocument doc = new ODocument(DOCUMENT_CLASS); - - return convert(doc, item); - } - - /** - * Method description - * - * - * @param doc - * @param user - * - * @return - */ - @Override - public ODocument convert(ODocument doc, User user) - { - appendModelObjectFields(doc, user); - appendField(doc, FIELD_DISPLAYNAME, user.getDisplayName()); - appendField(doc, FIELD_MAIL, user.getMail()); - appendField(doc, FIELD_PASSWORD, user.getPassword()); - appendField(doc, FIELD_ADMIN, user.isAdmin()); - appendField(doc, FIELD_ACTIVE, user.isActive()); - appendField(doc, FIELD_CREATIONDATE, user.getCreationDate(), OType.LONG); - appendPropertiesField(doc, user); - - return doc; - } - - /** - * Method description - * - * - * @param doc - * - * @return - */ - @Override - public User convert(ODocument doc) - { - User user = new User(); - - user.setName(getStringField(doc, FIELD_ID)); - user.setDisplayName(getStringField(doc, FIELD_DISPLAYNAME)); - user.setMail(getStringField(doc, FIELD_MAIL)); - user.setPassword(getStringField(doc, FIELD_PASSWORD)); - user.setType(getStringField(doc, FIELD_TYPE)); - user.setAdmin(getBooleanField(doc, FIELD_ADMIN)); - user.setAdmin(getBooleanField(doc, FIELD_ACTIVE)); - user.setLastModified(getLongField(doc, FIELD_LASTMODIFIED)); - user.setCreationDate(getLongField(doc, FIELD_CREATIONDATE)); - - Map properties = doc.field(FIELD_PROPERTIES); - - user.setProperties(properties); - - return user; - } - - /** - * Method description - * - * - * @param connection - */ - @Override - public void createShema(ODatabaseDocumentTx connection) - { - OSchema schema = connection.getMetadata().getSchema(); - OClass oclass = schema.getClass(DOCUMENT_CLASS); - - if (oclass == null) - { - oclass = schema.createClass(DOCUMENT_CLASS); - - // model properites - oclass.createProperty(FIELD_ID, OType.STRING); - oclass.createProperty(FIELD_TYPE, OType.STRING); - oclass.createProperty(FIELD_LASTMODIFIED, OType.LONG); - - // user properties - oclass.createProperty(FIELD_ADMIN, OType.BOOLEAN); - oclass.createProperty(FIELD_CREATIONDATE, OType.LONG); - oclass.createProperty(FIELD_DISPLAYNAME, OType.STRING); - oclass.createProperty(FIELD_MAIL, OType.STRING); - oclass.createProperty(FIELD_ACTIVE, OType.STRING); - oclass.createProperty(FIELD_PASSWORD, OType.STRING); - oclass.createProperty(FIELD_PROPERTIES, OType.EMBEDDEDMAP); - - // indexes - oclass.createIndex(INDEX_ID, INDEX_TYPE.UNIQUE, FIELD_ID); - schema.save(); - } - } -} diff --git a/scm-dao-orientdb/src/main/resources/META-INF/scm/override.xml b/scm-dao-orientdb/src/main/resources/META-INF/scm/override.xml deleted file mode 100644 index f15b1f30e8..0000000000 --- a/scm-dao-orientdb/src/main/resources/META-INF/scm/override.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - sonia.scm.user.UserDAO - sonia.scm.user.orientdb.OrientDBUserDAO - - - - sonia.scm.group.GroupDAO - sonia.scm.group.orientdb.OrientDBGroupDAO - - - - sonia.scm.repository.RepositoryDAO - sonia.scm.repository.orientdb.OrientDBRepositoryDAO - - - - sonia.scm.store.StoreFactory - sonia.scm.store.orientdb.OrientDBStoreFactory - - - sonia.scm.orientdb.OrientDBModule - - \ No newline at end of file diff --git a/scm-dao-orientdb/src/main/resources/sonia/scm/orientdb/server-configuration.xml b/scm-dao-orientdb/src/main/resources/sonia/scm/orientdb/server-configuration.xml deleted file mode 100644 index 797270bbdb..0000000000 --- a/scm-dao-orientdb/src/main/resources/sonia/scm/orientdb/server-configuration.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 4e58b82373a8ae3a8359a3403f3cb424f55a1017 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 5 Apr 2018 21:58:00 +0200 Subject: [PATCH 039/178] update fron sonatype aether to eclipse aether 1.1.0 --- scm-webapp/pom.xml | 162 +++++++++--------- .../scm/plugin/AbstractDependencyFilter.java | 11 +- .../main/java/sonia/scm/plugin/Aether.java | 103 +++++------ .../plugin/AetherAuthenticationSelector.java | 20 +-- .../scm/plugin/AetherDependencyResolver.java | 33 ++-- .../sonia/scm/plugin/AetherPluginHandler.java | 11 +- .../scm/plugin/AetherServiceLocator.java | 63 ++++--- .../scm/plugin/DefaultProxySelector.java | 15 +- .../plugin/StringDependencyGraphDumper.java | 4 +- 9 files changed, 216 insertions(+), 206 deletions(-) diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 8c2d6379ae..43031a8cb1 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -25,22 +25,22 @@ - - + + javax.transaction jta 1.1 provided - + - + sonia.scm scm-core 1.58-SNAPSHOT - + sonia.scm scm-dao-xml @@ -64,7 +64,7 @@ scm-git-plugin 1.58-SNAPSHOT - + @@ -72,7 +72,7 @@ shiro-web ${shiro.version} - + org.apache.shiro shiro-guice @@ -116,13 +116,13 @@ provided - + com.sun.jersey.contribs jersey-multipart ${jersey.version} - + @@ -130,26 +130,26 @@ guice-multibindings ${guice.version} - + ch.qos.logback logback-classic - + org.slf4j jcl-over-slf4j ${slf4j.version} - + org.slf4j log4j-over-slf4j ${slf4j.version} - + @@ -157,46 +157,46 @@ ehcache-core ${ehcache.version} - + - + xml-apis xml-apis 1.4.01 - + - + commons-beanutils commons-beanutils - + commons-collections commons-collections - - - + commons-codec commons-codec 1.9 - + com.google.guava guava ${guava.version} - + org.quartz-scheduler quartz @@ -208,7 +208,7 @@ - + @@ -216,7 +216,7 @@ freemarker ${freemarker.version} - + com.github.spullara.mustache.java compiler @@ -226,13 +226,13 @@ - org.sonatype.aether + org.eclipse.aether aether-api ${aether.version} - org.sonatype.aether + org.eclipse.aether aether-impl ${aether.version} @@ -250,19 +250,25 @@ - org.sonatype.aether - aether-connector-asynchttpclient + org.eclipse.aether + aether-transport-http ${aether.version} - + - org.sonatype.aether - aether-connector-file + org.eclipse.aether + aether-transport-file ${aether.version} - + + + org.eclipse.aether + aether-connector-basic + ${aether.version} + + - + com.webcohesion.enunciate enunciate-core-annotations @@ -283,7 +289,7 @@ - + sonia.scm.plugins scm-git-plugin @@ -291,7 +297,7 @@ tests test - + sonia.scm.plugins scm-hg-plugin @@ -299,7 +305,7 @@ tests test - + sonia.scm.plugins scm-svn-plugin @@ -307,7 +313,7 @@ tests test - + org.seleniumhq.selenium selenium-java @@ -321,7 +327,7 @@ ${selenium.version} test - + org.seleniumhq.selenium htmlunit-driver @@ -342,23 +348,23 @@ ${jersey.version} test - + com.github.sdorra shiro-unit 1.0.0 test - + - + commons-logging commons-logging 1.1.3 provided - + log4j log4j @@ -371,7 +377,7 @@ - + com.mycila.maven-license-plugin maven-license-plugin @@ -393,7 +399,7 @@ true - + org.apache.maven.plugins @@ -412,7 +418,7 @@ - + org.apache.maven.plugins maven-antrun-plugin @@ -444,7 +450,7 @@ - + org.apache.maven.plugins maven-war-plugin @@ -513,8 +519,8 @@ ${project.build.sourceEncoding} 0 - - + + scm-webapp @@ -526,9 +532,9 @@ default 2.53.1 2.9.1 - 1.13.1 + 1.1.0 1.0 - 3.0.5 + 3.3.9 0.8.17 Tomcat e1 @@ -538,18 +544,18 @@ - + cluster - + - + sonia.scm scm-dao-orientdb 1.58-SNAPSHOT - + @@ -679,29 +685,29 @@ - + - + selenium - + - + org.apache.httpcomponents httpclient 4.3.2 test - + - + - + org.apache.maven.plugins maven-failsafe-plugin @@ -726,7 +732,7 @@ - + org.mortbay.jetty jetty-maven-plugin @@ -770,7 +776,7 @@ - + org.codehaus.mojo selenium-maven-plugin @@ -791,22 +797,22 @@ post-integration-test stop-server - + - + - + - + doc - + - + org.apache.maven.plugins maven-resources-plugin @@ -820,7 +826,7 @@ ${project.build.directory} - + src/main/doc true @@ -828,12 +834,12 @@ **/enunciate.xml - - + + - + com.webcohesion.enunciate enunciate-maven-plugin @@ -865,7 +871,7 @@ - + org.apache.maven.plugins maven-assembly-plugin @@ -884,12 +890,12 @@ - + - + diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java b/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java index d448358b64..8a17b1e50c 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java @@ -36,18 +36,13 @@ package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.Throwables; - +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.DependencyFilter; +import org.eclipse.aether.graph.DependencyNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonatype.aether.artifact.Artifact; -import org.sonatype.aether.graph.DependencyFilter; -import org.sonatype.aether.graph.DependencyNode; - -//~--- JDK imports ------------------------------------------------------------ - import java.io.IOException; - import java.util.List; import java.util.Set; diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java b/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java index 0ad53e62c3..0657b167b5 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java @@ -35,41 +35,34 @@ package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- -import org.apache.maven.repository.internal.MavenRepositorySystemSession; - +import com.google.common.base.Throwables; +import org.apache.maven.repository.internal.MavenRepositorySystemUtils; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.collection.DependencyCollectionException; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyFilter; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.repository.*; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.DependencyResolutionException; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.util.artifact.JavaScopes; +import org.eclipse.aether.util.filter.AndDependencyFilter; +import org.eclipse.aether.util.filter.DependencyFilterUtils; +import org.eclipse.aether.util.graph.transformer.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import org.sonatype.aether.RepositorySystem; -import org.sonatype.aether.RepositorySystemSession; -import org.sonatype.aether.collection.CollectRequest; -import org.sonatype.aether.collection.DependencyCollectionException; -import org.sonatype.aether.collection.DependencyGraphTransformer; -import org.sonatype.aether.graph.Dependency; -import org.sonatype.aether.graph.DependencyFilter; -import org.sonatype.aether.graph.DependencyNode; -import org.sonatype.aether.repository.LocalRepository; -import org.sonatype.aether.repository.LocalRepositoryManager; -import org.sonatype.aether.repository.Proxy; -import org.sonatype.aether.repository.RemoteRepository; -import org.sonatype.aether.repository.RepositoryPolicy; -import org.sonatype.aether.resolution.DependencyRequest; -import org.sonatype.aether.resolution.DependencyResolutionException; -import org.sonatype.aether.util.artifact.DefaultArtifact; -import org.sonatype.aether.util.artifact.JavaScopes; -import org.sonatype.aether.util.filter.AndDependencyFilter; -import org.sonatype.aether.util.filter.DependencyFilterUtils; -import org.sonatype.aether.util.graph.transformer - .ChainedDependencyGraphTransformer; -import org.sonatype.aether.util.graph.transformer.ConflictMarker; -import org.sonatype.aether.util.graph.transformer.JavaDependencyContextRefiner; -import org.sonatype.aether.util.graph.transformer.JavaEffectiveScopeCalculator; -import org.sonatype.aether.util.graph.transformer - .NearestVersionConflictResolver; - import sonia.scm.config.ScmConfiguration; import sonia.scm.net.Proxies; +import java.net.MalformedURLException; +import java.net.URL; + /** * * @author Sebastian Sdorra @@ -77,6 +70,8 @@ import sonia.scm.net.Proxies; public final class Aether { + private static final ServiceLocator serviceLocator = new AetherServiceLocator(); + /** Field description */ private static final DependencyFilter FILTER = new AndDependencyFilter(new CoreDependencyFilter(), @@ -134,11 +129,9 @@ public final class Aether public static RemoteRepository createRemoteRepository( ScmConfiguration configuration, PluginRepository pluginRepository) { - RemoteRepository remoteRepository = - new RemoteRepository(pluginRepository.getId(), "default", - pluginRepository.getUrl()); + RemoteRepository.Builder builder = new RemoteRepository.Builder(pluginRepository.getId(), "default", pluginRepository.getUrl()); - if (Proxies.isEnabled(configuration, remoteRepository.getHost())) + if (Proxies.isEnabled(configuration, hostFromUrl(pluginRepository.getUrl()))) { Proxy proxy = DefaultProxySelector.createProxy(configuration); @@ -148,10 +141,18 @@ public final class Aether pluginRepository.getUrl()); } - remoteRepository.setProxy(proxy); + builder.setProxy(proxy); } - return remoteRepository; + return builder.build(); + } + + private static String hostFromUrl(String url) { + try { + return new URL(url).getHost(); + } catch (MalformedURLException e) { + throw Throwables.propagate(e); + } } /** @@ -162,7 +163,7 @@ public final class Aether */ public static RepositorySystem createRepositorySystem() { - return new AetherServiceLocator().getService(RepositorySystem.class); + return serviceLocator.getService(RepositorySystem.class); } /** @@ -181,8 +182,7 @@ public final class Aether ScmConfiguration configuration, AdvancedPluginConfiguration advancedPluginConfiguration) { - MavenRepositorySystemSession session = new MavenRepositorySystemSession(); - + DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_WARN); if (configuration.isEnableProxy()) @@ -191,23 +191,26 @@ public final class Aether session.setProxySelector(new DefaultProxySelector(configuration)); } - LocalRepositoryManager localRepositoryManager = - system.newLocalRepositoryManager(localRepository); + LocalRepositoryManager localRepositoryManager = system.newLocalRepositoryManager(session, localRepository); session.setLocalRepositoryManager(localRepositoryManager); session.setAuthenticationSelector( new AetherAuthenticationSelector(advancedPluginConfiguration) ); - // create graph transformer to resolve dependency conflicts - //J- - DependencyGraphTransformer dgt = new ChainedDependencyGraphTransformer( - new ConflictMarker(), - new JavaEffectiveScopeCalculator(), - new NearestVersionConflictResolver(), - new JavaDependencyContextRefiner() + // create graph transformer and conflictResolver to resolve dependency conflicts + ConflictResolver conflictResolver = new ConflictResolver( + new NearestVersionSelector(), + new JavaScopeSelector(), + new SimpleOptionalitySelector(), + new JavaScopeDeriver() + ); + + DependencyGraphTransformer dgt = new ChainedDependencyGraphTransformer( + new ConflictMarker(), + conflictResolver, + new JavaDependencyContextRefiner() ); - //J+ session.setDependencyGraphTransformer(dgt); @@ -228,7 +231,7 @@ public final class Aether * @throws DependencyResolutionException */ public static DependencyNode resolveDependencies(RepositorySystem system, - RepositorySystemSession session, CollectRequest request) + RepositorySystemSession session, CollectRequest request) throws DependencyCollectionException, DependencyResolutionException { DependencyNode node = system.collectDependencies(session, diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherAuthenticationSelector.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherAuthenticationSelector.java index 1f264940f8..59e8eb481e 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherAuthenticationSelector.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherAuthenticationSelector.java @@ -36,20 +36,18 @@ package sonia.scm.plugin; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; - +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.util.repository.AuthenticationBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import org.sonatype.aether.repository.Authentication; -import org.sonatype.aether.repository.AuthenticationSelector; -import org.sonatype.aether.repository.RemoteRepository; - import sonia.scm.plugin.AdvancedPluginConfiguration.Server; -//~--- JDK imports ------------------------------------------------------------ - import java.util.Map; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -115,8 +113,10 @@ public class AetherAuthenticationSelector implements AuthenticationSelector { logger.info("use user {} for repository wiht id {}", server.getUsername(), repository.getId()); - authentication = new Authentication(server.getUsername(), - server.getPassword()); + authentication = new AuthenticationBuilder() + .addUsername(server.getUsername()) + .addPassword(server.getPassword()) + .build(); } return authentication; diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java index ee0e9b586c..f4e26b9955 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java @@ -36,27 +36,24 @@ package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.collect.Lists; - +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.collection.DependencyCollectionException; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.DependencyResolutionException; +import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import org.sonatype.aether.RepositorySystem; -import org.sonatype.aether.RepositorySystemSession; -import org.sonatype.aether.collection.CollectRequest; -import org.sonatype.aether.collection.DependencyCollectionException; -import org.sonatype.aether.graph.Dependency; -import org.sonatype.aether.graph.DependencyNode; -import org.sonatype.aether.repository.LocalRepository; -import org.sonatype.aether.repository.RemoteRepository; -import org.sonatype.aether.resolution.DependencyResolutionException; -import org.sonatype.aether.util.graph.PreorderNodeListGenerator; - import sonia.scm.config.ScmConfiguration; -//~--- JDK imports ------------------------------------------------------------ - import java.util.List; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -83,9 +80,9 @@ public class AetherDependencyResolver * @param remoteRepositories */ public AetherDependencyResolver(ScmConfiguration configuration, - AdvancedPluginConfiguration advancedPluginConfiguration, - RepositorySystem system, LocalRepository localRepository, - List remoteRepositories) + AdvancedPluginConfiguration advancedPluginConfiguration, + RepositorySystem system, LocalRepository localRepository, + List remoteRepositories) { this.configuration = configuration; this.advancedPluginConfiguration = advancedPluginConfiguration; diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java index b122463a24..8668277f12 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java @@ -40,10 +40,10 @@ import com.google.common.collect.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonatype.aether.RepositorySystem; -import org.sonatype.aether.graph.Dependency; -import org.sonatype.aether.repository.LocalRepository; -import org.sonatype.aether.repository.RemoteRepository; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; import sonia.scm.ConfigurationException; import sonia.scm.SCMContextProvider; @@ -190,7 +190,6 @@ public class AetherPluginHandler * * * @param dependency - * @param dependencies * @param localDependencies */ private void collectDependencies(Dependency dependency, @@ -200,7 +199,7 @@ public class AetherPluginHandler { //J- AetherDependencyResolver resolver = new AetherDependencyResolver( - configuration, advancedPluginConfiguration, repositorySystem, + configuration, advancedPluginConfiguration, repositorySystem, localRepository, remoteRepositories ); //J+ diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherServiceLocator.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherServiceLocator.java index 79038a4102..4220064882 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherServiceLocator.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherServiceLocator.java @@ -37,32 +37,30 @@ package sonia.scm.plugin; import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader; import org.apache.maven.repository.internal.DefaultVersionRangeResolver; import org.apache.maven.repository.internal.DefaultVersionResolver; +import org.apache.maven.repository.internal.MavenRepositorySystemUtils; +import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; +import org.eclipse.aether.impl.ArtifactDescriptorReader; +import org.eclipse.aether.impl.DefaultServiceLocator; +import org.eclipse.aether.impl.VersionRangeResolver; +import org.eclipse.aether.impl.VersionResolver; +import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory; +import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.transport.file.FileTransporterFactory; +import org.eclipse.aether.transport.http.HttpTransporterFactory; -import org.slf4j.LoggerFactory; - -import org.sonatype.aether.connector.async.AsyncRepositoryConnectorFactory; -import org.sonatype.aether.connector.file.FileRepositoryConnectorFactory; -import org.sonatype.aether.impl.ArtifactDescriptorReader; -import org.sonatype.aether.impl.VersionRangeResolver; -import org.sonatype.aether.impl.VersionResolver; -import org.sonatype.aether.impl.internal.DefaultServiceLocator; -import org.sonatype.aether.impl.internal.Slf4jLogger; -import org.sonatype.aether.spi.connector.RepositoryConnectorFactory; -import org.sonatype.aether.spi.log.Logger; +import java.util.List; /** * * @author Sebastian Sdorra */ -public class AetherServiceLocator extends DefaultServiceLocator +public class AetherServiceLocator implements ServiceLocator { - /** Field description */ - private static final String LOGGER_NAME = "org.sonatype.aether"; - - /** Field description */ - private static final Slf4jLogger logger = - new Slf4jLogger(LoggerFactory.getLogger(LOGGER_NAME)); + private DefaultServiceLocator delegate; //~--- constructors --------------------------------------------------------- @@ -70,16 +68,25 @@ public class AetherServiceLocator extends DefaultServiceLocator * Constructs ... * */ - public AetherServiceLocator() + AetherServiceLocator() { - setServices(Logger.class, logger); - addService(VersionResolver.class, DefaultVersionResolver.class); - addService(VersionRangeResolver.class, DefaultVersionRangeResolver.class); - addService(ArtifactDescriptorReader.class, - DefaultArtifactDescriptorReader.class); - addService(RepositoryConnectorFactory.class, - AsyncRepositoryConnectorFactory.class); - addService(RepositoryConnectorFactory.class, - FileRepositoryConnectorFactory.class); + delegate = MavenRepositorySystemUtils.newServiceLocator(); + delegate.setService(LoggerFactory.class, Slf4jLoggerFactory.class); + delegate.addService(VersionResolver.class, DefaultVersionResolver.class); + delegate.addService(VersionRangeResolver.class, DefaultVersionRangeResolver.class); + delegate.addService(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class); + delegate.addService(TransporterFactory.class, HttpTransporterFactory.class); + delegate.addService(TransporterFactory.class, FileTransporterFactory.class); + delegate.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); + } + + @Override + public T getService(Class type) { + return delegate.getService(type); + } + + @Override + public List getServices(Class type) { + return delegate.getServices(type); } } diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultProxySelector.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultProxySelector.java index fd3ad16507..ba694e01a8 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultProxySelector.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultProxySelector.java @@ -34,13 +34,13 @@ package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RemoteRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonatype.aether.repository.Authentication; -import org.sonatype.aether.repository.Proxy; -import org.sonatype.aether.repository.ProxySelector; -import org.sonatype.aether.repository.RemoteRepository; import sonia.scm.config.ScmConfiguration; import sonia.scm.util.Util; @@ -89,8 +89,11 @@ public class DefaultProxySelector implements ProxySelector if (Util.isNotEmpty(username) || Util.isNotEmpty(password)) { - authentication = new Authentication(Util.nonNull(username), - Util.nonNull(password)); + /* + TODO + authentication = new Authentication(Util.nonNull(username), Util.nonNull(password)); + */ + } return new Proxy(Proxy.TYPE_HTTP, configuration.getProxyServer(), diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/StringDependencyGraphDumper.java b/scm-webapp/src/main/java/sonia/scm/plugin/StringDependencyGraphDumper.java index 5bfcdebd23..126be9da6a 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/StringDependencyGraphDumper.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/StringDependencyGraphDumper.java @@ -34,8 +34,8 @@ package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- -import org.sonatype.aether.graph.DependencyNode; -import org.sonatype.aether.graph.DependencyVisitor; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.graph.DependencyVisitor; /** * From 49168b10a7dd38ee2678857e0fa7ff5c9a943857 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 5 Apr 2018 21:59:41 +0200 Subject: [PATCH 040/178] update apache shiro to version 1.3.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6e4b76b847..65d5b6e35a 100644 --- a/pom.xml +++ b/pom.xml @@ -490,7 +490,7 @@ 1.9.13 - 1.3.0 + 1.3.2 v4.5.3.201708160445-r-scm1 From 482589fc67881c7e15e0da66b307e54dc125624c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 6 Apr 2018 08:28:50 +0200 Subject: [PATCH 041/178] [maven-release-plugin] prepare release 1.58 --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 22 +++++++++++----------- support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 23 files changed, 71 insertions(+), 71 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index d371d05c94..b035bf6ae1 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58-SNAPSHOT + 1.58 sonia.scm.maven scm-maven-plugins pom - 1.58-SNAPSHOT + 1.58 scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index f6d85bf8cb..df4251d610 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.58-SNAPSHOT + 1.58 sonia.scm.maven scm-maven-plugin - 1.58-SNAPSHOT + 1.58 maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 201664de81..4914db4c6a 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.58-SNAPSHOT + 1.58 sonia.scm.maven scm-plugin-archetype - 1.58-SNAPSHOT + 1.58 scm-plugin-archetype diff --git a/pom.xml b/pom.xml index 65d5b6e35a..7a8ece68b0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.58-SNAPSHOT + 1.58 The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - HEAD + 1.58 diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 0e18675860..82ec11c4ed 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58-SNAPSHOT + 1.58 sonia.scm.clients scm-clients pom - 1.58-SNAPSHOT + 1.58 scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.58-SNAPSHOT + 1.58 shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 1d26cee2b4..8360abe06f 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.58-SNAPSHOT + 1.58 sonia.scm.clients scm-cli-client - 1.58-SNAPSHOT + 1.58 scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.58-SNAPSHOT + 1.58 diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index 75ac3d81d7..a6f2fdf3b7 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.58-SNAPSHOT + 1.58 sonia.scm.clients scm-client-api jar - 1.58-SNAPSHOT + 1.58 scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index e97a96e380..1278c841e5 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.58-SNAPSHOT + 1.58 sonia.scm.clients scm-client-impl jar - 1.58-SNAPSHOT + 1.58 scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.58-SNAPSHOT + 1.58 @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.58-SNAPSHOT + 1.58 test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 72c40c1f9a..67baea7f97 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.58-SNAPSHOT + 1.58 sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 scm-core diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index a6f7898246..7694ccbb6f 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.58-SNAPSHOT + 1.58 sonia.scm scm-dao-xml - 1.58-SNAPSHOT + 1.58 scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.58-SNAPSHOT + 1.58 test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index bc59a101a8..aa99261ecb 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.58-SNAPSHOT + 1.58 sonia.scm scm-plugin-backend war - 1.58-SNAPSHOT + 1.58 ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index e11e11ebde..f42a7a58dc 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58-SNAPSHOT + 1.58 sonia.scm.plugins scm-plugins pom - 1.58-SNAPSHOT + 1.58 scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.58-SNAPSHOT + 1.58 process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 60c617cfd1..a3135bebea 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.58-SNAPSHOT + 1.58 sonia.scm.plugins scm-git-plugin - 1.58-SNAPSHOT + 1.58 scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.58-SNAPSHOT + 1.58 test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 0bced018e6..4e081d3766 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.58-SNAPSHOT + 1.58 sonia.scm.plugins scm-hg-plugin - 1.58-SNAPSHOT + 1.58 scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.58-SNAPSHOT + 1.58 test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 0be176d42c..b3f5214239 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.58-SNAPSHOT + 1.58 sonia.scm.plugins scm-svn-plugin - 1.58-SNAPSHOT + 1.58 scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.58-SNAPSHOT + 1.58 test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 22e4b9cc04..a5712aa81d 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58-SNAPSHOT + 1.58 sonia.scm.samples scm-samples pom - 1.58-SNAPSHOT + 1.58 scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 05ec3fddd9..13ec4d8266 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.58-SNAPSHOT + 1.58 sonia.scm.sample scm-sample-auth - 1.58-SNAPSHOT + 1.58 scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index f896257930..67b34814d1 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.58-SNAPSHOT + 1.58 sonia.scm.sample scm-sample-hello - 1.58-SNAPSHOT + 1.58 scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 50c77d05fd..b5c1bbff15 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.58-SNAPSHOT + 1.58 sonia.scm scm-server - 1.58-SNAPSHOT + 1.58 scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 3f769f3367..6de92ac324 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.58-SNAPSHOT + 1.58 sonia.scm scm-test - 1.58-SNAPSHOT + 1.58 scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 43031a8cb1..c4c0e54bee 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58-SNAPSHOT + 1.58 sonia.scm scm-webapp war - 1.58-SNAPSHOT + 1.58 scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 sonia.scm scm-dao-xml - 1.58-SNAPSHOT + 1.58 sonia.scm.plugins scm-hg-plugin - 1.58-SNAPSHOT + 1.58 sonia.scm.plugins scm-svn-plugin - 1.58-SNAPSHOT + 1.58 sonia.scm.plugins scm-git-plugin - 1.58-SNAPSHOT + 1.58 @@ -280,7 +280,7 @@ sonia.scm scm-test - 1.58-SNAPSHOT + 1.58 test @@ -293,7 +293,7 @@ sonia.scm.plugins scm-git-plugin - 1.58-SNAPSHOT + 1.58 tests test @@ -301,7 +301,7 @@ sonia.scm.plugins scm-hg-plugin - 1.58-SNAPSHOT + 1.58 tests test @@ -309,7 +309,7 @@ sonia.scm.plugins scm-svn-plugin - 1.58-SNAPSHOT + 1.58 tests test diff --git a/support/pom.xml b/support/pom.xml index 9db5842b99..768b99b4b6 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58-SNAPSHOT + 1.58 sonia.scm.support scm-support pom - 1.58-SNAPSHOT + 1.58 scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index 28b1febe75..fbc1f06fdc 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.58-SNAPSHOT + 1.58 sonia.scm scm-support-btrace - 1.58-SNAPSHOT + 1.58 jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.58-SNAPSHOT + 1.58 From 5575b4cd11087649ca18dd38ec5987919e58638c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 6 Apr 2018 08:28:51 +0200 Subject: [PATCH 042/178] [maven-release-plugin] copy for tag 1.58 From dd313036ffbb9a75ac71198a2c59fec3e5db3fc9 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 6 Apr 2018 08:28:51 +0200 Subject: [PATCH 043/178] [maven-release-plugin] prepare for next development iteration --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 22 +++++++++++----------- support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 23 files changed, 71 insertions(+), 71 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index b035bf6ae1..a1ed336d8c 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58 + 1.59-SNAPSHOT sonia.scm.maven scm-maven-plugins pom - 1.58 + 1.59-SNAPSHOT scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index df4251d610..c52e518a7d 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.58 + 1.59-SNAPSHOT sonia.scm.maven scm-maven-plugin - 1.58 + 1.59-SNAPSHOT maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 4914db4c6a..4b74d47a7c 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.58 + 1.59-SNAPSHOT sonia.scm.maven scm-plugin-archetype - 1.58 + 1.59-SNAPSHOT scm-plugin-archetype diff --git a/pom.xml b/pom.xml index 7a8ece68b0..eb5d09d1fe 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.58 + 1.59-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - 1.58 + HEAD diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 82ec11c4ed..1903d4ea2a 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58 + 1.59-SNAPSHOT sonia.scm.clients scm-clients pom - 1.58 + 1.59-SNAPSHOT scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.58 + 1.59-SNAPSHOT shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 8360abe06f..7b3d7d9464 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.58 + 1.59-SNAPSHOT sonia.scm.clients scm-cli-client - 1.58 + 1.59-SNAPSHOT scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.58 + 1.59-SNAPSHOT diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index a6f2fdf3b7..74dcb8c861 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.58 + 1.59-SNAPSHOT sonia.scm.clients scm-client-api jar - 1.58 + 1.59-SNAPSHOT scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 1278c841e5..e6cae0bbaa 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.58 + 1.59-SNAPSHOT sonia.scm.clients scm-client-impl jar - 1.58 + 1.59-SNAPSHOT scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.58 + 1.59-SNAPSHOT @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.58 + 1.59-SNAPSHOT test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 67baea7f97..8371073636 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.58 + 1.59-SNAPSHOT sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT scm-core diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 7694ccbb6f..1716dff787 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.58 + 1.59-SNAPSHOT sonia.scm scm-dao-xml - 1.58 + 1.59-SNAPSHOT scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.58 + 1.59-SNAPSHOT test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index aa99261ecb..070dc2955e 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.58 + 1.59-SNAPSHOT sonia.scm scm-plugin-backend war - 1.58 + 1.59-SNAPSHOT ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index f42a7a58dc..b4214fab06 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58 + 1.59-SNAPSHOT sonia.scm.plugins scm-plugins pom - 1.58 + 1.59-SNAPSHOT scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.58 + 1.59-SNAPSHOT process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index a3135bebea..66590a19d6 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.58 + 1.59-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.58 + 1.59-SNAPSHOT scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.58 + 1.59-SNAPSHOT test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 4e081d3766..938936df13 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.58 + 1.59-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.58 + 1.59-SNAPSHOT scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.58 + 1.59-SNAPSHOT test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index b3f5214239..26054696e7 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.58 + 1.59-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.58 + 1.59-SNAPSHOT scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.58 + 1.59-SNAPSHOT test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index a5712aa81d..5d91b43022 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58 + 1.59-SNAPSHOT sonia.scm.samples scm-samples pom - 1.58 + 1.59-SNAPSHOT scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 13ec4d8266..f53b75e16e 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.58 + 1.59-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.58 + 1.59-SNAPSHOT scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 67b34814d1..2b1eb4302f 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.58 + 1.59-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.58 + 1.59-SNAPSHOT scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT diff --git a/scm-server/pom.xml b/scm-server/pom.xml index b5c1bbff15..857e0cf5be 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.58 + 1.59-SNAPSHOT sonia.scm scm-server - 1.58 + 1.59-SNAPSHOT scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 6de92ac324..003aa41c64 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.58 + 1.59-SNAPSHOT sonia.scm scm-test - 1.58 + 1.59-SNAPSHOT scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index c4c0e54bee..5684b7ace1 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58 + 1.59-SNAPSHOT sonia.scm scm-webapp war - 1.58 + 1.59-SNAPSHOT scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT sonia.scm scm-dao-xml - 1.58 + 1.59-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.58 + 1.59-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.58 + 1.59-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.58 + 1.59-SNAPSHOT @@ -280,7 +280,7 @@ sonia.scm scm-test - 1.58 + 1.59-SNAPSHOT test @@ -293,7 +293,7 @@ sonia.scm.plugins scm-git-plugin - 1.58 + 1.59-SNAPSHOT tests test @@ -301,7 +301,7 @@ sonia.scm.plugins scm-hg-plugin - 1.58 + 1.59-SNAPSHOT tests test @@ -309,7 +309,7 @@ sonia.scm.plugins scm-svn-plugin - 1.58 + 1.59-SNAPSHOT tests test diff --git a/support/pom.xml b/support/pom.xml index 768b99b4b6..d099d6bf4e 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.58 + 1.59-SNAPSHOT sonia.scm.support scm-support pom - 1.58 + 1.59-SNAPSHOT scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index fbc1f06fdc..9ced93263c 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.58 + 1.59-SNAPSHOT sonia.scm scm-support-btrace - 1.58 + 1.59-SNAPSHOT jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.58 + 1.59-SNAPSHOT From 7ed4dbcf002016a922c95db5157b771c037dcbb4 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 6 Apr 2018 14:01:00 +0200 Subject: [PATCH 044/178] fix hgweb execution for mercurial versions prior 4.1 --- .../scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py index ff2869044d..e2e7d8e931 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py @@ -36,7 +36,7 @@ from mercurial.hgweb import hgweb, wsgicgi demandimport.enable() -u = uimod.ui.load() +u = uimod.ui() # pass SCM_HTTP_POST_ARGS to enable experimental httppostargs protocol of mercurial # SCM_HTTP_POST_ARGS is set by HgCGIServlet From e230c0f4cd2eaa4bf437ea4121d11d1b963f56da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 6 Apr 2018 20:30:15 +0000 Subject: [PATCH 045/178] make {extras} work on old versions of Hg --- .../src/main/resources/sonia/scm/styles/changesets-eager.style | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style index 73b3ec694b..2185c47a05 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/styles/changesets-eager.style @@ -1,7 +1,8 @@ header = "%{pattern}" -changeset = "{rev}:{node}{author}\n{date|hgdate}\n{branch}\n{parents}close={ifeq(get(extras, 'close'),1,1,0)}\n{tags}{file_adds}{file_mods}{file_dels}\n{desc}\0" +changeset = "{rev}:{node}{author}\n{date|hgdate}\n{branch}\n{parents}{extras}\n{tags}{file_adds}{file_mods}{file_dels}\n{desc}\0" tag = "t {tag}\n" file_add = "a {file_add}\n" file_mod = "m {file_mod}\n" file_del = "d {file_del}\n" +extra = "{key}={value|stringescape}," footer = "%{pattern}" \ No newline at end of file From 92a492f68b5751cb1a649323dc4307f711f32723 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 11 Apr 2018 10:09:11 +0200 Subject: [PATCH 046/178] [maven-release-plugin] prepare release 1.59 --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 22 +++++++++++----------- support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 23 files changed, 71 insertions(+), 71 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index a1ed336d8c..816f79db1c 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59-SNAPSHOT + 1.59 sonia.scm.maven scm-maven-plugins pom - 1.59-SNAPSHOT + 1.59 scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index c52e518a7d..281b256428 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.59-SNAPSHOT + 1.59 sonia.scm.maven scm-maven-plugin - 1.59-SNAPSHOT + 1.59 maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 4b74d47a7c..6e80df4106 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.59-SNAPSHOT + 1.59 sonia.scm.maven scm-plugin-archetype - 1.59-SNAPSHOT + 1.59 scm-plugin-archetype diff --git a/pom.xml b/pom.xml index eb5d09d1fe..ab43a93112 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.59-SNAPSHOT + 1.59 The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - HEAD + 1.59 diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 1903d4ea2a..39ad548338 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59-SNAPSHOT + 1.59 sonia.scm.clients scm-clients pom - 1.59-SNAPSHOT + 1.59 scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.59-SNAPSHOT + 1.59 shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 7b3d7d9464..53fb3636d2 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.59-SNAPSHOT + 1.59 sonia.scm.clients scm-cli-client - 1.59-SNAPSHOT + 1.59 scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.59-SNAPSHOT + 1.59 diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index 74dcb8c861..e79a729934 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.59-SNAPSHOT + 1.59 sonia.scm.clients scm-client-api jar - 1.59-SNAPSHOT + 1.59 scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index e6cae0bbaa..2afc822d4f 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.59-SNAPSHOT + 1.59 sonia.scm.clients scm-client-impl jar - 1.59-SNAPSHOT + 1.59 scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.59-SNAPSHOT + 1.59 @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.59-SNAPSHOT + 1.59 test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 8371073636..a69d19d9bf 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.59-SNAPSHOT + 1.59 sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 scm-core diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 1716dff787..0af6ee3117 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.59-SNAPSHOT + 1.59 sonia.scm scm-dao-xml - 1.59-SNAPSHOT + 1.59 scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.59-SNAPSHOT + 1.59 test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index 070dc2955e..8a08b7c48f 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.59-SNAPSHOT + 1.59 sonia.scm scm-plugin-backend war - 1.59-SNAPSHOT + 1.59 ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index b4214fab06..031360efba 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59-SNAPSHOT + 1.59 sonia.scm.plugins scm-plugins pom - 1.59-SNAPSHOT + 1.59 scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.59-SNAPSHOT + 1.59 process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 66590a19d6..9973c8856d 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.59-SNAPSHOT + 1.59 sonia.scm.plugins scm-git-plugin - 1.59-SNAPSHOT + 1.59 scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.59-SNAPSHOT + 1.59 test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 938936df13..e911c7a030 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.59-SNAPSHOT + 1.59 sonia.scm.plugins scm-hg-plugin - 1.59-SNAPSHOT + 1.59 scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.59-SNAPSHOT + 1.59 test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 26054696e7..050ad7b2ef 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.59-SNAPSHOT + 1.59 sonia.scm.plugins scm-svn-plugin - 1.59-SNAPSHOT + 1.59 scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.59-SNAPSHOT + 1.59 test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 5d91b43022..84324dd576 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59-SNAPSHOT + 1.59 sonia.scm.samples scm-samples pom - 1.59-SNAPSHOT + 1.59 scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index f53b75e16e..898caddb9d 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.59-SNAPSHOT + 1.59 sonia.scm.sample scm-sample-auth - 1.59-SNAPSHOT + 1.59 scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 2b1eb4302f..faaef48f8e 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.59-SNAPSHOT + 1.59 sonia.scm.sample scm-sample-hello - 1.59-SNAPSHOT + 1.59 scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 857e0cf5be..5ad81d34cd 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.59-SNAPSHOT + 1.59 sonia.scm scm-server - 1.59-SNAPSHOT + 1.59 scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 003aa41c64..533f4c57be 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.59-SNAPSHOT + 1.59 sonia.scm scm-test - 1.59-SNAPSHOT + 1.59 scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 5684b7ace1..22fcd213bb 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59-SNAPSHOT + 1.59 sonia.scm scm-webapp war - 1.59-SNAPSHOT + 1.59 scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 sonia.scm scm-dao-xml - 1.59-SNAPSHOT + 1.59 sonia.scm.plugins scm-hg-plugin - 1.59-SNAPSHOT + 1.59 sonia.scm.plugins scm-svn-plugin - 1.59-SNAPSHOT + 1.59 sonia.scm.plugins scm-git-plugin - 1.59-SNAPSHOT + 1.59 @@ -280,7 +280,7 @@ sonia.scm scm-test - 1.59-SNAPSHOT + 1.59 test @@ -293,7 +293,7 @@ sonia.scm.plugins scm-git-plugin - 1.59-SNAPSHOT + 1.59 tests test @@ -301,7 +301,7 @@ sonia.scm.plugins scm-hg-plugin - 1.59-SNAPSHOT + 1.59 tests test @@ -309,7 +309,7 @@ sonia.scm.plugins scm-svn-plugin - 1.59-SNAPSHOT + 1.59 tests test diff --git a/support/pom.xml b/support/pom.xml index d099d6bf4e..b1c51c9494 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59-SNAPSHOT + 1.59 sonia.scm.support scm-support pom - 1.59-SNAPSHOT + 1.59 scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index 9ced93263c..6b47cdb7b6 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.59-SNAPSHOT + 1.59 sonia.scm scm-support-btrace - 1.59-SNAPSHOT + 1.59 jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.59-SNAPSHOT + 1.59 From 39ceb11e9b76ce27b1dec9253254ee5327ef91be Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 11 Apr 2018 10:09:11 +0200 Subject: [PATCH 047/178] [maven-release-plugin] copy for tag 1.59 From 247ee63a95a939484dce471337dda1d550947eec Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 11 Apr 2018 10:09:12 +0200 Subject: [PATCH 048/178] [maven-release-plugin] prepare for next development iteration --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 22 +++++++++++----------- support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 23 files changed, 71 insertions(+), 71 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index 816f79db1c..9215c0c526 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59 + 1.60-SNAPSHOT sonia.scm.maven scm-maven-plugins pom - 1.59 + 1.60-SNAPSHOT scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 281b256428..956a8339a4 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.59 + 1.60-SNAPSHOT sonia.scm.maven scm-maven-plugin - 1.59 + 1.60-SNAPSHOT maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 6e80df4106..8031c1e2a6 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.59 + 1.60-SNAPSHOT sonia.scm.maven scm-plugin-archetype - 1.59 + 1.60-SNAPSHOT scm-plugin-archetype diff --git a/pom.xml b/pom.xml index ab43a93112..3f4cfda18a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.59 + 1.60-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - 1.59 + HEAD diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 39ad548338..dbbf9abe99 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59 + 1.60-SNAPSHOT sonia.scm.clients scm-clients pom - 1.59 + 1.60-SNAPSHOT scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.59 + 1.60-SNAPSHOT shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index 53fb3636d2..ee196d5c11 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.59 + 1.60-SNAPSHOT sonia.scm.clients scm-cli-client - 1.59 + 1.60-SNAPSHOT scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.59 + 1.60-SNAPSHOT diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index e79a729934..498c3dac3d 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.59 + 1.60-SNAPSHOT sonia.scm.clients scm-client-api jar - 1.59 + 1.60-SNAPSHOT scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 2afc822d4f..1150017db7 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.59 + 1.60-SNAPSHOT sonia.scm.clients scm-client-impl jar - 1.59 + 1.60-SNAPSHOT scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.59 + 1.60-SNAPSHOT @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.59 + 1.60-SNAPSHOT test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index a69d19d9bf..1547e778f4 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.59 + 1.60-SNAPSHOT sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT scm-core diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 0af6ee3117..d42307809e 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.59 + 1.60-SNAPSHOT sonia.scm scm-dao-xml - 1.59 + 1.60-SNAPSHOT scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.59 + 1.60-SNAPSHOT test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index 8a08b7c48f..921e9756dd 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.59 + 1.60-SNAPSHOT sonia.scm scm-plugin-backend war - 1.59 + 1.60-SNAPSHOT ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 031360efba..513dc0a6fe 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59 + 1.60-SNAPSHOT sonia.scm.plugins scm-plugins pom - 1.59 + 1.60-SNAPSHOT scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.59 + 1.60-SNAPSHOT process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 9973c8856d..8b15ad31fa 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.59 + 1.60-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.59 + 1.60-SNAPSHOT scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.59 + 1.60-SNAPSHOT test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index e911c7a030..cf4c42d1dc 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.59 + 1.60-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.59 + 1.60-SNAPSHOT scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.59 + 1.60-SNAPSHOT test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 050ad7b2ef..025193838d 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.59 + 1.60-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.59 + 1.60-SNAPSHOT scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.59 + 1.60-SNAPSHOT test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 84324dd576..1b25fb0b18 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59 + 1.60-SNAPSHOT sonia.scm.samples scm-samples pom - 1.59 + 1.60-SNAPSHOT scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 898caddb9d..f443d37763 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.59 + 1.60-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.59 + 1.60-SNAPSHOT scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index faaef48f8e..21199294ba 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.59 + 1.60-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.59 + 1.60-SNAPSHOT scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 5ad81d34cd..ef1bac43c8 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.59 + 1.60-SNAPSHOT sonia.scm scm-server - 1.59 + 1.60-SNAPSHOT scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 533f4c57be..6401485329 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.59 + 1.60-SNAPSHOT sonia.scm scm-test - 1.59 + 1.60-SNAPSHOT scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 22fcd213bb..d467061d1d 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59 + 1.60-SNAPSHOT sonia.scm scm-webapp war - 1.59 + 1.60-SNAPSHOT scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT sonia.scm scm-dao-xml - 1.59 + 1.60-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.59 + 1.60-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.59 + 1.60-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.59 + 1.60-SNAPSHOT @@ -280,7 +280,7 @@ sonia.scm scm-test - 1.59 + 1.60-SNAPSHOT test @@ -293,7 +293,7 @@ sonia.scm.plugins scm-git-plugin - 1.59 + 1.60-SNAPSHOT tests test @@ -301,7 +301,7 @@ sonia.scm.plugins scm-hg-plugin - 1.59 + 1.60-SNAPSHOT tests test @@ -309,7 +309,7 @@ sonia.scm.plugins scm-svn-plugin - 1.59 + 1.60-SNAPSHOT tests test diff --git a/support/pom.xml b/support/pom.xml index b1c51c9494..882727808b 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.59 + 1.60-SNAPSHOT sonia.scm.support scm-support pom - 1.59 + 1.60-SNAPSHOT scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index 6b47cdb7b6..9dc37271b2 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.59 + 1.60-SNAPSHOT sonia.scm scm-support-btrace - 1.59 + 1.60-SNAPSHOT jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.59 + 1.60-SNAPSHOT From c841e72dcbc2c4df7059527a418e51f5663c0504 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 12 Apr 2018 11:34:00 +0200 Subject: [PATCH 049/178] #972 encforce jdk 7 bytecode for dependencies --- pom.xml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pom.xml b/pom.xml index 3f4cfda18a..fa324ac12e 100644 --- a/pom.xml +++ b/pom.xml @@ -159,6 +159,36 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M1 + + + enforce-java + compile + + enforce + + + + + 1.7 + + + true + + + + + + org.codehaus.mojo + extra-enforcer-rules + 1.0-beta-7 + + + + org.apache.maven.plugins maven-compiler-plugin From 7d6c65799e78ed2c94f02f4b525859f9c0bab96b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 12 Apr 2018 11:57:00 +0200 Subject: [PATCH 050/178] #972 use javahg version which is compatible with java 7 --- scm-plugins/scm-hg-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index cf4c42d1dc..bb339bb983 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -28,7 +28,7 @@ com.aragost.javahg javahg - 0.13 + 0.13-java7 com.google.guava From b568b9ee9356e007092eee531c46d85f57126b13 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 12 Apr 2018 12:41:58 +0200 Subject: [PATCH 051/178] fix some maven warnings --- pom.xml | 86 +++++++++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/pom.xml b/pom.xml index 3f4cfda18a..8a63ae0c44 100644 --- a/pom.xml +++ b/pom.xml @@ -59,10 +59,6 @@ https://scm-manager.ci.cloudbees.com/ - - 3.0.0 - - scm-core scm-test @@ -274,53 +270,53 @@ org.apache.maven.plugins maven-site-plugin - 3.2 - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.4 - - - - org.apache.maven.plugins - maven-jxr-plugin - 2.3 - - - - org.codehaus.mojo - findbugs-maven-plugin - 2.4.0 - - - - org.apache.maven.plugins - maven-surefire-report-plugin - 2.12 - - - - org.apache.maven.plugins - maven-pmd-plugin - 2.7.1 - - true - ${project.build.sourceEncoding} - ${project.build.javaLevel} - - - - - + 3.7 + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.4 + + + + org.apache.maven.plugins + maven-jxr-plugin + 2.3 + + + + org.codehaus.mojo + findbugs-maven-plugin + 2.4.0 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.12 + + + + org.apache.maven.plugins + maven-pmd-plugin + 2.7.1 + + ${project.build.sourceEncoding} + ${project.build.javaLevel} + + + + + + From bfee6331e1fe2281ca87406154890d7fce24e374 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 12 Apr 2018 13:15:04 +0200 Subject: [PATCH 052/178] fix build on java 9 --- pom.xml | 31 +++++++++++++++++++++++++-- scm-core/pom.xml | 54 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index 8a63ae0c44..71cbb28e22 100644 --- a/pom.xml +++ b/pom.xml @@ -137,7 +137,7 @@ org.codehaus.mojo animal-sniffer-maven-plugin - 1.15 + 1.16 org.codehaus.mojo.signature @@ -360,7 +360,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.8.1 + 3.0.0 org.jboss.apiviz.APIviz @@ -448,6 +448,32 @@ ${jackson.version} + + + + javax.xml.bind + jaxb-api + ${jaxb.version} + + + + com.sun.xml.bind + jaxb-impl + ${jaxb.version} + + + + org.glassfish.jaxb + jaxb-runtime + ${jaxb.version} + + + + javax.activation + activation + 1.1.1 + + @@ -484,6 +510,7 @@ 7.6.21.v20160908 7.6.16.v20140903 1.9.13 + 2.3.0 1.3.2 diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 1547e778f4..5ab21b553b 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -1,6 +1,6 @@ - + 4.0.0 @@ -15,7 +15,7 @@ scm-core - + @@ -24,22 +24,22 @@ ${servlet.version} provided - + slf4j-api org.slf4j - + - + org.apache.shiro shiro-core ${shiro.version} - + @@ -59,13 +59,13 @@ guice-servlet ${guice.version} - + com.google.inject.extensions guice-throwingproviders ${guice.version} - + @@ -73,15 +73,37 @@ jersey-core ${jersey.version} - + + + + + javax.xml.bind + jaxb-api + + + + com.sun.xml.bind + jaxb-impl + + + + org.glassfish.jaxb + jaxb-runtime + + + + javax.activation + activation + + - + com.google.guava guava ${guava.version} - + commons-lang commons-lang @@ -89,14 +111,14 @@ - + - + org.apache.maven.plugins maven-javadoc-plugin - 2.9 + 3.0.0 true ${project.build.sourceEncoding} @@ -122,8 +144,8 @@ - + - + From 68006b322d810ef356012fe5f2204b229ea6a265 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 12 Apr 2018 20:20:32 +0200 Subject: [PATCH 053/178] removed unused import from GroupCollectorTest --- .../scm/security/GroupCollectorTest.java | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java index 57f0362549..e366b15b50 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java @@ -1,10 +1,10 @@ /** * Copyright (c) 2014, 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, @@ -13,7 +13,7 @@ * 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 @@ -24,20 +24,15 @@ * 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.security; import com.google.common.collect.ImmutableSet; -import java.util.Set; -import jdk.nashorn.internal.ir.annotations.Immutable; import org.junit.Test; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; -import static org.hamcrest.Matchers.*; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -47,9 +42,15 @@ import sonia.scm.group.GroupManager; import sonia.scm.user.UserTestData; import sonia.scm.web.security.AuthenticationResult; +import java.util.Set; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; + /** * Unit tests for {@link GroupCollector}. - * + * * @author Sebastian Sdorra * @since 1.52 */ @@ -58,10 +59,10 @@ public class GroupCollectorTest { @Mock private GroupManager groupManager; - + @InjectMocks private GroupCollector collector; - + /** * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} without groups from authenticator. */ @@ -70,7 +71,7 @@ public class GroupCollectorTest { Set groups = collector.collectGroups(new AuthenticationResult(UserTestData.createSlarti())); assertThat(groups, containsInAnyOrder("_authenticated")); } - + /** * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} with groups from authenticator. */ @@ -80,7 +81,7 @@ public class GroupCollectorTest { Set groups = collector.collectGroups(new AuthenticationResult(UserTestData.createSlarti(), authGroups)); assertThat(groups, containsInAnyOrder("_authenticated", "puzzle42")); } - + /** * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} with groups from db. */ @@ -91,7 +92,7 @@ public class GroupCollectorTest { Set groups = collector.collectGroups(new AuthenticationResult(UserTestData.createSlarti())); assertThat(groups, containsInAnyOrder("_authenticated", "puzzle42")); } - + /** * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} with groups from db. */ @@ -104,4 +105,4 @@ public class GroupCollectorTest { assertThat(groups, containsInAnyOrder("_authenticated", "puzzle42", "heartOfGold")); } -} \ No newline at end of file +} From 0fc9f6d4856aab2cd1559e0bdb7148708deee65c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 12 Apr 2018 20:21:22 +0200 Subject: [PATCH 054/178] use APIviz only for javadoc of scm-core --- pom.xml | 11 +---------- scm-core/pom.xml | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 71cbb28e22..7553913789 100644 --- a/pom.xml +++ b/pom.xml @@ -362,16 +362,7 @@ maven-javadoc-plugin 3.0.0 - org.jboss.apiviz.APIviz - - org.jboss.apiviz - apiviz - 1.3.2.GA - - - -sourceclasspath ${project.build.outputDirectory} - -nopackagediagram - + false diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 5ab21b553b..411a3c1d78 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -142,6 +142,20 @@ http://www.slf4j.org/api/ http://shiro.apache.org/static/current/apidocs/ + org.jboss.apiviz.APIviz + + org.jboss.apiviz + apiviz + 1.3.2.GA + + + + -sourceclasspath ${project.build.outputDirectory} + + + -nopackagediagram + + From 966c18eca17471393b462c509ef00b08b9c1aa0c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 12 Apr 2018 20:22:40 +0200 Subject: [PATCH 055/178] close branch issue-972 From b8144b514e2b40eb9473cd453c375534c466a4a4 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 13 Apr 2018 16:23:33 +0200 Subject: [PATCH 056/178] ignore module-info for enforceBytecodeVersion rule --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 180a95745a..b27cbf84ea 100644 --- a/pom.xml +++ b/pom.xml @@ -170,6 +170,13 @@ 1.7 + + + module-info + true From b8456d364cd5609cbac42f77bf9ec5338c89dc35 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 13 Apr 2018 23:32:50 +0200 Subject: [PATCH 057/178] update commons-daemon to version 1.1.0 --- scm-server/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scm-server/pom.xml b/scm-server/pom.xml index ef1bac43c8..7103b0a701 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -308,8 +308,8 @@ - 1.0.15 - 1.0.15.1 + 1.1.0 + 1.1.0 ${project.build.directory}/appassembler/commons-daemon/scm-server From a55dd9873bf5e79873a839f11d9fced303ca727b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Tue, 17 Apr 2018 22:00:54 +0200 Subject: [PATCH 058/178] #979 split implementation of ScmClientConfigFileHandler in order to create new more secure implementation --- .../scm/cli/config/CipherStreamHandler.java | 60 +++++ .../java/sonia/scm/cli/config/KeyStore.java | 57 ++++ .../sonia/scm/cli/config/PrefsKeyStore.java | 64 +++++ .../sonia/scm/cli/config/ScmClientConfig.java | 2 +- .../config/ScmClientConfigFileHandler.java | 246 ++++-------------- .../cli/config/WeakCipherStreamHandler.java | 109 ++++++++ .../ScmClientConfigFileHandlerTest.java | 98 +++++++ 7 files changed, 439 insertions(+), 197 deletions(-) create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsKeyStore.java create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java create mode 100644 scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java new file mode 100644 index 0000000000..e687988be3 --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java @@ -0,0 +1,60 @@ +/** + * 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.cli.config; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * The CipherStreamHandler is able to encrypt and decrypt streams. + */ +public interface CipherStreamHandler { + + /** + * Decrypts the given input stream. + * + * @param inputStream encrypted input stream + * + * @return raw input stream + */ + InputStream decrypt(InputStream inputStream); + + /** + * Encrypts the given output stream. + * + * @param outputStream raw output stream + * + * @return encrypting output stream + */ + OutputStream encrypt(OutputStream outputStream); +} diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java new file mode 100644 index 0000000000..39874b499c --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java @@ -0,0 +1,57 @@ +/** + * 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.cli.config; + +/** + * KeyStore is able to read and write keys. + */ +public interface KeyStore { + + /** + * Writes the given secret key to the store. + * + * @param secretKey secret key to write + */ + void set(String secretKey); + + /** + * Reads the secret key from the store. The method returns {@code null} if no secret key was stored. + * + * @return secret key of {@code null} + */ + String get(); + + /** + * Removes the secret key from store. + */ + void remove(); +} diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsKeyStore.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsKeyStore.java new file mode 100644 index 0000000000..26a7e67b05 --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsKeyStore.java @@ -0,0 +1,64 @@ +/** + * 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.cli.config; + +import java.util.prefs.Preferences; + +/** + * KeyStore implementation with uses {@link Preferences}. + */ +public class PrefsKeyStore implements KeyStore { + + private static final String PREF_SECRET_KEY = "scm.client.key"; + + private final Preferences preferences; + + public PrefsKeyStore() { + // we use ScmClientConfigFileHandler as base for backward compatibility + preferences = Preferences.userNodeForPackage(ScmClientConfigFileHandler.class); + } + + @Override + public void set(String secretKey) { + preferences.put(PREF_SECRET_KEY, secretKey); + } + + @Override + public String get() { + return preferences.get(PREF_SECRET_KEY, null); + } + + @Override + public void remove() { + preferences.remove(PREF_SECRET_KEY); + } +} diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfig.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfig.java index 9edb2b382a..7bec710974 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfig.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfig.java @@ -66,7 +66,7 @@ public class ScmClientConfig * Constructs ... * */ - private ScmClientConfig() + ScmClientConfig() { this.serverConfigMap = new HashMap(); } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java index 5cc2c46978..bbb0fd85c1 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java @@ -35,38 +35,17 @@ package sonia.scm.cli.config; //~--- non-JDK imports -------------------------------------------------------- -import sonia.scm.util.IOUtil; +import sonia.scm.security.KeyGenerator; +import sonia.scm.security.UUIDKeyGenerator; import sonia.scm.util.Util; -//~--- JDK imports ------------------------------------------------------------ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; - -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; - -import java.util.UUID; -import java.util.prefs.Preferences; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; +import java.io.*; + +//~--- JDK imports ------------------------------------------------------------ /** * @@ -81,62 +60,66 @@ public class ScmClientConfigFileHandler /** Field description */ public static final String ENV_CONFIG_FILE = "SCM_CLI_CONFIG"; - /** Field description */ - public static final String PREF_SECRET_KEY = "scm.client.key"; - - /** Field description */ - public static final String SALT = "AE16347F"; - - /** Field description */ - public static final int SPEC_ITERATION = 12; - - /** Field description */ - private static final String CIPHER_NAME = "PBEWithMD5AndDES"; - //~--- constructors --------------------------------------------------------- + private final KeyStore keyStore; + private final KeyGenerator keyGenerator; + private final File file; + private final JAXBContext context; + + private final CipherStreamHandler cipherStreamHandler; + + /** * Constructs ... * */ - public ScmClientConfigFileHandler() - { - prefs = Preferences.userNodeForPackage(ScmClientConfigFileHandler.class); - key = prefs.get(PREF_SECRET_KEY, null); + public ScmClientConfigFileHandler() { + this(new PrefsKeyStore(), new UUIDKeyGenerator(), getDefaultConfigFile()); + } - if (Util.isEmpty(key)) - { - key = createNewKey(); - prefs.put(PREF_SECRET_KEY, key); + ScmClientConfigFileHandler(KeyStore keyStore, KeyGenerator keyGenerator, File file) { + this.keyStore = keyStore; + this.keyGenerator = keyGenerator; + this.file = file; + + String key = keyStore.get(); + + if (Util.isEmpty(key)) { + key = keyGenerator.createKey(); + keyStore.set(key); } - try - { + cipherStreamHandler = new WeakCipherStreamHandler(key.toCharArray()); + + try { context = JAXBContext.newInstance(ScmClientConfig.class); - } - catch (JAXBException ex) - { - throw new ScmConfigException( - "could not create JAXBContext for ScmClientConfig", ex); + } catch (JAXBException ex) { + throw new ScmConfigException("could not create JAXBContext for ScmClientConfig", ex); } } //~--- methods -------------------------------------------------------------- + private static File getDefaultConfigFile() { + String configPath = System.getenv(ENV_CONFIG_FILE); + + if (Util.isNotEmpty(configPath)){ + return new File(configPath); + } + return new File(System.getProperty("user.home"), DEFAULT_CONFIG_NAME); + } + /** * Method description * */ - public void delete() - { - File configFile = getConfigFile(); - - if (configFile.exists() &&!configFile.delete()) - { + public void delete() { + if (file.exists() &&!file.delete()) { throw new ScmConfigException("could not delete config file"); } - prefs.remove(PREF_SECRET_KEY); + keyStore.remove(); } /** @@ -145,33 +128,16 @@ public class ScmClientConfigFileHandler * * @return */ - public ScmClientConfig read() - { + public ScmClientConfig read() { ScmClientConfig config = null; - File configFile = getConfigFile(); - - if (configFile.exists()) - { - InputStream input = null; - - try - { - Cipher c = createCipher(Cipher.DECRYPT_MODE); - - input = new CipherInputStream(new FileInputStream(configFile), c); + if (file.exists()) { + try (InputStream input = cipherStreamHandler.decrypt(new FileInputStream(file))) { Unmarshaller um = context.createUnmarshaller(); - config = (ScmClientConfig) um.unmarshal(input); - } - catch (Exception ex) - { + } catch (IOException | JAXBException ex) { throw new ScmConfigException("could not read config file", ex); } - finally - { - IOUtil.close(input); - } } return config; @@ -183,124 +149,12 @@ public class ScmClientConfigFileHandler * * @param config */ - public void write(ScmClientConfig config) - { - File configFile = getConfigFile(); - OutputStream output = null; - - try - { - Cipher c = createCipher(Cipher.ENCRYPT_MODE); - - output = new CipherOutputStream(new FileOutputStream(configFile), c); - + public void write(ScmClientConfig config) { + try (OutputStream output = cipherStreamHandler.encrypt(new FileOutputStream(file))) { Marshaller m = context.createMarshaller(); - m.marshal(config, output); - } - catch (Exception ex) - { + } catch (IOException | JAXBException ex) { throw new ScmConfigException("could not write config file", ex); } - finally - { - IOUtil.close(output); - } } - - /** - * Method description - * - * - * @param mode - * - * @return - * - * - * @throws InvalidAlgorithmParameterException - * @throws InvalidKeyException - * @throws InvalidKeySpecException - * @throws NoSuchAlgorithmException - * @throws NoSuchPaddingException - */ - private Cipher createCipher(int mode) - throws NoSuchAlgorithmException, NoSuchPaddingException, - InvalidKeySpecException, InvalidKeyException, - InvalidAlgorithmParameterException - { - SecretKey sk = createSecretKey(); - Cipher cipher = Cipher.getInstance(CIPHER_NAME); - PBEParameterSpec spec = new PBEParameterSpec(SALT.getBytes(), - SPEC_ITERATION); - - cipher.init(mode, sk, spec); - - return cipher; - } - - /** - * Method description - * - * - * @return - */ - private String createNewKey() - { - return UUID.randomUUID().toString(); - } - - /** - * Method description - * - * - * @return - * - * @throws InvalidKeySpecException - * @throws NoSuchAlgorithmException - */ - private SecretKey createSecretKey() - throws NoSuchAlgorithmException, InvalidKeySpecException - { - PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray()); - SecretKeyFactory factory = SecretKeyFactory.getInstance(CIPHER_NAME); - - return factory.generateSecret(keySpec); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - private File getConfigFile() - { - File configFile = null; - String configPath = System.getenv(ENV_CONFIG_FILE); - - if (Util.isEmpty(configPath)) - { - configFile = new File(System.getProperty("user.home"), - DEFAULT_CONFIG_NAME); - } - else - { - configFile = new File(configPath); - } - - return configFile; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private JAXBContext context; - - /** Field description */ - private String key; - - /** Field description */ - private Preferences prefs; } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java new file mode 100644 index 0000000000..0a867d5b30 --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java @@ -0,0 +1,109 @@ +/** + * 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.cli.config; + +import javax.crypto.*; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; + +/** + * Weak implementation of {@link CipherStreamHandler}. + * + * @see Issue 978 + * @see Issue 979 + */ +public class WeakCipherStreamHandler implements CipherStreamHandler { + + private static final String SALT = "AE16347F"; + private static final int SPEC_ITERATION = 12; + private static final String CIPHER_NAME = "PBEWithMD5AndDES"; + + private final char[] secretKey; + + /** + * Creates a new handler with the given secret key. + * + * @param secretKey secret key + */ + public WeakCipherStreamHandler(char[] secretKey) { + this.secretKey = secretKey; + } + + @Override + public InputStream decrypt(InputStream inputStream) { + try { + Cipher c = createCipher(Cipher.DECRYPT_MODE); + return new CipherInputStream(inputStream, c); + } catch (Exception ex) { + throw new ScmConfigException("could not encrypt output stream", ex); + } + } + + @Override + public OutputStream encrypt(OutputStream outputStream) { + try { + Cipher c = createCipher(Cipher.ENCRYPT_MODE); + return new CipherOutputStream(outputStream, c); + } catch (Exception ex) { + throw new ScmConfigException("could not encrypt output stream", ex); + } + } + + private Cipher createCipher(int mode) + throws NoSuchAlgorithmException, NoSuchPaddingException, + InvalidKeySpecException, InvalidKeyException, + InvalidAlgorithmParameterException + { + SecretKey sk = createSecretKey(); + Cipher cipher = Cipher.getInstance(CIPHER_NAME); + PBEParameterSpec spec = new PBEParameterSpec(SALT.getBytes(), SPEC_ITERATION); + + cipher.init(mode, sk, spec); + + return cipher; + } + + private SecretKey createSecretKey() + throws NoSuchAlgorithmException, InvalidKeySpecException + { + PBEKeySpec keySpec = new PBEKeySpec(secretKey); + SecretKeyFactory factory = SecretKeyFactory.getInstance(CIPHER_NAME); + + return factory.generateSecret(keySpec); + } +} diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java new file mode 100644 index 0000000000..ec598fd2d4 --- /dev/null +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java @@ -0,0 +1,98 @@ +/** + * 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.cli.config; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import sonia.scm.security.UUIDKeyGenerator; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ScmClientConfigFileHandlerTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void testClientConfigFileHandler() throws IOException { + File configFile = temporaryFolder.newFile(); + + ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( + new InMemoryKeyStore(), new UUIDKeyGenerator(), configFile + ); + + ScmClientConfig config = new ScmClientConfig(); + ServerConfig defaultConfig = config.getDefaultConfig(); + defaultConfig.setServerUrl("http://localhost:8080/scm"); + defaultConfig.setUsername("scmadmin"); + defaultConfig.setPassword("admin123"); + handler.write(config); + + assertTrue(configFile.exists()); + + config = handler.read(); + defaultConfig = config.getDefaultConfig(); + assertEquals("http://localhost:8080/scm", defaultConfig.getServerUrl()); + assertEquals("scmadmin", defaultConfig.getUsername()); + assertEquals("admin123", defaultConfig.getPassword()); + + handler.delete(); + + assertFalse(configFile.exists()); + } + + private static class InMemoryKeyStore implements KeyStore { + + private String secretKey; + + @Override + public void set(String secretKey) { + this.secretKey = secretKey; + } + + @Override + public String get() { + return secretKey; + } + + @Override + public void remove() { + this.secretKey = null; + } + } +} From d9e7de82022beb80c7812b435970f12357d3c7c9 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 18 Apr 2018 08:09:28 +0200 Subject: [PATCH 059/178] #979 improve javadoc --- .../src/main/java/sonia/scm/cli/config/KeyStore.java | 2 +- .../java/sonia/scm/cli/config/WeakCipherStreamHandler.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java index 39874b499c..7ce64750ce 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java @@ -46,7 +46,7 @@ public interface KeyStore { /** * Reads the secret key from the store. The method returns {@code null} if no secret key was stored. * - * @return secret key of {@code null} + * @return secret key or {@code null} */ String get(); diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java index 0a867d5b30..a9e3e5ef42 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java @@ -42,7 +42,8 @@ import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; /** - * Weak implementation of {@link CipherStreamHandler}. + * Weak implementation of {@link CipherStreamHandler}. This is the old implementation, which was used in versions prior + * 1.60. * * @see Issue 978 * @see Issue 979 From 3ee0bcedac4ce72cffb8f474ac33ae4d5c1b77a4 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 18 Apr 2018 14:41:38 +0200 Subject: [PATCH 060/178] #979 encrypt cli configuration with aes instead of pbe --- .../cli/config/AesCipherStreamHandler.java | 108 +++++++++++++ .../scm/cli/config/CipherStreamHandler.java | 8 +- .../sonia/scm/cli/config/ConfigFiles.java | 151 ++++++++++++++++++ .../config/ScmClientConfigFileHandler.java | 64 +++----- .../cli/config/SecureRandomKeyGenerator.java | 69 ++++++++ .../cli/config/WeakCipherStreamHandler.java | 7 +- .../config/AesCipherStreamHandlerTest.java | 68 ++++++++ .../cli/config/ClientConfigurationTests.java | 96 +++++++++++ .../sonia/scm/cli/config/ConfigFilesTest.java | 105 ++++++++++++ .../scm/cli/config/InMemoryKeyStore.java | 53 ++++++ .../ScmClientConfigFileHandlerTest.java | 76 ++++++--- .../config/SecureRandomKeyGeneratorTest.java | 47 ++++++ .../scm/cli/config/scm-cli-config.enc.xml | Bin 0 -> 296 bytes 13 files changed, 790 insertions(+), 62 deletions(-) create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.java create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/SecureRandomKeyGenerator.java create mode 100644 scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/AesCipherStreamHandlerTest.java create mode 100644 scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ClientConfigurationTests.java create mode 100644 scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java create mode 100644 scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemoryKeyStore.java create mode 100644 scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/SecureRandomKeyGeneratorTest.java create mode 100644 scm-clients/scm-cli-client/src/test/resources/sonia/scm/cli/config/scm-cli-config.enc.xml diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.java new file mode 100644 index 0000000000..5955b8b762 --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.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.cli.config; + +import com.google.common.base.Charsets; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; + +/** + * Implementation of {@link CipherStreamHandler} which uses AES. This version is used since version 1.60 for the + * cli client encryption. + * + * @author Sebastian Sdorra + * @since 1.60 + */ +public class AesCipherStreamHandler implements CipherStreamHandler { + + private static final String ALGORITHM = "AES/GCM/NoPadding"; + + private final SecureRandom random = new SecureRandom(); + + private final byte[] secretKey; + + AesCipherStreamHandler(String secretKey) { + this.secretKey = secretKey.getBytes(Charsets.UTF_8); + } + + @Override + public OutputStream encrypt(OutputStream outputStream) throws IOException { + Cipher cipher = createCipherForEncryption(); + outputStream.write(cipher.getIV()); + return new CipherOutputStream(outputStream, cipher); + } + + @Override + public InputStream decrypt(InputStream inputStream) throws IOException { + Cipher cipher = createCipherForDecryption(inputStream); + return new CipherInputStream(inputStream, cipher); + } + + private Cipher createCipherForDecryption(InputStream inputStream) throws IOException { + byte[] iv =new byte[12]; + inputStream.read(iv); + return createCipher(Cipher.DECRYPT_MODE, iv); + } + + private Cipher createCipherForEncryption() { + byte[] iv = generateIV(); + return createCipher(Cipher.ENCRYPT_MODE, iv); + } + + private byte[] generateIV() { + // use 12 byte as described at nist + // https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf + byte[] iv = new byte[12]; + random.nextBytes(iv); + return iv; + } + + private Cipher createCipher(int mode, byte[] iv) { + try { + Cipher cipher = Cipher.getInstance(ALGORITHM); + GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); + cipher.init(mode, new SecretKeySpec(secretKey, "AES"), parameterSpec); + return cipher; + } catch (Exception ex) { + throw new ScmConfigException("failed to create cipher", ex); + } + } +} diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java index e687988be3..2321b3d9d9 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/CipherStreamHandler.java @@ -32,11 +32,15 @@ package sonia.scm.cli.config; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * The CipherStreamHandler is able to encrypt and decrypt streams. + * + * @author Sebastian Sdorra + * @since 1.60 */ public interface CipherStreamHandler { @@ -47,7 +51,7 @@ public interface CipherStreamHandler { * * @return raw input stream */ - InputStream decrypt(InputStream inputStream); + InputStream decrypt(InputStream inputStream) throws IOException; /** * Encrypts the given output stream. @@ -56,5 +60,5 @@ public interface CipherStreamHandler { * * @return encrypting output stream */ - OutputStream encrypt(OutputStream outputStream); + OutputStream encrypt(OutputStream outputStream) throws IOException; } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java new file mode 100644 index 0000000000..5087c50746 --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java @@ -0,0 +1,151 @@ +/** + * 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.cli.config; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import sonia.scm.security.KeyGenerator; + +import javax.xml.bind.JAXB; +import java.io.*; +import java.util.Arrays; + +/** + * Util methods for configuration files. + * + * @author Sebastian Sdorra + * @since 1.60 + */ +final class ConfigFiles { + + private static final KeyGenerator keyGenerator = new SecureRandomKeyGenerator(); + + // SCM Config Version 2 + @VisibleForTesting + static final byte[] VERSION_IDENTIFIER = "SCV2".getBytes(Charsets.US_ASCII); + + private ConfigFiles() { + } + + /** + * Returns {@code true} if the file is encrypted with the v2 format. + * + * @param file configuration file + * + * @return {@code true} for format v2 + * + * @throws IOException + */ + static boolean isFormatV2(File file) throws IOException { + try (InputStream input = new FileInputStream(file)) { + byte[] bytes = new byte[VERSION_IDENTIFIER.length]; + input.read(bytes); + return Arrays.equals(VERSION_IDENTIFIER, bytes); + } + } + + /** + * Decrypt and parse v1 configuration file. + * + * @param keyStore key store + * @param file configuration file + * + * @return client configuration + * + * @throws IOException + */ + static ScmClientConfig parseV1(KeyStore keyStore, File file) throws IOException { + String secretKey = secretKey(keyStore); + CipherStreamHandler cipherStreamHandler = new WeakCipherStreamHandler(secretKey); + return decrypt(cipherStreamHandler, new FileInputStream(file)); + } + + /** + * Decrypt and parse v12configuration file. + * + * @param keyStore key store + * @param file configuration file + * + * @return client configuration + * + * @throws IOException + */ + static ScmClientConfig parseV2(KeyStore keyStore, File file) throws IOException { + String secretKey = secretKey(keyStore); + CipherStreamHandler cipherStreamHandler = new AesCipherStreamHandler(secretKey); + try (InputStream input = new FileInputStream(file)) { + input.skip(VERSION_IDENTIFIER.length); + return decrypt(cipherStreamHandler, input); + } + } + + /** + * Store encrypt and write the configuration to the given file. + * Note the method uses always the latest available format. + * + * @param keyStore key store + * @param config configuration + * @param file configuration file + * + * @throws IOException + */ + static void store(KeyStore keyStore, ScmClientConfig config, File file) throws IOException { + String secretKey = keyGenerator.createKey(); + CipherStreamHandler cipherStreamHandler = new AesCipherStreamHandler(secretKey); + try (OutputStream output = new FileOutputStream(file)) { + output.write(VERSION_IDENTIFIER); + encrypt(cipherStreamHandler, output, config); + } + keyStore.set(secretKey); + } + + private static String secretKey(KeyStore keyStore) { + String secretKey = keyStore.get(); + Preconditions.checkState(!Strings.isNullOrEmpty(secretKey), "no stored secret key found"); + return secretKey; + } + + private static ScmClientConfig decrypt(CipherStreamHandler cipherStreamHandler, InputStream input) throws IOException { + try ( InputStream decryptedInputStream = cipherStreamHandler.decrypt(input) ) { + return JAXB.unmarshal(decryptedInputStream, ScmClientConfig.class); + } + } + + private static void encrypt(CipherStreamHandler cipherStreamHandler, OutputStream output, ScmClientConfig clientConfig) throws IOException { + try ( OutputStream encryptedOutputStream = cipherStreamHandler.encrypt(output) ) { + JAXB.marshal(clientConfig, encryptedOutputStream); + } + } + +} diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java index bbb0fd85c1..00a0eb6cf6 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java @@ -35,15 +35,10 @@ package sonia.scm.cli.config; //~--- non-JDK imports -------------------------------------------------------- -import sonia.scm.security.KeyGenerator; -import sonia.scm.security.UUIDKeyGenerator; import sonia.scm.util.Util; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import java.io.*; +import java.io.File; +import java.io.IOException; //~--- JDK imports ------------------------------------------------------------ @@ -63,40 +58,20 @@ public class ScmClientConfigFileHandler //~--- constructors --------------------------------------------------------- private final KeyStore keyStore; - private final KeyGenerator keyGenerator; private final File file; - private final JAXBContext context; - - private final CipherStreamHandler cipherStreamHandler; /** - * Constructs ... + * Constructs a new ScmClientConfigFileHandler * */ public ScmClientConfigFileHandler() { - this(new PrefsKeyStore(), new UUIDKeyGenerator(), getDefaultConfigFile()); + this(new PrefsKeyStore(), getDefaultConfigFile()); } - ScmClientConfigFileHandler(KeyStore keyStore, KeyGenerator keyGenerator, File file) { + ScmClientConfigFileHandler(KeyStore keyStore,File file) { this.keyStore = keyStore; - this.keyGenerator = keyGenerator; this.file = file; - - String key = keyStore.get(); - - if (Util.isEmpty(key)) { - key = keyGenerator.createKey(); - keyStore.set(key); - } - - cipherStreamHandler = new WeakCipherStreamHandler(key.toCharArray()); - - try { - context = JAXBContext.newInstance(ScmClientConfig.class); - } catch (JAXBException ex) { - throw new ScmConfigException("could not create JAXBContext for ScmClientConfig", ex); - } } //~--- methods -------------------------------------------------------------- @@ -132,17 +107,27 @@ public class ScmClientConfigFileHandler ScmClientConfig config = null; if (file.exists()) { - try (InputStream input = cipherStreamHandler.decrypt(new FileInputStream(file))) { - Unmarshaller um = context.createUnmarshaller(); - config = (ScmClientConfig) um.unmarshal(input); - } catch (IOException | JAXBException ex) { - throw new ScmConfigException("could not read config file", ex); - } + config = readFromFile(); } return config; } + private ScmClientConfig readFromFile() { + ScmClientConfig config; + try { + if (ConfigFiles.isFormatV2(file)) { + config = ConfigFiles.parseV2(keyStore, file); + } else { + config = ConfigFiles.parseV1(keyStore, file); + ConfigFiles.store(keyStore, config, file); + } + } catch (IOException ex) { + throw new ScmConfigException("could not read config file", ex); + } + return config; + } + /** * Method description * @@ -150,10 +135,9 @@ public class ScmClientConfigFileHandler * @param config */ public void write(ScmClientConfig config) { - try (OutputStream output = cipherStreamHandler.encrypt(new FileOutputStream(file))) { - Marshaller m = context.createMarshaller(); - m.marshal(config, output); - } catch (IOException | JAXBException ex) { + try { + ConfigFiles.store(keyStore, config, file); + } catch (IOException ex) { throw new ScmConfigException("could not write config file", ex); } } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/SecureRandomKeyGenerator.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/SecureRandomKeyGenerator.java new file mode 100644 index 0000000000..19ae135461 --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/SecureRandomKeyGenerator.java @@ -0,0 +1,69 @@ +/** + * 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.cli.config; + +import com.google.common.annotations.VisibleForTesting; +import sonia.scm.security.KeyGenerator; + +import java.security.SecureRandom; +import java.util.Locale; + +/** + * Create keys by using {@link SecureRandom}. The SecureRandomKeyGenerator produces aes compatible keys. + * Warning the class is not thread safe. + * + * @author Sebastian Sdorra + * @since 1.60 + */ +public class SecureRandomKeyGenerator implements KeyGenerator { + + private SecureRandom random = new SecureRandom(); + + // key length 16 for aes128 + @VisibleForTesting + static final int KEY_LENGTH = 16; + + private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private static final String LOWER = UPPER.toLowerCase(Locale.ENGLISH); + private static final String DIGITS = "0123456789"; + private static final char[] ALL = (UPPER + LOWER + DIGITS).toCharArray(); + + @Override + public String createKey() { + char[] key = new char[KEY_LENGTH]; + for (int idx = 0; idx < KEY_LENGTH; ++idx) { + key[idx] = ALL[random.nextInt(ALL.length)]; + } + return new String(key); + } +} diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java index a9e3e5ef42..175d1986c6 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/WeakCipherStreamHandler.java @@ -45,6 +45,9 @@ import java.security.spec.InvalidKeySpecException; * Weak implementation of {@link CipherStreamHandler}. This is the old implementation, which was used in versions prior * 1.60. * + * @author Sebastian Sdorra + * @since 1.60 + * * @see Issue 978 * @see Issue 979 */ @@ -61,8 +64,8 @@ public class WeakCipherStreamHandler implements CipherStreamHandler { * * @param secretKey secret key */ - public WeakCipherStreamHandler(char[] secretKey) { - this.secretKey = secretKey; + WeakCipherStreamHandler(String secretKey) { + this.secretKey = secretKey.toCharArray(); } @Override diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/AesCipherStreamHandlerTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/AesCipherStreamHandlerTest.java new file mode 100644 index 0000000000..14000faa33 --- /dev/null +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/AesCipherStreamHandlerTest.java @@ -0,0 +1,68 @@ +/** + * 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.cli.config; + +import com.google.common.base.Charsets; +import com.google.common.io.ByteStreams; +import org.junit.Test; +import sonia.scm.security.KeyGenerator; + +import java.io.*; + +import static org.junit.Assert.assertEquals; + +public class AesCipherStreamHandlerTest { + + private final KeyGenerator keyGenerator = new SecureRandomKeyGenerator(); + + @Test + public void testEncryptAndDecrypt() throws IOException { + AesCipherStreamHandler cipherStreamHandler = new AesCipherStreamHandler(keyGenerator.createKey()); + + // douglas adams + String content = "If you try and take a cat apart to see how it works, the first thing you have on your hands is a nonworking cat."; + + // encrypt + ByteArrayOutputStream output = new ByteArrayOutputStream(); + OutputStream encryptedOutput = cipherStreamHandler.encrypt(output); + encryptedOutput.write(content.getBytes(Charsets.UTF_8)); + encryptedOutput.close(); + + InputStream input = new ByteArrayInputStream(output.toByteArray()); + input = cipherStreamHandler.decrypt(input); + byte[] decrypted = ByteStreams.toByteArray(input); + + assertEquals(content, new String(decrypted, Charsets.UTF_8)); + } + +} diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ClientConfigurationTests.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ClientConfigurationTests.java new file mode 100644 index 0000000000..20422df7ed --- /dev/null +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ClientConfigurationTests.java @@ -0,0 +1,96 @@ +/** + * 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.cli.config; + +import com.google.common.base.Charsets; +import com.google.common.io.ByteStreams; + +import javax.xml.bind.JAXB; +import java.io.*; + +import static org.junit.Assert.assertEquals; + +final class ClientConfigurationTests { + + private ClientConfigurationTests() { + } + + static void testCipherStream(CipherStreamHandler cipherStreamHandler, String content) throws IOException { + byte[] encrypted = encrypt(cipherStreamHandler, content); + String decrypted = decrypt(cipherStreamHandler, encrypted); + assertEquals(content, decrypted); + } + + + static byte[] encrypt(CipherStreamHandler cipherStreamHandler, String content) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + OutputStream encryptedOutput = cipherStreamHandler.encrypt(output); + encryptedOutput.write(content.getBytes(Charsets.UTF_8)); + encryptedOutput.close(); + return output.toByteArray(); + } + + static String decrypt(CipherStreamHandler cipherStreamHandler, byte[] encrypted) throws IOException { + InputStream input = new ByteArrayInputStream(encrypted); + input = cipherStreamHandler.decrypt(input); + byte[] decrypted = ByteStreams.toByteArray(input); + input.close(); + + return new String(decrypted, Charsets.UTF_8); + } + + static void assertSampleConfig(ScmClientConfig config) { + ServerConfig defaultConfig; + defaultConfig = config.getDefaultConfig(); + + assertEquals("http://localhost:8080/scm", defaultConfig.getServerUrl()); + assertEquals("admin", defaultConfig.getUsername()); + assertEquals("admin123", defaultConfig.getPassword()); + } + + static ScmClientConfig createSampleConfig() { + ScmClientConfig config = new ScmClientConfig(); + ServerConfig defaultConfig = config.getDefaultConfig(); + defaultConfig.setServerUrl("http://localhost:8080/scm"); + defaultConfig.setUsername("admin"); + defaultConfig.setPassword("admin123"); + return config; + } + + static void encrypt(CipherStreamHandler cipherStreamHandler, ScmClientConfig config, File file) throws IOException { + try (OutputStream output = cipherStreamHandler.encrypt(new FileOutputStream(file))) { + JAXB.marshal(config, output); + } + } + +} diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java new file mode 100644 index 0000000000..5fbdfdc0c0 --- /dev/null +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java @@ -0,0 +1,105 @@ +/** + * 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.cli.config; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.*; + +public class ConfigFilesTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void testIsFormatV2() throws IOException { + byte[] content = "The door was the way to... to... The Door was The Way".getBytes(Charsets.UTF_8); + + File fileV1 = temporaryFolder.newFile(); + Files.write(content, fileV1); + + assertFalse(ConfigFiles.isFormatV2(fileV1)); + + File fileV2 = temporaryFolder.newFile(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(ConfigFiles.VERSION_IDENTIFIER); + baos.write(content); + Files.write(baos.toByteArray(), fileV2); + + assertTrue(ConfigFiles.isFormatV2(fileV2)); + } + + @Test + public void testParseV1() throws IOException { + InMemoryKeyStore keyStore = createKeyStore(); + WeakCipherStreamHandler handler = new WeakCipherStreamHandler(keyStore.get()); + + ScmClientConfig config = ClientConfigurationTests.createSampleConfig(); + File file = temporaryFolder.newFile(); + ClientConfigurationTests.encrypt(handler, config, file); + + config = ConfigFiles.parseV1(keyStore, file); + ClientConfigurationTests.assertSampleConfig(config); + } + + @Test + public void storeAndParseV2() throws IOException { + InMemoryKeyStore keyStore = new InMemoryKeyStore(); + ScmClientConfig config = ClientConfigurationTests.createSampleConfig(); + File file = temporaryFolder.newFile(); + + ConfigFiles.store(keyStore, config, file); + + String key = keyStore.get(); + assertNotNull(key); + + config = ConfigFiles.parseV2(keyStore, file); + ClientConfigurationTests.assertSampleConfig(config); + } + + private InMemoryKeyStore createKeyStore() { + String secretKey = new SecureRandomKeyGenerator().createKey(); + InMemoryKeyStore keyStore = new InMemoryKeyStore(); + keyStore.set(secretKey); + return keyStore; + } + +} diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemoryKeyStore.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemoryKeyStore.java new file mode 100644 index 0000000000..1d0069a087 --- /dev/null +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemoryKeyStore.java @@ -0,0 +1,53 @@ +/** + * 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.cli.config; + +public class InMemoryKeyStore implements KeyStore { + + private String secretKey; + + @Override + public void set(String secretKey) { + this.secretKey = secretKey; + } + + @Override + public String get() { + return secretKey; + } + + @Override + public void remove() { + this.secretKey = null; + } +} diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java index ec598fd2d4..a9f6a46418 100644 --- a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java @@ -31,6 +31,8 @@ package sonia.scm.cli.config; +import com.google.common.io.Files; +import com.google.common.io.Resources; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -38,10 +40,9 @@ import sonia.scm.security.UUIDKeyGenerator; import java.io.File; import java.io.IOException; +import java.net.URL; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class ScmClientConfigFileHandlerTest { @@ -53,7 +54,7 @@ public class ScmClientConfigFileHandlerTest { File configFile = temporaryFolder.newFile(); ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( - new InMemoryKeyStore(), new UUIDKeyGenerator(), configFile + new InMemoryKeyStore(), configFile ); ScmClientConfig config = new ScmClientConfig(); @@ -76,23 +77,62 @@ public class ScmClientConfigFileHandlerTest { assertFalse(configFile.exists()); } - private static class InMemoryKeyStore implements KeyStore { + @Test + public void testClientConfigFileHandlerWithOldConfiguration() throws IOException { + File configFile = temporaryFolder.newFile(); - private String secretKey; + // old implementation has used uuids as keys + String key = new UUIDKeyGenerator().createKey(); - @Override - public void set(String secretKey) { - this.secretKey = secretKey; - } + WeakCipherStreamHandler weakCipherStreamHandler = new WeakCipherStreamHandler(key); + ScmClientConfig clientConfig = ClientConfigurationTests.createSampleConfig(); + ClientConfigurationTests.encrypt(weakCipherStreamHandler, clientConfig, configFile); - @Override - public String get() { - return secretKey; - } + assertFalse(ConfigFiles.isFormatV2(configFile)); - @Override - public void remove() { - this.secretKey = null; - } + KeyStore keyStore = new InMemoryKeyStore(); + keyStore.set(key); + + ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( + keyStore, configFile + ); + + ScmClientConfig config = handler.read(); + ClientConfigurationTests.assertSampleConfig(config); + + // ensure key has changed + assertNotEquals(key, keyStore.get()); + + // ensure config rewritten with v2 + assertTrue(ConfigFiles.isFormatV2(configFile)); + } + + @Test + public void testClientConfigFileHandlerWithRealMigration() throws IOException { + URL resource = Resources.getResource("sonia/scm/cli/config/scm-cli-config.enc.xml"); + byte[] bytes = Resources.toByteArray(resource); + + File configFile = temporaryFolder.newFile(); + Files.write(bytes, configFile); + + String key = "358e018a-0c3c-4339-8266-3874e597305f"; + KeyStore keyStore = new InMemoryKeyStore(); + keyStore.set(key); + + ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( + keyStore, configFile + ); + + ScmClientConfig config = handler.read(); + ServerConfig defaultConfig = config.getDefaultConfig(); + assertEquals("http://hitchhicker.com/scm", defaultConfig.getServerUrl()); + assertEquals("tricia", defaultConfig.getUsername()); + assertEquals("trillian123", defaultConfig.getPassword()); + + // ensure key has changed + assertNotEquals(key, keyStore.get()); + + // ensure config rewritten with v2 + assertTrue(ConfigFiles.isFormatV2(configFile)); } } diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/SecureRandomKeyGeneratorTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/SecureRandomKeyGeneratorTest.java new file mode 100644 index 0000000000..e847e89cb1 --- /dev/null +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/SecureRandomKeyGeneratorTest.java @@ -0,0 +1,47 @@ +/** + * 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.cli.config; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SecureRandomKeyGeneratorTest { + + @Test + public void testCreateKey() { + SecureRandomKeyGenerator keyGenerator = new SecureRandomKeyGenerator(); + assertNotNull(keyGenerator.createKey()); + assertEquals(SecureRandomKeyGenerator.KEY_LENGTH, keyGenerator.createKey().length()); + } + +} diff --git a/scm-clients/scm-cli-client/src/test/resources/sonia/scm/cli/config/scm-cli-config.enc.xml b/scm-clients/scm-cli-client/src/test/resources/sonia/scm/cli/config/scm-cli-config.enc.xml new file mode 100644 index 0000000000000000000000000000000000000000..94132772a470186bfb3f7fcef19147caa328fb43 GIT binary patch literal 296 zcmV+@0oVRHh)0-9KiSs&h;Gc9iYttD@?y@sK-DK9rt+UqcB$|LJIGtiuWhPCD8AV|${J04dxuLvemaJDR8bujM$6VA+!l-1QGeQ)~D{8o;7;j|7E z{HjWNPp_;e+jmnC$8b58PmorI<1lg5!<=30g;E*#1Zoe+=vFqAjR2LPW0GvPwTh7{dS&&BRDH%NNkQTUEVsSI^Vz!`vE}xPm}6UZF0e3HMZ?%rM^3;`HLf89 ul*7JXT?4Q0fR^`g-Fk}4l+hkg?Dkrwzz~`30=lveB36|b^%kxKF|9s{3XnMf literal 0 HcmV?d00001 From cbecb3731bb77822aaafddb2b9e261ff6115864e Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 30 Apr 2018 09:27:00 +0200 Subject: [PATCH 061/178] #979 use a java 7 compatible cipher spec --- .../cli/config/AesCipherStreamHandler.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.java index 5955b8b762..680dd25563 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/AesCipherStreamHandler.java @@ -37,7 +37,7 @@ import com.google.common.base.Charsets; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; -import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.io.InputStream; @@ -53,7 +53,9 @@ import java.security.SecureRandom; */ public class AesCipherStreamHandler implements CipherStreamHandler { - private static final String ALGORITHM = "AES/GCM/NoPadding"; + private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5PADDING"; + private static final String SECRET_KEY_ALGORITHM = "AES"; + private static final int IV_LENGTH = 16; private final SecureRandom random = new SecureRandom(); @@ -77,11 +79,15 @@ public class AesCipherStreamHandler implements CipherStreamHandler { } private Cipher createCipherForDecryption(InputStream inputStream) throws IOException { - byte[] iv =new byte[12]; + byte[] iv = createEmptyIvArray(); inputStream.read(iv); return createCipher(Cipher.DECRYPT_MODE, iv); } + private byte[] createEmptyIvArray() { + return new byte[IV_LENGTH]; + } + private Cipher createCipherForEncryption() { byte[] iv = generateIV(); return createCipher(Cipher.ENCRYPT_MODE, iv); @@ -90,16 +96,16 @@ public class AesCipherStreamHandler implements CipherStreamHandler { private byte[] generateIV() { // use 12 byte as described at nist // https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf - byte[] iv = new byte[12]; + byte[] iv = createEmptyIvArray(); random.nextBytes(iv); return iv; } private Cipher createCipher(int mode, byte[] iv) { try { - Cipher cipher = Cipher.getInstance(ALGORITHM); - GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); - cipher.init(mode, new SecretKeySpec(secretKey, "AES"), parameterSpec); + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + cipher.init(mode, new SecretKeySpec(secretKey, SECRET_KEY_ALGORITHM), ivParameterSpec); return cipher; } catch (Exception ex) { throw new ScmConfigException("failed to create cipher", ex); From 40b5ef485b7b002f5bdbddd2b86741ccc8f3ee40 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 30 Apr 2018 09:36:51 +0200 Subject: [PATCH 062/178] #979 encrypt the configuration keys before they are written to prefs --- .../cli/config/EncryptionKeyStoreWrapper.java | 138 ++++++++++++++++++ .../config/ScmClientConfigFileHandler.java | 6 +- .../config/EncryptionKeyStoreWrapperTest.java | 60 ++++++++ .../ScmClientConfigFileHandlerTest.java | 6 +- 4 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java create mode 100644 scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionKeyStoreWrapperTest.java diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java new file mode 100644 index 0000000000..826660f00f --- /dev/null +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java @@ -0,0 +1,138 @@ +/** + * 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.cli.config; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; +import com.google.common.base.Strings; +import com.google.common.io.BaseEncoding; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +/** + * The EncryptionKeyStoreWrapper is a wrapper around the {@link KeyStore} interface. The wrapper will encrypt the passed + * keys, before they are written to the underlying {@link KeyStore} implementation. The wrapper will also honor old + * unencrypted keys. + * + * @author Sebastian Sdorra + * @since 1.60 + */ +public class EncryptionKeyStoreWrapper implements KeyStore { + + private static final String ALGORITHM = "AES"; + + private static final SecureRandom random = new SecureRandom(); + + // i know storing the key directly in the class is far away from a best practice, but this is a chicken egg type + // of problem. We need a key to encrypt the stored keys, however encrypting the keys with a static defined key + // is better as storing them as plain text. + private static final byte[] SECRET_KEY = new byte[]{ 0x50, 0x61, 0x41, 0x67, 0x55, 0x43, 0x48, 0x7a, 0x48, 0x59, + 0x7a, 0x57, 0x6b, 0x34, 0x54, 0x62 + }; + + @VisibleForTesting + static final String ENCRYPTED_PREFIX = "enc:"; + + private KeyStore wrappedKeyStore; + + EncryptionKeyStoreWrapper(KeyStore wrappedKeyStore) { + this.wrappedKeyStore = wrappedKeyStore; + } + + @Override + public void set(String secretKey) { + String encrypted = encrypt(secretKey); + wrappedKeyStore.set(ENCRYPTED_PREFIX.concat(encrypted)); + } + + private String encrypt(String value) { + try { + Cipher cipher = createCipher(Cipher.ENCRYPT_MODE); + byte[] raw = cipher.doFinal(value.getBytes(Charsets.UTF_8)); + return encode(raw); + } catch (IllegalBlockSizeException | BadPaddingException ex) { + throw new ScmConfigException("failed to encrypt key", ex); + } + } + + private String encode(byte[] raw) { + return BaseEncoding.base64().encode(raw); + } + + @Override + public String get() { + String value = wrappedKeyStore.get(); + if (Strings.nullToEmpty(value).startsWith(ENCRYPTED_PREFIX)) { + String encrypted = value.substring(ENCRYPTED_PREFIX.length()); + return decrypt(encrypted); + } + return value; + } + + private String decrypt(String encoded) { + try { + Cipher cipher = createCipher(Cipher.DECRYPT_MODE); + byte[] raw = decode(encoded); + return new String(cipher.doFinal(raw), Charsets.UTF_8); + } catch (IllegalBlockSizeException | BadPaddingException ex) { + throw new ScmConfigException("failed to decrypt key", ex); + } + } + + private byte[] decode(String encoded) { + return BaseEncoding.base64().decode(encoded); + } + + private Cipher createCipher(int mode) { + try { + Cipher cipher = Cipher.getInstance(ALGORITHM); + SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET_KEY, "AES"); + cipher.init(mode, secretKeySpec, random); + return cipher; + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException ex) { + throw new ScmConfigException("failed to create key", ex); + } + } + + @Override + public void remove() { + wrappedKeyStore.remove(); + } +} diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java index 00a0eb6cf6..78efd5f149 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java @@ -62,11 +62,11 @@ public class ScmClientConfigFileHandler /** - * Constructs a new ScmClientConfigFileHandler - * + * Constructs a new ScmClientConfigFileHandler with a encrypted {@link java.util.prefs.Preferences} based + * {@link KeyStore} and a determined default location. */ public ScmClientConfigFileHandler() { - this(new PrefsKeyStore(), getDefaultConfigFile()); + this(new EncryptionKeyStoreWrapper(new PrefsKeyStore()), getDefaultConfigFile()); } ScmClientConfigFileHandler(KeyStore keyStore,File file) { diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionKeyStoreWrapperTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionKeyStoreWrapperTest.java new file mode 100644 index 0000000000..0a77c9d772 --- /dev/null +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionKeyStoreWrapperTest.java @@ -0,0 +1,60 @@ +/** + * 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.cli.config; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class EncryptionKeyStoreWrapperTest { + + private KeyStore keyStore = new InMemoryKeyStore(); + + @Test + public void testEncryptionKeyStoreWrapper() { + EncryptionKeyStoreWrapper wrapper = new EncryptionKeyStoreWrapper(keyStore); + wrapper.set("mysecretkey"); + + assertEquals("mysecretkey", wrapper.get()); + assertTrue(keyStore.get().startsWith(EncryptionKeyStoreWrapper.ENCRYPTED_PREFIX)); + } + + @Test + public void testEncryptionKeyStoreWrapperWithOldUnencryptedKey() { + keyStore.set("mysecretkey"); + EncryptionKeyStoreWrapper wrapper = new EncryptionKeyStoreWrapper(keyStore); + assertEquals("mysecretkey", wrapper.get()); + } + +} diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java index a9f6a46418..f7dfc36deb 100644 --- a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java @@ -54,7 +54,7 @@ public class ScmClientConfigFileHandlerTest { File configFile = temporaryFolder.newFile(); ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( - new InMemoryKeyStore(), configFile + new EncryptionKeyStoreWrapper(new InMemoryKeyStore()), configFile ); ScmClientConfig config = new ScmClientConfig(); @@ -90,7 +90,7 @@ public class ScmClientConfigFileHandlerTest { assertFalse(ConfigFiles.isFormatV2(configFile)); - KeyStore keyStore = new InMemoryKeyStore(); + KeyStore keyStore = new EncryptionKeyStoreWrapper(new InMemoryKeyStore()); keyStore.set(key); ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( @@ -116,7 +116,7 @@ public class ScmClientConfigFileHandlerTest { Files.write(bytes, configFile); String key = "358e018a-0c3c-4339-8266-3874e597305f"; - KeyStore keyStore = new InMemoryKeyStore(); + KeyStore keyStore = new EncryptionKeyStoreWrapper(new InMemoryKeyStore()); keyStore.set(key); ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( From f3459729353b6c29c9570a225d72f8afcb9a173d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 30 Apr 2018 11:01:00 +0200 Subject: [PATCH 063/178] #979 change encryption key prefix from enc to SKV2 (scm key version 2) --- .../java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java index 826660f00f..d86bfa40b6 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java @@ -68,7 +68,7 @@ public class EncryptionKeyStoreWrapper implements KeyStore { }; @VisibleForTesting - static final String ENCRYPTED_PREFIX = "enc:"; + static final String ENCRYPTED_PREFIX = "SKV2:"; private KeyStore wrappedKeyStore; From 41dea4741337414ba96b89c659b5a75f2c63c8e2 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 4 May 2018 07:20:07 +0200 Subject: [PATCH 064/178] #979 rename KeyStore to SecretKeyStore --- .../sonia/scm/cli/config/ConfigFiles.java | 22 +++++++++---------- ...a => EncryptionSecretKeyStoreWrapper.java} | 20 ++++++++--------- ...KeyStore.java => PrefsSecretKeyStore.java} | 9 +++++--- .../config/ScmClientConfigFileHandler.java | 20 ++++++++--------- .../{KeyStore.java => SecretKeyStore.java} | 7 ++++-- .../sonia/scm/cli/config/ConfigFilesTest.java | 8 +++---- ... EncryptionSecretKeyStoreWrapperTest.java} | 12 +++++----- ...Store.java => InMemorySecretKeyStore.java} | 2 +- .../ScmClientConfigFileHandlerTest.java | 18 +++++++-------- 9 files changed, 62 insertions(+), 56 deletions(-) rename scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/{EncryptionKeyStoreWrapper.java => EncryptionSecretKeyStoreWrapper.java} (86%) rename scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/{PrefsKeyStore.java => PrefsSecretKeyStore.java} (91%) rename scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/{KeyStore.java => SecretKeyStore.java} (93%) rename scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/{EncryptionKeyStoreWrapperTest.java => EncryptionSecretKeyStoreWrapperTest.java} (81%) rename scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/{InMemoryKeyStore.java => InMemorySecretKeyStore.java} (96%) diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java index 5087c50746..0f88ef662a 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ConfigFiles.java @@ -78,15 +78,15 @@ final class ConfigFiles { /** * Decrypt and parse v1 configuration file. * - * @param keyStore key store + * @param secretKeyStore key store * @param file configuration file * * @return client configuration * * @throws IOException */ - static ScmClientConfig parseV1(KeyStore keyStore, File file) throws IOException { - String secretKey = secretKey(keyStore); + static ScmClientConfig parseV1(SecretKeyStore secretKeyStore, File file) throws IOException { + String secretKey = secretKey(secretKeyStore); CipherStreamHandler cipherStreamHandler = new WeakCipherStreamHandler(secretKey); return decrypt(cipherStreamHandler, new FileInputStream(file)); } @@ -94,15 +94,15 @@ final class ConfigFiles { /** * Decrypt and parse v12configuration file. * - * @param keyStore key store + * @param secretKeyStore key store * @param file configuration file * * @return client configuration * * @throws IOException */ - static ScmClientConfig parseV2(KeyStore keyStore, File file) throws IOException { - String secretKey = secretKey(keyStore); + static ScmClientConfig parseV2(SecretKeyStore secretKeyStore, File file) throws IOException { + String secretKey = secretKey(secretKeyStore); CipherStreamHandler cipherStreamHandler = new AesCipherStreamHandler(secretKey); try (InputStream input = new FileInputStream(file)) { input.skip(VERSION_IDENTIFIER.length); @@ -114,24 +114,24 @@ final class ConfigFiles { * Store encrypt and write the configuration to the given file. * Note the method uses always the latest available format. * - * @param keyStore key store + * @param secretKeyStore key store * @param config configuration * @param file configuration file * * @throws IOException */ - static void store(KeyStore keyStore, ScmClientConfig config, File file) throws IOException { + static void store(SecretKeyStore secretKeyStore, ScmClientConfig config, File file) throws IOException { String secretKey = keyGenerator.createKey(); CipherStreamHandler cipherStreamHandler = new AesCipherStreamHandler(secretKey); try (OutputStream output = new FileOutputStream(file)) { output.write(VERSION_IDENTIFIER); encrypt(cipherStreamHandler, output, config); } - keyStore.set(secretKey); + secretKeyStore.set(secretKey); } - private static String secretKey(KeyStore keyStore) { - String secretKey = keyStore.get(); + private static String secretKey(SecretKeyStore secretKeyStore) { + String secretKey = secretKeyStore.get(); Preconditions.checkState(!Strings.isNullOrEmpty(secretKey), "no stored secret key found"); return secretKey; } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionSecretKeyStoreWrapper.java similarity index 86% rename from scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java rename to scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionSecretKeyStoreWrapper.java index d86bfa40b6..123655a7e3 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionKeyStoreWrapper.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/EncryptionSecretKeyStoreWrapper.java @@ -47,14 +47,14 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; /** - * The EncryptionKeyStoreWrapper is a wrapper around the {@link KeyStore} interface. The wrapper will encrypt the passed - * keys, before they are written to the underlying {@link KeyStore} implementation. The wrapper will also honor old - * unencrypted keys. + * The EncryptionSecretKeyStoreWrapper is a wrapper around the {@link SecretKeyStore} interface. The wrapper will + * encrypt the passed secret keys, before they are written to the underlying {@link SecretKeyStore} implementation. The + * wrapper will also honor old unencrypted keys. * * @author Sebastian Sdorra * @since 1.60 */ -public class EncryptionKeyStoreWrapper implements KeyStore { +public class EncryptionSecretKeyStoreWrapper implements SecretKeyStore { private static final String ALGORITHM = "AES"; @@ -70,16 +70,16 @@ public class EncryptionKeyStoreWrapper implements KeyStore { @VisibleForTesting static final String ENCRYPTED_PREFIX = "SKV2:"; - private KeyStore wrappedKeyStore; + private SecretKeyStore wrappedSecretKeyStore; - EncryptionKeyStoreWrapper(KeyStore wrappedKeyStore) { - this.wrappedKeyStore = wrappedKeyStore; + EncryptionSecretKeyStoreWrapper(SecretKeyStore wrappedSecretKeyStore) { + this.wrappedSecretKeyStore = wrappedSecretKeyStore; } @Override public void set(String secretKey) { String encrypted = encrypt(secretKey); - wrappedKeyStore.set(ENCRYPTED_PREFIX.concat(encrypted)); + wrappedSecretKeyStore.set(ENCRYPTED_PREFIX.concat(encrypted)); } private String encrypt(String value) { @@ -98,7 +98,7 @@ public class EncryptionKeyStoreWrapper implements KeyStore { @Override public String get() { - String value = wrappedKeyStore.get(); + String value = wrappedSecretKeyStore.get(); if (Strings.nullToEmpty(value).startsWith(ENCRYPTED_PREFIX)) { String encrypted = value.substring(ENCRYPTED_PREFIX.length()); return decrypt(encrypted); @@ -133,6 +133,6 @@ public class EncryptionKeyStoreWrapper implements KeyStore { @Override public void remove() { - wrappedKeyStore.remove(); + wrappedSecretKeyStore.remove(); } } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsKeyStore.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsSecretKeyStore.java similarity index 91% rename from scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsKeyStore.java rename to scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsSecretKeyStore.java index 26a7e67b05..d3bd6847a8 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsKeyStore.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/PrefsSecretKeyStore.java @@ -34,15 +34,18 @@ package sonia.scm.cli.config; import java.util.prefs.Preferences; /** - * KeyStore implementation with uses {@link Preferences}. + * SecretKeyStore implementation with uses {@link Preferences}. + * + * @author Sebastian Sdorra + * @since 1.60 */ -public class PrefsKeyStore implements KeyStore { +public class PrefsSecretKeyStore implements SecretKeyStore { private static final String PREF_SECRET_KEY = "scm.client.key"; private final Preferences preferences; - public PrefsKeyStore() { + PrefsSecretKeyStore() { // we use ScmClientConfigFileHandler as base for backward compatibility preferences = Preferences.userNodeForPackage(ScmClientConfigFileHandler.class); } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java index 78efd5f149..5619d85f7e 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/ScmClientConfigFileHandler.java @@ -57,20 +57,20 @@ public class ScmClientConfigFileHandler //~--- constructors --------------------------------------------------------- - private final KeyStore keyStore; + private final SecretKeyStore secretKeyStore; private final File file; /** * Constructs a new ScmClientConfigFileHandler with a encrypted {@link java.util.prefs.Preferences} based - * {@link KeyStore} and a determined default location. + * {@link SecretKeyStore} and a determined default location. */ public ScmClientConfigFileHandler() { - this(new EncryptionKeyStoreWrapper(new PrefsKeyStore()), getDefaultConfigFile()); + this(new EncryptionSecretKeyStoreWrapper(new PrefsSecretKeyStore()), getDefaultConfigFile()); } - ScmClientConfigFileHandler(KeyStore keyStore,File file) { - this.keyStore = keyStore; + ScmClientConfigFileHandler(SecretKeyStore secretKeyStore, File file) { + this.secretKeyStore = secretKeyStore; this.file = file; } @@ -94,7 +94,7 @@ public class ScmClientConfigFileHandler throw new ScmConfigException("could not delete config file"); } - keyStore.remove(); + secretKeyStore.remove(); } /** @@ -117,10 +117,10 @@ public class ScmClientConfigFileHandler ScmClientConfig config; try { if (ConfigFiles.isFormatV2(file)) { - config = ConfigFiles.parseV2(keyStore, file); + config = ConfigFiles.parseV2(secretKeyStore, file); } else { - config = ConfigFiles.parseV1(keyStore, file); - ConfigFiles.store(keyStore, config, file); + config = ConfigFiles.parseV1(secretKeyStore, file); + ConfigFiles.store(secretKeyStore, config, file); } } catch (IOException ex) { throw new ScmConfigException("could not read config file", ex); @@ -136,7 +136,7 @@ public class ScmClientConfigFileHandler */ public void write(ScmClientConfig config) { try { - ConfigFiles.store(keyStore, config, file); + ConfigFiles.store(secretKeyStore, config, file); } catch (IOException ex) { throw new ScmConfigException("could not write config file", ex); } diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/SecretKeyStore.java similarity index 93% rename from scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java rename to scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/SecretKeyStore.java index 7ce64750ce..be600125b7 100644 --- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/KeyStore.java +++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/config/SecretKeyStore.java @@ -32,9 +32,12 @@ package sonia.scm.cli.config; /** - * KeyStore is able to read and write keys. + * SecretKeyStore is able to read and write secret keys. + * + * @author Sebastian Sdorra + * @since 1.60 */ -public interface KeyStore { +public interface SecretKeyStore { /** * Writes the given secret key to the store. diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java index 5fbdfdc0c0..d9edc64884 100644 --- a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ConfigFilesTest.java @@ -69,7 +69,7 @@ public class ConfigFilesTest { @Test public void testParseV1() throws IOException { - InMemoryKeyStore keyStore = createKeyStore(); + InMemorySecretKeyStore keyStore = createKeyStore(); WeakCipherStreamHandler handler = new WeakCipherStreamHandler(keyStore.get()); ScmClientConfig config = ClientConfigurationTests.createSampleConfig(); @@ -82,7 +82,7 @@ public class ConfigFilesTest { @Test public void storeAndParseV2() throws IOException { - InMemoryKeyStore keyStore = new InMemoryKeyStore(); + InMemorySecretKeyStore keyStore = new InMemorySecretKeyStore(); ScmClientConfig config = ClientConfigurationTests.createSampleConfig(); File file = temporaryFolder.newFile(); @@ -95,9 +95,9 @@ public class ConfigFilesTest { ClientConfigurationTests.assertSampleConfig(config); } - private InMemoryKeyStore createKeyStore() { + private InMemorySecretKeyStore createKeyStore() { String secretKey = new SecureRandomKeyGenerator().createKey(); - InMemoryKeyStore keyStore = new InMemoryKeyStore(); + InMemorySecretKeyStore keyStore = new InMemorySecretKeyStore(); keyStore.set(secretKey); return keyStore; } diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionKeyStoreWrapperTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionSecretKeyStoreWrapperTest.java similarity index 81% rename from scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionKeyStoreWrapperTest.java rename to scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionSecretKeyStoreWrapperTest.java index 0a77c9d772..c9190c3357 100644 --- a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionKeyStoreWrapperTest.java +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/EncryptionSecretKeyStoreWrapperTest.java @@ -37,23 +37,23 @@ import org.junit.Test; import static org.junit.Assert.*; -public class EncryptionKeyStoreWrapperTest { +public class EncryptionSecretKeyStoreWrapperTest { - private KeyStore keyStore = new InMemoryKeyStore(); + private SecretKeyStore secretKeyStore = new InMemorySecretKeyStore(); @Test public void testEncryptionKeyStoreWrapper() { - EncryptionKeyStoreWrapper wrapper = new EncryptionKeyStoreWrapper(keyStore); + EncryptionSecretKeyStoreWrapper wrapper = new EncryptionSecretKeyStoreWrapper(secretKeyStore); wrapper.set("mysecretkey"); assertEquals("mysecretkey", wrapper.get()); - assertTrue(keyStore.get().startsWith(EncryptionKeyStoreWrapper.ENCRYPTED_PREFIX)); + assertTrue(secretKeyStore.get().startsWith(EncryptionSecretKeyStoreWrapper.ENCRYPTED_PREFIX)); } @Test public void testEncryptionKeyStoreWrapperWithOldUnencryptedKey() { - keyStore.set("mysecretkey"); - EncryptionKeyStoreWrapper wrapper = new EncryptionKeyStoreWrapper(keyStore); + secretKeyStore.set("mysecretkey"); + EncryptionSecretKeyStoreWrapper wrapper = new EncryptionSecretKeyStoreWrapper(secretKeyStore); assertEquals("mysecretkey", wrapper.get()); } diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemoryKeyStore.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemorySecretKeyStore.java similarity index 96% rename from scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemoryKeyStore.java rename to scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemorySecretKeyStore.java index 1d0069a087..4510a7a072 100644 --- a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemoryKeyStore.java +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/InMemorySecretKeyStore.java @@ -32,7 +32,7 @@ package sonia.scm.cli.config; -public class InMemoryKeyStore implements KeyStore { +public class InMemorySecretKeyStore implements SecretKeyStore { private String secretKey; diff --git a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java index f7dfc36deb..9f65d34655 100644 --- a/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java +++ b/scm-clients/scm-cli-client/src/test/java/sonia/scm/cli/config/ScmClientConfigFileHandlerTest.java @@ -54,7 +54,7 @@ public class ScmClientConfigFileHandlerTest { File configFile = temporaryFolder.newFile(); ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( - new EncryptionKeyStoreWrapper(new InMemoryKeyStore()), configFile + new EncryptionSecretKeyStoreWrapper(new InMemorySecretKeyStore()), configFile ); ScmClientConfig config = new ScmClientConfig(); @@ -90,18 +90,18 @@ public class ScmClientConfigFileHandlerTest { assertFalse(ConfigFiles.isFormatV2(configFile)); - KeyStore keyStore = new EncryptionKeyStoreWrapper(new InMemoryKeyStore()); - keyStore.set(key); + SecretKeyStore secretKeyStore = new EncryptionSecretKeyStoreWrapper(new InMemorySecretKeyStore()); + secretKeyStore.set(key); ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( - keyStore, configFile + secretKeyStore, configFile ); ScmClientConfig config = handler.read(); ClientConfigurationTests.assertSampleConfig(config); // ensure key has changed - assertNotEquals(key, keyStore.get()); + assertNotEquals(key, secretKeyStore.get()); // ensure config rewritten with v2 assertTrue(ConfigFiles.isFormatV2(configFile)); @@ -116,11 +116,11 @@ public class ScmClientConfigFileHandlerTest { Files.write(bytes, configFile); String key = "358e018a-0c3c-4339-8266-3874e597305f"; - KeyStore keyStore = new EncryptionKeyStoreWrapper(new InMemoryKeyStore()); - keyStore.set(key); + SecretKeyStore secretKeyStore = new EncryptionSecretKeyStoreWrapper(new InMemorySecretKeyStore()); + secretKeyStore.set(key); ScmClientConfigFileHandler handler = new ScmClientConfigFileHandler( - keyStore, configFile + secretKeyStore, configFile ); ScmClientConfig config = handler.read(); @@ -130,7 +130,7 @@ public class ScmClientConfigFileHandlerTest { assertEquals("trillian123", defaultConfig.getPassword()); // ensure key has changed - assertNotEquals(key, keyStore.get()); + assertNotEquals(key, secretKeyStore.get()); // ensure config rewritten with v2 assertTrue(ConfigFiles.isFormatV2(configFile)); From 418ad370e2bed25b3c6a89e5199eacdbd9594fed Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 4 May 2018 09:07:18 +0200 Subject: [PATCH 065/178] close branch issue-979 From a0b3b154c81cdf310fab618d0959910d8335e42e Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 4 May 2018 11:14:45 +0200 Subject: [PATCH 066/178] [maven-release-plugin] prepare release 1.60 --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 22 +++++++++++----------- support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 23 files changed, 71 insertions(+), 71 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index 9215c0c526..0796fc4477 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60-SNAPSHOT + 1.60 sonia.scm.maven scm-maven-plugins pom - 1.60-SNAPSHOT + 1.60 scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 956a8339a4..8fc3a40f54 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.60-SNAPSHOT + 1.60 sonia.scm.maven scm-maven-plugin - 1.60-SNAPSHOT + 1.60 maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 8031c1e2a6..88f00440af 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.60-SNAPSHOT + 1.60 sonia.scm.maven scm-plugin-archetype - 1.60-SNAPSHOT + 1.60 scm-plugin-archetype diff --git a/pom.xml b/pom.xml index b27cbf84ea..8db5fede90 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.60-SNAPSHOT + 1.60 The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - HEAD + 1.60 diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index dbbf9abe99..9b2108efa7 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60-SNAPSHOT + 1.60 sonia.scm.clients scm-clients pom - 1.60-SNAPSHOT + 1.60 scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.60-SNAPSHOT + 1.60 shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index ee196d5c11..b29ea2d1d5 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.60-SNAPSHOT + 1.60 sonia.scm.clients scm-cli-client - 1.60-SNAPSHOT + 1.60 scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.60-SNAPSHOT + 1.60 diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index 498c3dac3d..efed7951f2 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.60-SNAPSHOT + 1.60 sonia.scm.clients scm-client-api jar - 1.60-SNAPSHOT + 1.60 scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 1150017db7..d4bb203488 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.60-SNAPSHOT + 1.60 sonia.scm.clients scm-client-impl jar - 1.60-SNAPSHOT + 1.60 scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.60-SNAPSHOT + 1.60 @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.60-SNAPSHOT + 1.60 test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 411a3c1d78..cfe6c9b68d 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.60-SNAPSHOT + 1.60 sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 scm-core diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index d42307809e..ee8089d480 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.60-SNAPSHOT + 1.60 sonia.scm scm-dao-xml - 1.60-SNAPSHOT + 1.60 scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.60-SNAPSHOT + 1.60 test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index 921e9756dd..d16fe4492a 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.60-SNAPSHOT + 1.60 sonia.scm scm-plugin-backend war - 1.60-SNAPSHOT + 1.60 ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 513dc0a6fe..12e78c8dc9 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60-SNAPSHOT + 1.60 sonia.scm.plugins scm-plugins pom - 1.60-SNAPSHOT + 1.60 scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.60-SNAPSHOT + 1.60 process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 8b15ad31fa..51ab7b34e4 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.60-SNAPSHOT + 1.60 sonia.scm.plugins scm-git-plugin - 1.60-SNAPSHOT + 1.60 scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.60-SNAPSHOT + 1.60 test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index bb339bb983..82c2355033 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.60-SNAPSHOT + 1.60 sonia.scm.plugins scm-hg-plugin - 1.60-SNAPSHOT + 1.60 scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.60-SNAPSHOT + 1.60 test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 025193838d..e7382c5235 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.60-SNAPSHOT + 1.60 sonia.scm.plugins scm-svn-plugin - 1.60-SNAPSHOT + 1.60 scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.60-SNAPSHOT + 1.60 test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 1b25fb0b18..5088dd9a29 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60-SNAPSHOT + 1.60 sonia.scm.samples scm-samples pom - 1.60-SNAPSHOT + 1.60 scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index f443d37763..8f74ed5f3b 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.60-SNAPSHOT + 1.60 sonia.scm.sample scm-sample-auth - 1.60-SNAPSHOT + 1.60 scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 21199294ba..3dec8f9e21 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.60-SNAPSHOT + 1.60 sonia.scm.sample scm-sample-hello - 1.60-SNAPSHOT + 1.60 scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 7103b0a701..5bf22f2af0 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.60-SNAPSHOT + 1.60 sonia.scm scm-server - 1.60-SNAPSHOT + 1.60 scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 6401485329..b30ba2c534 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.60-SNAPSHOT + 1.60 sonia.scm scm-test - 1.60-SNAPSHOT + 1.60 scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index d467061d1d..ec768b1cfc 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60-SNAPSHOT + 1.60 sonia.scm scm-webapp war - 1.60-SNAPSHOT + 1.60 scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 sonia.scm scm-dao-xml - 1.60-SNAPSHOT + 1.60 sonia.scm.plugins scm-hg-plugin - 1.60-SNAPSHOT + 1.60 sonia.scm.plugins scm-svn-plugin - 1.60-SNAPSHOT + 1.60 sonia.scm.plugins scm-git-plugin - 1.60-SNAPSHOT + 1.60 @@ -280,7 +280,7 @@ sonia.scm scm-test - 1.60-SNAPSHOT + 1.60 test @@ -293,7 +293,7 @@ sonia.scm.plugins scm-git-plugin - 1.60-SNAPSHOT + 1.60 tests test @@ -301,7 +301,7 @@ sonia.scm.plugins scm-hg-plugin - 1.60-SNAPSHOT + 1.60 tests test @@ -309,7 +309,7 @@ sonia.scm.plugins scm-svn-plugin - 1.60-SNAPSHOT + 1.60 tests test diff --git a/support/pom.xml b/support/pom.xml index 882727808b..084b056359 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60-SNAPSHOT + 1.60 sonia.scm.support scm-support pom - 1.60-SNAPSHOT + 1.60 scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index 9dc37271b2..cd53813efa 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.60-SNAPSHOT + 1.60 sonia.scm scm-support-btrace - 1.60-SNAPSHOT + 1.60 jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.60-SNAPSHOT + 1.60 From 0ba7fab12c340e21c8708725ededb609c93f867e Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 4 May 2018 11:14:45 +0200 Subject: [PATCH 067/178] [maven-release-plugin] copy for tag 1.60 From 3f27dd8ccab7b208f727f60a1d07d9611e9dd914 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 4 May 2018 11:14:45 +0200 Subject: [PATCH 068/178] [maven-release-plugin] prepare for next development iteration --- maven/pom.xml | 4 ++-- maven/scm-maven-plugin/pom.xml | 4 ++-- maven/scm-plugin-archetype/pom.xml | 4 ++-- pom.xml | 4 ++-- scm-clients/pom.xml | 6 +++--- scm-clients/scm-cli-client/pom.xml | 6 +++--- scm-clients/scm-client-api/pom.xml | 4 ++-- scm-clients/scm-client-impl/pom.xml | 8 ++++---- scm-core/pom.xml | 4 ++-- scm-dao-xml/pom.xml | 8 ++++---- scm-plugin-backend/pom.xml | 6 +++--- scm-plugins/pom.xml | 8 ++++---- scm-plugins/scm-git-plugin/pom.xml | 6 +++--- scm-plugins/scm-hg-plugin/pom.xml | 6 +++--- scm-plugins/scm-svn-plugin/pom.xml | 6 +++--- scm-samples/pom.xml | 4 ++-- scm-samples/scm-sample-auth/pom.xml | 6 +++--- scm-samples/scm-sample-hello/pom.xml | 6 +++--- scm-server/pom.xml | 4 ++-- scm-test/pom.xml | 6 +++--- scm-webapp/pom.xml | 22 +++++++++++----------- support/pom.xml | 4 ++-- support/scm-support-btrace/pom.xml | 6 +++--- 23 files changed, 71 insertions(+), 71 deletions(-) diff --git a/maven/pom.xml b/maven/pom.xml index 0796fc4477..0135f1f40c 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60 + 1.61-SNAPSHOT sonia.scm.maven scm-maven-plugins pom - 1.60 + 1.61-SNAPSHOT scm-maven-plugins diff --git a/maven/scm-maven-plugin/pom.xml b/maven/scm-maven-plugin/pom.xml index 8fc3a40f54..8b8bb20afe 100644 --- a/maven/scm-maven-plugin/pom.xml +++ b/maven/scm-maven-plugin/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.60 + 1.61-SNAPSHOT sonia.scm.maven scm-maven-plugin - 1.60 + 1.61-SNAPSHOT maven-plugin scm-maven-plugin diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 88f00440af..5d86da291c 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -6,12 +6,12 @@ scm-maven-plugins sonia.scm.maven - 1.60 + 1.61-SNAPSHOT sonia.scm.maven scm-plugin-archetype - 1.60 + 1.61-SNAPSHOT scm-plugin-archetype diff --git a/pom.xml b/pom.xml index 8db5fede90..840c9f1ec3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.60 + 1.61-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -36,7 +36,7 @@ scm:hg:http://bitbucket.org/sdorra/scm-manager scm:hg:https://bitbucket.org/sdorra/scm-manager http://bitbucket.org/sdorra/scm-manager - 1.60 + HEAD diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml index 9b2108efa7..9a957975be 100644 --- a/scm-clients/pom.xml +++ b/scm-clients/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60 + 1.61-SNAPSHOT sonia.scm.clients scm-clients pom - 1.60 + 1.61-SNAPSHOT scm-clients @@ -32,7 +32,7 @@ scm-core sonia.scm jar - 1.60 + 1.61-SNAPSHOT shiro-core diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml index b29ea2d1d5..43b42e70ef 100644 --- a/scm-clients/scm-cli-client/pom.xml +++ b/scm-clients/scm-cli-client/pom.xml @@ -6,12 +6,12 @@ scm-clients sonia.scm.clients - 1.60 + 1.61-SNAPSHOT sonia.scm.clients scm-cli-client - 1.60 + 1.61-SNAPSHOT scm-cli-client @@ -34,7 +34,7 @@ sonia.scm.clients scm-client-impl - 1.60 + 1.61-SNAPSHOT diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml index efed7951f2..71586cffe9 100644 --- a/scm-clients/scm-client-api/pom.xml +++ b/scm-clients/scm-client-api/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.60 + 1.61-SNAPSHOT sonia.scm.clients scm-client-api jar - 1.60 + 1.61-SNAPSHOT scm-client-api diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index d4bb203488..ba6edb9130 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -6,13 +6,13 @@ sonia.scm.clients scm-clients - 1.60 + 1.61-SNAPSHOT sonia.scm.clients scm-client-impl jar - 1.60 + 1.61-SNAPSHOT scm-client-impl @@ -36,7 +36,7 @@ sonia.scm.clients scm-client-api - 1.60 + 1.61-SNAPSHOT @@ -70,7 +70,7 @@ sonia.scm scm-test - 1.60 + 1.61-SNAPSHOT test diff --git a/scm-core/pom.xml b/scm-core/pom.xml index cfe6c9b68d..ae0057dbdf 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.60 + 1.61-SNAPSHOT sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT scm-core diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index ee8089d480..b26d86a9ad 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -6,12 +6,12 @@ sonia.scm scm - 1.60 + 1.61-SNAPSHOT sonia.scm scm-dao-xml - 1.60 + 1.61-SNAPSHOT scm-dao-xml @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT @@ -34,7 +34,7 @@ sonia.scm scm-test - 1.60 + 1.61-SNAPSHOT test diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml index d16fe4492a..ad29e34d1f 100644 --- a/scm-plugin-backend/pom.xml +++ b/scm-plugin-backend/pom.xml @@ -6,13 +6,13 @@ scm sonia.scm - 1.60 + 1.61-SNAPSHOT sonia.scm scm-plugin-backend war - 1.60 + 1.61-SNAPSHOT ${project.artifactId} @@ -62,7 +62,7 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 12e78c8dc9..7d62a261b4 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60 + 1.61-SNAPSHOT sonia.scm.plugins scm-plugins pom - 1.60 + 1.61-SNAPSHOT scm-plugins @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT @@ -59,7 +59,7 @@ sonia.scm.maven scm-maven-plugin - 1.60 + 1.61-SNAPSHOT process-resources diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 51ab7b34e4..dc02c4ab5a 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.60 + 1.61-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.60 + 1.61-SNAPSHOT scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -54,7 +54,7 @@ sonia.scm scm-test - 1.60 + 1.61-SNAPSHOT test diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 82c2355033..b1b5f33d4a 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -6,12 +6,12 @@ sonia.scm.plugins scm-plugins - 1.60 + 1.61-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.60 + 1.61-SNAPSHOT scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -42,7 +42,7 @@ sonia.scm scm-test - 1.60 + 1.61-SNAPSHOT test diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index e7382c5235..e5ceb8b7ef 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -6,12 +6,12 @@ scm-plugins sonia.scm.plugins - 1.60 + 1.61-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.60 + 1.61-SNAPSHOT scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion @@ -48,7 +48,7 @@ sonia.scm scm-test - 1.60 + 1.61-SNAPSHOT test diff --git a/scm-samples/pom.xml b/scm-samples/pom.xml index 5088dd9a29..918606a1e8 100644 --- a/scm-samples/pom.xml +++ b/scm-samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60 + 1.61-SNAPSHOT sonia.scm.samples scm-samples pom - 1.60 + 1.61-SNAPSHOT scm-samples diff --git a/scm-samples/scm-sample-auth/pom.xml b/scm-samples/scm-sample-auth/pom.xml index 8f74ed5f3b..1fdfe1fd0f 100644 --- a/scm-samples/scm-sample-auth/pom.xml +++ b/scm-samples/scm-sample-auth/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.60 + 1.61-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.60 + 1.61-SNAPSHOT scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT diff --git a/scm-samples/scm-sample-hello/pom.xml b/scm-samples/scm-sample-hello/pom.xml index 3dec8f9e21..313cb5faad 100644 --- a/scm-samples/scm-sample-hello/pom.xml +++ b/scm-samples/scm-sample-hello/pom.xml @@ -6,12 +6,12 @@ scm-samples sonia.scm.samples - 1.60 + 1.61-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.60 + 1.61-SNAPSHOT scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -28,7 +28,7 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 5bf22f2af0..562cd101fd 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.60 + 1.61-SNAPSHOT sonia.scm scm-server - 1.60 + 1.61-SNAPSHOT scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index b30ba2c534..0e89e416cb 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -6,12 +6,12 @@ scm sonia.scm - 1.60 + 1.61-SNAPSHOT sonia.scm scm-test - 1.60 + 1.61-SNAPSHOT scm-test @@ -25,7 +25,7 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index ec768b1cfc..3803b24e00 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60 + 1.61-SNAPSHOT sonia.scm scm-webapp war - 1.60 + 1.61-SNAPSHOT scm-webapp @@ -38,31 +38,31 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT sonia.scm scm-dao-xml - 1.60 + 1.61-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.60 + 1.61-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.60 + 1.61-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.60 + 1.61-SNAPSHOT @@ -280,7 +280,7 @@ sonia.scm scm-test - 1.60 + 1.61-SNAPSHOT test @@ -293,7 +293,7 @@ sonia.scm.plugins scm-git-plugin - 1.60 + 1.61-SNAPSHOT tests test @@ -301,7 +301,7 @@ sonia.scm.plugins scm-hg-plugin - 1.60 + 1.61-SNAPSHOT tests test @@ -309,7 +309,7 @@ sonia.scm.plugins scm-svn-plugin - 1.60 + 1.61-SNAPSHOT tests test diff --git a/support/pom.xml b/support/pom.xml index 084b056359..88be822886 100644 --- a/support/pom.xml +++ b/support/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.60 + 1.61-SNAPSHOT sonia.scm.support scm-support pom - 1.60 + 1.61-SNAPSHOT scm-support diff --git a/support/scm-support-btrace/pom.xml b/support/scm-support-btrace/pom.xml index cd53813efa..4e113fbfd7 100644 --- a/support/scm-support-btrace/pom.xml +++ b/support/scm-support-btrace/pom.xml @@ -4,12 +4,12 @@ sonia.scm.support scm-support - 1.60 + 1.61-SNAPSHOT sonia.scm scm-support-btrace - 1.60 + 1.61-SNAPSHOT jar scm-support-btrace @@ -18,7 +18,7 @@ sonia.scm scm-core - 1.60 + 1.61-SNAPSHOT From e826b833cc93365249831ec51ff12bdfeeb4376d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Tue, 27 Jun 2017 20:16:05 +0200 Subject: [PATCH 069/178] switch from jersey 1.x to resteasy --- pom.xml | 355 +++++++------- scm-clients/scm-client-impl/pom.xml | 4 +- scm-core/pom.xml | 6 +- .../scm/security/DefaultCipherHandler.java | 7 +- .../java/sonia/scm/template/Viewable.java | 110 ++--- .../main/java/sonia/scm/web/HgCGIServlet.java | 34 +- scm-webapp/pom.xml | 434 ++++++++---------- .../main/java/sonia/scm/ScmServletModule.java | 209 ++------- .../scm/api/rest/TemplateEngineViewable.java | 64 +-- .../resources/AbstractPermissionResource.java | 8 +- .../resources/ChangePasswordResource.java | 2 +- .../rest/resources/ConfigurationResource.java | 4 +- .../scm/api/rest/resources/GroupResource.java | 8 +- .../api/rest/resources/PluginResource.java | 16 +- .../resources/RepositoryImportResource.java | 27 +- .../rest/resources/RepositoryResource.java | 22 +- .../resources/RepositoryRootResource.java | 21 +- .../api/rest/resources/SearchResource.java | 4 +- .../scm/api/rest/resources/UserResource.java | 8 +- .../java/sonia/scm/debug/DebugResource.java | 4 +- .../scm/net/ahc/JsonContentTransformer.java | 20 +- .../src/main/resources/logback.default.xml | 2 + scm-webapp/src/main/webapp/WEB-INF/web.xml | 38 +- .../sonia.action.changepasswordwindow.js | 2 +- .../js/config/sonia.config.scmconfigpanel.js | 4 +- .../js/group/sonia.group.formpanel.js | 4 +- .../resources/js/group/sonia.group.panel.js | 2 +- .../resources/js/login/sonia.login.form.js | 15 +- .../js/plugin/sonia.plugin.center.js | 6 +- .../resources/js/plugin/sonia.plugin.grid.js | 2 +- .../sonia.repository.branchcombobox.js | 2 +- .../sonia.repository.changesetviewerpanel.js | 2 +- .../sonia.repository.commitpanel.js | 2 +- .../repository/sonia.repository.formpanel.js | 4 +- .../js/repository/sonia.repository.grid.js | 2 +- .../sonia.repository.healthcheckfailure.js | 2 +- .../sonia.repository.importwindow.js | 4 +- .../js/repository/sonia.repository.js | 2 +- .../js/repository/sonia.repository.panel.js | 4 +- .../sonia.repository.repositorybrowser.js | 2 +- .../sonia.repository.tagcombobox.js | 2 +- .../sonia.security.permissionspanel.js | 8 +- .../main/webapp/resources/js/sonia.global.js | 4 +- .../src/main/webapp/resources/js/sonia.scm.js | 2 +- .../resources/js/user/sonia.user.formpanel.js | 4 +- .../resources/js/user/sonia.user.grid.js | 2 +- .../resources/js/user/sonia.user.panel.js | 2 +- .../test/java/sonia/scm/it/GitLfsITCase.java | 7 +- 48 files changed, 622 insertions(+), 877 deletions(-) rename scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java => scm-core/src/main/java/sonia/scm/template/Viewable.java (52%) diff --git a/pom.xml b/pom.xml index 840c9f1ec3..3674300b1d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.61-SNAPSHOT + 2.0.0-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -59,18 +59,20 @@ https://scm-manager.ci.cloudbees.com/ + + 3.1.0 + + + scm-annotations + scm-annotation-processor scm-core scm-test - maven scm-plugins - scm-samples scm-dao-xml scm-webapp scm-server - scm-plugin-backend scm-clients - support @@ -80,6 +82,15 @@ scm-manager release repository http://maven.scm-manager.org/nexus/content/groups/public + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + true + daily + + @@ -128,20 +139,52 @@ ${mokito.version} test - + + + + org.apache.maven.plugins + maven-enforcer-plugin + 1.4.1 + + + enforce-java + compile + + enforce + + + + + + [1.8.0-101,) + + + + [3.1,) + + + true + + + + org.codehaus.mojo animal-sniffer-maven-plugin - 1.16 + 1.15 org.codehaus.mojo.signature - java17 + java18 1.0 @@ -155,51 +198,23 @@ - - org.apache.maven.plugins - maven-enforcer-plugin - 3.0.0-M1 - - - enforce-java - compile - - enforce - - - - - 1.7 - - - module-info - - - - true - - - - - - org.codehaus.mojo - extra-enforcer-rules - 1.0-beta-7 - - - - org.apache.maven.plugins maven-compiler-plugin - 3.0 + 3.5.1 + true + true ${project.build.javaLevel} ${project.build.javaLevel} + ${project.test.javaLevel} + ${project.test.javaLevel} ${project.build.sourceEncoding} + + -Xlint:unchecked,-options @@ -244,7 +259,7 @@ true true - http://download.oracle.com/javase/7/docs/api/ + http://download.oracle.com/javase/8/docs/api/ http://download.oracle.com/docs/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/ http://jersey.java.net/nonav/apidocs/${jersey.version}/jersey/ https://google.github.io/guice/api-docs/${guice.version}/javadoc @@ -301,59 +316,81 @@ maven-eclipse-plugin 2.6 - + + + + + org.jacoco + jacoco-maven-plugin + 0.7.7.201606060606 + + + + prepare-agent + + + + report + prepare-package + + report + + + + + org.apache.maven.plugins maven-site-plugin - 3.7 + 3.2 + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.4 + + + + org.apache.maven.plugins + maven-jxr-plugin + 2.3 + + + + org.codehaus.mojo + findbugs-maven-plugin + 2.4.0 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.12 + + + + org.apache.maven.plugins + maven-pmd-plugin + 2.7.1 + + true + ${project.build.sourceEncoding} + ${project.build.javaLevel} + + + + + - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.4 - - - - org.apache.maven.plugins - maven-jxr-plugin - 2.3 - - - - org.codehaus.mojo - findbugs-maven-plugin - 2.4.0 - - - - org.apache.maven.plugins - maven-surefire-report-plugin - 2.12 - - - - org.apache.maven.plugins - maven-pmd-plugin - 2.7.1 - - ${project.build.sourceEncoding} - ${project.build.javaLevel} - - - - - - @@ -397,9 +434,18 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 + 2.8.1 - false + org.jboss.apiviz.APIviz + + org.jboss.apiviz + apiviz + 1.3.2.GA + + + -sourceclasspath ${project.build.outputDirectory} + -nopackagediagram + @@ -410,101 +456,6 @@ - - - - - - - commons-beanutils - commons-beanutils - 1.9.3 - - - - commons-collections - commons-collections - 3.2.2 - - - - - - org.apache.httpcomponents - httpclient - 4.5.5 - - - - - - slf4j-api - org.slf4j - ${slf4j.version} - - - - ch.qos.logback - logback-classic - ${logback.version} - - - - - - - org.codehaus.jackson - jackson-core-asl - ${jackson.version} - - - - org.codehaus.jackson - jackson-mapper-asl - ${jackson.version} - - - - org.codehaus.jackson - jackson-jaxrs - ${jackson.version} - - - - org.codehaus.jackson - jackson-xc - ${jackson.version} - - - - - - javax.xml.bind - jaxb-api - ${jaxb.version} - - - - com.sun.xml.bind - jaxb-impl - ${jaxb.version} - - - - org.glassfish.jaxb - jaxb-runtime - ${jaxb.version} - - - - javax.activation - activation - 1.1.1 - - - - - @@ -528,31 +479,37 @@ 4.12 - 1.7.25 + 1.7.22 1.2.3 - 2.5 - 3.0 + 3.0.1 + 2.0.1 + 4.0 1.19.4 + + + 1.2.0 + 2.6.6 2.3.20 - 7.6.21.v20160908 - 7.6.16.v20140903 - 1.9.13 - 2.3.0 + + + 9.2.10.v20150310 + 9.2.10.v20150310 - 1.3.2 + 1.0.0-SNAPSHOT + 1.4.0-RC2 - - v4.5.3.201708160445-r-scm1 - 1.9.0-scm3 + + v4.5.2.201704071617-r-scm1 + 1.8.15-scm1 - 15.0 + 16.0.1 2.2.3 - 1.7 + 1.8 UTF-8 SCM-BSD diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index ba6edb9130..1e6847349f 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -42,13 +42,13 @@ com.sun.jersey jersey-client - ${jersey.version} + ${jersey-client.version} com.sun.jersey.contribs jersey-multipart - ${jersey.version} + ${jersey-client.version} diff --git a/scm-core/pom.xml b/scm-core/pom.xml index ae0057dbdf..fde7dceb47 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -69,9 +69,9 @@ - com.sun.jersey - jersey-core - ${jersey.version} + javax.ws.rs + javax.ws.rs-api + ${jaxrs.version} diff --git a/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java b/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java index ddb8a699a7..b4f0d81cd3 100644 --- a/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java +++ b/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java @@ -45,8 +45,6 @@ import sonia.scm.util.IOUtil; //~--- JDK imports ------------------------------------------------------------ -import com.sun.jersey.core.util.Base64; - import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -60,6 +58,7 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; +import java.util.Base64; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; @@ -165,7 +164,7 @@ public class DefaultCipherHandler implements CipherHandler { String result = null; try { - byte[] encodedInput = Base64.decode(value); + byte[] encodedInput = Base64.getDecoder().decode(value); byte[] salt = new byte[SALT_LENGTH]; byte[] encoded = new byte[encodedInput.length - SALT_LENGTH]; @@ -222,7 +221,7 @@ public class DefaultCipherHandler implements CipherHandler { System.arraycopy(salt, 0, result, 0, SALT_LENGTH); System.arraycopy(encodedInput, 0, result, SALT_LENGTH, result.length - SALT_LENGTH); - res = new String(Base64.encode(result), ENCODING); + res = new String(Base64.getEncoder().encode(result), ENCODING); } catch (IOException | GeneralSecurityException ex) { throw new CipherException("could not encode string", ex); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java b/scm-core/src/main/java/sonia/scm/template/Viewable.java similarity index 52% rename from scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java rename to scm-core/src/main/java/sonia/scm/template/Viewable.java index 637866ad61..8344d2820e 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java +++ b/scm-core/src/main/java/sonia/scm/template/Viewable.java @@ -28,89 +28,63 @@ * http://bitbucket.org/sdorra/scm-manager * */ +package sonia.scm.template; +import com.google.common.base.Objects; -package sonia.scm.api.rest; - -//~--- JDK imports ------------------------------------------------------------ - -import com.sun.jersey.api.core.PackagesResourceConfig; - -import java.util.HashMap; -import java.util.Map; - -import javax.ws.rs.core.MediaType; - /** - * + * A viewable holds the path to a template and the context object which is used to render the template. Viewables can + * be used as return type of jax-rs resources. + * * @author Sebastian Sdorra + * @since 2.0.0 */ -public class UriExtensionsConfig extends PackagesResourceConfig -{ +public final class Viewable { + + private final String path; + private final Object context; - /** Field description */ - public static final String EXTENSION_JSON = "json"; - - /** Field description */ - public static final String EXTENSION_XML = "xml"; - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - public UriExtensionsConfig() - { - super(); + public Viewable(String path, Object context) { + this.path = path; + this.context = context; } - /** - * Constructs ... - * - * - * @param props - */ - public UriExtensionsConfig(Map props) - { - super(props); + public String getPath() { + return path; } - /** - * Constructs ... - * - * - * @param paths - */ - public UriExtensionsConfig(String[] paths) - { - super(paths); + public Object getContext() { + return context; } - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ @Override - public Map getMediaTypeMappings() - { - if (mediaTypeMap == null) - { - mediaTypeMap = new HashMap(); - mediaTypeMap.put(EXTENSION_JSON, MediaType.APPLICATION_JSON_TYPE); - mediaTypeMap.put(EXTENSION_XML, MediaType.APPLICATION_XML_TYPE); - } - - return mediaTypeMap; + public int hashCode() { + return Objects.hashCode(path, context); } - //~--- fields --------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Viewable other = (Viewable) obj; + return !Objects.equal(this.path, other.path) + && Objects.equal(this.context, other.context); + } - /** Field description */ - private Map mediaTypeMap; + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("path", path) + .add("context", context) + .toString(); + } + } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 1fb78161e0..0befcf6f11 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -36,6 +36,7 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.Stopwatch; +import com.google.common.base.Strings; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -52,18 +53,21 @@ import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; +import sonia.scm.security.CipherUtil; import sonia.scm.util.AssertUtil; +import sonia.scm.util.HttpUtil; import sonia.scm.web.cgi.CGIExecutor; import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.EnvList; //~--- JDK imports ------------------------------------------------------------ +import com.sun.jersey.core.util.Base64; + import java.io.File; import java.io.IOException; import java.util.Enumeration; -import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -79,19 +83,18 @@ import javax.servlet.http.HttpSession; public class HgCGIServlet extends HttpServlet { - private static final String ENV_PYTHON_HTTPS_VERIFY = "PYTHONHTTPSVERIFY"; - /** Field description */ public static final String ENV_REPOSITORY_NAME = "REPO_NAME"; /** Field description */ public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH"; - private static final String ENV_HTTP_POST_ARGS = "SCM_HTTP_POST_ARGS"; - /** Field description */ public static final String ENV_SESSION_PREFIX = "SCM_"; + /** Field description */ + private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS"; + /** Field description */ private static final long serialVersionUID = -3492811300905099810L; @@ -228,6 +231,7 @@ public class HgCGIServlet extends HttpServlet * @param env * @param session */ + @SuppressWarnings("unchecked") private void passSessionAttributes(EnvList env, HttpSession session) { Enumeration enm = session.getAttributeNames(); @@ -273,27 +277,19 @@ public class HgCGIServlet extends HttpServlet directory.getAbsolutePath()); // add hook environment - Map environment = executor.getEnvironment().asMutableMap(); - if (handler.getConfig().isDisableHookSSLValidation()) { - // disable ssl validation - // Issue 959: https://goo.gl/zH5eY8 - environment.put(ENV_PYTHON_HTTPS_VERIFY, "0"); - } - - // enable experimental httppostargs protocol of mercurial - // Issue 970: https://goo.gl/poascp - environment.put(ENV_HTTP_POST_ARGS, String.valueOf(handler.getConfig().isEnableHttpPostArgs())); - //J- HgEnvironment.prepareEnvironment( - environment, + executor.getEnvironment().asMutableMap(), handler, - hookManager, + hookManager, request ); //J+ - HttpSession session = request.getSession(); + addCredentials(executor.getEnvironment(), request); + + // unused ??? + HttpSession session = request.getSession(false); if (session != null) { diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 3803b24e00..b22ceccb90 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,63 +6,54 @@ sonia.scm scm - 1.61-SNAPSHOT + 2.0.0-SNAPSHOT sonia.scm scm-webapp war - 1.61-SNAPSHOT + 2.0.0-SNAPSHOT scm-webapp + + + + sonia.scm + scm-annotation-processor + 2.0.0-SNAPSHOT + provided + + javax.servlet - servlet-api + javax.servlet-api ${servlet.version} provided - - + + javax.transaction jta 1.1 provided - + - + sonia.scm scm-core - 1.61-SNAPSHOT + 2.0.0-SNAPSHOT - + sonia.scm scm-dao-xml - 1.61-SNAPSHOT - - - - sonia.scm.plugins - scm-hg-plugin - 1.61-SNAPSHOT - - - - sonia.scm.plugins - scm-svn-plugin - 1.61-SNAPSHOT - - - - sonia.scm.plugins - scm-git-plugin - 1.61-SNAPSHOT + 2.0.0-SNAPSHOT @@ -72,12 +63,18 @@ shiro-web ${shiro.version} - + org.apache.shiro shiro-guice ${shiro.version} + + + io.jsonwebtoken + jjwt + 0.4 + @@ -116,13 +113,13 @@ provided - + com.sun.jersey.contribs jersey-multipart ${jersey.version} - + @@ -130,73 +127,66 @@ guice-multibindings ${guice.version} - + + + + + com.github.legman.support + shiro + ${legman.version} + + ch.qos.logback logback-classic + ${logback.version} - + org.slf4j jcl-over-slf4j ${slf4j.version} - + org.slf4j log4j-over-slf4j ${slf4j.version} - - - - - net.sf.ehcache - ehcache-core - ${ehcache.version} - - - - - - xml-apis - xml-apis - 1.4.01 - - + - + commons-beanutils commons-beanutils + 1.9.2 - + commons-collections commons-collections + 3.2.1 - - - + commons-codec commons-codec 1.9 - + com.google.guava guava ${guava.version} - + org.quartz-scheduler quartz @@ -208,67 +198,25 @@ - - - + + + - org.freemarker - freemarker - ${freemarker.version} + org.apache.httpcomponents + httpclient + 4.2.6 - + + + com.github.spullara.mustache.java compiler ${mustache.version} - - - - - org.eclipse.aether - aether-api - ${aether.version} - - - - org.eclipse.aether - aether-impl - ${aether.version} - - - - org.apache.maven - maven-aether-provider - ${maven.version} - - - plexus-component-annotations - org.codehaus.plexus - - - - - - org.eclipse.aether - aether-transport-http - ${aether.version} - - - - org.eclipse.aether - aether-transport-file - ${aether.version} - - - - org.eclipse.aether - aether-connector-basic - ${aether.version} - - + - + com.webcohesion.enunciate enunciate-core-annotations @@ -280,7 +228,7 @@ sonia.scm scm-test - 1.61-SNAPSHOT + 2.0.0-SNAPSHOT test @@ -289,31 +237,7 @@ - - - sonia.scm.plugins - scm-git-plugin - 1.61-SNAPSHOT - tests - test - - - - sonia.scm.plugins - scm-hg-plugin - 1.61-SNAPSHOT - tests - test - - - - sonia.scm.plugins - scm-svn-plugin - 1.61-SNAPSHOT - tests - test - - + org.seleniumhq.selenium selenium-java @@ -327,7 +251,7 @@ ${selenium.version} test - + org.seleniumhq.selenium htmlunit-driver @@ -348,23 +272,71 @@ ${jersey.version} test - + + + + com.github.sdorra shiro-unit 1.0.0 test - + + + sonia.scm.plugins + scm-git-plugin + 2.0.0-SNAPSHOT + tests + test + + + + sonia.scm.plugins + scm-git-plugin + 2.0.0-SNAPSHOT + test + + + + sonia.scm.plugins + scm-hg-plugin + 2.0.0-SNAPSHOT + tests + test + + + + sonia.scm.plugins + scm-hg-plugin + 2.0.0-SNAPSHOT + test + + + + sonia.scm.plugins + scm-svn-plugin + 2.0.0-SNAPSHOT + tests + test + + + + sonia.scm.plugins + scm-svn-plugin + 2.0.0-SNAPSHOT + test + + - + commons-logging commons-logging 1.1.3 provided - + log4j log4j @@ -375,9 +347,8 @@ - - + com.mycila.maven-license-plugin maven-license-plugin @@ -400,7 +371,6 @@ - org.apache.maven.plugins maven-dependency-plugin @@ -418,39 +388,49 @@ - + - org.apache.maven.plugins - maven-antrun-plugin - 1.6 + sonia.scm.maven + smp-maven-plugin + 1.0.0-alpha-2 + + + + sonia.scm.plugins + scm-hg-plugin + ${project.version} + smp + + + sonia.scm.plugins + scm-svn-plugin + ${project.version} + smp + + + sonia.scm.plugins + scm-git-plugin + ${project.version} + smp + + + sonia.scm.plugins + scm-legacy-plugin + ${project.version} + smp + + + - repack compile - run + copy-core-plugins - - - - - - - - - - - - - - - - + org.apache.maven.plugins maven-war-plugin @@ -464,7 +444,7 @@ - + sonia.maven change-env @@ -484,7 +464,7 @@ - org.mortbay.jetty + org.eclipse.jetty jetty-maven-plugin ${jetty.maven.version} @@ -504,23 +484,14 @@ true - - - 8081 - 60000 - 16384 - - /scm - ${project.build.javaLevel} - ${project.build.javaLevel} - ${project.build.sourceEncoding} + ${project.basedir}/src/main/conf/jetty.xml 0 - - + + scm-webapp @@ -532,9 +503,7 @@ default 2.53.1 2.9.1 - 1.1.0 1.0 - 3.3.9 0.8.17 Tomcat e1 @@ -544,21 +513,7 @@ - - - cluster - - - - - sonia.scm - scm-dao-orientdb - 1.58-SNAPSHOT - - - - - + release @@ -639,7 +594,7 @@ - org.mortbay.jetty + org.eclipse.jetty jetty-maven-plugin ${jetty.maven.version} @@ -655,16 +610,7 @@ ${scm.stage} - - - 8081 - 60000 - 16384 - - - ${project.build.javaLevel} - ${project.build.javaLevel} - ${project.build.sourceEncoding} + ${project.basedir}/src/main/conf/jetty.xml 0 true @@ -685,29 +631,29 @@ - + - + selenium - + - + org.apache.httpcomponents httpclient 4.3.2 test - + - + - + org.apache.maven.plugins maven-failsafe-plugin @@ -732,12 +678,15 @@ - + - org.mortbay.jetty + org.eclipse.jetty jetty-maven-plugin ${jetty.maven.version} + + 8082 + 8086 STOP @@ -746,16 +695,7 @@ target/scm-it - - - 8082 - 60000 - 16384 - - - ${project.build.javaLevel} - ${project.build.javaLevel} - ${project.build.sourceEncoding} + ${project.basedir}/src/main/conf/jetty.xml 0 true @@ -776,7 +716,7 @@ - + org.codehaus.mojo selenium-maven-plugin @@ -797,22 +737,22 @@ post-integration-test stop-server - + - + - + - + doc - + - + org.apache.maven.plugins maven-resources-plugin @@ -826,7 +766,7 @@ ${project.build.directory} - + src/main/doc true @@ -834,12 +774,12 @@ **/enunciate.xml - - + + - + com.webcohesion.enunciate enunciate-maven-plugin @@ -871,7 +811,7 @@ - + org.apache.maven.plugins maven-assembly-plugin @@ -890,12 +830,12 @@ - + - + diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 1b8e0c7803..12c30fd152 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -35,15 +35,13 @@ package sonia.scm; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.collect.Maps; import com.google.inject.Provider; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import com.google.inject.servlet.RequestScoped; -import com.google.inject.servlet.ServletModule; import com.google.inject.throwingproviders.ThrowingProviderBinder; -import org.apache.shiro.authz.permission.PermissionResolver; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,11 +50,6 @@ import sonia.scm.cache.CacheManager; import sonia.scm.cache.GuavaCacheManager; import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; -import sonia.scm.filter.AdminSecurityFilter; -import sonia.scm.filter.BaseUrlFilter; -import sonia.scm.filter.GZipFilter; -import sonia.scm.filter.MDCFilter; -import sonia.scm.filter.SecurityFilter; import sonia.scm.group.DefaultGroupManager; import sonia.scm.group.GroupDAO; import sonia.scm.group.GroupManager; @@ -64,20 +57,14 @@ import sonia.scm.group.GroupManagerProvider; import sonia.scm.group.xml.XmlGroupDAO; import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.FileSystem; -import sonia.scm.net.HttpClient; -import sonia.scm.net.URLHttpClient; import sonia.scm.plugin.DefaultPluginLoader; import sonia.scm.plugin.DefaultPluginManager; -import sonia.scm.plugin.Plugin; import sonia.scm.plugin.PluginLoader; import sonia.scm.plugin.PluginManager; -import sonia.scm.repository.ChangesetViewerUtil; import sonia.scm.repository.DefaultRepositoryManager; import sonia.scm.repository.DefaultRepositoryProvider; import sonia.scm.repository.HealthCheckContextListener; -import sonia.scm.repository.LastModifiedUpdateListener; import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryBrowserUtil; import sonia.scm.repository.RepositoryDAO; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManagerProvider; @@ -92,15 +79,9 @@ import sonia.scm.resources.ResourceManager; import sonia.scm.resources.ScriptResourceServlet; 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.EncryptionHandler; import sonia.scm.security.KeyGenerator; -import sonia.scm.security.LoginAttemptHandler; -import sonia.scm.security.MessageDigestEncryptionHandler; -import sonia.scm.security.RepositoryPermissionResolver; -import sonia.scm.security.SecurityContext; import sonia.scm.security.SecuritySystem; import sonia.scm.store.BlobStoreFactory; import sonia.scm.store.ConfigurationEntryStoreFactory; @@ -108,16 +89,10 @@ import sonia.scm.store.DataStoreFactory; import sonia.scm.store.FileBlobStoreFactory; import sonia.scm.store.JAXBConfigurationEntryStoreFactory; import sonia.scm.store.JAXBDataStoreFactory; -import sonia.scm.store.JAXBStoreFactory; -import sonia.scm.store.ListenableStoreFactory; -import sonia.scm.store.StoreFactory; -import sonia.scm.template.DefaultEngine; -import sonia.scm.template.FreemarkerTemplateEngine; -import sonia.scm.template.FreemarkerTemplateHandler; +import sonia.scm.store.JAXBConfigurationStoreFactory; import sonia.scm.template.MustacheTemplateEngine; import sonia.scm.template.TemplateEngine; import sonia.scm.template.TemplateEngineFactory; -import sonia.scm.template.TemplateHandler; import sonia.scm.template.TemplateServlet; import sonia.scm.url.RestJsonUrlProvider; import sonia.scm.url.RestXmlUrlProvider; @@ -133,21 +108,16 @@ import sonia.scm.util.DebugServlet; import sonia.scm.util.ScmConfigurationUtil; import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.DefaultCGIExecutorFactory; -import sonia.scm.web.filter.AutoLoginFilter; import sonia.scm.web.filter.LoggingFilter; import sonia.scm.web.security.AdministrationContext; -import sonia.scm.web.security.ApiBasicAuthenticationFilter; -import sonia.scm.web.security.AuthenticationManager; -import sonia.scm.web.security.BasicSecurityContext; -import sonia.scm.web.security.ChainAuthenticatonManager; import sonia.scm.web.security.DefaultAdministrationContext; -import sonia.scm.web.security.WebSecurityContext; //~--- JDK imports ------------------------------------------------------------ import com.sun.jersey.api.core.PackagesResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.api.json.JSONConfiguration; +import com.sun.jersey.guice.JerseyServletModule; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import com.sun.jersey.spi.container.servlet.ServletContainer; @@ -157,6 +127,10 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; + +import javax.servlet.ServletContext; +import sonia.scm.store.ConfigurationStoreFactory; + import javax.net.ssl.SSLContext; import sonia.scm.net.SSLContextProvider; import sonia.scm.net.ahc.AdvancedHttpClient; @@ -166,15 +140,16 @@ import sonia.scm.net.ahc.JsonContentTransformer; import sonia.scm.net.ahc.XmlContentTransformer; import sonia.scm.schedule.QuartzScheduler; import sonia.scm.schedule.Scheduler; +import sonia.scm.security.ConfigurableLoginAttemptHandler; +import sonia.scm.security.LoginAttemptHandler; import sonia.scm.security.AuthorizationChangedEventProducer; -import sonia.scm.security.XsrfProtectionFilter; import sonia.scm.web.UserAgentParser; /** * * @author Sebastian Sdorra */ -public class ScmServletModule extends ServletModule +public class ScmServletModule extends JerseyServletModule { /** Field description */ @@ -239,11 +214,15 @@ public class ScmServletModule extends ServletModule * Constructs ... * * + * + * @param servletContext * @param pluginLoader * @param overrides */ - ScmServletModule(DefaultPluginLoader pluginLoader, ClassOverrides overrides) + ScmServletModule(ServletContext servletContext, + DefaultPluginLoader pluginLoader, ClassOverrides overrides) { + this.servletContext = servletContext; this.pluginLoader = pluginLoader; this.overrides = overrides; } @@ -263,22 +242,24 @@ public class ScmServletModule extends ServletModule bind(SCMContextProvider.class).toInstance(context); - ScmConfiguration config = getScmConfiguration(context); + ScmConfiguration config = getScmConfiguration(); CipherUtil cu = CipherUtil.getInstance(); - + // bind repository provider ThrowingProviderBinder.create(binder()).bind( RepositoryProvider.class, Repository.class).to( DefaultRepositoryProvider.class).in(RequestScoped.class); + // bind servlet context + bind(ServletContext.class).annotatedWith(Default.class).toInstance( + servletContext); + // bind event api bind(ScmEventBus.class).toInstance(ScmEventBus.getInstance()); // bind core - bind(StoreFactory.class, JAXBStoreFactory.class); - bind(ListenableStoreFactory.class, JAXBStoreFactory.class); - bind(ConfigurationEntryStoreFactory.class, - JAXBConfigurationEntryStoreFactory.class); + bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class); + bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class); bind(DataStoreFactory.class, JAXBDataStoreFactory.class); bind(BlobStoreFactory.class, FileBlobStoreFactory.class); bind(ScmConfiguration.class).toInstance(config); @@ -291,24 +272,20 @@ public class ScmServletModule extends ServletModule // note CipherUtil uses an other generator bind(KeyGenerator.class).to(DefaultKeyGenerator.class); bind(CipherHandler.class).toInstance(cu.getCipherHandler()); - bind(EncryptionHandler.class, MessageDigestEncryptionHandler.class); bind(FileSystem.class, DefaultFileSystem.class); // bind health check stuff bind(HealthCheckContextListener.class); // bind extensions - pluginLoader.processExtensions(binder()); + pluginLoader.getExtensionProcessor().processAutoBindExtensions(binder()); // bind security stuff + bind(LoginAttemptHandler.class).to(ConfigurableLoginAttemptHandler.class); bind(AuthorizationChangedEventProducer.class); - bind(PermissionResolver.class, RepositoryPermissionResolver.class); - bind(AuthenticationManager.class, ChainAuthenticatonManager.class); - bind(SecurityContext.class).to(BasicSecurityContext.class); - bind(WebSecurityContext.class).to(BasicSecurityContext.class); + bind(SecuritySystem.class).to(DefaultSecuritySystem.class); bind(AdministrationContext.class, DefaultAdministrationContext.class); - bind(LoginAttemptHandler.class, ConfigurableLoginAttemptHandler.class); // bind cache bind(CacheManager.class, GuavaCacheManager.class); @@ -326,14 +303,10 @@ public class ScmServletModule extends ServletModule bindDecorated(GroupManager.class, DefaultGroupManager.class, GroupManagerProvider.class); bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class); - bind(ChangesetViewerUtil.class); - bind(RepositoryBrowserUtil.class); // bind sslcontext provider bind(SSLContext.class).toProvider(SSLContextProvider.class); - // bind httpclient - bind(HttpClient.class, URLHttpClient.class); // bind ahc Multibinder transformers = @@ -378,24 +351,7 @@ public class ScmServletModule extends ServletModule { filter(PATTERN_ALL).through(LoggingFilter.class); } - - // protect api agains xsrf attacks - filter(PATTERN_RESTAPI).through(XsrfProtectionFilter.class); - /* - * filter(PATTERN_PAGE, - * PATTERN_STATIC_RESOURCES).through(StaticResourceFilter.class); - */ - filter(PATTERN_ALL).through(BaseUrlFilter.class); - filter(PATTERN_ALL).through(AutoLoginFilter.class); - filterRegex(RESOURCE_REGEX).through(GZipFilter.class); - filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(ApiBasicAuthenticationFilter.class); - filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(SecurityFilter.class); - filter(PATTERN_CONFIG, PATTERN_ADMIN).through(AdminSecurityFilter.class); - - // added mdcs for logging - filter(PATTERN_ALL).through(MDCFilter.class); - // debug servlet serve(PATTERN_DEBUG).with(DebugServlet.class); @@ -403,23 +359,21 @@ public class ScmServletModule extends ServletModule serve(PATTERN_PLUGIN_SCRIPT).with(ScriptResourceServlet.class); // template - bind(TemplateHandler.class).to(FreemarkerTemplateHandler.class); serve(PATTERN_INDEX, "/").with(TemplateServlet.class); Multibinder engineBinder = Multibinder.newSetBinder(binder(), TemplateEngine.class); engineBinder.addBinding().to(MustacheTemplateEngine.class); - engineBinder.addBinding().to(FreemarkerTemplateEngine.class); - bind(TemplateEngine.class).annotatedWith(DefaultEngine.class).to( + bind(TemplateEngine.class).annotatedWith(Default.class).to( MustacheTemplateEngine.class); bind(TemplateEngineFactory.class); // bind events - bind(LastModifiedUpdateListener.class); + // bind(LastModifiedUpdateListener.class); // jersey - Map params = new HashMap(); + Map params = Maps.newHashMap(); /* * params.put("com.sun.jersey.spi.container.ContainerRequestFilters", @@ -432,63 +386,17 @@ public class ScmServletModule extends ServletModule params.put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_REDIRECT, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_DISABLE_WADL, Boolean.TRUE.toString()); + + /* + * TODO remove UriExtensionsConfig and PackagesResourceConfig + * to stop jersey classpath scanning + */ params.put(ServletContainer.RESOURCE_CONFIG_CLASS, UriExtensionsConfig.class.getName()); - - String restPath = getRestPackages(); - logger.info("configure jersey with package path: {}", restPath); - - params.put(PackagesResourceConfig.PROPERTY_PACKAGES, restPath); + params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "unbound"); serve(PATTERN_RESTAPI).with(GuiceContainer.class, params); } - /** - * Method description - * - * - * @param packageSet - * @param plugin - */ - private void appendPluginPackages(Set packageSet, Plugin plugin) - { - Set pluginPackageSet = plugin.getPackageSet(); - - if (pluginPackageSet != null) - { - for (String pluginPkg : pluginPackageSet) - { - boolean append = true; - - for (String pkg : packageSet) - { - if (pluginPkg.startsWith(pkg)) - { - append = false; - - break; - } - } - - if (append) - { - if (logger.isDebugEnabled()) - { - String name = "unknown"; - - if (plugin.getInformation() != null) - { - name = plugin.getInformation().getName(); - } - - logger.debug("plugin {} added rest path {}", name, pluginPkg); - } - - packageSet.add(pluginPkg); - } - } - } - } - /** * Method description * @@ -576,44 +484,6 @@ public class ScmServletModule extends ServletModule //~--- get methods ---------------------------------------------------------- - /** - * Method description - * - * - * @return - */ - private String getRestPackages() - { - Set packageSet = new HashSet(); - - packageSet.add(SCMContext.DEFAULT_PACKAGE); - - Collection plugins = pluginLoader.getInstalledPlugins(); - - if (plugins != null) - { - for (Plugin plugin : plugins) - { - appendPluginPackages(packageSet, plugin); - } - } - - StringBuilder buffer = new StringBuilder(); - Iterator pkgIterator = packageSet.iterator(); - - while (pkgIterator.hasNext()) - { - buffer.append(pkgIterator.next()); - - if (pkgIterator.hasNext()) - { - buffer.append(";"); - } - } - - return buffer.toString(); - } - /** * Load ScmConfiguration with JAXB * @@ -622,7 +492,7 @@ public class ScmServletModule extends ServletModule * * @return */ - private ScmConfiguration getScmConfiguration(SCMContextProvider context) + private ScmConfiguration getScmConfiguration() { ScmConfiguration configuration = new ScmConfiguration(); @@ -634,8 +504,11 @@ public class ScmServletModule extends ServletModule //~--- fields --------------------------------------------------------------- /** Field description */ - private ClassOverrides overrides; + private final ClassOverrides overrides; /** Field description */ - private DefaultPluginLoader pluginLoader; + private final DefaultPluginLoader pluginLoader; + + /** Field description */ + private final ServletContext servletContext; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java b/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java index 4a089ab150..b36cf6c7e7 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java @@ -42,65 +42,50 @@ import sonia.scm.template.TemplateEngineFactory; //~--- JDK imports ------------------------------------------------------------ -import com.sun.jersey.api.view.Viewable; -import com.sun.jersey.spi.template.ViewProcessor; - import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; +import sonia.scm.template.Viewable; /** * * @author Sebastian Sdorra */ @Provider -public class TemplateEngineViewable implements ViewProcessor +public class TemplateEngineViewable implements MessageBodyWriter { + + private final TemplateEngineFactory templateEngineFactory; - /** - * Constructs ... - * - * - * @param templateEngineFactory - */ @Inject public TemplateEngineViewable(TemplateEngineFactory templateEngineFactory) { this.templateEngineFactory = templateEngineFactory; } - //~--- methods -------------------------------------------------------------- - /** - * Method description - * - * - * @param name - * - * @return - */ @Override - public String resolve(String name) - { - return name; + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.isAssignableFrom(Viewable.class); } - /** - * Method description - * - * - * @param path - * @param viewable - * @param out - * - * @throws IOException - */ @Override - public void writeTo(String path, Viewable viewable, OutputStream out) - throws IOException - { + public long getSize(Viewable viewable, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return -1; + } + + @Override + public void writeTo(Viewable viewable, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + String path = viewable.getPath(); + TemplateEngine engine = templateEngineFactory.getEngineByExtension(path); if (engine == null) @@ -115,14 +100,9 @@ public class TemplateEngineViewable implements ViewProcessor throw new IOException("could not find template for ".concat(path)); } - PrintWriter writer = new PrintWriter(out); + PrintWriter writer = new PrintWriter(entityStream); - template.execute(writer, viewable.getModel()); + template.execute(writer, viewable.getContext()); writer.flush(); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private TemplateEngineFactory templateEngineFactory; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java index e9e63d16d8..040eb6b2dc 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java @@ -133,7 +133,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response add(@Context UriInfo uriInfo, Permission permission) { AssignedPermission ap = transformPermission(permission); @@ -185,7 +185,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response update(@PathParam("id") String id, Permission permission) { StoredAssignedPermission sap = getPermission(id); @@ -213,7 +213,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 404, condition = "not found, no permission with the specified id available"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Permission get(@PathParam("id") String id) { StoredAssignedPermission sap = getPermission(id); @@ -231,7 +231,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 204, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public List getAll() { return getPermissions(getPredicate()); diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java index 52b8b02c37..87626c7045 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java @@ -118,7 +118,7 @@ public class ChangePasswordResource @ResponseCode(code = 400, condition = "bad request, the old password is not correct"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response changePassword(@FormParam("old-password") String oldPassword, @FormParam("new-password") String newPassword) throws UserException, IOException diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java index 2fb6bdda3d..a9beea7679 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java @@ -89,7 +89,7 @@ public class ConfigurationResource * @return */ @GET - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response getConfiguration() { Response response = null; @@ -118,7 +118,7 @@ public class ConfigurationResource * @return */ @POST - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response setConfig(@Context UriInfo uriInfo, ScmConfiguration newConfig) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java index 808aaa498b..dd61f0aecb 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java @@ -119,7 +119,7 @@ public class GroupResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Override public Response create(@Context UriInfo uriInfo, Group group) { @@ -164,7 +164,7 @@ public class GroupResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Override public Response update(@Context UriInfo uriInfo, @PathParam("id") String name, Group group) @@ -191,7 +191,7 @@ public class GroupResource @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Override public Response get(@Context Request request, @PathParam("id") String id) { @@ -221,7 +221,7 @@ public class GroupResource * @return */ @GET - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @TypeHint(Group[].class) @StatusCodes({ @ResponseCode(code = 200, condition = "success"), diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java index 54c9369a57..fda978b3fe 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java @@ -52,7 +52,6 @@ import sonia.scm.plugin.PluginInformationComparator; //~--- JDK imports ------------------------------------------------------------ -import com.sun.jersey.multipart.FormDataParam; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.TypeHint; @@ -66,6 +65,7 @@ import java.util.Iterator; import java.util.List; import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -124,9 +124,9 @@ public class PluginResource @ResponseCode(code = 500, condition = "internal server error") }) @Consumes(MediaType.MULTIPART_FORM_DATA) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response install( - @FormDataParam("package") InputStream uploadedInputStream) + /*@FormParam("package")*/ InputStream uploadedInputStream) throws IOException { Response response = null; @@ -194,7 +194,7 @@ public class PluginResource @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.TEXT_HTML) public Response installFromUI( - @FormDataParam("package") InputStream uploadedInputStream) + /*@FormParam("package")*/ InputStream uploadedInputStream) throws IOException { return install(uploadedInputStream); @@ -257,7 +257,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Collection getAll() { return pluginManager.getAll(); @@ -274,7 +274,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Collection getAvailable() { return pluginManager.getAvailable(); @@ -291,7 +291,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Collection getAvailableUpdates() { return pluginManager.getAvailableUpdates(); @@ -325,7 +325,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Collection getOverview() { //J- diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java index 9382f58c5c..9c01e3d4a8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java @@ -69,8 +69,6 @@ import static com.google.common.base.Preconditions.*; //~--- JDK imports ------------------------------------------------------------ -import com.sun.jersey.api.client.ClientResponse.Status; -import com.sun.jersey.multipart.FormDataParam; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.ResponseHeader; import com.webcohesion.enunciate.metadata.rs.StatusCodes; @@ -89,6 +87,7 @@ import java.util.Set; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; +import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -111,7 +110,7 @@ import javax.xml.bind.annotation.XmlRootElement; * * @author Sebastian Sdorra */ -@Path("import/repositories") +// @Path("import/repositories") public class RepositoryImportResource { @@ -170,8 +169,8 @@ public class RepositoryImportResource @TypeHint(TypeHint.NO_CONTENT.class) @Consumes(MediaType.MULTIPART_FORM_DATA) public Response importFromBundle(@Context UriInfo uriInfo, - @PathParam("type") String type, @FormDataParam("name") String name, - @FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed") + @PathParam("type") String type, @FormParam("name") String name, + @FormParam("bundle") InputStream inputStream, @QueryParam("compressed") @DefaultValue("false") boolean compressed) { Repository repository = doImportFromBundle(type, name, inputStream, @@ -211,8 +210,8 @@ public class RepositoryImportResource @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.TEXT_HTML) public Response importFromBundleUI(@PathParam("type") String type, - @FormDataParam("name") String name, - @FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed") + @FormParam("name") String name, + @FormParam("bundle") InputStream inputStream, @QueryParam("compressed") @DefaultValue("false") boolean compressed) { Response response; @@ -260,7 +259,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response importFromUrl(@Context UriInfo uriInfo, @PathParam("type") String type, UrlImportRequest request) { @@ -320,7 +319,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(Repository[].class) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response importRepositories(@PathParam("type") String type) { SecurityUtils.getSubject().checkRole(Role.ADMIN); @@ -352,7 +351,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(Repository[].class) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response importRepositories() { SecurityUtils.getSubject().checkRole(Role.ADMIN); @@ -394,7 +393,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(ImportResult.class) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response importRepositoriesFromDirectory( @PathParam("type") String type) { @@ -435,7 +434,7 @@ public class RepositoryImportResource .warn( "import feature is not supported by repository handler for type " .concat(type), ex); - response = Response.status(Status.BAD_REQUEST).build(); + response = Response.status(Response.Status.BAD_REQUEST).build(); } catch (IOException ex) { @@ -451,7 +450,7 @@ public class RepositoryImportResource else { logger.warn("could not find reposiotry handler for type {}", type); - response = Response.status(Status.BAD_REQUEST).build(); + response = Response.status(Response.Status.BAD_REQUEST).build(); } return response; @@ -475,7 +474,7 @@ public class RepositoryImportResource ), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response getImportableTypes() { SecurityUtils.getSubject().checkRole(Role.ADMIN); diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java index 16168aefc7..e9f7812ee0 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java @@ -166,7 +166,7 @@ public class RepositoryResource extends AbstractManagerResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Override public Response create(@Context UriInfo uriInfo, User user) { @@ -170,7 +170,7 @@ public class UserResource extends AbstractManagerResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Override public Response update(@Context UriInfo uriInfo, @PathParam("id") String name, User user) @@ -197,7 +197,7 @@ public class UserResource extends AbstractManagerResource @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Override public Response get(@Context Request request, @PathParam("id") String id) { @@ -233,7 +233,7 @@ public class UserResource extends AbstractManagerResource @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Override public Response getAll(@Context Request request, @DefaultValue("0") @QueryParam("start") int start, @DefaultValue("-1") diff --git a/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java b/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java index f65e0c7708..0933242b49 100644 --- a/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java +++ b/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java @@ -67,7 +67,7 @@ public final class DebugResource * @return all received hook data for the given repository */ @GET - @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Collection getAll(@PathParam("repository") String repository){ return debugService.getAll(repository); } @@ -81,7 +81,7 @@ public final class DebugResource */ @GET @Path("last") - @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public DebugHookData getLast(@PathParam("repository") String repository){ return debugService.getLast(repository); } diff --git a/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java b/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java index 5e61ed6965..2998f82890 100644 --- a/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java +++ b/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java @@ -33,13 +33,15 @@ package sonia.scm.net.ahc; //~--- non-JDK imports -------------------------------------------------------- -import com.google.common.io.ByteSource; +import com.fasterxml.jackson.databind.AnnotationIntrospector; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; +import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; -import org.codehaus.jackson.map.AnnotationIntrospector; -import org.codehaus.jackson.map.DeserializationConfig; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector; -import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; +import com.google.common.io.ByteSource; import sonia.scm.plugin.ext.Extension; import sonia.scm.util.IOUtil; @@ -73,12 +75,12 @@ public class JsonContentTransformer implements ContentTransformer // allow jackson and jaxb annotations AnnotationIntrospector jackson = new JacksonAnnotationIntrospector(); - AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector(); + AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); - this.mapper.setAnnotationIntrospector(new AnnotationIntrospector.Pair(jackson, jaxb)); + this.mapper.setAnnotationIntrospector(new AnnotationIntrospectorPair(jackson, jaxb)); // do not fail on unknown json properties - this.mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); + this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } //~--- methods -------------------------------------------------------------- diff --git a/scm-webapp/src/main/resources/logback.default.xml b/scm-webapp/src/main/resources/logback.default.xml index 318cd6112a..bf18f02893 100644 --- a/scm-webapp/src/main/resources/logback.default.xml +++ b/scm-webapp/src/main/resources/logback.default.xml @@ -90,6 +90,8 @@ + + diff --git a/scm-webapp/src/main/webapp/WEB-INF/web.xml b/scm-webapp/src/main/webapp/WEB-INF/web.xml index 513c708e80..8a54ee72cd 100644 --- a/scm-webapp/src/main/webapp/WEB-INF/web.xml +++ b/scm-webapp/src/main/webapp/WEB-INF/web.xml @@ -40,7 +40,7 @@ SCM-Manager ${project.version} - sonia.scm.boot.BootstrapListener + sonia.scm.boot.BootstrapContextListener @@ -48,15 +48,45 @@ - guiceFilter - sonia.scm.boot.BootstrapFilter + BootstrapFilter + sonia.scm.boot.BootstrapContextFilter - guiceFilter + BootstrapFilter /* + + + + resteasy.servlet.mapping.prefix + /api/rest + + + + Resteasy + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + + + Resteasy + /api/rest/* + + + + + + + sonia.scm.HttpSessionListenerHolder + + + + index.html diff --git a/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js b/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js index b1c0a5372f..3d044d69c5 100644 --- a/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js +++ b/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js @@ -55,7 +55,7 @@ Sonia.action.ChangePasswordWindow = Ext.extend(Ext.Window,{ title: this.titleText, items: [{ id: 'changePasswordForm', - url: restUrl + 'action/change-password.json', + url: restUrl + 'action/change-password', frame: true, xtype: 'form', monitorValid: true, diff --git a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js index a985688a3e..0f9c2fdd57 100644 --- a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js @@ -261,7 +261,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ onSubmit: function(values){ this.el.mask(this.submitText); Ext.Ajax.request({ - url: restUrl + 'config.json', + url: restUrl + 'config', method: 'POST', jsonData: values, scope: this, @@ -283,7 +283,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ onLoad: function(el){ var tid = setTimeout( function(){ el.mask(this.loadingText); }, 100); Ext.Ajax.request({ - url: restUrl + 'config.json', + url: restUrl + 'config', method: 'GET', scope: this, disableCaching: true, diff --git a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js index 5d560d9717..4ec278bf6b 100644 --- a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js @@ -59,7 +59,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ // this.updateMembers(group); this.fireEvent('preUpdate', group); - var url = restUrl + 'groups/' + encodeURIComponent(group.name) + '.json'; + var url = restUrl + 'groups/' + encodeURIComponent(group.name); var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); @@ -96,7 +96,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ } item.type = state.defaultUserType; - var url = restUrl + 'groups.json'; + var url = restUrl + 'groups'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); diff --git a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js index 18d3841fc2..1bc3fbe819 100644 --- a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js @@ -95,7 +95,7 @@ Sonia.group.Panel = Ext.extend(Sonia.rest.Panel, { var selected = grid.getSelectionModel().getSelected(); if ( selected ){ var item = selected.data; - var url = restUrl + 'groups/' + encodeURIComponent(item.name) + '.json'; + var url = restUrl + 'groups/' + encodeURIComponent(item.name); Ext.MessageBox.show({ title: this.removeTitleText, diff --git a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js index b27f2484b4..19ad6d0e15 100644 --- a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js +++ b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js @@ -41,7 +41,6 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ failedDescriptionText: 'Incorrect username, password or not enough permission. Please Try again.', accountLockedText: 'Account is locked.', accountTemporaryLockedText: 'Account is temporary locked. Please try again later.', - rememberMeText: 'Remember me', initComponent: function(){ var buttons = []; @@ -94,11 +93,14 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ scope: this } } - },{ - xtype: 'checkbox', - fieldLabel: this.rememberMeText, - name: 'rememberMe', - inputValue: 'true' + }, { + name: 'grant_type', + value: 'password', + xtype: 'hidden' + }, { + name: 'cookie', + value: 'true', + xtype: 'hidden' }], buttons: buttons }; @@ -116,6 +118,7 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ authenticate: function(){ var form = this.getForm(); + form.submit({ scope: this, method: 'POST', diff --git a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js index 11113e2601..ebd2119886 100644 --- a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js +++ b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js @@ -81,7 +81,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, { var loadingBox = this.createLoadingBox( this.installWaitMsgText ); Ext.Ajax.request({ - url: restUrl + 'plugins/install/' + pluginId + '.json', + url: restUrl + 'plugins/install/' + pluginId, method: 'POST', scope: this, timeout: 300000, // 5min @@ -116,7 +116,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, { var loadingBox = this.createLoadingBox( this.uninstallWaitMsgText ); Ext.Ajax.request({ - url: restUrl + 'plugins/uninstall/' + pluginId + '.json', + url: restUrl + 'plugins/uninstall/' + pluginId, method: 'POST', scope: this, success: function(){ @@ -150,7 +150,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, { var loadingBox = this.createLoadingBox( this.updateWaitMsgText ); Ext.Ajax.request({ - url: restUrl + 'plugins/update/' + pluginId + '.json', + url: restUrl + 'plugins/update/' + pluginId, method: 'POST', scope: this, timeout: 300000, // 5min diff --git a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js index cb5ea6bec1..5f44e51ebc 100644 --- a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js @@ -81,7 +81,7 @@ Sonia.plugin.Grid = Ext.extend(Sonia.rest.Grid, { var pluginStore = new Ext.data.GroupingStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'plugins/overview.json', + url: restUrl + 'plugins/overview', disableCaching: false }), reader: new Ext.data.JsonReader({ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js index cddcad4552..4c3dcbc7c8 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js @@ -38,7 +38,7 @@ Sonia.repository.BranchComboBox = Ext.extend(Ext.form.ComboBox, { initComponent: function(){ var branchStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories/' + this.repositoryId + '/branches.json', + url: restUrl + 'repositories/' + this.repositoryId + '/branches', method: 'GET', disableCaching: false }), diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js index aa18d29e0d..468b99dbec 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js @@ -46,7 +46,7 @@ Sonia.repository.ChangesetViewerPanel = Ext.extend(Ext.Panel, { initComponent: function(){ if (! this.url){ - this.url = restUrl + 'repositories/' + this.repository.id + '/changesets.json'; + this.url = restUrl + 'repositories/' + this.repository.id + '/changesets'; } if ( ! this.startLimit ){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js index 7b72c4fca3..591d77d43f 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js @@ -131,7 +131,7 @@ Sonia.repository.CommitPanel = Ext.extend(Ext.Panel, { } Ext.Ajax.request({ - url: restUrl + 'repositories/' + this.repository.id + '/changeset/' + this.revision + '.json', + url: restUrl + 'repositories/' + this.repository.id + '/changeset/' + this.revision, method: 'GET', scope: this, success: function(response){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js index 66482399ac..422a81ce6b 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js @@ -73,7 +73,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ if ( debug ){ console.debug( 'update repository: ' + item.name ); } - var url = restUrl + 'repositories/' + item.id + '.json'; + var url = restUrl + 'repositories/' + item.id; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); @@ -124,7 +124,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ if ( debug ){ console.debug( 'create repository: ' + item.name ); } - var url = restUrl + 'repositories.json'; + var url = restUrl + 'repositories'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js index fb66b91a5a..9e2f76f607 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js @@ -71,7 +71,7 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, { var repositoryStore = new Ext.data.GroupingStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories.json', + url: restUrl + 'repositories', disableCaching: false }), idProperty: 'id', diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js index 195d7d7509..076f73e712 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js @@ -75,7 +75,7 @@ Sonia.repository.HealthCheckFailure = Ext.extend(Ext.Panel, { }, rerunHealthChecks: function(){ - var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck.json'; + var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js index 209b554e82..ac6bbc2206 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js @@ -514,7 +514,7 @@ Sonia.repository.ImportPanel = Ext.extend(Ext.Panel, { importFromUrl: function(layout, repository){ var lbox = this.showLoadingBox(); Ext.Ajax.request({ - url: restUrl + 'import/repositories/' + this.repositoryType + '/url.json', + url: restUrl + 'import/repositories/' + this.repositoryType + '/url', method: 'POST', scope: this, timeout: 300000, // 5min @@ -533,7 +533,7 @@ Sonia.repository.ImportPanel = Ext.extend(Ext.Panel, { importFromDirectory: function(layout){ var lbox = this.showLoadingBox(); Ext.Ajax.request({ - url: restUrl + 'import/repositories/' + this.repositoryType + '/directory.json', + url: restUrl + 'import/repositories/' + this.repositoryType + '/directory', timeout: 300000, // 5min method: 'POST', scope: this, diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js index 7e10a58f4e..e978c0ffe9 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js @@ -181,7 +181,7 @@ Sonia.repository.get = function(id, callback){ execCallback(repository); } else { Ext.Ajax.request({ - url: restUrl + 'repositories/' + id + '.json', + url: restUrl + 'repositories/' + id, method: 'GET', scope: this, success: function(response){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js index 17a301509a..767c294242 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js @@ -311,7 +311,7 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, { console.debug('toggle repository ' + item.name + ' archive to ' + item.archived); } - var url = restUrl + 'repositories/' + item.id + '.json'; + var url = restUrl + 'repositories/' + item.id; this.executeRemoteCall(title, String.format(msg, item.name), 'PUT', url, item, function(result){ main.handleFailure( @@ -331,7 +331,7 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, { console.debug( 'remove repository ' + item.name ); } - var url = restUrl + 'repositories/' + item.id + '.json'; + var url = restUrl + 'repositories/' + item.id; this.executeRemoteCall(this.removeTitleText, String.format(this.removeMsgText, item.name), 'DELETE', url, null, function(result){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js index 489dd3c06c..59677cab7e 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js @@ -58,7 +58,7 @@ Sonia.repository.RepositoryBrowser = Ext.extend(Ext.grid.GridPanel, { var browserStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories/' + this.repository.id + '/browse.json', + url: restUrl + 'repositories/' + this.repository.id, method: 'GET' }), fields: ['path', 'name', 'length', 'lastModified', 'directory', 'description', 'subrepository'], diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js index 3f045a8cf6..5af3cc97f1 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js @@ -37,7 +37,7 @@ Sonia.repository.TagComboBox = Ext.extend(Ext.form.ComboBox, { initComponent: function(){ var tagStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories/' + this.repositoryId + '/tags.json', + url: restUrl + 'repositories/' + this.repositoryId + '/tags', method: 'GET', disableCaching: false }), diff --git a/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js b/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js index 5ea8855251..676114fc78 100644 --- a/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js +++ b/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js @@ -53,7 +53,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { this.permissionStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ api: { - read: restUrl + this.baseUrl + '.json' + read: restUrl + this.baseUrl }, disableCaching: false }), @@ -179,7 +179,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { addPermission: function(record){ Ext.Ajax.request({ - url: restUrl + this.baseUrl + '.json', + url: restUrl + this.baseUrl, method: 'POST', jsonData: record.data, scope: this, @@ -194,7 +194,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { modifyPermission: function(id, record){ Ext.Ajax.request({ - url: restUrl + this.baseUrl + '/' + encodeURIComponent(id) + '.json', + url: restUrl + this.baseUrl + '/' + encodeURIComponent(id), method: 'PUT', jsonData: record.data, scope: this, @@ -207,7 +207,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { removePermission: function(store, record){ Ext.Ajax.request({ - url: restUrl + this.baseUrl + '/' + encodeURIComponent(record.get('id')) + '.json', + url: restUrl + this.baseUrl + '/' + encodeURIComponent(record.get('id')), method: 'DELETE', scope: this, success: function(){ diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.global.js b/scm-webapp/src/main/webapp/resources/js/sonia.global.js index a43feb824b..98299546b1 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.global.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.global.js @@ -83,7 +83,7 @@ var userSearchStore = new Ext.data.JsonStore({ idProperty: 'value', fields: ['value','label'], proxy: new Ext.data.HttpProxy({ - url: restUrl + 'search/users.json', + url: restUrl + 'search/users', method: 'GET' }) }); @@ -93,7 +93,7 @@ var groupSearchStore = new Ext.data.JsonStore({ idProperty: 'value', fields: ['value','label'], proxy: new Ext.data.HttpProxy({ - url: restUrl + 'search/groups.json', + url: restUrl + 'search/groups', method: 'GET' }) }); diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js index 6d7e6a3257..db92a77d60 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js @@ -689,4 +689,4 @@ Ext.onReady(function(){ main.init(); main.checkLogin(); -}); \ No newline at end of file +}); diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js index 6ef00e73d7..e8a03e5966 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js @@ -129,7 +129,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ console.debug( 'update user: ' + item.name ); } this.fixRequest(item); - var url = restUrl + 'users/' + encodeURIComponent(item.name) + '.json'; + var url = restUrl + 'users/' + encodeURIComponent(item.name); Ext.Ajax.request({ url: url, jsonData: item, @@ -159,7 +159,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ this.fixRequest(user); // set user type user.type = state.defaultUserType; - var url = restUrl + 'users.json'; + var url = restUrl + 'users'; Ext.Ajax.request({ url: url, jsonData: user, diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js index c44d336ba9..b671e67bdc 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js @@ -49,7 +49,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, { var userStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'users.json', + url: restUrl + 'users', disableCaching: false }), idProperty: 'name', diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js index 8e98c645df..0ca0fd78e1 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js @@ -126,7 +126,7 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, { var selected = grid.getSelectionModel().getSelected(); if ( selected ){ var item = selected.data; - var url = restUrl + 'users/' + encodeURIComponent(item.name) + '.json'; + var url = restUrl + 'users/' + encodeURIComponent(item.name); Ext.MessageBox.show({ title: this.removeTitleText, diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index f8adb90ff1..33e020f85d 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -32,6 +32,9 @@ package sonia.scm.it; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; import com.google.common.base.Charsets; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.UniformInterfaceException; @@ -41,8 +44,6 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import org.apache.shiro.crypto.hash.Sha256Hash; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Test; @@ -81,7 +82,7 @@ public class GitLfsITCase { private Repository repository; public GitLfsITCase() { - mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector()); + mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(TypeFactory.defaultInstance())); } // lifecycle methods From 8111eae65a16181dc5b22d82a3def3c48b58a88b Mon Sep 17 00:00:00 2001 From: broDom Date: Tue, 25 Jul 2017 09:21:01 +0200 Subject: [PATCH 070/178] build: update shiro (1.4-rc2 -> 1.4) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b0997dcd3d..4af61a0b2b 100644 --- a/pom.xml +++ b/pom.xml @@ -495,7 +495,7 @@ 1.0.0-SNAPSHOT - 1.4.0-RC2 + 1.4.0 v4.5.2.201704071617-r-scm1 From d007f665f095a607ee1e3186037a9ebd0d0a7292 Mon Sep 17 00:00:00 2001 From: broDom Date: Tue, 25 Jul 2017 09:38:42 +0200 Subject: [PATCH 071/178] build(core): add missing commons-logging --- scm-core/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 5dfba770e6..6e07756295 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -40,6 +40,12 @@ org.slf4j ${slf4j.version} + + + commons-logging + commons-logging + 1.2 + From 7b044ede3aeea34c500b3b61aa59329f486dd391 Mon Sep 17 00:00:00 2001 From: broDom Date: Tue, 25 Jul 2017 09:40:26 +0200 Subject: [PATCH 072/178] build(webapp): update jackson (2.8.6 -> .9) --- scm-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 7d0e0fc8c9..8f577818a1 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -527,7 +527,7 @@ 1.0 0.8.17 3.1.3.Final - 2.8.6 + 2.8.9 Tomcat e1 javascript:S3827 From 5799f368fd94964ae4fe53c6f25beaab56aa11fe Mon Sep 17 00:00:00 2001 From: broDom Date: Tue, 25 Jul 2017 09:40:49 +0200 Subject: [PATCH 073/178] build(webapp): update resteasy (3.1.3 -> .4) --- scm-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 8f577818a1..e5cb99481a 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -526,7 +526,7 @@ 2.9.1 1.0 0.8.17 - 3.1.3.Final + 3.1.4.Final 2.8.9 Tomcat e1 From e598d6fe4e6df60400edac875b71813c5f7e2b85 Mon Sep 17 00:00:00 2001 From: broDom Date: Tue, 25 Jul 2017 09:43:49 +0200 Subject: [PATCH 074/178] build(server): update jetty --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4af61a0b2b..ecf138a4b4 100644 --- a/pom.xml +++ b/pom.xml @@ -490,8 +490,8 @@ 1.2.0 - 9.2.10.v20150310 - 9.2.10.v20150310 + 9.4.6.v20170531 + 9.4.6.v20170531 1.0.0-SNAPSHOT From 08a7f8f11d31d0d0c2ed59dcdb188ac5dae6c847 Mon Sep 17 00:00:00 2001 From: broDom Date: Tue, 25 Jul 2017 09:44:08 +0200 Subject: [PATCH 075/178] build(server): remove invalid config element --- scm-server/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 64172d6673..7400d6b05e 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -64,7 +64,6 @@ ${exploded.directory} lib flat - true From a051eb159cfa6495c806001fa758dfb3ab58f4de Mon Sep 17 00:00:00 2001 From: Matt Harbison Date: Fri, 22 Jun 2018 16:06:35 -0400 Subject: [PATCH 076/178] #989 load global configuration in hgweb on Mercurial 4.1 and later --- .../src/main/resources/sonia/scm/python/hgweb.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py index e2e7d8e931..7f99a85585 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/hgweb.py @@ -36,7 +36,11 @@ from mercurial.hgweb import hgweb, wsgicgi demandimport.enable() -u = uimod.ui() +try: + u = uimod.ui.load() +except AttributeError: + # For installations earlier than Mercurial 4.1 + u = uimod.ui() # pass SCM_HTTP_POST_ARGS to enable experimental httppostargs protocol of mercurial # SCM_HTTP_POST_ARGS is set by HgCGIServlet From 2d103b7f958939cc912f9bcc55dae47cda7c1492 Mon Sep 17 00:00:00 2001 From: Matt Harbison Date: Fri, 22 Jun 2018 16:33:52 -0400 Subject: [PATCH 077/178] optionally print tracebacks when the Mercurial hook swallows an exception If `ui.traceback=True` is set on the server, this prints the stacktrace for the exception on the client side. Otherwise, nothing happens. I tried allowing the exception to propagate back to Mercurial, but then the client sees this message with 4.4.2 and 4.6.1: abort: remote error: Mercurial/Python process ends with return code 1 Something odd changed when upgrading from CentOS 7.4 to 7.5 around forwarding requests from the loopback address that I don't fully understand. First, we were getting a ValueError from inside `opener.open()` saying that 'localhost' didn't match the host listed in the SSL certificate. That wasn't visible until adding this. Then what happened is a connection refused out of the same function, so the traceback is added to the other handler too. Running the equivalent command on the command line from the 'vcs' host stopped working in 7.5: $ curl https://vcs.domain.com/hook/hg/?ping=true curl: (7) Failed connect to vcs.domain.com:443; Connection refused But it works when run on another machine targeting that same 'vcs' host. Adding another firewall rule allows everything to work from the 'vcs' host again: $ iptables -t nat -I OUTPUT -p tcp -o lo --dport 443 -j REDIRECT --to-ports 8443 --- .../src/main/resources/sonia/scm/python/scmhooks.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py index e9a58d589f..73b5bfe083 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py @@ -78,8 +78,10 @@ def callHookUrl(ui, repo, hooktype, node): printMessages(ui, msg.splitlines(True)) else: ui.warn( "ERROR: scm-hook failed with an unknown error\n" ) + ui.traceback() except ValueError: ui.warn( "scm-hook failed with an exception\n" ) + ui.traceback() return abort def callback(ui, repo, hooktype, node=None, source=None, pending=None, **kwargs): From 405dd672754ddd80ca9a7972eb9460aaf1fb67cf Mon Sep 17 00:00:00 2001 From: Matt Harbison Date: Fri, 22 Jun 2018 16:42:05 -0400 Subject: [PATCH 078/178] ensure each message line printed in the Mercurial hook gets a trailing newline I noticed that the exception printed in the previous commit started on the same line as the print for the `str(e)` case right before it. Since this also prints the content of urllib2.URLError.read(), it seems better to remove any existing newline and re-add it, than to just assume the `str(e)` case was the only problem. --- .../src/main/resources/sonia/scm/python/scmhooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py index 73b5bfe083..d4999cf2fd 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/python/scmhooks.py @@ -46,7 +46,7 @@ def printMessages(ui, msgs): for line in msgs: if line.startswith("_e") or line.startswith("_n"): line = line[2:]; - ui.warn(line); + ui.warn('%s\n' % line.rstrip()) def callHookUrl(ui, repo, hooktype, node): abort = True From 83d6ab8e9cb49d40801abf023b63bce1c9aa7e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 25 Jun 2018 11:52:36 +0200 Subject: [PATCH 079/178] Backed out changeset 5d23ff274a2f --- pom.xml | 355 +++++++------- scm-clients/scm-client-impl/pom.xml | 4 +- scm-core/pom.xml | 6 +- .../scm/security/DefaultCipherHandler.java | 7 +- .../main/java/sonia/scm/web/HgCGIServlet.java | 34 +- scm-webapp/pom.xml | 436 ++++++++++-------- .../main/java/sonia/scm/ScmServletModule.java | 209 +++++++-- .../scm/api/rest/TemplateEngineViewable.java | 64 ++- .../scm/api/rest/UriExtensionsConfig.java | 110 +++-- .../resources/AbstractPermissionResource.java | 8 +- .../resources/ChangePasswordResource.java | 2 +- .../rest/resources/ConfigurationResource.java | 4 +- .../scm/api/rest/resources/GroupResource.java | 8 +- .../api/rest/resources/PluginResource.java | 16 +- .../resources/RepositoryImportResource.java | 27 +- .../rest/resources/RepositoryResource.java | 22 +- .../resources/RepositoryRootResource.java | 21 +- .../api/rest/resources/SearchResource.java | 4 +- .../scm/api/rest/resources/UserResource.java | 8 +- .../java/sonia/scm/debug/DebugResource.java | 4 +- .../scm/net/ahc/JsonContentTransformer.java | 20 +- .../src/main/resources/logback.default.xml | 2 - scm-webapp/src/main/webapp/WEB-INF/web.xml | 38 +- .../sonia.action.changepasswordwindow.js | 2 +- .../js/config/sonia.config.scmconfigpanel.js | 4 +- .../js/group/sonia.group.formpanel.js | 4 +- .../resources/js/group/sonia.group.panel.js | 2 +- .../resources/js/login/sonia.login.form.js | 15 +- .../js/plugin/sonia.plugin.center.js | 6 +- .../resources/js/plugin/sonia.plugin.grid.js | 2 +- .../sonia.repository.branchcombobox.js | 2 +- .../sonia.repository.changesetviewerpanel.js | 2 +- .../sonia.repository.commitpanel.js | 2 +- .../repository/sonia.repository.formpanel.js | 4 +- .../js/repository/sonia.repository.grid.js | 2 +- .../sonia.repository.healthcheckfailure.js | 2 +- .../sonia.repository.importwindow.js | 4 +- .../js/repository/sonia.repository.js | 2 +- .../js/repository/sonia.repository.panel.js | 4 +- .../sonia.repository.repositorybrowser.js | 2 +- .../sonia.repository.tagcombobox.js | 2 +- .../sonia.security.permissionspanel.js | 8 +- .../main/webapp/resources/js/sonia.global.js | 4 +- .../src/main/webapp/resources/js/sonia.scm.js | 2 +- .../resources/js/user/sonia.user.formpanel.js | 4 +- .../resources/js/user/sonia.user.grid.js | 2 +- .../resources/js/user/sonia.user.panel.js | 2 +- .../test/java/sonia/scm/it/GitLfsITCase.java | 7 +- 48 files changed, 878 insertions(+), 623 deletions(-) rename scm-core/src/main/java/sonia/scm/template/Viewable.java => scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java (52%) diff --git a/pom.xml b/pom.xml index 3674300b1d..840c9f1ec3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 2.0.0-SNAPSHOT + 1.61-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories over http. @@ -59,20 +59,18 @@ https://scm-manager.ci.cloudbees.com/ - - 3.1.0 - - - scm-annotations - scm-annotation-processor scm-core scm-test + maven scm-plugins + scm-samples scm-dao-xml scm-webapp scm-server + scm-plugin-backend scm-clients + support @@ -82,15 +80,6 @@ scm-manager release repository http://maven.scm-manager.org/nexus/content/groups/public - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - true - daily - - @@ -139,52 +128,20 @@ ${mokito.version} test - + - - - org.apache.maven.plugins - maven-enforcer-plugin - 1.4.1 - - - enforce-java - compile - - enforce - - - - - - [1.8.0-101,) - - - - [3.1,) - - - true - - - - org.codehaus.mojo animal-sniffer-maven-plugin - 1.15 + 1.16 org.codehaus.mojo.signature - java18 + java17 1.0 @@ -198,23 +155,51 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M1 + + + enforce-java + compile + + enforce + + + + + 1.7 + + + module-info + + + + true + + + + + + org.codehaus.mojo + extra-enforcer-rules + 1.0-beta-7 + + + + org.apache.maven.plugins maven-compiler-plugin - 3.5.1 + 3.0 - true - true ${project.build.javaLevel} ${project.build.javaLevel} - ${project.test.javaLevel} - ${project.test.javaLevel} ${project.build.sourceEncoding} - - -Xlint:unchecked,-options @@ -259,7 +244,7 @@ true true - http://download.oracle.com/javase/8/docs/api/ + http://download.oracle.com/javase/7/docs/api/ http://download.oracle.com/docs/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/ http://jersey.java.net/nonav/apidocs/${jersey.version}/jersey/ https://google.github.io/guice/api-docs/${guice.version}/javadoc @@ -316,81 +301,59 @@ maven-eclipse-plugin 2.6 - - - - - org.jacoco - jacoco-maven-plugin - 0.7.7.201606060606 - - - - prepare-agent - - - - report - prepare-package - - report - - - - - + org.apache.maven.plugins maven-site-plugin - 3.2 - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.4 - - - - org.apache.maven.plugins - maven-jxr-plugin - 2.3 - - - - org.codehaus.mojo - findbugs-maven-plugin - 2.4.0 - - - - org.apache.maven.plugins - maven-surefire-report-plugin - 2.12 - - - - org.apache.maven.plugins - maven-pmd-plugin - 2.7.1 - - true - ${project.build.sourceEncoding} - ${project.build.javaLevel} - - - - - + 3.7 + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.4 + + + + org.apache.maven.plugins + maven-jxr-plugin + 2.3 + + + + org.codehaus.mojo + findbugs-maven-plugin + 2.4.0 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.12 + + + + org.apache.maven.plugins + maven-pmd-plugin + 2.7.1 + + ${project.build.sourceEncoding} + ${project.build.javaLevel} + + + + + + @@ -434,18 +397,9 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.8.1 + 3.0.0 - org.jboss.apiviz.APIviz - - org.jboss.apiviz - apiviz - 1.3.2.GA - - - -sourceclasspath ${project.build.outputDirectory} - -nopackagediagram - + false @@ -456,6 +410,101 @@ + + + + + + + commons-beanutils + commons-beanutils + 1.9.3 + + + + commons-collections + commons-collections + 3.2.2 + + + + + + org.apache.httpcomponents + httpclient + 4.5.5 + + + + + + slf4j-api + org.slf4j + ${slf4j.version} + + + + ch.qos.logback + logback-classic + ${logback.version} + + + + + + + org.codehaus.jackson + jackson-core-asl + ${jackson.version} + + + + org.codehaus.jackson + jackson-mapper-asl + ${jackson.version} + + + + org.codehaus.jackson + jackson-jaxrs + ${jackson.version} + + + + org.codehaus.jackson + jackson-xc + ${jackson.version} + + + + + + javax.xml.bind + jaxb-api + ${jaxb.version} + + + + com.sun.xml.bind + jaxb-impl + ${jaxb.version} + + + + org.glassfish.jaxb + jaxb-runtime + ${jaxb.version} + + + + javax.activation + activation + 1.1.1 + + + + + @@ -479,37 +528,31 @@ 4.12 - 1.7.22 + 1.7.25 1.2.3 - 3.0.1 - 2.0.1 - 4.0 + 2.5 + 3.0 1.19.4 - - - 1.2.0 - 2.6.6 2.3.20 - - - 9.2.10.v20150310 - 9.2.10.v20150310 + 7.6.21.v20160908 + 7.6.16.v20140903 + 1.9.13 + 2.3.0 - 1.0.0-SNAPSHOT - 1.4.0-RC2 + 1.3.2 - - v4.5.2.201704071617-r-scm1 - 1.8.15-scm1 + + v4.5.3.201708160445-r-scm1 + 1.9.0-scm3 - 16.0.1 + 15.0 2.2.3 - 1.8 + 1.7 UTF-8 SCM-BSD diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml index 1e6847349f..ba6edb9130 100644 --- a/scm-clients/scm-client-impl/pom.xml +++ b/scm-clients/scm-client-impl/pom.xml @@ -42,13 +42,13 @@ com.sun.jersey jersey-client - ${jersey-client.version} + ${jersey.version} com.sun.jersey.contribs jersey-multipart - ${jersey-client.version} + ${jersey.version} diff --git a/scm-core/pom.xml b/scm-core/pom.xml index fde7dceb47..ae0057dbdf 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -69,9 +69,9 @@ - javax.ws.rs - javax.ws.rs-api - ${jaxrs.version} + com.sun.jersey + jersey-core + ${jersey.version} diff --git a/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java b/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java index b4f0d81cd3..ddb8a699a7 100644 --- a/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java +++ b/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java @@ -45,6 +45,8 @@ import sonia.scm.util.IOUtil; //~--- JDK imports ------------------------------------------------------------ +import com.sun.jersey.core.util.Base64; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -58,7 +60,6 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; -import java.util.Base64; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; @@ -164,7 +165,7 @@ public class DefaultCipherHandler implements CipherHandler { String result = null; try { - byte[] encodedInput = Base64.getDecoder().decode(value); + byte[] encodedInput = Base64.decode(value); byte[] salt = new byte[SALT_LENGTH]; byte[] encoded = new byte[encodedInput.length - SALT_LENGTH]; @@ -221,7 +222,7 @@ public class DefaultCipherHandler implements CipherHandler { System.arraycopy(salt, 0, result, 0, SALT_LENGTH); System.arraycopy(encodedInput, 0, result, SALT_LENGTH, result.length - SALT_LENGTH); - res = new String(Base64.getEncoder().encode(result), ENCODING); + res = new String(Base64.encode(result), ENCODING); } catch (IOException | GeneralSecurityException ex) { throw new CipherException("could not encode string", ex); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 0befcf6f11..1fb78161e0 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -36,7 +36,6 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.Stopwatch; -import com.google.common.base.Strings; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -53,21 +52,18 @@ import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; -import sonia.scm.security.CipherUtil; import sonia.scm.util.AssertUtil; -import sonia.scm.util.HttpUtil; import sonia.scm.web.cgi.CGIExecutor; import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.EnvList; //~--- JDK imports ------------------------------------------------------------ -import com.sun.jersey.core.util.Base64; - import java.io.File; import java.io.IOException; import java.util.Enumeration; +import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -83,17 +79,18 @@ import javax.servlet.http.HttpSession; public class HgCGIServlet extends HttpServlet { + private static final String ENV_PYTHON_HTTPS_VERIFY = "PYTHONHTTPSVERIFY"; + /** 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 */ - public static final String ENV_SESSION_PREFIX = "SCM_"; + private static final String ENV_HTTP_POST_ARGS = "SCM_HTTP_POST_ARGS"; /** Field description */ - private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS"; + public static final String ENV_SESSION_PREFIX = "SCM_"; /** Field description */ private static final long serialVersionUID = -3492811300905099810L; @@ -231,7 +228,6 @@ public class HgCGIServlet extends HttpServlet * @param env * @param session */ - @SuppressWarnings("unchecked") private void passSessionAttributes(EnvList env, HttpSession session) { Enumeration enm = session.getAttributeNames(); @@ -277,19 +273,27 @@ public class HgCGIServlet extends HttpServlet directory.getAbsolutePath()); // add hook environment + Map environment = executor.getEnvironment().asMutableMap(); + if (handler.getConfig().isDisableHookSSLValidation()) { + // disable ssl validation + // Issue 959: https://goo.gl/zH5eY8 + environment.put(ENV_PYTHON_HTTPS_VERIFY, "0"); + } + + // enable experimental httppostargs protocol of mercurial + // Issue 970: https://goo.gl/poascp + environment.put(ENV_HTTP_POST_ARGS, String.valueOf(handler.getConfig().isEnableHttpPostArgs())); + //J- HgEnvironment.prepareEnvironment( - executor.getEnvironment().asMutableMap(), + environment, handler, - hookManager, + hookManager, request ); //J+ - addCredentials(executor.getEnvironment(), request); - - // unused ??? - HttpSession session = request.getSession(false); + HttpSession session = request.getSession(); if (session != null) { diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index b22ceccb90..3803b24e00 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -6,54 +6,63 @@ sonia.scm scm - 2.0.0-SNAPSHOT + 1.61-SNAPSHOT sonia.scm scm-webapp war - 2.0.0-SNAPSHOT + 1.61-SNAPSHOT scm-webapp - - - - sonia.scm - scm-annotation-processor - 2.0.0-SNAPSHOT - provided - - javax.servlet - javax.servlet-api + servlet-api ${servlet.version} provided - - + + javax.transaction jta 1.1 provided - + - + sonia.scm scm-core - 2.0.0-SNAPSHOT + 1.61-SNAPSHOT - + sonia.scm scm-dao-xml - 2.0.0-SNAPSHOT + 1.61-SNAPSHOT + + + + sonia.scm.plugins + scm-hg-plugin + 1.61-SNAPSHOT + + + + sonia.scm.plugins + scm-svn-plugin + 1.61-SNAPSHOT + + + + sonia.scm.plugins + scm-git-plugin + 1.61-SNAPSHOT @@ -63,18 +72,12 @@ shiro-web ${shiro.version} - + org.apache.shiro shiro-guice ${shiro.version} - - - io.jsonwebtoken - jjwt - 0.4 - @@ -113,13 +116,13 @@ provided - + com.sun.jersey.contribs jersey-multipart ${jersey.version} - + @@ -127,66 +130,73 @@ guice-multibindings ${guice.version} - - - - - com.github.legman.support - shiro - ${legman.version} - - + ch.qos.logback logback-classic - ${logback.version} - + org.slf4j jcl-over-slf4j ${slf4j.version} - + org.slf4j log4j-over-slf4j ${slf4j.version} - + + + + + net.sf.ehcache + ehcache-core + ${ehcache.version} + + + + + + xml-apis + xml-apis + 1.4.01 + + - + commons-beanutils commons-beanutils - 1.9.2 - + commons-collections commons-collections - 3.2.1 - - - + commons-codec commons-codec 1.9 - + com.google.guava guava ${guava.version} - + org.quartz-scheduler quartz @@ -198,25 +208,67 @@ - - - - - org.apache.httpcomponents - httpclient - 4.2.6 - - + - + + + org.freemarker + freemarker + ${freemarker.version} + + com.github.spullara.mustache.java compiler ${mustache.version} - + + + + + org.eclipse.aether + aether-api + ${aether.version} + + + + org.eclipse.aether + aether-impl + ${aether.version} + + + + org.apache.maven + maven-aether-provider + ${maven.version} + + + plexus-component-annotations + org.codehaus.plexus + + + + + + org.eclipse.aether + aether-transport-http + ${aether.version} + + + + org.eclipse.aether + aether-transport-file + ${aether.version} + + + + org.eclipse.aether + aether-connector-basic + ${aether.version} + + - + com.webcohesion.enunciate enunciate-core-annotations @@ -228,7 +280,7 @@ sonia.scm scm-test - 2.0.0-SNAPSHOT + 1.61-SNAPSHOT test @@ -237,7 +289,31 @@ - + + + sonia.scm.plugins + scm-git-plugin + 1.61-SNAPSHOT + tests + test + + + + sonia.scm.plugins + scm-hg-plugin + 1.61-SNAPSHOT + tests + test + + + + sonia.scm.plugins + scm-svn-plugin + 1.61-SNAPSHOT + tests + test + + org.seleniumhq.selenium selenium-java @@ -251,7 +327,7 @@ ${selenium.version} test - + org.seleniumhq.selenium htmlunit-driver @@ -272,71 +348,23 @@ ${jersey.version} test - - - - + com.github.sdorra shiro-unit 1.0.0 test - - - sonia.scm.plugins - scm-git-plugin - 2.0.0-SNAPSHOT - tests - test - - - - sonia.scm.plugins - scm-git-plugin - 2.0.0-SNAPSHOT - test - - - - sonia.scm.plugins - scm-hg-plugin - 2.0.0-SNAPSHOT - tests - test - - - - sonia.scm.plugins - scm-hg-plugin - 2.0.0-SNAPSHOT - test - - - - sonia.scm.plugins - scm-svn-plugin - 2.0.0-SNAPSHOT - tests - test - - - - sonia.scm.plugins - scm-svn-plugin - 2.0.0-SNAPSHOT - test - - + - + commons-logging commons-logging 1.1.3 provided - + log4j log4j @@ -347,8 +375,9 @@ + - + com.mycila.maven-license-plugin maven-license-plugin @@ -371,6 +400,7 @@ + org.apache.maven.plugins maven-dependency-plugin @@ -388,49 +418,39 @@ - + - sonia.scm.maven - smp-maven-plugin - 1.0.0-alpha-2 - - - - sonia.scm.plugins - scm-hg-plugin - ${project.version} - smp - - - sonia.scm.plugins - scm-svn-plugin - ${project.version} - smp - - - sonia.scm.plugins - scm-git-plugin - ${project.version} - smp - - - sonia.scm.plugins - scm-legacy-plugin - ${project.version} - smp - - - + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + repack compile - copy-core-plugins + run + + + + + + + + + + + + + + + - + org.apache.maven.plugins maven-war-plugin @@ -444,7 +464,7 @@ - + sonia.maven change-env @@ -464,7 +484,7 @@ - org.eclipse.jetty + org.mortbay.jetty jetty-maven-plugin ${jetty.maven.version} @@ -484,14 +504,23 @@ true + + + 8081 + 60000 + 16384 + + /scm - ${project.basedir}/src/main/conf/jetty.xml + ${project.build.javaLevel} + ${project.build.javaLevel} + ${project.build.sourceEncoding} 0 - - + + scm-webapp @@ -503,7 +532,9 @@ default 2.53.1 2.9.1 + 1.1.0 1.0 + 3.3.9 0.8.17 Tomcat e1 @@ -513,7 +544,21 @@ - + + + cluster + + + + + sonia.scm + scm-dao-orientdb + 1.58-SNAPSHOT + + + + + release @@ -594,7 +639,7 @@ - org.eclipse.jetty + org.mortbay.jetty jetty-maven-plugin ${jetty.maven.version} @@ -610,7 +655,16 @@ ${scm.stage} - ${project.basedir}/src/main/conf/jetty.xml + + + 8081 + 60000 + 16384 + + + ${project.build.javaLevel} + ${project.build.javaLevel} + ${project.build.sourceEncoding} 0 true @@ -631,29 +685,29 @@ - + - + selenium - + - + org.apache.httpcomponents httpclient 4.3.2 test - + - + - + org.apache.maven.plugins maven-failsafe-plugin @@ -678,15 +732,12 @@ - + - org.eclipse.jetty + org.mortbay.jetty jetty-maven-plugin ${jetty.maven.version} - - 8082 - 8086 STOP @@ -695,7 +746,16 @@ target/scm-it - ${project.basedir}/src/main/conf/jetty.xml + + + 8082 + 60000 + 16384 + + + ${project.build.javaLevel} + ${project.build.javaLevel} + ${project.build.sourceEncoding} 0 true @@ -716,7 +776,7 @@ - + org.codehaus.mojo selenium-maven-plugin @@ -737,22 +797,22 @@ post-integration-test stop-server - + - + - + - + doc - + - + org.apache.maven.plugins maven-resources-plugin @@ -766,7 +826,7 @@ ${project.build.directory} - + src/main/doc true @@ -774,12 +834,12 @@ **/enunciate.xml - - + + - + com.webcohesion.enunciate enunciate-maven-plugin @@ -811,7 +871,7 @@ - + org.apache.maven.plugins maven-assembly-plugin @@ -830,12 +890,12 @@ - + - + diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 12c30fd152..1b8e0c7803 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -35,13 +35,15 @@ package sonia.scm; //~--- non-JDK imports -------------------------------------------------------- -import com.google.common.collect.Maps; import com.google.inject.Provider; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import com.google.inject.servlet.RequestScoped; +import com.google.inject.servlet.ServletModule; import com.google.inject.throwingproviders.ThrowingProviderBinder; +import org.apache.shiro.authz.permission.PermissionResolver; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,6 +52,11 @@ import sonia.scm.cache.CacheManager; import sonia.scm.cache.GuavaCacheManager; import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; +import sonia.scm.filter.AdminSecurityFilter; +import sonia.scm.filter.BaseUrlFilter; +import sonia.scm.filter.GZipFilter; +import sonia.scm.filter.MDCFilter; +import sonia.scm.filter.SecurityFilter; import sonia.scm.group.DefaultGroupManager; import sonia.scm.group.GroupDAO; import sonia.scm.group.GroupManager; @@ -57,14 +64,20 @@ import sonia.scm.group.GroupManagerProvider; import sonia.scm.group.xml.XmlGroupDAO; import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.FileSystem; +import sonia.scm.net.HttpClient; +import sonia.scm.net.URLHttpClient; import sonia.scm.plugin.DefaultPluginLoader; import sonia.scm.plugin.DefaultPluginManager; +import sonia.scm.plugin.Plugin; import sonia.scm.plugin.PluginLoader; import sonia.scm.plugin.PluginManager; +import sonia.scm.repository.ChangesetViewerUtil; import sonia.scm.repository.DefaultRepositoryManager; import sonia.scm.repository.DefaultRepositoryProvider; import sonia.scm.repository.HealthCheckContextListener; +import sonia.scm.repository.LastModifiedUpdateListener; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryBrowserUtil; import sonia.scm.repository.RepositoryDAO; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManagerProvider; @@ -79,9 +92,15 @@ import sonia.scm.resources.ResourceManager; import sonia.scm.resources.ScriptResourceServlet; 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.EncryptionHandler; import sonia.scm.security.KeyGenerator; +import sonia.scm.security.LoginAttemptHandler; +import sonia.scm.security.MessageDigestEncryptionHandler; +import sonia.scm.security.RepositoryPermissionResolver; +import sonia.scm.security.SecurityContext; import sonia.scm.security.SecuritySystem; import sonia.scm.store.BlobStoreFactory; import sonia.scm.store.ConfigurationEntryStoreFactory; @@ -89,10 +108,16 @@ import sonia.scm.store.DataStoreFactory; import sonia.scm.store.FileBlobStoreFactory; import sonia.scm.store.JAXBConfigurationEntryStoreFactory; import sonia.scm.store.JAXBDataStoreFactory; -import sonia.scm.store.JAXBConfigurationStoreFactory; +import sonia.scm.store.JAXBStoreFactory; +import sonia.scm.store.ListenableStoreFactory; +import sonia.scm.store.StoreFactory; +import sonia.scm.template.DefaultEngine; +import sonia.scm.template.FreemarkerTemplateEngine; +import sonia.scm.template.FreemarkerTemplateHandler; import sonia.scm.template.MustacheTemplateEngine; import sonia.scm.template.TemplateEngine; import sonia.scm.template.TemplateEngineFactory; +import sonia.scm.template.TemplateHandler; import sonia.scm.template.TemplateServlet; import sonia.scm.url.RestJsonUrlProvider; import sonia.scm.url.RestXmlUrlProvider; @@ -108,16 +133,21 @@ import sonia.scm.util.DebugServlet; import sonia.scm.util.ScmConfigurationUtil; import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.DefaultCGIExecutorFactory; +import sonia.scm.web.filter.AutoLoginFilter; import sonia.scm.web.filter.LoggingFilter; import sonia.scm.web.security.AdministrationContext; +import sonia.scm.web.security.ApiBasicAuthenticationFilter; +import sonia.scm.web.security.AuthenticationManager; +import sonia.scm.web.security.BasicSecurityContext; +import sonia.scm.web.security.ChainAuthenticatonManager; import sonia.scm.web.security.DefaultAdministrationContext; +import sonia.scm.web.security.WebSecurityContext; //~--- JDK imports ------------------------------------------------------------ import com.sun.jersey.api.core.PackagesResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.api.json.JSONConfiguration; -import com.sun.jersey.guice.JerseyServletModule; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import com.sun.jersey.spi.container.servlet.ServletContainer; @@ -127,10 +157,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; - -import javax.servlet.ServletContext; -import sonia.scm.store.ConfigurationStoreFactory; - import javax.net.ssl.SSLContext; import sonia.scm.net.SSLContextProvider; import sonia.scm.net.ahc.AdvancedHttpClient; @@ -140,16 +166,15 @@ import sonia.scm.net.ahc.JsonContentTransformer; import sonia.scm.net.ahc.XmlContentTransformer; import sonia.scm.schedule.QuartzScheduler; import sonia.scm.schedule.Scheduler; -import sonia.scm.security.ConfigurableLoginAttemptHandler; -import sonia.scm.security.LoginAttemptHandler; import sonia.scm.security.AuthorizationChangedEventProducer; +import sonia.scm.security.XsrfProtectionFilter; import sonia.scm.web.UserAgentParser; /** * * @author Sebastian Sdorra */ -public class ScmServletModule extends JerseyServletModule +public class ScmServletModule extends ServletModule { /** Field description */ @@ -214,15 +239,11 @@ public class ScmServletModule extends JerseyServletModule * Constructs ... * * - * - * @param servletContext * @param pluginLoader * @param overrides */ - ScmServletModule(ServletContext servletContext, - DefaultPluginLoader pluginLoader, ClassOverrides overrides) + ScmServletModule(DefaultPluginLoader pluginLoader, ClassOverrides overrides) { - this.servletContext = servletContext; this.pluginLoader = pluginLoader; this.overrides = overrides; } @@ -242,24 +263,22 @@ public class ScmServletModule extends JerseyServletModule bind(SCMContextProvider.class).toInstance(context); - ScmConfiguration config = getScmConfiguration(); + ScmConfiguration config = getScmConfiguration(context); CipherUtil cu = CipherUtil.getInstance(); - + // bind repository provider ThrowingProviderBinder.create(binder()).bind( RepositoryProvider.class, Repository.class).to( DefaultRepositoryProvider.class).in(RequestScoped.class); - // bind servlet context - bind(ServletContext.class).annotatedWith(Default.class).toInstance( - servletContext); - // bind event api bind(ScmEventBus.class).toInstance(ScmEventBus.getInstance()); // bind core - bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class); - bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class); + bind(StoreFactory.class, JAXBStoreFactory.class); + bind(ListenableStoreFactory.class, JAXBStoreFactory.class); + bind(ConfigurationEntryStoreFactory.class, + JAXBConfigurationEntryStoreFactory.class); bind(DataStoreFactory.class, JAXBDataStoreFactory.class); bind(BlobStoreFactory.class, FileBlobStoreFactory.class); bind(ScmConfiguration.class).toInstance(config); @@ -272,20 +291,24 @@ public class ScmServletModule extends JerseyServletModule // note CipherUtil uses an other generator bind(KeyGenerator.class).to(DefaultKeyGenerator.class); bind(CipherHandler.class).toInstance(cu.getCipherHandler()); + bind(EncryptionHandler.class, MessageDigestEncryptionHandler.class); bind(FileSystem.class, DefaultFileSystem.class); // bind health check stuff bind(HealthCheckContextListener.class); // bind extensions - pluginLoader.getExtensionProcessor().processAutoBindExtensions(binder()); + pluginLoader.processExtensions(binder()); // bind security stuff - bind(LoginAttemptHandler.class).to(ConfigurableLoginAttemptHandler.class); bind(AuthorizationChangedEventProducer.class); - + bind(PermissionResolver.class, RepositoryPermissionResolver.class); + bind(AuthenticationManager.class, ChainAuthenticatonManager.class); + bind(SecurityContext.class).to(BasicSecurityContext.class); + bind(WebSecurityContext.class).to(BasicSecurityContext.class); bind(SecuritySystem.class).to(DefaultSecuritySystem.class); bind(AdministrationContext.class, DefaultAdministrationContext.class); + bind(LoginAttemptHandler.class, ConfigurableLoginAttemptHandler.class); // bind cache bind(CacheManager.class, GuavaCacheManager.class); @@ -303,10 +326,14 @@ public class ScmServletModule extends JerseyServletModule bindDecorated(GroupManager.class, DefaultGroupManager.class, GroupManagerProvider.class); bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class); + bind(ChangesetViewerUtil.class); + bind(RepositoryBrowserUtil.class); // bind sslcontext provider bind(SSLContext.class).toProvider(SSLContextProvider.class); + // bind httpclient + bind(HttpClient.class, URLHttpClient.class); // bind ahc Multibinder transformers = @@ -351,7 +378,24 @@ public class ScmServletModule extends JerseyServletModule { filter(PATTERN_ALL).through(LoggingFilter.class); } + + // protect api agains xsrf attacks + filter(PATTERN_RESTAPI).through(XsrfProtectionFilter.class); + /* + * filter(PATTERN_PAGE, + * PATTERN_STATIC_RESOURCES).through(StaticResourceFilter.class); + */ + filter(PATTERN_ALL).through(BaseUrlFilter.class); + filter(PATTERN_ALL).through(AutoLoginFilter.class); + filterRegex(RESOURCE_REGEX).through(GZipFilter.class); + filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(ApiBasicAuthenticationFilter.class); + filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(SecurityFilter.class); + filter(PATTERN_CONFIG, PATTERN_ADMIN).through(AdminSecurityFilter.class); + + // added mdcs for logging + filter(PATTERN_ALL).through(MDCFilter.class); + // debug servlet serve(PATTERN_DEBUG).with(DebugServlet.class); @@ -359,21 +403,23 @@ public class ScmServletModule extends JerseyServletModule serve(PATTERN_PLUGIN_SCRIPT).with(ScriptResourceServlet.class); // template + bind(TemplateHandler.class).to(FreemarkerTemplateHandler.class); serve(PATTERN_INDEX, "/").with(TemplateServlet.class); Multibinder engineBinder = Multibinder.newSetBinder(binder(), TemplateEngine.class); engineBinder.addBinding().to(MustacheTemplateEngine.class); - bind(TemplateEngine.class).annotatedWith(Default.class).to( + engineBinder.addBinding().to(FreemarkerTemplateEngine.class); + bind(TemplateEngine.class).annotatedWith(DefaultEngine.class).to( MustacheTemplateEngine.class); bind(TemplateEngineFactory.class); // bind events - // bind(LastModifiedUpdateListener.class); + bind(LastModifiedUpdateListener.class); // jersey - Map params = Maps.newHashMap(); + Map params = new HashMap(); /* * params.put("com.sun.jersey.spi.container.ContainerRequestFilters", @@ -386,17 +432,63 @@ public class ScmServletModule extends JerseyServletModule params.put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_REDIRECT, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_DISABLE_WADL, Boolean.TRUE.toString()); - - /* - * TODO remove UriExtensionsConfig and PackagesResourceConfig - * to stop jersey classpath scanning - */ params.put(ServletContainer.RESOURCE_CONFIG_CLASS, UriExtensionsConfig.class.getName()); - params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "unbound"); + + String restPath = getRestPackages(); + logger.info("configure jersey with package path: {}", restPath); + + params.put(PackagesResourceConfig.PROPERTY_PACKAGES, restPath); serve(PATTERN_RESTAPI).with(GuiceContainer.class, params); } + /** + * Method description + * + * + * @param packageSet + * @param plugin + */ + private void appendPluginPackages(Set packageSet, Plugin plugin) + { + Set pluginPackageSet = plugin.getPackageSet(); + + if (pluginPackageSet != null) + { + for (String pluginPkg : pluginPackageSet) + { + boolean append = true; + + for (String pkg : packageSet) + { + if (pluginPkg.startsWith(pkg)) + { + append = false; + + break; + } + } + + if (append) + { + if (logger.isDebugEnabled()) + { + String name = "unknown"; + + if (plugin.getInformation() != null) + { + name = plugin.getInformation().getName(); + } + + logger.debug("plugin {} added rest path {}", name, pluginPkg); + } + + packageSet.add(pluginPkg); + } + } + } + } + /** * Method description * @@ -484,6 +576,44 @@ public class ScmServletModule extends JerseyServletModule //~--- get methods ---------------------------------------------------------- + /** + * Method description + * + * + * @return + */ + private String getRestPackages() + { + Set packageSet = new HashSet(); + + packageSet.add(SCMContext.DEFAULT_PACKAGE); + + Collection plugins = pluginLoader.getInstalledPlugins(); + + if (plugins != null) + { + for (Plugin plugin : plugins) + { + appendPluginPackages(packageSet, plugin); + } + } + + StringBuilder buffer = new StringBuilder(); + Iterator pkgIterator = packageSet.iterator(); + + while (pkgIterator.hasNext()) + { + buffer.append(pkgIterator.next()); + + if (pkgIterator.hasNext()) + { + buffer.append(";"); + } + } + + return buffer.toString(); + } + /** * Load ScmConfiguration with JAXB * @@ -492,7 +622,7 @@ public class ScmServletModule extends JerseyServletModule * * @return */ - private ScmConfiguration getScmConfiguration() + private ScmConfiguration getScmConfiguration(SCMContextProvider context) { ScmConfiguration configuration = new ScmConfiguration(); @@ -504,11 +634,8 @@ public class ScmServletModule extends JerseyServletModule //~--- fields --------------------------------------------------------------- /** Field description */ - private final ClassOverrides overrides; + private ClassOverrides overrides; /** Field description */ - private final DefaultPluginLoader pluginLoader; - - /** Field description */ - private final ServletContext servletContext; + private DefaultPluginLoader pluginLoader; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java b/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java index b36cf6c7e7..4a089ab150 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/TemplateEngineViewable.java @@ -42,50 +42,65 @@ import sonia.scm.template.TemplateEngineFactory; //~--- JDK imports ------------------------------------------------------------ +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.spi.template.ViewProcessor; + import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; -import sonia.scm.template.Viewable; /** * * @author Sebastian Sdorra */ @Provider -public class TemplateEngineViewable implements MessageBodyWriter +public class TemplateEngineViewable implements ViewProcessor { - - private final TemplateEngineFactory templateEngineFactory; + /** + * Constructs ... + * + * + * @param templateEngineFactory + */ @Inject public TemplateEngineViewable(TemplateEngineFactory templateEngineFactory) { this.templateEngineFactory = templateEngineFactory; } + //~--- methods -------------------------------------------------------------- + /** + * Method description + * + * + * @param name + * + * @return + */ @Override - public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return type.isAssignableFrom(Viewable.class); + public String resolve(String name) + { + return name; } + /** + * Method description + * + * + * @param path + * @param viewable + * @param out + * + * @throws IOException + */ @Override - public long getSize(Viewable viewable, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return -1; - } - - @Override - public void writeTo(Viewable viewable, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { - String path = viewable.getPath(); - + public void writeTo(String path, Viewable viewable, OutputStream out) + throws IOException + { TemplateEngine engine = templateEngineFactory.getEngineByExtension(path); if (engine == null) @@ -100,9 +115,14 @@ public class TemplateEngineViewable implements MessageBodyWriter throw new IOException("could not find template for ".concat(path)); } - PrintWriter writer = new PrintWriter(entityStream); + PrintWriter writer = new PrintWriter(out); - template.execute(writer, viewable.getContext()); + template.execute(writer, viewable.getModel()); writer.flush(); } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private TemplateEngineFactory templateEngineFactory; } diff --git a/scm-core/src/main/java/sonia/scm/template/Viewable.java b/scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java similarity index 52% rename from scm-core/src/main/java/sonia/scm/template/Viewable.java rename to scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java index 8344d2820e..637866ad61 100644 --- a/scm-core/src/main/java/sonia/scm/template/Viewable.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/UriExtensionsConfig.java @@ -28,63 +28,89 @@ * http://bitbucket.org/sdorra/scm-manager * */ -package sonia.scm.template; -import com.google.common.base.Objects; +package sonia.scm.api.rest; + +//~--- JDK imports ------------------------------------------------------------ + +import com.sun.jersey.api.core.PackagesResourceConfig; + +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.core.MediaType; + /** - * A viewable holds the path to a template and the context object which is used to render the template. Viewables can - * be used as return type of jax-rs resources. - * + * * @author Sebastian Sdorra - * @since 2.0.0 */ -public final class Viewable { - - private final String path; - private final Object context; +public class UriExtensionsConfig extends PackagesResourceConfig +{ - public Viewable(String path, Object context) { - this.path = path; - this.context = context; + /** Field description */ + public static final String EXTENSION_JSON = "json"; + + /** Field description */ + public static final String EXTENSION_XML = "xml"; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + */ + public UriExtensionsConfig() + { + super(); } - public String getPath() { - return path; + /** + * Constructs ... + * + * + * @param props + */ + public UriExtensionsConfig(Map props) + { + super(props); } - public Object getContext() { - return context; + /** + * Constructs ... + * + * + * @param paths + */ + public UriExtensionsConfig(String[] paths) + { + super(paths); } + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ @Override - public int hashCode() { - return Objects.hashCode(path, context); + public Map getMediaTypeMappings() + { + if (mediaTypeMap == null) + { + mediaTypeMap = new HashMap(); + mediaTypeMap.put(EXTENSION_JSON, MediaType.APPLICATION_JSON_TYPE); + mediaTypeMap.put(EXTENSION_XML, MediaType.APPLICATION_XML_TYPE); + } + + return mediaTypeMap; } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Viewable other = (Viewable) obj; - return !Objects.equal(this.path, other.path) - && Objects.equal(this.context, other.context); - } + //~--- fields --------------------------------------------------------------- - @Override - public String toString() { - return Objects.toStringHelper(this) - .add("path", path) - .add("context", context) - .toString(); - } - + /** Field description */ + private Map mediaTypeMap; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java index 040eb6b2dc..e9e63d16d8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java @@ -133,7 +133,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response add(@Context UriInfo uriInfo, Permission permission) { AssignedPermission ap = transformPermission(permission); @@ -185,7 +185,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response update(@PathParam("id") String id, Permission permission) { StoredAssignedPermission sap = getPermission(id); @@ -213,7 +213,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 404, condition = "not found, no permission with the specified id available"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Permission get(@PathParam("id") String id) { StoredAssignedPermission sap = getPermission(id); @@ -231,7 +231,7 @@ public abstract class AbstractPermissionResource @ResponseCode(code = 204, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public List getAll() { return getPermissions(getPredicate()); diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java index 87626c7045..52b8b02c37 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java @@ -118,7 +118,7 @@ public class ChangePasswordResource @ResponseCode(code = 400, condition = "bad request, the old password is not correct"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response changePassword(@FormParam("old-password") String oldPassword, @FormParam("new-password") String newPassword) throws UserException, IOException diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java index a9beea7679..2fb6bdda3d 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java @@ -89,7 +89,7 @@ public class ConfigurationResource * @return */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response getConfiguration() { Response response = null; @@ -118,7 +118,7 @@ public class ConfigurationResource * @return */ @POST - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response setConfig(@Context UriInfo uriInfo, ScmConfiguration newConfig) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java index dd61f0aecb..808aaa498b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java @@ -119,7 +119,7 @@ public class GroupResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public Response create(@Context UriInfo uriInfo, Group group) { @@ -164,7 +164,7 @@ public class GroupResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public Response update(@Context UriInfo uriInfo, @PathParam("id") String name, Group group) @@ -191,7 +191,7 @@ public class GroupResource @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public Response get(@Context Request request, @PathParam("id") String id) { @@ -221,7 +221,7 @@ public class GroupResource * @return */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @TypeHint(Group[].class) @StatusCodes({ @ResponseCode(code = 200, condition = "success"), diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java index fda978b3fe..54c9369a57 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java @@ -52,6 +52,7 @@ import sonia.scm.plugin.PluginInformationComparator; //~--- JDK imports ------------------------------------------------------------ +import com.sun.jersey.multipart.FormDataParam; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.TypeHint; @@ -65,7 +66,6 @@ import java.util.Iterator; import java.util.List; import javax.ws.rs.Consumes; -import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -124,9 +124,9 @@ public class PluginResource @ResponseCode(code = 500, condition = "internal server error") }) @Consumes(MediaType.MULTIPART_FORM_DATA) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response install( - /*@FormParam("package")*/ InputStream uploadedInputStream) + @FormDataParam("package") InputStream uploadedInputStream) throws IOException { Response response = null; @@ -194,7 +194,7 @@ public class PluginResource @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.TEXT_HTML) public Response installFromUI( - /*@FormParam("package")*/ InputStream uploadedInputStream) + @FormDataParam("package") InputStream uploadedInputStream) throws IOException { return install(uploadedInputStream); @@ -257,7 +257,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Collection getAll() { return pluginManager.getAll(); @@ -274,7 +274,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Collection getAvailable() { return pluginManager.getAvailable(); @@ -291,7 +291,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Collection getAvailableUpdates() { return pluginManager.getAvailableUpdates(); @@ -325,7 +325,7 @@ public class PluginResource @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Collection getOverview() { //J- diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java index 9c01e3d4a8..9382f58c5c 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java @@ -69,6 +69,8 @@ import static com.google.common.base.Preconditions.*; //~--- JDK imports ------------------------------------------------------------ +import com.sun.jersey.api.client.ClientResponse.Status; +import com.sun.jersey.multipart.FormDataParam; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.ResponseHeader; import com.webcohesion.enunciate.metadata.rs.StatusCodes; @@ -87,7 +89,6 @@ import java.util.Set; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; -import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -110,7 +111,7 @@ import javax.xml.bind.annotation.XmlRootElement; * * @author Sebastian Sdorra */ -// @Path("import/repositories") +@Path("import/repositories") public class RepositoryImportResource { @@ -169,8 +170,8 @@ public class RepositoryImportResource @TypeHint(TypeHint.NO_CONTENT.class) @Consumes(MediaType.MULTIPART_FORM_DATA) public Response importFromBundle(@Context UriInfo uriInfo, - @PathParam("type") String type, @FormParam("name") String name, - @FormParam("bundle") InputStream inputStream, @QueryParam("compressed") + @PathParam("type") String type, @FormDataParam("name") String name, + @FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed") @DefaultValue("false") boolean compressed) { Repository repository = doImportFromBundle(type, name, inputStream, @@ -210,8 +211,8 @@ public class RepositoryImportResource @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.TEXT_HTML) public Response importFromBundleUI(@PathParam("type") String type, - @FormParam("name") String name, - @FormParam("bundle") InputStream inputStream, @QueryParam("compressed") + @FormDataParam("name") String name, + @FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed") @DefaultValue("false") boolean compressed) { Response response; @@ -259,7 +260,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response importFromUrl(@Context UriInfo uriInfo, @PathParam("type") String type, UrlImportRequest request) { @@ -319,7 +320,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(Repository[].class) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response importRepositories(@PathParam("type") String type) { SecurityUtils.getSubject().checkRole(Role.ADMIN); @@ -351,7 +352,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(Repository[].class) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response importRepositories() { SecurityUtils.getSubject().checkRole(Role.ADMIN); @@ -393,7 +394,7 @@ public class RepositoryImportResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(ImportResult.class) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response importRepositoriesFromDirectory( @PathParam("type") String type) { @@ -434,7 +435,7 @@ public class RepositoryImportResource .warn( "import feature is not supported by repository handler for type " .concat(type), ex); - response = Response.status(Response.Status.BAD_REQUEST).build(); + response = Response.status(Status.BAD_REQUEST).build(); } catch (IOException ex) { @@ -450,7 +451,7 @@ public class RepositoryImportResource else { logger.warn("could not find reposiotry handler for type {}", type); - response = Response.status(Response.Status.BAD_REQUEST).build(); + response = Response.status(Status.BAD_REQUEST).build(); } return response; @@ -474,7 +475,7 @@ public class RepositoryImportResource ), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response getImportableTypes() { SecurityUtils.getSubject().checkRole(Role.ADMIN); diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java index e9f7812ee0..16168aefc7 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java @@ -166,7 +166,7 @@ public class RepositoryResource extends AbstractManagerResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public Response create(@Context UriInfo uriInfo, User user) { @@ -170,7 +170,7 @@ public class UserResource extends AbstractManagerResource @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public Response update(@Context UriInfo uriInfo, @PathParam("id") String name, User user) @@ -197,7 +197,7 @@ public class UserResource extends AbstractManagerResource @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public Response get(@Context Request request, @PathParam("id") String id) { @@ -233,7 +233,7 @@ public class UserResource extends AbstractManagerResource @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public Response getAll(@Context Request request, @DefaultValue("0") @QueryParam("start") int start, @DefaultValue("-1") diff --git a/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java b/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java index 0933242b49..f65e0c7708 100644 --- a/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java +++ b/scm-webapp/src/main/java/sonia/scm/debug/DebugResource.java @@ -67,7 +67,7 @@ public final class DebugResource * @return all received hook data for the given repository */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Collection getAll(@PathParam("repository") String repository){ return debugService.getAll(repository); } @@ -81,7 +81,7 @@ public final class DebugResource */ @GET @Path("last") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public DebugHookData getLast(@PathParam("repository") String repository){ return debugService.getLast(repository); } diff --git a/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java b/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java index 2998f82890..5e61ed6965 100644 --- a/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java +++ b/scm-webapp/src/main/java/sonia/scm/net/ahc/JsonContentTransformer.java @@ -33,16 +33,14 @@ package sonia.scm.net.ahc; //~--- non-JDK imports -------------------------------------------------------- -import com.fasterxml.jackson.databind.AnnotationIntrospector; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; -import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; -import com.fasterxml.jackson.databind.type.TypeFactory; -import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; - import com.google.common.io.ByteSource; +import org.codehaus.jackson.map.AnnotationIntrospector; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector; +import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; + import sonia.scm.plugin.ext.Extension; import sonia.scm.util.IOUtil; @@ -75,12 +73,12 @@ public class JsonContentTransformer implements ContentTransformer // allow jackson and jaxb annotations AnnotationIntrospector jackson = new JacksonAnnotationIntrospector(); - AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); + AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector(); - this.mapper.setAnnotationIntrospector(new AnnotationIntrospectorPair(jackson, jaxb)); + this.mapper.setAnnotationIntrospector(new AnnotationIntrospector.Pair(jackson, jaxb)); // do not fail on unknown json properties - this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + this.mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); } //~--- methods -------------------------------------------------------------- diff --git a/scm-webapp/src/main/resources/logback.default.xml b/scm-webapp/src/main/resources/logback.default.xml index bf18f02893..318cd6112a 100644 --- a/scm-webapp/src/main/resources/logback.default.xml +++ b/scm-webapp/src/main/resources/logback.default.xml @@ -90,8 +90,6 @@ - - diff --git a/scm-webapp/src/main/webapp/WEB-INF/web.xml b/scm-webapp/src/main/webapp/WEB-INF/web.xml index 8a54ee72cd..513c708e80 100644 --- a/scm-webapp/src/main/webapp/WEB-INF/web.xml +++ b/scm-webapp/src/main/webapp/WEB-INF/web.xml @@ -40,7 +40,7 @@ SCM-Manager ${project.version} - sonia.scm.boot.BootstrapContextListener + sonia.scm.boot.BootstrapListener @@ -48,45 +48,15 @@ - BootstrapFilter - sonia.scm.boot.BootstrapContextFilter + guiceFilter + sonia.scm.boot.BootstrapFilter - BootstrapFilter + guiceFilter /* - - - - resteasy.servlet.mapping.prefix - /api/rest - - - - Resteasy - - org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher - - - - - Resteasy - /api/rest/* - - - - - - - sonia.scm.HttpSessionListenerHolder - - - - index.html diff --git a/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js b/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js index 3d044d69c5..b1c0a5372f 100644 --- a/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js +++ b/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js @@ -55,7 +55,7 @@ Sonia.action.ChangePasswordWindow = Ext.extend(Ext.Window,{ title: this.titleText, items: [{ id: 'changePasswordForm', - url: restUrl + 'action/change-password', + url: restUrl + 'action/change-password.json', frame: true, xtype: 'form', monitorValid: true, diff --git a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js index 0f9c2fdd57..a985688a3e 100644 --- a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js @@ -261,7 +261,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ onSubmit: function(values){ this.el.mask(this.submitText); Ext.Ajax.request({ - url: restUrl + 'config', + url: restUrl + 'config.json', method: 'POST', jsonData: values, scope: this, @@ -283,7 +283,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ onLoad: function(el){ var tid = setTimeout( function(){ el.mask(this.loadingText); }, 100); Ext.Ajax.request({ - url: restUrl + 'config', + url: restUrl + 'config.json', method: 'GET', scope: this, disableCaching: true, diff --git a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js index 4ec278bf6b..5d560d9717 100644 --- a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.formpanel.js @@ -59,7 +59,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ // this.updateMembers(group); this.fireEvent('preUpdate', group); - var url = restUrl + 'groups/' + encodeURIComponent(group.name); + var url = restUrl + 'groups/' + encodeURIComponent(group.name) + '.json'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); @@ -96,7 +96,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ } item.type = state.defaultUserType; - var url = restUrl + 'groups'; + var url = restUrl + 'groups.json'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); diff --git a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js index 1bc3fbe819..18d3841fc2 100644 --- a/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/group/sonia.group.panel.js @@ -95,7 +95,7 @@ Sonia.group.Panel = Ext.extend(Sonia.rest.Panel, { var selected = grid.getSelectionModel().getSelected(); if ( selected ){ var item = selected.data; - var url = restUrl + 'groups/' + encodeURIComponent(item.name); + var url = restUrl + 'groups/' + encodeURIComponent(item.name) + '.json'; Ext.MessageBox.show({ title: this.removeTitleText, diff --git a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js index 19ad6d0e15..b27f2484b4 100644 --- a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js +++ b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js @@ -41,6 +41,7 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ failedDescriptionText: 'Incorrect username, password or not enough permission. Please Try again.', accountLockedText: 'Account is locked.', accountTemporaryLockedText: 'Account is temporary locked. Please try again later.', + rememberMeText: 'Remember me', initComponent: function(){ var buttons = []; @@ -93,14 +94,11 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ scope: this } } - }, { - name: 'grant_type', - value: 'password', - xtype: 'hidden' - }, { - name: 'cookie', - value: 'true', - xtype: 'hidden' + },{ + xtype: 'checkbox', + fieldLabel: this.rememberMeText, + name: 'rememberMe', + inputValue: 'true' }], buttons: buttons }; @@ -118,7 +116,6 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ authenticate: function(){ var form = this.getForm(); - form.submit({ scope: this, method: 'POST', diff --git a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js index ebd2119886..11113e2601 100644 --- a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js +++ b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.center.js @@ -81,7 +81,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, { var loadingBox = this.createLoadingBox( this.installWaitMsgText ); Ext.Ajax.request({ - url: restUrl + 'plugins/install/' + pluginId, + url: restUrl + 'plugins/install/' + pluginId + '.json', method: 'POST', scope: this, timeout: 300000, // 5min @@ -116,7 +116,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, { var loadingBox = this.createLoadingBox( this.uninstallWaitMsgText ); Ext.Ajax.request({ - url: restUrl + 'plugins/uninstall/' + pluginId, + url: restUrl + 'plugins/uninstall/' + pluginId + '.json', method: 'POST', scope: this, success: function(){ @@ -150,7 +150,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, { var loadingBox = this.createLoadingBox( this.updateWaitMsgText ); Ext.Ajax.request({ - url: restUrl + 'plugins/update/' + pluginId, + url: restUrl + 'plugins/update/' + pluginId + '.json', method: 'POST', scope: this, timeout: 300000, // 5min diff --git a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js index 5f44e51ebc..cb5ea6bec1 100644 --- a/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/plugin/sonia.plugin.grid.js @@ -81,7 +81,7 @@ Sonia.plugin.Grid = Ext.extend(Sonia.rest.Grid, { var pluginStore = new Ext.data.GroupingStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'plugins/overview', + url: restUrl + 'plugins/overview.json', disableCaching: false }), reader: new Ext.data.JsonReader({ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js index 4c3dcbc7c8..cddcad4552 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.branchcombobox.js @@ -38,7 +38,7 @@ Sonia.repository.BranchComboBox = Ext.extend(Ext.form.ComboBox, { initComponent: function(){ var branchStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories/' + this.repositoryId + '/branches', + url: restUrl + 'repositories/' + this.repositoryId + '/branches.json', method: 'GET', disableCaching: false }), diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js index 468b99dbec..aa18d29e0d 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.changesetviewerpanel.js @@ -46,7 +46,7 @@ Sonia.repository.ChangesetViewerPanel = Ext.extend(Ext.Panel, { initComponent: function(){ if (! this.url){ - this.url = restUrl + 'repositories/' + this.repository.id + '/changesets'; + this.url = restUrl + 'repositories/' + this.repository.id + '/changesets.json'; } if ( ! this.startLimit ){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js index 591d77d43f..7b72c4fca3 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.commitpanel.js @@ -131,7 +131,7 @@ Sonia.repository.CommitPanel = Ext.extend(Ext.Panel, { } Ext.Ajax.request({ - url: restUrl + 'repositories/' + this.repository.id + '/changeset/' + this.revision, + url: restUrl + 'repositories/' + this.repository.id + '/changeset/' + this.revision + '.json', method: 'GET', scope: this, success: function(response){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js index 422a81ce6b..66482399ac 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.formpanel.js @@ -73,7 +73,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ if ( debug ){ console.debug( 'update repository: ' + item.name ); } - var url = restUrl + 'repositories/' + item.id; + var url = restUrl + 'repositories/' + item.id + '.json'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); @@ -124,7 +124,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ if ( debug ){ console.debug( 'create repository: ' + item.name ); } - var url = restUrl + 'repositories'; + var url = restUrl + 'repositories.json'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js index 9e2f76f607..fb66b91a5a 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js @@ -71,7 +71,7 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, { var repositoryStore = new Ext.data.GroupingStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories', + url: restUrl + 'repositories.json', disableCaching: false }), idProperty: 'id', diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js index 076f73e712..195d7d7509 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.healthcheckfailure.js @@ -75,7 +75,7 @@ Sonia.repository.HealthCheckFailure = Ext.extend(Ext.Panel, { }, rerunHealthChecks: function(){ - var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck'; + var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck.json'; var el = this.el; var tid = setTimeout( function(){el.mask('Loading ...');}, 100); diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js index ac6bbc2206..209b554e82 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.importwindow.js @@ -514,7 +514,7 @@ Sonia.repository.ImportPanel = Ext.extend(Ext.Panel, { importFromUrl: function(layout, repository){ var lbox = this.showLoadingBox(); Ext.Ajax.request({ - url: restUrl + 'import/repositories/' + this.repositoryType + '/url', + url: restUrl + 'import/repositories/' + this.repositoryType + '/url.json', method: 'POST', scope: this, timeout: 300000, // 5min @@ -533,7 +533,7 @@ Sonia.repository.ImportPanel = Ext.extend(Ext.Panel, { importFromDirectory: function(layout){ var lbox = this.showLoadingBox(); Ext.Ajax.request({ - url: restUrl + 'import/repositories/' + this.repositoryType + '/directory', + url: restUrl + 'import/repositories/' + this.repositoryType + '/directory.json', timeout: 300000, // 5min method: 'POST', scope: this, diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js index e978c0ffe9..7e10a58f4e 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.js @@ -181,7 +181,7 @@ Sonia.repository.get = function(id, callback){ execCallback(repository); } else { Ext.Ajax.request({ - url: restUrl + 'repositories/' + id, + url: restUrl + 'repositories/' + id + '.json', method: 'GET', scope: this, success: function(response){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js index 767c294242..17a301509a 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.panel.js @@ -311,7 +311,7 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, { console.debug('toggle repository ' + item.name + ' archive to ' + item.archived); } - var url = restUrl + 'repositories/' + item.id; + var url = restUrl + 'repositories/' + item.id + '.json'; this.executeRemoteCall(title, String.format(msg, item.name), 'PUT', url, item, function(result){ main.handleFailure( @@ -331,7 +331,7 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, { console.debug( 'remove repository ' + item.name ); } - var url = restUrl + 'repositories/' + item.id; + var url = restUrl + 'repositories/' + item.id + '.json'; this.executeRemoteCall(this.removeTitleText, String.format(this.removeMsgText, item.name), 'DELETE', url, null, function(result){ diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js index 59677cab7e..489dd3c06c 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.repositorybrowser.js @@ -58,7 +58,7 @@ Sonia.repository.RepositoryBrowser = Ext.extend(Ext.grid.GridPanel, { var browserStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories/' + this.repository.id, + url: restUrl + 'repositories/' + this.repository.id + '/browse.json', method: 'GET' }), fields: ['path', 'name', 'length', 'lastModified', 'directory', 'description', 'subrepository'], diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js index 5af3cc97f1..3f045a8cf6 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.tagcombobox.js @@ -37,7 +37,7 @@ Sonia.repository.TagComboBox = Ext.extend(Ext.form.ComboBox, { initComponent: function(){ var tagStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'repositories/' + this.repositoryId + '/tags', + url: restUrl + 'repositories/' + this.repositoryId + '/tags.json', method: 'GET', disableCaching: false }), diff --git a/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js b/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js index 676114fc78..5ea8855251 100644 --- a/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js +++ b/scm-webapp/src/main/webapp/resources/js/security/sonia.security.permissionspanel.js @@ -53,7 +53,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { this.permissionStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ api: { - read: restUrl + this.baseUrl + read: restUrl + this.baseUrl + '.json' }, disableCaching: false }), @@ -179,7 +179,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { addPermission: function(record){ Ext.Ajax.request({ - url: restUrl + this.baseUrl, + url: restUrl + this.baseUrl + '.json', method: 'POST', jsonData: record.data, scope: this, @@ -194,7 +194,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { modifyPermission: function(id, record){ Ext.Ajax.request({ - url: restUrl + this.baseUrl + '/' + encodeURIComponent(id), + url: restUrl + this.baseUrl + '/' + encodeURIComponent(id) + '.json', method: 'PUT', jsonData: record.data, scope: this, @@ -207,7 +207,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, { removePermission: function(store, record){ Ext.Ajax.request({ - url: restUrl + this.baseUrl + '/' + encodeURIComponent(record.get('id')), + url: restUrl + this.baseUrl + '/' + encodeURIComponent(record.get('id')) + '.json', method: 'DELETE', scope: this, success: function(){ diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.global.js b/scm-webapp/src/main/webapp/resources/js/sonia.global.js index 98299546b1..a43feb824b 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.global.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.global.js @@ -83,7 +83,7 @@ var userSearchStore = new Ext.data.JsonStore({ idProperty: 'value', fields: ['value','label'], proxy: new Ext.data.HttpProxy({ - url: restUrl + 'search/users', + url: restUrl + 'search/users.json', method: 'GET' }) }); @@ -93,7 +93,7 @@ var groupSearchStore = new Ext.data.JsonStore({ idProperty: 'value', fields: ['value','label'], proxy: new Ext.data.HttpProxy({ - url: restUrl + 'search/groups', + url: restUrl + 'search/groups.json', method: 'GET' }) }); diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js index db92a77d60..6d7e6a3257 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js @@ -689,4 +689,4 @@ Ext.onReady(function(){ main.init(); main.checkLogin(); -}); +}); \ No newline at end of file diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js index e8a03e5966..6ef00e73d7 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js @@ -129,7 +129,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ console.debug( 'update user: ' + item.name ); } this.fixRequest(item); - var url = restUrl + 'users/' + encodeURIComponent(item.name); + var url = restUrl + 'users/' + encodeURIComponent(item.name) + '.json'; Ext.Ajax.request({ url: url, jsonData: item, @@ -159,7 +159,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ this.fixRequest(user); // set user type user.type = state.defaultUserType; - var url = restUrl + 'users'; + var url = restUrl + 'users.json'; Ext.Ajax.request({ url: url, jsonData: user, diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js index b671e67bdc..c44d336ba9 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js @@ -49,7 +49,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, { var userStore = new Sonia.rest.JsonStore({ proxy: new Ext.data.HttpProxy({ - url: restUrl + 'users', + url: restUrl + 'users.json', disableCaching: false }), idProperty: 'name', diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js index 0ca0fd78e1..8e98c645df 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js @@ -126,7 +126,7 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, { var selected = grid.getSelectionModel().getSelected(); if ( selected ){ var item = selected.data; - var url = restUrl + 'users/' + encodeURIComponent(item.name); + var url = restUrl + 'users/' + encodeURIComponent(item.name) + '.json'; Ext.MessageBox.show({ title: this.removeTitleText, diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index 33e020f85d..f8adb90ff1 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -32,9 +32,6 @@ package sonia.scm.it; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.type.TypeFactory; -import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; import com.google.common.base.Charsets; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.UniformInterfaceException; @@ -44,6 +41,8 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import org.apache.shiro.crypto.hash.Sha256Hash; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Test; @@ -82,7 +81,7 @@ public class GitLfsITCase { private Repository repository; public GitLfsITCase() { - mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(TypeFactory.defaultInstance())); + mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector()); } // lifecycle methods From 1e1fd41bda60971f9bc9e52b835402244bde2220 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 13 Oct 2018 17:34:36 +0200 Subject: [PATCH 080/178] #994 fixed empty repository name on non bare repositories --- .../sonia/scm/repository/RepositoryUtil.java | 22 +++--- .../scm/repository/RepositoryUtilTest.java | 73 +++++++++++++++++++ 2 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 scm-core/src/test/java/sonia/scm/repository/RepositoryUtilTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryUtil.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryUtil.java index 41b1b0aec5..e91722ebfe 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryUtil.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryUtil.java @@ -35,6 +35,7 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -237,23 +238,18 @@ public final class RepositoryUtil public static String getRepositoryName(File baseDirectory, File directory) throws IOException { - String name = null; String path = directory.getCanonicalPath(); - int directoryLength = baseDirectory.getCanonicalPath().length(); + String basePath = baseDirectory.getCanonicalPath(); - if (directoryLength < path.length()) - { - name = IOUtil.trimSeperatorChars(path.substring(directoryLength)); + Preconditions.checkArgument( + path.startsWith(basePath), + "repository path %s is not in the main repository path %s", path, basePath + ); - // replace windows path seperator - name = name.replaceAll("\\\\", "/"); - } - else if (logger.isWarnEnabled()) - { - logger.warn("path is shorter as the main repository path"); - } + String name = IOUtil.trimSeperatorChars(path.substring(basePath.length())); - return name; + // replace windows path seperator + return name.replaceAll("\\\\", "/"); } /** diff --git a/scm-core/src/test/java/sonia/scm/repository/RepositoryUtilTest.java b/scm-core/src/test/java/sonia/scm/repository/RepositoryUtilTest.java new file mode 100644 index 0000000000..a32a089181 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/RepositoryUtilTest.java @@ -0,0 +1,73 @@ +package sonia.scm.repository; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class RepositoryUtilTest { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Mock + private AbstractRepositoryHandler repositoryHandler; + + private SimpleRepositoryConfig repositoryConfig; + + @Before + public void setUpMocks() { + repositoryConfig = new SimpleRepositoryConfig(); + when(repositoryHandler.getConfig()).thenReturn(repositoryConfig); + } + + @Test + public void testGetRepositoryName() throws IOException { + File repositoryTypeRoot = temporaryFolder.newFolder(); + repositoryConfig.setRepositoryDirectory(repositoryTypeRoot); + + File repository = new File(repositoryTypeRoot, "abc"); + String name = RepositoryUtil.getRepositoryName(repositoryHandler, repository.getPath()); + assertEquals("abc", name); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetRepositoryNameWithInvalidPath() throws IOException { + File repositoryTypeRoot = temporaryFolder.newFolder(); + repositoryConfig.setRepositoryDirectory(repositoryTypeRoot); + + File repository = new File("/etc/abc"); + String name = RepositoryUtil.getRepositoryName(repositoryHandler, repository.getPath()); + assertEquals("abc", name); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetRepositoryNameWithInvalidPathButSameLength() throws IOException { + File repositoryTypeRoot = temporaryFolder.newFolder(); + repositoryConfig.setRepositoryDirectory(repositoryTypeRoot); + + File repository = new File(temporaryFolder.newFolder(), "abc"); + + String name = RepositoryUtil.getRepositoryName(repositoryHandler, repository.getPath()); + assertEquals("abc", name); + } + + @Test + public void testGetRepositoryNameWithSubDirectory() throws IOException { + File repositoryTypeRoot = temporaryFolder.newFolder(); + repositoryConfig.setRepositoryDirectory(repositoryTypeRoot); + + File repository = new File(repositoryTypeRoot, "abc/123"); + String name = RepositoryUtil.getRepositoryName(repositoryHandler, repository.getPath()); + assertEquals("abc/123", name); + } +} From 24e2885524769bbf784b70d02e8229f94ceb3589 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 14 Oct 2018 19:11:56 +0200 Subject: [PATCH 081/178] #998 git: set repository head to default branch --- .../sonia/scm/repository/GitHeadHandler.java | 53 ++++++++ .../sonia/scm/repository/GitHeadModifier.java | 7 ++ .../sonia/scm/repository/GitHeadResolver.java | 7 ++ .../GitRepositoryModifyListener.java | 51 +++++--- .../scm/repository/GitHeadHandlerTest.java | 60 +++++++++ .../GitRepositoryModifyListenerTest.java | 116 ++++++++++++------ 6 files changed, 239 insertions(+), 55 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java new file mode 100644 index 0000000000..23e6156297 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java @@ -0,0 +1,53 @@ +package sonia.scm.repository; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.io.Files; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.File; +import java.io.IOException; + +@Singleton +public class GitHeadHandler implements GitHeadResolver, GitHeadModifier { + + private final GitRepositoryHandler repositoryHandler; + + @Inject + public GitHeadHandler(GitRepositoryHandler repositoryHandler) { + this.repositoryHandler = repositoryHandler; + } + + @Override + public String resolve(Repository repository) { + File headFile = findHeadFile(repository); + try { + String line = Files.readFirstLine(headFile, Charsets.UTF_8); + // TODO handle invalid head file + int index = line.indexOf(GitUtil.REF_HEAD_PREFIX); + return line.substring(index + GitUtil.REF_HEAD_PREFIX.length()); + } catch (IOException e) { + // TODO + throw Throwables.propagate(e); + } + } + + @Override + public void modify(Repository repository, String head) { + File headFile = findHeadFile(repository); + try { + String line = "ref: " + GitUtil.REF_HEAD_PREFIX + head + "\n"; + Files.write(line, headFile, Charsets.UTF_8); + } catch (IOException e) { + // TODO + throw Throwables.propagate(e); + } + } + + private File findHeadFile(Repository repository) { + // TODO handle non bare repositories + File directory = repositoryHandler.getDirectory(repository); + return new File(directory, "HEAD"); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java new file mode 100644 index 0000000000..f6597e3958 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java @@ -0,0 +1,7 @@ +package sonia.scm.repository; + +public interface GitHeadModifier { + + void modify(Repository repository, String head); + +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java new file mode 100644 index 0000000000..c9f3dce609 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java @@ -0,0 +1,7 @@ +package sonia.scm.repository; + +public interface GitHeadResolver { + + String resolve(Repository repository); + +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java index 4309257350..64f93d45de 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java @@ -32,6 +32,7 @@ package sonia.scm.repository; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; +import com.google.common.base.Strings; import com.google.common.eventbus.Subscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,58 +41,74 @@ import sonia.scm.HandlerEvent; import sonia.scm.event.ScmEventBus; import sonia.scm.plugin.ext.Extension; +import javax.inject.Inject; + /** * Repository listener which handles git related repository events. - * + * * @author Sebastian Sdorra * @since 1.50 */ @Extension @EagerSingleton public class GitRepositoryModifyListener { - + /** * the logger for GitRepositoryModifyListener */ private static final Logger logger = LoggerFactory.getLogger(GitRepositoryModifyListener.class); - + + private final GitHeadResolver headResolver; + private final GitHeadModifier headModifier; + + @Inject + public GitRepositoryModifyListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { + this.headResolver = headResolver; + this.headModifier = headModifier; + } + /** * Receives {@link RepositoryModificationEvent} and fires a {@link ClearRepositoryCacheEvent} if * the default branch of a git repository was modified. - * + * * @param event repository modification event */ @Subscribe public void handleEvent(RepositoryModificationEvent event){ Repository repository = event.getItem(); - - if ( isModifyEvent(event) && - isGitRepository(event.getItem()) && - hasDefaultBranchChanged(event.getItemBeforeModification(), repository)) + + if ( isModifyEvent(event) && isGitRepository(event.getItem()) ) { - logger.info("git default branch of repository {} has changed, sending clear cache event", repository.getId()); - sendClearRepositoryCacheEvent(repository); + if (hasDefaultBranchChanged(event.getItemBeforeModification(), repository)) { + logger.info("git default branch of repository {} has changed, sending clear cache event", repository.getId()); + sendClearRepositoryCacheEvent(repository); + } + + String defaultBranch = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH); + if (defaultBranch != null && ! defaultBranch.equals(headResolver.resolve(repository))) { + headModifier.modify(repository, defaultBranch); + } } } - + @VisibleForTesting protected void sendClearRepositoryCacheEvent(Repository repository) { - ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); + ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); } - + private boolean isModifyEvent(RepositoryEvent event) { return event.getEventType() == HandlerEvent.MODIFY; } - + private boolean isGitRepository(Repository repository) { return GitRepositoryHandler.TYPE_NAME.equals(repository.getType()); } - + private boolean hasDefaultBranchChanged(Repository old, Repository current) { return !Objects.equal( - old.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH), + old.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH), current.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH) ); } - + } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java new file mode 100644 index 0000000000..e3ae85baa2 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java @@ -0,0 +1,60 @@ +package sonia.scm.repository; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class GitHeadHandlerTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Mock + private GitRepositoryHandler repositoryHandler; + + @InjectMocks + private GitHeadHandler headHandler; + + @Test + public void testResolve() throws IOException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + create(repository, "master"); + + String head = headHandler.resolve(repository); + assertEquals("master", head); + } + + @Test + public void testModify() throws IOException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + File file = create(repository, "master"); + + headHandler.modify(repository, "develop"); + + assertEquals("ref: refs/heads/develop", Files.readFirstLine(file, Charsets.UTF_8)); + } + + private File create(Repository repository, String head) throws IOException { + File directory = temporaryFolder.newFolder(); + File headFile = new File(directory, "HEAD"); + Files.write(String.format("ref: refs/heads/%s\n", head), headFile, Charsets.UTF_8); + + when(repositoryHandler.getDirectory(repository)).thenReturn(directory); + + return headFile; + } + +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java index 9f6768aeac..008000daef 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java @@ -1,10 +1,10 @@ /** * Copyright (c) 2014, 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, @@ -13,7 +13,7 @@ * 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 @@ -24,34 +24,42 @@ * 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.repository; import org.junit.Test; import static org.junit.Assert.*; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import sonia.scm.HandlerEvent; /** * Unit tests for {@link GitRepositoryModifyListener}. - * + * * @author Sebastian Sdorra */ +@RunWith(MockitoJUnitRunner.class) public class GitRepositoryModifyListenerTest { + @Mock + private GitHeadResolver headResolver; + + @Mock + private GitHeadModifier headModifier; + + @InjectMocks private GitRepositoryModifyTestListener repositoryModifyListener; - - /** - * Set up test object. - */ - @Before - public void setUpObjectUnderTest(){ - repositoryModifyListener = new GitRepositoryModifyTestListener(); - } /** * Tests happy path. @@ -62,14 +70,14 @@ public class GitRepositoryModifyListenerTest { old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNotNull(repositoryModifyListener.repository); assertSame(current, repositoryModifyListener.repository); } - + /** * Tests with new default branch. */ @@ -78,14 +86,14 @@ public class GitRepositoryModifyListenerTest { Repository old = RepositoryTestData.createHeartOfGold("git"); Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNotNull(repositoryModifyListener.repository); assertSame(current, repositoryModifyListener.repository); } - + /** * Tests with non git repositories. */ @@ -95,13 +103,13 @@ public class GitRepositoryModifyListenerTest { old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); Repository current = RepositoryTestData.createHeartOfGold("hg"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + /** * Tests without default branch. */ @@ -109,13 +117,13 @@ public class GitRepositoryModifyListenerTest { public void testWithoutDefaultBranch(){ Repository old = RepositoryTestData.createHeartOfGold("git"); Repository current = RepositoryTestData.createHeartOfGold("git"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + /** * Tests with non modify event. */ @@ -125,13 +133,13 @@ public class GitRepositoryModifyListenerTest { old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.CREATE); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + /** * Tests with non git repositories. */ @@ -144,20 +152,52 @@ public class GitRepositoryModifyListenerTest { RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + + @Test + public void testModifyRepositoryHead() { + Repository old = RepositoryTestData.createHeartOfGold("git"); + Repository current = RepositoryTestData.createHeartOfGold("git"); + current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); + + when(headResolver.resolve(current)).thenReturn("master"); + + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); + repositoryModifyListener.handleEvent(event); + + verify(headModifier).modify(current, "develop"); + } + + @Test + public void testWithEqualHeads() { + Repository old = RepositoryTestData.createHeartOfGold("git"); + Repository current = RepositoryTestData.createHeartOfGold("git"); + current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); + + when(headResolver.resolve(current)).thenReturn("develop"); + + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); + repositoryModifyListener.handleEvent(event); + + verify(headModifier, never()).modify(current, "develop"); + } + private static class GitRepositoryModifyTestListener extends GitRepositoryModifyListener { - + private Repository repository; - + + public GitRepositoryModifyTestListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { + super(headResolver, headModifier); + } + @Override protected void sendClearRepositoryCacheEvent(Repository repository) { this.repository = repository; - } - - } - + } -} \ No newline at end of file + } + + +} From 6fb99b70cd419d7b4836e5e1437b90c0b5fbe141 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 15 Oct 2018 21:32:03 +0200 Subject: [PATCH 082/178] #998 simplify api and use jgit to link new head --- .../sonia/scm/repository/GitHeadHandler.java | 53 ---------- .../sonia/scm/repository/GitHeadModifier.java | 98 ++++++++++++++++- .../sonia/scm/repository/GitHeadResolver.java | 7 -- .../GitRepositoryModifyListener.java | 9 +- .../scm/repository/GitHeadHandlerTest.java | 60 ----------- .../scm/repository/GitHeadModifierTest.java | 100 ++++++++++++++++++ .../GitRepositoryModifyListenerTest.java | 24 +---- 7 files changed, 202 insertions(+), 149 deletions(-) delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java delete mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java deleted file mode 100644 index 23e6156297..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -package sonia.scm.repository; - -import com.google.common.base.Charsets; -import com.google.common.base.Throwables; -import com.google.common.io.Files; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.io.File; -import java.io.IOException; - -@Singleton -public class GitHeadHandler implements GitHeadResolver, GitHeadModifier { - - private final GitRepositoryHandler repositoryHandler; - - @Inject - public GitHeadHandler(GitRepositoryHandler repositoryHandler) { - this.repositoryHandler = repositoryHandler; - } - - @Override - public String resolve(Repository repository) { - File headFile = findHeadFile(repository); - try { - String line = Files.readFirstLine(headFile, Charsets.UTF_8); - // TODO handle invalid head file - int index = line.indexOf(GitUtil.REF_HEAD_PREFIX); - return line.substring(index + GitUtil.REF_HEAD_PREFIX.length()); - } catch (IOException e) { - // TODO - throw Throwables.propagate(e); - } - } - - @Override - public void modify(Repository repository, String head) { - File headFile = findHeadFile(repository); - try { - String line = "ref: " + GitUtil.REF_HEAD_PREFIX + head + "\n"; - Files.write(line, headFile, Charsets.UTF_8); - } catch (IOException e) { - // TODO - throw Throwables.propagate(e); - } - } - - private File findHeadFile(Repository repository) { - // TODO handle non bare repositories - File directory = repositoryHandler.getDirectory(repository); - return new File(directory, "HEAD"); - } -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java index f6597e3958..d6613ad6da 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java @@ -1,7 +1,101 @@ +/** + * Copyright (c) 2014, 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.repository; -public interface GitHeadModifier { +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - void modify(Repository repository, String head); +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Objects; +/** + * The GitHeadModifier is able to modify the head of a git repository. + * + * @author Sebastian Sdorra + * @since 1.61 + */ +public class GitHeadModifier { + + private static final Logger LOG = LoggerFactory.getLogger(GitHeadModifier.class); + + private final GitRepositoryHandler repositoryHandler; + + @Inject + public GitHeadModifier(GitRepositoryHandler repositoryHandler) { + this.repositoryHandler = repositoryHandler; + } + + /** + * Ensures that the repositories head points to the given branch. The method will return {@code false} if the + * repositories head points already to the given branch. + * + * @param repository repository to modify + * @param newHead branch which should be the new head of the repository + * + * @return {@code true} if the head has changed + */ + public boolean ensure(Repository repository, String newHead) { + try (org.eclipse.jgit.lib.Repository gitRepository = open(repository)) { + String currentHead = resolve(gitRepository); + if (!Objects.equals(currentHead, newHead)) { + return modify(gitRepository, newHead); + } + } catch (IOException ex) { + LOG.warn("failed to change head of repository", ex); + } + return false; + } + + private String resolve(org.eclipse.jgit.lib.Repository gitRepository) throws IOException { + Ref ref = gitRepository.getRefDatabase().getRef(Constants.HEAD); + if ( ref.isSymbolic() ) { + ref = ref.getTarget(); + } + return GitUtil.getBranch(ref); + } + + private boolean modify(org.eclipse.jgit.lib.Repository gitRepository, String newHead) throws IOException { + RefUpdate refUpdate = gitRepository.getRefDatabase().newUpdate(Constants.HEAD, true); + refUpdate.setForceUpdate(true); + RefUpdate.Result result = refUpdate.link(Constants.R_HEADS + newHead); + return result == RefUpdate.Result.FORCED; + } + + private org.eclipse.jgit.lib.Repository open(Repository repository) throws IOException { + File directory = repositoryHandler.getDirectory(repository); + return GitUtil.open(directory); + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java deleted file mode 100644 index c9f3dce609..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java +++ /dev/null @@ -1,7 +0,0 @@ -package sonia.scm.repository; - -public interface GitHeadResolver { - - String resolve(Repository repository); - -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java index 64f93d45de..c0ab21af9d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java @@ -32,7 +32,6 @@ package sonia.scm.repository; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; -import com.google.common.base.Strings; import com.google.common.eventbus.Subscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,12 +57,10 @@ public class GitRepositoryModifyListener { */ private static final Logger logger = LoggerFactory.getLogger(GitRepositoryModifyListener.class); - private final GitHeadResolver headResolver; private final GitHeadModifier headModifier; @Inject - public GitRepositoryModifyListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { - this.headResolver = headResolver; + public GitRepositoryModifyListener(GitHeadModifier headModifier) { this.headModifier = headModifier; } @@ -85,8 +82,8 @@ public class GitRepositoryModifyListener { } String defaultBranch = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH); - if (defaultBranch != null && ! defaultBranch.equals(headResolver.resolve(repository))) { - headModifier.modify(repository, defaultBranch); + if (defaultBranch != null) { + headModifier.ensure(repository, defaultBranch); } } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java deleted file mode 100644 index e3ae85baa2..0000000000 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package sonia.scm.repository; - -import com.google.common.base.Charsets; -import com.google.common.io.Files; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.io.File; -import java.io.IOException; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - -@RunWith(MockitoJUnitRunner.class) -public class GitHeadHandlerTest { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Mock - private GitRepositoryHandler repositoryHandler; - - @InjectMocks - private GitHeadHandler headHandler; - - @Test - public void testResolve() throws IOException { - Repository repository = RepositoryTestData.createHeartOfGold("git"); - create(repository, "master"); - - String head = headHandler.resolve(repository); - assertEquals("master", head); - } - - @Test - public void testModify() throws IOException { - Repository repository = RepositoryTestData.createHeartOfGold("git"); - File file = create(repository, "master"); - - headHandler.modify(repository, "develop"); - - assertEquals("ref: refs/heads/develop", Files.readFirstLine(file, Charsets.UTF_8)); - } - - private File create(Repository repository, String head) throws IOException { - File directory = temporaryFolder.newFolder(); - File headFile = new File(directory, "HEAD"); - Files.write(String.format("ref: refs/heads/%s\n", head), headFile, Charsets.UTF_8); - - when(repositoryHandler.getDirectory(repository)).thenReturn(directory); - - return headFile; - } - -} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java new file mode 100644 index 0000000000..7a205d2584 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2014, 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.repository; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class GitHeadModifierTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Mock + private GitRepositoryHandler repositoryHandler; + + @InjectMocks + private GitHeadModifier modifier; + + @Test + public void testEnsure() throws IOException, GitAPIException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + File headFile = create(repository, "master"); + + boolean result = modifier.ensure(repository, "develop"); + + assertEquals("ref: refs/heads/develop", Files.readFirstLine(headFile, Charsets.UTF_8)); + assertTrue(result); + } + + @Test + public void testEnsureWithSameBranch() throws IOException, GitAPIException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + create(repository, "develop"); + + boolean result = modifier.ensure(repository, "develop"); + + assertFalse(result); + } + + private File create(Repository repository, String head) throws IOException, GitAPIException { + File directory = temporaryFolder.newFolder(); + + Git.init() + .setBare(true) + .setDirectory(directory) + .call(); + + File headFile = new File(directory, "HEAD"); + Files.write(String.format("ref: refs/heads/%s\n", head), headFile, Charsets.UTF_8); + + when(repositoryHandler.getDirectory(repository)).thenReturn(directory); + + return headFile; + } + +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java index 008000daef..5f0f0aca29 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java @@ -52,9 +52,6 @@ import sonia.scm.HandlerEvent; @RunWith(MockitoJUnitRunner.class) public class GitRepositoryModifyListenerTest { - @Mock - private GitHeadResolver headResolver; - @Mock private GitHeadModifier headModifier; @@ -162,34 +159,19 @@ public class GitRepositoryModifyListenerTest { Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - when(headResolver.resolve(current)).thenReturn("master"); - RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - verify(headModifier).modify(current, "develop"); + verify(headModifier).ensure(current, "develop"); } - @Test - public void testWithEqualHeads() { - Repository old = RepositoryTestData.createHeartOfGold("git"); - Repository current = RepositoryTestData.createHeartOfGold("git"); - current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - - when(headResolver.resolve(current)).thenReturn("develop"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); - repositoryModifyListener.handleEvent(event); - - verify(headModifier, never()).modify(current, "develop"); - } private static class GitRepositoryModifyTestListener extends GitRepositoryModifyListener { private Repository repository; - public GitRepositoryModifyTestListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { - super(headResolver, headModifier); + public GitRepositoryModifyTestListener(GitHeadModifier headModifier) { + super(headModifier); } @Override From c188e2cd96419471e0d7d37bb6cc25be369187e2 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 19 Oct 2018 18:55:14 +0200 Subject: [PATCH 083/178] close branch issue-998 From decc6d29d83937edd30d565f45e689738cdad8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 22 Jan 2019 10:18:17 +0100 Subject: [PATCH 084/178] Rename Permission -> RepositoryPermission --- .../java/sonia/scm/api/v2/resources/MapperModule.java | 2 +- ...toryPermissionDtoToRepositoryPermissionMapper.java} | 2 +- ...urce.java => RepositoryPermissionRootResource.java} | 6 +++--- .../sonia/scm/api/v2/resources/RepositoryResource.java | 6 +++--- .../java/sonia/scm/api/v2/resources/ResourceLinks.java | 2 +- ....java => RepositoryPermissionRootResourceTest.java} | 10 +++++----- .../sonia/scm/api/v2/resources/RepositoryTestBase.java | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) rename scm-webapp/src/main/java/sonia/scm/api/v2/resources/{PermissionDtoToPermissionMapper.java => RepositoryPermissionDtoToRepositoryPermissionMapper.java} (88%) rename scm-webapp/src/main/java/sonia/scm/api/v2/resources/{PermissionRootResource.java => RepositoryPermissionRootResource.java} (96%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{PermissionRootResourceTest.java => RepositoryPermissionRootResourceTest.java} (97%) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java index 4cf66f7b28..859a6481f6 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java @@ -25,7 +25,7 @@ public class MapperModule extends AbstractModule { bind(RepositoryTypeCollectionToDtoMapper.class); bind(BranchToBranchDtoMapper.class).to(Mappers.getMapper(BranchToBranchDtoMapper.class).getClass()); - bind(PermissionDtoToPermissionMapper.class).to(Mappers.getMapper(PermissionDtoToPermissionMapper.class).getClass()); + bind(RepositoryPermissionDtoToRepositoryPermissionMapper.class).to(Mappers.getMapper(RepositoryPermissionDtoToRepositoryPermissionMapper.class).getClass()); bind(RepositoryPermissionToRepositoryPermissionDtoMapper.class).to(Mappers.getMapper(RepositoryPermissionToRepositoryPermissionDtoMapper.class).getClass()); bind(ChangesetToChangesetDtoMapper.class).to(Mappers.getMapper(ChangesetToChangesetDtoMapper.class).getClass()); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionDtoToPermissionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDtoToRepositoryPermissionMapper.java similarity index 88% rename from scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionDtoToPermissionMapper.java rename to scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDtoToRepositoryPermissionMapper.java index 8d9761c28c..43efb19c07 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionDtoToPermissionMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDtoToRepositoryPermissionMapper.java @@ -5,7 +5,7 @@ import org.mapstruct.MappingTarget; import sonia.scm.repository.RepositoryPermission; @Mapper -public abstract class PermissionDtoToPermissionMapper { +public abstract class RepositoryPermissionDtoToRepositoryPermissionMapper { public abstract RepositoryPermission map(RepositoryPermissionDto permissionDto); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java similarity index 96% rename from scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java rename to scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java index cb3821cd67..18db82b91a 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java @@ -35,10 +35,10 @@ import static sonia.scm.NotFoundException.notFound; import static sonia.scm.api.v2.resources.RepositoryPermissionDto.GROUP_PREFIX; @Slf4j -public class PermissionRootResource { +public class RepositoryPermissionRootResource { - private PermissionDtoToPermissionMapper dtoToModelMapper; + private RepositoryPermissionDtoToRepositoryPermissionMapper dtoToModelMapper; private RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper; private RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper; private ResourceLinks resourceLinks; @@ -46,7 +46,7 @@ public class PermissionRootResource { @Inject - public PermissionRootResource(PermissionDtoToPermissionMapper dtoToModelMapper, RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper, RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper, ResourceLinks resourceLinks, RepositoryManager manager) { + public RepositoryPermissionRootResource(RepositoryPermissionDtoToRepositoryPermissionMapper dtoToModelMapper, RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper, RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper, ResourceLinks resourceLinks, RepositoryManager manager) { this.dtoToModelMapper = dtoToModelMapper; this.modelToDtoMapper = modelToDtoMapper; this.repositoryPermissionCollectionToDtoMapper = repositoryPermissionCollectionToDtoMapper; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java index b884a37771..5cc9df38f8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java @@ -39,7 +39,7 @@ public class RepositoryResource { private final Provider changesetRootResource; private final Provider sourceRootResource; private final Provider contentResource; - private final Provider permissionRootResource; + private final Provider permissionRootResource; private final Provider diffRootResource; private final Provider modificationsRootResource; private final Provider fileHistoryRootResource; @@ -54,7 +54,7 @@ public class RepositoryResource { Provider branchRootResource, Provider changesetRootResource, Provider sourceRootResource, Provider contentResource, - Provider permissionRootResource, + Provider permissionRootResource, Provider diffRootResource, Provider modificationsRootResource, Provider fileHistoryRootResource, @@ -194,7 +194,7 @@ public class RepositoryResource { } @Path("permissions/") - public PermissionRootResource permissions() { + public RepositoryPermissionRootResource permissions() { return permissionRootResource.get(); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index be036007be..c7369f7cd0 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -514,7 +514,7 @@ class ResourceLinks { private final LinkBuilder permissionLinkBuilder; RepositoryPermissionLinks(ScmPathInfo pathInfo) { - permissionLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, PermissionRootResource.class); + permissionLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, RepositoryPermissionRootResource.class); } String all(String namespace, String name) { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java similarity index 97% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index 012656c4cd..d1843ef14d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -66,7 +66,7 @@ import static sonia.scm.api.v2.resources.RepositoryPermissionDto.GROUP_PREFIX; password = "secret", configuration = "classpath:sonia/scm/repository/shiro.ini" ) -public class PermissionRootResourceTest extends RepositoryTestBase { +public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { private static final String REPOSITORY_NAMESPACE = "repo_namespace"; private static final String REPOSITORY_NAME = "repo"; private static final String PERMISSION_WRITE = "repository:permissionWrite:" + REPOSITORY_NAME; @@ -124,11 +124,11 @@ public class PermissionRootResourceTest extends RepositoryTestBase { private RepositoryPermissionToRepositoryPermissionDtoMapperImpl permissionToPermissionDtoMapper; @InjectMocks - private PermissionDtoToPermissionMapperImpl permissionDtoToPermissionMapper; + private RepositoryPermissionDtoToRepositoryPermissionMapperImpl permissionDtoToPermissionMapper; private RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper; - private PermissionRootResource permissionRootResource; + private RepositoryPermissionRootResource repositoryPermissionRootResource; private final Subject subject = mock(Subject.class); private final ThreadState subjectThreadState = new SubjectThreadState(subject); @@ -138,8 +138,8 @@ public class PermissionRootResourceTest extends RepositoryTestBase { public void prepareEnvironment() { initMocks(this); repositoryPermissionCollectionToDtoMapper = new RepositoryPermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks); - permissionRootResource = new PermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, repositoryPermissionCollectionToDtoMapper, resourceLinks, repositoryManager); - super.permissionRootResource = Providers.of(permissionRootResource); + repositoryPermissionRootResource = new RepositoryPermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, repositoryPermissionCollectionToDtoMapper, resourceLinks, repositoryManager); + super.permissionRootResource = Providers.of(repositoryPermissionRootResource); dispatcher = createDispatcher(getRepositoryRootResource()); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java index b2daf0536c..a8901e2d79 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java @@ -16,7 +16,7 @@ public abstract class RepositoryTestBase { protected Provider changesetRootResource; protected Provider sourceRootResource; protected Provider contentResource; - protected Provider permissionRootResource; + protected Provider permissionRootResource; protected Provider diffRootResource; protected Provider modificationsRootResource; protected Provider fileHistoryRootResource; From 4dcbcb80e7b125462ad0554b5bd6efb48bd795af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 22 Jan 2019 13:00:02 +0100 Subject: [PATCH 085/178] Remove permissions from repository --- .../java/sonia/scm/repository/Repository.java | 32 +------- .../RepositoryCollectionResource.java | 3 +- .../RepositoryDtoToRepositoryMapper.java | 1 - ...sitoryPermissionCollectionToDtoMapper.java | 11 +-- .../RepositoryPermissionRootResource.java | 50 +++++++------ .../api/v2/resources/RepositoryResource.java | 1 - .../AuthorizationChangedEventProducer.java | 4 +- .../DefaultAuthorizationCollector.java | 7 +- .../RepositoryPermissionAssigner.java | 6 ++ .../RepositoryPermissionRootResourceTest.java | 3 +- .../resources/RepositoryRootResourceTest.java | 35 ++------- .../RepositoryToRepositoryDtoMapperTest.java | 1 - .../DefaultRepositoryManagerPerfTest.java | 2 +- ...AuthorizationChangedEventProducerTest.java | 73 ++++++++++--------- .../DefaultAuthorizationCollectorTest.java | 5 +- 15 files changed, 103 insertions(+), 131 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java index 622eed6ad6..310a0f0556 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Repository.java +++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java @@ -68,7 +68,6 @@ import java.util.Set; @XmlRootElement(name = "repositories") public class Repository extends BasicPropertiesAware implements ModelObject, PermissionObject{ - private static final long serialVersionUID = 3486560714961909711L; private String contact; @@ -81,7 +80,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per private Long lastModified; private String namespace; private String name; - private final Set permissions = new HashSet<>(); @XmlElement(name = "public") private boolean publicReadable = false; private boolean archived = false; @@ -119,20 +117,14 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per * @param contact email address of a person who is responsible for * this repository. * @param description a short description of the repository - * @param permissions permissions for specific users and groups. */ - public Repository(String id, String type, String namespace, String name, String contact, - String description, RepositoryPermission... permissions) { + public Repository(String id, String type, String namespace, String name, String contact, String description) { this.id = id; this.type = type; this.namespace = namespace; this.name = name; this.contact = contact; this.description = description; - - if (Util.isNotEmpty(permissions)) { - this.permissions.addAll(Arrays.asList(permissions)); - } } /** @@ -201,10 +193,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per return new NamespaceAndName(getNamespace(), getName()); } - public Collection getPermissions() { - return Collections.unmodifiableCollection(permissions); - } - /** * Returns the type (hg, git, svn ...) of the {@link Repository}. * @@ -297,19 +285,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per this.name = name; } - public void setPermissions(Collection permissions) { - this.permissions.clear(); - this.permissions.addAll(permissions); - } - - public void addPermission(RepositoryPermission newPermission) { - this.permissions.add(newPermission); - } - - public void removePermission(RepositoryPermission permission) { - this.permissions.remove(permission); - } - public void setPublicReadable(boolean publicReadable) { this.publicReadable = publicReadable; } @@ -347,7 +322,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per repository.setCreationDate(creationDate); repository.setLastModified(lastModified); repository.setDescription(description); - repository.setPermissions(permissions); repository.setPublicReadable(publicReadable); repository.setArchived(archived); @@ -379,7 +353,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per && Objects.equal(description, other.description) && Objects.equal(publicReadable, other.publicReadable) && Objects.equal(archived, other.archived) - && Objects.equal(permissions, other.permissions) && Objects.equal(type, other.type) && Objects.equal(creationDate, other.creationDate) && Objects.equal(lastModified, other.lastModified) @@ -390,7 +363,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per @Override public int hashCode() { return Objects.hashCode(id, namespace, name, contact, description, publicReadable, - archived, permissions, type, creationDate, lastModified, properties, + archived, type, creationDate, lastModified, properties, healthCheckFailures); } @@ -404,7 +377,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per .add("description", description) .add("publicReadable", publicReadable) .add("archived", archived) - .add("permissions", permissions) .add("type", type) .add("lastModified", lastModified) .add("creationDate", creationDate) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java index 420e08fe96..e53db7ba13 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java @@ -100,7 +100,8 @@ public class RepositoryCollectionResource { private Repository createModelObjectFromDto(@Valid RepositoryDto repositoryDto) { Repository repository = dtoToRepositoryMapper.map(repositoryDto, null); - repository.setPermissions(singletonList(new RepositoryPermission(currentUser(), PermissionType.OWNER))); + // TODO RP +// repository.setPermissions(singletonList(new RepositoryPermission(currentUser(), PermissionType.OWNER))); return repository; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDtoToRepositoryMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDtoToRepositoryMapper.java index b7058d2830..b9add14529 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDtoToRepositoryMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDtoToRepositoryMapper.java @@ -10,7 +10,6 @@ public abstract class RepositoryDtoToRepositoryMapper extends BaseDtoMapper { @Mapping(target = "id", ignore = true) @Mapping(target = "publicReadable", ignore = true) @Mapping(target = "healthCheckFailures", ignore = true) - @Mapping(target = "permissions", ignore = true) public abstract Repository map(RepositoryDto repositoryDto, @Context String id); @AfterMapping diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java index 5e678212e8..9c05f80de4 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java @@ -26,11 +26,12 @@ public class RepositoryPermissionCollectionToDtoMapper { } public HalRepresentation map(Repository repository) { - List repositoryPermissionDtoList = repository.getPermissions() - .stream() - .map(permission -> repositoryPermissionToRepositoryPermissionDtoMapper.map(permission, repository)) - .collect(toList()); - return new HalRepresentation(createLinks(repository), embedDtos(repositoryPermissionDtoList)); +// List repositoryPermissionDtoList = repository.getPermissions() +// .stream() +// .map(permission -> repositoryPermissionToRepositoryPermissionDtoMapper.map(permission, repository)) +// .collect(toList()); +// return new HalRepresentation(createLinks(repository), embedDtos(repositoryPermissionDtoList)); + return new HalRepresentation(createLinks(repository)); } private Links createLinks(Repository repository) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java index 18db82b91a..9c22a5e1b0 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java @@ -78,7 +78,8 @@ public class RepositoryPermissionRootResource { Repository repository = load(namespace, name); RepositoryPermissions.permissionWrite(repository).check(); checkPermissionAlreadyExists(permission, repository); - repository.addPermission(dtoToModelMapper.map(permission)); + // TODO RP +// repository.addPermission(dtoToModelMapper.map(permission)); manager.modify(repository); String urlPermissionName = modelToDtoMapper.getUrlPermissionName(permission); return Response.created(URI.create(resourceLinks.repositoryPermission().self(namespace, name, urlPermissionName))).build(); @@ -106,12 +107,13 @@ public class RepositoryPermissionRootResource { Repository repository = load(namespace, name); RepositoryPermissions.permissionRead(repository).check(); return Response.ok( - repository.getPermissions() - .stream() - .filter(filterPermission(permissionName)) - .map(permission -> modelToDtoMapper.map(permission, repository)) - .findFirst() - .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))) + // TODO RP +// repository.getPermissions() +// .stream() +// .filter(filterPermission(permissionName)) +// .map(permission -> modelToDtoMapper.map(permission, repository)) +// .findFirst() +// .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))) ).build(); } @@ -172,12 +174,14 @@ public class RepositoryPermissionRootResource { if (!extractedPermissionName.equals(permission.getName())) { checkPermissionAlreadyExists(permission, repository); } - RepositoryPermission existingPermission = repository.getPermissions() - .stream() - .filter(filterPermission(permissionName)) - .findFirst() - .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))); - dtoToModelMapper.modify(existingPermission, permission); + + // TODO RP +// RepositoryPermission existingPermission = repository.getPermissions() +// .stream() +// .filter(filterPermission(permissionName)) +// .findFirst() +// .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))); +// dtoToModelMapper.modify(existingPermission, permission); manager.modify(repository); log.info("the permission with name: {} is updated.", permissionName); return Response.noContent().build(); @@ -204,12 +208,13 @@ public class RepositoryPermissionRootResource { log.info("try to delete the permission with name: {}.", permissionName); Repository repository = load(namespace, name); RepositoryPermissions.modify(repository).check(); - repository.getPermissions() - .stream() - .filter(filterPermission(permissionName)) - .findFirst() - .ifPresent(repository::removePermission) - ; + // TODO RP +// repository.getPermissions() +// .stream() +// .filter(filterPermission(permissionName)) +// .findFirst() +// .ifPresent(repository::removePermission) +// ; manager.modify(repository); log.info("the permission with name: {} is updated.", permissionName); return Response.noContent().build(); @@ -261,9 +266,10 @@ public class RepositoryPermissionRootResource { } private boolean isPermissionExist(RepositoryPermissionDto permission, Repository repository) { - return repository.getPermissions() - .stream() - .anyMatch(p -> p.getName().equals(permission.getName()) && p.isGroupPermission() == permission.isGroupPermission()); + return true; +// return repository.getPermissions() +// .stream() +// .anyMatch(p -> p.getName().equals(permission.getName()) && p.isGroupPermission() == permission.isGroupPermission()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java index 5cc9df38f8..e8c303e0f8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java @@ -154,7 +154,6 @@ public class RepositoryResource { private Repository processUpdate(RepositoryDto repositoryDto, Repository existing) { Repository changedRepository = dtoToRepositoryMapper.map(repositoryDto, existing.getId()); - changedRepository.setPermissions(existing.getPermissions()); return changedRepository; } diff --git a/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java b/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java index 0586db2bb3..c3e7dc4f0c 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java +++ b/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java @@ -167,7 +167,9 @@ public class AuthorizationChangedEventProducer { private boolean isAuthorizationDataModified(Repository repository, Repository beforeModification) { return repository.isArchived() != beforeModification.isArchived() || repository.isPublicReadable() != beforeModification.isPublicReadable() - || !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions())); + // TODO RP +// || !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions())) + ; } private void fireEventForEveryUser() { diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java index a5d99c2928..76dc036e25 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java @@ -63,6 +63,7 @@ import sonia.scm.user.UserPermissions; import sonia.scm.util.Util; import java.util.Collection; +import java.util.Collections; import java.util.Set; //~--- JDK imports ------------------------------------------------------------ @@ -198,8 +199,12 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector private void collectRepositoryPermissions(Builder builder, Repository repository, User user, GroupNames groups) { + + // TODO RP + Collection repositoryPermissions - = repository.getPermissions(); + = Collections.emptyList(); +// = repository.getPermissions(); if (Util.isNotEmpty(repositoryPermissions)) { diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java new file mode 100644 index 0000000000..5d0da1ae1c --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java @@ -0,0 +1,6 @@ +package sonia.scm.security; + +public class RepositoryPermissionAssigner { + + +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index d1843ef14d..48ff451298 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -412,7 +412,8 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { } private void createUserWithRepositoryAndPermissions(ArrayList permissions, String userPermission) { - createUserWithRepository(userPermission).setPermissions(permissions); + // TODO RP +// createUserWithRepository(userPermission).setPermissions(permissions); } private Stream createDynamicTestsToAssertResponses(ExpectedRequest... expectedRequests) { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 1677be95b1..bdb58fb73b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -291,34 +291,13 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { dispatcher.invoke(request, response); - Assertions.assertThat(createCaptor.getValue().getPermissions()) - .hasSize(1) - .allSatisfy(p -> { - assertThat(p.getName()).isEqualTo("trillian"); - assertThat(p.getType()).isEqualTo(PermissionType.OWNER); - }); - } - - @Test - public void shouldNotOverwriteExistingPermissionsOnUpdate() throws Exception { - Repository existingRepository = mockRepository("space", "repo"); - existingRepository.setPermissions(singletonList(new RepositoryPermission("user", PermissionType.READ))); - - URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json"); - byte[] repository = Resources.toByteArray(url); - - ArgumentCaptor modifiedRepositoryCaptor = forClass(Repository.class); - doNothing().when(repositoryManager).modify(modifiedRepositoryCaptor.capture()); - - MockHttpRequest request = MockHttpRequest - .put("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo") - .contentType(VndMediaType.REPOSITORY) - .content(repository); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertFalse(modifiedRepositoryCaptor.getValue().getPermissions().isEmpty()); + // TODO RP +// Assertions.assertThat(createCaptor.getValue().getPermissions()) +// .hasSize(1) +// .allSatisfy(p -> { +// assertThat(p.getName()).isEqualTo("trillian"); +// assertThat(p.getType()).isEqualTo(PermissionType.OWNER); +// }); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java index 9bf70093fd..c9e33d6727 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java @@ -238,7 +238,6 @@ public class RepositoryToRepositoryDtoMapperTest { repository.setId("1"); repository.setCreationDate(System.currentTimeMillis()); repository.setHealthCheckFailures(singletonList(new HealthCheckFailure("1", "summary", "url", "failure"))); - repository.setPermissions(singletonList(new RepositoryPermission("permission", PermissionType.READ))); return repository; } diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java index 146810e787..8c643d59a2 100644 --- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java +++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java @@ -184,7 +184,7 @@ private long calculateAverage(List times) { private Repository createTestRepository(int number) { Repository repository = new Repository(keyGenerator.createKey(), REPOSITORY_TYPE, "namespace", "repo-" + number); - repository.addPermission(new RepositoryPermission("trillian", PermissionType.READ)); +// repository.addPermission(new RepositoryPermission("trillian", PermissionType.READ)); return repository; } diff --git a/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java b/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java index ab8ce5dce8..abc0b33626 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java @@ -172,42 +172,43 @@ public class AuthorizationChangedEventProducerTest { @Test public void testOnRepositoryModificationEvent() { - Repository repositoryModified = RepositoryTestData.createHeartOfGold(); - repositoryModified.setName("test123"); - repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); - - Repository repository = RepositoryTestData.createHeartOfGold(); - repository.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); - - producer.onEvent(new RepositoryModificationEvent(HandlerEventType.BEFORE_CREATE, repositoryModified, repository)); - assertEventIsNotFired(); - - producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); - assertEventIsNotFired(); - - repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); - producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); - assertEventIsNotFired(); - - repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test123"))); - producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); - assertGlobalEventIsFired(); - - resetStoredEvent(); - - repositoryModified.setPermissions( - Lists.newArrayList(new RepositoryPermission("test", PermissionType.READ, true)) - ); - producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); - assertGlobalEventIsFired(); - - resetStoredEvent(); - - repositoryModified.setPermissions( - Lists.newArrayList(new RepositoryPermission("test", PermissionType.WRITE)) - ); - producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); - assertGlobalEventIsFired(); + // TODO RP +// Repository repositoryModified = RepositoryTestData.createHeartOfGold(); +// repositoryModified.setName("test123"); +// repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); +// +// Repository repository = RepositoryTestData.createHeartOfGold(); +// repository.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); +// +// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.BEFORE_CREATE, repositoryModified, repository)); +// assertEventIsNotFired(); +// +// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); +// assertEventIsNotFired(); +// +// repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); +// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); +// assertEventIsNotFired(); +// +// repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test123"))); +// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); +// assertGlobalEventIsFired(); +// +// resetStoredEvent(); +// +// repositoryModified.setPermissions( +// Lists.newArrayList(new RepositoryPermission("test", PermissionType.READ, true)) +// ); +// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); +// assertGlobalEventIsFired(); +// +// resetStoredEvent(); +// +// repositoryModified.setPermissions( +// Lists.newArrayList(new RepositoryPermission("test", PermissionType.WRITE)) +// ); +// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); +// assertGlobalEventIsFired(); } private void resetStoredEvent(){ diff --git a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java index 3b3a28861f..2a7a0fa328 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java @@ -225,11 +225,12 @@ public class DefaultAuthorizationCollectorTest { authenticate(UserTestData.createTrillian(), group); Repository heartOfGold = RepositoryTestData.createHeartOfGold(); heartOfGold.setId("one"); - heartOfGold.setPermissions(Lists.newArrayList(new RepositoryPermission("trillian"))); + // TODO RP +// heartOfGold.setPermissions(Lists.newArrayList(new RepositoryPermission("trillian"))); Repository puzzle42 = RepositoryTestData.create42Puzzle(); puzzle42.setId("two"); RepositoryPermission permission = new RepositoryPermission(group, PermissionType.WRITE, true); - puzzle42.setPermissions(Lists.newArrayList(permission)); +// puzzle42.setPermissions(Lists.newArrayList(permission)); when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold, puzzle42)); // execute and assert From 707d63426b2e19d22bdc78073b815642b9f98184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 22 Jan 2019 13:28:52 +0100 Subject: [PATCH 086/178] Remove enum PermissionType --- .../sonia/scm/repository/PermissionType.java | 99 -------- .../scm/repository/RepositoryPermission.java | 66 ++--- .../api/IncomingCommandBuilder.java | 6 +- .../api/OutgoingCommandBuilder.java | 6 +- .../repository/api/PullCommandBuilder.java | 15 +- .../repository/api/PushCommandBuilder.java | 7 +- .../scm/security/RepositoryPermission.java | 230 ------------------ .../security/RepositoryPermissionTest.java | 87 ------- .../java/sonia/scm/it/PermissionsITCase.java | 14 +- .../java/sonia/scm/it/utils/TestData.java | 34 +-- .../java/sonia/scm/api/rest/Permission.java | 168 ------------- .../RepositoryCollectionResource.java | 4 - .../DefaultAuthorizationCollector.java | 2 +- .../RepositoryPermissionRootResourceTest.java | 19 +- ...onToRepositoryPermissionDtoMapperTest.java | 5 +- .../resources/RepositoryRootResourceTest.java | 5 - .../RepositoryToRepositoryDtoMapperTest.java | 2 - .../test/java/sonia/scm/it/GitLfsITCase.java | 17 +- ...AuthorizationChangedEventProducerTest.java | 4 - .../DefaultAuthorizationCollectorTest.java | 3 +- 20 files changed, 71 insertions(+), 722 deletions(-) delete mode 100644 scm-core/src/main/java/sonia/scm/repository/PermissionType.java delete mode 100644 scm-core/src/main/java/sonia/scm/security/RepositoryPermission.java delete mode 100644 scm-core/src/test/java/sonia/scm/security/RepositoryPermissionTest.java delete mode 100644 scm-webapp/src/main/java/sonia/scm/api/rest/Permission.java diff --git a/scm-core/src/main/java/sonia/scm/repository/PermissionType.java b/scm-core/src/main/java/sonia/scm/repository/PermissionType.java deleted file mode 100644 index bba0d44f3d..0000000000 --- a/scm-core/src/main/java/sonia/scm/repository/PermissionType.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * 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.repository; - -/** - * Type of permissionPrefix for a {@link Repository}. - * - * @author Sebastian Sdorra - */ -public enum PermissionType -{ - - /** read permision */ - READ(0, "repository:read,pull:"), - - /** read and write permissionPrefix */ - WRITE(10, "repository:read,pull,push:"), - - /** - * read, write and - * also the ability to manage the properties and permissions - */ - OWNER(100, "repository:*:"); - - /** - * Constructs a new permissionPrefix type - * - * - * @param value - */ - private PermissionType(int value, String permissionPrefix) - { - this.value = value; - this.permissionPrefix = permissionPrefix; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * - * @return - * - * @since 2.0.0 - */ - public String getPermissionPrefix() - { - return permissionPrefix; - } - - /** - * Returns the integer representation of the {@link PermissionType} - * - * - * @return integer representation - */ - public int getValue() - { - return value; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private final String permissionPrefix; - - /** Field description */ - private final int value; -} diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java index 0aff771fce..492142674d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java @@ -60,54 +60,18 @@ public class RepositoryPermission implements PermissionObject, Serializable private boolean groupPermission = false; private String name; - private PermissionType type = PermissionType.READ; + private String verb; /** * Constructs a new {@link RepositoryPermission}. - * This constructor is used by JAXB. - * + * This constructor is used by JAXB and mapstruct. */ public RepositoryPermission() {} - /** - * Constructs a new {@link RepositoryPermission} with type = {@link PermissionType#READ} - * for the specified user. - * - * - * @param name name of the user - */ - public RepositoryPermission(String name) + public RepositoryPermission(String name, String verb, boolean groupPermission) { - this(); this.name = name; - } - - /** - * Constructs a new {@link RepositoryPermission} with the specified type for - * the given user. - * - * - * @param name name of the user - * @param type type of the permission - */ - public RepositoryPermission(String name, PermissionType type) - { - this(name); - this.type = type; - } - - /** - * Constructs a new {@link RepositoryPermission} with the specified type for - * the given user or group. - * - * - * @param name name of the user or group - * @param type type of the permission - * @param groupPermission true if the permission is a permission for a group - */ - public RepositoryPermission(String name, PermissionType type, boolean groupPermission) - { - this(name, type); + this.verb = verb; this.groupPermission = groupPermission; } @@ -137,7 +101,7 @@ public class RepositoryPermission implements PermissionObject, Serializable final RepositoryPermission other = (RepositoryPermission) obj; return Objects.equal(name, other.name) - && Objects.equal(type, other.type) + && Objects.equal(verb, other.verb) && Objects.equal(groupPermission, other.groupPermission); } @@ -150,7 +114,7 @@ public class RepositoryPermission implements PermissionObject, Serializable @Override public int hashCode() { - return Objects.hashCode(name, type, groupPermission); + return Objects.hashCode(name, verb, groupPermission); } @@ -160,7 +124,7 @@ public class RepositoryPermission implements PermissionObject, Serializable //J- return MoreObjects.toStringHelper(this) .add("name", name) - .add("type", type) + .add("verb", verb) .add("groupPermission", groupPermission) .toString(); //J+ @@ -181,14 +145,14 @@ public class RepositoryPermission implements PermissionObject, Serializable } /** - * Returns the {@link PermissionType} of the permission. + * Returns the verb of the permission. * * - * @return {@link PermissionType} of the permission + * @return verb of the permission */ - public PermissionType getType() + public String getVerb() { - return type; + return verb; } /** @@ -228,13 +192,13 @@ public class RepositoryPermission implements PermissionObject, Serializable } /** - * Sets the type of the permission. + * Sets the verb of the permission. * * - * @param type type of the permission + * @param verb verb of the permission */ - public void setType(PermissionType type) + public void setVerb(String verb) { - this.type = type; + this.verb = verb; } } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/IncomingCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/IncomingCommandBuilder.java index 6c7c620fa4..6098bdf92b 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/IncomingCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/IncomingCommandBuilder.java @@ -39,12 +39,11 @@ import org.apache.shiro.subject.Subject; import sonia.scm.cache.CacheManager; import sonia.scm.repository.Changeset; import sonia.scm.repository.ChangesetPagingResult; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.PreProcessorUtil; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.spi.IncomingCommand; import sonia.scm.repository.spi.IncomingCommandRequest; -import sonia.scm.security.RepositoryPermission; import java.io.IOException; @@ -94,8 +93,7 @@ public final class IncomingCommandBuilder { Subject subject = SecurityUtils.getSubject(); - subject.checkPermission(new RepositoryPermission(remoteRepository, - PermissionType.READ)); + subject.isPermitted(RepositoryPermissions.pull(remoteRepository).asShiroString()); request.setRemoteRepository(remoteRepository); diff --git a/scm-core/src/main/java/sonia/scm/repository/api/OutgoingCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/OutgoingCommandBuilder.java index 2753128eac..d39c95e0e2 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/OutgoingCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/OutgoingCommandBuilder.java @@ -34,12 +34,11 @@ import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import sonia.scm.cache.CacheManager; import sonia.scm.repository.ChangesetPagingResult; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.PreProcessorUtil; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.spi.OutgoingCommand; import sonia.scm.repository.spi.OutgoingCommandRequest; -import sonia.scm.security.RepositoryPermission; import java.io.IOException; @@ -84,8 +83,7 @@ public final class OutgoingCommandBuilder { Subject subject = SecurityUtils.getSubject(); - subject.checkPermission(new RepositoryPermission(remoteRepository, - PermissionType.READ)); + subject.isPermitted(RepositoryPermissions.pull(remoteRepository).asShiroString()); request.setRemoteRepository(remoteRepository); diff --git a/scm-core/src/main/java/sonia/scm/repository/api/PullCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/PullCommandBuilder.java index a0f5ff4115..969ec6ef11 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/PullCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/PullCommandBuilder.java @@ -38,11 +38,10 @@ import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.spi.PullCommand; import sonia.scm.repository.spi.PullCommandRequest; -import sonia.scm.security.RepositoryPermission; import java.io.IOException; import java.net.URL; @@ -96,9 +95,7 @@ public final class PullCommandBuilder public PullResponse pull(String url) throws IOException { Subject subject = SecurityUtils.getSubject(); //J- - subject.checkPermission( - new RepositoryPermission(localRepository, PermissionType.WRITE) - ); + subject.isPermitted(RepositoryPermissions.push(localRepository).asShiroString()); //J+ URL remoteUrl = new URL(url); @@ -124,12 +121,8 @@ public final class PullCommandBuilder Subject subject = SecurityUtils.getSubject(); //J- - subject.checkPermission( - new RepositoryPermission(localRepository, PermissionType.WRITE) - ); - subject.checkPermission( - new RepositoryPermission(remoteRepository, PermissionType.READ) - ); + subject.isPermitted(RepositoryPermissions.push(localRepository).asShiroString()); + subject.isPermitted(RepositoryPermissions.push(remoteRepository).asShiroString()); //J+ request.reset(); diff --git a/scm-core/src/main/java/sonia/scm/repository/api/PushCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/PushCommandBuilder.java index 7b318e49ec..a734225281 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/PushCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/PushCommandBuilder.java @@ -39,11 +39,10 @@ import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.spi.PushCommand; import sonia.scm.repository.spi.PushCommandRequest; -import sonia.scm.security.RepositoryPermission; import java.io.IOException; import java.net.URL; @@ -92,9 +91,7 @@ public final class PushCommandBuilder Subject subject = SecurityUtils.getSubject(); //J- - subject.checkPermission( - new RepositoryPermission(remoteRepository, PermissionType.WRITE) - ); + subject.isPermitted(RepositoryPermissions.push(remoteRepository).asShiroString()); //J+ logger.info("push changes to repository {}", remoteRepository.getId()); diff --git a/scm-core/src/main/java/sonia/scm/security/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/security/RepositoryPermission.java deleted file mode 100644 index 1b0229d6f5..0000000000 --- a/scm-core/src/main/java/sonia/scm/security/RepositoryPermission.java +++ /dev/null @@ -1,230 +0,0 @@ -/** - * 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.security; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.base.MoreObjects; -import com.google.common.base.Objects; -import org.apache.shiro.authz.Permission; -import sonia.scm.repository.PermissionType; -import sonia.scm.repository.Repository; - -import java.io.Serializable; - -//~--- JDK imports ------------------------------------------------------------ - -/** - * This class represents the permission to a repository of a user. - * - * @author Sebastian Sdorra - * @since 1.21 - */ -public final class RepositoryPermission - implements StringablePermission, Serializable -{ - - /** - * Type string of the permission - * @since 1.31 - */ - public static final String TYPE = "repository"; - - /** Field description */ - public static final String WILDCARD = "*"; - - /** Field description */ - private static final long serialVersionUID = 3832804235417228043L; - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param repository - * @param permissionType - */ - public RepositoryPermission(Repository repository, - PermissionType permissionType) - { - this(repository.getId(), permissionType); - } - - /** - * Constructs ... - * - * - * @param repositoryId - * @param permissionType - */ - public RepositoryPermission(String repositoryId, - PermissionType permissionType) - { - this.repositoryId = repositoryId; - this.permissionType = permissionType; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param obj - * - * @return - */ - @Override - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - - if (getClass() != obj.getClass()) - { - return false; - } - - final RepositoryPermission other = (RepositoryPermission) obj; - - return Objects.equal(repositoryId, other.repositoryId) - && Objects.equal(permissionType, other.permissionType); - } - - /** - * Method description - * - * - * @return - */ - @Override - public int hashCode() - { - return Objects.hashCode(repositoryId, permissionType); - } - - /** - * Method description - * - * - * @param p - * - * @return - */ - @Override - public boolean implies(Permission p) - { - boolean result = false; - - if (p instanceof RepositoryPermission) - { - RepositoryPermission rp = (RepositoryPermission) p; - - //J- - result = (repositoryId.equals(WILDCARD) || repositoryId.equals(rp.repositoryId)) - && (permissionType.getValue() >= rp.permissionType.getValue()); - //J+ - } - - return result; - } - - /** - * Method description - * - * - * @return - */ - @Override - public String toString() - { - //J- - return MoreObjects.toStringHelper(this) - .add("repositoryId", repositoryId) - .add("permissionType", permissionType) - .toString(); - //J+ - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - @Override - public String getAsString() - { - StringBuilder buffer = new StringBuilder(TYPE); - - buffer.append(":").append(repositoryId).append(":").append(permissionType); - - return buffer.toString(); - } - - /** - * Method description - * - * - * @return - */ - public PermissionType getPermissionType() - { - return permissionType; - } - - /** - * Method description - * - * - * @return - */ - public String getRepositoryId() - { - return repositoryId; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private PermissionType permissionType; - - /** Field description */ - private String repositoryId; -} diff --git a/scm-core/src/test/java/sonia/scm/security/RepositoryPermissionTest.java b/scm-core/src/test/java/sonia/scm/security/RepositoryPermissionTest.java deleted file mode 100644 index e8180ca24a..0000000000 --- a/scm-core/src/test/java/sonia/scm/security/RepositoryPermissionTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * 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.security; - -//~--- non-JDK imports -------------------------------------------------------- - -import org.junit.Test; - -import sonia.scm.repository.PermissionType; - -import static org.junit.Assert.*; - -/** - * - * @author Sebastian Sdorra - */ -public class RepositoryPermissionTest -{ - - /** - * Method description - * - */ - @Test - public void testImplies() - { - RepositoryPermission p = new RepositoryPermission("asd", - PermissionType.READ); - - assertTrue(p.implies(new RepositoryPermission("asd", PermissionType.READ))); - assertFalse(p.implies(new RepositoryPermission("asd", - PermissionType.OWNER))); - assertFalse(p.implies(new RepositoryPermission("asd", - PermissionType.WRITE))); - p = new RepositoryPermission("asd", PermissionType.OWNER); - assertTrue(p.implies(new RepositoryPermission("asd", PermissionType.READ))); - assertFalse(p.implies(new RepositoryPermission("bdb", - PermissionType.READ))); - } - - /** - * Method description - * - */ - @Test - public void testImpliesWithWildcard() - { - RepositoryPermission p = new RepositoryPermission("*", - PermissionType.OWNER); - - assertTrue(p.implies(new RepositoryPermission("asd", PermissionType.READ))); - assertTrue(p.implies(new RepositoryPermission("bdb", - PermissionType.OWNER))); - assertTrue(p.implies(new RepositoryPermission("cgd", - PermissionType.WRITE))); - } -} diff --git a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java index aa91e67022..15f5e30abc 100644 --- a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java @@ -42,7 +42,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import sonia.scm.it.utils.RepositoryUtil; import sonia.scm.it.utils.TestData; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.client.api.RepositoryClient; import sonia.scm.repository.client.api.RepositoryClientException; import sonia.scm.web.VndMediaType; @@ -91,12 +90,13 @@ public class PermissionsITCase { public void prepareEnvironment() { TestData.createDefault(); TestData.createNotAdminUser(USER_READ, USER_PASS); - TestData.createUserPermission(USER_READ, PermissionType.READ, repositoryType); - TestData.createNotAdminUser(USER_WRITE, USER_PASS); - TestData.createUserPermission(USER_WRITE, PermissionType.WRITE, repositoryType); - TestData.createNotAdminUser(USER_OWNER, USER_PASS); - TestData.createUserPermission(USER_OWNER, PermissionType.OWNER, repositoryType); - TestData.createNotAdminUser(USER_OTHER, USER_PASS); + // TODO RP +// TestData.createUserPermission(USER_READ, PermissionType.READ, repositoryType); +// TestData.createNotAdminUser(USER_WRITE, USER_PASS); +// TestData.createUserPermission(USER_WRITE, PermissionType.WRITE, repositoryType); +// TestData.createNotAdminUser(USER_OWNER, USER_PASS); +// TestData.createUserPermission(USER_OWNER, PermissionType.OWNER, repositoryType); +// TestData.createNotAdminUser(USER_OTHER, USER_PASS); createdPermissions = asList(USER_READ, USER_WRITE, USER_OWNER); } diff --git a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java index 48605437c6..fb92628287 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java @@ -4,7 +4,6 @@ import io.restassured.response.ValidatableResponse; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.PermissionType; import sonia.scm.web.VndMediaType; import javax.json.Json; @@ -82,22 +81,23 @@ public class TestData { ; } - public static void createUserPermission(String name, PermissionType permissionType, String repositoryType) { - String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType); - LOG.info("create permission with name {} and type: {} using the endpoint: {}", name, permissionType, defaultPermissionUrl); - given(VndMediaType.PERMISSION) - .when() - .content("{\n" + - "\t\"type\": \"" + permissionType.name() + "\",\n" + - "\t\"name\": \"" + name + "\",\n" + - "\t\"groupPermission\": false\n" + - "\t\n" + - "}") - .post(defaultPermissionUrl) - .then() - .statusCode(HttpStatus.SC_CREATED) - ; - } + // TODO RP +// public static void createUserPermission(String name, PermissionType permissionType, String repositoryType) { +// String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType); +// LOG.info("create permission with name {} and type: {} using the endpoint: {}", name, permissionType, defaultPermissionUrl); +// given(VndMediaType.PERMISSION) +// .when() +// .content("{\n" + +// "\t\"type\": \"" + permissionType.name() + "\",\n" + +// "\t\"name\": \"" + name + "\",\n" + +// "\t\"groupPermission\": false\n" + +// "\t\n" + +// "}") +// .post(defaultPermissionUrl) +// .then() +// .statusCode(HttpStatus.SC_CREATED) +// ; +// } public static List getUserPermissions(String username, String password, String repositoryType) { return callUserPermissions(username, password, repositoryType, HttpStatus.SC_OK) diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/Permission.java b/scm-webapp/src/main/java/sonia/scm/api/rest/Permission.java deleted file mode 100644 index ba707c19c2..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/Permission.java +++ /dev/null @@ -1,168 +0,0 @@ -/** - * 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.api.rest; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.base.MoreObjects; -import com.google.common.base.Objects; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlRootElement; -import java.io.Serializable; - -//~--- JDK imports ------------------------------------------------------------ - -/** - * - * @author Sebastian Sdorra - */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.FIELD) -public class Permission implements Serializable -{ - - /** Field description */ - private static final long serialVersionUID = 4320217034601679261L; - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - public Permission() {} - - /** - * Constructs ... - * - * - * @param id - * @param value - */ - public Permission(String id, String value) - { - this.id = id; - this.value = value; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param obj - * - * @return - */ - @Override - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - - if (getClass() != obj.getClass()) - { - return false; - } - - final Permission other = (Permission) obj; - - return Objects.equal(id, other.id) && Objects.equal(value, other.value); - } - - /** - * Method description - * - * - * @return - */ - @Override - public int hashCode() - { - return Objects.hashCode(id, value); - } - - /** - * Method description - * - * - * @return - */ - @Override - public String toString() - { - //J- - return MoreObjects.toStringHelper(this) - .add("id", id) - .add("value", value) - .toString(); - //J+ - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - public String getId() - { - return id; - } - - /** - * Method description - * - * - * @return - */ - public String getValue() - { - return value; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private String id; - - /** Field description */ - private String value; -} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java index e53db7ba13..cfcd279692 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java @@ -6,8 +6,6 @@ import com.webcohesion.enunciate.metadata.rs.ResponseHeaders; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.TypeHint; import org.apache.shiro.SecurityUtils; -import sonia.scm.repository.RepositoryPermission; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.user.User; @@ -24,8 +22,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; -import static java.util.Collections.singletonList; - public class RepositoryCollectionResource { private static final int DEFAULT_PAGE_SIZE = 10; diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java index 76dc036e25..e015ed90f6 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java @@ -214,7 +214,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector hasPermission = isUserPermitted(user, groups, permission); if (hasPermission) { - String perm = permission.getType().getPermissionPrefix().concat(repository.getId()); + String perm = null; // TODO RP permission.getType().getPermissionPrefix().concat(repository.getId()); if (logger.isTraceEnabled()) { logger.trace("add repository permission {} for user {} at repository {}", diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index 48ff451298..b66a274f0d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -30,7 +30,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.RepositoryPermission; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.web.VndMediaType; @@ -79,12 +78,12 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { private static final String PERMISSION_TEST_PAYLOAD = "{ \"name\" : \"permission_name\", \"type\" : \"READ\" }"; private static final ArrayList TEST_PERMISSIONS = Lists .newArrayList( - new RepositoryPermission("user_write", PermissionType.WRITE, false), - new RepositoryPermission("user_read", PermissionType.READ, false), - new RepositoryPermission("user_owner", PermissionType.OWNER, false), - new RepositoryPermission("group_read", PermissionType.READ, true), - new RepositoryPermission("group_write", PermissionType.WRITE, true), - new RepositoryPermission("group_owner", PermissionType.OWNER, true) + new RepositoryPermission("user_write", "read,modify", false), + new RepositoryPermission("user_read", "read", false), + new RepositoryPermission("user_owner", "read,modify,delete", false), + new RepositoryPermission("group_read", "read", true), + new RepositoryPermission("group_write", "read,modify", true), + new RepositoryPermission("group_owner", "read,modify,delete", true) ); private final ExpectedRequest requestGETAllPermissions = new ExpectedRequest() .description("GET all permissions") @@ -259,7 +258,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { @Test public void shouldGetCreatedPermissions() throws URISyntaxException { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); - RepositoryPermission newPermission = new RepositoryPermission("new_group_perm", PermissionType.WRITE, true); + RepositoryPermission newPermission = new RepositoryPermission("new_group_perm", "read,modify", true); ArrayList permissions = Lists.newArrayList(TEST_PERMISSIONS); permissions.add(newPermission); ImmutableList expectedPermissions = ImmutableList.copyOf(permissions); @@ -288,7 +287,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); RepositoryPermission modifiedPermission = TEST_PERMISSIONS.get(0); // modify the type to owner - modifiedPermission.setType(PermissionType.OWNER); + modifiedPermission.setVerb("read,modify,delete"); ImmutableList expectedPermissions = ImmutableList.copyOf(TEST_PERMISSIONS); assertExpectedRequest(requestPUTPermission .content("{\"name\" : \"" + modifiedPermission.getName() + "\" , \"type\" : \"OWNER\" , \"groupPermission\" : false}") @@ -382,7 +381,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { RepositoryPermissionDto result = new RepositoryPermissionDto(); result.setName(permission.getName()); result.setGroupPermission(permission.isGroupPermission()); - result.setType(permission.getType().name()); + result.setType(permission.getVerb()); String permissionName = Optional.of(permission.getName()) .filter(p -> !permission.isGroupPermission()) .orElse(GROUP_PREFIX + permission.getName()); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java index a6ab00db58..09a3ab4855 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java @@ -8,7 +8,6 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.RepositoryPermission; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import java.net.URI; @@ -36,7 +35,7 @@ public class RepositoryPermissionToRepositoryPermissionDtoMapperTest { @SubjectAware(username = "trillian", password = "secret") public void shouldMapGroupPermissionCorrectly() { Repository repository = getDummyRepository(); - RepositoryPermission permission = new RepositoryPermission("42", PermissionType.OWNER, true); + RepositoryPermission permission = new RepositoryPermission("42", "read,modify,delete", true); RepositoryPermissionDto repositoryPermissionDto = mapper.map(permission, repository); @@ -48,7 +47,7 @@ public class RepositoryPermissionToRepositoryPermissionDtoMapperTest { @SubjectAware(username = "trillian", password = "secret") public void shouldMapNonGroupPermissionCorrectly() { Repository repository = getDummyRepository(); - RepositoryPermission permission = new RepositoryPermission("42", PermissionType.OWNER, false); + RepositoryPermission permission = new RepositoryPermission("42", "read,modify,delete", false); RepositoryPermissionDto repositoryPermissionDto = mapper.map(permission, repository); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index bdb58fb73b..a18b63c53f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -6,7 +6,6 @@ import com.google.common.io.Resources; import com.google.inject.util.Providers; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; -import org.assertj.core.api.Assertions; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; @@ -18,8 +17,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.PageResult; import sonia.scm.repository.NamespaceAndName; -import sonia.scm.repository.RepositoryPermission; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryIsNotArchivedException; import sonia.scm.repository.RepositoryManager; @@ -45,11 +42,9 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentCaptor.forClass; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java index c9e33d6727..8469e966c8 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java @@ -10,8 +10,6 @@ import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.repository.HealthCheckFailure; -import sonia.scm.repository.RepositoryPermission; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.RepositoryService; diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index c55a33c39a..242c9b3047 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -50,7 +50,6 @@ import sonia.scm.api.rest.ObjectMapperProvider; import sonia.scm.api.v2.resources.RepositoryDto; import sonia.scm.api.v2.resources.UserDto; import sonia.scm.api.v2.resources.UserToUserDtoMapperImpl; -import sonia.scm.repository.PermissionType; import sonia.scm.user.User; import sonia.scm.user.UserTestData; import sonia.scm.util.HttpUtil; @@ -117,10 +116,17 @@ public class GitLfsITCase { @Test public void testLfsAPIWithOwnerPermissions() throws IOException { - uploadAndDownloadAsUser(PermissionType.OWNER); + // TODO RP + uploadAndDownloadAsUser(); } - private void uploadAndDownloadAsUser(PermissionType permissionType) throws IOException { + @Test + public void testLfsAPIWithWritePermissions() throws IOException { + // TODO RP + uploadAndDownloadAsUser(); + } + + private void uploadAndDownloadAsUser() throws IOException { User trillian = UserTestData.createTrillian(); trillian.setPassword("secret123"); createUser(trillian); @@ -140,11 +146,6 @@ public class GitLfsITCase { } } - @Test - public void testLfsAPIWithWritePermissions() throws IOException { - uploadAndDownloadAsUser(PermissionType.WRITE); - } - private void createUser(User user) { UserDto dto = new UserToUserDtoMapperImpl(){ @Override diff --git a/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java b/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java index abc0b33626..de31aa1298 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java @@ -31,7 +31,6 @@ package sonia.scm.security; -import com.google.common.collect.Lists; import org.junit.Test; import static org.junit.Assert.*; import org.junit.Before; @@ -39,11 +38,8 @@ import sonia.scm.HandlerEventType; import sonia.scm.group.Group; import sonia.scm.group.GroupEvent; import sonia.scm.group.GroupModificationEvent; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryEvent; -import sonia.scm.repository.RepositoryModificationEvent; -import sonia.scm.repository.RepositoryPermission; import sonia.scm.repository.RepositoryTestData; import sonia.scm.user.User; import sonia.scm.user.UserEvent; diff --git a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java index 2a7a0fa328..bfb97d0b40 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java @@ -51,7 +51,6 @@ import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; import sonia.scm.config.ScmConfiguration; import sonia.scm.group.GroupNames; -import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryDAO; import sonia.scm.repository.RepositoryPermission; @@ -229,7 +228,7 @@ public class DefaultAuthorizationCollectorTest { // heartOfGold.setPermissions(Lists.newArrayList(new RepositoryPermission("trillian"))); Repository puzzle42 = RepositoryTestData.create42Puzzle(); puzzle42.setId("two"); - RepositoryPermission permission = new RepositoryPermission(group, PermissionType.WRITE, true); + RepositoryPermission permission = new RepositoryPermission(group, "read,modify", true); // puzzle42.setPermissions(Lists.newArrayList(permission)); when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold, puzzle42)); From 101b21e914c2c153a4867e2acb4f42a99c5ca4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 22 Jan 2019 14:30:56 +0100 Subject: [PATCH 087/178] Read available repository permissions --- .../RepositoryPermissionAssigner.java | 130 ++++++++++++++++++ .../META-INF/scm/repository-permissions.xml | 35 +++++ .../RepositoryPermissionAssignerTest.java | 25 ++++ 3 files changed, 190 insertions(+) create mode 100644 scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml create mode 100644 scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java index 5d0da1ae1c..59bc489144 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java @@ -1,6 +1,136 @@ package sonia.scm.security; +import com.google.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.store.ConfigurationEntryStoreFactory; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.stream.Collectors; + public class RepositoryPermissionAssigner { + private static final Logger logger = LoggerFactory.getLogger(RepositoryPermissionAssigner.class); + private static final String NAME = "permissions"; + private static final String REPOSITORY_PERMISSION_DESCRIPTOR = "META-INF/scm/repository-permissions.xml"; + private final ConfigurationEntryStoreFactory storeFactory; + private final AvailableRepositoryPermissions availablePermissions; + @Inject + public RepositoryPermissionAssigner(ConfigurationEntryStoreFactory storeFactory, PluginLoader pluginLoader) { + this.storeFactory = storeFactory; + this.availablePermissions = readAvailablePermissions(pluginLoader); + } + + public Collection availableVerbs() { + return availablePermissions.availableVerbs; + } + + public Collection availableRoles() { + return availablePermissions.availableRoles; + } + + private static AvailableRepositoryPermissions readAvailablePermissions(PluginLoader pluginLoader) { + Collection availableVerbs = new ArrayList<>(); + Collection availableRoles = new ArrayList<>(); + + try { + JAXBContext context = + JAXBContext.newInstance(RepositoryPermissionsRoot.class); + + // Querying permissions from uberClassLoader returns also the permissions from plugin + Enumeration descriptorEnum = + pluginLoader.getUberClassLoader().getResources(REPOSITORY_PERMISSION_DESCRIPTOR); + + while (descriptorEnum.hasMoreElements()) { + URL descriptorUrl = descriptorEnum.nextElement(); + + logger.debug("read permission descriptor from {}", descriptorUrl); + + RepositoryPermissionsRoot repositoryPermissionsRoot = parsePermissionDescriptor(context, descriptorUrl); + availableVerbs.addAll(repositoryPermissionsRoot.verbs.verbs); + availableRoles.addAll(repositoryPermissionsRoot.roles.roles); + } + } catch (IOException ex) { + logger.error("could not read permission descriptors", ex); + } catch (JAXBException ex) { + logger.error( + "could not create jaxb context to read permission descriptors", ex); + } + + return new AvailableRepositoryPermissions(availableVerbs, availableRoles); + } + + @SuppressWarnings("unchecked") + private static RepositoryPermissionsRoot parsePermissionDescriptor(JAXBContext context, URL descriptorUrl) { + try { + RepositoryPermissionsRoot descriptorWrapper = + (RepositoryPermissionsRoot) context.createUnmarshaller().unmarshal( + descriptorUrl); + logger.trace("permissions from {}: {}", descriptorUrl, descriptorWrapper); + return descriptorWrapper; + } catch (JAXBException ex) { + logger.error("could not parse permission descriptor", ex); + return new RepositoryPermissionsRoot(); + } + } + + private static class AvailableRepositoryPermissions { + private final Collection availableVerbs; + private final Collection availableRoles; + + private AvailableRepositoryPermissions(Collection availableVerbs, Collection availableRoles) { + this.availableVerbs = Collections.unmodifiableCollection(availableVerbs); + this.availableRoles = Collections.unmodifiableCollection(availableRoles); + } + } + + @XmlRootElement(name = "repository-permissions") + @XmlAccessorType(XmlAccessType.FIELD) + private static class RepositoryPermissionsRoot { + private VerbListDescriptor verbs = new VerbListDescriptor(); + private RoleListDescriptor roles = new RoleListDescriptor(); + } + + @XmlRootElement(name = "verbs") + private static class VerbListDescriptor { + @XmlElement(name = "verb") + private List verbs = new ArrayList<>(); + } + + @XmlRootElement(name = "roles") + private static class RoleListDescriptor { + @XmlElement(name = "role") + private List roles = new ArrayList<>(); + } + + @XmlRootElement(name = "role") + @XmlAccessorType(XmlAccessType.FIELD) + public static class RoleDescriptor { + @XmlElement(name = "name") + private String name; + @XmlElement(name = "verbs") + private VerbListDescriptor verbs = new VerbListDescriptor(); + + public Collection getVerbs() { + return Collections.unmodifiableCollection(verbs.verbs); + } + + public String toString() { + return "Role " + name + " (" + verbs.verbs.stream().collect(Collectors.joining(", ")) + ")"; + } + } } diff --git a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml new file mode 100644 index 0000000000..9df450efb0 --- /dev/null +++ b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml @@ -0,0 +1,35 @@ + + + abc + xyz + + + + OWNER + + * + + + + WRITER + + read + push + pull + + + + READER + + read + pull + + + + HEALTH + + healthCheck + + + + diff --git a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java new file mode 100644 index 0000000000..d037c2cbfe --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java @@ -0,0 +1,25 @@ +package sonia.scm.security; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.store.ConfigurationEntryStoreFactory; +import sonia.scm.util.ClassLoaders; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class RepositoryPermissionAssignerTest { + + @Test + void x() { + PluginLoader pluginLoader = mock(PluginLoader.class); + when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class)); + ConfigurationEntryStoreFactory configurationEntryStoreFactory = mock(ConfigurationEntryStoreFactory.class); + RepositoryPermissionAssigner repositoryPermissionAssigner = new RepositoryPermissionAssigner(configurationEntryStoreFactory, pluginLoader); + Assertions.assertThat(repositoryPermissionAssigner.availableVerbs()).isNotEmpty(); + Assertions.assertThat(repositoryPermissionAssigner.availableRoles()).isNotEmpty().noneMatch(r -> r.getVerbs().isEmpty()); + System.out.println(repositoryPermissionAssigner.availableVerbs()); + System.out.println(repositoryPermissionAssigner.availableRoles()); + } +} From 9b4fc5e3d8099854b084f02f770edf4899bf7b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 22 Jan 2019 17:22:59 +0100 Subject: [PATCH 088/178] Persist permissions in repository --- .../java/sonia/scm/repository/Repository.java | 31 +++++++++++++++++-- .../scm/repository/RepositoryPermission.java | 25 ++++++++------- .../RepositoryCollectionResource.java | 7 +++-- .../RepositoryPermissionRootResourceTest.java | 19 ++++++------ ...onToRepositoryPermissionDtoMapperTest.java | 5 +-- .../DefaultAuthorizationCollectorTest.java | 3 +- 6 files changed, 63 insertions(+), 27 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java index 310a0f0556..3adb215d27 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Repository.java +++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java @@ -80,6 +80,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per private Long lastModified; private String namespace; private String name; + private final Set permissions = new HashSet<>(); @XmlElement(name = "public") private boolean publicReadable = false; private boolean archived = false; @@ -117,14 +118,20 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per * @param contact email address of a person who is responsible for * this repository. * @param description a short description of the repository + * @param permissions permissions for specific users and groups. */ - public Repository(String id, String type, String namespace, String name, String contact, String description) { + public Repository(String id, String type, String namespace, String name, String contact, + String description, RepositoryPermission... permissions) { this.id = id; this.type = type; this.namespace = namespace; this.name = name; this.contact = contact; this.description = description; + + if (Util.isNotEmpty(permissions)) { + this.permissions.addAll(Arrays.asList(permissions)); + } } /** @@ -193,6 +200,10 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per return new NamespaceAndName(getNamespace(), getName()); } + public Collection getPermissions() { + return Collections.unmodifiableCollection(permissions); + } + /** * Returns the type (hg, git, svn ...) of the {@link Repository}. * @@ -285,6 +296,19 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per this.name = name; } + public void setPermissions(Collection permissions) { + this.permissions.clear(); + this.permissions.addAll(permissions); + } + + public void addPermission(RepositoryPermission newPermission) { + this.permissions.add(newPermission); + } + + public void removePermission(RepositoryPermission permission) { + this.permissions.remove(permission); + } + public void setPublicReadable(boolean publicReadable) { this.publicReadable = publicReadable; } @@ -322,6 +346,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per repository.setCreationDate(creationDate); repository.setLastModified(lastModified); repository.setDescription(description); + repository.setPermissions(permissions); repository.setPublicReadable(publicReadable); repository.setArchived(archived); @@ -353,6 +378,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per && Objects.equal(description, other.description) && Objects.equal(publicReadable, other.publicReadable) && Objects.equal(archived, other.archived) + && Objects.equal(permissions, other.permissions) && Objects.equal(type, other.type) && Objects.equal(creationDate, other.creationDate) && Objects.equal(lastModified, other.lastModified) @@ -363,7 +389,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per @Override public int hashCode() { return Objects.hashCode(id, namespace, name, contact, description, publicReadable, - archived, type, creationDate, lastModified, properties, + archived, permissions, type, creationDate, lastModified, properties, healthCheckFailures); } @@ -377,6 +403,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per .add("description", description) .add("publicReadable", publicReadable) .add("archived", archived) + .add("permissions", permissions) .add("type", type) .add("lastModified", lastModified) .add("creationDate", creationDate) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java index 492142674d..70d0c8491e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java @@ -41,8 +41,10 @@ import sonia.scm.security.PermissionObject; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; +import java.util.Collection; //~--- JDK imports ------------------------------------------------------------ @@ -60,7 +62,8 @@ public class RepositoryPermission implements PermissionObject, Serializable private boolean groupPermission = false; private String name; - private String verb; + @XmlElement(name = "verb") + private Collection verbs; /** * Constructs a new {@link RepositoryPermission}. @@ -68,10 +71,10 @@ public class RepositoryPermission implements PermissionObject, Serializable */ public RepositoryPermission() {} - public RepositoryPermission(String name, String verb, boolean groupPermission) + public RepositoryPermission(String name, Collection verbs, boolean groupPermission) { this.name = name; - this.verb = verb; + this.verbs = verbs; this.groupPermission = groupPermission; } @@ -101,7 +104,7 @@ public class RepositoryPermission implements PermissionObject, Serializable final RepositoryPermission other = (RepositoryPermission) obj; return Objects.equal(name, other.name) - && Objects.equal(verb, other.verb) + && Objects.equal(verbs, other.verbs) && Objects.equal(groupPermission, other.groupPermission); } @@ -114,7 +117,7 @@ public class RepositoryPermission implements PermissionObject, Serializable @Override public int hashCode() { - return Objects.hashCode(name, verb, groupPermission); + return Objects.hashCode(name, verbs, groupPermission); } @@ -124,7 +127,7 @@ public class RepositoryPermission implements PermissionObject, Serializable //J- return MoreObjects.toStringHelper(this) .add("name", name) - .add("verb", verb) + .add("verbs", verbs) .add("groupPermission", groupPermission) .toString(); //J+ @@ -150,9 +153,9 @@ public class RepositoryPermission implements PermissionObject, Serializable * * @return verb of the permission */ - public String getVerb() + public Collection getVerbs() { - return verb; + return verbs; } /** @@ -195,10 +198,10 @@ public class RepositoryPermission implements PermissionObject, Serializable * Sets the verb of the permission. * * - * @param verb verb of the permission + * @param verbs verbs of the permission */ - public void setVerb(String verb) + public void setVerbs(Collection verbs) { - this.verb = verb; + this.verbs = verbs; } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java index cfcd279692..a9bd5c2424 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionResource.java @@ -8,6 +8,7 @@ import com.webcohesion.enunciate.metadata.rs.TypeHint; import org.apache.shiro.SecurityUtils; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; +import sonia.scm.repository.RepositoryPermission; import sonia.scm.user.User; import sonia.scm.web.VndMediaType; @@ -22,6 +23,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; + public class RepositoryCollectionResource { private static final int DEFAULT_PAGE_SIZE = 10; @@ -96,8 +100,7 @@ public class RepositoryCollectionResource { private Repository createModelObjectFromDto(@Valid RepositoryDto repositoryDto) { Repository repository = dtoToRepositoryMapper.map(repositoryDto, null); - // TODO RP -// repository.setPermissions(singletonList(new RepositoryPermission(currentUser(), PermissionType.OWNER))); + repository.setPermissions(singletonList(new RepositoryPermission(currentUser(), singletonList("*"), false))); return repository; } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index b66a274f0d..9fe13a71d8 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -46,6 +46,7 @@ import java.util.stream.Stream; import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; +import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -78,12 +79,12 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { private static final String PERMISSION_TEST_PAYLOAD = "{ \"name\" : \"permission_name\", \"type\" : \"READ\" }"; private static final ArrayList TEST_PERMISSIONS = Lists .newArrayList( - new RepositoryPermission("user_write", "read,modify", false), - new RepositoryPermission("user_read", "read", false), - new RepositoryPermission("user_owner", "read,modify,delete", false), - new RepositoryPermission("group_read", "read", true), - new RepositoryPermission("group_write", "read,modify", true), - new RepositoryPermission("group_owner", "read,modify,delete", true) + new RepositoryPermission("user_write", asList("read","modify"), false), + new RepositoryPermission("user_read", asList("read"), false), + new RepositoryPermission("user_owner", asList("*"), false), + new RepositoryPermission("group_read", asList("read"), true), + new RepositoryPermission("group_write", asList("read","modify"), true), + new RepositoryPermission("group_owner", asList("*"), true) ); private final ExpectedRequest requestGETAllPermissions = new ExpectedRequest() .description("GET all permissions") @@ -258,7 +259,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { @Test public void shouldGetCreatedPermissions() throws URISyntaxException { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); - RepositoryPermission newPermission = new RepositoryPermission("new_group_perm", "read,modify", true); + RepositoryPermission newPermission = new RepositoryPermission("new_group_perm", asList("read","modify"), true); ArrayList permissions = Lists.newArrayList(TEST_PERMISSIONS); permissions.add(newPermission); ImmutableList expectedPermissions = ImmutableList.copyOf(permissions); @@ -287,7 +288,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); RepositoryPermission modifiedPermission = TEST_PERMISSIONS.get(0); // modify the type to owner - modifiedPermission.setVerb("read,modify,delete"); + modifiedPermission.setVerbs(asList("read", "modify", "delete")); ImmutableList expectedPermissions = ImmutableList.copyOf(TEST_PERMISSIONS); assertExpectedRequest(requestPUTPermission .content("{\"name\" : \"" + modifiedPermission.getName() + "\" , \"type\" : \"OWNER\" , \"groupPermission\" : false}") @@ -381,7 +382,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { RepositoryPermissionDto result = new RepositoryPermissionDto(); result.setName(permission.getName()); result.setGroupPermission(permission.isGroupPermission()); - result.setType(permission.getVerb()); +// result.setType(permission.getVerbs()); TODO RP String permissionName = Optional.of(permission.getName()) .filter(p -> !permission.isGroupPermission()) .orElse(GROUP_PREFIX + permission.getName()); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java index 09a3ab4855..97146e67ff 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionToRepositoryPermissionDtoMapperTest.java @@ -12,6 +12,7 @@ import sonia.scm.repository.Repository; import java.net.URI; +import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; @RunWith(MockitoJUnitRunner.Silent.class) @@ -35,7 +36,7 @@ public class RepositoryPermissionToRepositoryPermissionDtoMapperTest { @SubjectAware(username = "trillian", password = "secret") public void shouldMapGroupPermissionCorrectly() { Repository repository = getDummyRepository(); - RepositoryPermission permission = new RepositoryPermission("42", "read,modify,delete", true); + RepositoryPermission permission = new RepositoryPermission("42", asList("read","modify","delete"), true); RepositoryPermissionDto repositoryPermissionDto = mapper.map(permission, repository); @@ -47,7 +48,7 @@ public class RepositoryPermissionToRepositoryPermissionDtoMapperTest { @SubjectAware(username = "trillian", password = "secret") public void shouldMapNonGroupPermissionCorrectly() { Repository repository = getDummyRepository(); - RepositoryPermission permission = new RepositoryPermission("42", "read,modify,delete", false); + RepositoryPermission permission = new RepositoryPermission("42", asList("read","modify","delete"), false); RepositoryPermissionDto repositoryPermissionDto = mapper.map(permission, repository); diff --git a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java index bfb97d0b40..d04c35686f 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java @@ -58,6 +58,7 @@ import sonia.scm.repository.RepositoryTestData; import sonia.scm.user.User; import sonia.scm.user.UserTestData; +import static java.util.Arrays.asList; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.nullValue; @@ -228,7 +229,7 @@ public class DefaultAuthorizationCollectorTest { // heartOfGold.setPermissions(Lists.newArrayList(new RepositoryPermission("trillian"))); Repository puzzle42 = RepositoryTestData.create42Puzzle(); puzzle42.setId("two"); - RepositoryPermission permission = new RepositoryPermission(group, "read,modify", true); + RepositoryPermission permission = new RepositoryPermission(group, asList("read","modify"), true); // puzzle42.setPermissions(Lists.newArrayList(permission)); when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold, puzzle42)); From 02b19e51ef71ac180a431c356d832e21e6fdaf11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 09:47:38 +0100 Subject: [PATCH 089/178] Fix repository permission rest interface --- .../java/sonia/scm/repository/Repository.java | 1 + .../repository/xml/XmlRepositoryDAOTest.java | 17 +++++ .../java/sonia/scm/it/PermissionsITCase.java | 16 +++-- .../java/sonia/scm/it/utils/TestData.java | 40 ++++++----- ...sitoryPermissionCollectionToDtoMapper.java | 11 ++- .../v2/resources/RepositoryPermissionDto.java | 14 +--- .../RepositoryPermissionRootResource.java | 70 ++++++++----------- .../DefaultAuthorizationCollector.java | 10 +-- .../META-INF/scm/repository-permissions.xml | 2 +- .../RepositoryPermissionRootResourceTest.java | 30 ++++---- .../resources/RepositoryRootResourceTest.java | 16 ++--- .../test/java/sonia/scm/it/GitLfsITCase.java | 11 --- .../DefaultAuthorizationCollectorTest.java | 7 +- 13 files changed, 119 insertions(+), 126 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java index 3adb215d27..568b75e525 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Repository.java +++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java @@ -80,6 +80,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per private Long lastModified; private String namespace; private String name; + @XmlElement(name = "permission") private final Set permissions = new HashSet<>(); @XmlElement(name = "public") private boolean publicReadable = false; diff --git a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java index 6330db56a0..68d8803c89 100644 --- a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java +++ b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java @@ -16,6 +16,7 @@ import sonia.scm.io.FileSystem; import sonia.scm.repository.InitialRepositoryLocationResolver; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermission; import sonia.scm.repository.RepositoryTestData; import java.io.IOException; @@ -23,9 +24,11 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Clock; +import java.util.Arrays; import java.util.Collection; import java.util.concurrent.atomic.AtomicLong; +import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -329,6 +332,20 @@ class XmlRepositoryDAOTest { assertThat(content).contains("Awesome Spaceship"); } + @Test + void x() throws IOException { + Repository heartOfGold = createHeartOfGold(); + heartOfGold.setPermissions(asList(new RepositoryPermission("trillian", asList("read", "write"), false), new RepositoryPermission("vorgons", asList("delete"), true))); + dao.add(heartOfGold); + + Path repositoryDirectory = getAbsolutePathFromDao(heartOfGold.getId()); + Path metadataPath = dao.resolveMetadataPath(repositoryDirectory); + + String content = content(metadataPath); + System.out.println(content); + assertThat(content).contains("Awesome Spaceship"); + } + @Test void shouldReadPathDatabaseAndMetadataOfRepositories() { Repository heartOfGold = createHeartOfGold(); diff --git a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java index 15f5e30abc..1f61cdb93a 100644 --- a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java @@ -58,7 +58,10 @@ import static org.junit.Assert.assertNull; import static sonia.scm.it.utils.RepositoryUtil.addAndCommitRandomFile; import static sonia.scm.it.utils.RestUtil.given; import static sonia.scm.it.utils.ScmTypes.availableScmTypes; +import static sonia.scm.it.utils.TestData.OWNER; +import static sonia.scm.it.utils.TestData.READ; import static sonia.scm.it.utils.TestData.USER_SCM_ADMIN; +import static sonia.scm.it.utils.TestData.WRITE; import static sonia.scm.it.utils.TestData.callRepository; @RunWith(Parameterized.class) @@ -90,13 +93,12 @@ public class PermissionsITCase { public void prepareEnvironment() { TestData.createDefault(); TestData.createNotAdminUser(USER_READ, USER_PASS); - // TODO RP -// TestData.createUserPermission(USER_READ, PermissionType.READ, repositoryType); -// TestData.createNotAdminUser(USER_WRITE, USER_PASS); -// TestData.createUserPermission(USER_WRITE, PermissionType.WRITE, repositoryType); -// TestData.createNotAdminUser(USER_OWNER, USER_PASS); -// TestData.createUserPermission(USER_OWNER, PermissionType.OWNER, repositoryType); -// TestData.createNotAdminUser(USER_OTHER, USER_PASS); + TestData.createUserPermission(USER_READ, READ, repositoryType); + TestData.createNotAdminUser(USER_WRITE, USER_PASS); + TestData.createUserPermission(USER_WRITE, WRITE, repositoryType); + TestData.createNotAdminUser(USER_OWNER, USER_PASS); + TestData.createUserPermission(USER_OWNER, OWNER, repositoryType); + TestData.createNotAdminUser(USER_OTHER, USER_PASS); createdPermissions = asList(USER_READ, USER_WRITE, USER_OWNER); } diff --git a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java index fb92628287..1a2394edda 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java @@ -9,9 +9,11 @@ import sonia.scm.web.VndMediaType; import javax.json.Json; import javax.json.JsonObjectBuilder; import java.net.URI; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static java.util.Arrays.asList; import static sonia.scm.it.utils.RestUtil.createResourceUrl; @@ -24,6 +26,11 @@ public class TestData { public static final String USER_SCM_ADMIN = "scmadmin"; public static final String USER_ANONYMOUS = "anonymous"; + + public static final Collection READ = asList("read", "pull"); + public static final Collection WRITE = asList("read", "write", "pull", "push"); + public static final Collection OWNER = asList("*"); + private static final List PROTECTED_USERS = asList(USER_SCM_ADMIN, USER_ANONYMOUS); private static Map DEFAULT_REPOSITORIES = new HashMap<>(); @@ -81,23 +88,22 @@ public class TestData { ; } - // TODO RP -// public static void createUserPermission(String name, PermissionType permissionType, String repositoryType) { -// String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType); -// LOG.info("create permission with name {} and type: {} using the endpoint: {}", name, permissionType, defaultPermissionUrl); -// given(VndMediaType.PERMISSION) -// .when() -// .content("{\n" + -// "\t\"type\": \"" + permissionType.name() + "\",\n" + -// "\t\"name\": \"" + name + "\",\n" + -// "\t\"groupPermission\": false\n" + -// "\t\n" + -// "}") -// .post(defaultPermissionUrl) -// .then() -// .statusCode(HttpStatus.SC_CREATED) -// ; -// } + public static void createUserPermission(String name, Collection permissionType, String repositoryType) { + String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType); + LOG.info("create permission with name {} and type: {} using the endpoint: {}", name, permissionType, defaultPermissionUrl); + given(VndMediaType.PERMISSION) + .when() + .content("{\n" + + "\t\"verbs\": " + permissionType.stream().collect(Collectors.joining("\",\"", "[\"", "\"]")) + ",\n" + + "\t\"name\": \"" + name + "\",\n" + + "\t\"groupPermission\": false\n" + + "\t\n" + + "}") + .post(defaultPermissionUrl) + .then() + .statusCode(HttpStatus.SC_CREATED) + ; + } public static List getUserPermissions(String username, String password, String repositoryType) { return callUserPermissions(username, password, repositoryType, HttpStatus.SC_OK) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java index 9c05f80de4..5e678212e8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionCollectionToDtoMapper.java @@ -26,12 +26,11 @@ public class RepositoryPermissionCollectionToDtoMapper { } public HalRepresentation map(Repository repository) { -// List repositoryPermissionDtoList = repository.getPermissions() -// .stream() -// .map(permission -> repositoryPermissionToRepositoryPermissionDtoMapper.map(permission, repository)) -// .collect(toList()); -// return new HalRepresentation(createLinks(repository), embedDtos(repositoryPermissionDtoList)); - return new HalRepresentation(createLinks(repository)); + List repositoryPermissionDtoList = repository.getPermissions() + .stream() + .map(permission -> repositoryPermissionToRepositoryPermissionDtoMapper.map(permission, repository)) + .collect(toList()); + return new HalRepresentation(createLinks(repository), embedDtos(repositoryPermissionDtoList)); } private Links createLinks(Repository repository) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java index 6e6b9fd7fc..0699b78e91 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java @@ -10,6 +10,8 @@ import lombok.ToString; import javax.validation.constraints.Pattern; +import java.util.Collection; + import static sonia.scm.api.v2.ValidationConstraints.USER_GROUP_PATTERN; @Getter @Setter @ToString @NoArgsConstructor @@ -20,16 +22,7 @@ public class RepositoryPermissionDto extends HalRepresentation { @Pattern(regexp = USER_GROUP_PATTERN) private String name; - /** - * the type can be replaced with a dto enum if the mapstruct 1.3.0 is stable - * the mapstruct has a Bug on mapping enums in the 1.2.0-Final Version - * - * see the bug fix: https://github.com/mapstruct/mapstruct/commit/460e87eef6eb71245b387fdb0509c726676a8e19 - * - **/ - @JsonInclude(JsonInclude.Include.NON_NULL) - private String type; - + private Collection verbs; private boolean groupPermission = false; @@ -38,7 +31,6 @@ public class RepositoryPermissionDto extends HalRepresentation { this.groupPermission = groupPermission; } - @Override @SuppressWarnings("squid:S1185") // We want to have this method available in this package protected HalRepresentation add(Links links) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java index 9c22a5e1b0..97ba519df8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java @@ -37,16 +37,19 @@ import static sonia.scm.api.v2.resources.RepositoryPermissionDto.GROUP_PREFIX; @Slf4j public class RepositoryPermissionRootResource { - private RepositoryPermissionDtoToRepositoryPermissionMapper dtoToModelMapper; private RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper; private RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper; private ResourceLinks resourceLinks; private final RepositoryManager manager; - @Inject - public RepositoryPermissionRootResource(RepositoryPermissionDtoToRepositoryPermissionMapper dtoToModelMapper, RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper, RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper, ResourceLinks resourceLinks, RepositoryManager manager) { + public RepositoryPermissionRootResource( + RepositoryPermissionDtoToRepositoryPermissionMapper dtoToModelMapper, + RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper, + RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper, + ResourceLinks resourceLinks, + RepositoryManager manager) { this.dtoToModelMapper = dtoToModelMapper; this.modelToDtoMapper = modelToDtoMapper; this.repositoryPermissionCollectionToDtoMapper = repositoryPermissionCollectionToDtoMapper; @@ -54,7 +57,6 @@ public class RepositoryPermissionRootResource { this.manager = manager; } - /** * Adds a new permission to the user or group managed by the repository * @@ -73,19 +75,17 @@ public class RepositoryPermissionRootResource { @TypeHint(TypeHint.NO_CONTENT.class) @Consumes(VndMediaType.PERMISSION) @Path("") - public Response create(@PathParam("namespace") String namespace, @PathParam("name") String name,@Valid RepositoryPermissionDto permission) { + public Response create(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryPermissionDto permission) { log.info("try to add new permission: {}", permission); Repository repository = load(namespace, name); RepositoryPermissions.permissionWrite(repository).check(); checkPermissionAlreadyExists(permission, repository); - // TODO RP -// repository.addPermission(dtoToModelMapper.map(permission)); + repository.addPermission(dtoToModelMapper.map(permission)); manager.modify(repository); String urlPermissionName = modelToDtoMapper.getUrlPermissionName(permission); return Response.created(URI.create(resourceLinks.repositoryPermission().self(namespace, name, urlPermissionName))).build(); } - /** * Get the searched permission with permission name related to a repository * @@ -107,17 +107,15 @@ public class RepositoryPermissionRootResource { Repository repository = load(namespace, name); RepositoryPermissions.permissionRead(repository).check(); return Response.ok( - // TODO RP -// repository.getPermissions() -// .stream() -// .filter(filterPermission(permissionName)) -// .map(permission -> modelToDtoMapper.map(permission, repository)) -// .findFirst() -// .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))) + repository.getPermissions() + .stream() + .filter(filterPermission(permissionName)) + .map(permission -> modelToDtoMapper.map(permission, repository)) + .findFirst() + .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))) ).build(); } - /** * Get all permissions related to a repository * @@ -141,7 +139,6 @@ public class RepositoryPermissionRootResource { return Response.ok(repositoryPermissionCollectionToDtoMapper.map(repository)).build(); } - /** * Update a permission to the user or group managed by the repository * ignore the user input for groupPermission and take it from the path parameter (if the group prefix (@) exists it is a group permission) @@ -175,13 +172,12 @@ public class RepositoryPermissionRootResource { checkPermissionAlreadyExists(permission, repository); } - // TODO RP -// RepositoryPermission existingPermission = repository.getPermissions() -// .stream() -// .filter(filterPermission(permissionName)) -// .findFirst() -// .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))); -// dtoToModelMapper.modify(existingPermission, permission); + RepositoryPermission existingPermission = repository.getPermissions() + .stream() + .filter(filterPermission(permissionName)) + .findFirst() + .orElseThrow(() -> notFound(entity(RepositoryPermission.class, namespace).in(Repository.class, namespace + "/" + name))); + dtoToModelMapper.modify(existingPermission, permission); manager.modify(repository); log.info("the permission with name: {} is updated.", permissionName); return Response.noContent().build(); @@ -208,22 +204,20 @@ public class RepositoryPermissionRootResource { log.info("try to delete the permission with name: {}.", permissionName); Repository repository = load(namespace, name); RepositoryPermissions.modify(repository).check(); - // TODO RP -// repository.getPermissions() -// .stream() -// .filter(filterPermission(permissionName)) -// .findFirst() -// .ifPresent(repository::removePermission) -// ; + repository.getPermissions() + .stream() + .filter(filterPermission(permissionName)) + .findFirst() + .ifPresent(repository::removePermission); manager.modify(repository); log.info("the permission with name: {} is updated.", permissionName); return Response.noContent().build(); } - Predicate filterPermission(String permissionName) { - return permission -> getPermissionName(permissionName).equals(permission.getName()) + private Predicate filterPermission(String name) { + return permission -> getPermissionName(name).equals(permission.getName()) && - permission.isGroupPermission() == isGroupPermission(permissionName); + permission.isGroupPermission() == isGroupPermission(name); } private String getPermissionName(String permissionName) { @@ -236,7 +230,6 @@ public class RepositoryPermissionRootResource { return permissionName.startsWith(GROUP_PREFIX); } - /** * check if the actual user is permitted to manage the repository permissions * return the repository if the user is permitted @@ -266,10 +259,9 @@ public class RepositoryPermissionRootResource { } private boolean isPermissionExist(RepositoryPermissionDto permission, Repository repository) { - return true; -// return repository.getPermissions() -// .stream() -// .anyMatch(p -> p.getName().equals(permission.getName()) && p.isGroupPermission() == permission.isGroupPermission()); + return repository.getPermissions() + .stream() + .anyMatch(p -> p.getName().equals(permission.getName()) && p.isGroupPermission() == permission.isGroupPermission()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java index e015ed90f6..1e0bffa568 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java @@ -63,7 +63,6 @@ import sonia.scm.user.UserPermissions; import sonia.scm.util.Util; import java.util.Collection; -import java.util.Collections; import java.util.Set; //~--- JDK imports ------------------------------------------------------------ @@ -199,12 +198,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector private void collectRepositoryPermissions(Builder builder, Repository repository, User user, GroupNames groups) { - - // TODO RP - - Collection repositoryPermissions - = Collections.emptyList(); -// = repository.getPermissions(); + Collection repositoryPermissions = repository.getPermissions(); if (Util.isNotEmpty(repositoryPermissions)) { @@ -214,7 +208,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector hasPermission = isUserPermitted(user, groups, permission); if (hasPermission) { - String perm = null; // TODO RP permission.getType().getPermissionPrefix().concat(repository.getId()); + String perm = "repository:" + String.join(",", permission.getVerbs()) + ":" + repository.getId(); if (logger.isTraceEnabled()) { logger.trace("add repository permission {} for user {} at repository {}", diff --git a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml index 9df450efb0..89d47e156f 100644 --- a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml +++ b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml @@ -14,8 +14,8 @@ WRITER read - push pull + push diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index 9fe13a71d8..6f44b8d522 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -1,5 +1,6 @@ package sonia.scm.api.v2.resources; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; @@ -29,9 +30,9 @@ import org.junit.jupiter.api.TestFactory; import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.repository.NamespaceAndName; -import sonia.scm.repository.RepositoryPermission; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; +import sonia.scm.repository.RepositoryPermission; import sonia.scm.web.VndMediaType; import java.io.IOException; @@ -47,6 +48,7 @@ import java.util.stream.Stream; import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -76,7 +78,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { private static final String PERMISSION_NAME = "perm"; private static final String PATH_OF_ALL_PERMISSIONS = REPOSITORY_NAMESPACE + "/" + REPOSITORY_NAME + "/permissions/"; private static final String PATH_OF_ONE_PERMISSION = PATH_OF_ALL_PERMISSIONS + PERMISSION_NAME; - private static final String PERMISSION_TEST_PAYLOAD = "{ \"name\" : \"permission_name\", \"type\" : \"READ\" }"; + private static final String PERMISSION_TEST_PAYLOAD = "{ \"name\" : \"permission_name\", \"verbs\" : [\"read\",\"pull\"] }"; private static final ArrayList TEST_PERMISSIONS = Lists .newArrayList( new RepositoryPermission("user_write", asList("read","modify"), false), @@ -232,7 +234,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { public void shouldGet400OnCreatingNewPermissionWithNotAllowedCharacters() throws URISyntaxException { // the @ character at the begin of the name is not allowed createUserWithRepository("user"); - String permissionJson = "{ \"name\": \"@permission\", \"type\": \"OWNER\" }"; + String permissionJson = "{ \"name\": \"@permission\", \"verbs\": [\"*\"] }"; MockHttpRequest request = MockHttpRequest .post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS) .content(permissionJson.getBytes()) @@ -244,7 +246,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { assertEquals(400, response.getStatus()); // the whitespace at the begin opf the name is not allowed - permissionJson = "{ \"name\": \" permission\", \"type\": \"OWNER\" }"; + permissionJson = "{ \"name\": \" permission\", \"verbs\": [\"*\"] }"; request = MockHttpRequest .post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS) .content(permissionJson.getBytes()) @@ -259,12 +261,12 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { @Test public void shouldGetCreatedPermissions() throws URISyntaxException { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); - RepositoryPermission newPermission = new RepositoryPermission("new_group_perm", asList("read","modify"), true); + RepositoryPermission newPermission = new RepositoryPermission("new_group_perm", asList("read", "pull", "push"), true); ArrayList permissions = Lists.newArrayList(TEST_PERMISSIONS); permissions.add(newPermission); ImmutableList expectedPermissions = ImmutableList.copyOf(permissions); assertExpectedRequest(requestPOSTPermission - .content("{\"name\" : \"" + newPermission.getName() + "\" , \"type\" : \"WRITE\" , \"groupPermission\" : true}") + .content("{\"name\" : \"" + newPermission.getName() + "\" , \"verbs\" : [\"read\",\"pull\",\"push\"], \"groupPermission\" : true}") .expectedResponseStatus(201) .responseValidator(response -> assertThat(response.getContentAsString()) .as("POST response has no body") @@ -278,7 +280,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); RepositoryPermission newPermission = TEST_PERMISSIONS.get(0); assertExpectedRequest(requestPOSTPermission - .content("{\"name\" : \"" + newPermission.getName() + "\" , \"type\" : \"WRITE\" , \"groupPermission\" : false}") + .content("{\"name\" : \"" + newPermission.getName() + "\" , \"verbs\" : [\"read\",\"pull\",\"push\"], \"groupPermission\" : false}") .expectedResponseStatus(409) ); } @@ -288,10 +290,10 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); RepositoryPermission modifiedPermission = TEST_PERMISSIONS.get(0); // modify the type to owner - modifiedPermission.setVerbs(asList("read", "modify", "delete")); + modifiedPermission.setVerbs(new ArrayList<>(singletonList("*"))); ImmutableList expectedPermissions = ImmutableList.copyOf(TEST_PERMISSIONS); assertExpectedRequest(requestPUTPermission - .content("{\"name\" : \"" + modifiedPermission.getName() + "\" , \"type\" : \"OWNER\" , \"groupPermission\" : false}") + .content("{\"name\" : \"" + modifiedPermission.getName() + "\" , \"verbs\" : [\"*\"], \"groupPermission\" : false}") .path(PATH_OF_ALL_PERMISSIONS + modifiedPermission.getName()) .expectedResponseStatus(204) .responseValidator(response -> assertThat(response.getContentAsString()) @@ -353,7 +355,10 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { .map(hal -> { RepositoryPermissionDto result = new RepositoryPermissionDto(); result.setName(hal.getAttribute("name").asText()); - result.setType(hal.getAttribute("type").asText()); + JsonNode attribute = hal.getAttribute("verbs"); + List verbs = new ArrayList<>(); + attribute.iterator().forEachRemaining(v -> verbs.add(v.asText())); + result.setVerbs(verbs); result.setGroupPermission(hal.getAttribute("groupPermission").asBoolean()); result.add(hal.getLinks()); return result; @@ -382,7 +387,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { RepositoryPermissionDto result = new RepositoryPermissionDto(); result.setName(permission.getName()); result.setGroupPermission(permission.isGroupPermission()); -// result.setType(permission.getVerbs()); TODO RP + result.setVerbs(permission.getVerbs()); String permissionName = Optional.of(permission.getName()) .filter(p -> !permission.isGroupPermission()) .orElse(GROUP_PREFIX + permission.getName()); @@ -412,8 +417,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { } private void createUserWithRepositoryAndPermissions(ArrayList permissions, String userPermission) { - // TODO RP -// createUserWithRepository(userPermission).setPermissions(permissions); + createUserWithRepository(userPermission).setPermissions(permissions); } private Stream createDynamicTestsToAssertResponses(ExpectedRequest... expectedRequests) { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index a18b63c53f..bf4366f0b2 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -38,9 +38,8 @@ import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; import static javax.servlet.http.HttpServletResponse.SC_OK; import static javax.servlet.http.HttpServletResponse.SC_PRECONDITION_FAILED; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; @@ -286,13 +285,12 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { dispatcher.invoke(request, response); - // TODO RP -// Assertions.assertThat(createCaptor.getValue().getPermissions()) -// .hasSize(1) -// .allSatisfy(p -> { -// assertThat(p.getName()).isEqualTo("trillian"); -// assertThat(p.getType()).isEqualTo(PermissionType.OWNER); -// }); + assertThat(createCaptor.getValue().getPermissions()) + .hasSize(1) + .allSatisfy(p -> { + assertThat(p.getName()).isEqualTo("trillian"); + assertThat(p.getVerbs()).containsExactly("*"); + }); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index 242c9b3047..a377337eea 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -116,17 +116,6 @@ public class GitLfsITCase { @Test public void testLfsAPIWithOwnerPermissions() throws IOException { - // TODO RP - uploadAndDownloadAsUser(); - } - - @Test - public void testLfsAPIWithWritePermissions() throws IOException { - // TODO RP - uploadAndDownloadAsUser(); - } - - private void uploadAndDownloadAsUser() throws IOException { User trillian = UserTestData.createTrillian(); trillian.setPassword("secret123"); createUser(trillian); diff --git a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java index d04c35686f..e9345c9599 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java @@ -225,12 +225,11 @@ public class DefaultAuthorizationCollectorTest { authenticate(UserTestData.createTrillian(), group); Repository heartOfGold = RepositoryTestData.createHeartOfGold(); heartOfGold.setId("one"); - // TODO RP -// heartOfGold.setPermissions(Lists.newArrayList(new RepositoryPermission("trillian"))); + heartOfGold.setPermissions(Lists.newArrayList(new RepositoryPermission("trillian", asList("read", "pull"), false))); Repository puzzle42 = RepositoryTestData.create42Puzzle(); puzzle42.setId("two"); - RepositoryPermission permission = new RepositoryPermission(group, asList("read","modify"), true); -// puzzle42.setPermissions(Lists.newArrayList(permission)); + RepositoryPermission permission = new RepositoryPermission(group, asList("read", "pull", "push"), true); + puzzle42.setPermissions(Lists.newArrayList(permission)); when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold, puzzle42)); // execute and assert From 8a0d2ba81903dbdb54863094deeb3b044ee9b02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 10:06:48 +0100 Subject: [PATCH 090/178] Rename --- ...signer.java => RepositoryPermissions.java} | 7 ++-- .../RepositoryPermissionAssignerTest.java | 25 ------------- .../security/RepositoryPermissionsTest.java | 36 +++++++++++++++++++ 3 files changed, 39 insertions(+), 29 deletions(-) rename scm-webapp/src/main/java/sonia/scm/security/{RepositoryPermissionAssigner.java => RepositoryPermissions.java} (95%) delete mode 100644 scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissions.java similarity index 95% rename from scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java rename to scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissions.java index 59bc489144..463c2def6e 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionAssigner.java +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissions.java @@ -21,16 +21,15 @@ import java.util.Enumeration; import java.util.List; import java.util.stream.Collectors; -public class RepositoryPermissionAssigner { +public class RepositoryPermissions { - private static final Logger logger = LoggerFactory.getLogger(RepositoryPermissionAssigner.class); - private static final String NAME = "permissions"; + private static final Logger logger = LoggerFactory.getLogger(RepositoryPermissions.class); private static final String REPOSITORY_PERMISSION_DESCRIPTOR = "META-INF/scm/repository-permissions.xml"; private final ConfigurationEntryStoreFactory storeFactory; private final AvailableRepositoryPermissions availablePermissions; @Inject - public RepositoryPermissionAssigner(ConfigurationEntryStoreFactory storeFactory, PluginLoader pluginLoader) { + public RepositoryPermissions(ConfigurationEntryStoreFactory storeFactory, PluginLoader pluginLoader) { this.storeFactory = storeFactory; this.availablePermissions = readAvailablePermissions(pluginLoader); } diff --git a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java deleted file mode 100644 index d037c2cbfe..0000000000 --- a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionAssignerTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package sonia.scm.security; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; -import sonia.scm.plugin.PluginLoader; -import sonia.scm.store.ConfigurationEntryStoreFactory; -import sonia.scm.util.ClassLoaders; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class RepositoryPermissionAssignerTest { - - @Test - void x() { - PluginLoader pluginLoader = mock(PluginLoader.class); - when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class)); - ConfigurationEntryStoreFactory configurationEntryStoreFactory = mock(ConfigurationEntryStoreFactory.class); - RepositoryPermissionAssigner repositoryPermissionAssigner = new RepositoryPermissionAssigner(configurationEntryStoreFactory, pluginLoader); - Assertions.assertThat(repositoryPermissionAssigner.availableVerbs()).isNotEmpty(); - Assertions.assertThat(repositoryPermissionAssigner.availableRoles()).isNotEmpty().noneMatch(r -> r.getVerbs().isEmpty()); - System.out.println(repositoryPermissionAssigner.availableVerbs()); - System.out.println(repositoryPermissionAssigner.availableRoles()); - } -} diff --git a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java new file mode 100644 index 0000000000..433e91e64c --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java @@ -0,0 +1,36 @@ +package sonia.scm.security; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.store.ConfigurationEntryStoreFactory; +import sonia.scm.util.ClassLoaders; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class RepositoryPermissionsTest { + + private RepositoryPermissions repositoryPermissions; + + @BeforeEach + void init() { + PluginLoader pluginLoader = mock(PluginLoader.class); + when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class)); + ConfigurationEntryStoreFactory configurationEntryStoreFactory = mock(ConfigurationEntryStoreFactory.class); + repositoryPermissions = new RepositoryPermissions(configurationEntryStoreFactory, pluginLoader); + } + + @Test + void shouldReadAvailableRoles() { + Assertions.assertThat(repositoryPermissions.availableRoles()).isNotEmpty().noneMatch(r -> r.getVerbs().isEmpty()); + System.out.println(repositoryPermissions.availableRoles()); + } + + @Test + void shouldReadAvailableVerbs() { + Assertions.assertThat(repositoryPermissions.availableVerbs()).isNotEmpty(); + System.out.println(repositoryPermissions.availableVerbs()); + } +} From d011c82def6c931253da543880a6a58d62a0d91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 10:13:21 +0100 Subject: [PATCH 091/178] Fix unit test --- .../java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java index 68d8803c89..9c289b061c 100644 --- a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java +++ b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java @@ -333,7 +333,7 @@ class XmlRepositoryDAOTest { } @Test - void x() throws IOException { + void shouldPersistPermissions() throws IOException { Repository heartOfGold = createHeartOfGold(); heartOfGold.setPermissions(asList(new RepositoryPermission("trillian", asList("read", "write"), false), new RepositoryPermission("vorgons", asList("delete"), true))); dao.add(heartOfGold); @@ -343,7 +343,7 @@ class XmlRepositoryDAOTest { String content = content(metadataPath); System.out.println(content); - assertThat(content).contains("Awesome Spaceship"); + assertThat(content).containsSubsequence("trillian", "read", "write", "vorgons", "delete"); } @Test From 8c049446235e31d7474c7892321a3cdf519d3d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 11:18:02 +0100 Subject: [PATCH 092/178] Do not return null --- .../main/java/sonia/scm/repository/RepositoryPermission.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java index 70d0c8491e..97872f29eb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java @@ -46,6 +46,8 @@ import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; import java.util.Collection; +import static java.util.Collections.emptyList; + //~--- JDK imports ------------------------------------------------------------ /** @@ -155,7 +157,7 @@ public class RepositoryPermission implements PermissionObject, Serializable */ public Collection getVerbs() { - return verbs; + return verbs == null? emptyList(): verbs; } /** From b8679d1f8302f48ff2350747b4d3deaf053b21b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 11:18:47 +0100 Subject: [PATCH 093/178] Fix permission check --- .../src/main/java/sonia/scm/web/filter/PermissionFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 328494a626..a062fdb360 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 @@ -252,7 +252,7 @@ public abstract class PermissionFilter extends ScmProviderHttpServletDecorator } else { - permitted = RepositoryPermissions.read(repository).isPermitted(); + permitted = RepositoryPermissions.pull(repository).isPermitted(); } return permitted; From 6bf216d3798ab4875805e216a2dfe515ec3422a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 11:19:55 +0100 Subject: [PATCH 094/178] Rename media type --- .../src/main/java/sonia/scm/web/VndMediaType.java | 2 +- .../test/java/sonia/scm/it/PermissionsITCase.java | 6 +++--- .../src/test/java/sonia/scm/it/utils/TestData.java | 4 ++-- .../resources/RepositoryPermissionRootResource.java | 8 ++++---- .../RepositoryPermissionRootResourceTest.java | 6 +++--- .../src/test/java/sonia/scm/it/GitLfsITCase.java | 12 ++++++------ 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java index 8596bab754..0836f177ee 100644 --- a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java +++ b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java @@ -20,7 +20,7 @@ public class VndMediaType { public static final String GROUP = PREFIX + "group" + SUFFIX; public static final String AUTOCOMPLETE = PREFIX + "autocomplete" + SUFFIX; public static final String REPOSITORY = PREFIX + "repository" + SUFFIX; - public static final String PERMISSION = PREFIX + "permission" + SUFFIX; + public static final String REPOSITORY_PERMISSION = PREFIX + "repositoryPermission" + SUFFIX; public static final String CHANGESET = PREFIX + "changeset" + SUFFIX; public static final String CHANGESET_COLLECTION = PREFIX + "changesetCollection" + SUFFIX; public static final String MODIFICATIONS = PREFIX + "modifications" + SUFFIX; diff --git a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java index 1f61cdb93a..926be5459f 100644 --- a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java @@ -111,7 +111,7 @@ public class PermissionsITCase { @Test public void readUserShouldNotSeeBruteForcePermissions() { - given(VndMediaType.PERMISSION, USER_READ, USER_PASS) + given(VndMediaType.REPOSITORY_PERMISSION, USER_READ, USER_PASS) .when() .get(TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType)) .then() @@ -127,7 +127,7 @@ public class PermissionsITCase { @Test public void writeUserShouldNotSeeBruteForcePermissions() { - given(VndMediaType.PERMISSION, USER_WRITE, USER_PASS) + given(VndMediaType.REPOSITORY_PERMISSION, USER_WRITE, USER_PASS) .when() .get(TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType)) .then() @@ -147,7 +147,7 @@ public class PermissionsITCase { @Test public void otherUserShouldNotSeeBruteForcePermissions() { - given(VndMediaType.PERMISSION, USER_OTHER, USER_PASS) + given(VndMediaType.REPOSITORY_PERMISSION, USER_OTHER, USER_PASS) .when() .get(TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType)) .then() diff --git a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java index 1a2394edda..584737221f 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java @@ -91,7 +91,7 @@ public class TestData { public static void createUserPermission(String name, Collection permissionType, String repositoryType) { String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType); LOG.info("create permission with name {} and type: {} using the endpoint: {}", name, permissionType, defaultPermissionUrl); - given(VndMediaType.PERMISSION) + given(VndMediaType.REPOSITORY_PERMISSION) .when() .content("{\n" + "\t\"verbs\": " + permissionType.stream().collect(Collectors.joining("\",\"", "[\"", "\"]")) + ",\n" + @@ -112,7 +112,7 @@ public class TestData { } public static ValidatableResponse callUserPermissions(String username, String password, String repositoryType, int expectedStatusCode) { - return given(VndMediaType.PERMISSION, username, password) + return given(VndMediaType.REPOSITORY_PERMISSION, username, password) .when() .get(TestData.getDefaultPermissionUrl(username, password, repositoryType)) .then() diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java index 97ba519df8..dd66e6e5f2 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java @@ -73,7 +73,7 @@ public class RepositoryPermissionRootResource { @ResponseCode(code = 409, condition = "conflict") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes(VndMediaType.PERMISSION) + @Consumes(VndMediaType.REPOSITORY_PERMISSION) @Path("") public Response create(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryPermissionDto permission) { log.info("try to add new permission: {}", permission); @@ -100,7 +100,7 @@ public class RepositoryPermissionRootResource { @ResponseCode(code = 404, condition = "not found"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces(VndMediaType.PERMISSION) + @Produces(VndMediaType.REPOSITORY_PERMISSION) @TypeHint(RepositoryPermissionDto.class) @Path("{permission-name}") public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("permission-name") String permissionName) { @@ -130,7 +130,7 @@ public class RepositoryPermissionRootResource { @ResponseCode(code = 404, condition = "not found"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces(VndMediaType.PERMISSION) + @Produces(VndMediaType.REPOSITORY_PERMISSION) @TypeHint(RepositoryPermissionDto.class) @Path("") public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) { @@ -154,7 +154,7 @@ public class RepositoryPermissionRootResource { @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - @Consumes(VndMediaType.PERMISSION) + @Consumes(VndMediaType.REPOSITORY_PERMISSION) @Path("{permission-name}") public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index 6f44b8d522..5d9af10d09 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -238,7 +238,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { MockHttpRequest request = MockHttpRequest .post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS) .content(permissionJson.getBytes()) - .contentType(VndMediaType.PERMISSION); + .contentType(VndMediaType.REPOSITORY_PERMISSION); MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke(request, response); @@ -250,7 +250,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { request = MockHttpRequest .post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS) .content(permissionJson.getBytes()) - .contentType(VndMediaType.PERMISSION); + .contentType(VndMediaType.REPOSITORY_PERMISSION); response = new MockHttpResponse(); dispatcher.invoke(request, response); @@ -430,7 +430,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { HttpRequest request = MockHttpRequest .create(entry.method, "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + entry.path) .content(entry.content) - .contentType(VndMediaType.PERMISSION); + .contentType(VndMediaType.REPOSITORY_PERMISSION); dispatcher.invoke(request, response); log.info("Test the Request :{}", entry); assertThat(response.getStatus()) diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index a377337eea..c431e9c09a 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -124,8 +124,8 @@ public class GitLfsITCase { String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) .accept("*/*") - .type(VndMediaType.PERMISSION) - .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"type\":\"WRITE\"}"); + .type(VndMediaType.REPOSITORY_PERMISSION) + .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"verbs\":[\"*\"]}"); ScmClient client = new ScmClient(trillian.getId(), "secret123"); @@ -165,8 +165,8 @@ public class GitLfsITCase { String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) .accept("*/*") - .type(VndMediaType.PERMISSION) - .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"type\":\"READ\"}"); + .type(VndMediaType.REPOSITORY_PERMISSION) + .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"verbs\":[\"read\"]}"); ScmClient client = new ScmClient(trillian.getId(), "secret123"); uploadAndDownload(client); @@ -186,8 +186,8 @@ public class GitLfsITCase { String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) .accept("*/*") - .type(VndMediaType.PERMISSION) - .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"type\":\"READ\"}"); + .type(VndMediaType.REPOSITORY_PERMISSION) + .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"verbs\":[\"read\"]}"); // upload data as admin String data = UUID.randomUUID().toString(); From 48e1e16fe6f38512168aa2ee19417cf29d69eb41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 11:20:27 +0100 Subject: [PATCH 095/178] Do not create empty permissions --- .../java/sonia/scm/security/DefaultAuthorizationCollector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java index 1e0bffa568..3fdbcdf351 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java @@ -206,7 +206,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector for (RepositoryPermission permission : repositoryPermissions) { hasPermission = isUserPermitted(user, groups, permission); - if (hasPermission) + if (hasPermission && !permission.getVerbs().isEmpty()) { String perm = "repository:" + String.join(",", permission.getVerbs()) + ":" + repository.getId(); if (logger.isTraceEnabled()) From 7e9d60fa8ddd1d74a90d22f6fd7c4b4e436c713c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 11:20:43 +0100 Subject: [PATCH 096/178] Fetch authorization exceptions --- .../main/java/sonia/scm/web/protocol/HttpProtocolServlet.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java index c6a96e4b9e..250846a8cc 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java @@ -4,6 +4,7 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpStatus; +import org.apache.shiro.authz.AuthorizationException; import sonia.scm.NotFoundException; import sonia.scm.PushStateDispatcher; import sonia.scm.filter.WebElement; @@ -74,6 +75,9 @@ public class HttpProtocolServlet extends HttpServlet { } catch (NotFoundException e) { log.debug(e.getMessage()); resp.setStatus(HttpStatus.SC_NOT_FOUND); + } catch (AuthorizationException e) { + log.debug(e.getMessage()); + resp.setStatus(HttpStatus.SC_FORBIDDEN); } } } From fdf4421a551250586a7e35ce33f7fcfd5675bef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 12:22:06 +0100 Subject: [PATCH 097/178] Fix verbs for repository and rename class --- .../RepositoryPermissionResource.java | 50 +++++++++++++++ ...java => RepositoryPermissionProvider.java} | 11 ++-- .../META-INF/scm/repository-permissions.xml | 11 +++- .../RepositoryPermissionProviderTest.java | 62 +++++++++++++++++++ .../security/RepositoryPermissionsTest.java | 36 ----------- 5 files changed, 127 insertions(+), 43 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java rename scm-webapp/src/main/java/sonia/scm/security/{RepositoryPermissions.java => RepositoryPermissionProvider.java} (90%) create mode 100644 scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java delete mode 100644 scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java new file mode 100644 index 0000000000..2cfbf30de6 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java @@ -0,0 +1,50 @@ +package sonia.scm.api.v2.resources; + +import com.webcohesion.enunciate.metadata.rs.ResponseCode; +import com.webcohesion.enunciate.metadata.rs.StatusCodes; +import sonia.scm.security.RepositoryPermissionProvider; +import sonia.scm.web.VndMediaType; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import java.util.Collection; + +/** + * RESTful Web Service Resource to get available repository types. + */ +@Path(RepositoryPermissionResource.PATH) +public class RepositoryPermissionResource { + + static final String PATH = "v2/repositoryPermissions/"; + + private final RepositoryPermissionProvider repositoryPermissionProvider; + + @Inject + public RepositoryPermissionResource(RepositoryPermissionProvider repositoryPermissionProvider) { + this.repositoryPermissionProvider = repositoryPermissionProvider; + } + + @GET + @Path("verbs") + @StatusCodes({ + @ResponseCode(code = 200, condition = "success"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @Produces(VndMediaType.REPOSITORY_TYPE_COLLECTION) + public Collection getRepositoryPermissionVerbs() { + return repositoryPermissionProvider.availableVerbs(); + } + + @GET + @Path("roles") + @StatusCodes({ + @ResponseCode(code = 200, condition = "success"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @Produces(VndMediaType.REPOSITORY_TYPE_COLLECTION) + public Collection getRepositoryRoles() { + return repositoryPermissionProvider.availableRoles(); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissions.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java similarity index 90% rename from scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissions.java rename to scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java index 463c2def6e..f02c31b0ed 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissions.java +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java @@ -21,15 +21,15 @@ import java.util.Enumeration; import java.util.List; import java.util.stream.Collectors; -public class RepositoryPermissions { +public class RepositoryPermissionProvider { - private static final Logger logger = LoggerFactory.getLogger(RepositoryPermissions.class); + private static final Logger logger = LoggerFactory.getLogger(RepositoryPermissionProvider.class); private static final String REPOSITORY_PERMISSION_DESCRIPTOR = "META-INF/scm/repository-permissions.xml"; private final ConfigurationEntryStoreFactory storeFactory; private final AvailableRepositoryPermissions availablePermissions; @Inject - public RepositoryPermissions(ConfigurationEntryStoreFactory storeFactory, PluginLoader pluginLoader) { + public RepositoryPermissionProvider(ConfigurationEntryStoreFactory storeFactory, PluginLoader pluginLoader) { this.storeFactory = storeFactory; this.availablePermissions = readAvailablePermissions(pluginLoader); } @@ -57,7 +57,7 @@ public class RepositoryPermissions { while (descriptorEnum.hasMoreElements()) { URL descriptorUrl = descriptorEnum.nextElement(); - logger.debug("read permission descriptor from {}", descriptorUrl); + logger.debug("read repository permission descriptor from {}", descriptorUrl); RepositoryPermissionsRoot repositoryPermissionsRoot = parsePermissionDescriptor(context, descriptorUrl); availableVerbs.addAll(repositoryPermissionsRoot.verbs.verbs); @@ -79,7 +79,8 @@ public class RepositoryPermissions { RepositoryPermissionsRoot descriptorWrapper = (RepositoryPermissionsRoot) context.createUnmarshaller().unmarshal( descriptorUrl); - logger.trace("permissions from {}: {}", descriptorUrl, descriptorWrapper); + logger.trace("repository permissions from {}: {}", descriptorUrl, descriptorWrapper.verbs.verbs); + logger.trace("repository roles from {}: {}", descriptorUrl, descriptorWrapper.roles.roles); return descriptorWrapper; } catch (JAXBException ex) { logger.error("could not parse permission descriptor", ex); diff --git a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml index 89d47e156f..14412847a6 100644 --- a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml +++ b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml @@ -1,7 +1,14 @@ - abc - xyz + read + modify + delete + delete + healthCheck + pull + push + permissionRead + permissionWrite diff --git a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java new file mode 100644 index 0000000000..f1aa62f5b1 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java @@ -0,0 +1,62 @@ +package sonia.scm.security; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.repository.RepositoryPermissions; +import sonia.scm.store.ConfigurationEntryStoreFactory; +import sonia.scm.util.ClassLoaders; + +import java.lang.reflect.Field; +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class RepositoryPermissionProviderTest { + + private RepositoryPermissionProvider repositoryPermissionProvider; + private String[] allVerbsFromRepositoryClass; + + + @BeforeEach + void init() { + PluginLoader pluginLoader = mock(PluginLoader.class); + when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class)); + ConfigurationEntryStoreFactory configurationEntryStoreFactory = mock(ConfigurationEntryStoreFactory.class); + repositoryPermissionProvider = new RepositoryPermissionProvider(configurationEntryStoreFactory, pluginLoader); + allVerbsFromRepositoryClass = Arrays.stream(RepositoryPermissions.class.getDeclaredFields()) + .filter(field -> field.getName().startsWith("ACTION_")) + .map(this::getString) + .filter(verb -> !"create".equals(verb)) + .toArray(String[]::new); + } + + @Test + void shouldReadAvailableRoles() { + assertThat(repositoryPermissionProvider.availableRoles()).isNotEmpty(); + assertThat(repositoryPermissionProvider.availableRoles()).allSatisfy(this::eitherStarOrOnlyAvailableVerbs); + } + + private void eitherStarOrOnlyAvailableVerbs(RepositoryPermissionProvider.RoleDescriptor role) { + if (!role.getVerbs().contains("*") || role.getVerbs().size() > 1) { + assertThat(role.getVerbs()).isSubsetOf(allVerbsFromRepositoryClass); + } + } + + @Test + void shouldReadAvailableVerbsFromRepository() { + assertThat(repositoryPermissionProvider.availableVerbs()).contains(allVerbsFromRepositoryClass); + } + + private String getString(Field field) { + try { + return (String) field.get(null); + } catch (IllegalAccessException e) { + fail(e); + return null; + } + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java deleted file mode 100644 index 433e91e64c..0000000000 --- a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionsTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package sonia.scm.security; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import sonia.scm.plugin.PluginLoader; -import sonia.scm.store.ConfigurationEntryStoreFactory; -import sonia.scm.util.ClassLoaders; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class RepositoryPermissionsTest { - - private RepositoryPermissions repositoryPermissions; - - @BeforeEach - void init() { - PluginLoader pluginLoader = mock(PluginLoader.class); - when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class)); - ConfigurationEntryStoreFactory configurationEntryStoreFactory = mock(ConfigurationEntryStoreFactory.class); - repositoryPermissions = new RepositoryPermissions(configurationEntryStoreFactory, pluginLoader); - } - - @Test - void shouldReadAvailableRoles() { - Assertions.assertThat(repositoryPermissions.availableRoles()).isNotEmpty().noneMatch(r -> r.getVerbs().isEmpty()); - System.out.println(repositoryPermissions.availableRoles()); - } - - @Test - void shouldReadAvailableVerbs() { - Assertions.assertThat(repositoryPermissions.availableVerbs()).isNotEmpty(); - System.out.println(repositoryPermissions.availableVerbs()); - } -} From 69b64948a0a3aadfca70f7139cc14b03ce69335d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 12:33:34 +0100 Subject: [PATCH 098/178] Remove duplicates --- .../RepositoryPermissionProvider.java | 34 +++++++-------- .../sonia/scm/security/RepositoryRole.java | 42 +++++++++++++++++++ .../RepositoryPermissionProviderTest.java | 4 +- 3 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/security/RepositoryRole.java diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java index f02c31b0ed..d11da777e3 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java @@ -4,7 +4,6 @@ import com.google.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.plugin.PluginLoader; -import sonia.scm.store.ConfigurationEntryStoreFactory; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -16,30 +15,33 @@ import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Enumeration; +import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; +import static java.util.Collections.unmodifiableCollection; + public class RepositoryPermissionProvider { private static final Logger logger = LoggerFactory.getLogger(RepositoryPermissionProvider.class); private static final String REPOSITORY_PERMISSION_DESCRIPTOR = "META-INF/scm/repository-permissions.xml"; - private final ConfigurationEntryStoreFactory storeFactory; - private final AvailableRepositoryPermissions availablePermissions; + private final Collection availableVerbs; + private final Collection availableRoles; @Inject - public RepositoryPermissionProvider(ConfigurationEntryStoreFactory storeFactory, PluginLoader pluginLoader) { - this.storeFactory = storeFactory; - this.availablePermissions = readAvailablePermissions(pluginLoader); + public RepositoryPermissionProvider(PluginLoader pluginLoader) { + AvailableRepositoryPermissions availablePermissions = readAvailablePermissions(pluginLoader); + this.availableVerbs = unmodifiableCollection(new HashSet<>(availablePermissions.availableVerbs)); + this.availableRoles = unmodifiableCollection(new HashSet<>(availablePermissions.availableRoles.stream().map(r -> new RepositoryRole(r.name, r.verbs.verbs)).collect(Collectors.toList()))); } public Collection availableVerbs() { - return availablePermissions.availableVerbs; + return availableVerbs; } - public Collection availableRoles() { - return availablePermissions.availableRoles; + public Collection availableRoles() { + return availableRoles; } private static AvailableRepositoryPermissions readAvailablePermissions(PluginLoader pluginLoader) { @@ -93,8 +95,8 @@ public class RepositoryPermissionProvider { private final Collection availableRoles; private AvailableRepositoryPermissions(Collection availableVerbs, Collection availableRoles) { - this.availableVerbs = Collections.unmodifiableCollection(availableVerbs); - this.availableRoles = Collections.unmodifiableCollection(availableRoles); + this.availableVerbs = unmodifiableCollection(availableVerbs); + this.availableRoles = unmodifiableCollection(availableRoles); } } @@ -124,13 +126,5 @@ public class RepositoryPermissionProvider { private String name; @XmlElement(name = "verbs") private VerbListDescriptor verbs = new VerbListDescriptor(); - - public Collection getVerbs() { - return Collections.unmodifiableCollection(verbs.verbs); - } - - public String toString() { - return "Role " + name + " (" + verbs.verbs.stream().collect(Collectors.joining(", ")) + ")"; - } } } diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryRole.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryRole.java new file mode 100644 index 0000000000..12170e3cf4 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryRole.java @@ -0,0 +1,42 @@ +package sonia.scm.security; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; + +public class RepositoryRole { + + private final String name; + private final Collection verbs; + + public RepositoryRole(String name, Collection verbs) { + this.name = name; + this.verbs = verbs; + } + + public String getName() { + return name; + } + + public Collection getVerbs() { + return Collections.unmodifiableCollection(verbs); + } + + public String toString() { + return "Role " + name + " (" + String.join(", ", verbs) + ")"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RepositoryRole)) return false; + RepositoryRole that = (RepositoryRole) o; + return name.equals(that.name) && + verbs.equals(that.verbs); + } + + @Override + public int hashCode() { + return Objects.hash(name, verbs); + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java index f1aa62f5b1..487d8b71c8 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java @@ -26,7 +26,7 @@ class RepositoryPermissionProviderTest { PluginLoader pluginLoader = mock(PluginLoader.class); when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class)); ConfigurationEntryStoreFactory configurationEntryStoreFactory = mock(ConfigurationEntryStoreFactory.class); - repositoryPermissionProvider = new RepositoryPermissionProvider(configurationEntryStoreFactory, pluginLoader); + repositoryPermissionProvider = new RepositoryPermissionProvider(pluginLoader); allVerbsFromRepositoryClass = Arrays.stream(RepositoryPermissions.class.getDeclaredFields()) .filter(field -> field.getName().startsWith("ACTION_")) .map(this::getString) @@ -40,7 +40,7 @@ class RepositoryPermissionProviderTest { assertThat(repositoryPermissionProvider.availableRoles()).allSatisfy(this::eitherStarOrOnlyAvailableVerbs); } - private void eitherStarOrOnlyAvailableVerbs(RepositoryPermissionProvider.RoleDescriptor role) { + private void eitherStarOrOnlyAvailableVerbs(RepositoryRole role) { if (!role.getVerbs().contains("*") || role.getVerbs().size() > 1) { assertThat(role.getVerbs()).isSubsetOf(allVerbsFromRepositoryClass); } From 1bd0bbc7a32cddd67f869fa41e3ac3a227ce93ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 12:46:08 +0100 Subject: [PATCH 099/178] Better rest --- .../main/java/sonia/scm/web/VndMediaType.java | 1 + .../AvailableRepositoryPermissionsDto.java | 31 +++++++++++++++++++ .../RepositoryPermissionResource.java | 27 ++++++---------- .../scm/api/v2/resources/ResourceLinks.java | 22 +++++++++++-- .../META-INF/scm/repository-permissions.xml | 1 + .../api/v2/resources/ResourceLinksMock.java | 1 + .../RepositoryPermissionProviderTest.java | 10 ++---- 7 files changed, 66 insertions(+), 27 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailableRepositoryPermissionsDto.java diff --git a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java index 0836f177ee..19859b876b 100644 --- a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java +++ b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java @@ -33,6 +33,7 @@ public class VndMediaType { public static final String REPOSITORY_COLLECTION = PREFIX + "repositoryCollection" + SUFFIX; public static final String BRANCH_COLLECTION = PREFIX + "branchCollection" + SUFFIX; public static final String CONFIG = PREFIX + "config" + SUFFIX; + public static final String REPOSITORY_PERMISSION_COLLECTION = PREFIX + "repositoryPermissionCollection" + SUFFIX; public static final String REPOSITORY_TYPE_COLLECTION = PREFIX + "repositoryTypeCollection" + SUFFIX; public static final String REPOSITORY_TYPE = PREFIX + "repositoryType" + SUFFIX; public static final String UI_PLUGIN = PREFIX + "uiPlugin" + SUFFIX; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailableRepositoryPermissionsDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailableRepositoryPermissionsDto.java new file mode 100644 index 0000000000..60203b565b --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailableRepositoryPermissionsDto.java @@ -0,0 +1,31 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.HalRepresentation; +import de.otto.edison.hal.Links; +import sonia.scm.security.RepositoryRole; + +import java.util.Collection; + +public class AvailableRepositoryPermissionsDto extends HalRepresentation { + private final Collection availableVerbs; + private final Collection availableRoles; + + public AvailableRepositoryPermissionsDto(Collection availableVerbs, Collection availableRoles) { + this.availableVerbs = availableVerbs; + this.availableRoles = availableRoles; + } + + public Collection getAvailableVerbs() { + return availableVerbs; + } + + public Collection getAvailableRoles() { + return availableRoles; + } + + @Override + @SuppressWarnings("squid:S1185") // We want to have this method available in this package + protected HalRepresentation add(Links links) { + return super.add(links); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java index 2cfbf30de6..e5734085ca 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionResource.java @@ -2,6 +2,7 @@ package sonia.scm.api.v2.resources; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; +import de.otto.edison.hal.Links; import sonia.scm.security.RepositoryPermissionProvider; import sonia.scm.web.VndMediaType; @@ -9,7 +10,6 @@ import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; -import java.util.Collection; /** * RESTful Web Service Resource to get available repository types. @@ -20,31 +20,24 @@ public class RepositoryPermissionResource { static final String PATH = "v2/repositoryPermissions/"; private final RepositoryPermissionProvider repositoryPermissionProvider; + private final ResourceLinks resourceLinks; @Inject - public RepositoryPermissionResource(RepositoryPermissionProvider repositoryPermissionProvider) { + public RepositoryPermissionResource(RepositoryPermissionProvider repositoryPermissionProvider, ResourceLinks resourceLinks) { this.repositoryPermissionProvider = repositoryPermissionProvider; + this.resourceLinks = resourceLinks; } @GET - @Path("verbs") + @Path("") @StatusCodes({ @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 500, condition = "internal server error") }) - @Produces(VndMediaType.REPOSITORY_TYPE_COLLECTION) - public Collection getRepositoryPermissionVerbs() { - return repositoryPermissionProvider.availableVerbs(); - } - - @GET - @Path("roles") - @StatusCodes({ - @ResponseCode(code = 200, condition = "success"), - @ResponseCode(code = 500, condition = "internal server error") - }) - @Produces(VndMediaType.REPOSITORY_TYPE_COLLECTION) - public Collection getRepositoryRoles() { - return repositoryPermissionProvider.availableRoles(); + @Produces(VndMediaType.REPOSITORY_PERMISSION_COLLECTION) + public AvailableRepositoryPermissionsDto get() { + AvailableRepositoryPermissionsDto dto = new AvailableRepositoryPermissionsDto(repositoryPermissionProvider.availableVerbs(), repositoryPermissionProvider.availableRoles()); + dto.add(Links.linkingTo().self(resourceLinks.availableRepositoryPermissions().self()).build()); + return dto; } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index c7369f7cd0..644b3adc3f 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -639,14 +639,30 @@ class ResourceLinks { } static class PermissionsLinks { - private final LinkBuilder permissionsLlinkBuilder; + private final LinkBuilder permissionsLinkBuilder; PermissionsLinks(ScmPathInfo scmPathInfo) { - this.permissionsLlinkBuilder = new LinkBuilder(scmPathInfo, GlobalPermissionResource.class); + this.permissionsLinkBuilder = new LinkBuilder(scmPathInfo, GlobalPermissionResource.class); } String self() { - return permissionsLlinkBuilder.method("getAll").parameters().href(); + return permissionsLinkBuilder.method("getAll").parameters().href(); + } + } + + public AvailableRepositoryPermissionLinks availableRepositoryPermissions() { + return new AvailableRepositoryPermissionLinks(scmPathInfoStore.get()); + } + + static class AvailableRepositoryPermissionLinks { + private final LinkBuilder linkBuilder; + + AvailableRepositoryPermissionLinks(ScmPathInfo scmPathInfo) { + this.linkBuilder = new LinkBuilder(scmPathInfo, RepositoryPermissionResource.class); + } + + String self() { + return linkBuilder.method("get").parameters().href(); } } } diff --git a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml index 14412847a6..acbe0a8a82 100644 --- a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml +++ b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml @@ -9,6 +9,7 @@ push permissionRead permissionWrite + * diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java index 655d00fc10..8714496e1a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java @@ -42,6 +42,7 @@ public class ResourceLinksMock { when(resourceLinks.index()).thenReturn(new ResourceLinks.IndexLinks(uriInfo)); when(resourceLinks.merge()).thenReturn(new ResourceLinks.MergeLinks(uriInfo)); when(resourceLinks.permissions()).thenReturn(new ResourceLinks.PermissionsLinks(uriInfo)); + when(resourceLinks.availableRepositoryPermissions()).thenReturn(new ResourceLinks.AvailableRepositoryPermissionLinks(uriInfo)); return resourceLinks; } diff --git a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java index 487d8b71c8..b5998084f8 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java @@ -4,7 +4,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import sonia.scm.plugin.PluginLoader; import sonia.scm.repository.RepositoryPermissions; -import sonia.scm.store.ConfigurationEntryStoreFactory; import sonia.scm.util.ClassLoaders; import java.lang.reflect.Field; @@ -25,7 +24,6 @@ class RepositoryPermissionProviderTest { void init() { PluginLoader pluginLoader = mock(PluginLoader.class); when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class)); - ConfigurationEntryStoreFactory configurationEntryStoreFactory = mock(ConfigurationEntryStoreFactory.class); repositoryPermissionProvider = new RepositoryPermissionProvider(pluginLoader); allVerbsFromRepositoryClass = Arrays.stream(RepositoryPermissions.class.getDeclaredFields()) .filter(field -> field.getName().startsWith("ACTION_")) @@ -37,13 +35,11 @@ class RepositoryPermissionProviderTest { @Test void shouldReadAvailableRoles() { assertThat(repositoryPermissionProvider.availableRoles()).isNotEmpty(); - assertThat(repositoryPermissionProvider.availableRoles()).allSatisfy(this::eitherStarOrOnlyAvailableVerbs); + assertThat(repositoryPermissionProvider.availableRoles()).allSatisfy(this::containsOnlyAvailableVerbs); } - private void eitherStarOrOnlyAvailableVerbs(RepositoryRole role) { - if (!role.getVerbs().contains("*") || role.getVerbs().size() > 1) { - assertThat(role.getVerbs()).isSubsetOf(allVerbsFromRepositoryClass); - } + private void containsOnlyAvailableVerbs(RepositoryRole role) { + assertThat(role.getVerbs()).isSubsetOf(repositoryPermissionProvider.availableVerbs()); } @Test From 452977c5a977d45290bae8668b1037d9ce9cb18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 13:01:14 +0100 Subject: [PATCH 100/178] Fix unit test --- scm-core/src/test/resources/sonia/scm/shiro.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scm-core/src/test/resources/sonia/scm/shiro.ini b/scm-core/src/test/resources/sonia/scm/shiro.ini index fbdd35ba50..fda268ec83 100644 --- a/scm-core/src/test/resources/sonia/scm/shiro.ini +++ b/scm-core/src/test/resources/sonia/scm/shiro.ini @@ -8,5 +8,5 @@ unpriv = secret [roles] admin = * user = something:* -repo_read = "repository:read:1" -repo_write = "repository:push:1" +repo_read = "repository:read,pull:1" +repo_write = "repository:read,write,pull,push:1" From c33e7713d58791c7ae028d8dcbdd91678a75e588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 13:05:22 +0100 Subject: [PATCH 101/178] Fix integration test --- scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index c431e9c09a..8cdb162740 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -187,7 +187,7 @@ public class GitLfsITCase { IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) .accept("*/*") .type(VndMediaType.REPOSITORY_PERMISSION) - .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"verbs\":[\"read\"]}"); + .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"verbs\":[\"read\",\"pull\"]}"); // upload data as admin String data = UUID.randomUUID().toString(); From 9898cd372123008f6502b061c70c2e0b6bad9abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 15:00:48 +0100 Subject: [PATCH 102/178] Fix authorization events --- .../scm/repository/RepositoryPermission.java | 11 +- .../repository/RepositoryPermissionTest.java | 49 ++++++++ .../AuthorizationChangedEventProducer.java | 4 +- ...AuthorizationChangedEventProducerTest.java | 108 ++++++++++-------- 4 files changed, 121 insertions(+), 51 deletions(-) create mode 100644 scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java index 97872f29eb..e83eaca66c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java @@ -37,6 +37,7 @@ package sonia.scm.repository; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; +import org.apache.commons.collections.CollectionUtils; import sonia.scm.security.PermissionObject; import javax.xml.bind.annotation.XmlAccessType; @@ -45,8 +46,10 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; import java.util.Collection; +import java.util.HashSet; import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableCollection; //~--- JDK imports ------------------------------------------------------------ @@ -76,7 +79,7 @@ public class RepositoryPermission implements PermissionObject, Serializable public RepositoryPermission(String name, Collection verbs, boolean groupPermission) { this.name = name; - this.verbs = verbs; + this.verbs = unmodifiableCollection(new HashSet<>(verbs)); this.groupPermission = groupPermission; } @@ -106,7 +109,7 @@ public class RepositoryPermission implements PermissionObject, Serializable final RepositoryPermission other = (RepositoryPermission) obj; return Objects.equal(name, other.name) - && Objects.equal(verbs, other.verbs) + && CollectionUtils.isEqualCollection(verbs, other.verbs) && Objects.equal(groupPermission, other.groupPermission); } @@ -119,7 +122,9 @@ public class RepositoryPermission implements PermissionObject, Serializable @Override public int hashCode() { - return Objects.hashCode(name, verbs, groupPermission); + // Normally we do not have a log of repository permissions having the same size of verbs, but different content. + // Therefore we do not use the verbs themselves for the hash code but only the number of verbs. + return Objects.hashCode(name, verbs.size(), groupPermission); } diff --git a/scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionTest.java b/scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionTest.java new file mode 100644 index 0000000000..2e9383b2e2 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionTest.java @@ -0,0 +1,49 @@ +package sonia.scm.repository; + +import org.junit.jupiter.api.Test; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +class RepositoryPermissionTest { + + @Test + void shouldBeEqualWithSameVerbs() { + RepositoryPermission permission1 = new RepositoryPermission("name", asList("one", "two"), false); + RepositoryPermission permission2 = new RepositoryPermission("name", asList("two", "one"), false); + + assertThat(permission1).isEqualTo(permission2); + } + + @Test + void shouldHaveSameHashCodeWithSameVerbs() { + long hash1 = new RepositoryPermission("name", asList("one", "two"), false).hashCode(); + long hash2 = new RepositoryPermission("name", asList("two", "one"), false).hashCode(); + + assertThat(hash1).isEqualTo(hash2); + } + + @Test + void shouldNotBeEqualWithSameVerbs() { + RepositoryPermission permission1 = new RepositoryPermission("name", asList("one", "two"), false); + RepositoryPermission permission2 = new RepositoryPermission("name", asList("three", "one"), false); + + assertThat(permission1).isNotEqualTo(permission2); + } + + @Test + void shouldNotBeEqualWithDifferentType() { + RepositoryPermission permission1 = new RepositoryPermission("name", asList("one"), false); + RepositoryPermission permission2 = new RepositoryPermission("name", asList("one"), true); + + assertThat(permission1).isNotEqualTo(permission2); + } + + @Test + void shouldNotBeEqualWithDifferentName() { + RepositoryPermission permission1 = new RepositoryPermission("name1", asList("one"), false); + RepositoryPermission permission2 = new RepositoryPermission("name2", asList("one"), false); + + assertThat(permission1).isNotEqualTo(permission2); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java b/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java index c3e7dc4f0c..0586db2bb3 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java +++ b/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java @@ -167,9 +167,7 @@ public class AuthorizationChangedEventProducer { private boolean isAuthorizationDataModified(Repository repository, Repository beforeModification) { return repository.isArchived() != beforeModification.isArchived() || repository.isPublicReadable() != beforeModification.isPublicReadable() - // TODO RP -// || !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions())) - ; + || !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions())); } private void fireEventForEveryUser() { diff --git a/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java b/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java index de31aa1298..59b6951025 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/AuthorizationChangedEventProducerTest.java @@ -31,21 +31,31 @@ package sonia.scm.security; -import org.junit.Test; -import static org.junit.Assert.*; +import com.google.common.collect.Lists; import org.junit.Before; +import org.junit.Test; import sonia.scm.HandlerEventType; import sonia.scm.group.Group; import sonia.scm.group.GroupEvent; import sonia.scm.group.GroupModificationEvent; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryEvent; +import sonia.scm.repository.RepositoryModificationEvent; +import sonia.scm.repository.RepositoryPermission; import sonia.scm.repository.RepositoryTestData; import sonia.scm.user.User; import sonia.scm.user.UserEvent; import sonia.scm.user.UserModificationEvent; import sonia.scm.user.UserTestData; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + /** * Unit tests for {@link AuthorizationChangedEventProducer}. * @@ -83,7 +93,12 @@ public class AuthorizationChangedEventProducerTest { assertTrue(producer.event.isEveryUserAffected()); assertEquals(username, producer.event.getNameOfAffectedUser()); } - + + private void assertGlobalEventIsFired(){ + assertNotNull(producer.event); + assertFalse(producer.event.isEveryUserAffected()); + } + /** * Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.user.UserEvent)} with modified user. */ @@ -123,11 +138,6 @@ public class AuthorizationChangedEventProducerTest { assertGlobalEventIsFired(); } - private void assertGlobalEventIsFired(){ - assertNotNull(producer.event); - assertFalse(producer.event.isEveryUserAffected()); - } - /** * Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.group.GroupEvent)} with modified groups. */ @@ -168,43 +178,51 @@ public class AuthorizationChangedEventProducerTest { @Test public void testOnRepositoryModificationEvent() { - // TODO RP -// Repository repositoryModified = RepositoryTestData.createHeartOfGold(); -// repositoryModified.setName("test123"); -// repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); -// -// Repository repository = RepositoryTestData.createHeartOfGold(); -// repository.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); -// -// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.BEFORE_CREATE, repositoryModified, repository)); -// assertEventIsNotFired(); -// -// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); -// assertEventIsNotFired(); -// -// repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test"))); -// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); -// assertEventIsNotFired(); -// -// repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test123"))); -// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); -// assertGlobalEventIsFired(); -// -// resetStoredEvent(); -// -// repositoryModified.setPermissions( -// Lists.newArrayList(new RepositoryPermission("test", PermissionType.READ, true)) -// ); -// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); -// assertGlobalEventIsFired(); -// -// resetStoredEvent(); -// -// repositoryModified.setPermissions( -// Lists.newArrayList(new RepositoryPermission("test", PermissionType.WRITE)) -// ); -// producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); -// assertGlobalEventIsFired(); + Repository repositoryModified = RepositoryTestData.createHeartOfGold(); + repositoryModified.setName("test123"); + repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), false))); + + Repository repository = RepositoryTestData.createHeartOfGold(); + repository.setPermissions(Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), false))); + + producer.onEvent(new RepositoryModificationEvent(HandlerEventType.BEFORE_CREATE, repositoryModified, repository)); + assertEventIsNotFired(); + + producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); + assertEventIsNotFired(); + + repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), false))); + producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); + assertEventIsNotFired(); + + repositoryModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test123", singletonList("read"), false))); + producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); + assertGlobalEventIsFired(); + + resetStoredEvent(); + + repositoryModified.setPermissions( + Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), true)) + ); + producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); + assertGlobalEventIsFired(); + + resetStoredEvent(); + + repositoryModified.setPermissions( + Lists.newArrayList(new RepositoryPermission("test", asList("read", "write"), false)) + ); + producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); + assertGlobalEventIsFired(); + + resetStoredEvent(); + repository.setPermissions(Lists.newArrayList(new RepositoryPermission("test", asList("read", "write"), false))); + + repositoryModified.setPermissions( + Lists.newArrayList(new RepositoryPermission("test", asList("write", "read"), false)) + ); + producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository)); + assertEventIsNotFired(); } private void resetStoredEvent(){ From f52edf4dd1cf5f5f52c50c0f1c97eaa5fea9b015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 15:03:40 +0100 Subject: [PATCH 103/178] Add link to available repository permissions to index --- .../main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java index 6377f21163..3eff661385 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java @@ -56,6 +56,7 @@ public class IndexDtoGenerator extends LinkAppenderMapper { if (PermissionPermissions.list().isPermitted()) { builder.single(link("permissions", resourceLinks.permissions().self())); } + builder.single(link("availableRepositoryPermissions", resourceLinks.availableRepositoryPermissions().self())); } else { builder.single(link("login", resourceLinks.authentication().jsonLogin())); } From 42dcaec71afa710628f98ff12a1c471a18feecfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 23 Jan 2019 15:40:08 +0100 Subject: [PATCH 104/178] Keep order of permissions --- .../java/sonia/scm/repository/RepositoryPermission.java | 4 ++-- .../sonia/scm/security/RepositoryPermissionProvider.java | 6 +++--- .../main/resources/META-INF/scm/repository-permissions.xml | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java index e83eaca66c..9e132ef93c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java @@ -46,7 +46,7 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; import java.util.Collection; -import java.util.HashSet; +import java.util.LinkedHashSet; import static java.util.Collections.emptyList; import static java.util.Collections.unmodifiableCollection; @@ -79,7 +79,7 @@ public class RepositoryPermission implements PermissionObject, Serializable public RepositoryPermission(String name, Collection verbs, boolean groupPermission) { this.name = name; - this.verbs = unmodifiableCollection(new HashSet<>(verbs)); + this.verbs = unmodifiableCollection(new LinkedHashSet<>(verbs)); this.groupPermission = groupPermission; } diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java index d11da777e3..0a508753bd 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java @@ -16,7 +16,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.stream.Collectors; @@ -32,8 +32,8 @@ public class RepositoryPermissionProvider { @Inject public RepositoryPermissionProvider(PluginLoader pluginLoader) { AvailableRepositoryPermissions availablePermissions = readAvailablePermissions(pluginLoader); - this.availableVerbs = unmodifiableCollection(new HashSet<>(availablePermissions.availableVerbs)); - this.availableRoles = unmodifiableCollection(new HashSet<>(availablePermissions.availableRoles.stream().map(r -> new RepositoryRole(r.name, r.verbs.verbs)).collect(Collectors.toList()))); + this.availableVerbs = unmodifiableCollection(new LinkedHashSet<>(availablePermissions.availableVerbs)); + this.availableRoles = unmodifiableCollection(new LinkedHashSet<>(availablePermissions.availableRoles.stream().map(r -> new RepositoryRole(r.name, r.verbs.verbs)).collect(Collectors.toList()))); } public Collection availableVerbs() { diff --git a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml index acbe0a8a82..0266e4e22e 100644 --- a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml +++ b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml @@ -3,12 +3,11 @@ read modify delete - delete - healthCheck pull push permissionRead permissionWrite + healthCheck * From 628973ed7d52439b2fabfc366207f8979762c17f Mon Sep 17 00:00:00 2001 From: Matt Harbison Date: Wed, 23 Jan 2019 11:49:57 -0500 Subject: [PATCH 105/178] #1001 support Mercurial 4.7 through 4.9 The command fallback is per the documented example[1], and the date fallback is adapted from hg-evolve. [1] https://www.mercurial-scm.org/repo/hg/rev/86f6b441adea --- .../resources/sonia/scm/hg/ext/fileview.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg/ext/fileview.py b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg/ext/fileview.py index 518f229011..02f3eb3e06 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg/ext/fileview.py +++ b/scm-plugins/scm-hg-plugin/src/main/resources/sonia/scm/hg/ext/fileview.py @@ -32,10 +32,24 @@ Prints date, size and last message of files. """ -from mercurial import cmdutil,util cmdtable = {} -command = cmdutil.command(cmdtable) + +try: + from mercurial import registrar + command = registrar.command(cmdtable) +except (AttributeError, ImportError): + # Fallback to hg < 4.3 support + from mercurial import cmdutil + command = cmdutil.command(cmdtable) + +try: + from mercurial.utils import dateutil + _parsedate = dateutil.parsedate +except ImportError: + # compat with hg < 4.6 + from mercurial import util + _parsedate = util.parsedate class SubRepository: url = None @@ -129,7 +143,7 @@ def printFile(ui, repo, file, disableLastCommit, transport): description = 'n/a' if not disableLastCommit: linkrev = repo[file.linkrev()] - date = '%d %d' % util.parsedate(linkrev.date()) + date = '%d %d' % _parsedate(linkrev.date()) description = linkrev.description() format = '%s %i %s %s\n' if transport: From 5d3cbff461c475283e24bb46af0a288749f062b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 08:05:28 +0100 Subject: [PATCH 106/178] Load available repository permissions --- .../src/AvailableRepositoryPermissions.js | 11 + .../ui-types/src/RepositoryPermissions.js | 2 +- .../packages/ui-types/src/index.js | 2 + .../permissions/containers/Permissions.js | 462 +++++++++--------- .../repos/permissions/modules/permissions.js | 95 +++- 5 files changed, 344 insertions(+), 228 deletions(-) create mode 100644 scm-ui-components/packages/ui-types/src/AvailableRepositoryPermissions.js diff --git a/scm-ui-components/packages/ui-types/src/AvailableRepositoryPermissions.js b/scm-ui-components/packages/ui-types/src/AvailableRepositoryPermissions.js new file mode 100644 index 0000000000..ab7e8d82e4 --- /dev/null +++ b/scm-ui-components/packages/ui-types/src/AvailableRepositoryPermissions.js @@ -0,0 +1,11 @@ +// @flow + +export type RepositoryRole = { + name: string, + verbs: string[] +}; + +export type AvailableRepositoryPermissions = { + availableVerbs: string[], + availableRoles: RepositoryRole[] +}; diff --git a/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js b/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js index 4352c21da6..ed3c925283 100644 --- a/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js +++ b/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js @@ -7,7 +7,7 @@ export type Permission = PermissionCreateEntry & { export type PermissionCreateEntry = { name: string, - type: string, + verbs: string[], groupPermission: boolean } diff --git a/scm-ui-components/packages/ui-types/src/index.js b/scm-ui-components/packages/ui-types/src/index.js index cf739f747d..f7b375ac98 100644 --- a/scm-ui-components/packages/ui-types/src/index.js +++ b/scm-ui-components/packages/ui-types/src/index.js @@ -24,3 +24,5 @@ export type { Permission, PermissionCreateEntry, PermissionCollection } from "./ export type { SubRepository, File } from "./Sources"; export type { SelectValue, AutocompleteObject } from "./Autocomplete"; + +export type { AvailableRepositoryPermissions, RepositoryRole } from "./AvailableRepositoryPermissions"; diff --git a/scm-ui/src/repos/permissions/containers/Permissions.js b/scm-ui/src/repos/permissions/containers/Permissions.js index 48f4e585f7..4d17f65e16 100644 --- a/scm-ui/src/repos/permissions/containers/Permissions.js +++ b/scm-ui/src/repos/permissions/containers/Permissions.js @@ -1,225 +1,237 @@ -//@flow -import React from "react"; -import { connect } from "react-redux"; -import { translate } from "react-i18next"; -import { - fetchPermissions, - getFetchPermissionsFailure, - isFetchPermissionsPending, - getPermissionsOfRepo, - hasCreatePermission, - createPermission, - isCreatePermissionPending, - getCreatePermissionFailure, - createPermissionReset, - getDeletePermissionsFailure, - getModifyPermissionsFailure, - modifyPermissionReset, - deletePermissionReset -} from "../modules/permissions"; -import { Loading, ErrorPage } from "@scm-manager/ui-components"; -import type { - Permission, - PermissionCollection, - PermissionCreateEntry -} from "@scm-manager/ui-types"; -import SinglePermission from "./SinglePermission"; -import CreatePermissionForm from "../components/CreatePermissionForm"; -import type { History } from "history"; -import { getPermissionsLink } from "../../modules/repos"; -import { - getGroupAutoCompleteLink, - getUserAutoCompleteLink -} from "../../../modules/indexResource"; - -type Props = { - namespace: string, - repoName: string, - loading: boolean, - error: Error, - permissions: PermissionCollection, - hasPermissionToCreate: boolean, - loadingCreatePermission: boolean, - permissionsLink: string, - groupAutoCompleteLink: string, - userAutoCompleteLink: string, - - //dispatch functions - fetchPermissions: (link: string, namespace: string, repoName: string) => void, - createPermission: ( - link: string, - permission: PermissionCreateEntry, - namespace: string, - repoName: string, - callback?: () => void - ) => void, - createPermissionReset: (string, string) => void, - modifyPermissionReset: (string, string) => void, - deletePermissionReset: (string, string) => void, - // context props - t: string => string, - match: any, - history: History -}; - -class Permissions extends React.Component { - componentDidMount() { - const { - fetchPermissions, - namespace, - repoName, - modifyPermissionReset, - createPermissionReset, - deletePermissionReset, - permissionsLink - } = this.props; - - createPermissionReset(namespace, repoName); - modifyPermissionReset(namespace, repoName); - deletePermissionReset(namespace, repoName); - fetchPermissions(permissionsLink, namespace, repoName); - } - - createPermission = (permission: Permission) => { - this.props.createPermission( - this.props.permissionsLink, - permission, - this.props.namespace, - this.props.repoName - ); - }; - - render() { - const { - loading, - error, - permissions, - t, - namespace, - repoName, - loadingCreatePermission, - hasPermissionToCreate, - userAutoCompleteLink, - groupAutoCompleteLink - } = this.props; - if (error) { - return ( - - ); - } - - if (loading || !permissions) { - return ; - } - - const createPermissionForm = hasPermissionToCreate ? ( - this.createPermission(permission)} - loading={loadingCreatePermission} - currentPermissions={permissions} - userAutoCompleteLink={userAutoCompleteLink} - groupAutoCompleteLink={groupAutoCompleteLink} - /> - ) : null; - - return ( -
- - - - - - - - - - {permissions.map(permission => { - return ( - - ); - })} - -
{t("permission.name")} - {t("permission.group-permission")} - {t("permission.type")} -
- {createPermissionForm} -
- ); - } -} - -const mapStateToProps = (state, ownProps) => { - const namespace = ownProps.namespace; - const repoName = ownProps.repoName; - const error = - getFetchPermissionsFailure(state, namespace, repoName) || - getCreatePermissionFailure(state, namespace, repoName) || - getDeletePermissionsFailure(state, namespace, repoName) || - getModifyPermissionsFailure(state, namespace, repoName); - const loading = isFetchPermissionsPending(state, namespace, repoName); - const permissions = getPermissionsOfRepo(state, namespace, repoName); - const loadingCreatePermission = isCreatePermissionPending( - state, - namespace, - repoName - ); - const hasPermissionToCreate = hasCreatePermission(state, namespace, repoName); - const permissionsLink = getPermissionsLink(state, namespace, repoName); - const groupAutoCompleteLink = getGroupAutoCompleteLink(state); - const userAutoCompleteLink = getUserAutoCompleteLink(state); - return { - namespace, - repoName, - error, - loading, - permissions, - hasPermissionToCreate, - loadingCreatePermission, - permissionsLink, - groupAutoCompleteLink, - userAutoCompleteLink - }; -}; - -const mapDispatchToProps = dispatch => { - return { - fetchPermissions: (link: string, namespace: string, repoName: string) => { - dispatch(fetchPermissions(link, namespace, repoName)); - }, - createPermission: ( - link: string, - permission: PermissionCreateEntry, - namespace: string, - repoName: string, - callback?: () => void - ) => { - dispatch( - createPermission(link, permission, namespace, repoName, callback) - ); - }, - createPermissionReset: (namespace: string, repoName: string) => { - dispatch(createPermissionReset(namespace, repoName)); - }, - modifyPermissionReset: (namespace: string, repoName: string) => { - dispatch(modifyPermissionReset(namespace, repoName)); - }, - deletePermissionReset: (namespace: string, repoName: string) => { - dispatch(deletePermissionReset(namespace, repoName)); - } - }; -}; - -export default connect( - mapStateToProps, - mapDispatchToProps -)(translate("repos")(Permissions)); +//@flow +import React from "react"; +import { connect } from "react-redux"; +import { translate } from "react-i18next"; +import { + fetchAvailablePermissionsIfNeeded, + fetchPermissions, + getFetchAvailablePermissionsFailure, + getFetchPermissionsFailure, + isFetchAvailablePermissionsPending, + isFetchPermissionsPending, + getPermissionsOfRepo, + hasCreatePermission, + createPermission, + isCreatePermissionPending, + getCreatePermissionFailure, + createPermissionReset, + getDeletePermissionsFailure, + getModifyPermissionsFailure, + modifyPermissionReset, + deletePermissionReset +} from "../modules/permissions"; +import { Loading, ErrorPage } from "@scm-manager/ui-components"; +import type { + Permission, + PermissionCollection, + PermissionCreateEntry +} from "@scm-manager/ui-types"; +import SinglePermission from "./SinglePermission"; +import CreatePermissionForm from "../components/CreatePermissionForm"; +import type { History } from "history"; +import { getPermissionsLink } from "../../modules/repos"; +import { + getGroupAutoCompleteLink, + getUserAutoCompleteLink +} from "../../../modules/indexResource"; + +type Props = { + namespace: string, + repoName: string, + loading: boolean, + error: Error, + permissions: PermissionCollection, + hasPermissionToCreate: boolean, + loadingCreatePermission: boolean, + permissionsLink: string, + groupAutoCompleteLink: string, + userAutoCompleteLink: string, + + //dispatch functions + fetchAvailablePermissionsIfNeeded: () => void, + fetchPermissions: (link: string, namespace: string, repoName: string) => void, + createPermission: ( + link: string, + permission: PermissionCreateEntry, + namespace: string, + repoName: string, + callback?: () => void + ) => void, + createPermissionReset: (string, string) => void, + modifyPermissionReset: (string, string) => void, + deletePermissionReset: (string, string) => void, + // context props + t: string => string, + match: any, + history: History +}; + +class Permissions extends React.Component { + componentDidMount() { + const { + fetchAvailablePermissionsIfNeeded, + fetchPermissions, + namespace, + repoName, + modifyPermissionReset, + createPermissionReset, + deletePermissionReset, + permissionsLink + } = this.props; + + createPermissionReset(namespace, repoName); + modifyPermissionReset(namespace, repoName); + deletePermissionReset(namespace, repoName); + fetchAvailablePermissionsIfNeeded(); + fetchPermissions(permissionsLink, namespace, repoName); + } + + createPermission = (permission: Permission) => { + this.props.createPermission( + this.props.permissionsLink, + permission, + this.props.namespace, + this.props.repoName + ); + }; + + render() { + const { + loading, + error, + permissions, + t, + namespace, + repoName, + loadingCreatePermission, + hasPermissionToCreate, + userAutoCompleteLink, + groupAutoCompleteLink + } = this.props; + if (error) { + return ( + + ); + } + + if (loading || !permissions) { + return ; + } + + const createPermissionForm = hasPermissionToCreate ? ( + this.createPermission(permission)} + loading={loadingCreatePermission} + currentPermissions={permissions} + userAutoCompleteLink={userAutoCompleteLink} + groupAutoCompleteLink={groupAutoCompleteLink} + /> + ) : null; + + return ( +
+ + + + + + + + + + {permissions.map(permission => { + return ( + + ); + })} + +
{t("permission.name")} + {t("permission.group-permission")} + {t("permission.type")} +
+ {createPermissionForm} +
+ ); + } +} + +const mapStateToProps = (state, ownProps) => { + const namespace = ownProps.namespace; + const repoName = ownProps.repoName; + const error = + getFetchPermissionsFailure(state, namespace, repoName) || + getCreatePermissionFailure(state, namespace, repoName) || + getDeletePermissionsFailure(state, namespace, repoName) || + getModifyPermissionsFailure(state, namespace, repoName) || + getFetchAvailablePermissionsFailure(state); + const loading = + isFetchPermissionsPending(state, namespace, repoName) || + isFetchAvailablePermissionsPending(state); + const permissions = getPermissionsOfRepo(state, namespace, repoName); + const loadingCreatePermission = isCreatePermissionPending( + state, + namespace, + repoName + ); + const hasPermissionToCreate = hasCreatePermission(state, namespace, repoName); + const permissionsLink = getPermissionsLink(state, namespace, repoName); + const groupAutoCompleteLink = getGroupAutoCompleteLink(state); + const userAutoCompleteLink = getUserAutoCompleteLink(state); + return { + namespace, + repoName, + error, + loading, + permissions, + hasPermissionToCreate, + loadingCreatePermission, + permissionsLink, + groupAutoCompleteLink, + userAutoCompleteLink + }; +}; + +const mapDispatchToProps = dispatch => { + return { + fetchPermissions: (link: string, namespace: string, repoName: string) => { + dispatch(fetchPermissions(link, namespace, repoName)); + }, + fetchAvailablePermissionsIfNeeded: () => { + dispatch(fetchAvailablePermissionsIfNeeded()); + }, + createPermission: ( + link: string, + permission: PermissionCreateEntry, + namespace: string, + repoName: string, + callback?: () => void + ) => { + dispatch( + createPermission(link, permission, namespace, repoName, callback) + ); + }, + createPermissionReset: (namespace: string, repoName: string) => { + dispatch(createPermissionReset(namespace, repoName)); + }, + modifyPermissionReset: (namespace: string, repoName: string) => { + dispatch(modifyPermissionReset(namespace, repoName)); + }, + deletePermissionReset: (namespace: string, repoName: string) => { + dispatch(deletePermissionReset(namespace, repoName)); + } + }; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(translate("repos")(Permissions)); diff --git a/scm-ui/src/repos/permissions/modules/permissions.js b/scm-ui/src/repos/permissions/modules/permissions.js index 9f5330bbcd..74d0ea5bc7 100644 --- a/scm-ui/src/repos/permissions/modules/permissions.js +++ b/scm-ui/src/repos/permissions/modules/permissions.js @@ -4,6 +4,7 @@ import type { Action } from "@scm-manager/ui-components"; import { apiClient } from "@scm-manager/ui-components"; import * as types from "../../../modules/types"; import type { + AvailableRepositoryPermissions, Permission, PermissionCollection, PermissionCreateEntry @@ -11,7 +12,18 @@ import type { import { isPending } from "../../../modules/pending"; import { getFailure } from "../../../modules/failure"; import { Dispatch } from "redux"; +import { getLinks } from "../../../modules/indexResource"; +export const FETCH_AVAILABLE = "scm/permissions/FETCH_AVAILABLE"; +export const FETCH_AVAILABLE_PENDING = `${FETCH_AVAILABLE}_${ + types.PENDING_SUFFIX +}`; +export const FETCH_AVAILABLE_SUCCESS = `${FETCH_AVAILABLE}_${ + types.SUCCESS_SUFFIX +}`; +export const FETCH_AVAILABLE_FAILURE = `${FETCH_AVAILABLE}_${ + types.FAILURE_SUFFIX +}`; export const FETCH_PERMISSIONS = "scm/permissions/FETCH_PERMISSIONS"; export const FETCH_PERMISSIONS_PENDING = `${FETCH_PERMISSIONS}_${ types.PENDING_SUFFIX @@ -62,7 +74,71 @@ export const DELETE_PERMISSION_RESET = `${DELETE_PERMISSION}_${ types.RESET_SUFFIX }`; -const CONTENT_TYPE = "application/vnd.scmm-permission+json"; +const CONTENT_TYPE = "application/vnd.scmm-repositoryPermission+json"; + +// fetch available permissions + +export function fetchAvailablePermissionsIfNeeded() { + return function(dispatch: any, getState: () => Object) { + if (shouldFetchAvailablePermissions(getState())) { + return fetchAvailablePermissions(dispatch, getState); + } + }; +} + +export function fetchAvailablePermissions( + dispatch: any, + getState: () => Object +) { + dispatch(fetchAvailablePending()); + return apiClient + .get(getLinks(getState()).availableRepositoryPermissions.href) + .then(response => response.json()) + .then(available => { + dispatch(fetchAvailableSuccess(available)); + }) + .catch(err => { + dispatch(fetchAvailableFailure(err)); + }); +} + +export function shouldFetchAvailablePermissions(state: Object) { + if ( + isFetchAvailablePermissionsPending(state) || + getFetchAvailablePermissionsFailure(state) + ) { + return false; + } + return !state.available; +} + +export function fetchAvailablePending(): Action { + return { + type: FETCH_AVAILABLE_PENDING, + payload: {}, + itemId: "available" + }; +} + +export function fetchAvailableSuccess( + available: AvailableRepositoryPermissions +): Action { + return { + type: FETCH_AVAILABLE_SUCCESS, + payload: available, + itemId: "available" + }; +} + +export function fetchAvailableFailure(error: Error): Action { + return { + type: FETCH_AVAILABLE_FAILURE, + payload: { + error + }, + itemId: "available" + }; +} // fetch permissions @@ -368,6 +444,7 @@ export function deletePermissionReset(namespace: string, repoName: string) { itemId: namespace + "/" + repoName }; } + function deletePermissionFromState( oldPermissions: PermissionCollection, permission: Permission @@ -399,12 +476,17 @@ export default function reducer( return state; } switch (action.type) { + case FETCH_AVAILABLE_SUCCESS: + return { + ...state, + available: action.payload + }; case FETCH_PERMISSIONS_SUCCESS: return { ...state, [action.itemId]: { entries: action.payload._embedded.permissions, - createPermission: action.payload._links.create ? true : false + createPermission: !!action.payload._links.create } }; case MODIFY_PERMISSION_SUCCESS: @@ -463,6 +545,10 @@ export function getPermissionsOfRepo( } } +export function isFetchAvailablePermissionsPending(state: Object) { + return isPending(state, FETCH_AVAILABLE, "available"); +} + export function isFetchPermissionsPending( state: Object, namespace: string, @@ -471,6 +557,10 @@ export function isFetchPermissionsPending( return isPending(state, FETCH_PERMISSIONS, namespace + "/" + repoName); } +export function getFetchAvailablePermissionsFailure(state: Object) { + return getFailure(state, FETCH_AVAILABLE, "available"); +} + export function getFetchPermissionsFailure( state: Object, namespace: string, @@ -522,6 +612,7 @@ export function isCreatePermissionPending( ) { return isPending(state, CREATE_PERMISSION, namespace + "/" + repoName); } + export function getCreatePermissionFailure( state: Object, namespace: string, From 5b8518fbd9836d60d62094c876d5b4da1c33ce5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 09:53:26 +0100 Subject: [PATCH 107/178] Load available permissions and find matching role --- .../permissions/components/TypeSelector.js | 93 ++-- .../permissions/containers/Permissions.js | 9 +- .../containers/SinglePermission.js | 397 ++++++++++-------- .../repos/permissions/modules/permissions.js | 6 + 4 files changed, 286 insertions(+), 219 deletions(-) diff --git a/scm-ui/src/repos/permissions/components/TypeSelector.js b/scm-ui/src/repos/permissions/components/TypeSelector.js index bec2c5b278..9945fa4def 100644 --- a/scm-ui/src/repos/permissions/components/TypeSelector.js +++ b/scm-ui/src/repos/permissions/components/TypeSelector.js @@ -1,42 +1,51 @@ -// @flow -import React from "react"; -import { translate } from "react-i18next"; -import { Select } from "@scm-manager/ui-components"; - -type Props = { - t: string => string, - handleTypeChange: string => void, - type: string, - label?: string, - helpText?: string, - loading?: boolean -}; - -class TypeSelector extends React.Component { - render() { - const { type, handleTypeChange, loading, label, helpText } = this.props; - const types = ["READ", "OWNER", "WRITE"]; - - return ( - + ); + } + + createSelectOptions(types: string[]) { + return types.map(type => { + return { + label: type, + value: type + }; + }); + } +} + +export default translate("repos")(TypeSelector); diff --git a/scm-ui/src/repos/permissions/containers/Permissions.js b/scm-ui/src/repos/permissions/containers/Permissions.js index 4d17f65e16..830d71df66 100644 --- a/scm-ui/src/repos/permissions/containers/Permissions.js +++ b/scm-ui/src/repos/permissions/containers/Permissions.js @@ -6,6 +6,7 @@ import { fetchAvailablePermissionsIfNeeded, fetchPermissions, getFetchAvailablePermissionsFailure, + getAvailablePermissions, getFetchPermissionsFailure, isFetchAvailablePermissionsPending, isFetchPermissionsPending, @@ -22,6 +23,7 @@ import { } from "../modules/permissions"; import { Loading, ErrorPage } from "@scm-manager/ui-components"; import type { + AvailableRepositoryPermissions, Permission, PermissionCollection, PermissionCreateEntry @@ -36,6 +38,7 @@ import { } from "../../../modules/indexResource"; type Props = { + availablePermissions: AvailableRepositoryPermissions, namespace: string, repoName: string, loading: boolean, @@ -97,6 +100,7 @@ class Permissions extends React.Component { render() { const { + availablePermissions, loading, error, permissions, @@ -118,7 +122,7 @@ class Permissions extends React.Component { ); } - if (loading || !permissions) { + if (loading || !permissions || !availablePermissions) { return ; } @@ -149,6 +153,7 @@ class Permissions extends React.Component { {permissions.map(permission => { return ( { const permissionsLink = getPermissionsLink(state, namespace, repoName); const groupAutoCompleteLink = getGroupAutoCompleteLink(state); const userAutoCompleteLink = getUserAutoCompleteLink(state); + const availablePermissions = getAvailablePermissions(state); return { + availablePermissions, namespace, repoName, error, diff --git a/scm-ui/src/repos/permissions/containers/SinglePermission.js b/scm-ui/src/repos/permissions/containers/SinglePermission.js index 62380128be..1f260b4ae7 100644 --- a/scm-ui/src/repos/permissions/containers/SinglePermission.js +++ b/scm-ui/src/repos/permissions/containers/SinglePermission.js @@ -1,176 +1,221 @@ -// @flow -import React from "react"; -import type { Permission } from "@scm-manager/ui-types"; -import { translate } from "react-i18next"; -import { - modifyPermission, - isModifyPermissionPending, - deletePermission, - isDeletePermissionPending -} from "../modules/permissions"; -import { connect } from "react-redux"; -import type { History } from "history"; -import { Checkbox } from "@scm-manager/ui-components"; -import DeletePermissionButton from "../components/buttons/DeletePermissionButton"; -import TypeSelector from "../components/TypeSelector"; - -type Props = { - submitForm: Permission => void, - modifyPermission: (Permission, string, string) => void, - permission: Permission, - t: string => string, - namespace: string, - repoName: string, - match: any, - history: History, - loading: boolean, - deletePermission: (Permission, string, string) => void, - deleteLoading: boolean -}; - -type State = { - permission: Permission -}; - -class SinglePermission extends React.Component { - constructor(props: Props) { - super(props); - - this.state = { - permission: { - name: "", - type: "READ", - groupPermission: false, - _links: {} - } - }; - } - - componentDidMount() { - const { permission } = this.props; - if (permission) { - this.setState({ - permission: { - name: permission.name, - type: permission.type, - groupPermission: permission.groupPermission, - _links: permission._links - } - }); - } - } - - deletePermission = () => { - this.props.deletePermission( - this.props.permission, - this.props.namespace, - this.props.repoName - ); - }; - - render() { - const { permission } = this.state; - const { loading, namespace, repoName } = this.props; - const typeSelector = - this.props.permission._links && this.props.permission._links.update ? ( - - - - ) : ( - {permission.type} - ); - - return ( - - {permission.name} - - - - {typeSelector} - - - - - ); - } - - handleTypeChange = (type: string) => { - this.setState({ - permission: { - ...this.state.permission, - type: type - } - }); - this.modifyPermission(type); - }; - - modifyPermission = (type: string) => { - let permission = this.state.permission; - permission.type = type; - this.props.modifyPermission( - permission, - this.props.namespace, - this.props.repoName - ); - }; - - createSelectOptions(types: string[]) { - return types.map(type => { - return { - label: type, - value: type - }; - }); - } -} - -const mapStateToProps = (state, ownProps) => { - const permission = ownProps.permission; - const loading = isModifyPermissionPending( - state, - ownProps.namespace, - ownProps.repoName, - permission - ); - const deleteLoading = isDeletePermissionPending( - state, - ownProps.namespace, - ownProps.repoName, - permission - ); - - return { loading, deleteLoading }; -}; - -const mapDispatchToProps = dispatch => { - return { - modifyPermission: ( - permission: Permission, - namespace: string, - repoName: string - ) => { - dispatch(modifyPermission(permission, namespace, repoName)); - }, - deletePermission: ( - permission: Permission, - namespace: string, - repoName: string - ) => { - dispatch(deletePermission(permission, namespace, repoName)); - } - }; -}; -export default connect( - mapStateToProps, - mapDispatchToProps -)(translate("repos")(SinglePermission)); +// @flow +import React from "react"; +import type { + AvailableRepositoryPermissions, + Permission +} from "@scm-manager/ui-types"; +import { translate } from "react-i18next"; +import { + modifyPermission, + isModifyPermissionPending, + deletePermission, + isDeletePermissionPending +} from "../modules/permissions"; +import { connect } from "react-redux"; +import type { History } from "history"; +import { Checkbox } from "@scm-manager/ui-components"; +import DeletePermissionButton from "../components/buttons/DeletePermissionButton"; +import TypeSelector from "../components/TypeSelector"; + +type Props = { + availablePermissions: AvailableRepositoryPermissions, + submitForm: Permission => void, + modifyPermission: (Permission, string, string) => void, + permission: Permission, + t: string => string, + namespace: string, + repoName: string, + match: any, + history: History, + loading: boolean, + deletePermission: (Permission, string, string) => void, + deleteLoading: boolean +}; + +type State = { + role: string, + permission: Permission +}; + +class SinglePermission extends React.Component { + constructor(props: Props) { + super(props); + + const defaultPermission = props.availablePermissions.availableRoles + ? props.availablePermissions.availableRoles[0] + : {}; + + this.state = { + permission: { + name: "", + verbs: defaultPermission.verbs, + groupPermission: false, + _links: {} + }, + role: defaultPermission.name + }; + } + + componentDidMount() { + const { permission } = this.props; + + const matchingRole = this.findMatchingRoleName(); + + if (permission) { + this.setState({ + permission: { + name: permission.name, + verbs: permission.verbs, + groupPermission: permission.groupPermission, + _links: permission._links + }, + role: matchingRole + }); + } + } + + findMatchingRoleName = () => { + const { availablePermissions, permission } = this.props; + if (!permission) { + return ""; + } + const matchingRole = availablePermissions.availableRoles.find(role => { + return this.equalVerbs(role.verbs, permission.verbs); + }); + + if (matchingRole) { + return matchingRole.name; + } else { + return ""; + } + }; + equalVerbs = (verbs1: string[], verbs2: string[]) => { + if (!verbs1 || !verbs2) { + return false; + } + + if (verbs1.length !== verbs2.length) { + return false; + } + + return verbs1.every(verb => verbs2.includes(verb)); + }; + + deletePermission = () => { + this.props.deletePermission( + this.props.permission, + this.props.namespace, + this.props.repoName + ); + }; + + render() { + const { role, permission } = this.state; + const { availablePermissions, loading, namespace, repoName } = this.props; + const availableRoleNames = availablePermissions.availableRoles.map( + r => r.name + ); + const typeSelector = + this.props.permission._links && this.props.permission._links.update ? ( + + + + ) : ( + {role} + ); + + return ( + + {permission.name} + + + + {typeSelector} + + + + + ); + } + + handleTypeChange = (type: string) => { + this.setState({ + permission: { + ...this.state.permission, + type: type + } + }); + this.modifyPermission(type); + }; + + modifyPermission = (type: string) => { + let permission = this.state.permission; + permission.type = type; + this.props.modifyPermission( + permission, + this.props.namespace, + this.props.repoName + ); + }; + + createSelectOptions(types: string[]) { + return types.map(type => { + return { + label: type, + value: type + }; + }); + } +} + +const mapStateToProps = (state, ownProps) => { + const permission = ownProps.permission; + const loading = isModifyPermissionPending( + state, + ownProps.namespace, + ownProps.repoName, + permission + ); + const deleteLoading = isDeletePermissionPending( + state, + ownProps.namespace, + ownProps.repoName, + permission + ); + + return { loading, deleteLoading }; +}; + +const mapDispatchToProps = dispatch => { + return { + modifyPermission: ( + permission: Permission, + namespace: string, + repoName: string + ) => { + dispatch(modifyPermission(permission, namespace, repoName)); + }, + deletePermission: ( + permission: Permission, + namespace: string, + repoName: string + ) => { + dispatch(deletePermission(permission, namespace, repoName)); + } + }; +}; +export default connect( + mapStateToProps, + mapDispatchToProps +)(translate("repos")(SinglePermission)); diff --git a/scm-ui/src/repos/permissions/modules/permissions.js b/scm-ui/src/repos/permissions/modules/permissions.js index 74d0ea5bc7..02c4670815 100644 --- a/scm-ui/src/repos/permissions/modules/permissions.js +++ b/scm-ui/src/repos/permissions/modules/permissions.js @@ -534,6 +534,12 @@ export default function reducer( // selectors +export function getAvailablePermissions(state: Object) { + if (state.permissions) { + return state.permissions.available; + } +} + export function getPermissionsOfRepo( state: Object, namespace: string, From 9fecc2396071ebb99affc5ede707caca6780c026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 09:54:04 +0100 Subject: [PATCH 108/178] Make READ the default role --- .../META-INF/scm/repository-permissions.xml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml index 0266e4e22e..4646482fe7 100644 --- a/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml +++ b/scm-webapp/src/main/resources/META-INF/scm/repository-permissions.xml @@ -12,31 +12,31 @@ - OWNER + READ - * + read + pull - WRITER + WRITE read pull push - - READER - - read - pull - - HEALTH healthCheck + + OWNER + + * + +
From 7385d6778e05e1f51d2aaa63086e63f09755ccfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 10:29:51 +0100 Subject: [PATCH 109/178] Add permissions for new user --- .../components/CreatePermissionForm.js | 56 +++++++++++++------ .../permissions/containers/Permissions.js | 1 + .../containers/SinglePermission.js | 52 ++++++----------- .../repos/permissions/modules/permissions.js | 30 ++++++++++ 4 files changed, 87 insertions(+), 52 deletions(-) diff --git a/scm-ui/src/repos/permissions/components/CreatePermissionForm.js b/scm-ui/src/repos/permissions/components/CreatePermissionForm.js index 5fd8224be4..f5a688eb9f 100644 --- a/scm-ui/src/repos/permissions/components/CreatePermissionForm.js +++ b/scm-ui/src/repos/permissions/components/CreatePermissionForm.js @@ -4,14 +4,17 @@ import { translate } from "react-i18next"; import { Autocomplete, SubmitButton } from "@scm-manager/ui-components"; import TypeSelector from "./TypeSelector"; import type { + AvailableRepositoryPermissions, PermissionCollection, PermissionCreateEntry, SelectValue } from "@scm-manager/ui-types"; import * as validator from "./permissionValidation"; +import { findMatchingRoleName } from "../modules/permissions"; type Props = { t: string => string, + availablePermissions: AvailableRepositoryPermissions, createPermission: (permission: PermissionCreateEntry) => void, loading: boolean, currentPermissions: PermissionCollection, @@ -21,7 +24,7 @@ type Props = { type State = { name: string, - type: string, + verbs: string[], groupPermission: boolean, valid: boolean, value?: SelectValue @@ -33,7 +36,7 @@ class CreatePermissionForm extends React.Component { this.state = { name: "", - type: "READ", + verbs: props.availablePermissions.availableRoles[0].verbs, groupPermission: false, valid: true, value: undefined @@ -121,9 +124,14 @@ class CreatePermissionForm extends React.Component { }; render() { - const { t, loading } = this.props; + const { t, availablePermissions, loading } = this.props; - const { type } = this.state; + const { verbs } = this.state; + + const availableRoleNames = availablePermissions.availableRoles.map( + r => r.name + ); + const matchingRole = findMatchingRoleName(availablePermissions, verbs); return (
@@ -155,20 +163,25 @@ class CreatePermissionForm extends React.Component {
-
+
- {this.renderAutocompletionField()} + {this.renderAutocompletionField()}
- +
-
-
+
+
{ disabled={!this.state.valid || this.state.name === ""} />
-
+
); @@ -185,7 +198,7 @@ class CreatePermissionForm extends React.Component { submit = e => { this.props.createPermission({ name: this.state.name, - type: this.state.type, + verbs: this.state.verbs, groupPermission: this.state.groupPermission }); this.removeState(); @@ -195,17 +208,24 @@ class CreatePermissionForm extends React.Component { removeState = () => { this.setState({ name: "", - type: "READ", + verbs: this.props.availablePermissions.availableRoles[0].verbs, groupPermission: false, valid: true }); }; handleTypeChange = (type: string) => { + const selectedRole = this.findAvailableRole(type); this.setState({ - type: type + verbs: selectedRole.verbs }); }; + + findAvailableRole = (type: string) => { + return this.props.availablePermissions.availableRoles.find( + role => role.name === type + ); + }; } export default translate("repos")(CreatePermissionForm); diff --git a/scm-ui/src/repos/permissions/containers/Permissions.js b/scm-ui/src/repos/permissions/containers/Permissions.js index 830d71df66..3994b1e10b 100644 --- a/scm-ui/src/repos/permissions/containers/Permissions.js +++ b/scm-ui/src/repos/permissions/containers/Permissions.js @@ -128,6 +128,7 @@ class Permissions extends React.Component { const createPermissionForm = hasPermissionToCreate ? ( this.createPermission(permission)} loading={loadingCreatePermission} currentPermissions={permissions} diff --git a/scm-ui/src/repos/permissions/containers/SinglePermission.js b/scm-ui/src/repos/permissions/containers/SinglePermission.js index 1f260b4ae7..6c019afcb8 100644 --- a/scm-ui/src/repos/permissions/containers/SinglePermission.js +++ b/scm-ui/src/repos/permissions/containers/SinglePermission.js @@ -9,7 +9,8 @@ import { modifyPermission, isModifyPermissionPending, deletePermission, - isDeletePermissionPending + isDeletePermissionPending, + findMatchingRoleName } from "../modules/permissions"; import { connect } from "react-redux"; import type { History } from "history"; @@ -57,9 +58,12 @@ class SinglePermission extends React.Component { } componentDidMount() { - const { permission } = this.props; + const { availablePermissions, permission } = this.props; - const matchingRole = this.findMatchingRoleName(); + const matchingRole = findMatchingRoleName( + availablePermissions, + permission.verbs + ); if (permission) { this.setState({ @@ -74,33 +78,6 @@ class SinglePermission extends React.Component { } } - findMatchingRoleName = () => { - const { availablePermissions, permission } = this.props; - if (!permission) { - return ""; - } - const matchingRole = availablePermissions.availableRoles.find(role => { - return this.equalVerbs(role.verbs, permission.verbs); - }); - - if (matchingRole) { - return matchingRole.name; - } else { - return ""; - } - }; - equalVerbs = (verbs1: string[], verbs2: string[]) => { - if (!verbs1 || !verbs2) { - return false; - } - - if (verbs1.length !== verbs2.length) { - return false; - } - - return verbs1.every(verb => verbs2.includes(verb)); - }; - deletePermission = () => { this.props.deletePermission( this.props.permission, @@ -150,18 +127,25 @@ class SinglePermission extends React.Component { } handleTypeChange = (type: string) => { + const selectedRole = this.findAvailableRole(type); this.setState({ permission: { ...this.state.permission, - type: type + verbs: selectedRole.verbs } }); - this.modifyPermission(type); + this.modifyPermission(selectedRole.verbs); }; - modifyPermission = (type: string) => { + findAvailableRole = (type: string) => { + return this.props.availablePermissions.availableRoles.find( + role => role.name === type + ); + }; + + modifyPermission = (verbs: string[]) => { let permission = this.state.permission; - permission.type = type; + permission.verbs = verbs; this.props.modifyPermission( permission, this.props.namespace, diff --git a/scm-ui/src/repos/permissions/modules/permissions.js b/scm-ui/src/repos/permissions/modules/permissions.js index 02c4670815..cb6b013c61 100644 --- a/scm-ui/src/repos/permissions/modules/permissions.js +++ b/scm-ui/src/repos/permissions/modules/permissions.js @@ -700,3 +700,33 @@ export function getModifyPermissionsFailure( } return null; } + +export function findMatchingRoleName( + availablePermissions: AvailableRepositoryPermissions, + verbs: string[] +) { + if (!verbs) { + return ""; + } + const matchingRole = availablePermissions.availableRoles.find(role => { + return equalVerbs(role.verbs, verbs); + }); + + if (matchingRole) { + return matchingRole.name; + } else { + return ""; + } +} + +function equalVerbs(verbs1: string[], verbs2: string[]) { + if (!verbs1 || !verbs2) { + return false; + } + + if (verbs1.length !== verbs2.length) { + return false; + } + + return verbs1.every(verb => verbs2.includes(verb)); +} From f9745121170f789c12088dd0aa308d4f4de967b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 10:30:17 +0100 Subject: [PATCH 110/178] Validate new permissions --- .../sonia/scm/api/v2/resources/RepositoryPermissionDto.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java index 0699b78e91..a896ba385d 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionDto.java @@ -7,7 +7,9 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.util.Collection; @@ -22,6 +24,7 @@ public class RepositoryPermissionDto extends HalRepresentation { @Pattern(regexp = USER_GROUP_PATTERN) private String name; + @NotEmpty @NotNull private Collection verbs; private boolean groupPermission = false; From 905177a8577d6f251bcc31c6dc96e497adc21daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 10:45:23 +0100 Subject: [PATCH 111/178] Set selected role after update --- scm-ui/src/repos/permissions/containers/SinglePermission.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scm-ui/src/repos/permissions/containers/SinglePermission.js b/scm-ui/src/repos/permissions/containers/SinglePermission.js index 6c019afcb8..cdeb536632 100644 --- a/scm-ui/src/repos/permissions/containers/SinglePermission.js +++ b/scm-ui/src/repos/permissions/containers/SinglePermission.js @@ -132,7 +132,8 @@ class SinglePermission extends React.Component { permission: { ...this.state.permission, verbs: selectedRole.verbs - } + }, + role: type }); this.modifyPermission(selectedRole.verbs); }; From 813153dfa149d6a696e561936c17979b37bc7057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 11:53:57 +0100 Subject: [PATCH 112/178] Add advanced dialog --- scm-ui/public/locales/en/permissions.json | 7 ++ .../permissions/components/TypeSelector.js | 8 +- .../containers/AdvancedPermissionsDialog.js | 87 +++++++++++++++++++ .../containers/SinglePermission.js | 65 +++++++++++--- 4 files changed, 154 insertions(+), 13 deletions(-) create mode 100644 scm-ui/src/repos/permissions/containers/AdvancedPermissionsDialog.js diff --git a/scm-ui/public/locales/en/permissions.json b/scm-ui/public/locales/en/permissions.json index 52059db60a..209e317cff 100644 --- a/scm-ui/public/locales/en/permissions.json +++ b/scm-ui/public/locales/en/permissions.json @@ -4,5 +4,12 @@ "label": "Set permissions" }, "set-permissions-successful": "Permissions set successfully" + }, + "advanced": { + "dialog": { + "title": "Advanced permissions", + "submit": "Submit", + "abort": "Abort" + } } } diff --git a/scm-ui/src/repos/permissions/components/TypeSelector.js b/scm-ui/src/repos/permissions/components/TypeSelector.js index 9945fa4def..4b027bdc6b 100644 --- a/scm-ui/src/repos/permissions/components/TypeSelector.js +++ b/scm-ui/src/repos/permissions/components/TypeSelector.js @@ -26,11 +26,15 @@ class TypeSelector extends React.Component { if (!availableTypes) return null; + const options = type + ? this.createSelectOptions(availableTypes) + : ["", ...this.createSelectOptions(availableTypes)]; + return ( + ); + } + + createSelectOptions(roles: string[]) { + return roles.map(role => { + return { + label: role, + value: role + }; + }); + } +} + +export default translate("repos")(RoleSelector); diff --git a/scm-ui/src/repos/permissions/components/TypeSelector.js b/scm-ui/src/repos/permissions/components/TypeSelector.js deleted file mode 100644 index 4b027bdc6b..0000000000 --- a/scm-ui/src/repos/permissions/components/TypeSelector.js +++ /dev/null @@ -1,55 +0,0 @@ -// @flow -import React from "react"; -import { translate } from "react-i18next"; -import { Select } from "@scm-manager/ui-components"; - -type Props = { - t: string => string, - availableTypes: string[], - handleTypeChange: string => void, - type: string, - label?: string, - helpText?: string, - loading?: boolean -}; - -class TypeSelector extends React.Component { - render() { - const { - availableTypes, - type, - handleTypeChange, - loading, - label, - helpText - } = this.props; - - if (!availableTypes) return null; - - const options = type - ? this.createSelectOptions(availableTypes) - : ["", ...this.createSelectOptions(availableTypes)]; - - return ( -