mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 00:45:44 +01:00
Merge with 2.0.0-m3
This commit is contained in:
@@ -2,8 +2,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;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.inject.util.Providers;
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
@@ -21,7 +19,6 @@ import org.jboss.resteasy.mock.MockHttpResponse;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
@@ -35,6 +32,7 @@ import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
@@ -64,11 +62,6 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
|
||||
import static sonia.scm.api.v2.resources.RepositoryPermissionDto.GROUP_PREFIX;
|
||||
|
||||
@Slf4j
|
||||
@SubjectAware(
|
||||
username = "trillian",
|
||||
password = "secret",
|
||||
configuration = "classpath:sonia/scm/repository/shiro.ini"
|
||||
)
|
||||
public class RepositoryPermissionRootResourceTest extends RepositoryTestBase {
|
||||
private static final String REPOSITORY_NAMESPACE = "repo_namespace";
|
||||
private static final String REPOSITORY_NAME = "repo";
|
||||
@@ -114,9 +107,6 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase {
|
||||
|
||||
private Dispatcher dispatcher;
|
||||
|
||||
@Rule
|
||||
public ShiroRule shiro = new ShiroRule();
|
||||
|
||||
@Mock
|
||||
private RepositoryManager repositoryManager;
|
||||
|
||||
@@ -363,6 +353,69 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase {
|
||||
assertGettingExpectedPermissions(expectedPermissions, PERMISSION_READ);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateValidationErrorForMissingRoleAndEmptyVerbs() throws Exception {
|
||||
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_OWNER);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
HttpRequest request = MockHttpRequest
|
||||
.create(HttpMethod.POST, "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS)
|
||||
.content("{ 'name' : 'permission_name', 'verbs' : [] }".replaceAll("'", "\"").getBytes())
|
||||
.contentType(VndMediaType.REPOSITORY_PERMISSION);
|
||||
dispatcher.invoke(request, response);
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
assertThat(response.getContentAsString()).contains("permission must either have a role or a not empty set of verbs");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateValidationErrorForEmptyRoleAndEmptyVerbs() throws Exception {
|
||||
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_OWNER);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
HttpRequest request = MockHttpRequest
|
||||
.create(HttpMethod.POST, "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS)
|
||||
.content("{ 'name' : 'permission_name', 'role': '', 'verbs' : [] }".replaceAll("'", "\"").getBytes())
|
||||
.contentType(VndMediaType.REPOSITORY_PERMISSION);
|
||||
dispatcher.invoke(request, response);
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
assertThat(response.getContentAsString()).contains("permission must either have a role or a not empty set of verbs");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateValidationErrorForRoleAndVerbs() throws Exception {
|
||||
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_OWNER);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
HttpRequest request = MockHttpRequest
|
||||
.create(HttpMethod.POST, "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS)
|
||||
.content("{ 'name' : 'permission_name', 'role': 'some role', 'verbs' : ['read'] }".replaceAll("'", "\"").getBytes())
|
||||
.contentType(VndMediaType.REPOSITORY_PERMISSION);
|
||||
dispatcher.invoke(request, response);
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
assertThat(response.getContentAsString()).contains("permission must either have a role or a not empty set of verbs");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPassWithoutValidationErrorForRoleAndEmptyVerbs() throws Exception {
|
||||
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_OWNER);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
HttpRequest request = MockHttpRequest
|
||||
.create(HttpMethod.POST, "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS)
|
||||
.content("{ 'name' : 'permission_name', 'role': 'some role', 'verbs': [] }".replaceAll("'", "\"").getBytes())
|
||||
.contentType(VndMediaType.REPOSITORY_PERMISSION);
|
||||
dispatcher.invoke(request, response);
|
||||
assertThat(response.getStatus()).isEqualTo(201);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPassWithoutValidationErrorForRoleAndNoVerbs() throws Exception {
|
||||
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_OWNER);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
HttpRequest request = MockHttpRequest
|
||||
.create(HttpMethod.POST, "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS)
|
||||
.content("{ 'name' : 'permission_name', 'role': 'some role' }".replaceAll("'", "\"").getBytes())
|
||||
.contentType(VndMediaType.REPOSITORY_PERMISSION);
|
||||
dispatcher.invoke(request, response);
|
||||
assertThat(response.getStatus()).isEqualTo(201);
|
||||
}
|
||||
|
||||
private void assertGettingExpectedPermissions(ImmutableList<RepositoryPermission> expectedPermissions, String userPermission) throws URISyntaxException {
|
||||
assertExpectedRequest(requestGETAllPermissions
|
||||
.expectedResponseStatus(200)
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.github.sdorra.shiro.ShiroRule;
|
||||
import com.github.sdorra.shiro.SubjectAware;
|
||||
import com.google.inject.util.Providers;
|
||||
import org.jboss.resteasy.core.Dispatcher;
|
||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.PageResult;
|
||||
import sonia.scm.api.rest.JSONContextResolver;
|
||||
import sonia.scm.api.rest.ObjectMapperProvider;
|
||||
import sonia.scm.repository.RepositoryRole;
|
||||
import sonia.scm.repository.RepositoryRoleManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
|
||||
import static java.net.URI.create;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
|
||||
|
||||
@SubjectAware(
|
||||
username = "trillian",
|
||||
password = "secret",
|
||||
configuration = "classpath:sonia/scm/repository/shiro.ini"
|
||||
)
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class RepositoryRoleRootResourceTest {
|
||||
|
||||
public static final String CUSTOM_ROLE = "customRole";
|
||||
public static final String SYSTEM_ROLE = "systemRole";
|
||||
public static final RepositoryRole CUSTOM_REPOSITORY_ROLE = new RepositoryRole(CUSTOM_ROLE, Collections.singleton("verb"), "xml");
|
||||
public static final RepositoryRole SYSTEM_REPOSITORY_ROLE = new RepositoryRole(SYSTEM_ROLE, Collections.singleton("admin"), "system");
|
||||
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(create("/"));
|
||||
|
||||
@Rule
|
||||
public ShiroRule shiroRule = new ShiroRule();
|
||||
|
||||
@Mock
|
||||
private RepositoryRoleManager repositoryRoleManager;
|
||||
|
||||
@InjectMocks
|
||||
private RepositoryRoleToRepositoryRoleDtoMapperImpl roleToDtoMapper;
|
||||
|
||||
@InjectMocks
|
||||
private RepositoryRoleDtoToRepositoryRoleMapperImpl dtoToRoleMapper;
|
||||
|
||||
private RepositoryRoleCollectionToDtoMapper collectionToDtoMapper;
|
||||
|
||||
private Dispatcher dispatcher;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<RepositoryRole> modifyCaptor;
|
||||
@Captor
|
||||
private ArgumentCaptor<RepositoryRole> createCaptor;
|
||||
@Captor
|
||||
private ArgumentCaptor<RepositoryRole> deleteCaptor;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
collectionToDtoMapper = new RepositoryRoleCollectionToDtoMapper(roleToDtoMapper, resourceLinks);
|
||||
|
||||
RepositoryRoleCollectionResource collectionResource = new RepositoryRoleCollectionResource(repositoryRoleManager, dtoToRoleMapper, collectionToDtoMapper, resourceLinks);
|
||||
RepositoryRoleResource roleResource = new RepositoryRoleResource(dtoToRoleMapper, roleToDtoMapper, repositoryRoleManager);
|
||||
RepositoryRoleRootResource rootResource = new RepositoryRoleRootResource(Providers.of(collectionResource), Providers.of(roleResource));
|
||||
|
||||
doNothing().when(repositoryRoleManager).modify(modifyCaptor.capture());
|
||||
when(repositoryRoleManager.create(createCaptor.capture())).thenAnswer(invocation -> invocation.getArguments()[0]);
|
||||
doNothing().when(repositoryRoleManager).delete(deleteCaptor.capture());
|
||||
|
||||
dispatcher = createDispatcher(rootResource);
|
||||
dispatcher.getProviderFactory().registerProviderInstance(new JSONContextResolver(new ObjectMapperProvider().get()));
|
||||
|
||||
when(repositoryRoleManager.get(CUSTOM_ROLE)).thenReturn(CUSTOM_REPOSITORY_ROLE);
|
||||
when(repositoryRoleManager.get(SYSTEM_ROLE)).thenReturn(SYSTEM_REPOSITORY_ROLE);
|
||||
when(repositoryRoleManager.getPage(any(), any(), anyInt(), anyInt())).thenReturn(new PageResult<>(asList(CUSTOM_REPOSITORY_ROLE, SYSTEM_REPOSITORY_ROLE), 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetNotFoundForNotExistingRole() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + "noSuchRole");
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetCustomRole() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + CUSTOM_ROLE);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
assertThat(response.getContentAsString())
|
||||
.contains(
|
||||
"\"name\":\"" + CUSTOM_ROLE + "\"",
|
||||
"\"verbs\":[\"verb\"]",
|
||||
"\"self\":{\"href\":\"/v2/repositoryRoles/" + CUSTOM_ROLE + "\"}",
|
||||
"\"update\":{\"href\":\"/v2/repositoryRoles/" + CUSTOM_ROLE + "\"}",
|
||||
"\"delete\":{\"href\":\"/v2/repositoryRoles/" + CUSTOM_ROLE + "\"}"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetSystemRole() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + SYSTEM_ROLE);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
assertThat(response.getContentAsString())
|
||||
.contains(
|
||||
"\"name\":\"" + SYSTEM_ROLE + "\"",
|
||||
"\"verbs\":[\"admin\"]",
|
||||
"\"self\":{\"href\":\"/v2/repositoryRoles/" + SYSTEM_ROLE + "\"}"
|
||||
)
|
||||
.doesNotContain(
|
||||
"\"delete\":{\"href\":\"/v2/repositoryRoles/" + CUSTOM_ROLE + "\"}",
|
||||
"\"update\":{\"href\":\"/v2/repositoryRoles/" + CUSTOM_ROLE + "\"}"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "dent")
|
||||
public void shouldNotGetDeleteLinkWithoutPermission() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + CUSTOM_ROLE);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
assertThat(response.getContentAsString())
|
||||
.doesNotContain("delete");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateRole() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.put("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + CUSTOM_ROLE)
|
||||
.contentType(VndMediaType.REPOSITORY_ROLE)
|
||||
.content(content("{'name': '" + CUSTOM_ROLE + "', 'verbs': ['write', 'push']}"));
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_NO_CONTENT);
|
||||
verify(repositoryRoleManager).modify(any());
|
||||
assertThat(modifyCaptor.getValue().getName()).isEqualTo(CUSTOM_ROLE);
|
||||
assertThat(modifyCaptor.getValue().getVerbs()).containsExactly("write", "push");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotChangeRoleName() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.put("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + CUSTOM_ROLE)
|
||||
.contentType(VndMediaType.REPOSITORY_ROLE)
|
||||
.content(content("{'name': 'changedName', 'verbs': ['write', 'push']}"));
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST);
|
||||
verify(repositoryRoleManager, never()).modify(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailForUpdateOfNotExistingRole() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.put("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + "noSuchRole")
|
||||
.contentType(VndMediaType.REPOSITORY_ROLE)
|
||||
.content(content("{'name': 'noSuchRole', 'verbs': ['write', 'push']}"));
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_NOT_FOUND);
|
||||
verify(repositoryRoleManager, never()).modify(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateRole() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.post("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2)
|
||||
.contentType(VndMediaType.REPOSITORY_ROLE)
|
||||
.content(content("{'name': 'newRole', 'verbs': ['write', 'push']}"));
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_CREATED);
|
||||
verify(repositoryRoleManager).create(any());
|
||||
assertThat(createCaptor.getValue().getName()).isEqualTo("newRole");
|
||||
assertThat(createCaptor.getValue().getVerbs()).containsExactly("write", "push");
|
||||
Object location = response.getOutputHeaders().getFirst("Location");
|
||||
assertThat(location).isEqualTo(create("/v2/repositoryRoles/newRole"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeleteRole() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.delete("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2 + CUSTOM_ROLE);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_NO_CONTENT);
|
||||
verify(repositoryRoleManager).delete(any());
|
||||
assertThat(deleteCaptor.getValue().getName()).isEqualTo(CUSTOM_ROLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetAllRoles() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
assertThat(response.getContentAsString())
|
||||
.contains(
|
||||
"\"name\":\"" + CUSTOM_ROLE + "\"",
|
||||
"\"name\":\"" + SYSTEM_ROLE + "\"",
|
||||
"\"verbs\":[\"verb\"]",
|
||||
"\"verbs\":[\"admin\"]",
|
||||
"\"self\":{\"href\":\"/v2/repositoryRoles",
|
||||
"\"delete\":{\"href\":\"/v2/repositoryRoles/" + CUSTOM_ROLE + "\"}",
|
||||
"\"create\":{\"href\":\"/v2/repositoryRoles/\"}"
|
||||
)
|
||||
.doesNotContain(
|
||||
"\"delete\":{\"href\":\"/v2/repositoryRoles/" + SYSTEM_ROLE + "\"}"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailForEmptyName() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.post("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2)
|
||||
.contentType(VndMediaType.REPOSITORY_ROLE)
|
||||
.content(content("{'name': '', 'verbs': ['write', 'push']}"));
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST);
|
||||
verify(repositoryRoleManager, never()).create(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailForMissingVerbs() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.post("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2)
|
||||
.contentType(VndMediaType.REPOSITORY_ROLE)
|
||||
.content(content("{'name': 'ok', 'verbs': []}"));
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST);
|
||||
verify(repositoryRoleManager, never()).create(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailForEmptyVerb() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.post("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2)
|
||||
.contentType(VndMediaType.REPOSITORY_ROLE)
|
||||
.content(content("{'name': 'ok', 'verbs': ['', 'push']}"));
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST);
|
||||
verify(repositoryRoleManager, never()).create(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "dent")
|
||||
public void shouldNotGetCreateLinkWithoutPermission() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRoleRootResource.REPOSITORY_ROLES_PATH_V2);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
assertThat(response.getContentAsString())
|
||||
.doesNotContain(
|
||||
"create"
|
||||
);
|
||||
}
|
||||
|
||||
private byte[] content(String data) {
|
||||
return data.replaceAll("'", "\"").getBytes();
|
||||
}
|
||||
}
|
||||
@@ -332,7 +332,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
.hasSize(1)
|
||||
.allSatisfy(p -> {
|
||||
assertThat(p.getName()).isEqualTo("trillian");
|
||||
assertThat(p.getVerbs()).containsExactly("*");
|
||||
assertThat(p.getRole()).isEqualTo("OWNER");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,9 @@ 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));
|
||||
when(resourceLinks.repositoryTypeCollection()).thenReturn(new ResourceLinks.RepositoryTypeCollectionLinks(uriInfo));
|
||||
when(resourceLinks.repositoryVerbs()).thenReturn(new ResourceLinks.RepositoryVerbLinks(uriInfo));
|
||||
when(resourceLinks.repositoryRole()).thenReturn(new ResourceLinks.RepositoryRoleLinks(uriInfo));
|
||||
when(resourceLinks.repositoryRoleCollection()).thenReturn(new ResourceLinks.RepositoryRoleCollectionLinks(uriInfo));
|
||||
when(resourceLinks.namespaceStrategies()).thenReturn(new ResourceLinks.NamespaceStrategiesLinks(uriInfo));
|
||||
|
||||
return resourceLinks;
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
package sonia.scm.repository;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.subject.support.SubjectThreadState;
|
||||
import org.apache.shiro.util.ThreadContext;
|
||||
import org.apache.shiro.util.ThreadState;
|
||||
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.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.ScmConstraintViolationException;
|
||||
import sonia.scm.security.RepositoryPermissionProvider;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
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.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class DefaultRepositoryRoleManagerTest {
|
||||
|
||||
private static final String CUSTOM_ROLE_NAME = "customRole";
|
||||
private static final String SYSTEM_ROLE_NAME = "systemRole";
|
||||
private static final RepositoryRole CUSTOM_ROLE = new RepositoryRole(CUSTOM_ROLE_NAME, singletonList("custom"), "xml");
|
||||
private static final RepositoryRole SYSTEM_ROLE = new RepositoryRole(SYSTEM_ROLE_NAME, singletonList("system"), "system");
|
||||
|
||||
private final Subject subject = mock(Subject.class);
|
||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||
|
||||
@Mock
|
||||
private RepositoryRoleDAO dao;
|
||||
@Mock
|
||||
private RepositoryPermissionProvider permissionProvider;
|
||||
|
||||
@InjectMocks
|
||||
private DefaultRepositoryRoleManager manager;
|
||||
|
||||
@BeforeEach
|
||||
void initUser() {
|
||||
subjectThreadState.bind();
|
||||
doAnswer(invocation -> {
|
||||
String permission = invocation.getArguments()[0].toString();
|
||||
if (!subject.isPermitted(permission)) {
|
||||
throw new UnauthorizedException(permission);
|
||||
}
|
||||
return null;
|
||||
}).when(subject).checkPermission(anyString());
|
||||
ThreadContext.bind(subject);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void initDao() {
|
||||
when(dao.getType()).thenReturn("xml");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void mockExistingRole() {
|
||||
when(dao.get(CUSTOM_ROLE_NAME)).thenReturn(CUSTOM_ROLE);
|
||||
when(permissionProvider.availableRoles()).thenReturn(asList(CUSTOM_ROLE, SYSTEM_ROLE));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanupContext() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithAuthorizedUser {
|
||||
|
||||
@BeforeEach
|
||||
void authorizeUser() {
|
||||
when(subject.isPermitted("repositoryRole:read")).thenReturn(true);
|
||||
when(subject.isPermitted("repositoryRole:modify")).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnNull_forNotExistingRole() {
|
||||
RepositoryRole role = manager.get("noSuchRole");
|
||||
assertThat(role).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnRole_forExistingRole() {
|
||||
RepositoryRole role = manager.get(CUSTOM_ROLE_NAME);
|
||||
assertThat(role).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateRole() {
|
||||
RepositoryRole role = manager.create(new RepositoryRole("new", singletonList("custom"), null));
|
||||
assertThat(role.getType()).isEqualTo("xml");
|
||||
verify(dao).add(role);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotCreateRole_whenSystemRoleExists() {
|
||||
assertThrows(UnauthorizedException.class, () -> manager.create(new RepositoryRole(SYSTEM_ROLE_NAME, singletonList("custom"), null)));
|
||||
verify(dao, never()).add(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldModifyRole() {
|
||||
RepositoryRole role = new RepositoryRole(CUSTOM_ROLE_NAME, singletonList("changed"), "xml");
|
||||
manager.modify(role);
|
||||
verify(dao).modify(role);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotModifyRole_whenTypeChanged() {
|
||||
assertThrows(ScmConstraintViolationException.class, () -> manager.modify(new RepositoryRole(CUSTOM_ROLE_NAME, singletonList("changed"), null)));
|
||||
verify(dao, never()).modify(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotModifyRole_whenRoleDoesNotExists() {
|
||||
assertThrows(NotFoundException.class, () -> manager.modify(new RepositoryRole("noSuchRole", singletonList("changed"), null)));
|
||||
verify(dao, never()).modify(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotModifyRole_whenSystemRoleExists() {
|
||||
assertThrows(UnauthorizedException.class, () -> manager.modify(new RepositoryRole(SYSTEM_ROLE_NAME, singletonList("changed"), null)));
|
||||
verify(dao, never()).modify(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAllRoles() {
|
||||
List<RepositoryRole> allRoles = manager.getAll();
|
||||
assertThat(allRoles).containsExactly(CUSTOM_ROLE, SYSTEM_ROLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnFilteredRoles() {
|
||||
Collection<RepositoryRole> allRoles = manager.getAll(role -> CUSTOM_ROLE_NAME.equals(role.getName()), null);
|
||||
assertThat(allRoles).containsExactly(CUSTOM_ROLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnOrderedFilteredRoles() {
|
||||
Collection<RepositoryRole> allRoles =
|
||||
manager.getAll(
|
||||
role -> true,
|
||||
Comparator.comparing(RepositoryRole::getType));
|
||||
assertThat(allRoles).containsExactly(SYSTEM_ROLE, CUSTOM_ROLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnPaginatedRoles() {
|
||||
Collection<RepositoryRole> allRoles =
|
||||
manager.getAll(
|
||||
Comparator.comparing(RepositoryRole::getType),
|
||||
1, 1
|
||||
);
|
||||
assertThat(allRoles).containsExactly(CUSTOM_ROLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithUnauthorizedUser {
|
||||
|
||||
@BeforeEach
|
||||
void authorizeUser() {
|
||||
when(subject.isPermitted(any(String.class))).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowException_forGet() {
|
||||
assertThrows(UnauthorizedException.class, () -> manager.get("any"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowException_forCreate() {
|
||||
assertThrows(UnauthorizedException.class, () -> manager.create(new RepositoryRole("new", singletonList("custom"), null)));
|
||||
verify(dao, never()).add(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowException_forModify() {
|
||||
assertThrows(UnauthorizedException.class, () -> manager.modify(new RepositoryRole(CUSTOM_ROLE_NAME, singletonList("custom"), null)));
|
||||
verify(dao, never()).modify(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyList() {
|
||||
assertThat(manager.getAll()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyFilteredList() {
|
||||
assertThat(manager.getAll(x -> true, null)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyPaginatedList() {
|
||||
assertThat(manager.getAll(1, 1)).isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,10 @@ package sonia.scm.security;
|
||||
|
||||
import com.github.sdorra.shiro.ShiroRule;
|
||||
import com.github.sdorra.shiro.SubjectAware;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.hamcrest.Matchers;
|
||||
@@ -49,16 +49,19 @@ import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.cache.Cache;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.group.GroupNames;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryDAO;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.repository.RepositoryRole;
|
||||
import sonia.scm.repository.RepositoryTestData;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserTestData;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
@@ -90,6 +93,9 @@ public class DefaultAuthorizationCollectorTest {
|
||||
@Mock
|
||||
private SecuritySystem securitySystem;
|
||||
|
||||
@Mock
|
||||
private RepositoryPermissionProvider repositoryPermissionProvider;
|
||||
|
||||
private DefaultAuthorizationCollector collector;
|
||||
|
||||
@Rule
|
||||
@@ -101,11 +107,11 @@ public class DefaultAuthorizationCollectorTest {
|
||||
@Before
|
||||
public void setUp(){
|
||||
when(cacheManager.getCache(Mockito.any(String.class))).thenReturn(cache);
|
||||
collector = new DefaultAuthorizationCollector(cacheManager, repositoryDAO, securitySystem);
|
||||
collector = new DefaultAuthorizationCollector(cacheManager, repositoryDAO, securitySystem, repositoryPermissionProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect()} without user role.
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} without user role.
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware
|
||||
@@ -118,7 +124,7 @@ public class DefaultAuthorizationCollectorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect()} from cache.
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} from cache.
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware(
|
||||
@@ -134,7 +140,7 @@ public class DefaultAuthorizationCollectorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect()} with cache.
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} with cache.
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware(
|
||||
@@ -148,7 +154,7 @@ public class DefaultAuthorizationCollectorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect()} without permissions.
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} without permissions.
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware(
|
||||
@@ -165,7 +171,7 @@ public class DefaultAuthorizationCollectorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect()} with repository permissions.
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} with repository permissions.
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware(
|
||||
@@ -191,7 +197,76 @@ public class DefaultAuthorizationCollectorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect()} with global permissions.
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} with repository roles.
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware(
|
||||
configuration = "classpath:sonia/scm/shiro-001.ini"
|
||||
)
|
||||
public void testCollectWithRepositoryRolePermissions() {
|
||||
when(repositoryPermissionProvider.availableRoles()).thenReturn(
|
||||
asList(
|
||||
new RepositoryRole("user role", singletonList("user"), "xml"),
|
||||
new RepositoryRole("group role", singletonList("group"), "xml"),
|
||||
new RepositoryRole("system role", singletonList("system"), "system")
|
||||
));
|
||||
|
||||
String group = "heart-of-gold-crew";
|
||||
authenticate(UserTestData.createTrillian(), group);
|
||||
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
||||
heartOfGold.setId("one");
|
||||
heartOfGold.setPermissions(Lists.newArrayList(
|
||||
new RepositoryPermission("trillian", "user role", false),
|
||||
new RepositoryPermission("trillian", "system role", false)
|
||||
));
|
||||
Repository puzzle42 = RepositoryTestData.create42Puzzle();
|
||||
puzzle42.setId("two");
|
||||
RepositoryPermission permission = new RepositoryPermission(group, "group role", true);
|
||||
puzzle42.setPermissions(Lists.newArrayList(permission));
|
||||
when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold, puzzle42));
|
||||
|
||||
// execute and assert
|
||||
AuthorizationInfo authInfo = collector.collect();
|
||||
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
|
||||
assertThat(authInfo.getObjectPermissions(), nullValue());
|
||||
assertThat(authInfo.getStringPermissions(), containsInAnyOrder(
|
||||
"user:autocomplete",
|
||||
"group:autocomplete",
|
||||
"user:changePassword:trillian",
|
||||
"repository:user:one",
|
||||
"repository:system:one",
|
||||
"repository:group:two",
|
||||
"user:read:trillian"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} with repository roles.
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@SubjectAware(
|
||||
configuration = "classpath:sonia/scm/shiro-001.ini"
|
||||
)
|
||||
public void testCollectWithUnknownRepositoryRole() {
|
||||
when(repositoryPermissionProvider.availableRoles()).thenReturn(
|
||||
singletonList(
|
||||
new RepositoryRole("something", singletonList("something"), "xml")
|
||||
));
|
||||
|
||||
String group = "heart-of-gold-crew";
|
||||
authenticate(UserTestData.createTrillian(), group);
|
||||
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
||||
heartOfGold.setId("one");
|
||||
heartOfGold.setPermissions(singletonList(
|
||||
new RepositoryPermission("trillian", "unknown", false)
|
||||
));
|
||||
when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold));
|
||||
|
||||
// execute and assert
|
||||
AuthorizationInfo authInfo = collector.collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} with global permissions.
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware(
|
||||
|
||||
@@ -1,72 +1,51 @@
|
||||
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.util.ClassLoaders;
|
||||
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.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
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.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RepositoryPermissionProviderTest {
|
||||
|
||||
private RepositoryPermissionProvider repositoryPermissionProvider;
|
||||
private String[] allVerbsFromRepositoryClass;
|
||||
@Mock
|
||||
SystemRepositoryPermissionProvider systemRepositoryPermissionProvider;
|
||||
@Mock
|
||||
RepositoryRoleDAO repositoryRoleDAO;
|
||||
|
||||
@InjectMocks
|
||||
RepositoryPermissionProvider repositoryPermissionProvider;
|
||||
|
||||
@BeforeEach
|
||||
void init() {
|
||||
PluginLoader pluginLoader = mock(PluginLoader.class);
|
||||
when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class));
|
||||
repositoryPermissionProvider = new RepositoryPermissionProvider(pluginLoader);
|
||||
allVerbsFromRepositoryClass = Arrays.stream(RepositoryPermissions.class.getDeclaredFields())
|
||||
.filter(field -> field.getName().startsWith("ACTION_"))
|
||||
.filter(field -> !field.getName().equals("ACTION_HEALTHCHECK"))
|
||||
.map(this::getString)
|
||||
.filter(verb -> !"create".equals(verb))
|
||||
.toArray(String[]::new);
|
||||
@Test
|
||||
void shouldReturnVerbsFromSystem() {
|
||||
List<String> expectedVerbs = asList("verb1", "verb2");
|
||||
when(systemRepositoryPermissionProvider.availableVerbs()).thenReturn(expectedVerbs);
|
||||
|
||||
Collection<String> actualVerbs = repositoryPermissionProvider.availableVerbs();
|
||||
|
||||
assertThat(actualVerbs).isEqualTo(expectedVerbs);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReadAvailableRoles() {
|
||||
assertThat(repositoryPermissionProvider.availableRoles()).isNotEmpty();
|
||||
assertThat(repositoryPermissionProvider.availableRoles()).allSatisfy(this::containsOnlyAvailableVerbs);
|
||||
}
|
||||
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));
|
||||
|
||||
private void containsOnlyAvailableVerbs(RepositoryRole role) {
|
||||
assertThat(role.getVerbs()).isSubsetOf(repositoryPermissionProvider.availableVerbs());
|
||||
}
|
||||
Collection<RepositoryRole> actualRoles = repositoryPermissionProvider.availableRoles();
|
||||
|
||||
@Test
|
||||
void shouldReadAvailableVerbsFromRepository() {
|
||||
assertThat(repositoryPermissionProvider.availableVerbs()).contains(allVerbsFromRepositoryClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMergeRepositoryRoles() {
|
||||
Collection<String> verbsInMergedRole = repositoryPermissionProvider
|
||||
.availableRoles()
|
||||
.stream()
|
||||
.filter(r -> "READ".equals(r.getName()))
|
||||
.findFirst()
|
||||
.get()
|
||||
.getVerbs();
|
||||
assertThat(verbsInMergedRole).contains("read", "pull", "test");
|
||||
}
|
||||
|
||||
private String getString(Field field) {
|
||||
try {
|
||||
return (String) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
fail(e);
|
||||
return null;
|
||||
}
|
||||
assertThat(actualRoles).containsExactly(systemRole, daoRole);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
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.repository.RepositoryRole;
|
||||
import sonia.scm.util.ClassLoaders;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
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 SystemRepositoryPermissionProviderTest {
|
||||
|
||||
private SystemRepositoryPermissionProvider repositoryPermissionProvider;
|
||||
private String[] allVerbsFromRepositoryClass;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void init() {
|
||||
PluginLoader pluginLoader = mock(PluginLoader.class);
|
||||
when(pluginLoader.getUberClassLoader()).thenReturn(ClassLoaders.getContextClassLoader(DefaultSecuritySystem.class));
|
||||
repositoryPermissionProvider = new SystemRepositoryPermissionProvider(pluginLoader);
|
||||
allVerbsFromRepositoryClass = Arrays.stream(RepositoryPermissions.class.getDeclaredFields())
|
||||
.filter(field -> field.getName().startsWith("ACTION_"))
|
||||
.filter(field -> !field.getName().equals("ACTION_HEALTHCHECK"))
|
||||
.map(this::getString)
|
||||
.filter(verb -> !"create".equals(verb))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReadAvailableRoles() {
|
||||
assertThat(repositoryPermissionProvider.availableRoles()).isNotEmpty();
|
||||
assertThat(repositoryPermissionProvider.availableRoles()).allSatisfy(this::containsOnlyAvailableVerbs);
|
||||
}
|
||||
|
||||
private void containsOnlyAvailableVerbs(RepositoryRole role) {
|
||||
assertThat(role.getVerbs()).isSubsetOf(repositoryPermissionProvider.availableVerbs());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReadAvailableVerbsFromRepository() {
|
||||
assertThat(repositoryPermissionProvider.availableVerbs()).contains(allVerbsFromRepositoryClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMergeRepositoryRoles() {
|
||||
Collection<String> verbsInMergedRole = repositoryPermissionProvider
|
||||
.availableRoles()
|
||||
.stream()
|
||||
.filter(r -> "READ".equals(r.getName()))
|
||||
.findFirst()
|
||||
.get()
|
||||
.getVerbs();
|
||||
assertThat(verbsInMergedRole).contains("read", "pull", "test");
|
||||
}
|
||||
|
||||
private String getString(Field field) {
|
||||
try {
|
||||
return (String) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
fail(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user