Compare commits
5 Commits
952fafffdb
...
243c6c488f
Author | SHA1 | Date | |
---|---|---|---|
|
243c6c488f | ||
|
3107bd33cc | ||
87af20a3a1 | |||
7f418c12a1 | |||
f8fb273918 |
@ -82,7 +82,7 @@ If you have at least Docker and the Java JDK installed in appropriate versions a
|
||||
|
||||
# the following command should return a JSON array with just all packages visible for the admin of the customer yyy:
|
||||
curl \
|
||||
-H 'current-user: superuser-alex@hostsharing.net' -H 'assumed-roles: test_customer#yyy:admin' \
|
||||
-H 'current-user: superuser-alex@hostsharing.net' -H 'assumed-roles: test_customer#yyy:ADMIN' \
|
||||
http://localhost:8080/api/test/packages
|
||||
|
||||
# add a new customer
|
||||
|
22
doc/rbac.md
22
doc/rbac.md
@ -206,7 +206,7 @@ and the *role-stereotype* describes a role relative to a referenced business-obj
|
||||
#### owner
|
||||
|
||||
The owner-role is granted to the subject which created the business object.
|
||||
E.g. for a new *customer* it would be granted to 'administrators' and for a new *package* to the 'customer#...:admin'.
|
||||
E.g. for a new *customer* it would be granted to 'administrators' and for a new *package* to the 'customer#...:ADMIN'.
|
||||
|
||||
Whoever has the owner-role assigned can do everything with the related business-object, including deleting (or deactivating) it.
|
||||
|
||||
@ -470,14 +470,14 @@ together {
|
||||
permCustomerXyzSELECT--> boCustXyz
|
||||
}
|
||||
|
||||
entity "Role customer#xyz:tenant" as roleCustXyzTenant
|
||||
entity "Role customer#xyz:TENANT" as roleCustXyzTenant
|
||||
roleCustXyzTenant --> permCustomerXyzSELECT
|
||||
|
||||
entity "Role customer#xyz:admin" as roleCustXyzAdmin
|
||||
entity "Role customer#xyz:ADMIN" as roleCustXyzAdmin
|
||||
roleCustXyzAdmin --> roleCustXyzTenant
|
||||
roleCustXyzAdmin --> permCustomerXyzINSERT:package
|
||||
|
||||
entity "Role customer#xyz:owner" as roleCustXyzOwner
|
||||
entity "Role customer#xyz:OWNER" as roleCustXyzOwner
|
||||
roleCustXyzOwner ..> roleCustXyzAdmin
|
||||
roleCustXyzOwner --> permCustomerXyzDELETE
|
||||
|
||||
@ -493,7 +493,7 @@ actorHostmaster --> roleAdmins
|
||||
```
|
||||
|
||||
As you can see, there something special:
|
||||
From the 'Role customer#xyz:owner' to the 'Role customer#xyz:admin' there is a dashed line, whereas all other lines are solid lines.
|
||||
From the 'Role customer#xyz:OWNER' to the 'Role customer#xyz:admin' there is a dashed line, whereas all other lines are solid lines.
|
||||
Solid lines means, that one role is granted to another and automatically assumed in all queries to the restricted views.
|
||||
The dashed line means that one role is granted to another but not automatically assumed in queries to the restricted views.
|
||||
|
||||
@ -541,15 +541,15 @@ together {
|
||||
}
|
||||
|
||||
package {
|
||||
entity "Role customer#xyz:tenant" as roleCustXyzTenant
|
||||
entity "Role customer#xyz:admin" as roleCustXyzAdmin
|
||||
entity "Role customer#xyz:owner" as roleCustXyzOwner
|
||||
entity "Role customer#xyz:TENANT" as roleCustXyzTenant
|
||||
entity "Role customer#xyz:ADMIN" as roleCustXyzAdmin
|
||||
entity "Role customer#xyz:OWNER" as roleCustXyzOwner
|
||||
}
|
||||
|
||||
package {
|
||||
entity "Role package#xyz00:owner" as rolePacXyz00Owner
|
||||
entity "Role package#xyz00:admin" as rolePacXyz00Admin
|
||||
entity "Role package#xyz00:tenant" as rolePacXyz00Tenant
|
||||
entity "Role package#xyz00:OWNER" as rolePacXyz00Owner
|
||||
entity "Role package#xyz00:ADMIN" as rolePacXyz00Admin
|
||||
entity "Role package#xyz00:TENANT" as rolePacXyz00Tenant
|
||||
}
|
||||
|
||||
rolePacXyz00Tenant --> permPacXyz00SELECT
|
||||
|
@ -1,16 +1,29 @@
|
||||
|
||||
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.io.IOException;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
@ -20,8 +33,11 @@ import java.util.UUID;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||
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.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.Role.ADMIN;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
@ -34,7 +50,7 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@DisplayName("CoopAssetsTransaction")
|
||||
public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, RbacObject {
|
||||
public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, HasUuid {
|
||||
|
||||
private static Stringify<HsOfficeCoopAssetsTransactionEntity> stringify = stringify(HsOfficeCoopAssetsTransactionEntity.class)
|
||||
.withIdProp(HsOfficeCoopAssetsTransactionEntity::getTaggedMemberNumber)
|
||||
@ -109,7 +125,7 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, RbacO
|
||||
|
||||
.toRole("membership", ADMIN).grantPermission(INSERT)
|
||||
.toRole("membership", ADMIN).grantPermission(UPDATE)
|
||||
.toRole("membership", ADMIN).grantPermission(SELECT);
|
||||
.toRole("membership", AGENT).grantPermission(SELECT);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
@ -1,15 +1,28 @@
|
||||
package net.hostsharing.hsadminng.hs.office.coopshares;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.io.IOException;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
@ -17,9 +30,11 @@ import java.util.UUID;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||
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.Permission.INSERT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||
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.Role.ADMIN;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
@ -32,7 +47,7 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@DisplayName("CoopShareTransaction")
|
||||
public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, RbacObject {
|
||||
public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, HasUuid {
|
||||
|
||||
private static Stringify<HsOfficeCoopSharesTransactionEntity> stringify = stringify(HsOfficeCoopSharesTransactionEntity.class)
|
||||
.withProp(HsOfficeCoopSharesTransactionEntity::getMemberNumberTagged)
|
||||
@ -105,7 +120,7 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, RbacO
|
||||
|
||||
.toRole("membership", ADMIN).grantPermission(INSERT)
|
||||
.toRole("membership", ADMIN).grantPermission(UPDATE)
|
||||
.toRole("membership", ADMIN).grantPermission(SELECT);
|
||||
.toRole("membership", AGENT).grantPermission(SELECT);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
@ -28,7 +28,8 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.
|
||||
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;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.REFERRER;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||
@ -148,14 +149,14 @@ public class HsOfficeMembershipEntity implements RbacObject, Stringifyable {
|
||||
|
||||
.createRole(OWNER, (with) -> {
|
||||
with.owningUser(CREATOR);
|
||||
with.incomingSuperRole("partnerRel", ADMIN);
|
||||
with.permission(DELETE);
|
||||
})
|
||||
.createSubRole(ADMIN, (with) -> {
|
||||
with.incomingSuperRole("partnerRel", AGENT);
|
||||
with.incomingSuperRole("partnerRel", ADMIN);
|
||||
with.permission(DELETE);
|
||||
with.permission(UPDATE);
|
||||
})
|
||||
.createSubRole(REFERRER, (with) -> {
|
||||
.createSubRole(AGENT, (with) -> {
|
||||
with.incomingSuperRole("partnerRel", AGENT);
|
||||
with.outgoingSubRole("partnerRel", TENANT);
|
||||
with.permission(SELECT);
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ public class RbacRoleController implements RbacRolesApi {
|
||||
|
||||
context.define(currentUser, assumedRoles);
|
||||
|
||||
final List<RbacRoleRvEntity> result = rbacRoleRepository.findAll();
|
||||
final List<RbacRoleEntity> result = rbacRoleRepository.findAll();
|
||||
|
||||
return ResponseEntity.ok(mapper.mapList(result, RbacRoleResource.class));
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import java.util.UUID;
|
||||
@Immutable
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RbacRoleRvEntity {
|
||||
public class RbacRoleEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
@ -5,7 +5,7 @@ import org.springframework.data.repository.Repository;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface RbacRoleRepository extends Repository<RbacRoleRvEntity, UUID> {
|
||||
public interface RbacRoleRepository extends Repository<RbacRoleEntity, UUID> {
|
||||
|
||||
/**
|
||||
* @return the number of persistent RbacRoleEntity instances, mostly for testing purposes.
|
||||
@ -15,7 +15,7 @@ public interface RbacRoleRepository extends Repository<RbacRoleRvEntity, UUID> {
|
||||
/**
|
||||
* @return all persistent RbacRoleEntity instances, assigned to the current subject (user or assumed roles)
|
||||
*/
|
||||
List<RbacRoleRvEntity> findAll();
|
||||
List<RbacRoleEntity> findAll();
|
||||
|
||||
RbacRoleRvEntity findByRoleName(String roleName);
|
||||
RbacRoleEntity findByRoleName(String roleName);
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ declare
|
||||
objectUuidOfRole uuid;
|
||||
roleUuid uuid;
|
||||
begin
|
||||
-- TODO.refa: extract function toRbacRoleDescriptor(roleIdName varchar) + find other occurrences
|
||||
-- TODO.refact: extract function toRbacRoleDescriptor(roleIdName varchar) + find other occurrences
|
||||
roleParts = overlay(roleIdName placing '#' from length(roleIdName) + 1 - strpos(reverse(roleIdName), ':'));
|
||||
objectTableFromRoleIdName = split_part(roleParts, '#', 1);
|
||||
objectNameFromRoleIdName = split_part(roleParts, '#', 2);
|
||||
@ -356,13 +356,16 @@ create trigger deleteRbacRolesOfRbacObject_Trigger
|
||||
/*
|
||||
|
||||
*/
|
||||
create domain RbacOp as varchar(6)
|
||||
create domain RbacOp as varchar(67) -- TODO: shorten to 8, once the deprecated values are gone
|
||||
check (
|
||||
VALUE = 'DELETE'
|
||||
or VALUE = 'UPDATE'
|
||||
or VALUE = 'SELECT'
|
||||
or VALUE = 'INSERT'
|
||||
or VALUE = 'ASSUME'
|
||||
-- TODO: all values below are deprecated, use insert with table
|
||||
or VALUE ~ '^add-[a-z]+$'
|
||||
or VALUE ~ '^new-[a-z-]+$'
|
||||
);
|
||||
|
||||
create table RbacPermission
|
||||
@ -414,6 +417,37 @@ begin
|
||||
return permissionUuid;
|
||||
end; $$;
|
||||
|
||||
-- TODO: deprecated, remove and amend all usages to createPermission
|
||||
create or replace function createPermissions(forObjectUuid uuid, permitOps RbacOp[])
|
||||
returns uuid[]
|
||||
language plpgsql as $$
|
||||
declare
|
||||
refId uuid;
|
||||
permissionIds uuid[] = array []::uuid[];
|
||||
begin
|
||||
if (forObjectUuid is null) then
|
||||
raise exception 'forObjectUuid must not be null';
|
||||
end if;
|
||||
|
||||
for i in array_lower(permitOps, 1)..array_upper(permitOps, 1)
|
||||
loop
|
||||
refId = (select uuid from RbacPermission where objectUuid = forObjectUuid and op = permitOps[i]);
|
||||
if (refId is null) then
|
||||
insert
|
||||
into RbacReference ("type")
|
||||
values ('RbacPermission')
|
||||
returning uuid into refId;
|
||||
insert
|
||||
into RbacPermission (uuid, objectUuid, op)
|
||||
values (refId, forObjectUuid, permitOps[i]);
|
||||
end if;
|
||||
permissionIds = permissionIds || refId;
|
||||
end loop;
|
||||
|
||||
return permissionIds;
|
||||
end;
|
||||
$$;
|
||||
|
||||
create or replace function findEffectivePermissionId(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
|
||||
returns uuid
|
||||
returns null on null input
|
||||
@ -615,6 +649,25 @@ begin
|
||||
end;
|
||||
$$;
|
||||
|
||||
-- TODO: deprecated, remove and use grantPermissionToRole(...)
|
||||
create or replace procedure grantPermissionsToRole(roleUuid uuid, permissionIds uuid[])
|
||||
language plpgsql as $$
|
||||
begin
|
||||
if cardinality(permissionIds) = 0 then return; end if;
|
||||
|
||||
for i in array_lower(permissionIds, 1)..array_upper(permissionIds, 1)
|
||||
loop
|
||||
perform assertReferenceType('roleId (ascendant)', roleUuid, 'RbacRole');
|
||||
perform assertReferenceType('permissionId (descendant)', permissionIds[i], 'RbacPermission');
|
||||
|
||||
insert
|
||||
into RbacGrants (grantedByTriggerOf, ascendantUuid, descendantUuid, assumed)
|
||||
values (currentTriggerObjectUuid(), roleUuid, permissionIds[i], true)
|
||||
on conflict do nothing; -- allow granting multiple times
|
||||
end loop;
|
||||
end;
|
||||
$$;
|
||||
|
||||
create or replace procedure grantRoleToRole(subRoleId uuid, superRoleId uuid, doAssume bool = true)
|
||||
language plpgsql as $$
|
||||
begin
|
||||
@ -638,7 +691,7 @@ declare
|
||||
superRoleId uuid;
|
||||
subRoleId uuid;
|
||||
begin
|
||||
-- TODO.refa: maybe separate method grantRoleToRoleIfNotNull(...) for NULLABLE references
|
||||
-- TODO: maybe separate method grantRoleToRoleIfNotNull(...) for NULLABLE references
|
||||
if superRole.objectUuid is null or subRole.objectuuid is null then
|
||||
return;
|
||||
end if;
|
||||
|
@ -73,6 +73,15 @@ begin
|
||||
return roleDescriptor('%2$s', entity.uuid, 'TENANT', assumed);
|
||||
end; $f$;
|
||||
|
||||
-- TODO: remove guest role
|
||||
create or replace function %1$sGuest(entity %2$s, assumed boolean = true)
|
||||
returns RbacRoleDescriptor
|
||||
language plpgsql
|
||||
strict as $f$
|
||||
begin
|
||||
return roleDescriptor('%2$s', entity.uuid, 'GUEST', assumed);
|
||||
end; $f$;
|
||||
|
||||
create or replace function %1$sReferrer(entity %2$s)
|
||||
returns RbacRoleDescriptor
|
||||
language plpgsql
|
||||
|
@ -139,7 +139,7 @@ select 'global', (select uuid from RbacObject where objectTable = 'global'), 'GU
|
||||
$$;
|
||||
|
||||
begin transaction;
|
||||
call defineContext('creating role:global#loba:guest', null, null, null);
|
||||
call defineContext('creating role:global#global:guest', null, null, null);
|
||||
select createRole(globalGuest());
|
||||
commit;
|
||||
--//
|
||||
|
@ -42,7 +42,7 @@ subgraph membership["`**membership**`"]
|
||||
|
||||
role:membership:OWNER[[membership:OWNER]]
|
||||
role:membership:ADMIN[[membership:ADMIN]]
|
||||
role:membership:REFERRER[[membership:REFERRER]]
|
||||
role:membership:AGENT[[membership:AGENT]]
|
||||
end
|
||||
|
||||
subgraph membership:permissions[ ]
|
||||
@ -105,16 +105,16 @@ role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT
|
||||
role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER
|
||||
role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER
|
||||
role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER
|
||||
role:partnerRel:ADMIN ==> role:membership:OWNER
|
||||
role:membership:OWNER ==> role:membership:ADMIN
|
||||
role:partnerRel:AGENT ==> role:membership:ADMIN
|
||||
role:membership:ADMIN ==> role:membership:REFERRER
|
||||
role:membership:REFERRER ==> role:partnerRel:TENANT
|
||||
role:partnerRel:ADMIN ==> role:membership:ADMIN
|
||||
role:membership:ADMIN ==> role:membership:AGENT
|
||||
role:partnerRel:AGENT ==> role:membership:AGENT
|
||||
role:membership:AGENT ==> role:partnerRel:TENANT
|
||||
|
||||
%% granting permissions to roles
|
||||
role:global:ADMIN ==> perm:membership:INSERT
|
||||
role:membership:OWNER ==> perm:membership:DELETE
|
||||
role:membership:ADMIN ==> perm:membership:DELETE
|
||||
role:membership:ADMIN ==> perm:membership:UPDATE
|
||||
role:membership:REFERRER ==> perm:membership:SELECT
|
||||
role:membership:AGENT ==> perm:membership:SELECT
|
||||
|
||||
```
|
||||
|
@ -45,23 +45,23 @@ begin
|
||||
|
||||
perform createRoleWithGrants(
|
||||
hsOfficeMembershipOWNER(NEW),
|
||||
permissions => array['DELETE'],
|
||||
incomingSuperRoles => array[hsOfficeRelationADMIN(newPartnerRel)],
|
||||
userUuids => array[currentUserUuid()]
|
||||
);
|
||||
|
||||
perform createRoleWithGrants(
|
||||
hsOfficeMembershipADMIN(NEW),
|
||||
permissions => array['UPDATE'],
|
||||
permissions => array['DELETE', 'UPDATE'],
|
||||
incomingSuperRoles => array[
|
||||
hsOfficeMembershipOWNER(NEW),
|
||||
hsOfficeRelationAGENT(newPartnerRel)]
|
||||
hsOfficeRelationADMIN(newPartnerRel)]
|
||||
);
|
||||
|
||||
perform createRoleWithGrants(
|
||||
hsOfficeMembershipREFERRER(NEW),
|
||||
hsOfficeMembershipAGENT(NEW),
|
||||
permissions => array['SELECT'],
|
||||
incomingSuperRoles => array[hsOfficeMembershipADMIN(NEW)],
|
||||
incomingSuperRoles => array[
|
||||
hsOfficeMembershipADMIN(NEW),
|
||||
hsOfficeRelationAGENT(newPartnerRel)],
|
||||
outgoingSubRoles => array[hsOfficeRelationTENANT(newPartnerRel)]
|
||||
);
|
||||
|
||||
|
@ -54,7 +54,7 @@ subgraph membership["`**membership**`"]
|
||||
|
||||
role:membership:OWNER[[membership:OWNER]]
|
||||
role:membership:ADMIN[[membership:ADMIN]]
|
||||
role:membership:REFERRER[[membership:REFERRER]]
|
||||
role:membership:AGENT[[membership:AGENT]]
|
||||
end
|
||||
end
|
||||
|
||||
@ -106,15 +106,15 @@ role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT
|
||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER
|
||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER
|
||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER
|
||||
role:membership.partnerRel:ADMIN -.-> role:membership:OWNER
|
||||
role:membership:OWNER -.-> role:membership:ADMIN
|
||||
role:membership.partnerRel:AGENT -.-> role:membership:ADMIN
|
||||
role:membership:ADMIN -.-> role:membership:REFERRER
|
||||
role:membership:REFERRER -.-> role:membership.partnerRel:TENANT
|
||||
role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN
|
||||
role:membership:ADMIN -.-> role:membership:AGENT
|
||||
role:membership.partnerRel:AGENT -.-> role:membership:AGENT
|
||||
role:membership:AGENT -.-> role:membership.partnerRel:TENANT
|
||||
|
||||
%% granting permissions to roles
|
||||
role:membership:ADMIN ==> perm:coopSharesTransaction:INSERT
|
||||
role:membership:ADMIN ==> perm:coopSharesTransaction:UPDATE
|
||||
role:membership:ADMIN ==> perm:coopSharesTransaction:SELECT
|
||||
role:membership:AGENT ==> perm:coopSharesTransaction:SELECT
|
||||
|
||||
```
|
||||
|
@ -38,7 +38,7 @@ begin
|
||||
SELECT * FROM hs_office_membership WHERE uuid = NEW.membershipUuid INTO newMembership;
|
||||
assert newMembership.uuid is not null, format('newMembership must not be null for NEW.membershipUuid = %s', NEW.membershipUuid);
|
||||
|
||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeMembershipADMIN(newMembership));
|
||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeMembershipAGENT(newMembership));
|
||||
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeMembershipADMIN(newMembership));
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
|
@ -54,7 +54,7 @@ subgraph membership["`**membership**`"]
|
||||
|
||||
role:membership:OWNER[[membership:OWNER]]
|
||||
role:membership:ADMIN[[membership:ADMIN]]
|
||||
role:membership:REFERRER[[membership:REFERRER]]
|
||||
role:membership:AGENT[[membership:AGENT]]
|
||||
end
|
||||
end
|
||||
|
||||
@ -106,15 +106,15 @@ role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT
|
||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER
|
||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER
|
||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER
|
||||
role:membership.partnerRel:ADMIN -.-> role:membership:OWNER
|
||||
role:membership:OWNER -.-> role:membership:ADMIN
|
||||
role:membership.partnerRel:AGENT -.-> role:membership:ADMIN
|
||||
role:membership:ADMIN -.-> role:membership:REFERRER
|
||||
role:membership:REFERRER -.-> role:membership.partnerRel:TENANT
|
||||
role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN
|
||||
role:membership:ADMIN -.-> role:membership:AGENT
|
||||
role:membership.partnerRel:AGENT -.-> role:membership:AGENT
|
||||
role:membership:AGENT -.-> role:membership.partnerRel:TENANT
|
||||
|
||||
%% granting permissions to roles
|
||||
role:membership:ADMIN ==> perm:coopAssetsTransaction:INSERT
|
||||
role:membership:ADMIN ==> perm:coopAssetsTransaction:UPDATE
|
||||
role:membership:ADMIN ==> perm:coopAssetsTransaction:SELECT
|
||||
role:membership:AGENT ==> perm:coopAssetsTransaction:SELECT
|
||||
|
||||
```
|
||||
|
@ -38,7 +38,7 @@ begin
|
||||
SELECT * FROM hs_office_membership WHERE uuid = NEW.membershipUuid INTO newMembership;
|
||||
assert newMembership.uuid is not null, format('newMembership must not be null for NEW.membershipUuid = %s', NEW.membershipUuid);
|
||||
|
||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeMembershipADMIN(newMembership));
|
||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeMembershipAGENT(newMembership));
|
||||
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeMembershipADMIN(newMembership));
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
|
@ -112,7 +112,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
||||
.map(s -> s.replace("hs_office_", ""))
|
||||
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||
initialGrantNames,
|
||||
"{ grant perm:coopassetstransaction#temprefB:SELECT to role:membership#M-1000101:ADMIN by system and assume }",
|
||||
"{ grant perm:coopassetstransaction#temprefB:SELECT to role:membership#M-1000101:AGENT by system and assume }",
|
||||
"{ grant perm:coopassetstransaction#temprefB:UPDATE to role:membership#M-1000101:ADMIN by system and assume }",
|
||||
null));
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
|
||||
.map(s -> s.replace("hs_office_", ""))
|
||||
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||
initialGrantNames,
|
||||
"{ grant perm:coopsharestransaction#temprefB:SELECT to role:membership#M-1000101:ADMIN by system and assume }",
|
||||
"{ grant perm:coopsharestransaction#temprefB:SELECT to role:membership#M-1000101:AGENT by system and assume }",
|
||||
"{ grant perm:coopsharestransaction#temprefB:UPDATE to role:membership#M-1000101:ADMIN by system and assume }",
|
||||
null));
|
||||
}
|
||||
|
@ -335,18 +335,18 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
}
|
||||
|
||||
@Test
|
||||
void partnerRelAgent_canPatchValidityOfRelatedMembership() {
|
||||
void partnerRelAdmin_canPatchValidityOfRelatedMembership() {
|
||||
|
||||
// given
|
||||
final var givenPartnerAgent = "hs_office_relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT";
|
||||
context.define("superuser-alex@hostsharing.net", givenPartnerAgent);
|
||||
final var givenPartnerAdmin = "hs_office_relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN";
|
||||
context.define("superuser-alex@hostsharing.net", givenPartnerAdmin);
|
||||
final var givenMembership = givenSomeTemporaryMembershipBessler("First");
|
||||
|
||||
// when
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
.header("current-user", "superuser-alex@hostsharing.net")
|
||||
.header("assumed-roles", givenPartnerAgent)
|
||||
.header("assumed-roles", givenPartnerAdmin)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
|
@ -110,9 +110,9 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
||||
final var all = rawRoleRepo.findAll();
|
||||
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(
|
||||
initialRoleNames,
|
||||
"hs_office_membership#M-1000117:ADMIN",
|
||||
"hs_office_membership#M-1000117:OWNER",
|
||||
"hs_office_membership#M-1000117:REFERRER"));
|
||||
"hs_office_membership#M-1000117:ADMIN",
|
||||
"hs_office_membership#M-1000117:AGENT"));
|
||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
|
||||
.map(s -> s.replace("hs_office_", ""))
|
||||
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||
@ -122,21 +122,20 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
||||
"{ grant perm:membership#M-1000117:INSERT>coopsharestransaction to role:membership#M-1000117:ADMIN by system and assume }",
|
||||
|
||||
// owner
|
||||
"{ grant perm:membership#M-1000117:DELETE to role:membership#M-1000117:OWNER by system and assume }",
|
||||
"{ grant perm:membership#M-1000117:DELETE to role:membership#M-1000117:ADMIN by system and assume }",
|
||||
"{ grant role:membership#M-1000117:OWNER to user:superuser-alex@hostsharing.net by membership#M-1000117:OWNER and assume }",
|
||||
|
||||
// admin
|
||||
"{ grant perm:membership#M-1000117:UPDATE to role:membership#M-1000117:ADMIN by system and assume }",
|
||||
"{ grant role:membership#M-1000117:ADMIN to role:membership#M-1000117:OWNER by system and assume }",
|
||||
"{ grant role:membership#M-1000117:OWNER to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN by system and assume }",
|
||||
"{ grant role:membership#M-1000117:OWNER to user:superuser-alex@hostsharing.net by membership#M-1000117:OWNER and assume }",
|
||||
"{ grant role:membership#M-1000117:ADMIN to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN by system and assume }",
|
||||
|
||||
// agent
|
||||
"{ grant role:membership#M-1000117:ADMIN to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT by system and assume }",
|
||||
"{ grant perm:membership#M-1000117:SELECT to role:membership#M-1000117:AGENT by system and assume }",
|
||||
"{ grant role:membership#M-1000117:AGENT to role:membership#M-1000117:ADMIN by system and assume }",
|
||||
|
||||
// referrer
|
||||
"{ grant perm:membership#M-1000117:SELECT to role:membership#M-1000117:REFERRER by system and assume }",
|
||||
"{ grant role:membership#M-1000117:REFERRER to role:membership#M-1000117:ADMIN by system and assume }",
|
||||
"{ grant role:relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT to role:membership#M-1000117:REFERRER by system and assume }",
|
||||
"{ grant role:membership#M-1000117:AGENT to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT by system and assume }",
|
||||
"{ grant role:relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT to role:membership#M-1000117:AGENT by system and assume }",
|
||||
|
||||
null));
|
||||
}
|
||||
@ -224,20 +223,20 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void membershipReferrer_canViewButNotUpdateRelatedMembership() {
|
||||
public void membershipAgent_canViewButNotUpdateRelatedMembership() {
|
||||
// given
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var givenMembership = givenSomeTemporaryMembership("First", "13");
|
||||
assertThatMembershipExistsAndIsAccessibleToCurrentContext(givenMembership);
|
||||
assertThatMembershipIsVisibleForRole(
|
||||
givenMembership,
|
||||
"hs_office_membership#M-1000113:REFERRER");
|
||||
"hs_office_membership#M-1000113:AGENT");
|
||||
final var newValidityEnd = LocalDate.now();
|
||||
|
||||
// when
|
||||
final var result = jpaAttempt.transacted(() -> {
|
||||
// TODO: we should test with debitor- and partner-admin as well
|
||||
context("superuser-alex@hostsharing.net", "hs_office_membership#M-1000113:REFERRER");
|
||||
context("superuser-alex@hostsharing.net", "hs_office_membership#M-1000113:AGENT");
|
||||
givenMembership.setValidity(
|
||||
Range.closedOpen(givenMembership.getValidity().lower(), newValidityEnd));
|
||||
return membershipRepo.save(givenMembership);
|
||||
|
@ -5,8 +5,7 @@ import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantRepository;
|
||||
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService;
|
||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRvEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository;
|
||||
import net.hostsharing.test.JpaAttempt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -255,7 +254,7 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
return rbacRoleRepo.findAll().stream()
|
||||
.map(RbacRoleRvEntity::getRoleName)
|
||||
.map(RbacRoleEntity::getRoleName)
|
||||
.collect(toSet());
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import io.restassured.http.ContentType;
|
||||
import io.restassured.response.ValidatableResponse;
|
||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
import net.hostsharing.hsadminng.context.ContextBasedTest;
|
||||
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRvEntity;
|
||||
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;
|
||||
@ -361,11 +361,11 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
|
||||
this(currentUser, "");
|
||||
}
|
||||
|
||||
GrantFixture grantsRole(final RbacRoleRvEntity givenOwnPackageAdminRole) {
|
||||
GrantFixture grantsRole(final RbacRoleEntity givenOwnPackageAdminRole) {
|
||||
return new GrantFixture(givenOwnPackageAdminRole);
|
||||
}
|
||||
|
||||
RevokeFixture revokesRole(final RbacRoleRvEntity givenOwnPackageAdminRole) {
|
||||
RevokeFixture revokesRole(final RbacRoleEntity givenOwnPackageAdminRole) {
|
||||
return new RevokeFixture(givenOwnPackageAdminRole);
|
||||
}
|
||||
|
||||
@ -376,11 +376,11 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
|
||||
class GrantFixture {
|
||||
|
||||
private Subject grantingSubject = Subject.this;
|
||||
private final RbacRoleRvEntity grantedRole;
|
||||
private final RbacRoleEntity grantedRole;
|
||||
private boolean assumed;
|
||||
private RbacUserEntity granteeUser;
|
||||
|
||||
public GrantFixture(final RbacRoleRvEntity roleToGrant) {
|
||||
public GrantFixture(final RbacRoleEntity roleToGrant) {
|
||||
this.grantedRole = roleToGrant;
|
||||
}
|
||||
|
||||
@ -417,11 +417,11 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
|
||||
class RevokeFixture {
|
||||
|
||||
private Subject currentSubject = Subject.this;
|
||||
private final RbacRoleRvEntity grantedRole;
|
||||
private final RbacRoleEntity grantedRole;
|
||||
private boolean assumed;
|
||||
private RbacUserEntity granteeUser;
|
||||
|
||||
public RevokeFixture(final RbacRoleRvEntity roleToGrant) {
|
||||
public RevokeFixture(final RbacRoleEntity roleToGrant) {
|
||||
this.grantedRole = roleToGrant;
|
||||
}
|
||||
|
||||
@ -455,9 +455,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
|
||||
private class GetGrantByIdFixture {
|
||||
|
||||
private Subject currentSubject = Subject.this;
|
||||
private RbacRoleRvEntity grantedRole;
|
||||
private RbacRoleEntity grantedRole;
|
||||
|
||||
GetGrantByIdFixture forGrantedRole(final RbacRoleRvEntity grantedRole) {
|
||||
GetGrantByIdFixture forGrantedRole(final RbacRoleEntity grantedRole) {
|
||||
this.grantedRole = grantedRole;
|
||||
return this;
|
||||
}
|
||||
@ -507,7 +507,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
|
||||
}).assertNotNull().returnedValue();
|
||||
}
|
||||
|
||||
RbacRoleRvEntity getRbacRoleByName(final String roleName) {
|
||||
RbacRoleEntity getRbacRoleByName(final String roleName) {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context("superuser-alex@hostsharing.net", null);
|
||||
return rbacRoleRepository.findByRoleName(roleName);
|
||||
|
@ -175,21 +175,21 @@ class RbacRoleRepositoryIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
void exactlyTheseRbacRolesAreReturned(final List<RbacRoleRvEntity> actualResult, final String... expectedRoleNames) {
|
||||
void exactlyTheseRbacRolesAreReturned(final List<RbacRoleEntity> actualResult, final String... expectedRoleNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(RbacRoleRvEntity::getRoleName)
|
||||
.extracting(RbacRoleEntity::getRoleName)
|
||||
.containsExactlyInAnyOrder(expectedRoleNames);
|
||||
}
|
||||
|
||||
void allTheseRbacRolesAreReturned(final List<RbacRoleRvEntity> actualResult, final String... expectedRoleNames) {
|
||||
void allTheseRbacRolesAreReturned(final List<RbacRoleEntity> actualResult, final String... expectedRoleNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(RbacRoleRvEntity::getRoleName)
|
||||
.extracting(RbacRoleEntity::getRoleName)
|
||||
.contains(expectedRoleNames);
|
||||
}
|
||||
|
||||
void noneOfTheseRbacRolesIsReturned(final List<RbacRoleRvEntity> actualResult, final String... unexpectedRoleNames) {
|
||||
void noneOfTheseRbacRolesIsReturned(final List<RbacRoleEntity> actualResult, final String... unexpectedRoleNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(RbacRoleRvEntity::getRoleName)
|
||||
.extracting(RbacRoleEntity::getRoleName)
|
||||
.doesNotContain(unexpectedRoleNames);
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,11 @@ import static java.util.UUID.randomUUID;
|
||||
|
||||
public class TestRbacRole {
|
||||
|
||||
public static final RbacRoleRvEntity hostmasterRole = rbacRole("global", "global", RbacRoleType.ADMIN);
|
||||
static final RbacRoleRvEntity customerXxxOwner = rbacRole("test_customer", "xxx", RbacRoleType.OWNER);
|
||||
static final RbacRoleRvEntity customerXxxAdmin = rbacRole("test_customer", "xxx", RbacRoleType.ADMIN);
|
||||
public static final RbacRoleEntity hostmasterRole = rbacRole("global", "global", RbacRoleType.ADMIN);
|
||||
static final RbacRoleEntity customerXxxOwner = rbacRole("test_customer", "xxx", RbacRoleType.OWNER);
|
||||
static final RbacRoleEntity customerXxxAdmin = rbacRole("test_customer", "xxx", RbacRoleType.ADMIN);
|
||||
|
||||
static public RbacRoleRvEntity rbacRole(final String objectTable, final String objectIdName, final RbacRoleType roleType) {
|
||||
return new RbacRoleRvEntity(randomUUID(), randomUUID(), objectTable, objectIdName, roleType, objectTable+'#'+objectIdName+':'+roleType);
|
||||
static public RbacRoleEntity rbacRole(final String objectTable, final String objectIdName, final RbacRoleType roleType) {
|
||||
return new RbacRoleEntity(randomUUID(), randomUUID(), objectTable, objectIdName, roleType, objectTable+'#'+objectIdName+':'+roleType);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user