improve test code coverage
This commit is contained in:
parent
2531b9071f
commit
1a18ba4a3d
22
build.gradle
22
build.gradle
@ -156,11 +156,8 @@ jacocoTestReport {
|
|||||||
classDirectories.setFrom(files(classDirectories.files.collect {
|
classDirectories.setFrom(files(classDirectories.files.collect {
|
||||||
fileTree(dir: it, exclude: [
|
fileTree(dir: it, exclude: [
|
||||||
"net/hostsharing/hsadminng/generated/**/*.class",
|
"net/hostsharing/hsadminng/generated/**/*.class",
|
||||||
|
"net/hostsharing/hsadminng/TestController.class",
|
||||||
// TODO: improve test code coverage for these classes:
|
"net/hostsharing/hsadminng/hs/hscustomer/HsadminNgApplication.class"
|
||||||
"net/hostsharing/hsadminng/rbac/rbacuser/UserController.class",
|
|
||||||
"net/hostsharing/hsadminng/rbac/rbacgrant/GrantController.class",
|
|
||||||
"net/hostsharing/hsadminng/hs/hscustomer/CustomerController.class"
|
|
||||||
])
|
])
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -174,7 +171,7 @@ jacocoTestCoverageVerification {
|
|||||||
rule {
|
rule {
|
||||||
excludes = ['net.hostsharing.hsadminng.generated.**']
|
excludes = ['net.hostsharing.hsadminng.generated.**']
|
||||||
limit {
|
limit {
|
||||||
minimum = 0.7 // TODO: increase to 0.9
|
minimum = 0.8 // TODO: increase to 0.9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,14 +187,13 @@ jacocoTestCoverageVerification {
|
|||||||
'net.hostsharing.hsadminng.TestController',
|
'net.hostsharing.hsadminng.TestController',
|
||||||
|
|
||||||
// TODO: improve test code coverage:
|
// TODO: improve test code coverage:
|
||||||
'net.hostsharing.hsadminng.rbac.rbacuser.UserController',
|
'net.hostsharing.hsadminng.Mapper',
|
||||||
'net.hostsharing.hsadminng.hs.hscustomer.CustomerController'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
limit {
|
limit {
|
||||||
counter = 'LINE'
|
counter = 'LINE'
|
||||||
value = 'COVEREDRATIO'
|
value = 'COVEREDRATIO'
|
||||||
minimum = 0.7
|
minimum = 0.95
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rule {
|
rule {
|
||||||
@ -205,13 +201,7 @@ jacocoTestCoverageVerification {
|
|||||||
excludes = [
|
excludes = [
|
||||||
'net.hostsharing.hsadminng.generated.**',
|
'net.hostsharing.hsadminng.generated.**',
|
||||||
'net.hostsharing.hsadminng.HsadminNgApplication.*',
|
'net.hostsharing.hsadminng.HsadminNgApplication.*',
|
||||||
|
'net.hostsharing.hsadminng.TestController.*']
|
||||||
// TODO: improve test code coverage:
|
|
||||||
'net.hostsharing.hsadminng.rbac.rbacuser.RbacUserController.listUsers(*)',
|
|
||||||
'net.hostsharing.hsadminng.rbac.rbacuser.RbacUserController.listUserPermissions(*)',
|
|
||||||
'net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantController.listUserGrants(*)',
|
|
||||||
'net.hostsharing.hsadminng.hs.hscustomer.CustomerController.addCustomer(java.lang.String, java.lang.String, net.hostsharing.hsadminng.generated.api.v1.model.CustomerResource)'
|
|
||||||
]
|
|
||||||
|
|
||||||
limit {
|
limit {
|
||||||
counter = 'BRANCH'
|
counter = 'BRANCH'
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
|
||||||
# Spring BOM overrides
|
# Spring BOM overrides
|
||||||
postgresql.version = 42.4.1
|
postgresql.version = 42.4.1
|
||||||
|
|
||||||
|
# TODO: can be removed if all dependencies are JDK 16 compliant
|
||||||
|
#org.gradle.jvmargs= \
|
||||||
|
# --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
|
||||||
|
# --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
|
||||||
|
# --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
|
||||||
|
# --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
|
||||||
|
# --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
|
||||||
|
@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.hscustomer;
|
|||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.api.CustomersApi;
|
import net.hostsharing.hsadminng.generated.api.v1.api.CustomersApi;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.model.CustomerResource;
|
import net.hostsharing.hsadminng.generated.api.v1.model.CustomerResource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -33,7 +34,7 @@ public class CustomerController implements CustomersApi {
|
|||||||
String prefix
|
String prefix
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(userName);
|
context.setCurrentUser(userName);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ public class CustomerController implements CustomersApi {
|
|||||||
|
|
||||||
context.setCurrentTask("create new customer: #" + customer.getReference() + " / " + customer.getPrefix());
|
context.setCurrentTask("create new customer: #" + customer.getReference() + " / " + customer.getPrefix());
|
||||||
context.setCurrentUser(currentUser);
|
context.setCurrentUser(currentUser);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
if (customer.getUuid() == null) {
|
if (customer.getUuid() == null) {
|
||||||
@ -62,7 +63,7 @@ public class CustomerController implements CustomersApi {
|
|||||||
|
|
||||||
final var uri =
|
final var uri =
|
||||||
MvcUriComponentsBuilder.fromController(getClass())
|
MvcUriComponentsBuilder.fromController(getClass())
|
||||||
.path("/api/rbac-users/{id}")
|
.path("/api/customers/{id}")
|
||||||
.buildAndExpand(customer.getUuid())
|
.buildAndExpand(customer.getUuid())
|
||||||
.toUri();
|
.toUri();
|
||||||
return ResponseEntity.created(uri).body(map(saved, CustomerResource.class));
|
return ResponseEntity.created(uri).body(map(saved, CustomerResource.class));
|
||||||
|
@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.context.Context;
|
|||||||
import net.hostsharing.hsadminng.generated.api.v1.api.PackagesApi;
|
import net.hostsharing.hsadminng.generated.api.v1.api.PackagesApi;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.model.PackageResource;
|
import net.hostsharing.hsadminng.generated.api.v1.model.PackageResource;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.model.PackageUpdateResource;
|
import net.hostsharing.hsadminng.generated.api.v1.model.PackageUpdateResource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -33,7 +34,7 @@ public class PackageController implements PackagesApi {
|
|||||||
String name
|
String name
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(userName);
|
context.setCurrentUser(userName);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
final var result = packageRepository.findAllByOptionalNameLike(name);
|
final var result = packageRepository.findAllByOptionalNameLike(name);
|
||||||
@ -49,7 +50,7 @@ public class PackageController implements PackagesApi {
|
|||||||
final PackageUpdateResource body) {
|
final PackageUpdateResource body) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.setCurrentUser(currentUser);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
final var current = packageRepository.findByUuid(packageUuid);
|
final var current = packageRepository.findByUuid(packageUuid);
|
||||||
|
@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.rbac.rbacgrant;
|
|||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.api.RbacgrantsApi;
|
import net.hostsharing.hsadminng.generated.api.v1.api.RbacgrantsApi;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.model.RbacGrantResource;
|
import net.hostsharing.hsadminng.generated.api.v1.model.RbacGrantResource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -38,7 +39,7 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
final UUID granteeUserUuid) {
|
final UUID granteeUserUuid) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.setCurrentUser(currentUser);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
final String assumedRoles) {
|
final String assumedRoles) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.setCurrentUser(currentUser);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
return ResponseEntity.ok(mapList(rbacGrantRepository.findAll(), RbacGrantResource.class));
|
return ResponseEntity.ok(mapList(rbacGrantRepository.findAll(), RbacGrantResource.class));
|
||||||
@ -72,7 +73,7 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
|
|
||||||
context.setCurrentTask("granting role to user");
|
context.setCurrentTask("granting role to user");
|
||||||
context.setCurrentUser(currentUser);
|
context.setCurrentUser(currentUser);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +99,7 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
|
|
||||||
context.setCurrentTask("revoking role from user");
|
context.setCurrentTask("revoking role from user");
|
||||||
context.setCurrentUser(currentUser);
|
context.setCurrentUser(currentUser);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.rbac.rbacrole;
|
|||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.api.RbacrolesApi;
|
import net.hostsharing.hsadminng.generated.api.v1.api.RbacrolesApi;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.model.RbacRoleResource;
|
import net.hostsharing.hsadminng.generated.api.v1.model.RbacRoleResource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -29,7 +30,7 @@ public class RbacRoleController implements RbacrolesApi {
|
|||||||
final String assumedRoles) {
|
final String assumedRoles) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.setCurrentUser(currentUser);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
return ResponseEntity.ok(mapList(rbacRoleRepository.findAll(), RbacRoleResource.class));
|
return ResponseEntity.ok(mapList(rbacRoleRepository.findAll(), RbacRoleResource.class));
|
||||||
|
@ -2,8 +2,11 @@ package net.hostsharing.hsadminng.rbac.rbacuser;
|
|||||||
|
|
||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.api.RbacusersApi;
|
import net.hostsharing.hsadminng.generated.api.v1.api.RbacusersApi;
|
||||||
|
import net.hostsharing.hsadminng.generated.api.v1.model.RbacGrantResource;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.model.RbacUserPermissionResource;
|
import net.hostsharing.hsadminng.generated.api.v1.model.RbacUserPermissionResource;
|
||||||
import net.hostsharing.hsadminng.generated.api.v1.model.RbacUserResource;
|
import net.hostsharing.hsadminng.generated.api.v1.model.RbacUserResource;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantId;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -28,7 +31,7 @@ public class RbacUserController implements RbacusersApi {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public ResponseEntity<RbacUserResource> createUser(
|
public ResponseEntity<RbacUserResource> createUser(
|
||||||
@RequestBody final RbacUserResource body
|
final RbacUserResource body
|
||||||
) {
|
) {
|
||||||
context.setCurrentTask("creating new user: " + body.getName());
|
context.setCurrentTask("creating new user: " + body.getName());
|
||||||
context.setCurrentUser(body.getName());
|
context.setCurrentUser(body.getName());
|
||||||
@ -47,22 +50,33 @@ public class RbacUserController implements RbacusersApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<List<RbacUserPermissionResource>> getUserById(
|
@Transactional(readOnly = true)
|
||||||
|
public ResponseEntity<RbacUserResource> getUserById(
|
||||||
final String currentUser,
|
final String currentUser,
|
||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final String userName) {
|
final UUID userUuid) {
|
||||||
return null; // TODO implement getUserById
|
|
||||||
|
context.setCurrentUser(currentUser);
|
||||||
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
|
context.assumeRoles(assumedRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
final var result = rbacUserRepository.findByUuid(userUuid);
|
||||||
|
if (result == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(map(result, RbacUserResource.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<RbacUserResource>> listUsers(
|
public ResponseEntity<List<RbacUserResource>> listUsers(
|
||||||
@RequestHeader(name = "current-user") final String currentUserName,
|
final String currentUserName,
|
||||||
@RequestHeader(name = "assumed-roles", required = false) final String assumedRoles,
|
final String assumedRoles,
|
||||||
@RequestParam(name = "name", required = false) final String userName
|
final String userName
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(currentUserName);
|
context.setCurrentUser(currentUserName);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
return ResponseEntity.ok(mapList(rbacUserRepository.findByOptionalNameLike(userName), RbacUserResource.class));
|
return ResponseEntity.ok(mapList(rbacUserRepository.findByOptionalNameLike(userName), RbacUserResource.class));
|
||||||
@ -71,14 +85,14 @@ public class RbacUserController implements RbacusersApi {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<RbacUserPermissionResource>> listUserPermissions(
|
public ResponseEntity<List<RbacUserPermissionResource>> listUserPermissions(
|
||||||
@RequestHeader(name = "current-user") final String currentUserName,
|
final String currentUserName,
|
||||||
@RequestHeader(name = "assumed-roles", required = false) final String assumedRoles,
|
final String assumedRoles,
|
||||||
@PathVariable(name = "userName") final String userName
|
final UUID userUuid
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(currentUserName);
|
context.setCurrentUser(currentUserName);
|
||||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
context.assumeRoles(assumedRoles);
|
context.assumeRoles(assumedRoles);
|
||||||
}
|
}
|
||||||
return ResponseEntity.ok(mapList(rbacUserRepository.findPermissionsOfUser(userName), RbacUserPermissionResource.class));
|
return ResponseEntity.ok(mapList(rbacUserRepository.findPermissionsOfUserByUuid(userUuid), RbacUserPermissionResource.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,8 @@ public interface RbacUserRepository extends Repository<RbacUserEntity, UUID> {
|
|||||||
|
|
||||||
RbacUserEntity findByUuid(UUID uuid);
|
RbacUserEntity findByUuid(UUID uuid);
|
||||||
|
|
||||||
@Query(value = "select * from grantedPermissions(:userName)", nativeQuery = true)
|
@Query(value = "select * from grantedPermissions(:userUuid)", nativeQuery = true)
|
||||||
List<RbacUserPermission> findPermissionsOfUser(String userName);
|
List<RbacUserPermission> findPermissionsOfUserByUuid(UUID userUuid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Can't use save/saveAndFlush from SpringData because the uuid is not generated on the entity level,
|
Can't use save/saveAndFlush from SpringData because the uuid is not generated on the entity level,
|
||||||
|
@ -13,12 +13,12 @@ paths:
|
|||||||
/api/rbac-users:
|
/api/rbac-users:
|
||||||
$ref: "./api-definition/rbac-users.yaml"
|
$ref: "./api-definition/rbac-users.yaml"
|
||||||
|
|
||||||
/api/rbac-users/{userUuid}:
|
|
||||||
$ref: "./api-definition/rbac-users-with-id.yaml"
|
|
||||||
|
|
||||||
/api/rbac-users/{userUuid}/permissions:
|
/api/rbac-users/{userUuid}/permissions:
|
||||||
$ref: "./api-definition/rbac-users-with-id-permissions.yaml"
|
$ref: "./api-definition/rbac-users-with-id-permissions.yaml"
|
||||||
|
|
||||||
|
/api/rbac-users/{userUuid}:
|
||||||
|
$ref: "./api-definition/rbac-users-with-id.yaml"
|
||||||
|
|
||||||
/api/rbac-roles:
|
/api/rbac-roles:
|
||||||
$ref: "./api-definition/rbac-roles.yaml"
|
$ref: "./api-definition/rbac-roles.yaml"
|
||||||
|
|
||||||
|
@ -6,11 +6,12 @@ get:
|
|||||||
parameters:
|
parameters:
|
||||||
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
||||||
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: userName
|
- name: userUuid
|
||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
format: uuid
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -6,20 +6,19 @@ get:
|
|||||||
parameters:
|
parameters:
|
||||||
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
- $ref: './api-definition/auth.yaml#/components/parameters/currentUser'
|
||||||
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
- $ref: './api-definition/auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: userName
|
- name: userUuid
|
||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
format: uuid
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
type: array
|
$ref: './api-definition/rbac-user-schemas.yaml#/components/schemas/RbacUser'
|
||||||
items:
|
|
||||||
$ref: './api-definition/rbac-user-schemas.yaml#/components/schemas/RbacUserPermission'
|
|
||||||
|
|
||||||
"401":
|
"401":
|
||||||
$ref: './api-definition/error-responses.yaml#/components/responses/Unauthorized'
|
$ref: './api-definition/error-responses.yaml#/components/responses/Unauthorized'
|
||||||
|
@ -205,24 +205,18 @@ grant all privileges on RbacOwnGrantedPermissions_rv to restricted;
|
|||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
create or replace function grantedPermissions(userName varchar)
|
create or replace function grantedPermissions(targetUserUuid uuid)
|
||||||
returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, objectTable varchar, objectIdName varchar, objectUuid uuid)
|
returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, objectTable varchar, objectIdName varchar, objectUuid uuid)
|
||||||
returns null on null input
|
returns null on null input
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
targetUserId uuid;
|
|
||||||
currentUserId uuid;
|
currentUserId uuid;
|
||||||
begin
|
begin
|
||||||
-- @formatter:off
|
-- @formatter:off
|
||||||
if cardinality(assumedRoles()) > 0 then
|
|
||||||
raise exception '[400] grantedPermissions(...) does not support assumed roles';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
targetUserId := findRbacUserId(userName);
|
|
||||||
currentUserId := currentUserId();
|
currentUserId := currentUserId();
|
||||||
|
|
||||||
if hasGlobalRoleGranted(targetUserId) and not hasGlobalRoleGranted(currentUserId) then
|
if hasGlobalRoleGranted(targetUserUuid) and not hasGlobalRoleGranted(currentUserId) then
|
||||||
raise exception '[403] permissions of user "%" are not accessible to user "%"', userName, currentUser();
|
raise exception '[403] permissions of user "%" are not accessible to user "%"', targetUserUuid, currentUser();
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
return query select
|
return query select
|
||||||
@ -235,12 +229,12 @@ begin
|
|||||||
p.uuid as permissionUuid, p.op, po.objecttable as permissionObjectTable,
|
p.uuid as permissionUuid, p.op, po.objecttable as permissionObjectTable,
|
||||||
findIdNameByObjectUuid(po.objectTable, po.uuid) as permissionObjectIdName,
|
findIdNameByObjectUuid(po.objectTable, po.uuid) as permissionObjectIdName,
|
||||||
po.uuid as permissionObjectUuid
|
po.uuid as permissionObjectUuid
|
||||||
from queryPermissionsGrantedToSubjectId( targetUserId) as p
|
from queryPermissionsGrantedToSubjectId( targetUserUuid) as p
|
||||||
join rbacgrants as g on g.descendantUuid = p.uuid
|
join rbacgrants as g on g.descendantUuid = p.uuid
|
||||||
join rbacobject as po on po.uuid = p.objectUuid
|
join rbacobject as po on po.uuid = p.objectUuid
|
||||||
join rbacrole_rv as r on r.uuid = g.ascendantUuid
|
join rbacrole_rv as r on r.uuid = g.ascendantUuid
|
||||||
join rbacobject as ro on ro.uuid = r.objectUuid
|
join rbacobject as ro on ro.uuid = r.objectUuid
|
||||||
where isGranted(targetUserId, r.uuid)
|
where isGranted(targetUserUuid, r.uuid)
|
||||||
) xp;
|
) xp;
|
||||||
-- @formatter:on
|
-- @formatter:on
|
||||||
end; $$;
|
end; $$;
|
||||||
|
@ -141,6 +141,36 @@ class CustomerControllerAcceptanceTest {
|
|||||||
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("vvv"));
|
.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
|
@Test
|
||||||
void customerAdmin_withoutAssumedRole_canNotCreateCustomer() throws Exception {
|
void customerAdmin_withoutAssumedRole_canNotCreateCustomer() throws Exception {
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
@SpringBootTest(
|
@SpringBootTest(
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
@ -55,6 +56,108 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
JpaAttempt jpaAttempt;
|
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
|
@Nested
|
||||||
class GetGrantById {
|
class GetGrantById {
|
||||||
|
|
||||||
|
@ -2,8 +2,10 @@ package net.hostsharing.hsadminng.rbac.rbacuser;
|
|||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
|
import net.hostsharing.hsadminng.Accepts;
|
||||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import net.hostsharing.test.JpaAttempt;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -19,7 +21,7 @@ import static org.hamcrest.Matchers.*;
|
|||||||
|
|
||||||
@SpringBootTest(
|
@SpringBootTest(
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
classes = HsadminNgApplication.class
|
classes = { HsadminNgApplication.class, JpaAttempt.class }
|
||||||
)
|
)
|
||||||
@Transactional
|
@Transactional
|
||||||
class RbacUserControllerAcceptanceTest {
|
class RbacUserControllerAcceptanceTest {
|
||||||
@ -30,6 +32,9 @@ class RbacUserControllerAcceptanceTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
EntityManager em;
|
EntityManager em;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
Context context;
|
Context context;
|
||||||
|
|
||||||
@ -37,9 +42,125 @@ class RbacUserControllerAcceptanceTest {
|
|||||||
RbacUserRepository rbacUserRepository;
|
RbacUserRepository rbacUserRepository;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class ApiRbacUsersGet {
|
class CreateRbacUser {
|
||||||
|
|
||||||
@Test
|
@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() {
|
void hostsharingAdmin_withoutAssumedRole_canViewAllUsers() {
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@ -65,6 +186,7 @@ class RbacUserControllerAcceptanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Accepts({ "USR:F(Filter)" })
|
||||||
void hostsharingAdmin_withoutAssumedRole_canViewAllUsersByName() {
|
void hostsharingAdmin_withoutAssumedRole_canViewAllUsersByName() {
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@ -85,6 +207,30 @@ class RbacUserControllerAcceptanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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() {
|
void customerAdmin_withoutAssumedRole_canViewUsersInItsRealm() {
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@ -106,6 +252,7 @@ class RbacUserControllerAcceptanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Accepts({ "USR:L(List)", "USR:X(Access Control)" })
|
||||||
void packetAdmin_withoutAssumedRole_canViewAllUsersOfItsPackage() {
|
void packetAdmin_withoutAssumedRole_canViewAllUsersOfItsPackage() {
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@ -125,37 +272,135 @@ class RbacUserControllerAcceptanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class ApiRbacUsersPost {
|
class ListRbacUserPermissions {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void anybody_canCreateANewUser() {
|
@Accepts({ "PRM:L(List)" })
|
||||||
|
void hostsharingAdmin_withoutAssumedRole_canViewArbitraryUsersPermissions() {
|
||||||
|
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
final var location = RestAssured
|
RestAssured
|
||||||
.given()
|
.given()
|
||||||
.contentType(ContentType.JSON)
|
.header("current-user", "mike@hostsharing.net")
|
||||||
.body("""
|
|
||||||
{
|
|
||||||
"name": "new-user@example.com"
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/rbac-users")
|
.get("http://localhost/api/rbac-users/" + givenUser.getUuid() + "/permissions")
|
||||||
.then().assertThat()
|
.then().log().body().assertThat()
|
||||||
.statusCode(201)
|
.statusCode(200)
|
||||||
.contentType(ContentType.JSON)
|
.contentType("application/json")
|
||||||
.body("name", is("new-user@example.com"))
|
.body("", hasItem(
|
||||||
.header("Location", startsWith("http://localhost"))
|
allOf(
|
||||||
.extract().header("Location");
|
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
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
// finally, the user can view its own record
|
@Test
|
||||||
final var newUserUuid = UUID.fromString(
|
@Accepts({ "PRM:L(List)" })
|
||||||
location.substring(location.lastIndexOf('/') + 1));
|
void hostsharingAdmin_withAssumedCustomerAdminRole_canViewArbitraryUsersPermissions() {
|
||||||
context.setCurrentUser("new-user@example.com");
|
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
|
||||||
assertThat(rbacUserRepository.findByUuid(newUserUuid))
|
|
||||||
.extracting(RbacUserEntity::getName).isEqualTo("new-user@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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,35 +231,19 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
context("mike@hostsharing.net");
|
context("mike@hostsharing.net");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net");
|
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("mike@hostsharing.net"));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS);
|
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
|
@Test
|
||||||
public void customerAdmin_withoutAssumedRole_canViewTheirOwnPermissions() {
|
public void customerAdmin_withoutAssumedRole_canViewTheirOwnPermissions() {
|
||||||
// given
|
// given
|
||||||
context("customer-admin@xxx.example.com");
|
context("customer-admin@xxx.example.com");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = rbacUserRepository.findPermissionsOfUser("customer-admin@xxx.example.com");
|
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("customer-admin@xxx.example.com"));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
allTheseRbacPermissionsAreReturned(
|
allTheseRbacPermissionsAreReturned(
|
||||||
@ -299,16 +283,18 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void customerAdmin_withoutAssumedRole_isNotAllowedToViewGlobalAdminsPermissions() {
|
public void customerAdmin_withoutAssumedRole_isNotAllowedToViewGlobalAdminsPermissions() {
|
||||||
// given
|
// given
|
||||||
context("customer-admin@xxx.example.com");
|
context("customer-admin@xxx.example.com");
|
||||||
|
final UUID userUuid = userUUID("mike@hostsharing.net");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = attempt(em, () ->
|
final var result = attempt(em, () ->
|
||||||
rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net")
|
rbacUserRepository.findPermissionsOfUserByUuid(userUuid)
|
||||||
);
|
);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
result.assertExceptionWithRootCauseMessage(
|
result.assertExceptionWithRootCauseMessage(
|
||||||
JpaSystemException.class,
|
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
|
@Test
|
||||||
@ -317,7 +303,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
context("customer-admin@xxx.example.com");
|
context("customer-admin@xxx.example.com");
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
allTheseRbacPermissionsAreReturned(
|
allTheseRbacPermissionsAreReturned(
|
||||||
@ -353,7 +339,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
context("customer-admin@xxx.example.com");
|
context("customer-admin@xxx.example.com");
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
noRbacPermissionsAreReturned(result);
|
noRbacPermissionsAreReturned(result);
|
||||||
@ -365,7 +351,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
context("pac-admin-xxx00@xxx.example.com");
|
context("pac-admin-xxx00@xxx.example.com");
|
||||||
|
|
||||||
// when
|
// 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
|
// then
|
||||||
allTheseRbacPermissionsAreReturned(
|
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) {
|
void exactlyTheseRbacUsersAreReturned(final List<RbacUserEntity> actualResult, final String... expectedUserNames) {
|
||||||
assertThat(actualResult)
|
assertThat(actualResult)
|
||||||
.extracting(RbacUserEntity::getName)
|
.extracting(RbacUserEntity::getName)
|
||||||
|
Loading…
Reference in New Issue
Block a user