From c0760688e9f954216ab8679db947d0dc3e4b6835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 3 May 2019 14:47:49 +0200 Subject: [PATCH] Join repository roles from the system and from the database --- .../scm/repository/RepositoryRoleDAO.java | 4 ++ .../repository/xml/XmlRepositoryRoleDAO.java | 7 +++ .../RepositoryPermissionResource.java | 6 +- .../RepositoryPermissionProvider.java | 60 +++++++++++++++++++ .../SystemRepositoryPermissionProvider.java | 14 ++--- .../RepositoryPermissionProviderTest.java | 51 ++++++++++++++++ 6 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java create mode 100644 scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryRoleDAO.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryRoleDAO.java index 82bd163989..3d7e53b3a2 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryRoleDAO.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryRoleDAO.java @@ -2,5 +2,9 @@ package sonia.scm.repository; import sonia.scm.GenericDAO; +import java.util.List; + public interface RepositoryRoleDAO extends GenericDAO { + @Override + List getAll(); } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryRoleDAO.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryRoleDAO.java index 4fa814e3c8..c913d57ee4 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryRoleDAO.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryRoleDAO.java @@ -6,6 +6,8 @@ import sonia.scm.repository.RepositoryRoleDAO; import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.xml.AbstractXmlDAO; +import java.util.List; + public class XmlRepositoryRoleDAO extends AbstractXmlDAO implements RepositoryRoleDAO { @@ -30,4 +32,9 @@ public class XmlRepositoryRoleDAO extends AbstractXmlDAO getAll() { + return (List) super.getAll(); + } } 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 df042f3e61..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 @@ -3,7 +3,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.SystemRepositoryPermissionProvider; +import sonia.scm.security.RepositoryPermissionProvider; import sonia.scm.web.VndMediaType; import javax.inject.Inject; @@ -19,11 +19,11 @@ public class RepositoryPermissionResource { static final String PATH = "v2/repositoryPermissions/"; - private final SystemRepositoryPermissionProvider repositoryPermissionProvider; + private final RepositoryPermissionProvider repositoryPermissionProvider; private final ResourceLinks resourceLinks; @Inject - public RepositoryPermissionResource(SystemRepositoryPermissionProvider repositoryPermissionProvider, ResourceLinks resourceLinks) { + public RepositoryPermissionResource(RepositoryPermissionProvider repositoryPermissionProvider, ResourceLinks resourceLinks) { this.repositoryPermissionProvider = repositoryPermissionProvider; this.resourceLinks = resourceLinks; } diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java new file mode 100644 index 0000000000..292feee7c1 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionProvider.java @@ -0,0 +1,60 @@ +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.repository.RepositoryRole; +import sonia.scm.repository.RepositoryRoleDAO; + +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.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static java.util.Collections.unmodifiableCollection; + +public class RepositoryPermissionProvider { + + private final SystemRepositoryPermissionProvider systemRepositoryPermissionProvider; + private final RepositoryRoleDAO repositoryRoleDAO; + + @Inject + public RepositoryPermissionProvider(SystemRepositoryPermissionProvider systemRepositoryPermissionProvider, RepositoryRoleDAO repositoryRoleDAO) { + this.systemRepositoryPermissionProvider = systemRepositoryPermissionProvider; + this.repositoryRoleDAO = repositoryRoleDAO; + } + + public Collection availableVerbs() { + return systemRepositoryPermissionProvider.availableVerbs(); + } + + public Collection availableRoles() { + List customRoles = repositoryRoleDAO.getAll(); + List availableSystemRoles = systemRepositoryPermissionProvider.availableRoles(); + + return new AbstractList() { + @Override + public RepositoryRole get(int index) { + return index < availableSystemRoles.size()? availableSystemRoles.get(index): customRoles.get(index - availableSystemRoles.size()); + } + + @Override + public int size() { + return availableSystemRoles.size() + customRoles.size(); + } + }; + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/security/SystemRepositoryPermissionProvider.java b/scm-webapp/src/main/java/sonia/scm/security/SystemRepositoryPermissionProvider.java index 5856abbc8b..63fdeec702 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/SystemRepositoryPermissionProvider.java +++ b/scm-webapp/src/main/java/sonia/scm/security/SystemRepositoryPermissionProvider.java @@ -26,25 +26,25 @@ import java.util.stream.Collectors; import static java.util.Collections.unmodifiableCollection; import static java.util.Collections.unmodifiableList; -public class SystemRepositoryPermissionProvider { +class SystemRepositoryPermissionProvider { private static final Logger logger = LoggerFactory.getLogger(SystemRepositoryPermissionProvider.class); private static final String REPOSITORY_PERMISSION_DESCRIPTOR = "META-INF/scm/repository-permissions.xml"; - private final Collection availableVerbs; - private final Collection availableRoles; + private final List availableVerbs; + private final List availableRoles; @Inject public SystemRepositoryPermissionProvider(PluginLoader pluginLoader) { AvailableRepositoryPermissions availablePermissions = readAvailablePermissions(pluginLoader); - this.availableVerbs = unmodifiableCollection(new LinkedHashSet<>(availablePermissions.availableVerbs)); - this.availableRoles = unmodifiableList(new LinkedHashSet<>(availablePermissions.availableRoles.stream().map(r -> new RepositoryRole(r.name, r.verbs.verbs, "system")).collect(Collectors.toList()))); + this.availableVerbs = unmodifiableList(new ArrayList<>(availablePermissions.availableVerbs)); + this.availableRoles = unmodifiableList(new ArrayList<>(availablePermissions.availableRoles.stream().map(r -> new RepositoryRole(r.name, r.verbs.verbs, "system")).collect(Collectors.toList()))); } - public Collection availableVerbs() { + public List availableVerbs() { return availableVerbs; } - public Collection availableRoles() { + public List availableRoles() { return availableRoles; } 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..30e264dc6c --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionProviderTest.java @@ -0,0 +1,51 @@ +package sonia.scm.security; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.repository.RepositoryRole; +import sonia.scm.repository.RepositoryRoleDAO; + +import java.util.Collection; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RepositoryPermissionProviderTest { + + @Mock + SystemRepositoryPermissionProvider systemRepositoryPermissionProvider; + @Mock + RepositoryRoleDAO repositoryRoleDAO; + + @InjectMocks + RepositoryPermissionProvider repositoryPermissionProvider; + + @Test + void shouldReturnVerbsFromSystem() { + List expectedVerbs = asList("verb1", "verb2"); + when(systemRepositoryPermissionProvider.availableVerbs()).thenReturn(expectedVerbs); + + Collection actualVerbs = repositoryPermissionProvider.availableVerbs(); + + assertThat(actualVerbs).isEqualTo(expectedVerbs); + } + + @Test + void shouldReturnJoinedRolesFromSystemAndDao() { + RepositoryRole systemRole = new RepositoryRole("roleSystem", singletonList("verb1"), "system"); + RepositoryRole daoRole = new RepositoryRole("roleDao", singletonList("verb1"), "xml"); + when(systemRepositoryPermissionProvider.availableRoles()).thenReturn(singletonList(systemRole)); + when(repositoryRoleDAO.getAll()).thenReturn(singletonList(daoRole)); + + Collection actualRoles = repositoryPermissionProvider.availableRoles(); + + assertThat(actualRoles).containsExactly(systemRole, daoRole); + } +}