introduce separate database-schemas base+rbac #103

Merged
hsh-michaelhoennig merged 54 commits from introduce-separate-database-schemas-base-and-rbac into master 2024-09-16 15:36:38 +02:00
60 changed files with 376 additions and 384 deletions
Showing only changes of commit cb49292871 - Show all commits

View File

@ -29,7 +29,7 @@ skinparam linetype ortho
package RBAC {
' forward declarations
entity RbacUser
entity RbacSubject
together {
@ -37,8 +37,8 @@ package RBAC {
entity RbacPermission
RbacUser -[hidden]> RbacRole
RbacRole -[hidden]> RbacUser
RbacSubject -[hidden]> RbacRole
RbacRole -[hidden]> RbacSubject
}
together {
@ -57,11 +57,11 @@ package RBAC {
RbacGrant o-u-> RbacReference
enum RbacReferenceType {
RbacUser
RbacSubject
RbacRole
RbacPermission
}
RbacReferenceType ..> RbacUser
RbacReferenceType ..> RbacSubject
RbacReferenceType ..> RbacRole
RbacReferenceType ..> RbacPermission
@ -71,12 +71,12 @@ package RBAC {
type : RbacReferenceType
}
RbacReference o--> RbacReferenceType
entity RbacUser {
entity RbacSubject {
*uuid : uuid <<generated>>
--
name : varchar
}
RbacUser o-- RbacReference
RbacSubject o-- RbacReference
entity RbacRole {
*uuid : uuid(RbacReference)
@ -143,20 +143,20 @@ The primary key of the *RbacReference* and its referred object is always identic
#### RbacReferenceType
The enum *RbacReferenceType* describes the type of reference.
It's only needed to make it easier to find the referred object in *RbacUser*, *RbacRole* or *RbacPermission*.
It's only needed to make it easier to find the referred object in *RbacSubject*, *RbacRole* or *RbacPermission*.
#### RbacUser
#### RbacSubject
An *RbacUser* is a type of RBAC-subject which references a login account outside this system, identified by a name (usually an email-address).
An *RbacSubject* is a type of RBAC-subject which references a login account outside this system, identified by a name (usually an email-address).
*RbacUser*s can be assigned to multiple *RbacRole*s, through which they can get permissions to *RbacObject*s.
*RbacSubject*s can be assigned to multiple *RbacRole*s, through which they can get permissions to *RbacObject*s.
The primary key of the *RbacUser* is identical to its related *RbacReference*.
The primary key of the *RbacSubject* is identical to its related *RbacReference*.
#### RbacRole
An *RbacRole* represents a collection of directly or indirectly assigned *RbacPermission*s.
Each *RbacRole* can be assigned to *RbacUser*s or to another *RbacRole*.
Each *RbacRole* can be assigned to *RbacSubject*s or to another *RbacRole*.
Both kinds of assignments are represented via *RbacGrant*.
@ -184,7 +184,7 @@ Only with this rule, the foreign key in *RbacPermission* can be defined as `NOT
#### RbacGrant
The *RbacGrant* entities represent the access-rights structure from *RbacUser*s via hierarchical *RbacRoles* down to *RbacPermission*s.
The *RbacGrant* entities represent the access-rights structure from *RbacSubject*s via hierarchical *RbacRoles* down to *RbacPermission*s.
The core SQL queries to determine access rights are all recursive queries on the *RbacGrant* table.
@ -284,7 +284,7 @@ hide circle
' use right-angled line routing
' skinparam linetype ortho
package RbacUsers {
package RbacSubjects {
object UserMike
object UserSuse
object UserPaul
@ -296,7 +296,7 @@ package RbacRoles {
object RoleCustXyz_Admin
object RolePackXyz00_Owner
}
RbacUsers -[hidden]> RbacRoles
RbacSubjects -[hidden]> RbacRoles
package RbacPermissions {
object PermCustXyz_SELECT
@ -365,7 +365,7 @@ This way, each user can only select the data they have 'SELECT'-permission for,
### Current User
The current use is taken from the session variable `hsadminng.currentSubject` which contains the name of the user as stored in the
*RbacUser*s table. Example:
*RbacSubject*s table. Example:
SET LOCAL hsadminng.currentSubject = 'mike@hostsharing.net';
@ -671,9 +671,9 @@ Access Control for business objects checked according to the assigned roles.
But we decided not to create such roles and permissions for the RBAC-Objects itself.
It would have overcomplicated the system and the necessary information can easily be added to the RBAC-Objects itself, mostly the `RbacGrant`s.
### RbacUser
### RbacSubject
Users can self-register, thus to create a new RbacUser entity, no login is required.
Users can self-register, thus to create a new RbacSubject entity, no login is required.
But such a user has no access-rights except viewing itself.
Users can view themselves.

View File

@ -9,21 +9,21 @@ select isGranted(findRoleId('test_package#aaa00:OWNER'), findRoleId('administrat
-- call grantRoleToRole(findRoleId('administrators'), findRoleId('test_package#aaa00:OWNER'));
select count(*)
FROM queryAllPermissionsOfSubjectIdForObjectUuids(findRbacUser('superuser-fran@hostsharing.net'),
FROM queryAllPermissionsOfSubjectIdForObjectUuids(findRbacSubject('superuser-fran@hostsharing.net'),
ARRAY(select uuid from customer where reference < 1100000));
select count(*)
FROM queryAllPermissionsOfSubjectId(findRbacUser('superuser-fran@hostsharing.net'));
FROM queryAllPermissionsOfSubjectId(findRbacSubject('superuser-fran@hostsharing.net'));
select *
FROM queryAllPermissionsOfSubjectId(findRbacUser('alex@example.com'));
FROM queryAllPermissionsOfSubjectId(findRbacSubject('alex@example.com'));
select *
FROM queryAllPermissionsOfSubjectId(findRbacUser('rosa@example.com'));
FROM queryAllPermissionsOfSubjectId(findRbacSubject('rosa@example.com'));
select *
FROM queryAllRbacUsersWithPermissionsFor(findEffectivePermissionId('customer',
FROM queryAllRbacSubjectsWithPermissionsFor(findEffectivePermissionId('customer',
(SELECT uuid FROM RbacObject WHERE objectTable = 'customer' LIMIT 1),
'add-package'));
select *
FROM queryAllRbacUsersWithPermissionsFor(findEffectivePermissionId('package',
FROM queryAllRbacSubjectsWithPermissionsFor(findEffectivePermissionId('package',
(SELECT uuid FROM RbacObject WHERE objectTable = 'package' LIMIT 1),
'DELETE'));
@ -33,7 +33,7 @@ $$
userId uuid;
result bool;
BEGIN
userId = findRbacUser('superuser-alex@hostsharing.net');
userId = findRbacSubject('superuser-alex@hostsharing.net');
result = (SELECT * FROM isPermissionGrantedToSubject(findPermissionId('package', 94928, 'add-package'), userId));
IF (result) THEN
RAISE EXCEPTION 'expected permission NOT to be granted, but it is';

View File

@ -38,7 +38,7 @@ CREATE OR REPLACE RULE "_RETURN" AS
SELECT * FROM customer WHERE isPermissionGrantedToSubject(findEffectivePermissionId('test_customer', id, 'SELECT'), rbac.currentSubjectUuid());
SELECT * from cust_view LIMIT 10;
select queryAllPermissionsOfSubjectId(findRbacUser('superuser-alex@hostsharing.net'));
select queryAllPermissionsOfSubjectId(findRbacSubject('superuser-alex@hostsharing.net'));
-- access control via view-rule with join to recursive permissions - really fast (38ms for 1 million rows)
SET SESSION SESSION AUTHORIZATION DEFAULT;
@ -80,10 +80,10 @@ SELECT * from cust_view where reference=1144150;
select rr.uuid, rr.type from RbacGrants g
join RbacReference RR on g.ascendantUuid = RR.uuid
where g.descendantUuid in (
select uuid from queryAllPermissionsOfSubjectId(findRbacUser('alex@example.com'))
select uuid from queryAllPermissionsOfSubjectId(findRbacSubject('alex@example.com'))
where objectTable='test_customer');
call grantRoleToUser(findRoleId('test_customer#aaa:ADMIN'), findRbacUser('aaaaouq@example.com'));
call grantRoleToUser(findRoleId('test_customer#aaa:ADMIN'), findRbacSubject('aaaaouq@example.com'));
select queryAllPermissionsOfSubjectId(findRbacUser('aaaaouq@example.com'));
select queryAllPermissionsOfSubjectId(findRbacSubject('aaaaouq@example.com'));

View File

@ -22,7 +22,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.DELETE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.UPDATE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.GUEST;

View File

@ -14,7 +14,7 @@ import java.util.UUID;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;

View File

@ -11,7 +11,7 @@ import java.io.IOException;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;

View File

@ -45,7 +45,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.DELETE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.UPDATE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.OWNER;

View File

@ -16,7 +16,7 @@ import java.util.UUID;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;

View File

@ -24,7 +24,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.DELETE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.UPDATE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.OWNER;

View File

@ -26,7 +26,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingD
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;

View File

@ -27,7 +27,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingD
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.PERM_TO_ROLE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.ROLE_TO_ROLE;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.Part.AUTO_FETCH;
import static org.apache.commons.collections4.SetUtils.hashSet;
import static org.apache.commons.lang3.StringUtils.uncapitalize;
@ -41,7 +41,7 @@ public class RbacView {
private final EntityAlias rootEntityAlias;
private final Set<RbacUserReference> userDefs = new LinkedHashSet<>();
private final Set<RbacSubjectReference> userDefs = new LinkedHashSet<>();
private final Set<RbacRoleDefinition> roleDefs = new LinkedHashSet<>();
private final Set<RbacPermissionDefinition> permDefs = new LinkedHashSet<>();
private final Map<String, EntityAlias> entityAliases = new HashMap<>() {
@ -97,7 +97,7 @@ public class RbacView {
RbacView(final String alias, final Class<? extends BaseEntity> entityClass) {
rootEntityAlias = new EntityAlias(alias, entityClass);
entityAliases.put(alias, rootEntityAlias);
new RbacUserReference(CREATOR);
new RbacSubjectReference(CREATOR);
entityAliases.put("global", new EntityAlias("global"));
}
@ -467,7 +467,7 @@ public class RbacView {
return new RbacExampleRole(entityAlias, role);
}
private RbacGrantDefinition grantRoleToSubject(final RbacRoleDefinition roleDefinition, final RbacUserReference user) {
private RbacGrantDefinition grantRoleToSubject(final RbacRoleDefinition roleDefinition, final RbacSubjectReference user) {
return findOrCreateGrantDef(roleDefinition, user).toCreate();
}
@ -564,7 +564,7 @@ public class RbacView {
@EqualsAndHashCode
public class RbacGrantDefinition {
private final RbacUserReference userDef;
private final RbacSubjectReference userDef;
private final RbacRoleDefinition superRoleDef;
private final RbacRoleDefinition subRoleDef;
private final RbacPermissionDefinition permDef;
@ -605,7 +605,7 @@ public class RbacView {
register(this);
}
public RbacGrantDefinition(final RbacRoleDefinition roleDef, final RbacUserReference userDef) {
public RbacGrantDefinition(final RbacRoleDefinition roleDef, final RbacSubjectReference userDef) {
this.userDef = userDef;
this.subRoleDef = roleDef;
this.superRoleDef = null;
@ -770,7 +770,7 @@ public class RbacView {
* @return
* The grant definition for further chained calls.
*/
public RbacGrantDefinition owningUser(final RbacUserReference.UserRole userRole) {
public RbacGrantDefinition owningUser(final RbacSubjectReference.UserRole userRole) {
return grantRoleToSubject(this, findUserRef(userRole));
}
@ -833,12 +833,12 @@ public class RbacView {
}
}
public RbacUserReference findUserRef(final RbacUserReference.UserRole userRole) {
public RbacSubjectReference findUserRef(final RbacSubjectReference.UserRole userRole) {
return userDefs.stream().filter(u -> u.role == userRole).findFirst().orElseThrow();
}
@EqualsAndHashCode
public class RbacUserReference {
public class RbacSubjectReference {
public enum UserRole {
GLOBAL_ADMIN,
@ -847,7 +847,7 @@ public class RbacView {
final UserRole role;
public RbacUserReference(final UserRole creator) {
public RbacSubjectReference(final UserRole creator) {
this.role = creator;
userDefs.add(this);
}
@ -885,7 +885,7 @@ public class RbacView {
.orElseGet(() -> new RbacPermissionDefinition(entityAlias, perm, tableName, true)); // TODO: true => toCreate
}
private RbacGrantDefinition findOrCreateGrantDef(final RbacRoleDefinition roleDefinition, final RbacUserReference user) {
private RbacGrantDefinition findOrCreateGrantDef(final RbacRoleDefinition roleDefinition, final RbacSubjectReference user) {
return grantDefs.stream()
.filter(g -> g.subRoleDef == roleDefinition && g.userDef == user)
.findFirst()

View File

@ -578,7 +578,7 @@ class RolesGrantsAndPermissionsGenerator {
plPgSql.writeLn();
}
private String toPlPgSqlReference(final RbacView.RbacUserReference userRef) {
private String toPlPgSqlReference(final RbacView.RbacSubjectReference userRef) {
return switch (userRef.role) {
case CREATOR -> "currentSubjectUuid()";
default -> throw new IllegalArgumentException("unknown user role: " + userRef);

View File

@ -50,7 +50,7 @@ public class RbacGrantController implements RbacGrantsApi {
@Override
@Transactional(readOnly = true)
public ResponseEntity<List<RbacGrantResource>> listUserGrants(
public ResponseEntity<List<RbacGrantResource>> listSubjectGrants(
final String currentSubject,
final String assumedRoles) {
@ -97,7 +97,7 @@ public class RbacGrantController implements RbacGrantsApi {
// TODO.feat: implement an endpoint to create a Mermaid flowchart with all grants of a given user
// @GetMapping(
// path = "/api/rbac/users/{subjectUuid}/grants",
// path = "/api/rbac/subjects/{subjectUuid}/grants",
// produces = {"text/vnd.mermaid"})
// @Transactional(readOnly = true)
// public ResponseEntity<String> allGrantsOfUserAsMermaid(

View File

@ -33,7 +33,7 @@ public class RbacGrantEntity {
private UUID grantedRoleUuid;
@Column(name = "username", updatable = false, insertable = false)
private String granteeUserName;
private String granteeSubjectName;
@Id
@Column(name = "subjectuuid")
@ -60,7 +60,7 @@ public class RbacGrantEntity {
public String toDisplay() {
return "{ grant role:" + grantedRoleIdName +
" to user:" + granteeUserName +
" to user:" + granteeSubjectName +
" by role:" + grantedByRoleIdName +
(assumed ? " and assume" : "") +
" }";

View File

@ -1,46 +0,0 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import java.util.List;
import java.util.UUID;
public interface RbacUserRepository extends Repository<RbacUserEntity, UUID> {
@Query("""
select u from RbacUserEntity u
where :userName is null or u.name like concat(cast(:userName as text), '%')
order by u.name
""")
List<RbacUserEntity> findByOptionalNameLike(String userName);
// bypasses the restricted view, to be able to grant rights to arbitrary user
@Query(value = "select * from rbac.subject where name=:userName", nativeQuery = true)
RbacUserEntity findByName(String userName);
RbacUserEntity findByUuid(UUID uuid);
@Query(value = "select * from grantedPermissions(:subjectUuid)", nativeQuery = true)
List<RbacUserPermission> findPermissionsOfUserByUuid(UUID subjectUuid);
/*
Can't use save/saveAndFlush from SpringData because the uuid is not generated on the entity level,
but explicitly, and then SpringData check's if it exists using an SQL SELECT.
And SQL SELECT needs a currentSubject which we don't yet have in the case of self registration.
*/
@Modifying
@Query(value = "insert into RBacUser_RV (uuid, name) values( :#{#newUser.uuid}, :#{#newUser.name})", nativeQuery = true)
void insert(final RbacUserEntity newUser);
default RbacUserEntity create(final RbacUserEntity rbacUserEntity) {
if (rbacUserEntity.getUuid() == null) {
rbacUserEntity.setUuid(UUID.randomUUID());
}
insert(rbacUserEntity);
return rbacUserEntity;
}
void deleteByUuid(UUID subjectUuid);
}

View File

@ -1,10 +1,10 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
package net.hostsharing.hsadminng.rbac.subject;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.mapper.Mapper;
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacUsersApi;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacUserPermissionResource;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacUserResource;
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacSubjectsApi;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacSubjectPermissionResource;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacSubjectResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
@ -15,7 +15,7 @@ import java.util.List;
import java.util.UUID;
@RestController
public class RbacUserController implements RbacUsersApi {
public class RbacSubjectController implements RbacSubjectsApi {
@Autowired
private Context context;
@ -24,73 +24,73 @@ public class RbacUserController implements RbacUsersApi {
private Mapper mapper;
@Autowired
private RbacUserRepository rbacUserRepository;
private RbacSubjectRepository rbacSubjectRepository;
@Override
@Transactional
public ResponseEntity<RbacUserResource> createUser(
final RbacUserResource body
public ResponseEntity<RbacSubjectResource> createSubject(
final RbacSubjectResource body
) {
context.define(null);
if (body.getUuid() == null) {
body.setUuid(UUID.randomUUID());
}
final var saved = mapper.map(body, RbacUserEntity.class);
rbacUserRepository.create(saved);
final var saved = mapper.map(body, RbacSubjectEntity.class);
rbacSubjectRepository.create(saved);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/rbac.yaml/users/{id}")
.buildAndExpand(saved.getUuid())
.toUri();
return ResponseEntity.created(uri).body(mapper.map(saved, RbacUserResource.class));
return ResponseEntity.created(uri).body(mapper.map(saved, RbacSubjectResource.class));
}
@Override
@Transactional
public ResponseEntity<Void> deleteUserByUuid(
public ResponseEntity<Void> deleteSubjectByUuid(
final String currentSubject,
final String assumedRoles,
final UUID subjectUuid
) {
context.define(currentSubject, assumedRoles);
rbacUserRepository.deleteByUuid(subjectUuid);
rbacSubjectRepository.deleteByUuid(subjectUuid);
return ResponseEntity.noContent().build();
}
@Override
@Transactional(readOnly = true)
public ResponseEntity<RbacUserResource> getUserById(
public ResponseEntity<RbacSubjectResource> getSubjectById(
final String currentSubject,
final String assumedRoles,
final UUID subjectUuid) {
context.define(currentSubject, assumedRoles);
final var result = rbacUserRepository.findByUuid(subjectUuid);
final var result = rbacSubjectRepository.findByUuid(subjectUuid);
if (result == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(mapper.map(result, RbacUserResource.class));
return ResponseEntity.ok(mapper.map(result, RbacSubjectResource.class));
}
@Override
@Transactional(readOnly = true)
public ResponseEntity<List<RbacUserResource>> listUsers(
public ResponseEntity<List<RbacSubjectResource>> listSubjects(
final String currentSubject,
final String assumedRoles,
final String userName
) {
context.define(currentSubject, assumedRoles);
return ResponseEntity.ok(mapper.mapList(rbacUserRepository.findByOptionalNameLike(userName), RbacUserResource.class));
return ResponseEntity.ok(mapper.mapList(rbacSubjectRepository.findByOptionalNameLike(userName), RbacSubjectResource.class));
}
@Override
@Transactional(readOnly = true)
public ResponseEntity<List<RbacUserPermissionResource>> listUserPermissions(
public ResponseEntity<List<RbacSubjectPermissionResource>> listSubjectPermissions(
final String currentSubject,
final String assumedRoles,
final UUID subjectUuid
@ -98,7 +98,7 @@ public class RbacUserController implements RbacUsersApi {
context.define(currentSubject, assumedRoles);
return ResponseEntity.ok(mapper.mapList(
rbacUserRepository.findPermissionsOfUserByUuid(subjectUuid),
RbacUserPermissionResource.class));
rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid),
RbacSubjectPermissionResource.class));
}
}

View File

@ -1,4 +1,4 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
package net.hostsharing.hsadminng.rbac.subject;
import lombok.*;
import org.springframework.data.annotation.Immutable;
@ -13,14 +13,14 @@ import java.time.temporal.ChronoUnit;
import java.util.UUID;
@Entity
@Table(name = "rbacuser_rv")
@Table(schema = "rbac", name = "subject_rv")
@Getter
@Setter
@ToString
@Immutable
@NoArgsConstructor
@AllArgsConstructor
public class RbacUserEntity {
public class RbacSubjectEntity {
private static final int MAX_VALIDITY_DAYS = 21;
private static DateTimeFormatter DATE_FORMAT_WITH_FULLHOUR = DateTimeFormatter.ofPattern("MM-dd-yyyy HH");

View File

@ -1,8 +1,8 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
package net.hostsharing.hsadminng.rbac.subject;
import java.util.UUID;
public interface RbacUserPermission {
public interface RbacSubjectPermission {
UUID getRoleUuid();
String getRoleName();

View File

@ -0,0 +1,46 @@
package net.hostsharing.hsadminng.rbac.subject;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import java.util.List;
import java.util.UUID;
public interface RbacSubjectRepository extends Repository<RbacSubjectEntity, UUID> {
@Query("""
select u from RbacSubjectEntity u
where :userName is null or u.name like concat(cast(:userName as text), '%')
order by u.name
""")
List<RbacSubjectEntity> findByOptionalNameLike(String userName);
// bypasses the restricted view, to be able to grant rights to arbitrary user
@Query(value = "select * from rbac.subject where name=:userName", nativeQuery = true)
RbacSubjectEntity findByName(String userName);
RbacSubjectEntity findByUuid(UUID uuid);
@Query(value = "select * from rbac.grantedPermissions(:subjectUuid)", nativeQuery = true)
List<RbacSubjectPermission> findPermissionsOfUserByUuid(UUID subjectUuid);
/*
Can't use save/saveAndFlush from SpringData because the uuid is not generated on the entity level,
but explicitly, and then SpringData check's if it exists using an SQL SELECT.
And SQL SELECT needs a currentSubject which we don't yet have in the case of self registration.
*/
@Modifying
@Query(value = "insert into rbac.subject_rv (uuid, name) values( :#{#newUser.uuid}, :#{#newUser.name})", nativeQuery = true)
void insert(final RbacSubjectEntity newUser);
default RbacSubjectEntity create(final RbacSubjectEntity rbacSubjectEntity) {
if (rbacSubjectEntity.getUuid() == null) {
rbacSubjectEntity.setUuid(UUID.randomUUID());
}
insert(rbacSubjectEntity);
return rbacSubjectEntity;
}
void deleteByUuid(UUID subjectUuid);
}

View File

@ -15,7 +15,7 @@ import java.util.UUID;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;

View File

@ -9,7 +9,7 @@ components:
required: true
schema:
type: string
description: Identifying name of the currently logged in user.
description: Identifying name of the current subject (e.g. user).
assumedRoles:
name: assumed-roles
@ -17,4 +17,4 @@ components:
required: false
schema:
type: string
description: Semicolon-separated list of roles to assume. The current user needs to have the right to assume these roles.
description: Semicolon-separated list of roles to assume. The current subject needs to have the right to assume these roles.

View File

@ -8,13 +8,13 @@ components:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: The current user is unknown or not authorized.
description: The current subject is unknown or not authorized.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Forbidden:
description: The current user or none of the assumed or roles is granted access to the resource.
description: The current subject or none of the assumed or roles is granted access to the resource.
content:
application/json:
schema:

View File

@ -9,7 +9,7 @@ components:
required: true
schema:
type: string
description: Identifying name of the currently logged in user.
description: Identifying name of the currently logged in subject.
assumedRoles:
name: assumed-roles
@ -17,4 +17,4 @@ components:
required: false
schema:
type: string
description: Semicolon-separated list of roles to assume. The current user needs to have the right to assume these roles.
description: Semicolon-separated list of roles to assume. The current subject needs to have the right to assume these roles.

View File

@ -8,13 +8,13 @@ components:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: The current user is unknown or not authorized.
description: The current subject is unknown or not authorized.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Forbidden:
description: The current user or none of the assumed or roles is granted access to the resource.
description: The current subject or none of the assumed or roles is granted access to the resource.
content:
application/json:
schema:

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of all booking items for a specified project.
description: Returns the list of all booking items for a specified project which are visible to the current user or any of it's assumed roles.
description: Returns the list of all booking items for a specified project which are visible to the current subject or any of it's assumed roles.
tags:
- hs-booking-items
operationId: listBookingItemsByProjectUuid

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of all booking projects for a specified debitor.
description: Returns the list of all booking projects for a specified debitor which are visible to the current user or any of it's assumed roles.
description: Returns the list of all booking projects for a specified debitor which are visible to the current subject or any of it's assumed roles.
tags:
- hs-booking-projects
operationId: listBookingProjectsByDebitorUuid

View File

@ -9,7 +9,7 @@ components:
required: true
schema:
type: string
description: Identifying name of the currently logged in user.
description: Identifying name of the currently logged in subject.
assumedRoles:
name: assumed-roles
@ -17,4 +17,4 @@ components:
required: false
schema:
type: string
description: Semicolon-separated list of roles to assume. The current user needs to have the right to assume these roles.
description: Semicolon-separated list of roles to assume. The current subject needs to have the right to assume these roles.

View File

@ -8,13 +8,13 @@ components:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: The current user is unknown or not authorized.
description: The current subject is unknown or not authorized.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Forbidden:
description: The current user or none of the assumed or roles is granted access to the resource.
description: The current subject or none of the assumed or roles is granted access to the resource.
content:
application/json:
schema:

View File

@ -1,6 +1,6 @@
get:
summary: Returns a filtered list of all hosting assets.
description: Returns the list of all hosting assets which match the given filters and are visible to the current user or any of it's assumed roles.
description: Returns the list of all hosting assets which match the given filters and are visible to the current subject or any of it's assumed roles.
tags:
- hs-hosting-assets
operationId: listAssets

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) bankaccounts.
description: Returns the list of (optionally filtered) bankaccounts which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) bankaccounts which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-bank-accounts
operationId: listBankAccounts

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) contacts.
description: Returns the list of (optionally filtered) contacts which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) contacts which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-contacts
operationId: listContacts

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) cooperative asset transactions.
description: Returns the list of (optionally filtered) cooperative asset transactions which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) cooperative asset transactions which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-coopAssets
operationId: listCoopAssets

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) cooperative share transactions.
description: Returns the list of (optionally filtered) cooperative share transactions which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) cooperative share transactions which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-coopShares
operationId: listCoopShares

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) debitors.
description: Returns the list of (optionally filtered) debitors which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) debitors which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-debitors
operationId: listDebitors

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) memberships.
description: Returns the list of memberships which are visible to the current user or any of it's assumed roles.
description: Returns the list of memberships which are visible to the current subject or any of it's assumed roles.
The list can optionally be filtered by either the `partnerUuid` or the `memberNumber` - not both at the same time.
tags:
- hs-office-memberships

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) business partners.
description: Returns the list of (optionally filtered) business partners which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) business partners which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-partners
operationId: listPartners

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) persons.
description: Returns the list of (optionally filtered) persons which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) persons which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-persons
operationId: listPersons

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) person relations for a given person.
description: Returns the list of (optionally filtered) person relations of a given person and which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) person relations of a given person and which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-relations
operationId: listRelations

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) SEPA Mandates.
description: Returns the list of (optionally filtered) SEPA Mandates which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) SEPA Mandates which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-sepaMandates
operationId: listSepaMandatesByIBAN

View File

@ -18,7 +18,7 @@ components:
grantedRoleUuid:
type: string
format: uuid
granteeUserName:
granteeSubjectName:
type: string
granteeSubjectUuid:
type: string

View File

@ -18,7 +18,7 @@ get:
schema:
type: string
format: uuid
description: UUID of the user to whom the role was granted.
description: UUID of the subject to who the role was granted.
responses:
"200":
description: OK
@ -53,7 +53,7 @@ delete:
schema:
type: string
format: uuid
description: UUID of the user to whom the role was granted.
description: UUID of the subject to which the role was granted.
responses:
"204":
description: No Content

View File

@ -1,7 +1,7 @@
get:
tags:
- rbac-grants
operationId: listUserGrants
operationId: listSubjectGrants
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -3,7 +3,7 @@ components:
schemas:
RbacUser:
RbacSubject:
type: object
properties:
uuid:
@ -11,7 +11,7 @@ components:
format: uuid
name:
type: string
RbacUserPermission:
RbacSubjectPermission:
type: object
properties:
objectUuid:

View File

@ -1,8 +1,8 @@
get:
tags:
- rbac-users
description: 'List all visible permissions granted to the given user; reduced '
operationId: listUserPermissions
- rbac-subjects
description: 'List all visible permissions granted to the given subject; reduced '
operationId: listSubjectPermissions
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -20,7 +20,7 @@ get:
schema:
type: array
items:
$ref: 'rbac-user-schemas.yaml#/components/schemas/RbacUserPermission'
$ref: 'rbac-subject-schemas.yaml#/components/schemas/RbacSubjectPermission'
"401":
$ref: 'error-responses.yaml#/components/responses/Unauthorized'

View File

@ -1,8 +1,8 @@
get:
tags:
- rbac-users
description: 'Fetch a single user by its id, if visible for the current subject.'
operationId: getUserById
- rbac-subjects
description: 'Fetch a single subject by its id, if visible for the current subject.'
operationId: getSubjectById
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -18,7 +18,7 @@ get:
content:
'application/json':
schema:
$ref: 'rbac-user-schemas.yaml#/components/schemas/RbacUser'
$ref: 'rbac-subject-schemas.yaml#/components/schemas/RbacSubject'
"401":
$ref: 'error-responses.yaml#/components/responses/Unauthorized'
@ -28,8 +28,8 @@ get:
delete:
tags:
- rbac-users
operationId: deleteUserByUuid
- rbac-subjects
operationId: deleteSubjectByUuid
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -39,7 +39,7 @@ delete:
schema:
type: string
format: uuid
description: UUID of the user to delete.
description: UUID of the subject to delete.
responses:
"204":
description: No Content

View File

@ -1,8 +1,8 @@
get:
tags:
- rbac-users
description: List accessible RBAC users with optional filter by name.
operationId: listUsers
- rbac-subjects
description: List accessible RBAC subjects with optional filter by name.
operationId: listSubjects
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -19,7 +19,7 @@ get:
schema:
type: array
items:
$ref: 'rbac-user-schemas.yaml#/components/schemas/RbacUser'
$ref: 'rbac-subject-schemas.yaml#/components/schemas/RbacSubject'
'401':
$ref: 'error-responses.yaml#/components/responses/Unauthorized'
'403':
@ -27,22 +27,22 @@ get:
post:
tags:
- rbac-users
description: Create a new RBAC user.
operationId: createUser
- rbac-subjects
description: Create a new RBAC subject (e.g. user).
operationId: createSubject
requestBody:
required: true
content:
application/json:
schema:
$ref: 'rbac-user-schemas.yaml#/components/schemas/RbacUser'
$ref: 'rbac-subject-schemas.yaml#/components/schemas/RbacSubject'
responses:
'201':
description: Created
content:
'application/json':
schema:
$ref: 'rbac-user-schemas.yaml#/components/schemas/RbacUser'
$ref: 'rbac-subject-schemas.yaml#/components/schemas/RbacSubject'
'409':
$ref: 'error-responses.yaml#/components/responses/Conflict'

View File

@ -8,14 +8,14 @@ servers:
paths:
/api/rbac/users:
$ref: 'rbac-users.yaml'
/api/rbac/subjects:
$ref: 'rbac-subjects.yaml'
/api/rbac/users/{subjectUuid}/permissions:
$ref: 'rbac-users-with-id-permissions.yaml'
/api/rbac/subjects/{subjectUuid}/permissions:
$ref: 'rbac-subjects-with-id-permissions.yaml'
/api/rbac/users/{subjectUuid}:
$ref: 'rbac-users-with-uuid.yaml'
/api/rbac/subjects/{subjectUuid}:
$ref: 'rbac-subjects-with-uuid.yaml'
/api/rbac/roles:
$ref: 'rbac-roles.yaml'

View File

@ -1,6 +1,6 @@
get:
summary: Returns a list of (optionally filtered) customers.
description: Returns the list of (optionally filtered) customers which are visible to the current user or any of it's assumed roles.
description: Returns the list of (optionally filtered) customers which are visible to the current subject or any of it's assumed roles.
tags:
- testCustomers
operationId: listCustomers

View File

@ -204,8 +204,8 @@ execute function rbac.delete_grant_tf();
Creates a view to the users table with additional columns
for easier human readability.
*/
drop view if exists RbacUser_ev;
create or replace view RbacUser_ev as
drop view if exists rbac.subject_ev;
create or replace view rbac.subject_ev as
select distinct *
-- @formatter:off
from (
@ -229,8 +229,8 @@ select distinct *
Creates a view to the users table with row-level limitation
based on the grants of the current user or assumed roles.
*/
drop view if exists RbacUser_rv;
create or replace view RbacUser_rv as
drop view if exists rbac.subject_rv;
create or replace view rbac.subject_rv as
select distinct *
-- @formatter:off
from (
@ -247,7 +247,7 @@ create or replace view RbacUser_rv as
) as unordered
-- @formatter:on
order by unordered.name;
grant all privileges on RbacUser_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
grant all privileges on rbac.subject_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
--//
-- ============================================================================
@ -255,9 +255,9 @@ grant all privileges on RbacUser_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}
-- ----------------------------------------------------------------------------
/**
Instead of insert trigger function for RbacUser_rv.
Instead of insert trigger function for rbac.subject_rv.
*/
create or replace function insertRbacUser()
create or replace function rbac.insert_subject_tf()
returns trigger
language plpgsql as $$
declare
@ -277,13 +277,13 @@ end;
$$;
/*
Creates an instead of insert trigger for the RbacUser_rv view.
Creates an instead of insert trigger for the rbac.subject_rv view.
*/
create trigger insertRbacUser_Trigger
create trigger insert_subject_tg
instead of insert
on RbacUser_rv
on rbac.subject_rv
for each row
execute function insertRbacUser();
execute function rbac.insert_subject_tf();
--//
-- ============================================================================
@ -291,11 +291,11 @@ execute function insertRbacUser();
-- ----------------------------------------------------------------------------
/**
Instead of delete trigger function for RbacUser_RV.
Instead of delete trigger function for rbac.subject_rv.
Checks if the current subject (user / assumed role) has the permission to delete the user.
*/
create or replace function deleteRbacUser()
create or replace function delete_subject_tf()
returns trigger
language plpgsql as $$
begin
@ -307,13 +307,13 @@ begin
end; $$;
/*
Creates an instead of delete trigger for the RbacUser_rv view.
Creates an instead of delete trigger for the rbac.subject_rv view.
*/
create trigger deleteRbacUser_Trigger
create trigger delete_subject_tg
instead of delete
on RbacUser_rv
on rbac.subject_rv
for each row
execute function deleteRbacUser();
execute function delete_subject_tf();
--/
-- ============================================================================
@ -324,8 +324,8 @@ execute function deleteRbacUser();
based on the grants of the current user or assumed roles.
*/
-- @formatter:off
drop view if exists RbacOwnGrantedPermissions_rv;
create or replace view RbacOwnGrantedPermissions_rv as
drop view if exists rbac.own_granted_permissions_rv;
create or replace view rbac.own_granted_permissions_rv as
select r.uuid as roleuuid, p.uuid as permissionUuid,
(r.objecttable || ':' || r.objectidname || ':' || r.roletype) as roleName, p.op,
o.objecttable, r.objectidname, o.uuid as objectuuid
@ -333,7 +333,7 @@ select r.uuid as roleuuid, p.uuid as permissionUuid,
join rbacgrants g on g.ascendantuuid = r.uuid
join rbacpermission p on p.uuid = g.descendantuuid
join rbac.object o on o.uuid = p.objectuuid;
grant all privileges on RbacOwnGrantedPermissions_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
grant all privileges on rbac.own_granted_permissions_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
-- @formatter:om
-- ============================================================================
@ -343,7 +343,7 @@ grant all privileges on RbacOwnGrantedPermissions_rv to ${HSADMINNG_POSTGRES_RES
Returns all permissions granted to the given user,
which are also visible to the current user or assumed roles.
*/
create or replace function grantedPermissionsRaw(targetSubjectUuid uuid)
create or replace function rbac.grantedPermissionsRaw(targetSubjectUuid uuid)
returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, opTableName varchar(60), objectTable varchar(60), objectIdName varchar, objectUuid uuid)
returns null on null input
language plpgsql as $$
@ -379,14 +379,14 @@ begin
-- @formatter:on
end; $$;
create or replace function grantedPermissions(targetSubjectUuid uuid)
create or replace function rbac.grantedPermissions(targetSubjectUuid uuid)
returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, opTableName varchar(60), objectTable varchar(60), objectIdName varchar, objectUuid uuid)
returns null on null input
language sql as $$
select * from grantedPermissionsRaw(targetSubjectUuid)
select * from rbac.grantedPermissionsRaw(targetSubjectUuid)
union all
select roleUuid, roleName, permissionUuid, 'SELECT'::RbacOp, opTableName, objectTable, objectIdName, objectUuid
from grantedPermissionsRaw(targetSubjectUuid)
from rbac.grantedPermissionsRaw(targetSubjectUuid)
where op <> 'SELECT'::RbacOp;
$$;
--//

View File

@ -68,7 +68,7 @@ public class ArchitectureTest {
"..mapper",
"..ping",
"..rbac",
"..rbac.rbacuser",
"..rbac.rbacSubject",
"..rbac.rbacgrant",
"..rbac.rbacrole",
"..rbac.rbacobject",

View File

@ -298,7 +298,7 @@ public class CsvDataImport extends ContextBasedTest {
protected void deleteFromCommonTables() {
jpaAttempt.transacted(() -> {
context(rbacSuperuser);
em.createNativeQuery("delete from rbacuser_rv where name not like 'superuser-%'").executeUpdate();
em.createNativeQuery("delete from rbac.subject_rv where name not like 'superuser-%'").executeUpdate();
em.createNativeQuery("delete from basis.tx_journal where true").executeUpdate();
em.createNativeQuery("delete from basis.tx_context where true").executeUpdate();
}).assertSuccessful();

View File

@ -7,8 +7,8 @@ import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleEntity;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository;
import net.hostsharing.hsadminng.rbac.rbacuser.RbacUserEntity;
import net.hostsharing.hsadminng.rbac.rbacuser.RbacUserRepository;
import net.hostsharing.hsadminng.rbac.subject.RbacSubjectEntity;
import net.hostsharing.hsadminng.rbac.subject.RbacSubjectRepository;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.Nested;
@ -43,7 +43,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
EntityManager em;
@Autowired
RbacUserRepository rbacUserRepository;
RbacSubjectRepository rbacSubjectRepository;
@Autowired
RbacRoleRepository rbacRoleRepository;
@ -73,7 +73,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// TODO: should there be a grantedByRole or just a grantedByTrigger?
hasEntry("grantedByRoleIdName", "test_customer#xxx:OWNER"),
hasEntry("grantedRoleIdName", "test_customer#xxx:ADMIN"),
hasEntry("granteeUserName", "customer-admin@xxx.example.com")
hasEntry("granteeSubjectName", "customer-admin@xxx.example.com")
)
))
.body("", hasItem(
@ -81,28 +81,28 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// TODO: should there be a grantedByRole or just a grantedByTrigger?
hasEntry("grantedByRoleIdName", "test_customer#yyy:OWNER"),
hasEntry("grantedRoleIdName", "test_customer#yyy:ADMIN"),
hasEntry("granteeUserName", "customer-admin@yyy.example.com")
hasEntry("granteeSubjectName", "customer-admin@yyy.example.com")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "global#global:ADMIN"),
hasEntry("grantedRoleIdName", "global#global:ADMIN"),
hasEntry("granteeUserName", "superuser-fran@hostsharing.net")
hasEntry("granteeSubjectName", "superuser-fran@hostsharing.net")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "test_customer#xxx:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#xxx00:ADMIN"),
hasEntry("granteeUserName", "pac-admin-xxx00@xxx.example.com")
hasEntry("granteeSubjectName", "pac-admin-xxx00@xxx.example.com")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "test_customer#zzz:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#zzz02:ADMIN"),
hasEntry("granteeUserName", "pac-admin-zzz02@zzz.example.com")
hasEntry("granteeSubjectName", "pac-admin-zzz02@zzz.example.com")
)
))
.body("size()", greaterThanOrEqualTo(14));
@ -125,7 +125,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
allOf(
hasEntry("grantedByRoleIdName", "test_customer#yyy:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#yyy00:ADMIN"),
hasEntry("granteeUserName", "pac-admin-yyy00@yyy.example.com")
hasEntry("granteeSubjectName", "pac-admin-yyy00@yyy.example.com")
)
))
.body("size()", is(1));
@ -147,12 +147,12 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
allOf(
hasEntry("grantedByRoleIdName", "test_customer#yyy:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#yyy00:ADMIN"),
hasEntry("granteeUserName", "pac-admin-yyy00@yyy.example.com")
hasEntry("granteeSubjectName", "pac-admin-yyy00@yyy.example.com")
)
))
.body("[0].grantedByRoleIdName", is("test_customer#yyy:ADMIN"))
.body("[0].grantedRoleIdName", is("test_package#yyy00:ADMIN"))
.body("[0].granteeUserName", is("pac-admin-yyy00@yyy.example.com"));
.body("[0].granteeSubjectName", is("pac-admin-yyy00@yyy.example.com"));
// @formatter:on
}
}
@ -164,7 +164,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
void customerAdmin_withAssumedPacketAdminRole_canReadPacketAdminsGrantById() {
// given
final var givencurrentSubjectAsPackageAdmin = new Subject("customer-admin@xxx.example.com");
final var givenGranteeUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
// when
@ -176,14 +176,14 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.statusCode(200)
.body("grantedByRoleIdName", is("test_customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("granteeUserName", is("pac-admin-xxx00@xxx.example.com"));
.body("granteeSubjectName", is("pac-admin-xxx00@xxx.example.com"));
}
@Test
void packageAdmin_withoutAssumedRole_canReadItsOwnGrantById() {
// given
final var givencurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com");
final var givenGranteeUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
// when
@ -195,7 +195,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.statusCode(200)
.body("grantedByRoleIdName", is("test_customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("granteeUserName", is("pac-admin-xxx00@xxx.example.com"));
.body("granteeSubjectName", is("pac-admin-xxx00@xxx.example.com"));
}
@Test
@ -204,7 +204,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
final var givencurrentSubjectAsPackageAdmin = new Subject(
"pac-admin-xxx00@xxx.example.com",
"test_package#xxx00:ADMIN");
final var givenGranteeUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
// when
@ -216,7 +216,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.statusCode(200)
.body("grantedByRoleIdName", is("test_customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("granteeUserName", is("pac-admin-xxx00@xxx.example.com"));
.body("granteeSubjectName", is("pac-admin-xxx00@xxx.example.com"));
}
@Test
@ -226,7 +226,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
final var givencurrentSubjectAsPackageAdmin = new Subject(
"pac-admin-xxx00@xxx.example.com",
"test_package#xxx00:TENANT");
final var givenGranteeUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
final var grant = givencurrentSubjectAsPackageAdmin.getGrantById()
.forGrantedRole(givenGrantedRole).toGranteeUser(givenGranteeUser);
@ -244,7 +244,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
void packageAdmin_canGrantOwnPackageAdminRole_toArbitraryUser() {
// given
final var givenNewUser = createRBacUser();
final var givenNewUser = createRbacSubject();
final var givenRoleToGrant = "test_package#xxx00:ADMIN";
final var givencurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com", givenRoleToGrant);
final var givenOwnPackageAdminRole =
@ -261,7 +261,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.body("grantedByRoleIdName", is("test_package#xxx00:ADMIN"))
.body("assumed", is(true))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("granteeUserName", is(givenNewUser.getName()));
.body("granteeSubjectName", is(givenNewUser.getName()));
assertThat(findAllGrantsOf(givencurrentSubjectAsPackageAdmin))
.extracting(RbacGrantEntity::toDisplay)
.contains("{ grant role:" + givenOwnPackageAdminRole.getRoleName() +
@ -273,7 +273,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
void packageAdmin_canNotGrantAlienPackageAdminRole_toArbitraryUser() {
// given
final var givenNewUser = createRBacUser();
final var givenNewUser = createRbacSubject();
final var givenRoleToGrant = "test_package#xxx00:ADMIN";
final var givencurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com", givenRoleToGrant);
final var givenAlienPackageAdminRole = getRbacRoleByName("test_package#yyy00:ADMIN");
@ -289,7 +289,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.body("message", containsString("Access to granted role"))
.body("message", containsString("forbidden for test_package#xxx00:ADMIN"));
assertThat(findAllGrantsOf(givencurrentSubjectAsPackageAdmin))
.extracting(RbacGrantEntity::getGranteeUserName)
.extracting(RbacGrantEntity::getGranteeSubjectName)
.doesNotContain(givenNewUser.getName());
}
}
@ -302,7 +302,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
void packageAdmin_canRevokePackageAdminRole_grantedByPackageAdmin_fromArbitraryUser() {
// given
final var givenArbitraryUser = createRBacUser();
final var givenArbitraryUser = createRbacSubject();
final var givenRoleToGrant = "test_package#xxx00:ADMIN";
final var givenCurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com", givenRoleToGrant);
final var givenOwnPackageAdminRole = getRbacRoleByName("test_package#xxx00:ADMIN");
@ -326,7 +326,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// then
revokeResponse.assertThat().statusCode(204);
assertThat(findAllGrantsOf(givenCurrentSubjectAsPackageAdmin))
.extracting(RbacGrantEntity::getGranteeUserName)
.extracting(RbacGrantEntity::getGranteeSubjectName)
.doesNotContain(givenArbitraryUser.getName());
}
}
@ -366,7 +366,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
private Subject grantingSubject = Subject.this;
private final RbacRoleEntity grantedRole;
private boolean assumed;
private RbacUserEntity granteeUser;
private RbacSubjectEntity granteeUser;
public GrantFixture(final RbacRoleEntity roleToGrant) {
this.grantedRole = roleToGrant;
@ -377,7 +377,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
return this;
}
ValidatableResponse toUser(final RbacUserEntity granteeUser) {
ValidatableResponse toUser(final RbacSubjectEntity granteeUser) {
this.granteeUser = granteeUser;
return RestAssured // @formatter:ff
@ -407,13 +407,13 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
private Subject currentSubject = Subject.this;
private final RbacRoleEntity grantedRole;
private boolean assumed;
private RbacUserEntity granteeUser;
private RbacSubjectEntity granteeUser;
public RevokeFixture(final RbacRoleEntity roleToGrant) {
this.grantedRole = roleToGrant;
}
ValidatableResponse fromUser(final RbacUserEntity granteeUser) {
ValidatableResponse fromUser(final RbacSubjectEntity granteeUser) {
this.granteeUser = granteeUser;
return RestAssured // @formatter:ff
@ -450,7 +450,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
return this;
}
ValidatableResponse toGranteeUser(final RbacUserEntity granteeUser) {
ValidatableResponse toGranteeUser(final RbacSubjectEntity granteeUser) {
return RestAssured // @formatter:ff
.given()
@ -480,18 +480,18 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
}).returnedValue();
}
RbacUserEntity createRBacUser() {
RbacSubjectEntity createRbacSubject() {
return jpaAttempt.transacted(() -> {
final String newUserName = "test-user-" + RandomStringUtils.randomAlphabetic(8) + "@example.com";
context(null);
return rbacUserRepository.create(new RbacUserEntity(UUID.randomUUID(), newUserName));
return rbacSubjectRepository.create(new RbacSubjectEntity(UUID.randomUUID(), newUserName));
}).returnedValue();
}
RbacUserEntity findRbacUserByName(final String userName) {
RbacSubjectEntity findRbacSubjectByName(final String userName) {
return jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", null);
return rbacUserRepository.findByName(userName);
return rbacSubjectRepository.findByName(userName);
}).assertNotNull().returnedValue();
}

View File

@ -3,8 +3,8 @@ package net.hostsharing.hsadminng.rbac.rbacgrant;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository;
import net.hostsharing.hsadminng.rbac.rbacuser.RbacUserEntity;
import net.hostsharing.hsadminng.rbac.rbacuser.RbacUserRepository;
import net.hostsharing.hsadminng.rbac.subject.RbacSubjectEntity;
import net.hostsharing.hsadminng.rbac.subject.RbacSubjectRepository;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@ -42,7 +42,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
RawRbacGrantRepository rawRbacGrantRepository;
@Autowired
RbacUserRepository rbacUserRepository;
RbacSubjectRepository rbacSubjectRepository;
@Autowired
RbacRoleRepository rbacRoleRepository;
@ -109,7 +109,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
public void customerAdmin_canGrantOwnPackageAdminRole_toArbitraryUser() {
// given
context("customer-admin@xxx.example.com", "test_customer#xxx:ADMIN");
final var givenArbitrarySubjectUuid = rbacUserRepository.findByName("pac-admin-zzz00@zzz.example.com").getUuid();
final var givenArbitrarySubjectUuid = rbacSubjectRepository.findByName("pac-admin-zzz00@zzz.example.com").getUuid();
final var givenOwnPackageRoleUuid = rbacRoleRepository.findByRoleName("test_package#xxx00:ADMIN").getUuid();
// when
@ -133,7 +133,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
@Transactional(propagation = Propagation.NEVER)
public void packageAdmin_canNotGrantPackageOwnerRole() {
// given
record Given(RbacUserEntity arbitraryUser, UUID packageOwnerRoleUuid) {}
record Given(RbacSubjectEntity arbitraryUser, UUID packageOwnerRoleUuid) {}
final var given = jpaAttempt.transacted(() -> {
// to find the uuids of we need to have access rights to these
context("customer-admin@xxx.example.com", null);
@ -188,7 +188,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com", "test_customer#xxx:ADMIN");
assertThat(revokeAttempt.caughtExceptionsRootCause()).isNull();
assertThat(rbacGrantRepository.findAll())
.extracting(RbacGrantEntity::getGranteeUserName)
.extracting(RbacGrantEntity::getGranteeSubjectName)
.doesNotContain("pac-admin-zzz00@zzz.example.com");
}
@ -209,7 +209,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
assertThat(revokeAttempt.caughtExceptionsRootCause()).isNull();
context("customer-admin@xxx.example.com", "test_customer#xxx:ADMIN");
assertThat(rbacGrantRepository.findAll())
.extracting(RbacGrantEntity::getGranteeUserName)
.extracting(RbacGrantEntity::getGranteeSubjectName)
.doesNotContain("pac-admin-zzz00@zzz.example.com");
}
@ -236,7 +236,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
private RbacGrantEntity create(GrantBuilder with) {
context(with.byUserName, with.assumedRole);
final var givenArbitrarySubjectUuid = rbacUserRepository.findByName(with.granteeUserName).getUuid();
final var givenArbitrarySubjectUuid = rbacSubjectRepository.findByName(with.granteeSubjectName).getUuid();
final var givenOwnPackageRoleUuid = rbacRoleRepository.findByRoleName(with.grantedRole).getUuid();
final var grant = RbacGrantEntity.builder()
@ -251,7 +251,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
assertThat(rawRbacGrantRepository.findAll())
.extracting(RawRbacGrantEntity::toDisplay)
.contains("{ grant role:%s to user:%s by %s and assume }".formatted(
with.grantedRole, with.granteeUserName, with.assumedRole
with.grantedRole, with.granteeSubjectName, with.assumedRole
));
return grant;
@ -266,7 +266,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
String byUserName;
String assumedRole = "";
String grantedRole;
String granteeUserName;
String granteeSubjectName;
GrantBuilder byUser(final String userName) {
byUserName = userName;
@ -284,28 +284,28 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
}
GrantBuilder toUser(final String toUser) {
this.granteeUserName = toUser;
this.granteeSubjectName = toUser;
return this;
}
}
}
private RbacUserEntity createNewUserTransacted() {
private RbacSubjectEntity createNewUserTransacted() {
return jpaAttempt.transacted(() -> {
final var newUserName = "test-user-" + System.currentTimeMillis() + "@example.com";
context(null);
return rbacUserRepository.create(new RbacUserEntity(null, newUserName));
return rbacSubjectRepository.create(new RbacSubjectEntity(null, newUserName));
}).assumeSuccessful().returnedValue();
}
private RbacUserEntity createNewUser() {
return rbacUserRepository.create(
new RbacUserEntity(null, "test-user-" + System.currentTimeMillis() + "@example.com"));
private RbacSubjectEntity createNewUser() {
return rbacSubjectRepository.create(
new RbacSubjectEntity(null, "test-user-" + System.currentTimeMillis() + "@example.com"));
}
void exactlyTheseRbacGrantsAreReturned(final List<RbacGrantEntity> actualResult, final String... expectedGrant) {
assertThat(actualResult)
.filteredOn(g -> !g.getGranteeUserName().startsWith("test-user-")) // ignore test-users created by other tests
.filteredOn(g -> !g.getGranteeSubjectName().startsWith("test-user-")) // ignore test-users created by other tests
.extracting(RbacGrantEntity::toDisplay)
.containsExactlyInAnyOrder(expectedGrant);
}

View File

@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.rbac.rbacrole;
import io.restassured.RestAssured;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.rbac.rbacuser.RbacUserRepository;
import net.hostsharing.hsadminng.rbac.subject.RbacSubjectRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@ -24,7 +24,7 @@ class RbacRoleControllerAcceptanceTest {
Context context;
@Autowired
RbacUserRepository rbacUserRepository;
RbacSubjectRepository rbacSubjectRepository;
@Autowired
RbacRoleRepository rbacRoleRepository;

View File

@ -1,14 +0,0 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
import static java.util.UUID.randomUUID;
public class TestRbacUser {
static final RbacUserEntity userxxx = rbacRole("customer-admin@xxx.example.com");
static final RbacUserEntity userBbb = rbacRole("customer-admin@bbb.example.com");
static public RbacUserEntity rbacRole(final String userName) {
return new RbacUserEntity(randomUUID(), userName);
}
}

View File

@ -1,4 +1,4 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
package net.hostsharing.hsadminng.rbac.subject;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
@ -22,7 +22,7 @@ import static org.hamcrest.Matchers.*;
classes = { HsadminNgApplication.class, JpaAttempt.class }
)
@Transactional
class RbacUserControllerAcceptanceTest {
class RbacSubjectControllerAcceptanceTest {
@LocalServerPort
private Integer port;
@ -34,10 +34,10 @@ class RbacUserControllerAcceptanceTest {
Context context;
@Autowired
RbacUserRepository rbacUserRepository;
RbacSubjectRepository rbacSubjectRepository;
@Nested
class CreateRbacUser {
class CreateRbacSubject {
@Test
void anybody_canCreateANewUser() {
@ -53,7 +53,7 @@ class RbacUserControllerAcceptanceTest {
""")
.port(port)
.when()
.post("http://localhost/api/rbac/users")
.post("http://localhost/api/rbac/subjects")
.then().assertThat()
.statusCode(201)
.contentType(ContentType.JSON)
@ -66,17 +66,17 @@ class RbacUserControllerAcceptanceTest {
final var newSubjectUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.define("new-user@example.com");
assertThat(rbacUserRepository.findByUuid(newSubjectUuid))
.extracting(RbacUserEntity::getName).isEqualTo("new-user@example.com");
assertThat(rbacSubjectRepository.findByUuid(newSubjectUuid))
.extracting(RbacSubjectEntity::getName).isEqualTo("new-user@example.com");
}
}
@Nested
class GetRbacUser {
class GetRbacSubject {
@Test
void globalAdmin_withoutAssumedRole_canGetArbitraryUser() {
final var givenUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
// @formatter:off
RestAssured
@ -84,7 +84,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid())
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -94,7 +94,7 @@ class RbacUserControllerAcceptanceTest {
@Test
void globalAdmin_withAssumedCustomerAdminRole_canGetUserWithinInItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
@ -103,7 +103,7 @@ class RbacUserControllerAcceptanceTest {
.header("assumed-roles", "test_customer#yyy:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid())
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -113,7 +113,7 @@ class RbacUserControllerAcceptanceTest {
@Test
void customerAdmin_withoutAssumedRole_canGetUserWithinInItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
@ -121,7 +121,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "customer-admin@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid())
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -131,7 +131,7 @@ class RbacUserControllerAcceptanceTest {
@Test
void customerAdmin_withoutAssumedRole_canNotGetUserOutsideOfItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
@ -139,7 +139,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "customer-admin@xxx.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid())
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
.then().log().body().assertThat()
.statusCode(404);
// @formatter:on
@ -147,7 +147,7 @@ class RbacUserControllerAcceptanceTest {
}
@Nested
class ListRbacUsers {
class ListRbacSubjects {
@Test
void globalAdmin_withoutAssumedRole_canViewAllUsers() {
@ -158,7 +158,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/rbac/users")
.get("http://localhost/api/rbac/subjects")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -183,7 +183,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/rbac/users?name=pac-admin-zzz0")
.get("http://localhost/api/rbac/subjects?name=pac-admin-zzz0")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -204,7 +204,7 @@ class RbacUserControllerAcceptanceTest {
.header("assumed-roles", "test_customer#yyy:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/users")
.get("http://localhost/api/rbac/subjects")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
@ -225,7 +225,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "customer-admin@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac/users")
.get("http://localhost/api/rbac/subjects")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
@ -246,7 +246,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "pac-admin-xxx01@xxx.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac/users")
.get("http://localhost/api/rbac/subjects")
.then().assertThat()
.statusCode(200)
.contentType("application/json")
@ -257,11 +257,11 @@ class RbacUserControllerAcceptanceTest {
}
@Nested
class ListRbacUserPermissions {
class ListRbacSubjectPermissions {
@Test
void globalAdmin_withoutAssumedRole_canViewArbitraryUsersPermissions() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
@ -269,7 +269,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid() + "/permissions")
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -290,7 +290,7 @@ class RbacUserControllerAcceptanceTest {
@Test
void globalAdmin_withAssumedCustomerAdminRole_canViewArbitraryUsersPermissions() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
@ -299,7 +299,7 @@ class RbacUserControllerAcceptanceTest {
.header("assumed-roles", "test_customer#yyy:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid() + "/permissions")
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -320,7 +320,7 @@ class RbacUserControllerAcceptanceTest {
@Test
void packageAdmin_withoutAssumedRole_canViewPermissionsOfUsersInItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-yyy00@yyy.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-yyy00@yyy.example.com");
// @formatter:off
RestAssured
@ -328,7 +328,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "pac-admin-yyy00@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid() + "/permissions")
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -349,7 +349,7 @@ class RbacUserControllerAcceptanceTest {
@Test
void packageAdmin_canViewPermissionsOfUsersOutsideOfItsRealm() {
final var givenUser = findRbacUserByName("pac-admin-xxx00@xxx.example.com");
final var givenUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
// @formatter:off
RestAssured
@ -357,7 +357,7 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "pac-admin-yyy00@yyy.example.com")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid() + "/permissions")
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid() + "/permissions")
.then().log().body().assertThat()
.statusCode(200)
.contentType("application/json")
@ -367,7 +367,7 @@ class RbacUserControllerAcceptanceTest {
}
@Nested
class DeleteRbacUser {
class DeleteRbacSubject {
@Test
void anybody_canDeleteTheirOwnUser() {
@ -381,13 +381,13 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", givenUser.getName())
.port(port)
.when()
.delete("http://localhost/api/rbac/users/" + givenUser.getUuid())
.delete("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
.then().log().all().assertThat()
.statusCode(204);
// @formatter:on
// finally, the user is actually deleted
assertThat(rbacUserRepository.findByName(givenUser.getName())).isNull();
assertThat(rbacSubjectRepository.findByName(givenUser.getName())).isNull();
}
@Test
@ -402,14 +402,14 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "customer-admin@xxx.example.com")
.port(port)
.when()
.delete("http://localhost/api/rbac/users/" + givenUser.getUuid())
.delete("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
.then().log().all().assertThat()
// that user cannot even see other users, thus the system won't even try to delete
.statusCode(204);
// @formatter:on
// finally, the user is still there
assertThat(rbacUserRepository.findByName(givenUser.getName())).isNotNull();
assertThat(rbacSubjectRepository.findByName(givenUser.getName())).isNotNull();
}
@Test
@ -424,30 +424,30 @@ class RbacUserControllerAcceptanceTest {
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.delete("http://localhost/api/rbac/users/" + givenUser.getUuid())
.delete("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
.then().log().all().assertThat()
.statusCode(204);
// @formatter:on
// finally, the user is actually deleted
assertThat(rbacUserRepository.findByName(givenUser.getName())).isNull();
assertThat(rbacSubjectRepository.findByName(givenUser.getName())).isNull();
}
}
RbacUserEntity findRbacUserByName(final String userName) {
RbacSubjectEntity findRbacSubjectByName(final String userName) {
return jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net");
return rbacUserRepository.findByName(userName);
return rbacSubjectRepository.findByName(userName);
}).returnedValue();
}
RbacUserEntity givenANewUser() {
RbacSubjectEntity givenANewUser() {
final var givenUserName = "test-user-" + System.currentTimeMillis() + "@example.com";
final var givenUser = jpaAttempt.transacted(() -> {
context.define(null);
return rbacUserRepository.create(new RbacUserEntity(UUID.randomUUID(), givenUserName));
return rbacSubjectRepository.create(new RbacSubjectEntity(UUID.randomUUID(), givenUserName));
}).assumeSuccessful().returnedValue();
assertThat(rbacUserRepository.findByName(givenUser.getName())).isNotNull();
assertThat(rbacSubjectRepository.findByName(givenUser.getName())).isNotNull();
return givenUser;
}

View File

@ -1,4 +1,4 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
package net.hostsharing.hsadminng.rbac.subject;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.mapper.Mapper;
@ -30,10 +30,10 @@ import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(RbacUserController.class)
@WebMvcTest(RbacSubjectController.class)
@Import(Mapper.class)
@RunWith(SpringRunner.class)
class RbacUserControllerRestTest {
class RbacSubjectControllerRestTest {
@Autowired
MockMvc mockMvc;
@ -42,7 +42,7 @@ class RbacUserControllerRestTest {
Context contextMock;
@MockBean
RbacUserRepository rbacUserRepository;
RbacSubjectRepository rbacSubjectRepository;
@Mock
EntityManager em;
@ -59,13 +59,13 @@ class RbacUserControllerRestTest {
}
@Test
void createUserUsesGivenUuid() throws Exception {
void createSubjectUsesGivenUuid() throws Exception {
// given
final var givenUuid = UUID.randomUUID();
// when
mockMvc.perform(MockMvcRequestBuilders
.post("/api/rbac/users")
.post("/api/rbac/subjects")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
@ -79,14 +79,14 @@ class RbacUserControllerRestTest {
.andExpect(jsonPath("uuid", is(givenUuid.toString())));
// then
verify(rbacUserRepository).create(argThat(entity -> entity.getUuid().equals(givenUuid)));
verify(rbacSubjectRepository).create(argThat(entity -> entity.getUuid().equals(givenUuid)));
}
@Test
void createUserGeneratesRandomUuidIfNotGiven() throws Exception {
void createSubjectGeneratesRandomUuidIfNotGiven() throws Exception {
// when
mockMvc.perform(MockMvcRequestBuilders
.post("/api/rbac/users")
.post("/api/rbac/subjects")
.contentType(MediaType.APPLICATION_JSON)
.content("{}")
.accept(MediaType.APPLICATION_JSON))
@ -96,6 +96,6 @@ class RbacUserControllerRestTest {
.andExpect(jsonPath("uuid", isUuidValid()));
// then
verify(rbacUserRepository).create(argThat(entity -> entity.getUuid() != null));
verify(rbacSubjectRepository).create(argThat(entity -> entity.getUuid() != null));
}
}

View File

@ -1,4 +1,4 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
package net.hostsharing.hsadminng.rbac.subject;
import org.junit.jupiter.api.Test;
@ -9,9 +9,9 @@ import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class RbacUserEntityUnitTest {
class RbacSubjectEntityUnitTest {
RbacUserEntity givenUser = new RbacUserEntity(UUID.randomUUID(), "test@example.org");
RbacSubjectEntity givenUser = new RbacSubjectEntity(UUID.randomUUID(), "test@example.org");
@Test
void generatedAccessCodeMatchesDefinedPattern() {

View File

@ -1,4 +1,4 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
package net.hostsharing.hsadminng.rbac.subject;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
@ -26,10 +26,10 @@ import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
RbacUserRepository rbacUserRepository;
RbacSubjectRepository rbacSubjectRepository;
@Autowired
JpaAttempt jpaAttempt;
@ -41,7 +41,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
HttpServletRequest request;
@Nested
class CreateUser {
class CreateSubject {
@Test
@Transactional(propagation = Propagation.NEVER)
@ -54,35 +54,35 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// when:
final var result = jpaAttempt.transacted(() -> {
context(null);
return rbacUserRepository.create(new RbacUserEntity(givenUuid, newUserName));
return rbacSubjectRepository.create(new RbacSubjectEntity(givenUuid, newUserName));
});
// then:
assertThat(result.wasSuccessful()).isTrue();
assertThat(result.returnedValue()).isNotNull()
.extracting(RbacUserEntity::getUuid).isEqualTo(givenUuid);
assertThat(rbacUserRepository.findByName(result.returnedValue().getName())).isNotNull();
.extracting(RbacSubjectEntity::getUuid).isEqualTo(givenUuid);
assertThat(rbacSubjectRepository.findByName(result.returnedValue().getName())).isNotNull();
}
}
@Nested
class DeleteUser {
class DeleteSubject {
@Test
@Transactional(propagation = Propagation.NEVER)
public void anyoneCanDeleteTheirOwnUser() {
// given
final RbacUserEntity givenUser = givenANewUser();
final RbacSubjectEntity givenUser = givenANewSubject();
// when
final var result = jpaAttempt.transacted(() -> {
context(givenUser.getName());
rbacUserRepository.deleteByUuid(givenUser.getUuid());
rbacSubjectRepository.deleteByUuid(givenUser.getUuid());
});
// then the user is deleted
result.assertSuccessful();
assertThat(rbacUserRepository.findByName(givenUser.getName())).isNull();
assertThat(rbacSubjectRepository.findByName(givenUser.getName())).isNull();
}
}
@ -102,27 +102,27 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
);
@Test
public void globalAdmin_withoutAssumedRole_canViewAllRbacUsers() {
public void globalAdmin_withoutAssumedRole_canViewAllRbacSubjects() {
// given
context("superuser-alex@hostsharing.net");
// when
final var result = rbacUserRepository.findByOptionalNameLike(null);
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
// then
allTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
allTheseRbacSubjectsAreReturned(result, ALL_TEST_DATA_USERS);
}
@Test
public void globalAdmin_withAssumedglobalAdminRole_canViewAllRbacUsers() {
public void globalAdmin_withAssumedglobalAdminRole_canViewAllRbacSubjects() {
given:
context("superuser-alex@hostsharing.net", "global#global:ADMIN");
// when
final var result = rbacUserRepository.findByOptionalNameLike(null);
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
then:
allTheseRbacUsersAreReturned(result, ALL_TEST_DATA_USERS);
allTheseRbacSubjectsAreReturned(result, ALL_TEST_DATA_USERS);
}
@Test
@ -131,10 +131,10 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("superuser-alex@hostsharing.net", "test_customer#xxx:ADMIN");
// when
final var result = rbacUserRepository.findByOptionalNameLike(null);
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
then:
exactlyTheseRbacUsersAreReturned(
exactlyTheseRbacSubjectsAreReturned(
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,10 +147,10 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com");
// when:
final var result = rbacUserRepository.findByOptionalNameLike(null);
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
// then:
exactlyTheseRbacUsersAreReturned(
exactlyTheseRbacSubjectsAreReturned(
result,
"customer-admin@xxx.example.com",
"pac-admin-xxx00@xxx.example.com", "pac-admin-xxx01@xxx.example.com", "pac-admin-xxx02@xxx.example.com"
@ -161,24 +161,24 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyUsersHavingRolesInThatPackage() {
context("customer-admin@xxx.example.com", "test_package#xxx00:ADMIN");
final var result = rbacUserRepository.findByOptionalNameLike(null);
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
exactlyTheseRbacUsersAreReturned(result, "pac-admin-xxx00@xxx.example.com");
exactlyTheseRbacSubjectsAreReturned(result, "pac-admin-xxx00@xxx.example.com");
}
@Test
public void packageAdmin_withoutAssumedRole_canViewOnlyUsersHavingRolesInThatPackage() {
context("pac-admin-xxx00@xxx.example.com");
final var result = rbacUserRepository.findByOptionalNameLike(null);
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
exactlyTheseRbacUsersAreReturned(result, "pac-admin-xxx00@xxx.example.com");
exactlyTheseRbacSubjectsAreReturned(result, "pac-admin-xxx00@xxx.example.com");
}
}
@Nested
class ListUserPermissions {
class ListSubjectPermissions {
private static final String[] ALL_USER_PERMISSIONS = Array.of(
// @formatter:off
@ -232,9 +232,9 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("superuser-alex@hostsharing.net");
// when
final var result = rbacUserRepository.findPermissionsOfUserByUuid(subjectUuid("superuser-fran@hostsharing.net"))
final var result = rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid("superuser-fran@hostsharing.net"))
.stream().filter(p -> p.getObjectTable().contains("test_"))
.sorted(comparing(RbacUserPermission::toString)).toList();
.sorted(comparing(RbacSubjectPermission::toString)).toList();
// then
allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS);
@ -246,7 +246,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUserByUuid(subjectUuid("customer-admin@xxx.example.com"));
final var result = rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid("customer-admin@xxx.example.com"));
// then
allTheseRbacPermissionsAreReturned(
@ -290,7 +290,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () ->
rbacUserRepository.findPermissionsOfUserByUuid(subjectUuid)
rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid)
);
// then
@ -306,7 +306,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUserByUuid(subjectUuid("pac-admin-xxx00@xxx.example.com"));
final var result = rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid("pac-admin-xxx00@xxx.example.com"));
// then
allTheseRbacPermissionsAreReturned(
@ -342,7 +342,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUserByUuid(subjectUuid("pac-admin-yyy00@yyy.example.com"));
final var result = rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid("pac-admin-yyy00@yyy.example.com"));
// then
noRbacPermissionsAreReturned(result);
@ -354,7 +354,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("pac-admin-xxx00@xxx.example.com");
// when
final var result = rbacUserRepository.findPermissionsOfUserByUuid(subjectUuid("pac-admin-xxx00@xxx.example.com"));
final var result = rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid("pac-admin-xxx00@xxx.example.com"));
// then
allTheseRbacPermissionsAreReturned(
@ -386,50 +386,42 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
}
UUID subjectUuid(final String userName) {
return rbacUserRepository.findByName(userName).getUuid();
return rbacSubjectRepository.findByName(userName).getUuid();
}
RbacUserEntity givenANewUser() {
RbacSubjectEntity givenANewSubject() {
final var givenUserName = "test-user-" + System.currentTimeMillis() + "@example.com";
final var givenUser = jpaAttempt.transacted(() -> {
context(null);
return rbacUserRepository.create(new RbacUserEntity(UUID.randomUUID(), givenUserName));
return rbacSubjectRepository.create(new RbacSubjectEntity(UUID.randomUUID(), givenUserName));
}).assumeSuccessful().returnedValue();
assertThat(rbacUserRepository.findByName(givenUser.getName())).isNotNull();
assertThat(rbacSubjectRepository.findByName(givenUser.getName())).isNotNull();
return givenUser;
}
void exactlyTheseRbacUsersAreReturned(final List<RbacUserEntity> actualResult, final String... expectedUserNames) {
void exactlyTheseRbacSubjectsAreReturned(final List<RbacSubjectEntity> actualResult, final String... expectedUserNames) {
assertThat(actualResult)
.extracting(RbacUserEntity::getName)
.extracting(RbacSubjectEntity::getName)
.filteredOn(n -> !n.startsWith("test-user"))
.containsExactlyInAnyOrder(expectedUserNames);
}
void allTheseRbacUsersAreReturned(final List<RbacUserEntity> actualResult, final String... expectedUserNames) {
void allTheseRbacSubjectsAreReturned(final List<RbacSubjectEntity> actualResult, final String... expectedUserNames) {
assertThat(actualResult)
.extracting(RbacUserEntity::getName)
.extracting(RbacSubjectEntity::getName)
.filteredOn(n -> !n.startsWith("test-user"))
.contains(expectedUserNames);
}
void noRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult) {
final List<RbacSubjectPermission> actualResult) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.containsExactlyInAnyOrder();
}
void exactlyTheseRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult,
final String... expectedRoleNames) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.containsExactlyInAnyOrder(expectedRoleNames);
}
void allTheseRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult,
final List<RbacSubjectPermission> actualResult,
final String... expectedRoleNames) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp()
@ -438,7 +430,7 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
}
void noneOfTheseRbacPermissionsAreReturned(
final List<RbacUserPermission> actualResult,
final List<RbacSubjectPermission> actualResult,
final String... unexpectedRoleNames) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())

View File

@ -0,0 +1,14 @@
package net.hostsharing.hsadminng.rbac.subject;
import static java.util.UUID.randomUUID;
public class TestRbacSubject {
static final RbacSubjectEntity userxxx = rbacRole("customer-admin@xxx.example.com");
static final RbacSubjectEntity userBbb = rbacRole("customer-admin@bbb.example.com");
static public RbacSubjectEntity rbacRole(final String userName) {
return new RbacSubjectEntity(randomUUID(), userName);
}
}