mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 17:26:22 +01:00
Merge with 2.0.0-m3
This commit is contained in:
64
pom.xml
64
pom.xml
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -118,10 +119,26 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- JUnit 5 -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-params</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -139,15 +156,11 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>${mockito.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.assertj</groupId>
|
<groupId>org.assertj</groupId>
|
||||||
<artifactId>assertj-core</artifactId>
|
<artifactId>assertj-core</artifactId>
|
||||||
<version>3.10.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -282,9 +295,32 @@
|
|||||||
<version>${jackson.version}</version>
|
<version>${jackson.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JUnit 5 -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-params</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
<version>${junit.version}</version>
|
<version>${junit.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -348,7 +384,11 @@
|
|||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.0</version>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-enforcer-plugin</artifactId>
|
<artifactId>maven-enforcer-plugin</artifactId>
|
||||||
@@ -695,7 +735,7 @@
|
|||||||
<!-- test libraries -->
|
<!-- test libraries -->
|
||||||
<mockito.version>2.10.0</mockito.version>
|
<mockito.version>2.10.0</mockito.version>
|
||||||
<hamcrest.version>1.3</hamcrest.version>
|
<hamcrest.version>1.3</hamcrest.version>
|
||||||
<junit.version>4.12</junit.version>
|
<junit.version>5.2.0</junit.version>
|
||||||
|
|
||||||
<!-- logging libraries -->
|
<!-- logging libraries -->
|
||||||
<slf4j.version>1.7.22</slf4j.version>
|
<slf4j.version>1.7.22</slf4j.version>
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
class BaseDtoMapper {
|
||||||
|
Long mapDate(Instant value) {
|
||||||
|
if (value != null) {
|
||||||
|
return value.toEpochMilli();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,10 +42,10 @@ public enum PermissionType
|
|||||||
{
|
{
|
||||||
|
|
||||||
/** read permision */
|
/** read permision */
|
||||||
READ(0, "repository:read:"),
|
READ(0, "repository:read,pull:"),
|
||||||
|
|
||||||
/** read and write permissionPrefix */
|
/** read and write permissionPrefix */
|
||||||
WRITE(10, "repository:read,write:"),
|
WRITE(10, "repository:read,pull,push:"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read, write and
|
* read, write and
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@StaticPermissions(
|
@StaticPermissions(
|
||||||
value = "repository",
|
value = "repository",
|
||||||
permissions = {"read", "write", "modify", "delete", "healthCheck"}
|
permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"}
|
||||||
)
|
)
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
@XmlRootElement(name = "repositories")
|
@XmlRootElement(name = "repositories")
|
||||||
|
|||||||
@@ -36,13 +36,11 @@ package sonia.scm.web.filter;
|
|||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authz.AuthorizationException;
|
||||||
import org.apache.shiro.subject.Subject;
|
import org.apache.shiro.subject.Subject;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.ArgumentIsInvalidException;
|
import sonia.scm.ArgumentIsInvalidException;
|
||||||
import sonia.scm.SCMContext;
|
import sonia.scm.SCMContext;
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
@@ -53,17 +51,14 @@ import sonia.scm.security.ScmSecurityException;
|
|||||||
import sonia.scm.util.HttpUtil;
|
import sonia.scm.util.HttpUtil;
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import org.apache.shiro.authz.AuthorizationException;
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract http filter to check repository permissions.
|
* Abstract http filter to check repository permissions.
|
||||||
@@ -339,7 +334,7 @@ public abstract class PermissionFilter extends HttpFilter
|
|||||||
|
|
||||||
if (writeRequest)
|
if (writeRequest)
|
||||||
{
|
{
|
||||||
permitted = RepositoryPermissions.write(repository).isPermitted();
|
permitted = RepositoryPermissions.push(repository).isPermitted();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
225
scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java
Normal file
225
scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.apache.http.HttpStatus;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
import sonia.scm.repository.PermissionType;
|
||||||
|
import sonia.scm.repository.client.api.RepositoryClient;
|
||||||
|
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||||
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static sonia.scm.it.RepositoryUtil.addAndCommitRandomFile;
|
||||||
|
import static sonia.scm.it.RestUtil.given;
|
||||||
|
import static sonia.scm.it.ScmTypes.availableScmTypes;
|
||||||
|
import static sonia.scm.it.TestData.USER_SCM_ADMIN;
|
||||||
|
import static sonia.scm.it.TestData.callRepository;
|
||||||
|
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class PermissionsITCase {
|
||||||
|
|
||||||
|
public static final String USER_READ = "user_read";
|
||||||
|
public static final String USER_PASS = "pass";
|
||||||
|
private static final String USER_WRITE = "user_write";
|
||||||
|
private static final String USER_OWNER = "user_owner";
|
||||||
|
private static final String USER_OTHER = "user_other";
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
|
||||||
|
private final String repositoryType;
|
||||||
|
private int createdPermissions;
|
||||||
|
|
||||||
|
|
||||||
|
public PermissionsITCase(String repositoryType) {
|
||||||
|
this.repositoryType = repositoryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameters(name = "{0}")
|
||||||
|
public static Collection<String> createParameters() {
|
||||||
|
return availableScmTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void prepareEnvironment() {
|
||||||
|
TestData.createDefault();
|
||||||
|
TestData.createUser(USER_READ, USER_PASS);
|
||||||
|
TestData.createUserPermission(USER_READ, PermissionType.READ, repositoryType);
|
||||||
|
TestData.createUser(USER_WRITE, USER_PASS);
|
||||||
|
TestData.createUserPermission(USER_WRITE, PermissionType.WRITE, repositoryType);
|
||||||
|
TestData.createUser(USER_OWNER, USER_PASS);
|
||||||
|
TestData.createUserPermission(USER_OWNER, PermissionType.OWNER, repositoryType);
|
||||||
|
TestData.createUser(USER_OTHER, USER_PASS);
|
||||||
|
createdPermissions = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readUserShouldNotSeePermissions() {
|
||||||
|
assertNull(callRepository(USER_READ, USER_PASS, repositoryType, HttpStatus.SC_OK)
|
||||||
|
.extract()
|
||||||
|
.body().jsonPath().getString("_links.permissions.href"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readUserShouldNotSeeBruteForcePermissions() {
|
||||||
|
given(VndMediaType.PERMISSION, USER_READ, USER_PASS)
|
||||||
|
.when()
|
||||||
|
.get(TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType))
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeUserShouldNotSeePermissions() {
|
||||||
|
assertNull(callRepository(USER_WRITE, USER_PASS, repositoryType, HttpStatus.SC_OK)
|
||||||
|
.extract()
|
||||||
|
.body().jsonPath().getString("_links.permissions.href"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeUserShouldNotSeeBruteForcePermissions() {
|
||||||
|
given(VndMediaType.PERMISSION, USER_WRITE, USER_PASS)
|
||||||
|
.when()
|
||||||
|
.get(TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType))
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ownerShouldSeePermissions() {
|
||||||
|
List<Object> userPermissions = TestData.getUserPermissions(USER_OWNER, USER_PASS, repositoryType);
|
||||||
|
assertEquals(userPermissions.size(), createdPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void otherUserShouldNotSeeRepository() {
|
||||||
|
callRepository(USER_OTHER, USER_PASS, repositoryType, HttpStatus.SC_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void otherUserShouldNotSeeBruteForcePermissions() {
|
||||||
|
given(VndMediaType.PERMISSION, USER_OTHER, USER_PASS)
|
||||||
|
.when()
|
||||||
|
.get(TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType))
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readUserShouldCloneRepository() throws IOException {
|
||||||
|
RepositoryClient client = RepositoryUtil.createRepositoryClient(repositoryType, temporaryFolder.newFolder(), USER_READ, USER_PASS);
|
||||||
|
assertEquals(1, Objects.requireNonNull(client.getWorkingCopy().list()).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeUserShouldCloneRepository() throws IOException {
|
||||||
|
RepositoryClient client = RepositoryUtil.createRepositoryClient(repositoryType, temporaryFolder.newFolder(), USER_WRITE, USER_PASS);
|
||||||
|
assertEquals(1, Objects.requireNonNull(client.getWorkingCopy().list()).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ownerShouldCloneRepository() throws IOException {
|
||||||
|
RepositoryClient client = RepositoryUtil.createRepositoryClient(repositoryType, temporaryFolder.newFolder(), USER_OWNER, USER_PASS);
|
||||||
|
assertEquals(1, Objects.requireNonNull(client.getWorkingCopy().list()).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void otherUserShouldNotCloneRepository() {
|
||||||
|
TestData.callRepository(USER_OTHER, USER_PASS, repositoryType, HttpStatus.SC_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RepositoryClientException.class)
|
||||||
|
public void userWithReadPermissionShouldBeNotAuthorizedToCommit() throws IOException {
|
||||||
|
createAndCommit(USER_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userWithOwnerPermissionShouldBeAuthorizedToCommit() throws IOException {
|
||||||
|
createAndCommit(USER_OWNER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userWithWritePermissionShouldBeAuthorizedToCommit() throws IOException {
|
||||||
|
createAndCommit(USER_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createAndCommit(String username) throws IOException {
|
||||||
|
RepositoryClient client = RepositoryUtil.createRepositoryClient(repositoryType, temporaryFolder.newFolder(), username, PermissionsITCase.USER_PASS);
|
||||||
|
addAndCommitRandomFile(client, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userWithOwnerPermissionShouldBeAuthorizedToDeleteRepository(){
|
||||||
|
assertDeleteRepositoryOperation(HttpStatus.SC_NO_CONTENT, HttpStatus.SC_NOT_FOUND, USER_OWNER, repositoryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userWithReadPermissionShouldNotBeAuthorizedToDeleteRepository(){
|
||||||
|
assertDeleteRepositoryOperation(HttpStatus.SC_FORBIDDEN, HttpStatus.SC_OK, USER_READ, repositoryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userWithWritePermissionShouldNotBeAuthorizedToDeleteRepository(){
|
||||||
|
assertDeleteRepositoryOperation(HttpStatus.SC_FORBIDDEN, HttpStatus.SC_OK, USER_WRITE, repositoryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertDeleteRepositoryOperation(int expectedDeleteStatus, int expectedGetStatus, String user, String repositoryType) {
|
||||||
|
given(VndMediaType.REPOSITORY, user, PermissionsITCase.USER_PASS)
|
||||||
|
|
||||||
|
.when()
|
||||||
|
.delete(TestData.getDefaultRepositoryUrl(repositoryType))
|
||||||
|
|
||||||
|
.then()
|
||||||
|
.statusCode(expectedDeleteStatus);
|
||||||
|
|
||||||
|
given(VndMediaType.REPOSITORY, user, PermissionsITCase.USER_PASS)
|
||||||
|
|
||||||
|
.when()
|
||||||
|
.get(TestData.getDefaultRepositoryUrl(repositoryType))
|
||||||
|
|
||||||
|
.then()
|
||||||
|
.statusCode(expectedGetStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ package sonia.scm.it;
|
|||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -41,17 +42,12 @@ import org.junit.rules.TemporaryFolder;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
import org.junit.runners.Parameterized.Parameters;
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
import sonia.scm.repository.Person;
|
|
||||||
import sonia.scm.repository.client.api.ClientCommand;
|
|
||||||
import sonia.scm.repository.client.api.RepositoryClient;
|
import sonia.scm.repository.client.api.RepositoryClient;
|
||||||
import sonia.scm.repository.client.api.RepositoryClientFactory;
|
|
||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.UUID;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
@@ -66,8 +62,6 @@ import static sonia.scm.it.TestData.repositoryJson;
|
|||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public class RepositoriesITCase {
|
public class RepositoriesITCase {
|
||||||
|
|
||||||
public static final Person AUTHOR = new Person("SCM Administrator", "scmadmin@scm-manager.org");
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
|
||||||
@@ -142,57 +136,16 @@ public class RepositoriesITCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldCloneRepository() throws IOException {
|
public void shouldCloneRepository() throws IOException {
|
||||||
RepositoryClient client = createRepositoryClient();
|
RepositoryClient client = RepositoryUtil.createRepositoryClient(repositoryType, temporaryFolder.getRoot());
|
||||||
assertEquals("expected metadata dir", 1, client.getWorkingCopy().list().length);
|
assertEquals("expected metadata dir", 1, Objects.requireNonNull(client.getWorkingCopy().list()).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldCommitFiles() throws IOException {
|
public void shouldCommitFiles() throws IOException {
|
||||||
RepositoryClient client = createRepositoryClient();
|
RepositoryClient client = RepositoryUtil.createRepositoryClient(repositoryType, temporaryFolder.newFolder(), "scmadmin", "scmadmin");
|
||||||
|
String name = RepositoryUtil.addAndCommitRandomFile(client, "scmadmin");
|
||||||
for (int i = 0; i < 5; i++) {
|
RepositoryClient checkClient = RepositoryUtil.createRepositoryClient(repositoryType, temporaryFolder.newFolder(), "scmadmin", "scmadmin");
|
||||||
createRandomFile(client);
|
Assertions.assertThat(checkClient.getWorkingCopy().list()).contains(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
commit(client);
|
|
||||||
|
|
||||||
RepositoryClient checkClient = createRepositoryClient();
|
|
||||||
assertEquals("expected 5 files and metadata dir", 6, checkClient.getWorkingCopy().list().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void createRandomFile(RepositoryClient client) throws IOException {
|
|
||||||
String uuid = UUID.randomUUID().toString();
|
|
||||||
String name = "file-" + uuid + ".uuid";
|
|
||||||
|
|
||||||
File file = new File(client.getWorkingCopy(), name);
|
|
||||||
try (FileOutputStream out = new FileOutputStream(file)) {
|
|
||||||
out.write(uuid.getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
client.getAddCommand().add(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void commit(RepositoryClient repositoryClient) throws IOException {
|
|
||||||
repositoryClient.getCommitCommand().commit(AUTHOR, "commit");
|
|
||||||
if ( repositoryClient.isCommandSupported(ClientCommand.PUSH) ) {
|
|
||||||
repositoryClient.getPushCommand().push();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RepositoryClient createRepositoryClient() throws IOException {
|
|
||||||
RepositoryClientFactory clientFactory = new RepositoryClientFactory();
|
|
||||||
String cloneUrl = readCloneUrl();
|
|
||||||
return clientFactory.create(repositoryType, cloneUrl, "scmadmin", "scmadmin", temporaryFolder.newFolder());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readCloneUrl() {
|
|
||||||
return given(VndMediaType.REPOSITORY)
|
|
||||||
|
|
||||||
.when()
|
|
||||||
.get(repositoryUrl)
|
|
||||||
|
|
||||||
.then()
|
|
||||||
.extract()
|
|
||||||
.path("_links.httpProtocol.href");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
package sonia.scm.it;
|
package sonia.scm.it;
|
||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
|
import sonia.scm.repository.client.api.ClientCommand;
|
||||||
|
import sonia.scm.repository.client.api.RepositoryClient;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assume.assumeFalse;
|
|
||||||
import static sonia.scm.it.RestUtil.given;
|
import static sonia.scm.it.RestUtil.given;
|
||||||
import static sonia.scm.it.ScmTypes.availableScmTypes;
|
import static sonia.scm.it.ScmTypes.availableScmTypes;
|
||||||
|
|
||||||
@@ -23,7 +26,7 @@ public class RepositoryAccessITCase {
|
|||||||
public TemporaryFolder tempFolder = new TemporaryFolder();
|
public TemporaryFolder tempFolder = new TemporaryFolder();
|
||||||
|
|
||||||
private final String repositoryType;
|
private final String repositoryType;
|
||||||
private RepositoryUtil repositoryUtil;
|
private File folder;
|
||||||
|
|
||||||
public RepositoryAccessITCase(String repositoryType) {
|
public RepositoryAccessITCase(String repositoryType) {
|
||||||
this.repositoryType = repositoryType;
|
this.repositoryType = repositoryType;
|
||||||
@@ -35,16 +38,18 @@ public class RepositoryAccessITCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void initClient() throws IOException {
|
public void initClient() {
|
||||||
TestData.createDefault();
|
TestData.createDefault();
|
||||||
repositoryUtil = new RepositoryUtil(repositoryType, tempFolder.getRoot());
|
folder = tempFolder.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindBranches() throws IOException {
|
public void shouldFindBranches() throws IOException {
|
||||||
assumeFalse("There are no branches for SVN", repositoryType.equals("svn"));
|
RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
|
||||||
|
|
||||||
repositoryUtil.createAndCommitFile("a.txt", "a");
|
Assume.assumeTrue("There are no branches for " + repositoryType, repositoryClient.isCommandSupported(ClientCommand.BRANCH));
|
||||||
|
|
||||||
|
RepositoryUtil.createAndCommitFile(repositoryClient, "scmadmin", "a.txt", "a");
|
||||||
|
|
||||||
String branchesUrl = given()
|
String branchesUrl = given()
|
||||||
.when()
|
.when()
|
||||||
|
|||||||
@@ -8,52 +8,42 @@ import sonia.scm.repository.Person;
|
|||||||
import sonia.scm.repository.client.api.ClientCommand;
|
import sonia.scm.repository.client.api.ClientCommand;
|
||||||
import sonia.scm.repository.client.api.RepositoryClient;
|
import sonia.scm.repository.client.api.RepositoryClient;
|
||||||
import sonia.scm.repository.client.api.RepositoryClientFactory;
|
import sonia.scm.repository.client.api.RepositoryClientFactory;
|
||||||
import sonia.scm.web.VndMediaType;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
import static sonia.scm.it.RestUtil.ADMIN_PASSWORD;
|
|
||||||
import static sonia.scm.it.RestUtil.ADMIN_USERNAME;
|
|
||||||
import static sonia.scm.it.RestUtil.given;
|
|
||||||
|
|
||||||
public class RepositoryUtil {
|
public class RepositoryUtil {
|
||||||
|
|
||||||
private static final RepositoryClientFactory REPOSITORY_CLIENT_FACTORY = new RepositoryClientFactory();
|
private static final RepositoryClientFactory REPOSITORY_CLIENT_FACTORY = new RepositoryClientFactory();
|
||||||
|
|
||||||
private final RepositoryClient repositoryClient;
|
static RepositoryClient createRepositoryClient(String repositoryType, File folder) throws IOException {
|
||||||
private final File folder;
|
return createRepositoryClient(repositoryType, folder, "scmadmin", "scmadmin");
|
||||||
|
|
||||||
RepositoryUtil(String repositoryType, File folder) throws IOException {
|
|
||||||
this.repositoryClient = createRepositoryClient(repositoryType, folder);
|
|
||||||
this.folder = folder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RepositoryClient createRepositoryClient(String repositoryType, File folder) throws IOException {
|
static RepositoryClient createRepositoryClient(String repositoryType, File folder, String username, String password) throws IOException {
|
||||||
String httpProtocolUrl = given(VndMediaType.REPOSITORY)
|
String httpProtocolUrl = TestData.callRepository(username, password, repositoryType, HttpStatus.SC_OK)
|
||||||
|
|
||||||
.when()
|
|
||||||
.get(TestData.getDefaultRepositoryUrl(repositoryType))
|
|
||||||
|
|
||||||
.then()
|
|
||||||
.statusCode(HttpStatus.SC_OK)
|
|
||||||
.extract()
|
.extract()
|
||||||
.path("_links.httpProtocol.href");
|
.path("_links.httpProtocol.href");
|
||||||
|
|
||||||
|
return REPOSITORY_CLIENT_FACTORY.create(repositoryType, httpProtocolUrl, username, password, folder);
|
||||||
return REPOSITORY_CLIENT_FACTORY.create(repositoryType, httpProtocolUrl, ADMIN_USERNAME, ADMIN_PASSWORD, folder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void createAndCommitFile(String fileName, String content) throws IOException {
|
static String addAndCommitRandomFile(RepositoryClient client, String username) throws IOException {
|
||||||
Files.write(content, new File(folder, fileName), Charsets.UTF_8);
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
String name = "file-" + uuid + ".uuid";
|
||||||
|
createAndCommitFile(client, username, name, uuid);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createAndCommitFile(RepositoryClient repositoryClient, String username, String fileName, String content) throws IOException {
|
||||||
|
Files.write(content, new File(repositoryClient.getWorkingCopy(), fileName), Charsets.UTF_8);
|
||||||
repositoryClient.getAddCommand().add(fileName);
|
repositoryClient.getAddCommand().add(fileName);
|
||||||
commit("added " + fileName);
|
commit(repositoryClient, username, "added " + fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Changeset commit(String message) throws IOException {
|
static Changeset commit(RepositoryClient repositoryClient, String username, String message) throws IOException {
|
||||||
Changeset changeset = repositoryClient.getCommitCommand().commit(
|
Changeset changeset = repositoryClient.getCommitCommand().commit(new Person(username, username + "@scm-manager.org"), message);
|
||||||
new Person("scmadmin", "scmadmin@scm-manager.org"), message
|
|
||||||
);
|
|
||||||
if (repositoryClient.isCommandSupported(ClientCommand.PUSH)) {
|
if (repositoryClient.isCommandSupported(ClientCommand.PUSH)) {
|
||||||
repositoryClient.getPushCommand().push();
|
repositoryClient.getPushCommand().push();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,15 +19,19 @@ public class RestUtil {
|
|||||||
public static final String ADMIN_USERNAME = "scmadmin";
|
public static final String ADMIN_USERNAME = "scmadmin";
|
||||||
public static final String ADMIN_PASSWORD = "scmadmin";
|
public static final String ADMIN_PASSWORD = "scmadmin";
|
||||||
|
|
||||||
public static RequestSpecification given(String mediaType) {
|
|
||||||
return RestAssured.given()
|
|
||||||
.contentType(mediaType)
|
|
||||||
.accept(mediaType)
|
|
||||||
.auth().preemptive().basic(ADMIN_USERNAME, ADMIN_PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RequestSpecification given() {
|
public static RequestSpecification given() {
|
||||||
return RestAssured.given()
|
return RestAssured.given()
|
||||||
.auth().preemptive().basic(ADMIN_USERNAME, ADMIN_PASSWORD);
|
.auth().preemptive().basic(ADMIN_USERNAME, ADMIN_PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RequestSpecification given(String mediaType) {
|
||||||
|
return given(mediaType, ADMIN_USERNAME, ADMIN_PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RequestSpecification given(String mediaType, String username, String password) {
|
||||||
|
return RestAssured.given()
|
||||||
|
.contentType(mediaType)
|
||||||
|
.accept(mediaType)
|
||||||
|
.auth().preemptive().basic(username, password);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package sonia.scm.it;
|
package sonia.scm.it;
|
||||||
|
|
||||||
|
import io.restassured.response.ValidatableResponse;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import sonia.scm.repository.PermissionType;
|
||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
import javax.json.Json;
|
import javax.json.Json;
|
||||||
@@ -19,7 +21,9 @@ public class TestData {
|
|||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TestData.class);
|
private static final Logger LOG = LoggerFactory.getLogger(TestData.class);
|
||||||
|
|
||||||
private static final List<String> PROTECTED_USERS = asList("scmadmin", "anonymous");
|
public static final String USER_SCM_ADMIN = "scmadmin";
|
||||||
|
public static final String USER_ANONYMOUS = "anonymous";
|
||||||
|
private static final List<String> PROTECTED_USERS = asList(USER_SCM_ADMIN, USER_ANONYMOUS);
|
||||||
|
|
||||||
private static Map<String, String> DEFAULT_REPOSITORIES = new HashMap<>();
|
private static Map<String, String> DEFAULT_REPOSITORIES = new HashMap<>();
|
||||||
|
|
||||||
@@ -38,6 +42,77 @@ public class TestData {
|
|||||||
return DEFAULT_REPOSITORIES.get(repositoryType);
|
return DEFAULT_REPOSITORIES.get(repositoryType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void createUser(String username, String password) {
|
||||||
|
given(VndMediaType.USER)
|
||||||
|
.when()
|
||||||
|
.content(" {\n" +
|
||||||
|
" \"active\": true,\n" +
|
||||||
|
" \"admin\": false,\n" +
|
||||||
|
" \"creationDate\": \"2018-08-21T12:26:46.084Z\",\n" +
|
||||||
|
" \"displayName\": \"" + username + "\",\n" +
|
||||||
|
" \"mail\": \"user1@scm-manager.org\",\n" +
|
||||||
|
" \"name\": \"" + username + "\",\n" +
|
||||||
|
" \"password\": \"" + password + "\",\n" +
|
||||||
|
" \"type\": \"xml\"\n" +
|
||||||
|
" \n" +
|
||||||
|
" }")
|
||||||
|
.post(createResourceUrl("users"))
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_CREATED)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void createUserPermission(String name, PermissionType permissionType, String repositoryType) {
|
||||||
|
given(VndMediaType.PERMISSION)
|
||||||
|
.when()
|
||||||
|
.content("{\n" +
|
||||||
|
"\t\"type\": \"" + permissionType.name() + "\",\n" +
|
||||||
|
"\t\"name\": \"" + name + "\",\n" +
|
||||||
|
"\t\"groupPermission\": false\n" +
|
||||||
|
"\t\n" +
|
||||||
|
"}")
|
||||||
|
.post(TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType))
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_CREATED)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Object> getUserPermissions(String username, String password, String repositoryType) {
|
||||||
|
return callUserPermissions(username, password, repositoryType, HttpStatus.SC_OK)
|
||||||
|
.extract()
|
||||||
|
.body().jsonPath().getList("_embedded.permissions");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidatableResponse callUserPermissions(String username, String password, String repositoryType, int expectedStatusCode) {
|
||||||
|
return given(VndMediaType.PERMISSION, username, password)
|
||||||
|
.when()
|
||||||
|
.get(TestData.getDefaultPermissionUrl(username, password, repositoryType))
|
||||||
|
.then()
|
||||||
|
.statusCode(expectedStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidatableResponse callRepository(String username, String password, String repositoryType, int expectedStatusCode) {
|
||||||
|
return given(VndMediaType.REPOSITORY, username, password)
|
||||||
|
|
||||||
|
.when()
|
||||||
|
.get(getDefaultRepositoryUrl(repositoryType))
|
||||||
|
|
||||||
|
.then()
|
||||||
|
.statusCode(expectedStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDefaultPermissionUrl(String username, String password, String repositoryType) {
|
||||||
|
return given(VndMediaType.REPOSITORY, username, password)
|
||||||
|
.when()
|
||||||
|
.get(getDefaultRepositoryUrl(repositoryType))
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_OK)
|
||||||
|
.extract()
|
||||||
|
.body().jsonPath().getString("_links.permissions.href");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void cleanupRepositories() {
|
private static void cleanupRepositories() {
|
||||||
List<String> repositories = given(VndMediaType.REPOSITORY_COLLECTION)
|
List<String> repositories = given(VndMediaType.REPOSITORY_COLLECTION)
|
||||||
.when()
|
.when()
|
||||||
|
|||||||
@@ -28,12 +28,6 @@
|
|||||||
<version>2.0.0-SNAPSHOT</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.sdorra</groupId>
|
<groupId>com.github.sdorra</groupId>
|
||||||
<artifactId>shiro-unit</artifactId>
|
<artifactId>shiro-unit</artifactId>
|
||||||
|
|||||||
@@ -298,24 +298,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<version>5.2.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-params</artifactId>
|
|
||||||
<version>5.2.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
|
||||||
<version>5.2.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- core plugins -->
|
<!-- core plugins -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -8,15 +8,8 @@ import java.time.Instant;
|
|||||||
|
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public abstract class GroupDtoToGroupMapper {
|
public abstract class GroupDtoToGroupMapper extends BaseDtoMapper {
|
||||||
|
|
||||||
@Mapping(target = "creationDate", ignore = true)
|
@Mapping(target = "creationDate", ignore = true)
|
||||||
public abstract Group map(GroupDto groupDto);
|
public abstract Group map(GroupDto groupDto);
|
||||||
|
|
||||||
Long mapDate(Instant value) {
|
|
||||||
if (value != null) {
|
|
||||||
return value.toEpochMilli();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import de.otto.edison.hal.Embedded;
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
import de.otto.edison.hal.Links;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryPermissions;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static de.otto.edison.hal.Embedded.embeddedBuilder;
|
||||||
|
import static de.otto.edison.hal.Link.link;
|
||||||
|
import static de.otto.edison.hal.Links.linkingTo;
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
|
public class PermissionCollectionToDtoMapper {
|
||||||
|
|
||||||
|
private final ResourceLinks resourceLinks;
|
||||||
|
private final PermissionToPermissionDtoMapper permissionToPermissionDtoMapper;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public PermissionCollectionToDtoMapper(PermissionToPermissionDtoMapper permissionToPermissionDtoMapper, ResourceLinks resourceLinks) {
|
||||||
|
this.resourceLinks = resourceLinks;
|
||||||
|
this.permissionToPermissionDtoMapper = permissionToPermissionDtoMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HalRepresentation map(Repository repository) {
|
||||||
|
List<PermissionDto> permissionDtoList = repository.getPermissions()
|
||||||
|
.stream()
|
||||||
|
.map(permission -> permissionToPermissionDtoMapper.map(permission, repository))
|
||||||
|
.collect(toList());
|
||||||
|
return new HalRepresentation(createLinks(repository), embedDtos(permissionDtoList));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Links createLinks(Repository repository) {
|
||||||
|
RepositoryPermissions.permissionRead(repository).check();
|
||||||
|
Links.Builder linksBuilder = linkingTo()
|
||||||
|
.with(Links.linkingTo().self(resourceLinks.permission().all(repository.getNamespace(), repository.getName())).build());
|
||||||
|
if (RepositoryPermissions.permissionWrite(repository).isPermitted()) {
|
||||||
|
linksBuilder.single(link("create", resourceLinks.permission().create(repository.getNamespace(), repository.getName())));
|
||||||
|
}
|
||||||
|
return linksBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Embedded embedDtos(List<PermissionDto> permissionDtoList) {
|
||||||
|
return embeddedBuilder()
|
||||||
|
.with("permissions", permissionDtoList)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import sonia.scm.repository.Permission;
|
|||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.RepositoryManager;
|
import sonia.scm.repository.RepositoryManager;
|
||||||
import sonia.scm.repository.RepositoryNotFoundException;
|
import sonia.scm.repository.RepositoryNotFoundException;
|
||||||
|
import sonia.scm.repository.RepositoryPermissions;
|
||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -26,23 +27,23 @@ import javax.ws.rs.PathParam;
|
|||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PermissionRootResource {
|
public class PermissionRootResource {
|
||||||
|
|
||||||
private PermissionDtoToPermissionMapper dtoToModelMapper;
|
private PermissionDtoToPermissionMapper dtoToModelMapper;
|
||||||
private PermissionToPermissionDtoMapper modelToDtoMapper;
|
private PermissionToPermissionDtoMapper modelToDtoMapper;
|
||||||
|
private PermissionCollectionToDtoMapper permissionCollectionToDtoMapper;
|
||||||
private ResourceLinks resourceLinks;
|
private ResourceLinks resourceLinks;
|
||||||
private final RepositoryManager manager;
|
private final RepositoryManager manager;
|
||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public PermissionRootResource(PermissionDtoToPermissionMapper dtoToModelMapper, PermissionToPermissionDtoMapper modelToDtoMapper, ResourceLinks resourceLinks, RepositoryManager manager) {
|
public PermissionRootResource(PermissionDtoToPermissionMapper dtoToModelMapper, PermissionToPermissionDtoMapper modelToDtoMapper, PermissionCollectionToDtoMapper permissionCollectionToDtoMapper, ResourceLinks resourceLinks, RepositoryManager manager) {
|
||||||
this.dtoToModelMapper = dtoToModelMapper;
|
this.dtoToModelMapper = dtoToModelMapper;
|
||||||
this.modelToDtoMapper = modelToDtoMapper;
|
this.modelToDtoMapper = modelToDtoMapper;
|
||||||
|
this.permissionCollectionToDtoMapper = permissionCollectionToDtoMapper;
|
||||||
this.resourceLinks = resourceLinks;
|
this.resourceLinks = resourceLinks;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
@@ -65,9 +66,11 @@ public class PermissionRootResource {
|
|||||||
})
|
})
|
||||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||||
@Consumes(VndMediaType.PERMISSION)
|
@Consumes(VndMediaType.PERMISSION)
|
||||||
|
@Path("")
|
||||||
public Response create(@PathParam("namespace") String namespace, @PathParam("name") String name, PermissionDto permission) throws Exception {
|
public Response create(@PathParam("namespace") String namespace, @PathParam("name") String name, PermissionDto permission) throws Exception {
|
||||||
log.info("try to add new permission: {}", permission);
|
log.info("try to add new permission: {}", permission);
|
||||||
Repository repository = load(namespace, name);
|
Repository repository = load(namespace, name);
|
||||||
|
RepositoryPermissions.permissionWrite(repository).check();
|
||||||
checkPermissionAlreadyExists(permission, repository);
|
checkPermissionAlreadyExists(permission, repository);
|
||||||
repository.getPermissions().add(dtoToModelMapper.map(permission));
|
repository.getPermissions().add(dtoToModelMapper.map(permission));
|
||||||
manager.modify(repository);
|
manager.modify(repository);
|
||||||
@@ -94,11 +97,12 @@ public class PermissionRootResource {
|
|||||||
@Path("{permission-name}")
|
@Path("{permission-name}")
|
||||||
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("permission-name") String permissionName) throws NotFoundException {
|
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("permission-name") String permissionName) throws NotFoundException {
|
||||||
Repository repository = load(namespace, name);
|
Repository repository = load(namespace, name);
|
||||||
|
RepositoryPermissions.permissionRead(repository).check();
|
||||||
return Response.ok(
|
return Response.ok(
|
||||||
repository.getPermissions()
|
repository.getPermissions()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(permission -> permissionName.equals(permission.getName()))
|
.filter(permission -> permissionName.equals(permission.getName()))
|
||||||
.map(permission -> modelToDtoMapper.map(permission, new NamespaceAndName(repository.getNamespace(), repository.getName())))
|
.map(permission -> modelToDtoMapper.map(permission, repository))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(NotFoundException::new)
|
.orElseThrow(NotFoundException::new)
|
||||||
).build();
|
).build();
|
||||||
@@ -124,11 +128,8 @@ public class PermissionRootResource {
|
|||||||
@Path("")
|
@Path("")
|
||||||
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) throws RepositoryNotFoundException {
|
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) throws RepositoryNotFoundException {
|
||||||
Repository repository = load(namespace, name);
|
Repository repository = load(namespace, name);
|
||||||
List<PermissionDto> permissionDtoList = repository.getPermissions()
|
RepositoryPermissions.permissionRead(repository).check();
|
||||||
.stream()
|
return Response.ok(permissionCollectionToDtoMapper.map(repository)).build();
|
||||||
.map(per -> modelToDtoMapper.map(per, new NamespaceAndName(repository.getNamespace(), repository.getName())))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
return Response.ok(permissionDtoList).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -151,9 +152,10 @@ public class PermissionRootResource {
|
|||||||
public Response update(@PathParam("namespace") String namespace,
|
public Response update(@PathParam("namespace") String namespace,
|
||||||
@PathParam("name") String name,
|
@PathParam("name") String name,
|
||||||
@PathParam("permission-name") String permissionName,
|
@PathParam("permission-name") String permissionName,
|
||||||
PermissionDto permission) throws Exception {
|
PermissionDto permission) throws NotFoundException {
|
||||||
log.info("try to update the permission with name: {}. the modified permission is: {}", permissionName, permission);
|
log.info("try to update the permission with name: {}. the modified permission is: {}", permissionName, permission);
|
||||||
Repository repository = load(namespace, name);
|
Repository repository = load(namespace, name);
|
||||||
|
RepositoryPermissions.permissionWrite(repository).check();
|
||||||
Permission existingPermission = repository.getPermissions()
|
Permission existingPermission = repository.getPermissions()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(perm -> StringUtils.isNotBlank(perm.getName()) && perm.getName().equals(permissionName))
|
.filter(perm -> StringUtils.isNotBlank(perm.getName()) && perm.getName().equals(permissionName))
|
||||||
@@ -182,9 +184,10 @@ public class PermissionRootResource {
|
|||||||
@Path("{permission-name}")
|
@Path("{permission-name}")
|
||||||
public Response delete(@PathParam("namespace") String namespace,
|
public Response delete(@PathParam("namespace") String namespace,
|
||||||
@PathParam("name") String name,
|
@PathParam("name") String name,
|
||||||
@PathParam("permission-name") String permissionName) throws Exception {
|
@PathParam("permission-name") String permissionName) throws NotFoundException {
|
||||||
log.info("try to delete the permission with name: {}.", permissionName);
|
log.info("try to delete the permission with name: {}.", permissionName);
|
||||||
Repository repository = load(namespace, name);
|
Repository repository = load(namespace, name);
|
||||||
|
RepositoryPermissions.modify(repository).check();
|
||||||
repository.getPermissions()
|
repository.getPermissions()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(perm -> StringUtils.isNotBlank(perm.getName()) && perm.getName().equals(permissionName))
|
.filter(perm -> StringUtils.isNotBlank(perm.getName()) && perm.getName().equals(permissionName))
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package sonia.scm.api.v2.resources;
|
|||||||
|
|
||||||
import de.otto.edison.hal.Links;
|
import de.otto.edison.hal.Links;
|
||||||
import org.mapstruct.AfterMapping;
|
import org.mapstruct.AfterMapping;
|
||||||
|
import org.mapstruct.BeforeMapping;
|
||||||
import org.mapstruct.Context;
|
import org.mapstruct.Context;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.MappingTarget;
|
import org.mapstruct.MappingTarget;
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
|
||||||
import sonia.scm.repository.Permission;
|
import sonia.scm.repository.Permission;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryPermissions;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -21,21 +23,28 @@ public abstract class PermissionToPermissionDtoMapper {
|
|||||||
private ResourceLinks resourceLinks;
|
private ResourceLinks resourceLinks;
|
||||||
|
|
||||||
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
||||||
public abstract PermissionDto map(Permission permission, @Context NamespaceAndName namespaceAndName);
|
public abstract PermissionDto map(Permission permission, @Context Repository repository);
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeMapping
|
||||||
|
void validatePermissions(@Context Repository repository) {
|
||||||
|
RepositoryPermissions.permissionRead(repository).check();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the self, update and delete links.
|
* Add the self, update and delete links.
|
||||||
*
|
*
|
||||||
* @param target the mapped dto
|
* @param target the mapped dto
|
||||||
* @param namespaceAndName the repository namespace and name
|
* @param repository the repository
|
||||||
*/
|
*/
|
||||||
@AfterMapping
|
@AfterMapping
|
||||||
void appendLinks(@MappingTarget PermissionDto target, @Context NamespaceAndName namespaceAndName) {
|
void appendLinks(@MappingTarget PermissionDto target, @Context Repository repository) {
|
||||||
Links.Builder linksBuilder = linkingTo()
|
Links.Builder linksBuilder = linkingTo()
|
||||||
.self(resourceLinks.permission().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName()));
|
.self(resourceLinks.permission().self(repository.getNamespace(), repository.getName(), target.getName()));
|
||||||
linksBuilder.single(link("update", resourceLinks.permission().update(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName())));
|
if (RepositoryPermissions.permissionWrite(repository).isPermitted()) {
|
||||||
linksBuilder.single(link("delete", resourceLinks.permission().delete(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName())));
|
linksBuilder.single(link("update", resourceLinks.permission().update(repository.getNamespace(), repository.getName(), target.getName())));
|
||||||
|
linksBuilder.single(link("delete", resourceLinks.permission().delete(repository.getNamespace(), repository.getName(), target.getName())));
|
||||||
|
}
|
||||||
target.add(linksBuilder.build());
|
target.add(linksBuilder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ import org.mapstruct.*;
|
|||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public abstract class RepositoryDtoToRepositoryMapper {
|
public abstract class RepositoryDtoToRepositoryMapper extends BaseDtoMapper {
|
||||||
|
|
||||||
@Mapping(target = "creationDate", ignore = true)
|
@Mapping(target = "creationDate", ignore = true)
|
||||||
@Mapping(target = "lastModified", ignore = true)
|
|
||||||
@Mapping(target = "id", ignore = true)
|
@Mapping(target = "id", ignore = true)
|
||||||
@Mapping(target = "publicReadable", ignore = true)
|
@Mapping(target = "publicReadable", ignore = true)
|
||||||
@Mapping(target = "healthCheckFailures", ignore = true)
|
@Mapping(target = "healthCheckFailures", ignore = true)
|
||||||
|
|||||||
@@ -130,11 +130,17 @@ public class RepositoryResource {
|
|||||||
public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryDto repositoryDto) throws NotFoundException, ConcurrentModificationException {
|
public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryDto repositoryDto) throws NotFoundException, ConcurrentModificationException {
|
||||||
return adapter.update(
|
return adapter.update(
|
||||||
loadBy(namespace, name),
|
loadBy(namespace, name),
|
||||||
existing -> dtoToRepositoryMapper.map(repositoryDto, existing.getId()),
|
existing -> processUpdate(repositoryDto, existing),
|
||||||
nameAndNamespaceStaysTheSame(namespace, name)
|
nameAndNamespaceStaysTheSame(namespace, name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Repository processUpdate(RepositoryDto repositoryDto, Repository existing) {
|
||||||
|
Repository changedRepository = dtoToRepositoryMapper.map(repositoryDto, existing.getId());
|
||||||
|
changedRepository.setPermissions(existing.getPermissions());
|
||||||
|
return changedRepository;
|
||||||
|
}
|
||||||
|
|
||||||
@Path("tags/")
|
@Path("tags/")
|
||||||
public TagRootResource tags() {
|
public TagRootResource tags() {
|
||||||
return tagRootResource.get();
|
return tagRootResource.get();
|
||||||
@@ -178,6 +184,6 @@ public class RepositoryResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Predicate<Repository> nameAndNamespaceStaysTheSame(String namespace, String name) {
|
private Predicate<Repository> nameAndNamespaceStaysTheSame(String namespace, String name) {
|
||||||
return changed -> changed.getName().equals(name) && changed.getNamespace().equals(namespace);
|
return changed -> name.equals(changed.getName()) && namespace.equals(changed.getNamespace());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -313,6 +313,10 @@ class ResourceLinks {
|
|||||||
return permissionLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("permissions").parameters().method("getAll").parameters().href();
|
return permissionLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("permissions").parameters().method("getAll").parameters().href();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String create(String repositoryNamespace, String repositoryName) {
|
||||||
|
return permissionLinkBuilder.method("getRepositoryResource").parameters(repositoryNamespace, repositoryName).method("permissions").parameters().method("create").parameters().href();
|
||||||
|
}
|
||||||
|
|
||||||
String self(String repositoryNamespace, String repositoryName, String permissionName) {
|
String self(String repositoryNamespace, String repositoryName, String permissionName) {
|
||||||
return getLink(repositoryNamespace, repositoryName, permissionName, "get");
|
return getLink(repositoryNamespace, repositoryName, permissionName, "get");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,19 +9,20 @@ import sonia.scm.user.User;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
import static sonia.scm.api.rest.resources.UserResource.DUMMY_PASSWORT;
|
import static sonia.scm.api.rest.resources.UserResource.DUMMY_PASSWORT;
|
||||||
|
|
||||||
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
|
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
|
||||||
@SuppressWarnings("squid:S3306")
|
@SuppressWarnings("squid:S3306")
|
||||||
@Mapper
|
@Mapper
|
||||||
public abstract class UserDtoToUserMapper {
|
public abstract class UserDtoToUserMapper extends BaseDtoMapper {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PasswordService passwordService;
|
private PasswordService passwordService;
|
||||||
|
|
||||||
@Mapping(source = "password", target = "password", qualifiedByName = "encrypt")
|
@Mapping(source = "password", target = "password", qualifiedByName = "encrypt")
|
||||||
@Mapping(target = "creationDate", ignore = true)
|
@Mapping(target = "creationDate", ignore = true)
|
||||||
@Mapping(target = "lastModified", ignore = true)
|
|
||||||
public abstract User map(UserDto userDto, @Context String originalPassword);
|
public abstract User map(UserDto userDto, @Context String originalPassword);
|
||||||
|
|
||||||
@Named("encrypt")
|
@Named("encrypt")
|
||||||
|
|||||||
@@ -203,9 +203,9 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
|||||||
boolean hasPermission = false;
|
boolean hasPermission = false;
|
||||||
for (sonia.scm.repository.Permission permission : repositoryPermissions)
|
for (sonia.scm.repository.Permission permission : repositoryPermissions)
|
||||||
{
|
{
|
||||||
if (isUserPermitted(user, groups, permission))
|
hasPermission = isUserPermitted(user, groups, permission);
|
||||||
|
if (hasPermission)
|
||||||
{
|
{
|
||||||
|
|
||||||
String perm = permission.getType().getPermissionPrefix().concat(repository.getId());
|
String perm = permission.getType().getPermissionPrefix().concat(repository.getId());
|
||||||
if (logger.isTraceEnabled())
|
if (logger.isTraceEnabled())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
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.common.collect.ImmutableList;
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.authz.AuthorizationException;
|
import org.apache.shiro.authz.AuthorizationException;
|
||||||
|
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.assertj.core.util.Lists;
|
import org.assertj.core.util.Lists;
|
||||||
import org.jboss.resteasy.core.Dispatcher;
|
import org.jboss.resteasy.core.Dispatcher;
|
||||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||||
import org.jboss.resteasy.mock.MockHttpResponse;
|
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||||
import org.jboss.resteasy.spi.HttpRequest;
|
import org.jboss.resteasy.spi.HttpRequest;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
@@ -32,6 +39,7 @@ import java.net.URISyntaxException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static de.otto.edison.hal.Link.link;
|
import static de.otto.edison.hal.Link.link;
|
||||||
@@ -41,15 +49,25 @@ import static org.junit.Assert.fail;
|
|||||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.MockitoAnnotations.initMocks;
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
|
import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@SubjectAware(
|
||||||
|
username = "trillian",
|
||||||
|
password = "secret",
|
||||||
|
configuration = "classpath:sonia/scm/repository/shiro.ini"
|
||||||
|
)
|
||||||
public class PermissionRootResourceTest {
|
public class PermissionRootResourceTest {
|
||||||
private static final String REPOSITORY_NAMESPACE = "repo_namespace";
|
private static final String REPOSITORY_NAMESPACE = "repo_namespace";
|
||||||
private static final String REPOSITORY_NAME = "repo";
|
private static final String REPOSITORY_NAME = "repo";
|
||||||
|
private static final String PERMISSION_WRITE = "repository:permissionWrite:" + REPOSITORY_NAME;
|
||||||
|
private static final String PERMISSION_READ = "repository:permissionRead:" + REPOSITORY_NAME;
|
||||||
|
private static final String PERMISSION_OWNER = "repository:modify:" + REPOSITORY_NAME;
|
||||||
|
|
||||||
private static final String PERMISSION_NAME = "perm";
|
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_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 PATH_OF_ONE_PERMISSION = PATH_OF_ALL_PERMISSIONS + PERMISSION_NAME;
|
||||||
@@ -88,6 +106,9 @@ public class PermissionRootResourceTest {
|
|||||||
|
|
||||||
private Dispatcher dispatcher;
|
private Dispatcher dispatcher;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ShiroRule shiro = new ShiroRule();
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private RepositoryManager repositoryManager;
|
private RepositoryManager repositoryManager;
|
||||||
|
|
||||||
@@ -100,20 +121,28 @@ public class PermissionRootResourceTest {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private PermissionDtoToPermissionMapperImpl permissionDtoToPermissionMapper;
|
private PermissionDtoToPermissionMapperImpl permissionDtoToPermissionMapper;
|
||||||
|
|
||||||
|
private PermissionCollectionToDtoMapper permissionCollectionToDtoMapper;
|
||||||
|
|
||||||
private PermissionRootResource permissionRootResource;
|
private PermissionRootResource permissionRootResource;
|
||||||
|
|
||||||
|
private final Subject subject = mock(Subject.class);
|
||||||
|
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@Before
|
@Before
|
||||||
public void prepareEnvironment() {
|
public void prepareEnvironment() {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
permissionRootResource = new PermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, resourceLinks, repositoryManager);
|
permissionCollectionToDtoMapper = new PermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks);
|
||||||
|
permissionRootResource = new PermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, permissionCollectionToDtoMapper, resourceLinks, repositoryManager);
|
||||||
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
|
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
|
||||||
.of(new RepositoryResource(null, null, null, null, null, null, null,null, MockProvider.of(permissionRootResource))), null);
|
.of(new RepositoryResource(null, null, null, null, null, null, null, null, MockProvider.of(permissionRootResource))), null);
|
||||||
dispatcher = createDispatcher(repositoryRootResource);
|
dispatcher = createDispatcher(repositoryRootResource);
|
||||||
|
subjectThreadState.bind();
|
||||||
|
ThreadContext.bind(subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
@DisplayName("test endpoints on missing repository and user is Admin")
|
@DisplayName("test endpoints on missing repository")
|
||||||
Stream<DynamicTest> missedRepositoryTestFactory() {
|
Stream<DynamicTest> missedRepositoryTestFactory() {
|
||||||
return createDynamicTestsToAssertResponses(
|
return createDynamicTestsToAssertResponses(
|
||||||
requestGETAllPermissions.expectedResponseStatus(404),
|
requestGETAllPermissions.expectedResponseStatus(404),
|
||||||
@@ -124,9 +153,13 @@ public class PermissionRootResourceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
@DisplayName("test endpoints on missing permission and user is Admin")
|
@DisplayName("test endpoints on missing permissions and user is Admin")
|
||||||
Stream<DynamicTest> missedPermissionTestFactory() {
|
Stream<DynamicTest> missedPermissionTestFactory() {
|
||||||
authorizedUserHasARepository();
|
Repository mockRepository = mock(Repository.class);
|
||||||
|
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
|
||||||
|
when(mockRepository.getNamespace()).thenReturn(REPOSITORY_NAMESPACE);
|
||||||
|
when(mockRepository.getName()).thenReturn(REPOSITORY_NAME);
|
||||||
|
when(repositoryManager.get(any(NamespaceAndName.class))).thenReturn(mockRepository);
|
||||||
return createDynamicTestsToAssertResponses(
|
return createDynamicTestsToAssertResponses(
|
||||||
requestGETPermission.expectedResponseStatus(404),
|
requestGETPermission.expectedResponseStatus(404),
|
||||||
requestPOSTPermission.expectedResponseStatus(201),
|
requestPOSTPermission.expectedResponseStatus(201),
|
||||||
@@ -136,10 +169,12 @@ public class PermissionRootResourceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
@DisplayName("test endpoints on missing permission and user is not Admin")
|
@DisplayName("test endpoints on missing permissions and user is not Admin")
|
||||||
Stream<DynamicTest> missedPermissionUserForbiddenTestFactory() {
|
Stream<DynamicTest> missedPermissionUserForbiddenTestFactory() {
|
||||||
Repository mockRepository = mock(Repository.class);
|
Repository mockRepository = mock(Repository.class);
|
||||||
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
|
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
|
||||||
|
when(mockRepository.getNamespace()).thenReturn(REPOSITORY_NAMESPACE);
|
||||||
|
when(mockRepository.getName()).thenReturn(REPOSITORY_NAME);
|
||||||
doThrow(AuthorizationException.class).when(repositoryManager).get(any(NamespaceAndName.class));
|
doThrow(AuthorizationException.class).when(repositoryManager).get(any(NamespaceAndName.class));
|
||||||
return createDynamicTestsToAssertResponses(
|
return createDynamicTestsToAssertResponses(
|
||||||
requestGETPermission.expectedResponseStatus(403),
|
requestGETPermission.expectedResponseStatus(403),
|
||||||
@@ -149,15 +184,27 @@ public class PermissionRootResourceTest {
|
|||||||
requestPUTPermission.expectedResponseStatus(403));
|
requestPUTPermission.expectedResponseStatus(403));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userWithPermissionWritePermissionShouldGetAllPermissionsWithCreateAndUpdateLinks() throws URISyntaxException {
|
||||||
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE);
|
||||||
|
assertGettingExpectedPermissions(ImmutableList.copyOf(TEST_PERMISSIONS), PERMISSION_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userWithPermissionReadPermissionShouldGetAllPermissionsWithoutCreateAndUpdateLinks() throws URISyntaxException {
|
||||||
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_READ);
|
||||||
|
assertGettingExpectedPermissions(ImmutableList.copyOf(TEST_PERMISSIONS), PERMISSION_READ);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldGetAllPermissions() throws URISyntaxException {
|
public void shouldGetAllPermissions() throws URISyntaxException {
|
||||||
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_READ);
|
||||||
assertGettingExpectedPermissions(ImmutableList.copyOf(TEST_PERMISSIONS));
|
assertGettingExpectedPermissions(ImmutableList.copyOf(TEST_PERMISSIONS), PERMISSION_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldGetPermissionByName() throws URISyntaxException {
|
public void shouldGetPermissionByName() throws URISyntaxException {
|
||||||
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_READ);
|
||||||
Permission expectedPermission = TEST_PERMISSIONS.get(0);
|
Permission expectedPermission = TEST_PERMISSIONS.get(0);
|
||||||
assertExpectedRequest(requestGETPermission
|
assertExpectedRequest(requestGETPermission
|
||||||
.expectedResponseStatus(200)
|
.expectedResponseStatus(200)
|
||||||
@@ -169,7 +216,7 @@ public class PermissionRootResourceTest {
|
|||||||
PermissionDto actualPermissionDto = mapper.readValue(body, PermissionDto.class);
|
PermissionDto actualPermissionDto = mapper.readValue(body, PermissionDto.class);
|
||||||
assertThat(actualPermissionDto)
|
assertThat(actualPermissionDto)
|
||||||
.as("response payload match permission object model")
|
.as("response payload match permission object model")
|
||||||
.isEqualToComparingFieldByFieldRecursively(getExpectedPermissionDto(expectedPermission))
|
.isEqualToComparingFieldByFieldRecursively(getExpectedPermissionDto(expectedPermission, PERMISSION_READ))
|
||||||
;
|
;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
fail();
|
fail();
|
||||||
@@ -180,7 +227,7 @@ public class PermissionRootResourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldGetCreatedPermissions() throws URISyntaxException {
|
public void shouldGetCreatedPermissions() throws URISyntaxException {
|
||||||
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE);
|
||||||
Permission newPermission = new Permission("new_group_perm", PermissionType.WRITE, true);
|
Permission newPermission = new Permission("new_group_perm", PermissionType.WRITE, true);
|
||||||
ArrayList<Permission> permissions = Lists.newArrayList(TEST_PERMISSIONS);
|
ArrayList<Permission> permissions = Lists.newArrayList(TEST_PERMISSIONS);
|
||||||
permissions.add(newPermission);
|
permissions.add(newPermission);
|
||||||
@@ -192,12 +239,12 @@ public class PermissionRootResourceTest {
|
|||||||
.as("POST response has no body")
|
.as("POST response has no body")
|
||||||
.isBlank())
|
.isBlank())
|
||||||
);
|
);
|
||||||
assertGettingExpectedPermissions(expectedPermissions);
|
assertGettingExpectedPermissions(expectedPermissions, PERMISSION_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotAddExistingPermission() throws URISyntaxException {
|
public void shouldNotAddExistingPermission() throws URISyntaxException {
|
||||||
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE);
|
||||||
Permission newPermission = TEST_PERMISSIONS.get(0);
|
Permission newPermission = TEST_PERMISSIONS.get(0);
|
||||||
assertExpectedRequest(requestPOSTPermission
|
assertExpectedRequest(requestPOSTPermission
|
||||||
.content("{\"name\" : \"" + newPermission.getName() + "\" , \"type\" : \"WRITE\" , \"groupPermission\" : true}")
|
.content("{\"name\" : \"" + newPermission.getName() + "\" , \"type\" : \"WRITE\" , \"groupPermission\" : true}")
|
||||||
@@ -207,7 +254,7 @@ public class PermissionRootResourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldGetUpdatedPermissions() throws URISyntaxException {
|
public void shouldGetUpdatedPermissions() throws URISyntaxException {
|
||||||
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE);
|
||||||
Permission modifiedPermission = TEST_PERMISSIONS.get(0);
|
Permission modifiedPermission = TEST_PERMISSIONS.get(0);
|
||||||
// modify the type to owner
|
// modify the type to owner
|
||||||
modifiedPermission.setType(PermissionType.OWNER);
|
modifiedPermission.setType(PermissionType.OWNER);
|
||||||
@@ -220,13 +267,13 @@ public class PermissionRootResourceTest {
|
|||||||
.as("PUT response has no body")
|
.as("PUT response has no body")
|
||||||
.isBlank())
|
.isBlank())
|
||||||
);
|
);
|
||||||
assertGettingExpectedPermissions(expectedPermissions);
|
assertGettingExpectedPermissions(expectedPermissions, PERMISSION_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldDeletePermissions() throws URISyntaxException {
|
public void shouldDeletePermissions() throws URISyntaxException {
|
||||||
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_OWNER);
|
||||||
Permission deletedPermission = TEST_PERMISSIONS.get(0);
|
Permission deletedPermission = TEST_PERMISSIONS.get(0);
|
||||||
ImmutableList<Permission> expectedPermissions = ImmutableList.copyOf(TEST_PERMISSIONS.subList(1, TEST_PERMISSIONS.size()));
|
ImmutableList<Permission> expectedPermissions = ImmutableList.copyOf(TEST_PERMISSIONS.subList(1, TEST_PERMISSIONS.size()));
|
||||||
assertExpectedRequest(requestDELETEPermission
|
assertExpectedRequest(requestDELETEPermission
|
||||||
@@ -236,12 +283,12 @@ public class PermissionRootResourceTest {
|
|||||||
.as("DELETE response has no body")
|
.as("DELETE response has no body")
|
||||||
.isBlank())
|
.isBlank())
|
||||||
);
|
);
|
||||||
assertGettingExpectedPermissions(expectedPermissions);
|
assertGettingExpectedPermissions(expectedPermissions, PERMISSION_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deletingNotExistingPermissionShouldProcess() throws URISyntaxException {
|
public void deletingNotExistingPermissionShouldProcess() throws URISyntaxException {
|
||||||
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
|
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_OWNER);
|
||||||
Permission deletedPermission = TEST_PERMISSIONS.get(0);
|
Permission deletedPermission = TEST_PERMISSIONS.get(0);
|
||||||
ImmutableList<Permission> expectedPermissions = ImmutableList.copyOf(TEST_PERMISSIONS.subList(1, TEST_PERMISSIONS.size()));
|
ImmutableList<Permission> expectedPermissions = ImmutableList.copyOf(TEST_PERMISSIONS.subList(1, TEST_PERMISSIONS.size()));
|
||||||
assertExpectedRequest(requestDELETEPermission
|
assertExpectedRequest(requestDELETEPermission
|
||||||
@@ -251,7 +298,7 @@ public class PermissionRootResourceTest {
|
|||||||
.as("DELETE response has no body")
|
.as("DELETE response has no body")
|
||||||
.isBlank())
|
.isBlank())
|
||||||
);
|
);
|
||||||
assertGettingExpectedPermissions(expectedPermissions);
|
assertGettingExpectedPermissions(expectedPermissions, PERMISSION_READ);
|
||||||
assertExpectedRequest(requestDELETEPermission
|
assertExpectedRequest(requestDELETEPermission
|
||||||
.path(PATH_OF_ALL_PERMISSIONS + deletedPermission.getName())
|
.path(PATH_OF_ALL_PERMISSIONS + deletedPermission.getName())
|
||||||
.expectedResponseStatus(204)
|
.expectedResponseStatus(204)
|
||||||
@@ -259,23 +306,32 @@ public class PermissionRootResourceTest {
|
|||||||
.as("DELETE response has no body")
|
.as("DELETE response has no body")
|
||||||
.isBlank())
|
.isBlank())
|
||||||
);
|
);
|
||||||
assertGettingExpectedPermissions(expectedPermissions);
|
assertGettingExpectedPermissions(expectedPermissions, PERMISSION_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertGettingExpectedPermissions(ImmutableList<Permission> expectedPermissions) throws URISyntaxException {
|
private void assertGettingExpectedPermissions(ImmutableList<Permission> expectedPermissions, String userPermission) throws URISyntaxException {
|
||||||
assertExpectedRequest(requestGETAllPermissions
|
assertExpectedRequest(requestGETAllPermissions
|
||||||
.expectedResponseStatus(200)
|
.expectedResponseStatus(200)
|
||||||
.responseValidator((response) -> {
|
.responseValidator((response) -> {
|
||||||
String body = response.getContentAsString();
|
String body = response.getContentAsString();
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
try {
|
try {
|
||||||
List<PermissionDto> actualPermissionDtos = mapper.readValue(body, new TypeReference<List<PermissionDto>>() {
|
HalRepresentation halRepresentation = mapper.readValue(body, HalRepresentation.class);
|
||||||
});
|
List<HalRepresentation> actualPermissionDtos = halRepresentation.getEmbedded().getItemsBy("permissions", HalRepresentation.class);
|
||||||
assertThat(actualPermissionDtos)
|
List<PermissionDto> permissionDtoStream = actualPermissionDtos.stream()
|
||||||
|
.map(hal -> {
|
||||||
|
PermissionDto result = new PermissionDto();
|
||||||
|
result.setName(hal.getAttribute("name").asText());
|
||||||
|
result.setType(hal.getAttribute("type").asText());
|
||||||
|
result.setGroupPermission(hal.getAttribute("groupPermission").asBoolean());
|
||||||
|
result.add(hal.getLinks());
|
||||||
|
return result;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
assertThat(permissionDtoStream)
|
||||||
.as("response payload match permission object models")
|
.as("response payload match permission object models")
|
||||||
.hasSize(expectedPermissions.size())
|
.hasSize(expectedPermissions.size())
|
||||||
.usingRecursiveFieldByFieldElementComparator()
|
.usingRecursiveFieldByFieldElementComparator()
|
||||||
.containsExactlyInAnyOrder(getExpectedPermissionDtos(Lists.newArrayList(expectedPermissions)))
|
.containsExactlyInAnyOrder(getExpectedPermissionDtos(Lists.newArrayList(expectedPermissions), userPermission))
|
||||||
;
|
;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
fail();
|
fail();
|
||||||
@@ -284,38 +340,45 @@ public class PermissionRootResourceTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PermissionDto[] getExpectedPermissionDtos(ArrayList<Permission> permissions) {
|
private PermissionDto[] getExpectedPermissionDtos(ArrayList<Permission> permissions, String userPermission) {
|
||||||
return permissions
|
return permissions
|
||||||
.stream()
|
.stream()
|
||||||
.map(this::getExpectedPermissionDto)
|
.map(p -> getExpectedPermissionDto(p, userPermission))
|
||||||
.toArray(PermissionDto[]::new);
|
.toArray(PermissionDto[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PermissionDto getExpectedPermissionDto(Permission permission) {
|
private PermissionDto getExpectedPermissionDto(Permission permission, String userPermission) {
|
||||||
PermissionDto result = new PermissionDto();
|
PermissionDto result = new PermissionDto();
|
||||||
result.setName(permission.getName());
|
result.setName(permission.getName());
|
||||||
result.setGroupPermission(permission.isGroupPermission());
|
result.setGroupPermission(permission.isGroupPermission());
|
||||||
result.setType(permission.getType().name());
|
result.setType(permission.getType().name());
|
||||||
String permissionHref = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS + permission.getName();
|
String permissionHref = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS + permission.getName();
|
||||||
|
if (PERMISSION_READ.equals(userPermission)) {
|
||||||
|
result.add(linkingTo()
|
||||||
|
.self(permissionHref)
|
||||||
|
.build());
|
||||||
|
} else {
|
||||||
result.add(linkingTo()
|
result.add(linkingTo()
|
||||||
.self(permissionHref)
|
.self(permissionHref)
|
||||||
.single(link("update", permissionHref))
|
.single(link("update", permissionHref))
|
||||||
.single(link("delete", permissionHref))
|
.single(link("delete", permissionHref))
|
||||||
.build());
|
.build());
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Repository authorizedUserHasARepository() {
|
private Repository createUserWithRepository(String userPermission) {
|
||||||
Repository mockRepository = mock(Repository.class);
|
Repository mockRepository = mock(Repository.class);
|
||||||
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
|
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
|
||||||
when(mockRepository.getNamespace()).thenReturn(REPOSITORY_NAMESPACE);
|
when(mockRepository.getNamespace()).thenReturn(REPOSITORY_NAMESPACE);
|
||||||
when(mockRepository.getName()).thenReturn(REPOSITORY_NAME);
|
when(mockRepository.getName()).thenReturn(REPOSITORY_NAME);
|
||||||
when(repositoryManager.get(any(NamespaceAndName.class))).thenReturn(mockRepository);
|
when(repositoryManager.get(any(NamespaceAndName.class))).thenReturn(mockRepository);
|
||||||
|
when(subject.isPermitted(userPermission != null ? eq(userPermission) : any(String.class))).thenReturn(true);
|
||||||
return mockRepository;
|
return mockRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void authorizedUserHasARepositoryWithPermissions(ArrayList<Permission> permissions) {
|
private void createUserWithRepositoryAndPermissions(ArrayList<Permission> permissions, String userPermission) {
|
||||||
when(authorizedUserHasARepository().getPermissions()).thenReturn(permissions);
|
when(createUserWithRepository(userPermission).getPermissions()).thenReturn(permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<DynamicTest> createDynamicTestsToAssertResponses(ExpectedRequest... expectedRequests) {
|
private Stream<DynamicTest> createDynamicTestsToAssertResponses(ExpectedRequest... expectedRequests) {
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ import org.junit.Before;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import sonia.scm.PageResult;
|
import sonia.scm.PageResult;
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
|
import sonia.scm.repository.Permission;
|
||||||
|
import sonia.scm.repository.PermissionType;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.RepositoryIsNotArchivedException;
|
import sonia.scm.repository.RepositoryIsNotArchivedException;
|
||||||
import sonia.scm.repository.RepositoryManager;
|
import sonia.scm.repository.RepositoryManager;
|
||||||
@@ -33,10 +36,13 @@ import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
|||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_PRECONDITION_FAILED;
|
import static javax.servlet.http.HttpServletResponse.SC_PRECONDITION_FAILED;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentCaptor.forClass;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyObject;
|
import static org.mockito.Matchers.anyObject;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@@ -239,6 +245,28 @@ public class RepositoryRootResourceTest {
|
|||||||
verify(repositoryManager).create(any(Repository.class));
|
verify(repositoryManager).create(any(Repository.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotOverwriteExistingPermissionsOnUpdate() throws Exception {
|
||||||
|
Repository existingRepository = mockRepository("space", "repo");
|
||||||
|
existingRepository.setPermissions(singletonList(new Permission("user", PermissionType.READ)));
|
||||||
|
|
||||||
|
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
|
||||||
|
byte[] repository = Resources.toByteArray(url);
|
||||||
|
|
||||||
|
ArgumentCaptor<Repository> 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());
|
||||||
|
}
|
||||||
|
|
||||||
private PageResult<Repository> createSingletonPageResult(Repository repository) {
|
private PageResult<Repository> createSingletonPageResult(Repository repository) {
|
||||||
return new PageResult<>(singletonList(repository), 0);
|
return new PageResult<>(singletonList(repository), 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,15 +120,15 @@ public final class IntegrationTestUtil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<String> createRepositoryTypeParameters() {
|
public static Collection<String[]> createRepositoryTypeParameters() {
|
||||||
Collection<String> params = new ArrayList<>();
|
Collection<String[]> params = new ArrayList<>();
|
||||||
|
|
||||||
params.add("git");
|
params.add(new String[]{"git"});
|
||||||
params.add("svn" );
|
params.add(new String[]{"svn"});
|
||||||
|
|
||||||
if (IOUtil.search("hg") != null)
|
if (IOUtil.search("hg") != null)
|
||||||
{
|
{
|
||||||
params.add("hg");
|
params.add(new String[]{"hg"});
|
||||||
}
|
}
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class RepositoryArchiveITCase
|
|||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
@Parameterized.Parameters(name = "{0}")
|
@Parameterized.Parameters(name = "{0}")
|
||||||
public static Collection<String> createParameters() {
|
public static Collection<String[]> createParameters() {
|
||||||
return IntegrationTestUtil.createRepositoryTypeParameters();
|
return IntegrationTestUtil.createRepositoryTypeParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ public class RepositoryHookITCase extends AbstractAdminITCaseBase
|
|||||||
* @return repository types test parameter
|
* @return repository types test parameter
|
||||||
*/
|
*/
|
||||||
@Parameters(name = "{0}")
|
@Parameters(name = "{0}")
|
||||||
public static Collection<String> createParameters()
|
public static Collection<String[]> createParameters()
|
||||||
{
|
{
|
||||||
return IntegrationTestUtil.createRepositoryTypeParameters();
|
return IntegrationTestUtil.createRepositoryTypeParameters();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,15 +40,12 @@ import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
|||||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
import org.apache.shiro.subject.Subject;
|
import org.apache.shiro.subject.Subject;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import sonia.scm.cache.Cache;
|
import sonia.scm.cache.Cache;
|
||||||
import sonia.scm.cache.CacheManager;
|
import sonia.scm.cache.CacheManager;
|
||||||
@@ -60,6 +57,16 @@ import sonia.scm.repository.RepositoryTestData;
|
|||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserTestData;
|
import sonia.scm.user.UserTestData;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.anyObject;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link AuthorizationCollector}.
|
* Unit tests for {@link AuthorizationCollector}.
|
||||||
*
|
*
|
||||||
@@ -200,7 +207,7 @@ public class DefaultAuthorizationCollectorTest {
|
|||||||
AuthorizationInfo authInfo = collector.collect();
|
AuthorizationInfo authInfo = collector.collect();
|
||||||
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
|
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
|
||||||
assertThat(authInfo.getObjectPermissions(), nullValue());
|
assertThat(authInfo.getObjectPermissions(), nullValue());
|
||||||
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("repository:read:one", "repository:read,write:two"));
|
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("repository:read,pull:one", "repository:read,pull,push:two"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user