align create methods and improve and align acceptance tests

This commit is contained in:
Michael Hoennig 2022-08-25 14:46:05 +02:00
parent 9a7b683e7d
commit 2531b9071f
11 changed files with 324 additions and 235 deletions

View File

@ -28,26 +28,26 @@ public class CustomerController implements CustomersApi {
@Override
@Transactional(readOnly = true)
public ResponseEntity<List<CustomerResource>> listCustomers(
String userName,
String assumedRoles,
String prefix
String userName,
String assumedRoles,
String prefix
) {
context.setCurrentUser(userName);
if (assumedRoles != null && !assumedRoles.isBlank()) {
context.assumeRoles(assumedRoles);
}
return ResponseEntity.ok(
mapList(
customerRepository.findCustomerByOptionalPrefixLike(prefix),
CustomerResource.class));
final var result = customerRepository.findCustomerByOptionalPrefixLike(prefix);
return ResponseEntity.ok(mapList(result, CustomerResource.class));
}
@Override
@Transactional
public ResponseEntity<CustomerResource> addCustomer(
final String currentUser,
final String assumedRoles,
final CustomerResource customer) {
final String currentUser,
final String assumedRoles,
final CustomerResource customer) {
context.setCurrentTask("create new customer: #" + customer.getReference() + " / " + customer.getPrefix());
context.setCurrentUser(currentUser);
@ -61,10 +61,10 @@ public class CustomerController implements CustomersApi {
final var saved = customerRepository.save(map(customer, CustomerEntity.class));
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/rbac-users/{id}")
.buildAndExpand(customer.getUuid())
.toUri();
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/rbac-users/{id}")
.buildAndExpand(customer.getUuid())
.toUri();
return ResponseEntity.created(uri).body(map(saved, CustomerResource.class));
}

View File

@ -9,6 +9,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.UUID;
@ -25,6 +26,9 @@ public class RbacGrantController implements RbacgrantsApi {
@Autowired
private RbacGrantRepository rbacGrantRepository;
@Autowired
private EntityManager em;
@Override
@Transactional(readOnly = true)
public ResponseEntity<RbacGrantResource> getGrantById(
@ -61,7 +65,7 @@ public class RbacGrantController implements RbacgrantsApi {
@Override
@Transactional
public ResponseEntity<Void> grantRoleToUser(
public ResponseEntity<RbacGrantResource> grantRoleToUser(
final String currentUser,
final String assumedRoles,
final RbacGrantResource body) {
@ -72,14 +76,16 @@ public class RbacGrantController implements RbacgrantsApi {
context.assumeRoles(assumedRoles);
}
rbacGrantRepository.save(map(body, RbacGrantEntity.class));
final var granted = rbacGrantRepository.save(map(body, RbacGrantEntity.class));
em.flush();
em.refresh(granted);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/rbac-grants/{roleUuid}")
.buildAndExpand(body.getGrantedRoleUuid())
.toUri();
return ResponseEntity.created(uri).build();
return ResponseEntity.created(uri).body(map(granted, RbacGrantResource.class));
}
@Override
@ -100,5 +106,4 @@ public class RbacGrantController implements RbacgrantsApi {
return ResponseEntity.noContent().build();
}
}

View File

@ -17,7 +17,7 @@ public interface RbacGrantRepository extends Repository<RbacGrantEntity, RbacGra
List<RbacGrantEntity> findAll();
void save(final RbacGrantEntity grant);
RbacGrantEntity save(final RbacGrantEntity grant);
@Modifying
@Query(value = """

View File

@ -32,6 +32,9 @@ post:
"201":
description: OK
content:
'application/json':
schema:
$ref: './api-definition/rbac-grant-schemas.yaml#/components/schemas/RbacGrant'
"401":
$ref: './api-definition/error-responses.yaml#/components/responses/Unauthorized'
"403":

View File

@ -0,0 +1,173 @@
package net.hostsharing.hsadminng.hs.hscustomer;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.*;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class
)
@Transactional
class CustomerControllerAcceptanceTest {
@LocalServerPort
private Integer port;
@Autowired
Context context;
@Autowired
Context contextMock;
@Autowired
CustomerRepository customerRepository;
@Nested
class ListCustomers {
@Test
void hostsharingAdmin_withoutAssumedRoles_canViewAllCustomers_ifNoCriteriaGiven() {
RestAssured // @formatter:off
.given()
.header("current-user", "mike@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/customers")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
.body("[0].prefix", is("xxx"))
.body("[1].prefix", is("yyy"))
.body("[2].prefix", is("zzz"))
.body("size()", greaterThanOrEqualTo(3));
// @formatter:on
}
@Test
void hostsharingAdmin_withoutAssumedRoles_canViewMatchingCustomers_ifCriteriaGiven() throws Exception {
RestAssured // @formatter:off
.given()
.header("current-user", "mike@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/customers?prefix=y")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
.body("[0].prefix", is("yyy"))
.body("size()", is(1));
// @formatter:on
}
@Test
void hostsharingAdmin_withoutAssumedCustomerAdminRole_canOnlyViewOwnCustomer() throws Exception {
RestAssured // @formatter:off
.given()
.header("current-user", "mike@hostsharing.net")
.header("assumed-roles", "customer#yyy.admin")
.port(port)
.when()
.get("http://localhost/api/customers")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
.body("[0].prefix", is("yyy"))
.body("size()", is(1));
// @formatter:on
}
@Test
void customerAdmin_withoutAssumedRole_canOnlyViewOwnCustomer() throws Exception {
RestAssured // @formatter:off
.given()
.header("current-user", "customer-admin@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/customers")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
.body("[0].prefix", is("yyy"))
.body("size()", is(1));
// @formatter:on
}
}
@Nested
class CreateCustomer {
@Test
void hostsharingAdmin_withoutAssumedRole_canCreateCustomer() throws Exception {
final var location = RestAssured // @formatter:off
.given()
.header("current-user", "mike@hostsharing.net")
.contentType(ContentType.JSON)
.body("""
{
"reference": 90010,
"prefix": "vvv",
"adminUserName": "customer-admin@vvv.example.com"
}
""")
.port(port)
.when()
.post("http://localhost/api/customers")
.then().assertThat()
.statusCode(201)
.contentType(ContentType.JSON)
.body("prefix", is("vvv"))
.header("Location", startsWith("http://localhost"))
.extract().header("Location"); // @formatter:on
// finally, the new customer can be viewed by its own admin
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.setCurrentUser("customer-admin@vvv.example.com");
assertThat(customerRepository.findByUuid(newUserUuid))
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("vvv"));
}
@Test
void customerAdmin_withoutAssumedRole_canNotCreateCustomer() throws Exception {
RestAssured // @formatter:off
.given()
.header("current-user", "customer-admin@yyy.example.com")
.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-admin@yyy.example.com"));
// @formatter:on
// finally, the new customer was not created
context.setCurrentUser("sven@hostsharing.net");
assertThat(customerRepository.findCustomerByOptionalPrefixLike("uuu")).hasSize(0);
}
}
}

View File

@ -1,110 +0,0 @@
package net.hostsharing.hsadminng.hs.hscustomer;
import net.hostsharing.hsadminng.context.Context;
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.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 org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(CustomerController.class)
class CustomerControllerRestTest {
@Autowired
MockMvc mockMvc;
@MockBean
Context contextMock;
@MockBean
CustomerRepository customerRepositoryMock;
@Nested
class ListCustomers {
@Test
void listCustomersWillReturnAllCustomersFromRepositoryIfNoCriteriaGiven() throws Exception {
// given
when(customerRepositoryMock.findCustomerByOptionalPrefixLike(null)).thenReturn(List.of(
TestCustomer.xxx,
TestCustomer.yyy));
// when
mockMvc.perform(MockMvcRequestBuilders
.get("/api/customers")
.header("current-user", "mike@hostsharing.net")
.accept(MediaType.APPLICATION_JSON))
// then
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].prefix", is(TestCustomer.xxx.getPrefix())))
.andExpect(jsonPath("$[1].reference", is(TestCustomer.yyy.getReference()))
);
// then
verify(contextMock).setCurrentUser("mike@hostsharing.net");
verify(contextMock, never()).assumeRoles(anyString());
}
@Test
void listCustomersWillReturnMatchingCustomersFromRepositoryIfCriteriaGiven() throws Exception {
// given
when(customerRepositoryMock.findCustomerByOptionalPrefixLike("x")).thenReturn(List.of(TestCustomer.xxx));
// when
mockMvc.perform(MockMvcRequestBuilders
.get("/api/customers")
.header("current-user", "mike@hostsharing.net")
.param("prefix", "x")
.accept(MediaType.APPLICATION_JSON))
// then
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].prefix", is(TestCustomer.xxx.getPrefix()))
);
// then
verify(contextMock).setCurrentUser("mike@hostsharing.net");
verify(contextMock, never()).assumeRoles(anyString());
}
@Test
void listCustomersWillReturnAllCustomersForGivenAssumedRoles() throws Exception {
// given
when(customerRepositoryMock.findCustomerByOptionalPrefixLike(null)).thenReturn(List.of(TestCustomer.yyy));
// when
mockMvc.perform(MockMvcRequestBuilders
.get("/api/customers")
.header("current-user", "mike@hostsharing.net")
.header("assumed-roles", "customer-admin@yyy.example.com")
.accept(MediaType.APPLICATION_JSON))
// then
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].prefix", is(TestCustomer.yyy.getPrefix()))
);
// then
verify(contextMock).setCurrentUser("mike@hostsharing.net");
verify(contextMock).assumeRoles("customer-admin@yyy.example.com");
}
}
}

View File

@ -27,7 +27,8 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
CustomerRepository customerRepository;
@Autowired EntityManager em;
@Autowired
EntityManager em;
@Nested
class CreateCustomer {
@ -42,7 +43,7 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
final var result = attempt(em, () -> {
final var newCustomer = new CustomerEntity(
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
return customerRepository.save(newCustomer);
});
@ -61,14 +62,14 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () -> {
final var newCustomer = new CustomerEntity(
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
return customerRepository.save(newCustomer);
});
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"add-customer not permitted for customer#xxx.admin");
PersistenceException.class,
"add-customer not permitted for customer#xxx.admin");
}
@Test
@ -79,14 +80,14 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () -> {
final var newCustomer = new CustomerEntity(
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
return customerRepository.save(newCustomer);
});
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"add-customer not permitted for customer-admin@xxx.example.com");
PersistenceException.class,
"add-customer not permitted for customer-admin@xxx.example.com");
}
@ -108,7 +109,7 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
final var result = customerRepository.findCustomerByOptionalPrefixLike(null);
// then
exactlyTheseCustomersAreReturned(result, "xxx", "yyy", "zzz");
allTheseCustomersAreReturned(result, "xxx", "yyy", "zzz");
}
@Test
@ -120,7 +121,7 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
final var result = customerRepository.findCustomerByOptionalPrefixLike(null);
then:
exactlyTheseCustomersAreReturned(result, "xxx", "yyy", "zzz");
allTheseCustomersAreReturned(result, "xxx", "yyy", "zzz");
}
@Test
@ -151,13 +152,13 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(
em,
() -> customerRepository.findCustomerByOptionalPrefixLike(null));
em,
() -> customerRepository.findCustomerByOptionalPrefixLike(null));
// then
result.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"[403] user customer-admin@xxx.example.com", "has no permission to assume role package#yyy00#admin");
JpaSystemException.class,
"[403] user customer-admin@xxx.example.com", "has no permission to assume role package#yyy00#admin");
}
@Test
@ -165,12 +166,12 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
context("unknown@example.org", null);
final var result = attempt(
em,
() -> customerRepository.findCustomerByOptionalPrefixLike(null));
em,
() -> customerRepository.findCustomerByOptionalPrefixLike(null));
result.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"hsadminng.currentUser defined as unknown@example.org, but does not exists");
JpaSystemException.class,
"hsadminng.currentUser defined as unknown@example.org, but does not exists");
}
@Test
@ -179,12 +180,12 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
context("unknown@example.org", "customer#xxx.admin");
final var result = attempt(
em,
() -> customerRepository.findCustomerByOptionalPrefixLike(null));
em,
() -> customerRepository.findCustomerByOptionalPrefixLike(null));
result.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"hsadminng.currentUser defined as unknown@example.org, but does not exists");
JpaSystemException.class,
"hsadminng.currentUser defined as unknown@example.org, but does not exists");
}
}
@ -219,9 +220,14 @@ class CustomerRepositoryIntegrationTest extends ContextBasedTest {
void exactlyTheseCustomersAreReturned(final List<CustomerEntity> actualResult, final String... customerPrefixes) {
assertThat(actualResult)
.hasSize(customerPrefixes.length)
.extracting(CustomerEntity::getPrefix)
.containsExactlyInAnyOrder(customerPrefixes);
.hasSize(customerPrefixes.length)
.extracting(CustomerEntity::getPrefix)
.containsExactlyInAnyOrder(customerPrefixes);
}
void allTheseCustomersAreReturned(final List<CustomerEntity> actualResult, final String... customerPrefixes) {
assertThat(actualResult)
.extracting(CustomerEntity::getPrefix)
.contains(customerPrefixes);
}
}

View File

@ -102,7 +102,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
@Accepts({ "GRT:R(Read)" })
void packageAdmin_withAssumedUnixUserAdmin_canNotReadItsOwnGrantById() {
// given
final var givenCurrentUserAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com", "unixuser#xxx00-xxxa.admin");
final var givenCurrentUserAsPackageAdmin = new Subject(
"pac-admin-xxx00@xxx.example.com",
"unixuser#xxx00-xxxa.admin");
final var givenGranteeUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = findRbacRoleByName("package#xxx00.admin");
@ -131,11 +133,17 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
findRbacRoleByName(givenCurrentUserAsPackageAdmin.assumedRole);
// when
givenCurrentUserAsPackageAdmin
final var response = givenCurrentUserAsPackageAdmin
.grantsRole(givenOwnPackageAdminRole).assumed()
.toUser(givenNewUser);
// then
response.assertThat()
.statusCode(201)
.body("grantedByRoleIdName", is("package#xxx00.admin"))
.body("assumed", is(true))
.body("grantedRoleIdName", is("package#xxx00.admin"))
.body("granteeUserName", is(givenNewUser.getName()));
assertThat(findAllGrantsOf(givenCurrentUserAsPackageAdmin))
.extracting(RbacGrantEntity::toDisplay)
.contains("{ grant assumed role " + givenOwnPackageAdminRole.getRoleName() +
@ -160,9 +168,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// then
result.assertThat()
.statusCode(403)
.body("message", containsString("Access to granted role"))
.body("message", containsString("forbidden for {package#xxx00.admin}"))
.statusCode(403);
.body("message", containsString("forbidden for {package#xxx00.admin}"));
assertThat(findAllGrantsOf(givenCurrentUserAsPackageAdmin))
.extracting(RbacGrantEntity::getGranteeUserName)
.doesNotContain(givenNewUser.getName());
@ -200,7 +208,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.fromUser(givenArbitraryUser);
// then
assertRevoked(revokeResponse);
revokeResponse.assertThat().statusCode(204);
assertThat(findAllGrantsOf(givenCurrentUserAsPackageAdmin))
.extracting(RbacGrantEntity::getGranteeUserName)
.doesNotContain(givenArbitraryUser.getName());
@ -211,10 +219,6 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
assumeThat(response.extract().response().statusCode()).isEqualTo(201);
}
private void assertRevoked(final ValidatableResponse revokeResponse) {
revokeResponse.assertThat().statusCode(204);
}
class Subject {
final String currentUser;
@ -278,7 +282,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.port(port)
.when()
.post("http://localhost/api/rbac-grants")
.then(); // @formatter:on
.then().log().all(); // @formatter:on
}
}
@ -316,7 +320,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.delete("http://localhost/api/rbac-grants/%s/%s".formatted(
grantedRole.getUuid(), granteeUser.getUuid()
))
.then(); // @formatter:on
.then().log().all(); // @formatter:on
}
}
@ -344,7 +348,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.get("http://localhost/api/rbac-grants/%s/%s".formatted(
grantedRole.getUuid(), granteeUser.getUuid()
))
.then(); // @formatter:on
.then().log().all(); // @formatter:on
}
}
}

View File

@ -15,8 +15,8 @@ import javax.persistence.EntityManager;
import static org.hamcrest.Matchers.*;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class
)
@Accepts({ "ROL:*:S:Schema" })
class RbacRoleControllerAcceptanceTest {
@ -38,7 +38,7 @@ class RbacRoleControllerAcceptanceTest {
@Test
@Accepts({ "ROL:L(List)" })
void hostsharingAdmin_withoutAssumedRole_canViewPackageAdminRoles() {
void hostsharingAdmin_withoutAssumedRole_canViewAllRoles() {
// @formatter:off
RestAssured
@ -50,15 +50,15 @@ class RbacRoleControllerAcceptanceTest {
.then().assertThat()
.statusCode(200)
.contentType("application/json")
.body("[0].roleName", is("customer#xxx.admin"))
.body("[1].roleName", is("customer#xxx.owner"))
.body("[2].roleName", is("customer#xxx.tenant"))
.body("", hasItem(hasEntry("roleName", "customer#xxx.admin")))
.body("", hasItem(hasEntry("roleName", "customer#xxx.owner")))
.body("", hasItem(hasEntry("roleName", "customer#xxx.tenant")))
// ...
.body("", hasItem(hasEntry("roleName", "global#hostsharing.admin")))
.body("", hasItem(hasEntry("roleName", "customer#yyy.admin")))
.body("", hasItem(hasEntry("roleName", "package#yyy00.admin")))
.body("", hasItem(hasEntry("roleName", "unixuser#yyy00-aaaa.owner")))
.body( "size()", is(73)); // increases with new test data
.body( "size()", greaterThanOrEqualTo(73)); // increases with new test data
// @formatter:on
}

View File

@ -18,8 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class
)
@Transactional
class RbacUserControllerAcceptanceTest {
@ -52,14 +52,14 @@ class RbacUserControllerAcceptanceTest {
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
.body("[0].name", is("customer-admin@xxx.example.com"))
.body("[1].name", is("customer-admin@yyy.example.com"))
.body("[2].name", is("customer-admin@zzz.example.com"))
.body("[3].name", is("mike@hostsharing.net"))
.body("", hasItem(hasEntry("name", "customer-admin@xxx.example.com")))
.body("", hasItem(hasEntry("name", "customer-admin@yyy.example.com")))
.body("", hasItem(hasEntry("name", "customer-admin@zzz.example.com")))
.body("", hasItem(hasEntry("name", "mike@hostsharing.net")))
// ...
.body("[11].name", is("pac-admin-zzz01@zzz.example.com"))
.body("[12].name", is("pac-admin-zzz02@zzz.example.com"))
.body("[13].name", is("sven@hostsharing.net"))
.body("", hasItem(hasEntry("name", "pac-admin-zzz01@zzz.example.com")))
.body("", hasItem(hasEntry("name", "pac-admin-zzz02@zzz.example.com")))
.body("", hasItem(hasEntry("name", "sven@hostsharing.net")))
.body("size()", greaterThanOrEqualTo(14));
// @formatter:on
}
@ -152,10 +152,10 @@ class RbacUserControllerAcceptanceTest {
// finally, the user can view its own record
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
location.substring(location.lastIndexOf('/') + 1));
context.setCurrentUser("new-user@example.com");
assertThat(rbacUserRepository.findByUuid(newUserUuid))
.extracting(RbacUserEntity::getName).isEqualTo("new-user@example.com");
.extracting(RbacUserEntity::getName).isEqualTo("new-user@example.com");
}
}
}

View File

@ -32,7 +32,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
JpaAttempt jpaAttempt;
@Autowired EntityManager em;
@Autowired
EntityManager em;
@Nested
class CreateUser {
@ -45,7 +46,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = rbacUserRepository.create(
new RbacUserEntity(null, givenNewUserName));
new RbacUserEntity(null, givenNewUserName));
// then the persisted user is returned
assertThat(result).isNotNull().extracting(RbacUserEntity::getName).isEqualTo(givenNewUserName);
@ -53,7 +54,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// and the new user entity can be fetched by the user itself
context(givenNewUserName);
assertThat(em.find(RbacUserEntity.class, result.getUuid()))
.isNotNull().extracting(RbacUserEntity::getName).isEqualTo(givenNewUserName);
.isNotNull().extracting(RbacUserEntity::getName).isEqualTo(givenNewUserName);
}
@Test
@ -73,11 +74,11 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// then:
assertThat(result.wasSuccessful()).isTrue();
assertThat(result.returnedValue()).isNotNull()
.extracting(RbacUserEntity::getUuid).isEqualTo(givenUuid);
.extracting(RbacUserEntity::getUuid).isEqualTo(givenUuid);
jpaAttempt.transacted(() -> {
context(newUserName);
assertThat(em.find(RbacUserEntity.class, givenUuid))
.isNotNull().extracting(RbacUserEntity::getName).isEqualTo(newUserName);
.isNotNull().extracting(RbacUserEntity::getName).isEqualTo(newUserName);
});
}
}
@ -86,7 +87,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
class FindByOptionalNameLike {
private static final String[] ALL_TEST_DATA_USERS = Array.of(
// @formatter:off
// @formatter:off
"mike@hostsharing.net", "sven@hostsharing.net",
"customer-admin@xxx.example.com",
"pac-admin-xxx00@xxx.example.com", "pac-admin-xxx01@xxx.example.com", "pac-admin-xxx02@xxx.example.com",
@ -106,7 +107,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
final var result = rbacUserRepository.findByOptionalNameLike(null);
// then
exactlyTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
allTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
}
@Test
@ -118,7 +119,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
final var result = rbacUserRepository.findByOptionalNameLike(null);
then:
exactlyTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
allTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
}
@Test
@ -131,9 +132,9 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
then:
exactlyTheseRbacUsersAreReturned(
result,
"customer-admin@xxx.example.com",
"pac-admin-xxx00@xxx.example.com", "pac-admin-xxx01@xxx.example.com", "pac-admin-xxx02@xxx.example.com"
result,
"customer-admin@xxx.example.com",
"pac-admin-xxx00@xxx.example.com", "pac-admin-xxx01@xxx.example.com", "pac-admin-xxx02@xxx.example.com"
);
}
@ -147,9 +148,9 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// then:
exactlyTheseRbacUsersAreReturned(
result,
"customer-admin@xxx.example.com",
"pac-admin-xxx00@xxx.example.com", "pac-admin-xxx01@xxx.example.com", "pac-admin-xxx02@xxx.example.com"
result,
"customer-admin@xxx.example.com",
"pac-admin-xxx00@xxx.example.com", "pac-admin-xxx01@xxx.example.com", "pac-admin-xxx02@xxx.example.com"
);
}
@ -177,7 +178,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
class ListUserPermissions {
private static final String[] ALL_USER_PERMISSIONS = Array.of(
// @formatter:off
// @formatter:off
"global#hostsharing.admin -> global#hostsharing: add-customer",
"customer#xxx.admin -> customer#xxx: add-package",
@ -243,13 +244,13 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () ->
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
);
// then
result.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"[400] grantedPermissions(...) does not support assumed roles");
JpaSystemException.class,
"[400] grantedPermissions(...) does not support assumed roles");
}
@Test
@ -262,8 +263,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// then
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
result,
// @formatter:off
"customer#xxx.admin -> customer#xxx: add-package",
"customer#xxx.admin -> customer#xxx: view",
"customer#xxx.tenant -> customer#xxx: view",
@ -285,8 +286,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
result,
// @formatter:off
"customer#yyy.admin -> customer#yyy: add-package",
"customer#yyy.admin -> customer#yyy: view",
"customer#yyy.tenant -> customer#yyy: view"
@ -301,13 +302,13 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () ->
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
);
// then
result.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"[403] permissions of user \"mike@hostsharing.net\" are not accessible to user \"customer-admin@xxx.example.com\"");
JpaSystemException.class,
"[403] permissions of user \"mike@hostsharing.net\" are not accessible to user \"customer-admin@xxx.example.com\"");
}
@Test
@ -320,8 +321,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// then
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
result,
// @formatter:off
"customer#xxx.tenant -> customer#xxx: view",
// "customer#xxx.admin -> customer#xxx: view" - Not permissions through the customer admin!
"package#xxx00.admin -> package#xxx00: add-unixuser",
@ -332,8 +333,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
result,
// @formatter:off
"customer#yyy.admin -> customer#yyy: add-package",
"customer#yyy.admin -> customer#yyy: view",
"customer#yyy.tenant -> customer#yyy: view",
@ -368,8 +369,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// then
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
result,
// @formatter:off
"customer#xxx.tenant -> customer#xxx: view",
// "customer#xxx.admin -> customer#xxx: view" - Not permissions through the customer admin!
"package#xxx00.admin -> package#xxx00: add-unixuser",
@ -378,8 +379,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
result,
// @formatter:off
// no customer admin permissions
"customer#xxx.admin -> customer#xxx: add-package",
// no permissions on other customer's objects
@ -398,40 +399,47 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
void exactlyTheseRbacUsersAreReturned(final List<RbacUserEntity> actualResult, final String... expectedUserNames) {
assertThat(actualResult)
.filteredOn(u -> !u.getName().startsWith("test-user-"))
.extracting(RbacUserEntity::getName)
.containsExactlyInAnyOrder(expectedUserNames);
.extracting(RbacUserEntity::getName)
.filteredOn(n -> !n.startsWith("test-user"))
.containsExactlyInAnyOrder(expectedUserNames);
}
void allTheseRbacUsersAreReturned(final List<RbacUserEntity> actualResult, final String... expectedUserNames) {
assertThat(actualResult)
.extracting(RbacUserEntity::getName)
.filteredOn(n -> !n.startsWith("test-user"))
.contains(expectedUserNames);
}
void noRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult) {
final List<RbacUserPermission> actualResult) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.containsExactlyInAnyOrder();
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.containsExactlyInAnyOrder();
}
void exactlyTheseRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult,
final String... expectedRoleNames) {
final List<RbacUserPermission> actualResult,
final String... expectedRoleNames) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.containsExactlyInAnyOrder(expectedRoleNames);
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.containsExactlyInAnyOrder(expectedRoleNames);
}
void allTheseRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult,
final String... expectedRoleNames) {
final List<RbacUserPermission> actualResult,
final String... expectedRoleNames) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.contains(expectedRoleNames);
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.contains(expectedRoleNames);
}
void noneOfTheseRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult,
final String... unexpectedRoleNames) {
final List<RbacUserPermission> actualResult,
final String... unexpectedRoleNames) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.doesNotContain(unexpectedRoleNames);
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.doesNotContain(unexpectedRoleNames);
}
}