implemented permission checks

This commit is contained in:
Sebastian Sdorra
2019-08-21 09:25:44 +02:00
parent de7d18e026
commit 5694a953af
3 changed files with 222 additions and 133 deletions

View File

@@ -81,7 +81,7 @@ public class AvailablePluginResource {
/** /**
* Triggers plugin installation. * Triggers plugin installation.
* @param name plugin artefact name * @param name plugin name
* @return HTTP Status. * @return HTTP Status.
*/ */
@POST @POST

View File

@@ -74,6 +74,7 @@ public class DefaultPluginManager implements PluginManager {
@Override @Override
public Optional<AvailablePlugin> getAvailable(String name) { public Optional<AvailablePlugin> getAvailable(String name) {
PluginPermissions.read().check();
return center.getAvailable() return center.getAvailable()
.stream() .stream()
.filter(filterByName(name)) .filter(filterByName(name))
@@ -83,6 +84,7 @@ public class DefaultPluginManager implements PluginManager {
@Override @Override
public Optional<InstalledPlugin> getInstalled(String name) { public Optional<InstalledPlugin> getInstalled(String name) {
PluginPermissions.read().check();
return loader.getInstalledPlugins() return loader.getInstalledPlugins()
.stream() .stream()
.filter(filterByName(name)) .filter(filterByName(name))
@@ -91,11 +93,13 @@ public class DefaultPluginManager implements PluginManager {
@Override @Override
public List<InstalledPlugin> getInstalled() { public List<InstalledPlugin> getInstalled() {
PluginPermissions.read().check();
return ImmutableList.copyOf(loader.getInstalledPlugins()); return ImmutableList.copyOf(loader.getInstalledPlugins());
} }
@Override @Override
public List<AvailablePlugin> getAvailable() { public List<AvailablePlugin> getAvailable() {
PluginPermissions.read().check();
return center.getAvailable().stream().filter(this::isNotInstalled).collect(Collectors.toList()); return center.getAvailable().stream().filter(this::isNotInstalled).collect(Collectors.toList());
} }
@@ -109,6 +113,7 @@ public class DefaultPluginManager implements PluginManager {
@Override @Override
public void install(String name) { public void install(String name) {
PluginPermissions.manage().check();
List<AvailablePlugin> plugins = collectPluginsToInstall(name); List<AvailablePlugin> plugins = collectPluginsToInstall(name);
List<PendingPluginInstallation> pendingInstallations = new ArrayList<>(); List<PendingPluginInstallation> pendingInstallations = new ArrayList<>();
for (AvailablePlugin plugin : plugins) { for (AvailablePlugin plugin : plugins) {
@@ -131,6 +136,7 @@ public class DefaultPluginManager implements PluginManager {
collectPluginsToInstall(plugins, name); collectPluginsToInstall(plugins, name);
return plugins; return plugins;
} }
private void collectPluginsToInstall(List<AvailablePlugin> plugins, String name) { private void collectPluginsToInstall(List<AvailablePlugin> plugins, String name) {
if (!getInstalled(name).isPresent()) { if (!getInstalled(name).isPresent()) {
AvailablePlugin plugin = getAvailable(name).orElseThrow(() -> NotFoundException.notFound(entity(AvailablePlugin.class, name))); AvailablePlugin plugin = getAvailable(name).orElseThrow(() -> NotFoundException.notFound(entity(AvailablePlugin.class, name)));

View File

@@ -2,12 +2,19 @@ package sonia.scm.plugin;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers; import org.mockito.Answers;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.NotFoundException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -31,6 +38,22 @@ class DefaultPluginManagerTest {
@InjectMocks @InjectMocks
private DefaultPluginManager manager; private DefaultPluginManager manager;
@Mock
private Subject subject;
@Nested
class WithAdminPermissions {
@BeforeEach
void setUpSubject() {
ThreadContext.bind(subject);
}
@AfterEach
void clearThreadContext() {
ThreadContext.unbindSubject();
}
@Test @Test
void shouldReturnInstalledPlugins() { void shouldReturnInstalledPlugins() {
InstalledPlugin review = createInstalled("scm-review-plugin"); InstalledPlugin review = createInstalled("scm-review-plugin");
@@ -177,6 +200,66 @@ class DefaultPluginManagerTest {
verify(pendingMail).cancel(); verify(pendingMail).cancel();
} }
@Test
void shouldInstallNothingIfOneOfTheDependenciesIsNotAvailable() {
AvailablePlugin review = createAvailable("scm-review-plugin");
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
AvailablePlugin mail = createAvailable("scm-mail-plugin");
when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin"));
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail));
assertThrows(NotFoundException.class, () -> manager.install("scm-review-plugin"));
verify(installer, never()).install(any());
}
}
@Nested
class WithoutReadPermissions {
@BeforeEach
void setUpSubject() {
ThreadContext.bind(subject);
doThrow(AuthorizationException.class).when(subject).checkPermission("plugin:read");
}
@AfterEach
void clearThreadContext() {
ThreadContext.unbindSubject();
}
@Test
void shouldThrowAuthorizationExceptionsForReadMethods() {
assertThrows(AuthorizationException.class, () -> manager.getInstalled());
assertThrows(AuthorizationException.class, () -> manager.getInstalled("test"));
assertThrows(AuthorizationException.class, () -> manager.getAvailable());
assertThrows(AuthorizationException.class, () -> manager.getAvailable("test"));
}
}
@Nested
class WithoutManagePermissions {
@BeforeEach
void setUpSubject() {
ThreadContext.bind(subject);
doThrow(AuthorizationException.class).when(subject).checkPermission("plugin:manage");
}
@AfterEach
void clearThreadContext() {
ThreadContext.unbindSubject();
}
@Test
void shouldThrowAuthorizationExceptionsForInstallMethod() {
assertThrows(AuthorizationException.class, () -> manager.install("test"));
}
}
private AvailablePlugin createAvailable(String name) { private AvailablePlugin createAvailable(String name) {
PluginInformation information = new PluginInformation(); PluginInformation information = new PluginInformation();
information.setName(name); information.setName(name);