add RbacUser* tests and improved http status codes
This commit is contained in:
@ -159,7 +159,7 @@ class CustomerRepositoryIntegrationTest {
|
||||
// then
|
||||
attempt.assertExceptionWithRootCauseMessage(
|
||||
JpaSystemException.class,
|
||||
"user admin@aaa.example.com .* has no permission to assume role package#aab00#admin");
|
||||
"[403] user admin@aaa.example.com", "has no permission to assume role package#aab00#admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.test.Array;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -29,7 +30,7 @@ class RbacRoleRepositoryIntegrationTest {
|
||||
@Nested
|
||||
class FindAllRbacRoles {
|
||||
|
||||
private static final String[] ALL_TEST_DATA_ROLES = new String[] {
|
||||
private static final String[] ALL_TEST_DATA_ROLES = Array.of(
|
||||
// @formatter:off
|
||||
"global#hostsharing.admin",
|
||||
"customer#aaa.admin", "customer#aaa.owner", "customer#aaa.tenant",
|
||||
@ -45,7 +46,7 @@ class RbacRoleRepositoryIntegrationTest {
|
||||
"package#aac01.admin", "package#aac01.owner", "package#aac01.tenant",
|
||||
"package#aac02.admin", "package#aac02.owner", "package#aac02.tenant"
|
||||
// @formatter:on
|
||||
};
|
||||
);
|
||||
|
||||
@Test
|
||||
public void hostsharingAdmin_withoutAssumedRole_canViewAllRbacRoles() {
|
||||
@ -116,7 +117,7 @@ class RbacRoleRepositoryIntegrationTest {
|
||||
// then
|
||||
attempt.assertExceptionWithRootCauseMessage(
|
||||
JpaSystemException.class,
|
||||
"user admin@aaa.example.com .* has no permission to assume role package#aab00#admin");
|
||||
"[403] user admin@aaa.example.com", "has no permission to assume role package#aab00#admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -159,11 +160,10 @@ class RbacRoleRepositoryIntegrationTest {
|
||||
assertThat(context.getAssumedRoles()).as("precondition").containsExactly(assumedRoles.split(";"));
|
||||
}
|
||||
|
||||
void exactlyTheseRbacRolesAreReturned(final Iterable<RbacRoleEntity> actualResult, final String... rbacRoleNames) {
|
||||
void exactlyTheseRbacRolesAreReturned(final Iterable<RbacRoleEntity> actualResult, final String... expectedRoleNames) {
|
||||
assertThat(actualResult)
|
||||
//.hasSize(rbacRoleNames.length)
|
||||
.extracting(RbacRoleEntity::getRoleName)
|
||||
.containsExactlyInAnyOrder(rbacRoleNames);
|
||||
.containsExactlyInAnyOrder(expectedRoleNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static net.hostsharing.hsadminng.rbac.rbacrole.TestRbacRole.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacuser.TestRbacUser.userAaa;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacuser.TestRbacUser.userBbb;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest(RbacUserController.class)
|
||||
class RbacUserControllerRestTest {
|
||||
|
||||
@Autowired
|
||||
MockMvc mockMvc;
|
||||
@MockBean
|
||||
Context contextMock;
|
||||
@MockBean
|
||||
RbacUserRepository rbacUserRepository;
|
||||
|
||||
@Test
|
||||
void willListAllUsers() throws Exception {
|
||||
|
||||
// given
|
||||
when(rbacUserRepository.findByOptionalNameLike(null)).thenReturn(
|
||||
List.of(userAaa, userBbb));
|
||||
|
||||
// when
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.get("/api/rbacusers")
|
||||
.header("current-user", "mike@hostsharing.net")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
|
||||
// then
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(2)))
|
||||
.andExpect(jsonPath("$[0].name", is(userAaa.getName())))
|
||||
.andExpect(jsonPath("$[1].name", is(userBbb.getName())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void willListUsersByName() throws Exception {
|
||||
|
||||
// given
|
||||
when(rbacUserRepository.findByOptionalNameLike("admin@aaa")).thenReturn(
|
||||
List.of(userAaa));
|
||||
|
||||
// when
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.get("/api/rbacusers")
|
||||
.param("name", "admin@aaa")
|
||||
.header("current-user", "mike@hostsharing.net")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
|
||||
// then
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(1)))
|
||||
.andExpect(jsonPath("$[0].name", is(userAaa.getName())));
|
||||
}
|
||||
}
|
@ -0,0 +1,315 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.test.Array;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.List;
|
||||
|
||||
import static net.hostsharing.test.JpaAttempt.attempt;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DataJpaTest
|
||||
@ComponentScan(basePackageClasses = { Context.class, RbacUserRepository.class })
|
||||
class RbacUserRepositoryIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
Context context;
|
||||
|
||||
@Autowired
|
||||
RbacUserRepository rbacUserRepository;
|
||||
|
||||
@Autowired EntityManager em;
|
||||
|
||||
@Nested
|
||||
class FindByOptionalNameLike {
|
||||
|
||||
private static final String[] ALL_TEST_DATA_USERS = Array.of(
|
||||
// @formatter:off
|
||||
"mike@hostsharing.net", "sven@hostsharing.net",
|
||||
"admin@aaa.example.com",
|
||||
"aaa00@aaa.example.com", "aaa01@aaa.example.com", "aaa02@aaa.example.com",
|
||||
"admin@aab.example.com",
|
||||
"aab00@aab.example.com", "aab01@aab.example.com", "aab02@aab.example.com",
|
||||
"admin@aac.example.com",
|
||||
"aac00@aac.example.com", "aac01@aac.example.com", "aac02@aac.example.com"
|
||||
// @formatter:on
|
||||
);
|
||||
|
||||
@Test
|
||||
public void hostsharingAdmin_withoutAssumedRole_canViewAllRbacUsers() {
|
||||
// given
|
||||
currentUser("mike@hostsharing.net");
|
||||
|
||||
// when
|
||||
final var result = rbacUserRepository.findByOptionalNameLike(null);
|
||||
|
||||
// then
|
||||
exactlyTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostsharingAdmin_withAssumedHostsharingAdminRole_canViewAllRbacUsers() {
|
||||
given:
|
||||
currentUser("mike@hostsharing.net");
|
||||
assumedRoles("global#hostsharing.admin");
|
||||
|
||||
// when
|
||||
final var result = rbacUserRepository.findByOptionalNameLike(null);
|
||||
|
||||
then:
|
||||
exactlyTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostsharingAdmin_withAssumedCustomerAdminRole_canViewOnlyUsersHavingRolesInThatCustomersRealm() {
|
||||
given:
|
||||
currentUser("mike@hostsharing.net");
|
||||
assumedRoles("customer#aaa.admin");
|
||||
|
||||
// when
|
||||
final var result = rbacUserRepository.findByOptionalNameLike(null);
|
||||
|
||||
then:
|
||||
exactlyTheseRbacUsersAreReturned(
|
||||
result,
|
||||
"admin@aaa.example.com",
|
||||
"aaa00@aaa.example.com", "aaa01@aaa.example.com", "aaa02@aaa.example.com"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerAdmin_withoutAssumedRole_canViewOnlyUsersHavingRolesInThatCustomersRealm() {
|
||||
// given:
|
||||
currentUser("admin@aaa.example.com");
|
||||
|
||||
// when:
|
||||
final var result = rbacUserRepository.findByOptionalNameLike(null);
|
||||
|
||||
// then:
|
||||
exactlyTheseRbacUsersAreReturned(
|
||||
result,
|
||||
"admin@aaa.example.com",
|
||||
"aaa00@aaa.example.com", "aaa01@aaa.example.com", "aaa02@aaa.example.com"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyUsersHavingRolesInThatPackage() {
|
||||
currentUser("admin@aaa.example.com");
|
||||
assumedRoles("package#aaa00.admin");
|
||||
|
||||
final var result = rbacUserRepository.findByOptionalNameLike(null);
|
||||
|
||||
exactlyTheseRbacUsersAreReturned(result, "aaa00@aaa.example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageAdmin_withoutAssumedRole_canViewOnlyUsersHavingRolesInThatPackage() {
|
||||
currentUser("aaa00@aaa.example.com");
|
||||
|
||||
final var result = rbacUserRepository.findByOptionalNameLike(null);
|
||||
|
||||
exactlyTheseRbacUsersAreReturned(result, "aaa00@aaa.example.com");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class ListUserPermissions {
|
||||
|
||||
private static final String[] ALL_USER_PERMISSIONS = Array.of(
|
||||
// @formatter:off
|
||||
"global#hostsharing.admin -> global#hostsharing: add-customer",
|
||||
|
||||
"customer#aaa.admin -> customer#aaa: add-package",
|
||||
"customer#aaa.admin -> customer#aaa: view",
|
||||
"customer#aaa.owner -> customer#aaa: *",
|
||||
"customer#aaa.tenant -> customer#aaa: view",
|
||||
"package#aaa00.admin -> package#aaa00: add-domain",
|
||||
"package#aaa00.admin -> package#aaa00: add-unixuser",
|
||||
"package#aaa00.tenant -> package#aaa00: view",
|
||||
"package#aaa01.admin -> package#aaa01: add-domain",
|
||||
"package#aaa01.admin -> package#aaa01: add-unixuser",
|
||||
"package#aaa01.tenant -> package#aaa01: view",
|
||||
"package#aaa02.admin -> package#aaa02: add-domain",
|
||||
"package#aaa02.admin -> package#aaa02: add-unixuser",
|
||||
"package#aaa02.tenant -> package#aaa02: view",
|
||||
|
||||
"customer#aab.admin -> customer#aab: add-package",
|
||||
"customer#aab.admin -> customer#aab: view",
|
||||
"customer#aab.owner -> customer#aab: *",
|
||||
"customer#aab.tenant -> customer#aab: view",
|
||||
"package#aab00.admin -> package#aab00: add-domain",
|
||||
"package#aab00.admin -> package#aab00: add-unixuser",
|
||||
"package#aab00.tenant -> package#aab00: view",
|
||||
"package#aab01.admin -> package#aab01: add-domain",
|
||||
"package#aab01.admin -> package#aab01: add-unixuser",
|
||||
"package#aab01.tenant -> package#aab01: view",
|
||||
"package#aab02.admin -> package#aab02: add-domain",
|
||||
"package#aab02.admin -> package#aab02: add-unixuser",
|
||||
"package#aab02.tenant -> package#aab02: view",
|
||||
|
||||
"customer#aac.admin -> customer#aac: add-package",
|
||||
"customer#aac.admin -> customer#aac: view",
|
||||
"customer#aac.owner -> customer#aac: *",
|
||||
"customer#aac.tenant -> customer#aac: view",
|
||||
"package#aac00.admin -> package#aac00: add-domain",
|
||||
"package#aac00.admin -> package#aac00: add-unixuser",
|
||||
"package#aac00.tenant -> package#aac00: view",
|
||||
"package#aac01.admin -> package#aac01: add-domain",
|
||||
"package#aac01.admin -> package#aac01: add-unixuser",
|
||||
"package#aac01.tenant -> package#aac01: view",
|
||||
"package#aac02.admin -> package#aac02: add-domain",
|
||||
"package#aac02.admin -> package#aac02: add-unixuser",
|
||||
"package#aac02.tenant -> package#aac02: view"
|
||||
// @formatter:on
|
||||
);
|
||||
|
||||
@Test
|
||||
public void hostsharingAdmin_withoutAssumedRole_canViewTheirOwnPermissions() {
|
||||
// given
|
||||
currentUser("mike@hostsharing.net");
|
||||
|
||||
// when
|
||||
final var result = rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net");
|
||||
|
||||
// then
|
||||
exactlyTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostsharingAdmin_withAssumedHostmastersRole_willThrowException() {
|
||||
// given
|
||||
currentUser("mike@hostsharing.net");
|
||||
assumedRoles("global#hostsharing.admin");
|
||||
|
||||
// when
|
||||
final var result = attempt(em, () ->
|
||||
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
|
||||
);
|
||||
|
||||
// then
|
||||
result.assertExceptionWithRootCauseMessage(
|
||||
JpaSystemException.class,
|
||||
"[400] grantedPermissions(...) does not support assumed roles");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerAdmin_withoutAssumedRole_canViewTheirOwnPermissions() {
|
||||
// given
|
||||
currentUser("admin@aaa.example.com");
|
||||
|
||||
// when
|
||||
final var result = rbacUserRepository.findPermissionsOfUser("admin@aaa.example.com");
|
||||
|
||||
// then
|
||||
exactlyTheseRbacPermissionsAreReturned(result,
|
||||
// @formatter:off
|
||||
"customer#aaa.admin -> customer#aaa: add-package",
|
||||
"customer#aaa.admin -> customer#aaa: view",
|
||||
"customer#aaa.tenant -> customer#aaa: view",
|
||||
|
||||
"package#aaa00.admin -> package#aaa00: add-domain",
|
||||
"package#aaa00.admin -> package#aaa00: add-unixuser",
|
||||
"package#aaa00.tenant -> package#aaa00: view",
|
||||
|
||||
"package#aaa01.admin -> package#aaa01: add-domain",
|
||||
"package#aaa01.admin -> package#aaa01: add-unixuser",
|
||||
"package#aaa01.tenant -> package#aaa01: view",
|
||||
|
||||
"package#aaa02.admin -> package#aaa02: add-domain",
|
||||
"package#aaa02.admin -> package#aaa02: add-unixuser",
|
||||
"package#aaa02.tenant -> package#aaa02: view"
|
||||
// @formatter:on
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerAdmin_withoutAssumedRole_isNotAllowedToViewGlobalAdminsPermissions() {
|
||||
// given
|
||||
currentUser("admin@aaa.example.com");
|
||||
|
||||
// when
|
||||
final var result = attempt(em, () ->
|
||||
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
|
||||
);
|
||||
|
||||
// then
|
||||
result.assertExceptionWithRootCauseMessage(
|
||||
JpaSystemException.class,
|
||||
"[403] permissions of user \"mike@hostsharing.net\" are not accessible to user \"admin@aaa.example.com\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerAdmin_withoutAssumedRole_canViewAllPermissionsWithinThePacketsRealm() {
|
||||
// given
|
||||
currentUser("admin@aaa.example.com");
|
||||
|
||||
// when
|
||||
final var result = rbacUserRepository.findPermissionsOfUser("aaa00@aaa.example.com");
|
||||
|
||||
// then
|
||||
exactlyTheseRbacPermissionsAreReturned(result,
|
||||
// @formatter:off
|
||||
"customer#aaa.tenant -> customer#aaa: view",
|
||||
// "customer#aaa.admin -> customer#aaa: view" - Not permissions through the customer admin!
|
||||
"package#aaa00.admin -> package#aaa00: add-unixuser",
|
||||
"package#aaa00.admin -> package#aaa00: add-domain",
|
||||
"package#aaa00.tenant -> package#aaa00: view"
|
||||
// @formatter:on
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packetAdmin_withoutAssumedRole_canViewAllPermissionsWithinThePacketsRealm() {
|
||||
// given
|
||||
currentUser("aaa00@aaa.example.com");
|
||||
|
||||
// when
|
||||
final var result = rbacUserRepository.findPermissionsOfUser("aaa00@aaa.example.com");
|
||||
|
||||
// then
|
||||
exactlyTheseRbacPermissionsAreReturned(result,
|
||||
// @formatter:off
|
||||
"customer#aaa.tenant -> customer#aaa: view",
|
||||
// "customer#aaa.admin -> customer#aaa: view" - Not permissions through the customer admin!
|
||||
"package#aaa00.admin -> package#aaa00: add-unixuser",
|
||||
"package#aaa00.admin -> package#aaa00: add-domain",
|
||||
"package#aaa00.tenant -> package#aaa00: view"
|
||||
// @formatter:on
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void currentUser(final String currentUser) {
|
||||
context.setCurrentUser(currentUser);
|
||||
assertThat(context.getCurrentUser()).as("precondition").isEqualTo(currentUser);
|
||||
}
|
||||
|
||||
void assumedRoles(final String assumedRoles) {
|
||||
context.assumeRoles(assumedRoles);
|
||||
assertThat(context.getAssumedRoles()).as("precondition").containsExactly(assumedRoles.split(";"));
|
||||
}
|
||||
|
||||
void exactlyTheseRbacUsersAreReturned(final List<RbacUserEntity> actualResult, final String... expectedUserNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(RbacUserEntity::getName)
|
||||
.containsExactlyInAnyOrder(expectedUserNames);
|
||||
}
|
||||
|
||||
void exactlyTheseRbacPermissionsAreReturned(
|
||||
final List<RbacUserPermission> actualResult,
|
||||
final String... expectedRoleNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
|
||||
.containsExactlyInAnyOrder(expectedRoleNames);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
|
||||
|
||||
import static java.util.UUID.randomUUID;
|
||||
|
||||
public class TestRbacUser {
|
||||
|
||||
static final RbacUserEntity userAaa = rbacRole("admin@aaa.example.com");
|
||||
static final RbacUserEntity userBbb = rbacRole("admin@bbb.example.com");
|
||||
|
||||
static public RbacUserEntity rbacRole(final String userName) {
|
||||
return new RbacUserEntity(randomUUID(), userName);
|
||||
}
|
||||
}
|
13
src/test/java/net/hostsharing/test/Array.java
Normal file
13
src/test/java/net/hostsharing/test/Array.java
Normal file
@ -0,0 +1,13 @@
|
||||
package net.hostsharing.test;
|
||||
|
||||
/**
|
||||
* Java has List.of(...), Set.of(...) and Map.of(...) all with varargs parameter,
|
||||
* but no Array.of(...). Here it is.
|
||||
*/
|
||||
public class Array {
|
||||
|
||||
@SafeVarargs
|
||||
public static <E> E[] of(E... elements) {
|
||||
return elements;
|
||||
}
|
||||
}
|
@ -71,9 +71,11 @@ public class JpaAttempt<T> {
|
||||
|
||||
public void assertExceptionWithRootCauseMessage(
|
||||
final Class<? extends RuntimeException> expectedExceptionClass,
|
||||
final String expectedRootCauseMessage) {
|
||||
assertThat(
|
||||
firstRootCauseMessageLineOf(caughtException(expectedExceptionClass)))
|
||||
.matches(".*" + expectedRootCauseMessage + ".*");
|
||||
final String... expectedRootCauseMessages) {
|
||||
assertThat(wasSuccessful()).isFalse();
|
||||
final String firstRootCauseMessageLine = firstRootCauseMessageLineOf(caughtException(expectedExceptionClass));
|
||||
for ( String expectedRootCauseMessage: expectedRootCauseMessages ) {
|
||||
assertThat(firstRootCauseMessageLine).contains(expectedRootCauseMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user