mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-08 17:31:33 +02:00
Add integration tests for anonymous access
This commit is contained in:
@@ -1,26 +1,170 @@
|
||||
package sonia.scm.it;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junitpioneer.jupiter.TempDirectory;
|
||||
import sonia.scm.it.utils.RepositoryUtil;
|
||||
import sonia.scm.it.utils.RestUtil;
|
||||
import sonia.scm.it.utils.ScmRequests;
|
||||
import sonia.scm.it.utils.ScmTypes;
|
||||
import sonia.scm.it.utils.TestData;
|
||||
import sonia.scm.repository.client.api.RepositoryClient;
|
||||
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonArray;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static sonia.scm.it.utils.TestData.JSON_BUILDER;
|
||||
import static sonia.scm.it.utils.TestData.USER_ANONYMOUS;
|
||||
import static sonia.scm.it.utils.TestData.WRITE;
|
||||
import static sonia.scm.it.utils.TestData.getDefaultRepositoryUrl;
|
||||
|
||||
public class AnonymousAccessITCase {
|
||||
@ExtendWith(TempDirectory.class)
|
||||
class AnonymousAccessITCase {
|
||||
|
||||
@Test
|
||||
public void shouldAccessIndexResourceWithoutAuthentication() {
|
||||
void shouldAccessIndexResourceWithoutAuthentication() {
|
||||
ScmRequests.start()
|
||||
.requestIndexResource()
|
||||
.assertStatusCode(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRejectUserResourceWithoutAuthentication() {
|
||||
void shouldRejectRepositoryResourceWithoutAuthentication() {
|
||||
assertEquals(401, RestAssured.given()
|
||||
.when()
|
||||
.get(RestUtil.REST_BASE_URL.resolve("users/"))
|
||||
.get(RestUtil.REST_BASE_URL.resolve("repositories/"))
|
||||
.statusCode());
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class WithAnonymousAccess {
|
||||
@BeforeAll
|
||||
void enableAnonymousAccess() {
|
||||
setAnonymousAccess(true);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void createRepository() {
|
||||
TestData.createDefault();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGrantAnonymousAccessToRepositoryList() {
|
||||
assertEquals(200, RestAssured.given()
|
||||
.when()
|
||||
.get(RestUtil.REST_BASE_URL.resolve("repositories"))
|
||||
.statusCode());
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithoutAnonymousAccessForRepository {
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScmTypes.class)
|
||||
void shouldGrantAnonymousAccessToRepository(String type) {
|
||||
assertEquals(401, RestAssured.given()
|
||||
.when()
|
||||
.get(getDefaultRepositoryUrl(type))
|
||||
.statusCode());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScmTypes.class)
|
||||
void shouldNotCloneRepository(String type, @TempDirectory.TempDir Path temporaryFolder) {
|
||||
assertThrows(RepositoryClientException.class, () -> RepositoryUtil.createAnonymousRepositoryClient(type, Files.createDirectories(temporaryFolder).toFile()));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithAnonymousAccessForRepository {
|
||||
|
||||
@BeforeEach
|
||||
void grantAnonymousAccessToRepo() {
|
||||
ScmTypes.availableScmTypes().stream().forEach(type -> TestData.createUserPermission(USER_ANONYMOUS, WRITE, type));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScmTypes.class)
|
||||
void shouldGrantAnonymousAccessToRepository(String type) {
|
||||
assertEquals(200, RestAssured.given()
|
||||
.when()
|
||||
.get(getDefaultRepositoryUrl(type))
|
||||
.statusCode());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScmTypes.class)
|
||||
void shouldCloneRepository(String type, @TempDirectory.TempDir Path temporaryFolder) throws IOException {
|
||||
RepositoryClient client = RepositoryUtil.createAnonymousRepositoryClient(type, Files.createDirectories(temporaryFolder).toFile());
|
||||
assertEquals(1, Objects.requireNonNull(client.getWorkingCopy().list()).length);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
void disableAnonymousAccess() {
|
||||
setAnonymousAccess(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setAnonymousAccess(boolean anonymousAccessEnabled) {
|
||||
RestUtil.given("application/vnd.scmm-config+json;v=2")
|
||||
.body(createConfig(anonymousAccessEnabled))
|
||||
|
||||
.when()
|
||||
.put(RestUtil.REST_BASE_URL.toASCIIString() + "config")
|
||||
|
||||
.then()
|
||||
.statusCode(HttpServletResponse.SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
private static String createConfig(boolean anonymousAccessEnabled) {
|
||||
JsonArray emptyArray = Json.createBuilderFactory(emptyMap()).createArrayBuilder().build();
|
||||
return JSON_BUILDER
|
||||
.add("adminGroups", emptyArray)
|
||||
.add("adminUsers", emptyArray)
|
||||
.add("anonymousAccessEnabled", anonymousAccessEnabled)
|
||||
.add("baseUrl", "https://next-scm.cloudogu.com/scm")
|
||||
.add("dateFormat", "YYYY-MM-DD HH:mm:ss")
|
||||
.add("disableGroupingGrid", false)
|
||||
.add("enableProxy", false)
|
||||
.add("enabledXsrfProtection", true)
|
||||
.add("forceBaseUrl", false)
|
||||
.add("loginAttemptLimit", 100)
|
||||
.add("loginAttemptLimitTimeout", 300)
|
||||
.add("loginInfoUrl", "https://login-info.scm-manager.org/api/v1/login-info")
|
||||
.add("namespaceStrategy", "UsernameNamespaceStrategy")
|
||||
.add("pluginUrl", "https://oss.cloudogu.com/jenkins/job/scm-manager/job/scm-manager-bitbucket/job/plugin-snapshot/job/master/lastSuccessfulBuild/artifact/plugins/plugin-center.json")
|
||||
.add("proxyExcludes", emptyArray)
|
||||
.addNull("proxyPassword")
|
||||
.add("proxyPort", 8080)
|
||||
.add("proxyServer", "proxy.mydomain.com")
|
||||
.addNull("proxyUser")
|
||||
.add("realmDescription", "SONIA :: SCM Manager")
|
||||
.add("skipFailedAuthenticators", false)
|
||||
.build().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,14 @@ public class RepositoryUtil {
|
||||
return REPOSITORY_CLIENT_FACTORY.create(repositoryType, httpProtocolUrl, username, password, folder);
|
||||
}
|
||||
|
||||
public static RepositoryClient createAnonymousRepositoryClient(String repositoryType, File folder) throws IOException {
|
||||
String httpProtocolUrl = TestData.callRepository("scmadmin", "scmadmin", repositoryType, HttpStatus.SC_OK)
|
||||
.extract()
|
||||
.path("_links.protocol.find{it.name=='http'}.href");
|
||||
|
||||
return REPOSITORY_CLIENT_FACTORY.create(repositoryType, httpProtocolUrl, folder);
|
||||
}
|
||||
|
||||
public static String addAndCommitRandomFile(RepositoryClient client, String username) throws IOException {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String name = "file-" + uuid + ".uuid";
|
||||
|
||||
@@ -29,9 +29,13 @@ public class RestUtil {
|
||||
}
|
||||
|
||||
public static RequestSpecification given(String mediaType, String username, String password) {
|
||||
return RestAssured.given()
|
||||
.contentType(mediaType)
|
||||
.accept(mediaType)
|
||||
return givenAnonymous(mediaType)
|
||||
.auth().preemptive().basic(username, password);
|
||||
}
|
||||
|
||||
public static RequestSpecification givenAnonymous(String mediaType) {
|
||||
return RestAssured.given()
|
||||
.contentType(mediaType)
|
||||
.accept(mediaType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package sonia.scm.it.utils;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ScmTypes {
|
||||
public class ScmTypes implements ArgumentsProvider {
|
||||
public static Collection<String> availableScmTypes() {
|
||||
Collection<String> params = new ArrayList<>();
|
||||
|
||||
@@ -18,4 +22,9 @@ public class ScmTypes {
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception {
|
||||
return availableScmTypes().stream().map(Arguments::of);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.stream.Collectors;
|
||||
import static java.util.Arrays.asList;
|
||||
import static sonia.scm.it.utils.RestUtil.createResourceUrl;
|
||||
import static sonia.scm.it.utils.RestUtil.given;
|
||||
import static sonia.scm.it.utils.RestUtil.givenAnonymous;
|
||||
import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
|
||||
|
||||
public class TestData {
|
||||
@@ -25,7 +26,7 @@ public class TestData {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TestData.class);
|
||||
|
||||
public static final String USER_SCM_ADMIN = "scmadmin";
|
||||
public static final String USER_ANONYMOUS = "anonymous";
|
||||
public static final String USER_ANONYMOUS = "_anonymous";
|
||||
|
||||
public static final Collection<String> READ = asList("read", "pull");
|
||||
public static final Collection<String> WRITE = asList("read", "write", "pull", "push");
|
||||
@@ -147,6 +148,16 @@ public class TestData {
|
||||
.statusCode(expectedStatusCode);
|
||||
}
|
||||
|
||||
public static ValidatableResponse callAnonymousRepository(String repositoryType, int expectedStatusCode) {
|
||||
return givenAnonymous(VndMediaType.REPOSITORY)
|
||||
|
||||
.when()
|
||||
.get(getDefaultRepositoryUrl(repositoryType))
|
||||
|
||||
.then()
|
||||
.statusCode(expectedStatusCode);
|
||||
}
|
||||
|
||||
public static String getDefaultPermissionUrl(String username, String password, String repositoryType) {
|
||||
return given(VndMediaType.REPOSITORY, username, password)
|
||||
.when()
|
||||
|
||||
@@ -123,6 +123,12 @@ public final class RepositoryClientFactory
|
||||
password, workingCopy));
|
||||
}
|
||||
|
||||
public RepositoryClient create(String type, String url, File workingCopy)
|
||||
throws IOException
|
||||
{
|
||||
return new RepositoryClient(getProvider(type).create(url, null, null, workingCopy));
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user