This commit is contained in:
Mohamed Karray
2018-10-02 13:20:55 +02:00
42 changed files with 949 additions and 66 deletions

View File

@@ -0,0 +1,47 @@
package sonia.scm.api.v2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertFalse;
import static sonia.scm.api.v2.ValidationConstraints.USER_GROUP_PATTERN;
@RunWith(Parameterized.class)
public class ValidationConstraints_IllegalCharactersTest {
private static final List<Character> ACCEPTED_CHARS = asList('@', '_', '-', '.');
private final Pattern userGroupPattern=Pattern.compile(USER_GROUP_PATTERN);
private final String expression;
public ValidationConstraints_IllegalCharactersTest(String expression) {
this.expression = expression;
}
@Parameterized.Parameters(name = "{0}")
public static Collection<String[]> createParameters() {
return Stream.concat(IntStream.range(0x20, 0x2f).mapToObj(i -> (char) i), // chars before '0'
Stream.concat(IntStream.range(0x3a, 0x40).mapToObj(i -> (char) i), // chars between '9' and 'A'
Stream.concat(IntStream.range(0x5b, 0x60).mapToObj(i -> (char) i), // chars between 'Z' and 'a'
IntStream.range(0x7b, 0xff).mapToObj(i -> (char) i)))) // chars after 'z'
.filter(c -> !ACCEPTED_CHARS.contains(c))
.flatMap(c -> Stream.of("abc" + c + "xyz", "@" + c, c + "tail"))
.map(c -> new String[] {c})
.collect(Collectors.toList());
}
@Test
public void shouldNotAcceptSpecialCharacters() {
assertFalse(userGroupPattern.matcher(expression).matches());
}
}

View File

@@ -224,6 +224,64 @@ public class GroupRootResourceTest {
assertEquals("user1", createdGroup.getMembers().get(0));
}
@Test
public void shouldGet400OnCreatingNewGroupWithNotAllowedCharacters() throws URISyntaxException {
// the @ character at the begin of the name is not allowed
String groupJson = "{ \"name\": \"@grpname\", \"type\": \"admin\" }";
MockHttpRequest request = MockHttpRequest
.post("/" + GroupRootResource.GROUPS_PATH_V2)
.contentType(VndMediaType.GROUP)
.content(groupJson.getBytes());
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
// the whitespace at the begin of the name is not allowed
groupJson = "{ \"name\": \" grpname\", \"type\": \"admin\" }";
request = MockHttpRequest
.post("/" + GroupRootResource.GROUPS_PATH_V2)
.contentType(VndMediaType.GROUP)
.content(groupJson.getBytes());
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
// the characters {[ are not allowed
groupJson = "{ \"name\": \"grp{name}\", \"type\": \"admin\" }";
request = MockHttpRequest
.post("/" + GroupRootResource.GROUPS_PATH_V2)
.contentType(VndMediaType.GROUP)
.content(groupJson.getBytes());
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
groupJson = "{ \"name\": \"grp[name]\", \"type\": \"admin\" }";
request = MockHttpRequest
.post("/" + GroupRootResource.GROUPS_PATH_V2)
.contentType(VndMediaType.GROUP)
.content(groupJson.getBytes());
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
groupJson = "{ \"name\": \"grp/name\", \"type\": \"admin\" }";
request = MockHttpRequest
.post("/" + GroupRootResource.GROUPS_PATH_V2)
.contentType(VndMediaType.GROUP)
.content(groupJson.getBytes());
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
}
@Test
public void shouldFailForMissingContent() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest

View File

@@ -0,0 +1,115 @@
package sonia.scm.api.v2.resources;
import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import sonia.scm.SCMContextProvider;
import java.net.URI;
import java.util.Optional;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@SubjectAware(configuration = "classpath:sonia/scm/shiro-001.ini")
public class IndexResourceTest {
@Rule
public final ShiroRule shiroRule = new ShiroRule();
private final SCMContextProvider scmContextProvider = mock(SCMContextProvider.class);
private final IndexDtoGenerator indexDtoGenerator = new IndexDtoGenerator(ResourceLinksMock.createMock(URI.create("/")), scmContextProvider);
private final IndexResource indexResource = new IndexResource(indexDtoGenerator);
@Test
public void shouldRenderLoginUrlsForUnauthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("login")).matches(Optional::isPresent);
}
@Test
public void shouldRenderSelfLinkForUnauthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("self")).matches(Optional::isPresent);
}
@Test
public void shouldRenderUiPluginsLinkForUnauthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("uiPlugins")).matches(Optional::isPresent);
}
@Test
@SubjectAware(username = "trillian", password = "secret")
public void shouldRenderSelfLinkForAuthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("self")).matches(Optional::isPresent);
}
@Test
@SubjectAware(username = "trillian", password = "secret")
public void shouldRenderUiPluginsLinkForAuthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("uiPlugins")).matches(Optional::isPresent);
}
@Test
@SubjectAware(username = "trillian", password = "secret")
public void shouldRenderMeUrlForAuthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("me")).matches(Optional::isPresent);
}
@Test
@SubjectAware(username = "trillian", password = "secret")
public void shouldRenderLogoutUrlForAuthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("logout")).matches(Optional::isPresent);
}
@Test
@SubjectAware(username = "trillian", password = "secret")
public void shouldRenderRepositoriesForAuthenticatedRequest() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("repositories")).matches(Optional::isPresent);
}
@Test
@SubjectAware(username = "trillian", password = "secret")
public void shouldNotRenderAdminLinksIfNotAuthorized() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("users")).matches(o -> !o.isPresent());
Assertions.assertThat(index.getLinks().getLinkBy("groups")).matches(o -> !o.isPresent());
Assertions.assertThat(index.getLinks().getLinkBy("config")).matches(o -> !o.isPresent());
}
@Test
@SubjectAware(username = "dent", password = "secret")
public void shouldRenderAdminLinksIfAuthorized() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("users")).matches(Optional::isPresent);
Assertions.assertThat(index.getLinks().getLinkBy("groups")).matches(Optional::isPresent);
Assertions.assertThat(index.getLinks().getLinkBy("config")).matches(Optional::isPresent);
}
@Test
public void shouldGenerateVersion() {
when(scmContextProvider.getVersion()).thenReturn("v1");
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getVersion()).isEqualTo("v1");
}
}

View File

@@ -48,6 +48,7 @@ import java.util.stream.Stream;
import static de.otto.edison.hal.Link.link;
import static de.otto.edison.hal.Links.linkingTo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import static org.mockito.Matchers.any;
@@ -233,6 +234,35 @@ public class PermissionRootResourceTest extends RepositoryTestBase {
);
}
@Test
public void shouldGet400OnCreatingNewPermissionWithNotAllowedCharacters() throws URISyntaxException {
// the @ character at the begin of the name is not allowed
createUserWithRepository("user");
String permissionJson = "{ \"name\": \"@permission\", \"type\": \"OWNER\" }";
MockHttpRequest request = MockHttpRequest
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS)
.content(permissionJson.getBytes())
.contentType(VndMediaType.PERMISSION);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
// the whitespace at the begin opf the name is not allowed
permissionJson = "{ \"name\": \" permission\", \"type\": \"OWNER\" }";
request = MockHttpRequest
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + PATH_OF_ALL_PERMISSIONS)
.content(permissionJson.getBytes())
.contentType(VndMediaType.PERMISSION);
response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
}
@Test
public void shouldGetCreatedPermissions() throws URISyntaxException {
createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE);

View File

@@ -34,6 +34,8 @@ public class ResourceLinksMock {
when(resourceLinks.repositoryTypeCollection()).thenReturn(new ResourceLinks.RepositoryTypeCollectionLinks(uriInfo));
when(resourceLinks.uiPluginCollection()).thenReturn(new ResourceLinks.UIPluginCollectionLinks(uriInfo));
when(resourceLinks.uiPlugin()).thenReturn(new ResourceLinks.UIPluginLinks(uriInfo));
when(resourceLinks.authentication()).thenReturn(new ResourceLinks.AuthenticationLinks(uriInfo));
when(resourceLinks.index()).thenReturn(new ResourceLinks.IndexLinks(uriInfo));
return resourceLinks;
}

View File

@@ -98,6 +98,32 @@ public class UserRootResourceTest {
assertTrue(response.getContentAsString().contains("\"delete\":{\"href\":\"/v2/users/Neo\"}"));
}
@Test
public void shouldGet400OnCreatingNewUserWithNotAllowedCharacters() throws URISyntaxException {
// the @ character at the begin of the name is not allowed
String userJson = "{ \"name\": \"@user\", \"type\": \"db\" }";
MockHttpRequest request = MockHttpRequest
.post("/" + UserRootResource.USERS_PATH_V2)
.contentType(VndMediaType.USER)
.content(userJson.getBytes());
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
// the whitespace at the begin opf the name is not allowed
userJson = "{ \"name\": \" user\", \"type\": \"db\" }";
request = MockHttpRequest
.post("/" + UserRootResource.USERS_PATH_V2)
.contentType(VndMediaType.USER)
.content(userJson.getBytes());
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
}
@Test
@SubjectAware(username = "unpriv")
public void shouldCreateLimitedResponseForSimpleUser() throws URISyntaxException {

View File

@@ -37,6 +37,7 @@ package sonia.scm.it;
import com.sun.jersey.api.client.ClientResponse;
import de.otto.edison.hal.HalRepresentation;
import org.junit.Assume;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import sonia.scm.api.rest.ObjectMapperProvider;
@@ -158,6 +159,7 @@ public class UserPermissionITCase extends AbstractPermissionITCaseBase<User>
@Override
protected void checkGetAllResponse(ClientResponse response)
{
Assume.assumeTrue(credentials.getUsername() == null);
if (!credentials.isAnonymous())
{
assertNotNull(response);

View File

@@ -57,6 +57,7 @@ import sonia.scm.repository.RepositoryTestData;
import sonia.scm.user.User;
import sonia.scm.user.UserTestData;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.nullValue;
@@ -160,7 +161,8 @@ public class DefaultAuthorizationCollectorTest {
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.contains(Role.USER));
assertThat(authInfo.getStringPermissions(), hasSize(0));
assertThat(authInfo.getStringPermissions(), hasSize(1));
assertThat(authInfo.getStringPermissions(), contains("user:read:trillian"));
assertThat(authInfo.getObjectPermissions(), nullValue());
}
@@ -207,7 +209,7 @@ public class DefaultAuthorizationCollectorTest {
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("repository:read,pull:one", "repository:read,pull,push:two"));
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("repository:read,pull:one", "repository:read,pull,push:two", "user:read:trillian"));
}
/**
@@ -228,7 +230,7 @@ public class DefaultAuthorizationCollectorTest {
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("one:one", "two:two"));
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("one:one", "two:two", "user:read:trillian"));
}
private void authenticate(User user, String group, String... groups) {