1
0

improve test code coverage

This commit is contained in:
Michael Hoennig
2022-08-25 17:27:17 +02:00
parent 2531b9071f
commit 1a18ba4a3d
16 changed files with 485 additions and 107 deletions

View File

@@ -141,6 +141,36 @@ class CustomerControllerAcceptanceTest {
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("vvv"));
}
@Test
void hostsharingAdmin_withAssumedCustomerAdminRole_canNotCreateCustomer() throws Exception {
RestAssured // @formatter:off
.given()
.header("current-user", "mike@hostsharing.net")
.header("assumed-roles", "customer#xxx.admin")
.contentType(ContentType.JSON)
.body("""
{
"reference": 90010,
"prefix": "uuu",
"adminUserName": "customer-admin@uuu.example.com"
}
""")
.port(port)
.when()
.post("http://localhost/api/customers")
.then().assertThat()
.statusCode(403)
.contentType(ContentType.JSON)
.statusCode(403)
.body("message", containsString("add-customer not permitted for customer#xxx.admin"));
// @formatter:on
// finally, the new customer was not created
context.setCurrentUser("sven@hostsharing.net");
assertThat(customerRepository.findCustomerByOptionalPrefixLike("uuu")).hasSize(0);
}
@Test
void customerAdmin_withoutAssumedRole_canNotCreateCustomer() throws Exception {

View File

@@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.*;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
@@ -55,6 +56,108 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
@Autowired
JpaAttempt jpaAttempt;
@Nested
class ListGrants {
@Test
@Accepts("GRT:L(List)")
void hostsharingAdmin_withoutAssumedRole_canViewAllGrants() {
RestAssured // @formatter:off
.given()
.header("current-user", "mike@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/rbac-grants")
.then().log().all().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "global#hostsharing.admin"),
hasEntry("grantedRoleIdName", "customer#xxx.admin"),
hasEntry("granteeUserName", "customer-admin@xxx.example.com")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "global#hostsharing.admin"),
hasEntry("grantedRoleIdName", "customer#yyy.admin"),
hasEntry("granteeUserName", "customer-admin@yyy.example.com")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "global#hostsharing.admin"),
hasEntry("grantedRoleIdName", "global#hostsharing.admin"),
hasEntry("granteeUserName", "sven@hostsharing.net")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "customer#xxx.admin"),
hasEntry("grantedRoleIdName", "package#xxx00.admin"),
hasEntry("granteeUserName", "pac-admin-xxx00@xxx.example.com")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "customer#zzz.admin"),
hasEntry("grantedRoleIdName", "package#zzz02.admin"),
hasEntry("granteeUserName", "pac-admin-zzz02@zzz.example.com")
)
))
.body("size()", greaterThanOrEqualTo(14));
// @formatter:on
}
@Test
@Accepts({ "GRT:L(List)", "GRT:X(Access Control)" })
void hostsharingAdmin_withAssumedPackageAdminRole_canViewPacketRelatedGrants() {
RestAssured // @formatter:off
.given()
.header("current-user", "mike@hostsharing.net")
.header("assumed-roles", "package#yyy00.admin")
.port(port)
.when()
.get("http://localhost/api/rbac-grants")
.then().log().all().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "customer#yyy.admin"),
hasEntry("grantedRoleIdName", "package#yyy00.admin"),
hasEntry("granteeUserName", "pac-admin-yyy00@yyy.example.com")
)
))
.body("size()", is(1));
// @formatter:on
}
@Test
@Accepts({ "GRT:L(List)", "GRT:X(Access Control)" })
void packageAdmin_withoutAssumedRole_canViewPacketRelatedGrants() {
RestAssured // @formatter:off
.given()
.header("current-user", "pac-admin-yyy00@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac-grants")
.then().log().all().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "customer#yyy.admin"),
hasEntry("grantedRoleIdName", "package#yyy00.admin"),
hasEntry("granteeUserName", "pac-admin-yyy00@yyy.example.com")
)
))
.body("size()", is(1));
// @formatter:on
}
}
@Nested
class GetGrantById {

View File

@@ -2,8 +2,10 @@ package net.hostsharing.hsadminng.rbac.rbacuser;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.Accepts;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,7 +21,7 @@ import static org.hamcrest.Matchers.*;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class
classes = { HsadminNgApplication.class, JpaAttempt.class }
)
@Transactional
class RbacUserControllerAcceptanceTest {
@@ -30,6 +32,9 @@ class RbacUserControllerAcceptanceTest {
@Autowired
EntityManager em;
@Autowired
JpaAttempt jpaAttempt;
@Autowired
Context context;
@@ -37,9 +42,125 @@ class RbacUserControllerAcceptanceTest {
RbacUserRepository rbacUserRepository;
@Nested
class ApiRbacUsersGet {
class CreateRbacUser {
@Test
@Accepts({ "USR:C(Create)", "USR:X(Access Control)" })
void anybody_canCreateANewUser() {
// @formatter:off
final var location = RestAssured
.given()
.contentType(ContentType.JSON)
.body("""
{
"name": "new-user@example.com"
}
""")
.port(port)
.when()
.post("http://localhost/api/rbac-users")
.then().assertThat()
.statusCode(201)
.contentType(ContentType.JSON)
.body("name", is("new-user@example.com"))
.header("Location", startsWith("http://localhost"))
.extract().header("Location");
// @formatter:on
// finally, the user can view its own record
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.setCurrentUser("new-user@example.com");
assertThat(rbacUserRepository.findByUuid(newUserUuid))
.extracting(RbacUserEntity::getName).isEqualTo("new-user@example.com");
}
}
@Nested
class GetRbacUser {
@Test
@Accepts({ "USR:R(Read)" })
void hostsharingAdmin_withoutAssumedRole_canGetArbitraryUser() {
final var givenUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
// @formatter:off
RestAssured
.given()
.header("current-user", "mike@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/rbac-users/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("name", is("pac-admin-xxx00@xxx.example.com"));
// @formatter:on
}
@Test
@Accepts({ "USR:R(Read)", "USR:X(Access Control)" })
void hostsharingAdmin_withAssumedCustomerAdminRole_canGetUserWithinInItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
.given()
.header("current-user", "mike@hostsharing.net")
.header("assumed-roles", "customer#yyy.admin")
.port(port)
.when()
.get("http://localhost/api/rbac-users/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("name", is("pac-admin-yyy00@yyy.example.com"));
// @formatter:on
}
@Test
@Accepts({ "USR:R(Read)", "USR:X(Access Control)" })
void customerAdmin_withoutAssumedRole_canGetUserWithinInItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
.given()
.header("current-user", "customer-admin@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac-users/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("name", is("pac-admin-yyy00@yyy.example.com"));
// @formatter:on
}
@Test
@Accepts({ "USR:R(Read)", "USR:X(Access Control)" })
void customerAdmin_withoutAssumedRole_canNotGetUserOutsideOfItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
.given()
.header("current-user", "customer-admin@xxx.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac-users/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(404);
// @formatter:on
}
}
@Nested
class ListRbacUsers {
@Test
@Accepts({ "USR:L(List)" })
void hostsharingAdmin_withoutAssumedRole_canViewAllUsers() {
// @formatter:off
@@ -65,6 +186,7 @@ class RbacUserControllerAcceptanceTest {
}
@Test
@Accepts({ "USR:F(Filter)" })
void hostsharingAdmin_withoutAssumedRole_canViewAllUsersByName() {
// @formatter:off
@@ -85,6 +207,30 @@ class RbacUserControllerAcceptanceTest {
}
@Test
@Accepts({ "USR:L(List)", "USR:X(Access Control)" })
void hostsharingAdmin_withAssumedCustomerAdminRole_canViewUsersInItsRealm() {
// @formatter:off
RestAssured
.given()
.header("current-user", "mike@hostsharing.net")
.header("assumed-roles", "customer#yyy.admin")
.port(port)
.when()
.get("http://localhost/api/rbac-users")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
.body("[0].name", is("customer-admin@yyy.example.com"))
.body("[1].name", is("pac-admin-yyy00@yyy.example.com"))
.body("[2].name", is("pac-admin-yyy01@yyy.example.com"))
.body("[3].name", is("pac-admin-yyy02@yyy.example.com"))
.body("size()", is(4));
// @formatter:on
}
@Test
@Accepts({ "USR:L(List)", "USR:X(Access Control)" })
void customerAdmin_withoutAssumedRole_canViewUsersInItsRealm() {
// @formatter:off
@@ -106,6 +252,7 @@ class RbacUserControllerAcceptanceTest {
}
@Test
@Accepts({ "USR:L(List)", "USR:X(Access Control)" })
void packetAdmin_withoutAssumedRole_canViewAllUsersOfItsPackage() {
// @formatter:off
@@ -125,37 +272,135 @@ class RbacUserControllerAcceptanceTest {
}
@Nested
class ApiRbacUsersPost {
class ListRbacUserPermissions {
@Test
void anybody_canCreateANewUser() {
@Accepts({ "PRM:L(List)" })
void hostsharingAdmin_withoutAssumedRole_canViewArbitraryUsersPermissions() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
final var location = RestAssured
RestAssured
.given()
.contentType(ContentType.JSON)
.body("""
{
"name": "new-user@example.com"
}
""")
.header("current-user", "mike@hostsharing.net")
.port(port)
.when()
.post("http://localhost/api/rbac-users")
.then().assertThat()
.statusCode(201)
.contentType(ContentType.JSON)
.body("name", is("new-user@example.com"))
.header("Location", startsWith("http://localhost"))
.extract().header("Location");
.get("http://localhost/api/rbac-users/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("roleName", "customer#yyy.tenant"),
hasEntry("op", "view"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "package#yyy00.admin"),
hasEntry("op", "add-unixuser"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "unixuser#yyy00-aaaa.owner"),
hasEntry("op", "*"))
))
.body("size()", is(8));
// @formatter:on
}
// finally, the user can view its own record
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.setCurrentUser("new-user@example.com");
assertThat(rbacUserRepository.findByUuid(newUserUuid))
.extracting(RbacUserEntity::getName).isEqualTo("new-user@example.com");
@Test
@Accepts({ "PRM:L(List)" })
void hostsharingAdmin_withAssumedCustomerAdminRole_canViewArbitraryUsersPermissions() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
.given()
.header("current-user", "mike@hostsharing.net")
.header("assumed-roles", "package#yyy00.admin")
.port(port)
.when()
.get("http://localhost/api/rbac-users/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("roleName", "customer#yyy.tenant"),
hasEntry("op", "view"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "package#yyy00.admin"),
hasEntry("op", "add-unixuser"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "unixuser#yyy00-aaaa.owner"),
hasEntry("op", "*"))
))
.body("size()", is(8));
// @formatter:on
}
@Test
@Accepts({ "PRM:L(List)" })
void packageAdmin_withoutAssumedRole_canViewPermissionsOfUsersInItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
.given()
.header("current-user", "pac-admin-yyy00@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac-users/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("roleName", "customer#yyy.tenant"),
hasEntry("op", "view"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "package#yyy00.admin"),
hasEntry("op", "add-unixuser"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "unixuser#yyy00-aaaa.owner"),
hasEntry("op", "*"))
))
.body("size()", is(8));
// @formatter:on
}
@Test
@Accepts({ "PRM:L(List)" })
void packageAdmin_canViewPermissionsOfUsersOutsideOfItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
// @formatter:off
RestAssured
.given()
.header("current-user", "pac-admin-yyy00@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac-users/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("size()", is(0));
// @formatter:on
}
}
RbacUserEntity findRbacUserByName(final String userName) {
return jpaAttempt.transacted(() -> {
context.setCurrentUser("mike@hostsharing.net");
return rbacUserRepository.findByName(userName);
}).returnedValue();
}
}

View File

@@ -231,35 +231,19 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("mike@hostsharing.net");
// when
final var result = rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net");
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("mike@hostsharing.net"));
// then
allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS);
}
@Test
public void hostsharingAdmin_withAssumedHostmastersRole_willThrowException() {
// given
context("mike@hostsharing.net", "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
context("customer-admin@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUser("customer-admin@xxx.example.com");
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("customer-admin@xxx.example.com"));
// then
allTheseRbacPermissionsAreReturned(
@@ -299,16 +283,18 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
public void customerAdmin_withoutAssumedRole_isNotAllowedToViewGlobalAdminsPermissions() {
// given
context("customer-admin@xxx.example.com");
final UUID userUuid = userUUID("mike@hostsharing.net");
// when
final var result = attempt(em, () ->
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
rbacUserRepository.findPermissionsOfUserByUuid(userUuid)
);
// then
result.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"[403] permissions of user \"mike@hostsharing.net\" are not accessible to user \"customer-admin@xxx.example.com\"");
"[403] permissions of user \"" + userUuid
+ "\" are not accessible to user \"customer-admin@xxx.example.com\"");
}
@Test
@@ -317,7 +303,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUser("pac-admin-xxx00@xxx.example.com");
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("pac-admin-xxx00@xxx.example.com"));
// then
allTheseRbacPermissionsAreReturned(
@@ -353,7 +339,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUser("pac-admin-yyy00@yyy.example.com");
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("pac-admin-yyy00@yyy.example.com"));
// then
noRbacPermissionsAreReturned(result);
@@ -365,7 +351,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("pac-admin-xxx00@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUser("pac-admin-xxx00@xxx.example.com");
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("pac-admin-xxx00@xxx.example.com"));
// then
allTheseRbacPermissionsAreReturned(
@@ -397,6 +383,10 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
}
}
UUID userUUID(final String userName) {
return rbacUserRepository.findByName(userName).getUuid();
}
void exactlyTheseRbacUsersAreReturned(final List<RbacUserEntity> actualResult, final String... expectedUserNames) {
assertThat(actualResult)
.extracting(RbacUserEntity::getName)