diff --git a/CHANGELOG.md b/CHANGELOG.md index 2747e98d3a..f5c3c2da29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix usage of invalid cipher algorith on newer java versions ([#1110](https://github.com/scm-manager/scm-manager/issues/1110),[#1112](https://github.com/scm-manager/scm-manager/pull/1112)) - Handle obscure line breaks in diff viewer ([#1129](https://github.com/scm-manager/scm-manager/pull/1129)) - Validate subversion client checksum ([#1113](https://github.com/scm-manager/scm-manager/issues/1113)) +- Fix plugin manage permission ([#1135](https://github.com/scm-manager/scm-manager/pull/1135)) ## [2.0.0-rc7] - 2020-04-09 ### Added diff --git a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java index bd89156071..20f3751070 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java +++ b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java @@ -47,7 +47,7 @@ import java.io.Serializable; value = "plugin", generatedClass = "PluginPermissions", permissions = {}, - globalPermissions = {"read", "manage"}, + globalPermissions = {"read", "write"}, custom = true, customGlobal = true ) @XmlAccessorType(XmlAccessType.FIELD) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailablePluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailablePluginResource.java index b898eadafa..c4f11d8a91 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailablePluginResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AvailablePluginResource.java @@ -178,7 +178,7 @@ public class AvailablePluginResource { ) ) public Response installPlugin(@PathParam("name") String name, @QueryParam("restart") boolean restartAfterInstallation) { - PluginPermissions.manage().check(); + PluginPermissions.write().check(); pluginManager.install(name, restartAfterInstallation); return Response.ok().build(); } 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 8b0a0a5565..6f6ae8f6bc 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 @@ -82,7 +82,7 @@ public class IndexDtoGenerator extends HalAppenderMapper { builder.single(link("installedPlugins", resourceLinks.installedPluginCollection().self())); builder.single(link("availablePlugins", resourceLinks.availablePluginCollection().self())); } - if (PluginPermissions.manage().isPermitted()) { + if (PluginPermissions.write().isPermitted()) { builder.single(link("pendingPlugins", resourceLinks.pendingPluginCollection().self())); } if (UserPermissions.list().isPermitted()) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java index 72b44dc33d..0d59e4ef28 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java @@ -118,7 +118,7 @@ public class PendingPluginResource { List uninstallDtos = uninstallPlugins.map(i -> mapper.mapInstalled(i, pending)).collect(toList()); if ( - PluginPermissions.manage().isPermitted() && + PluginPermissions.write().isPermitted() && (!installDtos.isEmpty() || !updateDtos.isEmpty() || !uninstallDtos.isEmpty()) ) { if (restarter.isSupported()) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java index b579935b30..ff66f2bc85 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java @@ -31,6 +31,7 @@ import de.otto.edison.hal.Links; import sonia.scm.plugin.AvailablePlugin; import sonia.scm.plugin.InstalledPlugin; import sonia.scm.plugin.PluginManager; +import sonia.scm.plugin.PluginPermissions; import java.util.List; @@ -71,7 +72,7 @@ public class PluginDtoCollectionMapper { Links.Builder linksBuilder = linkingTo() .with(Links.linkingTo().self(baseUrl).build()); - if (!manager.getUpdatable().isEmpty()) { + if (!manager.getUpdatable().isEmpty() && PluginPermissions.write().isPermitted()) { linksBuilder.single(link("update", resourceLinks.installedPluginCollection().update())); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java index ff2522c352..1d71735278 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java @@ -81,7 +81,7 @@ public abstract class PluginDtoMapper { .self(resourceLinks.availablePlugin() .self(information.getName())); - if (!plugin.isPending() && PluginPermissions.manage().isPermitted()) { + if (!plugin.isPending() && PluginPermissions.write().isPermitted()) { String href = resourceLinks.availablePlugin().install(information.getName()); appendLink(links, "install", href); } @@ -106,7 +106,7 @@ public abstract class PluginDtoMapper { if (!plugin.isCore() && availablePlugin.isPresent() && !availablePlugin.get().isPending() - && PluginPermissions.manage().isPermitted() + && PluginPermissions.write().isPermitted() ) { String href = resourceLinks.availablePlugin().install(information.getName()); appendLink(links, "update", href); @@ -114,7 +114,7 @@ public abstract class PluginDtoMapper { if (plugin.isUninstallable() && (!availablePlugin.isPresent() || !availablePlugin.get().isPending()) - && PluginPermissions.manage().isPermitted() + && PluginPermissions.write().isPermitted() ) { String href = resourceLinks.installedPlugin().uninstall(information.getName()); appendLink(links, "uninstall", href); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java index bb6dc1491f..9acd07641e 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java @@ -157,7 +157,7 @@ public class DefaultPluginManager implements PluginManager { @Override public void install(String name, boolean restartAfterInstallation) { - PluginPermissions.manage().check(); + PluginPermissions.write().check(); getInstalled(name) .map(InstalledPlugin::isCore) @@ -192,7 +192,7 @@ public class DefaultPluginManager implements PluginManager { @Override public void uninstall(String name, boolean restartAfterInstallation) { - PluginPermissions.manage().check(); + PluginPermissions.write().check(); InstalledPlugin installed = getInstalled(name) .orElseThrow(() -> NotFoundException.notFound(entity(InstalledPlugin.class, name))); doThrow().violation("plugin is a core plugin and cannot be uninstalled").when(installed.isCore()); @@ -231,7 +231,7 @@ public class DefaultPluginManager implements PluginManager { @Override public void executePendingAndRestart() { - PluginPermissions.manage().check(); + PluginPermissions.write().check(); if (!pendingInstallQueue.isEmpty() || getInstalled().stream().anyMatch(InstalledPlugin::isMarkedForUninstall)) { triggerRestart("execute pending plugin changes"); } @@ -278,7 +278,7 @@ public class DefaultPluginManager implements PluginManager { @Override public void cancelPending() { - PluginPermissions.manage().check(); + PluginPermissions.write().check(); pendingUninstallQueue.forEach(PendingPluginUninstallation::cancel); pendingInstallQueue.forEach(PendingPluginInstallation::cancel); pendingUninstallQueue.clear(); @@ -288,7 +288,7 @@ public class DefaultPluginManager implements PluginManager { @Override public void updateAll() { - PluginPermissions.manage().check(); + PluginPermissions.write().check(); for (InstalledPlugin installedPlugin : getInstalled()) { String pluginName = installedPlugin.getDescriptor().getInformation().getName(); if (isUpdatable(pluginName)) { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java index 2f545761b7..00c4191dd7 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java @@ -114,7 +114,7 @@ class PendingPluginResourceTest { @BeforeEach void bindSubject() { ThreadContext.bind(subject); - lenient().when(subject.isPermitted("plugin:manage")).thenReturn(true); + lenient().when(subject.isPermitted("plugin:write")).thenReturn(true); lenient().when(restarter.isSupported()).thenReturn(true); } @@ -228,7 +228,7 @@ class PendingPluginResourceTest { @BeforeEach void bindSubject() { ThreadContext.bind(subject); - when(subject.isPermitted("plugin:manage")).thenReturn(false); + when(subject.isPermitted("plugin:write")).thenReturn(false); } @AfterEach diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapperTest.java index a3fa801a22..f91c7b08b9 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapperTest.java @@ -119,7 +119,7 @@ class PluginDtoCollectionMapperTest { @Test void shouldNotAddInstallLinkForNewVersionWhenNotPermitted() { - when(subject.isPermitted("plugin:manage")).thenReturn(false); + when(subject.isPermitted("plugin:write")).thenReturn(false); PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager); HalRepresentation result = mapper.mapInstalled( @@ -132,7 +132,7 @@ class PluginDtoCollectionMapperTest { @Test void shouldNotAddInstallLinkForNewVersionWhenInstallationIsPending() { - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager); AvailablePlugin availablePlugin = createAvailablePlugin("scm-some-plugin", "2"); @@ -147,7 +147,7 @@ class PluginDtoCollectionMapperTest { @Test void shouldAddUpdateLinkForNewVersionWhenPermitted() { - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager); HalRepresentation result = mapper.mapInstalled( @@ -161,7 +161,7 @@ class PluginDtoCollectionMapperTest { @Test void shouldAddUpdateWithRestartLinkForNewVersionWhenPermitted() { when(restarter.isSupported()).thenReturn(true); - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager); HalRepresentation result = mapper.mapInstalled( @@ -175,7 +175,7 @@ class PluginDtoCollectionMapperTest { @Test void shouldSetInstalledPluginPendingWhenCorrespondingAvailablePluginIsPending() { - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager); AvailablePlugin availablePlugin = createAvailablePlugin("scm-some-plugin", "2"); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java index 8301e6fb76..7c3c3975c0 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java @@ -127,7 +127,7 @@ class PluginDtoMapperTest { @Test void shouldAppendInstallLink() { - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); AvailablePlugin plugin = createAvailable(createPluginInformation()); PluginDto dto = mapper.mapAvailable(plugin); @@ -138,7 +138,7 @@ class PluginDtoMapperTest { @Test void shouldAppendInstallWithRestartLink() { when(restarter.isSupported()).thenReturn(true); - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); AvailablePlugin plugin = createAvailable(createPluginInformation()); PluginDto dto = mapper.mapAvailable(plugin); @@ -166,7 +166,7 @@ class PluginDtoMapperTest { @Test void shouldAppendUninstallLink() { - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); InstalledPlugin plugin = createInstalled(createPluginInformation()); when(plugin.isUninstallable()).thenReturn(true); @@ -178,7 +178,7 @@ class PluginDtoMapperTest { @Test void shouldAppendUninstallWithRestartLink() { when(restarter.isSupported()).thenReturn(true); - when(subject.isPermitted("plugin:manage")).thenReturn(true); + when(subject.isPermitted("plugin:write")).thenReturn(true); InstalledPlugin plugin = createInstalled(createPluginInformation()); when(plugin.isUninstallable()).thenReturn(true); diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java index 03b12f92cf..da7fce6527 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java @@ -602,12 +602,12 @@ class DefaultPluginManagerTest { } @Nested - class WithoutManagePermissions { + class WithoutWritePermissions { @BeforeEach void setUpSubject() { ThreadContext.bind(subject); - doThrow(AuthorizationException.class).when(subject).checkPermission("plugin:manage"); + doThrow(AuthorizationException.class).when(subject).checkPermission("plugin:write"); } @AfterEach