improve test code coverage and introduce context.register
This commit is contained in:
parent
1a18ba4a3d
commit
2124d448bf
13
build.gradle
13
build.gradle
@ -169,9 +169,12 @@ project.tasks.check.dependsOn(jacocoTestCoverageVerification)
|
|||||||
jacocoTestCoverageVerification {
|
jacocoTestCoverageVerification {
|
||||||
violationRules {
|
violationRules {
|
||||||
rule {
|
rule {
|
||||||
excludes = ['net.hostsharing.hsadminng.generated.**']
|
excludes = [
|
||||||
|
'net.hostsharing.hsadminng.generated.**',
|
||||||
|
'net.hostsharing.hsadminng.HsadminNgApplication' // main method
|
||||||
|
]
|
||||||
limit {
|
limit {
|
||||||
minimum = 0.8 // TODO: increase to 0.9
|
minimum = 0.94
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,8 +188,6 @@ jacocoTestCoverageVerification {
|
|||||||
'net.hostsharing.hsadminng.generated.**',
|
'net.hostsharing.hsadminng.generated.**',
|
||||||
'net.hostsharing.hsadminng.HsadminNgApplication',
|
'net.hostsharing.hsadminng.HsadminNgApplication',
|
||||||
'net.hostsharing.hsadminng.TestController',
|
'net.hostsharing.hsadminng.TestController',
|
||||||
|
|
||||||
// TODO: improve test code coverage:
|
|
||||||
'net.hostsharing.hsadminng.Mapper',
|
'net.hostsharing.hsadminng.Mapper',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -200,13 +201,13 @@ jacocoTestCoverageVerification {
|
|||||||
element = 'METHOD'
|
element = 'METHOD'
|
||||||
excludes = [
|
excludes = [
|
||||||
'net.hostsharing.hsadminng.generated.**',
|
'net.hostsharing.hsadminng.generated.**',
|
||||||
'net.hostsharing.hsadminng.HsadminNgApplication.*',
|
'net.hostsharing.hsadminng.HsadminNgApplication.main',
|
||||||
'net.hostsharing.hsadminng.TestController.*']
|
'net.hostsharing.hsadminng.TestController.*']
|
||||||
|
|
||||||
limit {
|
limit {
|
||||||
counter = 'BRANCH'
|
counter = 'BRANCH'
|
||||||
value = 'COVEREDRATIO'
|
value = 'COVEREDRATIO'
|
||||||
minimum = 0.5 // TODO: increase test code coverage
|
minimum = 0.95
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,8 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A nicer API for ModelMapper.
|
* A nicer API for ModelMapper.
|
||||||
*
|
|
||||||
* MOst
|
|
||||||
*/
|
*/
|
||||||
public class Mapper {
|
public abstract class Mapper {
|
||||||
private final static ModelMapper modelMapper = new ModelMapper();
|
private final static ModelMapper modelMapper = new ModelMapper();
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package net.hostsharing.hsadminng.context;
|
package net.hostsharing.hsadminng.context;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.springframework.transaction.annotation.Propagation.*;
|
import static org.springframework.transaction.annotation.Propagation.MANDATORY;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class Context {
|
public class Context {
|
||||||
@ -14,23 +18,55 @@ public class Context {
|
|||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager em;
|
private EntityManager em;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HttpServletRequest request;
|
||||||
|
|
||||||
|
@Transactional(propagation = MANDATORY)
|
||||||
|
public void register(final String currentUser, final String assumedRoles) {
|
||||||
|
if (request != null) {
|
||||||
|
setCurrentTask(request.getMethod() + " " + request.getRequestURI());
|
||||||
|
} else {
|
||||||
|
|
||||||
|
final Optional<StackWalker.StackFrame> caller =
|
||||||
|
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
|
||||||
|
.walk(frames ->
|
||||||
|
frames.skip(1)
|
||||||
|
.filter(c -> c.getDeclaringClass()
|
||||||
|
.getPackageName()
|
||||||
|
.startsWith("net.hostsharing.hsadminng"))
|
||||||
|
.filter(c -> !c.getDeclaringClass().getName().contains("BySpringCGLIB$$"))
|
||||||
|
.findFirst());
|
||||||
|
final var callerName = caller.map(
|
||||||
|
c -> c.getDeclaringClass().getSimpleName() + "." + c.getMethodName())
|
||||||
|
.orElse("unknown");
|
||||||
|
setCurrentTask(callerName);
|
||||||
|
}
|
||||||
|
setCurrentUser(currentUser);
|
||||||
|
if (!StringUtils.isBlank(assumedRoles)) {
|
||||||
|
assumeRoles(assumedRoles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(propagation = MANDATORY)
|
@Transactional(propagation = MANDATORY)
|
||||||
public void setCurrentTask(final String task) {
|
public void setCurrentTask(final String task) {
|
||||||
em.createNativeQuery(
|
final var sql = String.format(
|
||||||
String.format(
|
"set local hsadminng.currentTask = '%s';",
|
||||||
"set local hsadminng.currentTask = '%s';",
|
shortenToMaxLength(task, 95)
|
||||||
task
|
);
|
||||||
)
|
em.createNativeQuery(sql).executeUpdate();
|
||||||
).executeUpdate();
|
}
|
||||||
|
|
||||||
|
public String getCurrentTask() {
|
||||||
|
return (String) em.createNativeQuery("select current_setting('hsadminng.currentTask');").getSingleResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = MANDATORY)
|
@Transactional(propagation = MANDATORY)
|
||||||
public void setCurrentUser(final String userName) {
|
public void setCurrentUser(final String userName) {
|
||||||
em.createNativeQuery(
|
em.createNativeQuery(
|
||||||
String.format(
|
String.format(
|
||||||
"set local hsadminng.currentUser = '%s';",
|
"set local hsadminng.currentUser = '%s';",
|
||||||
userName
|
userName
|
||||||
)
|
)
|
||||||
).executeUpdate();
|
).executeUpdate();
|
||||||
assumeNoSpecialRole();
|
assumeNoSpecialRole();
|
||||||
}
|
}
|
||||||
@ -42,17 +78,17 @@ public class Context {
|
|||||||
@Transactional(propagation = MANDATORY)
|
@Transactional(propagation = MANDATORY)
|
||||||
public void assumeRoles(final String roles) {
|
public void assumeRoles(final String roles) {
|
||||||
em.createNativeQuery(
|
em.createNativeQuery(
|
||||||
String.format(
|
String.format(
|
||||||
"set local hsadminng.assumedRoles = '%s';",
|
"set local hsadminng.assumedRoles = '%s';",
|
||||||
roles
|
roles
|
||||||
)
|
)
|
||||||
).executeUpdate();
|
).executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = MANDATORY)
|
@Transactional(propagation = MANDATORY)
|
||||||
public void assumeNoSpecialRole() {
|
public void assumeNoSpecialRole() {
|
||||||
em.createNativeQuery(
|
em.createNativeQuery(
|
||||||
"set local hsadminng.assumedRoles = '';"
|
"set local hsadminng.assumedRoles = '';"
|
||||||
).executeUpdate();
|
).executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,4 +96,7 @@ public class Context {
|
|||||||
return (String[]) em.createNativeQuery("select assumedRoles()").getSingleResult();
|
return (String[]) em.createNativeQuery("select assumedRoles()").getSingleResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String shortenToMaxLength(final String task, final int maxLength) {
|
||||||
|
return task.substring(0, Math.min(task.length(), maxLength));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,11 @@ public class CustomerController implements CustomersApi {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<CustomerResource>> listCustomers(
|
public ResponseEntity<List<CustomerResource>> listCustomers(
|
||||||
String userName,
|
String currentUser,
|
||||||
String assumedRoles,
|
String assumedRoles,
|
||||||
String prefix
|
String prefix
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(userName);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
final var result = customerRepository.findCustomerByOptionalPrefixLike(prefix);
|
final var result = customerRepository.findCustomerByOptionalPrefixLike(prefix);
|
||||||
|
|
||||||
@ -50,11 +47,8 @@ public class CustomerController implements CustomersApi {
|
|||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final CustomerResource customer) {
|
final CustomerResource customer) {
|
||||||
|
|
||||||
context.setCurrentTask("create new customer: #" + customer.getReference() + " / " + customer.getPrefix());
|
context.register(currentUser, assumedRoles);
|
||||||
context.setCurrentUser(currentUser);
|
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
if (customer.getUuid() == null) {
|
if (customer.getUuid() == null) {
|
||||||
customer.setUuid(UUID.randomUUID());
|
customer.setUuid(UUID.randomUUID());
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,12 @@ public class PackageController implements PackagesApi {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<PackageResource>> listPackages(
|
public ResponseEntity<List<PackageResource>> listPackages(
|
||||||
String userName,
|
String currentUser,
|
||||||
String assumedRoles,
|
String assumedRoles,
|
||||||
String name
|
String name
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(userName);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
final var result = packageRepository.findAllByOptionalNameLike(name);
|
final var result = packageRepository.findAllByOptionalNameLike(name);
|
||||||
return ResponseEntity.ok(mapList(result, PackageResource.class));
|
return ResponseEntity.ok(mapList(result, PackageResource.class));
|
||||||
}
|
}
|
||||||
@ -49,10 +47,8 @@ public class PackageController implements PackagesApi {
|
|||||||
final UUID packageUuid,
|
final UUID packageUuid,
|
||||||
final PackageUpdateResource body) {
|
final PackageUpdateResource body) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
final var current = packageRepository.findByUuid(packageUuid);
|
final var current = packageRepository.findByUuid(packageUuid);
|
||||||
OptionalFromJson.of(body.getDescription()).ifPresent(current::setDescription);
|
OptionalFromJson.of(body.getDescription()).ifPresent(current::setDescription);
|
||||||
final var saved = packageRepository.save(current);
|
final var saved = packageRepository.save(current);
|
||||||
|
@ -38,10 +38,7 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
final UUID grantedRoleUuid,
|
final UUID grantedRoleUuid,
|
||||||
final UUID granteeUserUuid) {
|
final UUID granteeUserUuid) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
final var id = new RbacGrantId(granteeUserUuid, grantedRoleUuid);
|
final var id = new RbacGrantId(granteeUserUuid, grantedRoleUuid);
|
||||||
final var result = rbacGrantRepository.findById(id);
|
final var result = rbacGrantRepository.findById(id);
|
||||||
@ -57,10 +54,8 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
final String currentUser,
|
final String currentUser,
|
||||||
final String assumedRoles) {
|
final String assumedRoles) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
return ResponseEntity.ok(mapList(rbacGrantRepository.findAll(), RbacGrantResource.class));
|
return ResponseEntity.ok(mapList(rbacGrantRepository.findAll(), RbacGrantResource.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,11 +66,7 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final RbacGrantResource body) {
|
final RbacGrantResource body) {
|
||||||
|
|
||||||
context.setCurrentTask("granting role to user");
|
context.register(currentUser, assumedRoles);
|
||||||
context.setCurrentUser(currentUser);
|
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
final var granted = rbacGrantRepository.save(map(body, RbacGrantEntity.class));
|
final var granted = rbacGrantRepository.save(map(body, RbacGrantEntity.class));
|
||||||
em.flush();
|
em.flush();
|
||||||
@ -97,11 +88,7 @@ public class RbacGrantController implements RbacgrantsApi {
|
|||||||
final UUID grantedRoleUuid,
|
final UUID grantedRoleUuid,
|
||||||
final UUID granteeUserUuid) {
|
final UUID granteeUserUuid) {
|
||||||
|
|
||||||
context.setCurrentTask("revoking role from user");
|
context.register(currentUser, assumedRoles);
|
||||||
context.setCurrentUser(currentUser);
|
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
rbacGrantRepository.deleteByRbacGrantId(new RbacGrantId(granteeUserUuid, grantedRoleUuid));
|
rbacGrantRepository.deleteByRbacGrantId(new RbacGrantId(granteeUserUuid, grantedRoleUuid));
|
||||||
|
|
||||||
|
@ -22,34 +22,34 @@ public class RbacGrantEntity {
|
|||||||
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
|
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
|
||||||
private String grantedByRoleIdName;
|
private String grantedByRoleIdName;
|
||||||
|
|
||||||
@Column(name = "grantedroleidname", updatable = false, insertable = false)
|
|
||||||
private String grantedRoleIdName;
|
|
||||||
|
|
||||||
@Column(name = "username", updatable = false, insertable = false)
|
|
||||||
private String granteeUserName;
|
|
||||||
|
|
||||||
private boolean assumed;
|
|
||||||
|
|
||||||
@Column(name = "grantedbyroleuuid", updatable = false, insertable = false)
|
@Column(name = "grantedbyroleuuid", updatable = false, insertable = false)
|
||||||
private UUID grantedByRoleUuid;
|
private UUID grantedByRoleUuid;
|
||||||
|
|
||||||
|
@Column(name = "grantedroleidname", updatable = false, insertable = false)
|
||||||
|
private String grantedRoleIdName;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "grantedroleuuid")
|
@Column(name = "grantedroleuuid")
|
||||||
private UUID grantedRoleUuid;
|
private UUID grantedRoleUuid;
|
||||||
|
|
||||||
|
@Column(name = "username", updatable = false, insertable = false)
|
||||||
|
private String granteeUserName;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "useruuid")
|
@Column(name = "useruuid")
|
||||||
private UUID granteeUserUuid;
|
private UUID granteeUserUuid;
|
||||||
|
|
||||||
|
private boolean assumed;
|
||||||
|
|
||||||
@Column(name = "objecttable", updatable = false, insertable = false)
|
@Column(name = "objecttable", updatable = false, insertable = false)
|
||||||
private String objectTable;
|
private String objectTable;
|
||||||
|
|
||||||
@Column(name = "objectuuid", updatable = false, insertable = false)
|
|
||||||
private UUID objectUuid;
|
|
||||||
|
|
||||||
@Column(name = "objectidname", updatable = false, insertable = false)
|
@Column(name = "objectidname", updatable = false, insertable = false)
|
||||||
private String objectIdName;
|
private String objectIdName;
|
||||||
|
|
||||||
|
@Column(name = "objectuuid", updatable = false, insertable = false)
|
||||||
|
private UUID objectUuid;
|
||||||
|
|
||||||
@Column(name = "grantedroletype", updatable = false, insertable = false)
|
@Column(name = "grantedroletype", updatable = false, insertable = false)
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private RbacRoleType grantedRoleType;
|
private RbacRoleType grantedRoleType;
|
||||||
|
@ -3,7 +3,6 @@ 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;
|
||||||
@ -26,13 +25,11 @@ public class RbacRoleController implements RbacrolesApi {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<RbacRoleResource>> listRoles(
|
public ResponseEntity<List<RbacRoleResource>> listRoles(
|
||||||
final String currentUser,
|
final String currentUser,
|
||||||
final String assumedRoles) {
|
final String assumedRoles) {
|
||||||
|
|
||||||
|
context.register(currentUser, assumedRoles);
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
return ResponseEntity.ok(mapList(rbacRoleRepository.findAll(), RbacRoleResource.class));
|
return ResponseEntity.ok(mapList(rbacRoleRepository.findAll(), RbacRoleResource.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,7 @@ public class RbacUserController implements RbacusersApi {
|
|||||||
public ResponseEntity<RbacUserResource> createUser(
|
public ResponseEntity<RbacUserResource> createUser(
|
||||||
final RbacUserResource body
|
final RbacUserResource body
|
||||||
) {
|
) {
|
||||||
context.setCurrentTask("creating new user: " + body.getName());
|
context.register(body.getName(), null);
|
||||||
context.setCurrentUser(body.getName());
|
|
||||||
|
|
||||||
if (body.getUuid() == null) {
|
if (body.getUuid() == null) {
|
||||||
body.setUuid(UUID.randomUUID());
|
body.setUuid(UUID.randomUUID());
|
||||||
@ -56,10 +55,7 @@ public class RbacUserController implements RbacusersApi {
|
|||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final UUID userUuid) {
|
final UUID userUuid) {
|
||||||
|
|
||||||
context.setCurrentUser(currentUser);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
final var result = rbacUserRepository.findByUuid(userUuid);
|
final var result = rbacUserRepository.findByUuid(userUuid);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
@ -71,28 +67,24 @@ public class RbacUserController implements RbacusersApi {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<RbacUserResource>> listUsers(
|
public ResponseEntity<List<RbacUserResource>> listUsers(
|
||||||
final String currentUserName,
|
final String currentUser,
|
||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final String userName
|
final String userName
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(currentUserName);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
return ResponseEntity.ok(mapList(rbacUserRepository.findByOptionalNameLike(userName), RbacUserResource.class));
|
return ResponseEntity.ok(mapList(rbacUserRepository.findByOptionalNameLike(userName), RbacUserResource.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<RbacUserPermissionResource>> listUserPermissions(
|
public ResponseEntity<List<RbacUserPermissionResource>> listUserPermissions(
|
||||||
final String currentUserName,
|
final String currentUser,
|
||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final UUID userUuid
|
final UUID userUuid
|
||||||
) {
|
) {
|
||||||
context.setCurrentUser(currentUserName);
|
context.register(currentUser, assumedRoles);
|
||||||
if (!StringUtils.isBlank(assumedRoles)) {
|
|
||||||
context.assumeRoles(assumedRoles);
|
|
||||||
}
|
|
||||||
return ResponseEntity.ok(mapList(rbacUserRepository.findPermissionsOfUserByUuid(userUuid), RbacUserPermissionResource.class));
|
return ResponseEntity.ok(mapList(rbacUserRepository.findPermissionsOfUserByUuid(userUuid), RbacUserPermissionResource.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,15 @@ class ContextIntegrationTests {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void registerWithoutHttpServletRequestUsesCallStack() {
|
||||||
|
|
||||||
|
context.register("current-user", null);
|
||||||
|
|
||||||
|
final var currentTask = context.getCurrentTask();
|
||||||
|
assertThat(currentTask).isEqualTo("ContextIntegrationTests.registerWithoutHttpServletRequestUsesCallStack");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
void setCurrentUser() {
|
void setCurrentUser() {
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package net.hostsharing.hsadminng.context;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.Query;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class ContextUnitTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
EntityManager em;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
Query nativeQuery;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void registerWithoutHttpServletRequestUsesCallStack() {
|
||||||
|
given(em.createNativeQuery(any())).willReturn(nativeQuery);
|
||||||
|
|
||||||
|
context.register("current-user", null);
|
||||||
|
|
||||||
|
verify(em).createNativeQuery(
|
||||||
|
"set local hsadminng.currentTask = 'ContextUnitTest.registerWithoutHttpServletRequestUsesCallStack';");
|
||||||
|
}
|
||||||
|
}
|
@ -118,9 +118,9 @@ class CustomerControllerAcceptanceTest {
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"reference": 90010,
|
"reference": 90020,
|
||||||
"prefix": "vvv",
|
"prefix": "ttt",
|
||||||
"adminUserName": "customer-admin@vvv.example.com"
|
"adminUserName": "customer-admin@ttt.example.com"
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
.port(port)
|
.port(port)
|
||||||
@ -129,16 +129,54 @@ class CustomerControllerAcceptanceTest {
|
|||||||
.then().assertThat()
|
.then().assertThat()
|
||||||
.statusCode(201)
|
.statusCode(201)
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("prefix", is("vvv"))
|
.body("prefix", is("ttt"))
|
||||||
.header("Location", startsWith("http://localhost"))
|
.header("Location", startsWith("http://localhost"))
|
||||||
.extract().header("Location"); // @formatter:on
|
.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@ttt.example.com");
|
||||||
|
assertThat(customerRepository.findByUuid(newUserUuid))
|
||||||
|
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("ttt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hostsharingAdmin_withoutAssumedRole_canCreateCustomerWithGivenUuid() {
|
||||||
|
|
||||||
|
final var givenUuid = UUID.randomUUID();
|
||||||
|
|
||||||
|
final var location = RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-user", "mike@hostsharing.net")
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("""
|
||||||
|
{
|
||||||
|
"uuid": "%s",
|
||||||
|
"reference": 90010,
|
||||||
|
"prefix": "vvv",
|
||||||
|
"adminUserName": "customer-admin@vvv.example.com"
|
||||||
|
}
|
||||||
|
""".formatted(givenUuid))
|
||||||
|
.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
|
// finally, the new customer can be viewed by its own admin
|
||||||
final var newUserUuid = UUID.fromString(
|
final var newUserUuid = UUID.fromString(
|
||||||
location.substring(location.lastIndexOf('/') + 1));
|
location.substring(location.lastIndexOf('/') + 1));
|
||||||
context.setCurrentUser("customer-admin@vvv.example.com");
|
context.setCurrentUser("customer-admin@vvv.example.com");
|
||||||
assertThat(customerRepository.findByUuid(newUserUuid))
|
assertThat(customerRepository.findByUuid(newUserUuid))
|
||||||
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("vvv"));
|
.hasValueSatisfying(c -> {
|
||||||
|
assertThat(c.getPrefix()).isEqualTo("vvv");
|
||||||
|
assertThat(c.getUuid()).isEqualTo(givenUuid);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,152 +0,0 @@
|
|||||||
package net.hostsharing.hsadminng.hs.hspackage;
|
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration;
|
|
||||||
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.context.ContextConfiguration;
|
|
||||||
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.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
||||||
|
|
||||||
@WebMvcTest(PackageController.class)
|
|
||||||
@ContextConfiguration(classes = { PackageController.class, JsonObjectMapperConfiguration.class })
|
|
||||||
class PackageControllerRestTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
MockMvc mockMvc;
|
|
||||||
@MockBean
|
|
||||||
Context contextMock;
|
|
||||||
@MockBean
|
|
||||||
PackageRepository packageRepositoryMock;
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
class ListPackages {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void withoutNameParameter() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
final var givenPacs = List.of(TestPackage.xxx00, TestPackage.xxx01, TestPackage.xxx02);
|
|
||||||
when(packageRepositoryMock.findAllByOptionalNameLike(null)).thenReturn(givenPacs);
|
|
||||||
|
|
||||||
// when
|
|
||||||
mockMvc.perform(MockMvcRequestBuilders
|
|
||||||
.get("/api/packages")
|
|
||||||
.header("current-user", "mike@hostsharing.net")
|
|
||||||
.header("assumed-roles", "customer#xxx.admin")
|
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
|
||||||
|
|
||||||
// then
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$", hasSize(3)))
|
|
||||||
.andExpect(jsonPath("$[0].name", is("xxx00")))
|
|
||||||
.andExpect(jsonPath("$[1].uuid", is(TestPackage.xxx01.getUuid().toString())))
|
|
||||||
.andExpect(jsonPath("$[2].customer.prefix", is("xxx")));
|
|
||||||
|
|
||||||
verify(contextMock).setCurrentUser("mike@hostsharing.net");
|
|
||||||
verify(contextMock).assumeRoles("customer#xxx.admin");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void withNameParameter() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
final var givenPacs = List.of(TestPackage.xxx01);
|
|
||||||
when(packageRepositoryMock.findAllByOptionalNameLike("xxx01")).thenReturn(givenPacs);
|
|
||||||
|
|
||||||
// when
|
|
||||||
mockMvc.perform(MockMvcRequestBuilders
|
|
||||||
.get("/api/packages?name=xxx01")
|
|
||||||
.header("current-user", "mike@hostsharing.net")
|
|
||||||
.header("assumed-roles", "customer#xxx.admin")
|
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
|
||||||
|
|
||||||
// then
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$", hasSize(1)))
|
|
||||||
.andExpect(jsonPath("$[0].name", is("xxx01")));
|
|
||||||
|
|
||||||
verify(contextMock).setCurrentUser("mike@hostsharing.net");
|
|
||||||
verify(contextMock).assumeRoles("customer#xxx.admin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
class updatePackage {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void withDescriptionUpdatesDescription() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
final var givenPac = TestPackage.xxx01;
|
|
||||||
when(packageRepositoryMock.findByUuid(givenPac.getUuid())).thenReturn(givenPac);
|
|
||||||
when(packageRepositoryMock.save(any())).thenAnswer(invocation -> invocation.getArgument(0));
|
|
||||||
|
|
||||||
// when
|
|
||||||
mockMvc.perform(MockMvcRequestBuilders
|
|
||||||
.patch("/api/packages/" + givenPac.getUuid().toString())
|
|
||||||
.header("current-user", "mike@hostsharing.net")
|
|
||||||
.header("assumed-roles", "customer#xxx.admin")
|
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
|
||||||
.content("""
|
|
||||||
{
|
|
||||||
"description": "some description"
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
|
||||||
|
|
||||||
// then
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("description", is("some description")));
|
|
||||||
|
|
||||||
verify(contextMock).setCurrentUser("mike@hostsharing.net");
|
|
||||||
verify(contextMock).assumeRoles("customer#xxx.admin");
|
|
||||||
verify(packageRepositoryMock).save(argThat(entity ->
|
|
||||||
entity.getDescription().equals("some description") &&
|
|
||||||
entity.getUuid().equals(givenPac.getUuid())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void withoutDescriptionDoesNothing() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
final var givenPac = TestPackage.xxx01;
|
|
||||||
when(packageRepositoryMock.findByUuid(givenPac.getUuid())).thenReturn(givenPac);
|
|
||||||
when(packageRepositoryMock.save(any())).thenAnswer(invocation -> invocation.getArgument(0));
|
|
||||||
|
|
||||||
// when
|
|
||||||
mockMvc.perform(MockMvcRequestBuilders
|
|
||||||
.patch("/api/packages/" + givenPac.getUuid().toString())
|
|
||||||
.header("current-user", "mike@hostsharing.net")
|
|
||||||
.header("assumed-roles", "customer#xxx.admin")
|
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
|
||||||
.content("{}")
|
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
|
||||||
|
|
||||||
// then
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("description", is(givenPac.getDescription())));
|
|
||||||
|
|
||||||
verify(contextMock).setCurrentUser("mike@hostsharing.net");
|
|
||||||
verify(contextMock).assumeRoles("customer#xxx.admin");
|
|
||||||
verify(packageRepositoryMock).save(argThat(entity ->
|
|
||||||
givenPac.getDescription().equals(entity.getDescription()) &&
|
|
||||||
givenPac.getUuid().equals(entity.getUuid())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,63 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacgrant;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleType;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class RbacGrantEntityUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getRbacGrantId() {
|
||||||
|
// given
|
||||||
|
final var grantedRoleUuid = UUID.randomUUID();
|
||||||
|
final var granteeUserUuid = UUID.randomUUID();
|
||||||
|
final var entity = new RbacGrantEntity();
|
||||||
|
entity.setGrantedRoleUuid(grantedRoleUuid);
|
||||||
|
entity.setGranteeUserUuid(granteeUserUuid);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var grantId = entity.getRbacGrantId();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(grantId).isEqualTo(new RbacGrantId(granteeUserUuid, grantedRoleUuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toDisplayAssumed() {
|
||||||
|
// given
|
||||||
|
final var entity = new RbacGrantEntity( // @formatter:off
|
||||||
|
"GrantER", UUID.randomUUID(),
|
||||||
|
"GrantED", UUID.randomUUID(),
|
||||||
|
"GrantEE", UUID.randomUUID(),
|
||||||
|
true,
|
||||||
|
"ObjectTable", "ObjectId", UUID.randomUUID(),
|
||||||
|
RbacRoleType.admin); // @formatter:on
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var display = entity.toDisplay();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(display).isEqualTo("{ grant assumed role GrantED to user GrantEE by role GrantER }");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toDisplayNotAssumed() {
|
||||||
|
// given
|
||||||
|
final var entity = new RbacGrantEntity( // @formatter:off
|
||||||
|
"GrantER", UUID.randomUUID(),
|
||||||
|
"GrantED", UUID.randomUUID(),
|
||||||
|
"GrantEE", UUID.randomUUID(),
|
||||||
|
false,
|
||||||
|
"ObjectTable", "ObjectId", UUID.randomUUID(),
|
||||||
|
RbacRoleType.owner); // @formatter:on
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var display = entity.toDisplay();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(display).isEqualTo("{ grant role GrantED to user GrantEE by role GrantER }");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.test.IsValidUuidMatcher.isValidUuid;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@WebMvcTest(RbacUserController.class)
|
||||||
|
class RbacUserControllerRestTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mockMvc;
|
||||||
|
@MockBean
|
||||||
|
Context contextMock;
|
||||||
|
@MockBean
|
||||||
|
RbacUserRepository rbacUserRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createUserUsesGivenUuid() throws Exception {
|
||||||
|
// given
|
||||||
|
final var givenUuid = UUID.randomUUID();
|
||||||
|
|
||||||
|
// when
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders
|
||||||
|
.post("/api/rbac-users")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""
|
||||||
|
{
|
||||||
|
"uuid": "%s"
|
||||||
|
}
|
||||||
|
""".formatted(givenUuid))
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
|
||||||
|
// then
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("uuid", is(givenUuid.toString())));
|
||||||
|
|
||||||
|
// then
|
||||||
|
verify(rbacUserRepository).create(argThat(entity -> entity.getUuid().equals(givenUuid)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createUserGeneratesRandomUuidIfNotGiven() throws Exception {
|
||||||
|
// when
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders
|
||||||
|
.post("/api/rbac-users")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{}")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
|
||||||
|
// then
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("uuid", isValidUuid()));
|
||||||
|
|
||||||
|
// then
|
||||||
|
verify(rbacUserRepository).create(argThat(entity -> entity.getUuid() != null));
|
||||||
|
}
|
||||||
|
}
|
37
src/test/java/net/hostsharing/test/IsValidUuidMatcher.java
Normal file
37
src/test/java/net/hostsharing/test/IsValidUuidMatcher.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package net.hostsharing.test;
|
||||||
|
|
||||||
|
import org.hamcrest.BaseMatcher;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class IsValidUuidMatcher extends BaseMatcher<CharSequence> {
|
||||||
|
|
||||||
|
public static Matcher<CharSequence> isValidUuid() {
|
||||||
|
return new IsValidUuidMatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isValidUuid(final String actual) {
|
||||||
|
try {
|
||||||
|
UUID.fromString(actual);
|
||||||
|
} catch (final IllegalArgumentException exc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(final Object actual) {
|
||||||
|
if (actual == null || actual.getClass().isAssignableFrom(CharSequence.class)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isValidUuid(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(final Description description) {
|
||||||
|
description.appendText("valid UUID");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user