> listCustomers(
@@ -48,7 +53,6 @@ public class TestCustomerController implements TestCustomersApi {
context.define(currentUser, assumedRoles);
final var saved = testCustomerRepository.save(mapper.map(customer, TestCustomerEntity.class));
-
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/test/customers/{id}")
diff --git a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java
index 1f2bb0e1..99b0fb3c 100644
--- a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java
@@ -4,17 +4,27 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import net.hostsharing.hsadminng.persistence.HasUuid;
+import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
+import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import jakarta.persistence.*;
+import java.io.IOException;
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.Role.*;
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
+
@Entity
@Table(name = "test_customer_rv")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
-public class TestCustomerEntity {
+public class TestCustomerEntity implements HasUuid {
@Id
@GeneratedValue
@@ -25,4 +35,29 @@ public class TestCustomerEntity {
@Column(name = "adminusername")
private String adminUserName;
+
+ public static RbacView rbac() {
+ return rbacViewFor("customer", TestCustomerEntity.class)
+ .withIdentityView(SQL.projection("prefix"))
+ .withRestrictedViewOrderBy(SQL.expression("reference"))
+ .withUpdatableColumns("reference", "prefix", "adminUserName")
+ // TODO: do we want explicit specification of parent-independent insert permissions?
+ // .toRole("global", ADMIN).grantPermission("customer", INSERT)
+
+ .createRole(OWNER, (with) -> {
+ with.owningUser(CREATOR).unassumed();
+ with.incomingSuperRole(GLOBAL, ADMIN).unassumed();
+ with.permission(DELETE);
+ })
+ .createSubRole(ADMIN, (with) -> {
+ with.permission(UPDATE);
+ })
+ .createSubRole(TENANT, (with) -> {
+ with.permission(SELECT);
+ });
+ }
+
+ public static void main(String[] args) throws IOException {
+ rbac().generateWithBaseFileName("113-test-customer-rbac");
+ }
}
diff --git a/src/main/java/net/hostsharing/hsadminng/test/dom/TestDomainEntity.java b/src/main/java/net/hostsharing/hsadminng/test/dom/TestDomainEntity.java
new file mode 100644
index 00000000..6a031df7
--- /dev/null
+++ b/src/main/java/net/hostsharing/hsadminng/test/dom/TestDomainEntity.java
@@ -0,0 +1,73 @@
+package net.hostsharing.hsadminng.test.dom;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+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.test.pac.TestPackageEntity;
+
+import jakarta.persistence.*;
+import java.io.IOException;
+import java.util.UUID;
+
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
+
+@Entity
+@Table(name = "test_domain_rv")
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class TestDomainEntity implements HasUuid {
+
+ @Id
+ @GeneratedValue
+ private UUID uuid;
+
+ @Version
+ private int version;
+
+ @ManyToOne(optional = false)
+ @JoinColumn(name = "packageuuid")
+ private TestPackageEntity pac;
+
+ private String name;
+
+ private String description;
+
+ public static RbacView rbac() {
+ return rbacViewFor("domain", TestDomainEntity.class)
+ .withIdentityView(SQL.projection("name"))
+ .withUpdatableColumns("version", "packageUuid", "description")
+
+ .importEntityAlias("package", TestPackageEntity.class,
+ dependsOnColumn("packageUuid"),
+ fetchedBySql("""
+ SELECT * FROM test_package p
+ WHERE p.uuid= ${ref}.packageUuid
+ """))
+ .toRole("package", ADMIN).grantPermission("domain", INSERT)
+
+ .createRole(OWNER, (with) -> {
+ with.incomingSuperRole("package", ADMIN);
+ with.outgoingSubRole("package", TENANT);
+ with.permission(DELETE);
+ with.permission(UPDATE);
+ })
+ .createSubRole(ADMIN, (with) -> {
+ with.outgoingSubRole("package", TENANT);
+ with.permission(SELECT);
+ });
+ }
+
+ public static void main(String[] args) throws IOException {
+ rbac().generateWithBaseFileName("133-test-domain-rbac");
+ }
+}
diff --git a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java
index 8687666f..757fcf05 100644
--- a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java
@@ -4,18 +4,28 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+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.test.cust.TestCustomerEntity;
import jakarta.persistence.*;
+import java.io.IOException;
import java.util.UUID;
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
+import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
+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;
+
@Entity
@Table(name = "test_package_rv")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
-public class TestPackageEntity {
+public class TestPackageEntity implements HasUuid {
@Id
@GeneratedValue
@@ -31,4 +41,34 @@ public class TestPackageEntity {
private String name;
private String description;
+
+
+ public static RbacView rbac() {
+ return rbacViewFor("package", TestPackageEntity.class)
+ .withIdentityView(SQL.projection("name"))
+ .withUpdatableColumns("version", "customerUuid", "description")
+
+ .importEntityAlias("customer", TestCustomerEntity.class,
+ dependsOnColumn("customerUuid"),
+ fetchedBySql("""
+ SELECT * FROM test_customer c
+ WHERE c.uuid= ${ref}.customerUuid
+ """))
+ .toRole("customer", ADMIN).grantPermission("package", INSERT)
+
+ .createRole(OWNER, (with) -> {
+ with.incomingSuperRole("customer", ADMIN);
+ with.permission(DELETE);
+ with.permission(UPDATE);
+ })
+ .createSubRole(ADMIN)
+ .createSubRole(TENANT, (with) -> {
+ with.outgoingSubRole("customer", TENANT);
+ with.permission(SELECT);
+ });
+ }
+
+ public static void main(String[] args) throws IOException {
+ rbac().generateWithBaseFileName("123-test-package-rbac");
+ }
}
diff --git a/src/main/resources/db/changelog/010-context.sql b/src/main/resources/db/changelog/010-context.sql
index 4820cf9c..8de41891 100644
--- a/src/main/resources/db/changelog/010-context.sql
+++ b/src/main/resources/db/changelog/010-context.sql
@@ -23,22 +23,27 @@ end; $$;
Defines the transaction context.
*/
create or replace procedure defineContext(
- currentTask varchar,
- currentRequest varchar = null,
- currentUser varchar = null,
- assumedRoles varchar = null
+ currentTask varchar(96),
+ currentRequest text = null,
+ currentUser varchar(63) = null,
+ assumedRoles varchar(256) = null
)
language plpgsql as $$
begin
+ currentTask := coalesce(currentTask, '');
+ assert length(currentTask) <= 96, FORMAT('currentTask must not be longer than 96 characters: "%s"', currentTask);
+ assert length(currentTask) > 8, FORMAT('currentTask must be at least 8 characters long: "%s""', currentTask);
execute format('set local hsadminng.currentTask to %L', currentTask);
currentRequest := coalesce(currentRequest, '');
execute format('set local hsadminng.currentRequest to %L', currentRequest);
currentUser := coalesce(currentUser, '');
+ assert length(currentUser) <= 63, FORMAT('currentUser must not be longer than 63 characters: "%s"', currentUser);
execute format('set local hsadminng.currentUser to %L', currentUser);
assumedRoles := coalesce(assumedRoles, '');
+ assert length(assumedRoles) <= 256, FORMAT('assumedRoles must not be longer than 256 characters: "%s"', assumedRoles);
execute format('set local hsadminng.assumedRoles to %L', assumedRoles);
call contextDefined(currentTask, currentRequest, currentUser, assumedRoles);
diff --git a/src/main/resources/db/changelog/020-audit-log.sql b/src/main/resources/db/changelog/020-audit-log.sql
index 173e5741..ec14ad0d 100644
--- a/src/main/resources/db/changelog/020-audit-log.sql
+++ b/src/main/resources/db/changelog/020-audit-log.sql
@@ -27,9 +27,9 @@ create table tx_context
txId bigint not null,
txTimestamp timestamp not null,
currentUser varchar(63) not null, -- not the uuid, because users can be deleted
- assumedRoles varchar not null, -- not the uuids, because roles can be deleted
+ assumedRoles varchar(256) not null, -- not the uuids, because roles can be deleted
currentTask varchar(96) not null,
- currentRequest varchar(512) not null
+ currentRequest text not null
);
create index on tx_context using brin (txTimestamp);
diff --git a/src/main/resources/db/changelog/050-rbac-base.sql b/src/main/resources/db/changelog/050-rbac-base.sql
index fe2f30ae..2992d6a9 100644
--- a/src/main/resources/db/changelog/050-rbac-base.sql
+++ b/src/main/resources/db/changelog/050-rbac-base.sql
@@ -86,29 +86,6 @@ create or replace function findRbacUserId(userName varchar)
language sql as $$
select uuid from RbacUser where name = userName
$$;
-
-create type RbacWhenNotExists as enum ('fail', 'create');
-
-create or replace function getRbacUserId(userName varchar, whenNotExists RbacWhenNotExists)
- returns uuid
- returns null on null input
- language plpgsql as $$
-declare
- userUuid uuid;
-begin
- userUuid = findRbacUserId(userName);
- if (userUuid is null) then
- if (whenNotExists = 'fail') then
- raise exception 'RbacUser with name="%" not found', userName;
- end if;
- if (whenNotExists = 'create') then
- userUuid = createRbacUser(userName);
- end if;
- end if;
- return userUuid;
-end;
-$$;
-
--//
-- ============================================================================
@@ -203,15 +180,33 @@ create type RbacRoleDescriptor as
(
objectTable varchar(63), -- for human readability and easier debugging
objectUuid uuid,
- roleType RbacRoleType
+ roleType RbacRoleType,
+ assumed boolean
);
-create or replace function roleDescriptor(objectTable varchar(63), objectUuid uuid, roleType RbacRoleType)
+create or replace function assumed()
+ returns boolean
+ stable -- leakproof
+ language sql as $$
+ select true;
+$$;
+
+create or replace function unassumed()
+ returns boolean
+ stable -- leakproof
+ language sql as $$
+select false;
+$$;
+
+
+create or replace function roleDescriptor(
+ objectTable varchar(63), objectUuid uuid, roleType RbacRoleType,
+ assumed boolean = true) -- just for DSL readability, belongs actually to the grant
returns RbacRoleDescriptor
returns null on null input
stable -- leakproof
language sql as $$
-select objectTable, objectUuid, roleType::RbacRoleType;
+ select objectTable, objectUuid, roleType::RbacRoleType, assumed;
$$;
create or replace function createRole(roleDescriptor RbacRoleDescriptor)
@@ -275,21 +270,17 @@ create or replace function findRoleId(roleDescriptor RbacRoleDescriptor)
select uuid from RbacRole where objectUuid = roleDescriptor.objectUuid and roleType = roleDescriptor.roleType;
$$;
-create or replace function getRoleId(roleDescriptor RbacRoleDescriptor, whenNotExists RbacWhenNotExists)
+create or replace function getRoleId(roleDescriptor RbacRoleDescriptor)
returns uuid
- returns null on null input
language plpgsql as $$
declare
roleUuid uuid;
begin
- roleUuid = findRoleId(roleDescriptor);
+ assert roleDescriptor is not null, 'roleDescriptor must not be null';
+
+ roleUuid := findRoleId(roleDescriptor);
if (roleUuid is null) then
- if (whenNotExists = 'fail') then
- raise exception 'RbacRole "%#%.%" not found', roleDescriptor.objectTable, roleDescriptor.objectUuid, roleDescriptor.roleType;
- end if;
- if (whenNotExists = 'create') then
- roleUuid = createRole(roleDescriptor);
- end if;
+ raise exception 'RbacRole "%#%.%" not found', roleDescriptor.objectTable, roleDescriptor.objectUuid, roleDescriptor.roleType;
end if;
return roleUuid;
end;
@@ -365,38 +356,63 @@ create trigger deleteRbacRolesOfRbacObject_Trigger
/*
*/
-create domain RbacOp as varchar(67)
+create domain RbacOp as varchar(67) -- TODO: shorten to 8, once the deprecated values are gone
check (
- VALUE = '*'
- or VALUE = 'delete'
- or VALUE = 'edit'
- or VALUE = 'view'
- or VALUE = 'assume'
+ 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
(
- uuid uuid primary key references RbacReference (uuid) on delete cascade,
- objectUuid uuid not null references RbacObject,
- op RbacOp not null,
+ uuid uuid primary key references RbacReference (uuid) on delete cascade,
+ objectUuid uuid not null references RbacObject,
+ op RbacOp not null,
+ opTableName varchar(60),
unique (objectUuid, op)
);
call create_journal('RbacPermission');
-create or replace function permissionExists(forObjectUuid uuid, forOp RbacOp)
- returns bool
- language sql as $$
-select exists(
- select op
- from RbacPermission p
- where p.objectUuid = forObjectUuid
- and p.op in ('*', forOp)
- );
-$$;
+create or replace function createPermission(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
+ returns uuid
+ language plpgsql as $$
+declare
+ permissionUuid uuid;
+begin
+ if (forObjectUuid is null) then
+ raise exception 'forObjectUuid must not be null';
+ end if;
+ if (forOp = 'INSERT' and forOpTableName is null) then
+ raise exception 'INSERT permissions needs forOpTableName';
+ end if;
+ if (forOp <> 'INSERT' and forOpTableName is not null) then
+ raise exception 'forOpTableName must only be specified for ops: [INSERT]'; -- currently no other
+ end if;
+ permissionUuid = (select uuid from RbacPermission where objectUuid = forObjectUuid and op = forOp and opTableName = forOpTableName);
+ if (permissionUuid is null) then
+ insert into RbacReference ("type")
+ values ('RbacPermission')
+ returning uuid into permissionUuid;
+ begin
+ insert into RbacPermission (uuid, objectUuid, op, opTableName)
+ values (permissionUuid, forObjectUuid, forOp, forOpTableName);
+ exception
+ when others then
+ raise exception 'insert into RbacPermission (uuid, objectUuid, op, opTableName)
+ values (%, %, %, %);', permissionUuid, forObjectUuid, forOp, forOpTableName;
+ end;
+ end if;
+ 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 $$
@@ -407,9 +423,6 @@ begin
if (forObjectUuid is null) then
raise exception 'forObjectUuid must not be null';
end if;
- if (array_length(permitOps, 1) > 1 and '*' = any (permitOps)) then
- raise exception '"*" operation must not be assigned along with other operations: %', permitOps;
- end if;
for i in array_lower(permitOps, 1)..array_upper(permitOps, 1)
loop
@@ -430,7 +443,19 @@ begin
end;
$$;
-create or replace function findPermissionId(forObjectUuid uuid, forOp RbacOp)
+create or replace function findEffectivePermissionId(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
+ returns uuid
+ returns null on null input
+ stable -- leakproof
+ language sql as $$
+select uuid
+ from RbacPermission p
+ where p.objectUuid = forObjectUuid
+ and (forOp = 'SELECT' or p.op = forOp) -- all other RbacOp include 'SELECT'
+ and p.opTableName = forOpTableName
+$$;
+
+create or replace function findPermissionId(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
returns uuid
returns null on null input
stable -- leakproof
@@ -439,23 +464,8 @@ select uuid
from RbacPermission p
where p.objectUuid = forObjectUuid
and p.op = forOp
+ and p.opTableName = forOpTableName
$$;
-
-create or replace function findEffectivePermissionId(forObjectUuid uuid, forOp RbacOp)
- returns uuid
- returns null on null input
- stable -- leakproof
- language plpgsql as $$
-declare
- permissionId uuid;
-begin
- permissionId := findPermissionId(forObjectUuid, forOp);
- if permissionId is null and forOp <> '*' then
- permissionId := findPermissionId(forObjectUuid, '*');
- end if;
- return permissionId;
-end $$;
-
--//
-- ============================================================================
@@ -552,6 +562,18 @@ select exists(
);
$$;
+create or replace function hasInsertPermission(objectUuid uuid, forOp RbacOp, tableName text )
+ returns BOOL
+ stable -- leakproof
+ language plpgsql as $$
+declare
+ permissionUuid uuid;
+begin
+ permissionUuid = findPermissionId(objectUuid, forOp, tableName);
+ return permissionUuid is not null;
+end;
+$$;
+
create or replace function hasGlobalRoleGranted(userUuid uuid)
returns bool
stable -- leakproof
@@ -566,6 +588,27 @@ select exists(
);
$$;
+create or replace procedure grantPermissionToRole(roleUuid uuid, permissionUuid uuid)
+ language plpgsql as $$
+begin
+ perform assertReferenceType('roleId (ascendant)', roleUuid, 'RbacRole');
+ perform assertReferenceType('permissionId (descendant)', permissionUuid, 'RbacPermission');
+
+ insert
+ into RbacGrants (grantedByTriggerOf, ascendantUuid, descendantUuid, assumed)
+ values (currentTriggerObjectUuid(), roleUuid, permissionUuid, true)
+ on conflict do nothing; -- allow granting multiple times
+end;
+$$;
+
+create or replace procedure grantPermissionToRole(roleDesc RbacRoleDescriptor, permissionUuid uuid)
+ language plpgsql as $$
+begin
+ call grantPermissionToRole(findRoleId(roleDesc), permissionUuid);
+end;
+$$;
+
+-- TODO: deprecated, remove and use grantPermissionToRole(...)
create or replace procedure grantPermissionsToRole(roleUuid uuid, permissionIds uuid[])
language plpgsql as $$
begin
@@ -697,7 +740,7 @@ begin
select descendantUuid
from grants) as granted
join RbacPermission perm
- on granted.descendantUuid = perm.uuid and perm.op in ('*', requiredOp)
+ on granted.descendantUuid = perm.uuid and (requiredOp = 'SELECT' or perm.op = requiredOp)
join RbacObject obj on obj.uuid = perm.objectUuid and obj.objectTable = forObjectTable
limit maxObjects + 1;
@@ -789,6 +832,5 @@ do $$
create role restricted;
grant all privileges on all tables in schema public to restricted;
end if;
- end $$
+ end $$;
--//
-
diff --git a/src/main/resources/db/changelog/051-rbac-user-grant.sql b/src/main/resources/db/changelog/051-rbac-user-grant.sql
index 23dcbdd4..a82865c8 100644
--- a/src/main/resources/db/changelog/051-rbac-user-grant.sql
+++ b/src/main/resources/db/changelog/051-rbac-user-grant.sql
@@ -30,24 +30,35 @@ begin
insert
into RbacGrants (grantedByRoleUuid, ascendantUuid, descendantUuid, assumed)
values (grantedByRoleUuid, userUuid, roleUuid, doAssume);
- -- TODO.spec: What should happen on mupltiple grants? What if options (doAssume) are not the same?
+ -- TODO.spec: What should happen on multiple grants? What if options (doAssume) are not the same?
-- Most powerful or latest grant wins? What about managed?
-- on conflict do nothing; -- allow granting multiple times
end; $$;
create or replace procedure grantRoleToUser(grantedByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid, doAssume boolean = true)
language plpgsql as $$
+declare
+ grantedByRoleIdName text;
+ grantedRoleIdName text;
begin
perform assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'RbacRole');
perform assertReferenceType('grantedRoleUuid (descendant)', grantedRoleUuid, 'RbacRole');
perform assertReferenceType('userUuid (ascendant)', userUuid, 'RbacUser');
- if NOT isGranted(currentSubjectsUuids(), grantedByRoleUuid) then
- raise exception '[403] Access to granted-by-role % forbidden for %', grantedByRoleUuid, currentSubjects();
- end if;
+ assert grantedByRoleUuid is not null, 'grantedByRoleUuid must not be null';
+ assert grantedRoleUuid is not null, 'grantedRoleUuid must not be null';
+ assert userUuid is not null, 'userUuid must not be null';
+ if NOT isGranted(currentSubjectsUuids(), grantedByRoleUuid) then
+ select roleIdName from rbacRole_ev where uuid=grantedByRoleUuid into grantedByRoleIdName;
+ raise exception '[403] Access to granted-by-role % (%) forbidden for % (%)',
+ grantedByRoleIdName, grantedByRoleUuid, currentSubjects(), currentSubjectsUuids();
+ end if;
if NOT isGranted(grantedByRoleUuid, grantedRoleUuid) then
- raise exception '[403] Access to granted role % forbidden for %', grantedRoleUuid, currentSubjects();
+ select roleIdName from rbacRole_ev where uuid=grantedByRoleUuid into grantedByRoleIdName;
+ select roleIdName from rbacRole_ev where uuid=grantedRoleUuid into grantedRoleIdName;
+ raise exception '[403] Access to granted role % (%) forbidden for % (%)',
+ grantedRoleIdName, grantedRoleUuid, grantedByRoleIdName, grantedByRoleUuid;
end if;
insert
@@ -99,4 +110,17 @@ begin
where g.ascendantUuid = userUuid and g.descendantUuid = grantedRoleUuid
and g.grantedByRoleUuid = revokeRoleFromUser.grantedByRoleUuid;
end; $$;
---/
+--//
+
+-- ============================================================================
+--changeset rbac-user-grant-REVOKE-PERMISSION-FROM-ROLE:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+create or replace procedure revokePermissionFromRole(permissionUuid uuid, superRoleUuid uuid)
+ language plpgsql as $$
+begin
+ raise INFO 'delete from RbacGrants where ascendantUuid = % and descendantUuid = %', superRoleUuid, permissionUuid;
+ delete from RbacGrants as g
+ where g.ascendantUuid = superRoleUuid and g.descendantUuid = permissionUuid;
+end; $$;
+--//
diff --git a/src/main/resources/db/changelog/055-rbac-views.sql b/src/main/resources/db/changelog/055-rbac-views.sql
index b1757c56..b494d120 100644
--- a/src/main/resources/db/changelog/055-rbac-views.sql
+++ b/src/main/resources/db/changelog/055-rbac-views.sql
@@ -337,11 +337,9 @@ 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 grantedPermissions(targetUserUuid uuid)
- returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, objectTable varchar, objectIdName varchar, objectUuid uuid)
+*/
+create or replace function grantedPermissionsRaw(targetUserUuid 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 $$
declare
@@ -357,11 +355,13 @@ begin
return query select
xp.roleUuid,
(xp.roleObjectTable || '#' || xp.roleObjectIdName || '.' || xp.roleType) as roleName,
- xp.permissionUuid, xp.op, xp.permissionObjectTable, xp.permissionObjectIdName, xp.permissionObjectUuid
+ xp.permissionUuid, xp.op, xp.opTableName,
+ xp.permissionObjectTable, xp.permissionObjectIdName, xp.permissionObjectUuid
from (select
r.uuid as roleUuid, r.roletype, ro.objectTable as roleObjectTable,
findIdNameByObjectUuid(ro.objectTable, ro.uuid) as roleObjectIdName,
- p.uuid as permissionUuid, p.op, po.objecttable as permissionObjectTable,
+ p.uuid as permissionUuid, p.op, p.opTableName,
+ po.objecttable as permissionObjectTable,
findIdNameByObjectUuid(po.objectTable, po.uuid) as permissionObjectIdName,
po.uuid as permissionObjectUuid
from queryPermissionsGrantedToSubjectId( targetUserUuid) as p
@@ -373,4 +373,15 @@ begin
) xp;
-- @formatter:on
end; $$;
+
+create or replace function grantedPermissions(targetUserUuid 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(targetUserUuid)
+ union all
+ select roleUuid, roleName, permissionUuid, 'SELECT'::RbacOp, opTableName, objectTable, objectIdName, objectUuid
+ from grantedPermissionsRaw(targetUserUuid)
+ where op <> 'SELECT'::RbacOp;
+$$;
--//
diff --git a/src/main/resources/db/changelog/057-rbac-role-builder.sql b/src/main/resources/db/changelog/057-rbac-role-builder.sql
index 81a81590..1a7da953 100644
--- a/src/main/resources/db/changelog/057-rbac-role-builder.sql
+++ b/src/main/resources/db/changelog/057-rbac-role-builder.sql
@@ -13,24 +13,6 @@ begin
return createPermissions(forObjectUuid, permitOps);
end; $$;
-create or replace function toRoleUuids(roleDescriptors RbacRoleDescriptor[])
- returns uuid[]
- language plpgsql
- strict as $$
-declare
- superRoleDescriptor RbacRoleDescriptor;
- superRoleUuids uuid[] := array []::uuid[];
-begin
- foreach superRoleDescriptor in array roleDescriptors
- loop
- if superRoleDescriptor is not null then
- superRoleUuids := superRoleUuids || getRoleId(superRoleDescriptor, 'fail');
- end if;
- end loop;
-
- return superRoleUuids;
-end; $$;
-
-- =================================================================
-- CREATE ROLE
@@ -50,32 +32,37 @@ create or replace function createRoleWithGrants(
language plpgsql as $$
declare
roleUuid uuid;
- superRoleUuid uuid;
+ subRoleDesc RbacRoleDescriptor;
+ superRoleDesc RbacRoleDescriptor;
subRoleUuid uuid;
+ superRoleUuid uuid;
userUuid uuid;
grantedByRoleUuid uuid;
begin
roleUuid := createRole(roleDescriptor);
- if cardinality(permissions) >0 then
+ if cardinality(permissions) > 0 then
call grantPermissionsToRole(roleUuid, toPermissionUuids(roleDescriptor.objectuuid, permissions));
end if;
- foreach superRoleUuid in array toRoleUuids(incomingSuperRoles)
+ foreach superRoleDesc in array array_remove(incomingSuperRoles, null)
loop
- call grantRoleToRole(roleUuid, superRoleUuid);
+ superRoleUuid := getRoleId(superRoleDesc);
+ call grantRoleToRole(roleUuid, superRoleUuid, superRoleDesc.assumed);
end loop;
- foreach subRoleUuid in array toRoleUuids(outgoingSubRoles)
+ foreach subRoleDesc in array array_remove(outgoingSubRoles, null)
loop
- call grantRoleToRole(subRoleUuid, roleUuid);
+ subRoleUuid := getRoleId(subRoleDesc);
+ call grantRoleToRole(subRoleUuid, roleUuid, subRoleDesc.assumed);
end loop;
if cardinality(userUuids) > 0 then
if grantedByRole is null then
- raise exception 'to directly assign users to roles, grantingRole has to be given';
+ grantedByRoleUuid := roleUuid;
+ else
+ grantedByRoleUuid := getRoleId(grantedByRole);
end if;
- grantedByRoleUuid := getRoleId(grantedByRole, 'fail');
foreach userUuid in array userUuids
loop
call grantRoleToUserUnchecked(grantedByRoleUuid, roleUuid, userUuid);
diff --git a/src/main/resources/db/changelog/058-rbac-generators.sql b/src/main/resources/db/changelog/058-rbac-generators.sql
index fa198308..89d585ea 100644
--- a/src/main/resources/db/changelog/058-rbac-generators.sql
+++ b/src/main/resources/db/changelog/058-rbac-generators.sql
@@ -13,8 +13,7 @@ declare
begin
createInsertTriggerSQL = format($sql$
create trigger createRbacObjectFor_%s_Trigger
- before insert
- on %s
+ before insert on %s
for each row
execute procedure insertRelatedRbacObject();
$sql$, targetTable, targetTable);
@@ -36,50 +35,50 @@ end; $$;
--changeset rbac-generators-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-create or replace procedure generateRbacRoleDescriptors(prefix text, targetTable text)
+create procedure generateRbacRoleDescriptors(prefix text, targetTable text)
language plpgsql as $$
declare
sql text;
begin
sql = format($sql$
- create or replace function %1$sOwner(entity %2$s)
+ create or replace function %1$sOwner(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor
language plpgsql
strict as $f$
begin
- return roleDescriptor('%2$s', entity.uuid, 'owner');
+ return roleDescriptor('%2$s', entity.uuid, 'owner', assumed);
end; $f$;
- create or replace function %1$sAdmin(entity %2$s)
+ create or replace function %1$sAdmin(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor
language plpgsql
strict as $f$
begin
- return roleDescriptor('%2$s', entity.uuid, 'admin');
+ return roleDescriptor('%2$s', entity.uuid, 'admin', assumed);
end; $f$;
- create or replace function %1$sAgent(entity %2$s)
+ create or replace function %1$sAgent(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor
language plpgsql
strict as $f$
begin
- return roleDescriptor('%2$s', entity.uuid, 'agent');
+ return roleDescriptor('%2$s', entity.uuid, 'agent', assumed);
end; $f$;
- create or replace function %1$sTenant(entity %2$s)
+ create or replace function %1$sTenant(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor
language plpgsql
strict as $f$
begin
- return roleDescriptor('%2$s', entity.uuid, 'tenant');
+ return roleDescriptor('%2$s', entity.uuid, 'tenant', assumed);
end; $f$;
- create or replace function %1$sGuest(entity %2$s)
+ 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');
+ return roleDescriptor('%2$s', entity.uuid, 'guest', assumed);
end; $f$;
$sql$, prefix, targetTable);
@@ -92,7 +91,7 @@ end; $$;
--changeset rbac-generators-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-create or replace procedure generateRbacIdentityView(targetTable text, idNameExpression text)
+create or replace procedure generateRbacIdentityViewFromQuery(targetTable text, sqlQuery text)
language plpgsql as $$
declare
sql text;
@@ -101,11 +100,9 @@ begin
-- create a view to the target main table which maps an idName to the objectUuid
sql = format($sql$
- create or replace view %1$s_iv as
- select target.uuid, cleanIdentifier(%2$s) as idName
- from %1$s as target;
+ create or replace view %1$s_iv as %2$s;
grant all privileges on %1$s_iv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
- $sql$, targetTable, idNameExpression);
+ $sql$, targetTable, sqlQuery);
execute sql;
-- creates a function which maps an idName to the objectUuid
@@ -130,6 +127,20 @@ begin
$sql$, targetTable);
execute sql;
end; $$;
+
+create or replace procedure generateRbacIdentityViewFromProjection(targetTable text, sqlProjection text)
+ language plpgsql as $$
+declare
+ sqlQuery text;
+begin
+ targettable := lower(targettable);
+
+ sqlQuery = format($sql$
+ select target.uuid, cleanIdentifier(%2$s) as idName
+ from %1$s as target;
+ $sql$, targetTable, sqlProjection);
+ call generateRbacIdentityViewFromQuery(targetTable, sqlQuery);
+end; $$;
--//
@@ -145,13 +156,13 @@ begin
targetTable := lower(targetTable);
/*
- Creates a restricted view based on the 'view' permission of the current subject.
+ Creates a restricted view based on the 'SELECT' permission of the current subject.
*/
sql := format($sql$
set session session authorization default;
create view %1$s_rv as
with accessibleObjects as (
- select queryAccessibleObjectUuidsOfSubjectIds('view', '%1$s', currentSubjectsUuids())
+ select queryAccessibleObjectUuidsOfSubjectIds('SELECT', '%1$s', currentSubjectsUuids())
)
select target.*
from %1$s as target
@@ -200,7 +211,7 @@ begin
returns trigger
language plpgsql as $f$
begin
- if old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', '%1$s', currentSubjectsUuids())) then
+ if old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('DELETE', '%1$s', currentSubjectsUuids())) then
delete from %1$s p where p.uuid = old.uuid;
return old;
end if;
@@ -223,7 +234,7 @@ begin
/**
Instead of update trigger function for the restricted view
- based on the 'edit' permission of the current subject.
+ based on the 'UPDATE' permission of the current subject.
*/
if columnUpdates is not null then
sql := format($sql$
@@ -231,7 +242,7 @@ begin
returns trigger
language plpgsql as $f$
begin
- if old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('edit', '%1$s', currentSubjectsUuids())) then
+ if old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('UPDATE', '%1$s', currentSubjectsUuids())) then
update %1$s
set %2$s
where uuid = old.uuid;
diff --git a/src/main/resources/db/changelog/080-rbac-global.sql b/src/main/resources/db/changelog/080-rbac-global.sql
index 034400fa..8313d05d 100644
--- a/src/main/resources/db/changelog/080-rbac-global.sql
+++ b/src/main/resources/db/changelog/080-rbac-global.sql
@@ -22,6 +22,19 @@ grant select on global to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
--//
+-- ============================================================================
+--changeset rbac-global-IS-GLOBAL-ADMIN:1 endDelimiter:--//
+-- ------------------------------------------------------------------
+
+create or replace function isGlobalAdmin()
+ returns boolean
+ language plpgsql as $$
+begin
+ return isGranted(currentSubjectsUuids(), findRoleId(globalAdmin()));
+end; $$;
+--//
+
+
-- ============================================================================
--changeset rbac-global-HAS-GLOBAL-PERMISSION:1 endDelimiter:--//
-- ------------------------------------------------------------------
@@ -96,12 +109,12 @@ commit;
/*
A global administrator role.
*/
-create or replace function globalAdmin()
+create or replace function globalAdmin(assumed boolean = true)
returns RbacRoleDescriptor
returns null on null input
stable -- leakproof
language sql as $$
-select 'global', (select uuid from RbacObject where objectTable = 'global'), 'admin'::RbacRoleType;
+select 'global', (select uuid from RbacObject where objectTable = 'global'), 'admin'::RbacRoleType, assumed;
$$;
begin transaction;
diff --git a/src/main/resources/db/changelog/113-test-customer-rbac.md b/src/main/resources/db/changelog/113-test-customer-rbac.md
new file mode 100644
index 00000000..7770e470
--- /dev/null
+++ b/src/main/resources/db/changelog/113-test-customer-rbac.md
@@ -0,0 +1,43 @@
+### rbac customer
+
+This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-11T11:29:11.571772062.
+
+```mermaid
+%%{init:{'flowchart':{'htmlLabels':false}}}%%
+flowchart TB
+
+subgraph customer["`**customer**`"]
+ direction TB
+ style customer fill:#dd4901,stroke:#274d6e,stroke-width:8px
+
+ subgraph customer:roles[ ]
+ style customer:roles fill:#dd4901,stroke:white
+
+ role:customer:owner[[customer:owner]]
+ role:customer:admin[[customer:admin]]
+ role:customer:tenant[[customer:tenant]]
+ end
+
+ subgraph customer:permissions[ ]
+ style customer:permissions fill:#dd4901,stroke:white
+
+ perm:customer:DELETE{{customer:DELETE}}
+ perm:customer:UPDATE{{customer:UPDATE}}
+ perm:customer:SELECT{{customer:SELECT}}
+ end
+end
+
+%% granting roles to users
+user:creator ==>|XX| role:customer:owner
+
+%% granting roles to roles
+role:global:admin ==>|XX| role:customer:owner
+role:customer:owner ==> role:customer:admin
+role:customer:admin ==> role:customer:tenant
+
+%% granting permissions to roles
+role:customer:owner ==> perm:customer:DELETE
+role:customer:admin ==> perm:customer:UPDATE
+role:customer:tenant ==> perm:customer:SELECT
+
+```
diff --git a/src/main/resources/db/changelog/113-test-customer-rbac.sql b/src/main/resources/db/changelog/113-test-customer-rbac.sql
index d7682cc1..6ae19710 100644
--- a/src/main/resources/db/changelog/113-test-customer-rbac.sql
+++ b/src/main/resources/db/changelog/113-test-customer-rbac.sql
@@ -1,4 +1,5 @@
--liquibase formatted sql
+-- This code generated was by RbacViewPostgresGenerator at 2024-03-11T11:29:11.584886824.
-- ============================================================================
--changeset test-customer-rbac-OBJECT:1 endDelimiter:--//
@@ -15,82 +16,103 @@ call generateRbacRoleDescriptors('testCustomer', 'test_customer');
-- ============================================================================
---changeset test-customer-rbac-ROLES-CREATION:1 endDelimiter:--//
+--changeset test-customer-rbac-insert-trigger:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
- Creates the roles and their assignments for a new customer for the AFTER INSERT TRIGGER.
+ Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
*/
-create or replace function createRbacRolesForTestCustomer()
- returns trigger
- language plpgsql
- strict as $$
-declare
- testCustomerOwnerUuid uuid;
- customerAdminUuid uuid;
-begin
- if TG_OP <> 'INSERT' then
- raise exception 'invalid usage of TRIGGER AFTER INSERT';
- end if;
+create or replace procedure buildRbacSystemForTestCustomer(
+ NEW test_customer
+)
+ language plpgsql as $$
+declare
+
+begin
call enterTriggerForObjectUuid(NEW.uuid);
- -- the owner role with full access for Hostsharing administrators
- testCustomerOwnerUuid = createRoleWithGrants(
+ perform createRoleWithGrants(
testCustomerOwner(NEW),
- permissions => array['*'],
- incomingSuperRoles => array[globalAdmin()]
- );
+ permissions => array['DELETE'],
+ userUuids => array[currentUserUuid()],
+ incomingSuperRoles => array[globalAdmin(unassumed())]
+ );
- -- the admin role for the customer's admins, who can view and add products
- customerAdminUuid = createRoleWithGrants(
+ perform createRoleWithGrants(
testCustomerAdmin(NEW),
- permissions => array['view', 'add-package'],
- -- NO auto assume for customer owner to avoid exploding permissions for administrators
- userUuids => array[getRbacUserId(NEW.adminUserName, 'create')], -- implicitly ignored if null
- grantedByRole => globalAdmin()
- );
+ permissions => array['UPDATE'],
+ incomingSuperRoles => array[testCustomerOwner(NEW)]
+ );
- -- allow the customer owner role (thus administrators) to assume the customer admin role
- call grantRoleToRole(customerAdminUuid, testCustomerOwnerUuid, false);
-
- -- the tenant role which later can be used by owners+admins of sub-objects
perform createRoleWithGrants(
testCustomerTenant(NEW),
- permissions => array['view']
- );
+ permissions => array['SELECT'],
+ incomingSuperRoles => array[testCustomerAdmin(NEW)]
+ );
call leaveTriggerForObjectUuid(NEW.uuid);
- return NEW;
end; $$;
/*
- An AFTER INSERT TRIGGER which creates the role structure for a new customer.
+ AFTER INSERT TRIGGER to create the role+grant structure for a new test_customer row.
*/
-drop trigger if exists createRbacRolesForTestCustomer_Trigger on test_customer;
-create trigger createRbacRolesForTestCustomer_Trigger
- after insert
- on test_customer
+create or replace function insertTriggerForTestCustomer_tf()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ call buildRbacSystemForTestCustomer(NEW);
+ return NEW;
+end; $$;
+
+create trigger insertTriggerForTestCustomer_tg
+ after insert on test_customer
for each row
-execute procedure createRbacRolesForTestCustomer();
+execute procedure insertTriggerForTestCustomer_tf();
+
--//
+-- ============================================================================
+--changeset test-customer-rbac-INSERT:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+/**
+ Checks if the user or assumed roles are allowed to insert a row to test_customer.
+*/
+create or replace function test_customer_insert_permission_missing_tf()
+ returns trigger
+ language plpgsql as $$
+begin
+ raise exception '[403] insert into test_customer not allowed for current subjects % (%)',
+ currentSubjects(), currentSubjectsUuids();
+end; $$;
+
+create trigger test_customer_insert_permission_check_tg
+ before insert on test_customer
+ for each row
+ -- As there is no explicit INSERT grant specified for this table,
+ -- only global admins are allowed to insert any rows.
+ when ( not isGlobalAdmin() )
+ execute procedure test_customer_insert_permission_missing_tf();
+
+--//
-- ============================================================================
--changeset test-customer-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('test_customer', $idName$
- target.prefix
+
+call generateRbacIdentityViewFromProjection('test_customer', $idName$
+ prefix
$idName$);
+
--//
-
-
-- ============================================================================
--changeset test-customer-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacRestrictedView('test_customer', 'target.prefix',
+call generateRbacRestrictedView('test_customer',
+ 'reference',
$updates$
reference = new.reference,
prefix = new.prefix,
@@ -99,47 +121,3 @@ call generateRbacRestrictedView('test_customer', 'target.prefix',
--//
--- ============================================================================
---changeset test-customer-rbac-ADD-CUSTOMER:1 endDelimiter:--//
--- ----------------------------------------------------------------------------
-/*
- Creates a global permission for add-customer and assigns it to the hostsharing admins role.
- */
-do language plpgsql $$
- declare
- addCustomerPermissions uuid[];
- globalObjectUuid uuid;
- globalAdminRoleUuid uuid ;
- begin
- call defineContext('granting global add-customer permission to global admin role', null, null, null);
-
- globalAdminRoleUuid := findRoleId(globalAdmin());
- globalObjectUuid := (select uuid from global);
- addCustomerPermissions := createPermissions(globalObjectUuid, array ['add-customer']);
- call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
- end;
-$$;
-
-/**
- Used by the trigger to prevent the add-customer to current user respectively assumed roles.
- */
-create or replace function addTestCustomerNotAllowedForCurrentSubjects()
- returns trigger
- language PLPGSQL
-as $$
-begin
- raise exception '[403] add-customer not permitted for %',
- array_to_string(currentSubjects(), ';', 'null');
-end; $$;
-
-/**
- Checks if the user or assumed roles are allowed to add a new customer.
- */
-create trigger test_customer_insert_trigger
- before insert
- on test_customer
- for each row
- when ( not hasGlobalPermission('add-customer') )
-execute procedure addTestCustomerNotAllowedForCurrentSubjects();
---//
-
diff --git a/src/main/resources/db/changelog/118-test-customer-test-data.sql b/src/main/resources/db/changelog/118-test-customer-test-data.sql
index 353b8f59..85c34ac6 100644
--- a/src/main/resources/db/changelog/118-test-customer-test-data.sql
+++ b/src/main/resources/db/changelog/118-test-customer-test-data.sql
@@ -28,6 +28,8 @@ declare
currentTask varchar;
custRowId uuid;
custAdminName varchar;
+ custAdminUuid uuid;
+ newCust test_customer;
begin
currentTask = 'creating RBAC test customer #' || custReference || '/' || custPrefix;
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
@@ -35,10 +37,19 @@ begin
custRowId = uuid_generate_v4();
custAdminName = 'customer-admin@' || custPrefix || '.example.com';
+ custAdminUuid = createRbacUser(custAdminName);
insert
into test_customer (reference, prefix, adminUserName)
values (custReference, custPrefix, custAdminName);
+
+ select * into newCust
+ from test_customer where reference=custReference;
+ call grantRoleToUser(
+ getRoleId(testCustomerOwner(newCust)),
+ getRoleId(testCustomerAdmin(newCust)),
+ custAdminUuid,
+ true);
end; $$;
--//
diff --git a/src/main/resources/db/changelog/123-test-package-rbac.md b/src/main/resources/db/changelog/123-test-package-rbac.md
new file mode 100644
index 00000000..78da4439
--- /dev/null
+++ b/src/main/resources/db/changelog/123-test-package-rbac.md
@@ -0,0 +1,59 @@
+### rbac package
+
+This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-11T11:29:11.624847792.
+
+```mermaid
+%%{init:{'flowchart':{'htmlLabels':false}}}%%
+flowchart TB
+
+subgraph package["`**package**`"]
+ direction TB
+ style package fill:#dd4901,stroke:#274d6e,stroke-width:8px
+
+ subgraph package:roles[ ]
+ style package:roles fill:#dd4901,stroke:white
+
+ role:package:owner[[package:owner]]
+ role:package:admin[[package:admin]]
+ role:package:tenant[[package:tenant]]
+ end
+
+ subgraph package:permissions[ ]
+ style package:permissions fill:#dd4901,stroke:white
+
+ perm:package:INSERT{{package:INSERT}}
+ perm:package:DELETE{{package:DELETE}}
+ perm:package:UPDATE{{package:UPDATE}}
+ perm:package:SELECT{{package:SELECT}}
+ end
+end
+
+subgraph customer["`**customer**`"]
+ direction TB
+ style customer fill:#99bcdb,stroke:#274d6e,stroke-width:8px
+
+ subgraph customer:roles[ ]
+ style customer:roles fill:#99bcdb,stroke:white
+
+ role:customer:owner[[customer:owner]]
+ role:customer:admin[[customer:admin]]
+ role:customer:tenant[[customer:tenant]]
+ end
+end
+
+%% granting roles to roles
+role:global:admin -.->|XX| role:customer:owner
+role:customer:owner -.-> role:customer:admin
+role:customer:admin -.-> role:customer:tenant
+role:customer:admin ==> role:package:owner
+role:package:owner ==> role:package:admin
+role:package:admin ==> role:package:tenant
+role:package:tenant ==> role:customer:tenant
+
+%% granting permissions to roles
+role:customer:admin ==> perm:package:INSERT
+role:package:owner ==> perm:package:DELETE
+role:package:owner ==> perm:package:UPDATE
+role:package:tenant ==> perm:package:SELECT
+
+```
diff --git a/src/main/resources/db/changelog/123-test-package-rbac.sql b/src/main/resources/db/changelog/123-test-package-rbac.sql
index 9e68468c..20562642 100644
--- a/src/main/resources/db/changelog/123-test-package-rbac.sql
+++ b/src/main/resources/db/changelog/123-test-package-rbac.sql
@@ -1,4 +1,5 @@
--liquibase formatted sql
+-- This code generated was by RbacViewPostgresGenerator at 2024-03-11T11:29:11.625353859.
-- ============================================================================
--changeset test-package-rbac-OBJECT:1 endDelimiter:--//
@@ -15,95 +16,211 @@ call generateRbacRoleDescriptors('testPackage', 'test_package');
-- ============================================================================
---changeset test-package-rbac-ROLES-CREATION:1 endDelimiter:--//
+--changeset test-package-rbac-insert-trigger:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
+
/*
- Creates the roles and their assignments for a new package for the AFTER INSERT TRIGGER.
+ Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
*/
-create or replace function createRbacRolesForTestPackage()
- returns trigger
- language plpgsql
- strict as $$
+
+create or replace procedure buildRbacSystemForTestPackage(
+ NEW test_package
+)
+ language plpgsql as $$
+
declare
- parentCustomer test_customer;
+ newCustomer test_customer;
+
begin
- if TG_OP <> 'INSERT' then
- raise exception 'invalid usage of TRIGGER AFTER INSERT';
- end if;
-
call enterTriggerForObjectUuid(NEW.uuid);
+ SELECT * FROM test_customer c
+ WHERE c.uuid= NEW.customerUuid
+ into newCustomer;
- select * from test_customer as c where c.uuid = NEW.customerUuid into parentCustomer;
-
- -- an owner role is created and assigned to the customer's admin role
perform createRoleWithGrants(
- testPackageOwner(NEW),
- permissions => array ['*'],
- incomingSuperRoles => array[testCustomerAdmin(parentCustomer)]
- );
+ testPackageOwner(NEW),
+ permissions => array['DELETE', 'UPDATE'],
+ incomingSuperRoles => array[testCustomerAdmin(newCustomer)]
+ );
- -- an owner role is created and assigned to the package owner role
perform createRoleWithGrants(
- testPackageAdmin(NEW),
- permissions => array ['add-domain'],
+ testPackageAdmin(NEW),
incomingSuperRoles => array[testPackageOwner(NEW)]
- );
+ );
- -- and a package tenant role is created and assigned to the package admin as well
perform createRoleWithGrants(
- testPackageTenant(NEW),
- permissions => array['view'],
- incomingsuperroles => array[testPackageAdmin(NEW)],
- outgoingSubRoles => array[testCustomerTenant(parentCustomer)]
- );
+ testPackageTenant(NEW),
+ permissions => array['SELECT'],
+ incomingSuperRoles => array[testPackageAdmin(NEW)],
+ outgoingSubRoles => array[testCustomerTenant(newCustomer)]
+ );
call leaveTriggerForObjectUuid(NEW.uuid);
- return NEW;
end; $$;
/*
- An AFTER INSERT TRIGGER which creates the role structure for a new package.
+ AFTER INSERT TRIGGER to create the role+grant structure for a new test_package row.
*/
-create trigger createRbacRolesForTestPackage_Trigger
- after insert
- on test_package
+create or replace function insertTriggerForTestPackage_tf()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ call buildRbacSystemForTestPackage(NEW);
+ return NEW;
+end; $$;
+
+create trigger insertTriggerForTestPackage_tg
+ after insert on test_package
for each row
-execute procedure createRbacRolesForTestPackage();
+execute procedure insertTriggerForTestPackage_tf();
+
--//
-
-- ============================================================================
---changeset test-package-rbac-IDENTITY-VIEW:1 endDelimiter:--//
--- ----------------------------------------------------------------------------
-call generateRbacIdentityView('test_package', 'target.name');
---//
-
-
--- ============================================================================
---changeset test-package-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
+--changeset test-package-rbac-update-trigger:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
- Creates a view to the customer main table which maps the identifying name
- (in this case, the prefix) to the objectUuid.
+ Called from the AFTER UPDATE TRIGGER to re-wire the grants.
*/
--- drop view if exists test_package_rv;
--- create or replace view test_package_rv as
--- select target.*
--- from test_package as target
--- where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'test_package', currentSubjectsUuids()))
--- order by target.name;
--- grant all privileges on test_package_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
-call generateRbacRestrictedView('test_package', 'target.name',
- $updates$
- version = new.version,
- customerUuid = new.customerUuid,
- name = new.name,
- description = new.description
- $updates$);
+create or replace procedure updateRbacRulesForTestPackage(
+ OLD test_package,
+ NEW test_package
+)
+ language plpgsql as $$
+
+declare
+ oldCustomer test_customer;
+ newCustomer test_customer;
+
+begin
+ call enterTriggerForObjectUuid(NEW.uuid);
+
+ SELECT * FROM test_customer c
+ WHERE c.uuid= OLD.customerUuid
+ into oldCustomer;
+ SELECT * FROM test_customer c
+ WHERE c.uuid= NEW.customerUuid
+ into newCustomer;
+
+ if NEW.customerUuid <> OLD.customerUuid then
+
+ call revokePermissionFromRole(findPermissionId(OLD.uuid, 'INSERT'), testCustomerAdmin(oldCustomer));
+
+ call revokeRoleFromRole(testPackageOwner(OLD), testCustomerAdmin(oldCustomer));
+ call grantRoleToRole(testPackageOwner(NEW), testCustomerAdmin(newCustomer));
+
+ call revokeRoleFromRole(testCustomerTenant(oldCustomer), testPackageTenant(OLD));
+ call grantRoleToRole(testCustomerTenant(newCustomer), testPackageTenant(NEW));
+
+ end if;
+
+ call leaveTriggerForObjectUuid(NEW.uuid);
+end; $$;
+
+/*
+ AFTER INSERT TRIGGER to re-wire the grant structure for a new test_package row.
+ */
+
+create or replace function updateTriggerForTestPackage_tf()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ call updateRbacRulesForTestPackage(OLD, NEW);
+ return NEW;
+end; $$;
+
+create trigger updateTriggerForTestPackage_tg
+ after update on test_package
+ for each row
+execute procedure updateTriggerForTestPackage_tf();
--//
+-- ============================================================================
+--changeset test-package-rbac-INSERT:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+/*
+ Creates INSERT INTO test_package permissions for the related test_customer rows.
+ */
+do language plpgsql $$
+ declare
+ row test_customer;
+ permissionUuid uuid;
+ roleUuid uuid;
+ begin
+ call defineContext('create INSERT INTO test_package permissions for the related test_customer rows');
+
+ FOR row IN SELECT * FROM test_customer
+ LOOP
+ roleUuid := findRoleId(testCustomerAdmin(row));
+ permissionUuid := createPermission(row.uuid, 'INSERT', 'test_package');
+ call grantPermissionToRole(roleUuid, permissionUuid);
+ END LOOP;
+ END;
+$$;
+
+/**
+ Adds test_package INSERT permission to specified role of new test_customer rows.
+*/
+create or replace function test_package_test_customer_insert_tf()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ call grantPermissionToRole(
+ testCustomerAdmin(NEW),
+ createPermission(NEW.uuid, 'INSERT', 'test_package'));
+ return NEW;
+end; $$;
+
+create trigger test_package_test_customer_insert_tg
+ after insert on test_customer
+ for each row
+execute procedure test_package_test_customer_insert_tf();
+
+/**
+ Checks if the user or assumed roles are allowed to insert a row to test_package.
+*/
+create or replace function test_package_insert_permission_missing_tf()
+ returns trigger
+ language plpgsql as $$
+begin
+ raise exception '[403] insert into test_package not allowed for current subjects % (%)',
+ currentSubjects(), currentSubjectsUuids();
+end; $$;
+
+create trigger test_package_insert_permission_check_tg
+ before insert on test_package
+ for each row
+ when ( not hasInsertPermission(NEW.customerUuid, 'INSERT', 'test_package') )
+ execute procedure test_package_insert_permission_missing_tf();
+
+--//
+-- ============================================================================
+--changeset test-package-rbac-IDENTITY-VIEW:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+call generateRbacIdentityViewFromProjection('test_package', $idName$
+ name
+ $idName$);
+
+--//
+-- ============================================================================
+--changeset test-package-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+call generateRbacRestrictedView('test_package',
+ 'name',
+ $updates$
+ version = new.version,
+ customerUuid = new.customerUuid,
+ description = new.description
+ $updates$);
+--//
+
diff --git a/src/main/resources/db/changelog/128-test-package-test-data.sql b/src/main/resources/db/changelog/128-test-package-test-data.sql
index 4667b742..9abba772 100644
--- a/src/main/resources/db/changelog/128-test-package-test-data.sql
+++ b/src/main/resources/db/changelog/128-test-package-test-data.sql
@@ -26,7 +26,7 @@ begin
custAdminUser = 'customer-admin@' || cust.prefix || '.example.com';
custAdminRole = 'test_customer#' || cust.prefix || '.admin';
- call defineContext(currentTask, null, custAdminUser, custAdminRole);
+ call defineContext(currentTask, null, 'superuser-fran@hostsharing.net', custAdminRole);
raise notice 'task: % by % as %', currentTask, custAdminUser, custAdminRole;
insert
@@ -35,7 +35,7 @@ begin
returning * into pac;
call grantRoleToUser(
- getRoleId(testCustomerAdmin(cust), 'fail'),
+ getRoleId(testCustomerAdmin(cust)),
findRoleId(testPackageAdmin(pac)),
createRbacUser('pac-admin-' || pacName || '@' || cust.prefix || '.example.com'),
true);
diff --git a/src/main/resources/db/changelog/133-test-domain-rbac.md b/src/main/resources/db/changelog/133-test-domain-rbac.md
new file mode 100644
index 00000000..bd5cf706
--- /dev/null
+++ b/src/main/resources/db/changelog/133-test-domain-rbac.md
@@ -0,0 +1,88 @@
+### rbac domain
+
+This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-11T11:29:11.644658132.
+
+```mermaid
+%%{init:{'flowchart':{'htmlLabels':false}}}%%
+flowchart TB
+
+subgraph package.customer["`**package.customer**`"]
+ direction TB
+ style package.customer fill:#99bcdb,stroke:#274d6e,stroke-width:8px
+
+ subgraph package.customer:roles[ ]
+ style package.customer:roles fill:#99bcdb,stroke:white
+
+ role:package.customer:owner[[package.customer:owner]]
+ role:package.customer:admin[[package.customer:admin]]
+ role:package.customer:tenant[[package.customer:tenant]]
+ end
+end
+
+subgraph package["`**package**`"]
+ direction TB
+ style package fill:#99bcdb,stroke:#274d6e,stroke-width:8px
+
+ subgraph package.customer["`**package.customer**`"]
+ direction TB
+ style package.customer fill:#99bcdb,stroke:#274d6e,stroke-width:8px
+
+ subgraph package.customer:roles[ ]
+ style package.customer:roles fill:#99bcdb,stroke:white
+
+ role:package.customer:owner[[package.customer:owner]]
+ role:package.customer:admin[[package.customer:admin]]
+ role:package.customer:tenant[[package.customer:tenant]]
+ end
+ end
+
+ subgraph package:roles[ ]
+ style package:roles fill:#99bcdb,stroke:white
+
+ role:package:owner[[package:owner]]
+ role:package:admin[[package:admin]]
+ role:package:tenant[[package:tenant]]
+ end
+end
+
+subgraph domain["`**domain**`"]
+ direction TB
+ style domain fill:#dd4901,stroke:#274d6e,stroke-width:8px
+
+ subgraph domain:roles[ ]
+ style domain:roles fill:#dd4901,stroke:white
+
+ role:domain:owner[[domain:owner]]
+ role:domain:admin[[domain:admin]]
+ end
+
+ subgraph domain:permissions[ ]
+ style domain:permissions fill:#dd4901,stroke:white
+
+ perm:domain:INSERT{{domain:INSERT}}
+ perm:domain:DELETE{{domain:DELETE}}
+ perm:domain:UPDATE{{domain:UPDATE}}
+ perm:domain:SELECT{{domain:SELECT}}
+ end
+end
+
+%% granting roles to roles
+role:global:admin -.->|XX| role:package.customer:owner
+role:package.customer:owner -.-> role:package.customer:admin
+role:package.customer:admin -.-> role:package.customer:tenant
+role:package.customer:admin -.-> role:package:owner
+role:package:owner -.-> role:package:admin
+role:package:admin -.-> role:package:tenant
+role:package:tenant -.-> role:package.customer:tenant
+role:package:admin ==> role:domain:owner
+role:domain:owner ==> role:package:tenant
+role:domain:owner ==> role:domain:admin
+role:domain:admin ==> role:package:tenant
+
+%% granting permissions to roles
+role:package:admin ==> perm:domain:INSERT
+role:domain:owner ==> perm:domain:DELETE
+role:domain:owner ==> perm:domain:UPDATE
+role:domain:admin ==> perm:domain:SELECT
+
+```
diff --git a/src/main/resources/db/changelog/133-test-domain-rbac.sql b/src/main/resources/db/changelog/133-test-domain-rbac.sql
index a78bfb5f..e686dada 100644
--- a/src/main/resources/db/changelog/133-test-domain-rbac.sql
+++ b/src/main/resources/db/changelog/133-test-domain-rbac.sql
@@ -1,4 +1,5 @@
--liquibase formatted sql
+-- This code generated was by RbacViewPostgresGenerator at 2024-03-11T11:29:11.645391647.
-- ============================================================================
--changeset test-domain-rbac-OBJECT:1 endDelimiter:--//
@@ -11,107 +12,214 @@ call generateRelatedRbacObject('test_domain');
--changeset test-domain-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRoleDescriptors('testDomain', 'test_domain');
-
-create or replace function createTestDomainTenantRoleIfNotExists(domain test_domain)
- returns uuid
- returns null on null input
- language plpgsql as $$
-declare
- domainTenantRoleDesc RbacRoleDescriptor;
- domainTenantRoleUuid uuid;
-begin
- domainTenantRoleDesc = testdomainTenant(domain);
- domainTenantRoleUuid = findRoleId(domainTenantRoleDesc);
- if domainTenantRoleUuid is not null then
- return domainTenantRoleUuid;
- end if;
-
- return createRoleWithGrants(
- domainTenantRoleDesc,
- permissions => array['view'],
- incomingSuperRoles => array[testdomainAdmin(domain)]
- );
-end; $$;
--//
-- ============================================================================
---changeset test-domain-rbac-ROLES-CREATION:1 endDelimiter:--//
+--changeset test-domain-rbac-insert-trigger:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
+
/*
- Creates the roles and their assignments for a new domain for the AFTER INSERT TRIGGER.
+ Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
*/
-create or replace function createRbacRulesForTestDomain()
+create or replace procedure buildRbacSystemForTestDomain(
+ NEW test_domain
+)
+ language plpgsql as $$
+
+declare
+ newPackage test_package;
+
+begin
+ call enterTriggerForObjectUuid(NEW.uuid);
+ SELECT * FROM test_package p
+ WHERE p.uuid= NEW.packageUuid
+ into newPackage;
+
+ perform createRoleWithGrants(
+ testDomainOwner(NEW),
+ permissions => array['DELETE', 'UPDATE'],
+ incomingSuperRoles => array[testPackageAdmin(newPackage)],
+ outgoingSubRoles => array[testPackageTenant(newPackage)]
+ );
+
+ perform createRoleWithGrants(
+ testDomainAdmin(NEW),
+ permissions => array['SELECT'],
+ incomingSuperRoles => array[testDomainOwner(NEW)],
+ outgoingSubRoles => array[testPackageTenant(newPackage)]
+ );
+
+ call leaveTriggerForObjectUuid(NEW.uuid);
+end; $$;
+
+/*
+ AFTER INSERT TRIGGER to create the role+grant structure for a new test_domain row.
+ */
+
+create or replace function insertTriggerForTestDomain_tf()
returns trigger
language plpgsql
strict as $$
-declare
- parentPackage test_package;
begin
- if TG_OP <> 'INSERT' then
- raise exception 'invalid usage of TRIGGER AFTER INSERT';
- end if;
-
- call enterTriggerForObjectUuid(NEW.uuid);
-
- select * from test_package where uuid = NEW.packageUuid into parentPackage;
-
- -- an owner role is created and assigned to the package's admin group
- perform createRoleWithGrants(
- testDomainOwner(NEW),
- permissions => array['*'],
- incomingSuperRoles => array[testPackageAdmin(parentPackage)]
- );
-
- -- and a domain admin role is created and assigned to the domain owner as well
- perform createRoleWithGrants(
- testDomainAdmin(NEW),
- permissions => array['edit'],
- incomingSuperRoles => array[testDomainOwner(NEW)],
- outgoingSubRoles => array[testPackageTenant(parentPackage)]
- );
-
- -- a tenent role is only created on demand
-
- call leaveTriggerForObjectUuid(NEW.uuid);
+ call buildRbacSystemForTestDomain(NEW);
return NEW;
end; $$;
-
-/*
- An AFTER INSERT TRIGGER which creates the role structure for a new domain.
- */
-drop trigger if exists createRbacRulesForTestDomain_Trigger on test_domain;
-create trigger createRbacRulesForTestDomain_Trigger
- after insert
- on test_domain
+create trigger insertTriggerForTestDomain_tg
+ after insert on test_domain
for each row
-execute procedure createRbacRulesForTestDomain();
+execute procedure insertTriggerForTestDomain_tf();
+
--//
+-- ============================================================================
+--changeset test-domain-rbac-update-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+/*
+ Called from the AFTER UPDATE TRIGGER to re-wire the grants.
+ */
+
+create or replace procedure updateRbacRulesForTestDomain(
+ OLD test_domain,
+ NEW test_domain
+)
+ language plpgsql as $$
+
+declare
+ oldPackage test_package;
+ newPackage test_package;
+
+begin
+ call enterTriggerForObjectUuid(NEW.uuid);
+
+ SELECT * FROM test_package p
+ WHERE p.uuid= OLD.packageUuid
+ into oldPackage;
+ SELECT * FROM test_package p
+ WHERE p.uuid= NEW.packageUuid
+ into newPackage;
+
+ if NEW.packageUuid <> OLD.packageUuid then
+
+ call revokePermissionFromRole(findPermissionId(OLD.uuid, 'INSERT'), testPackageAdmin(oldPackage));
+
+ call revokeRoleFromRole(testDomainOwner(OLD), testPackageAdmin(oldPackage));
+ call grantRoleToRole(testDomainOwner(NEW), testPackageAdmin(newPackage));
+
+ call revokeRoleFromRole(testPackageTenant(oldPackage), testDomainOwner(OLD));
+ call grantRoleToRole(testPackageTenant(newPackage), testDomainOwner(NEW));
+
+ call revokeRoleFromRole(testPackageTenant(oldPackage), testDomainAdmin(OLD));
+ call grantRoleToRole(testPackageTenant(newPackage), testDomainAdmin(NEW));
+
+ end if;
+
+ call leaveTriggerForObjectUuid(NEW.uuid);
+end; $$;
+
+/*
+ AFTER INSERT TRIGGER to re-wire the grant structure for a new test_domain row.
+ */
+
+create or replace function updateTriggerForTestDomain_tf()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ call updateRbacRulesForTestDomain(OLD, NEW);
+ return NEW;
+end; $$;
+
+create trigger updateTriggerForTestDomain_tg
+ after update on test_domain
+ for each row
+execute procedure updateTriggerForTestDomain_tf();
+
+--//
+
+-- ============================================================================
+--changeset test-domain-rbac-INSERT:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+/*
+ Creates INSERT INTO test_domain permissions for the related test_package rows.
+ */
+do language plpgsql $$
+ declare
+ row test_package;
+ permissionUuid uuid;
+ roleUuid uuid;
+ begin
+ call defineContext('create INSERT INTO test_domain permissions for the related test_package rows');
+
+ FOR row IN SELECT * FROM test_package
+ LOOP
+ roleUuid := findRoleId(testPackageAdmin(row));
+ permissionUuid := createPermission(row.uuid, 'INSERT', 'test_domain');
+ call grantPermissionToRole(roleUuid, permissionUuid);
+ END LOOP;
+ END;
+$$;
+
+/**
+ Adds test_domain INSERT permission to specified role of new test_package rows.
+*/
+create or replace function test_domain_test_package_insert_tf()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ call grantPermissionToRole(
+ testPackageAdmin(NEW),
+ createPermission(NEW.uuid, 'INSERT', 'test_domain'));
+ return NEW;
+end; $$;
+
+create trigger test_domain_test_package_insert_tg
+ after insert on test_package
+ for each row
+execute procedure test_domain_test_package_insert_tf();
+
+/**
+ Checks if the user or assumed roles are allowed to insert a row to test_domain.
+*/
+create or replace function test_domain_insert_permission_missing_tf()
+ returns trigger
+ language plpgsql as $$
+begin
+ raise exception '[403] insert into test_domain not allowed for current subjects % (%)',
+ currentSubjects(), currentSubjectsUuids();
+end; $$;
+
+create trigger test_domain_insert_permission_check_tg
+ before insert on test_domain
+ for each row
+ when ( not hasInsertPermission(NEW.packageUuid, 'INSERT', 'test_domain') )
+ execute procedure test_domain_insert_permission_missing_tf();
+
+--//
-- ============================================================================
--changeset test-domain-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('test_domain', $idName$
- target.name
+
+call generateRbacIdentityViewFromProjection('test_domain', $idName$
+ name
$idName$);
+
--//
-
-
-- ============================================================================
--changeset test-domain-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-
-/*
- Creates a view to the customer main table which maps the identifying name
- (in this case, the prefix) to the objectUuid.
- */
-drop view if exists test_domain_rv;
-create or replace view test_domain_rv as
-select target.*
- from test_domain as target
- where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'domain', currentSubjectsUuids()));
-grant all privileges on test_domain_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
+call generateRbacRestrictedView('test_domain',
+ 'name',
+ $updates$
+ version = new.version,
+ packageUuid = new.packageUuid,
+ description = new.description
+ $updates$);
--//
+
+
diff --git a/src/main/resources/db/changelog/203-hs-office-contact-rbac.sql b/src/main/resources/db/changelog/203-hs-office-contact-rbac.sql
index 7ba7891b..3a9b0c34 100644
--- a/src/main/resources/db/changelog/203-hs-office-contact-rbac.sql
+++ b/src/main/resources/db/changelog/203-hs-office-contact-rbac.sql
@@ -33,7 +33,7 @@ begin
perform createRoleWithGrants(
hsOfficeContactOwner(NEW),
- permissions => array['*'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()],
userUuids => array[currentUserUuid()],
grantedByRole => globalAdmin()
@@ -41,7 +41,7 @@ begin
perform createRoleWithGrants(
hsOfficeContactAdmin(NEW),
- permissions => array['edit'],
+ permissions => array['UPDATE'],
incomingSuperRoles => array[hsOfficeContactOwner(NEW)]
);
@@ -52,7 +52,7 @@ begin
perform createRoleWithGrants(
hsOfficeContactGuest(NEW),
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[hsOfficeContactTenant(NEW)]
);
@@ -75,7 +75,7 @@ execute procedure createRbacRolesForHsOfficeContact();
--changeset hs-office-contact-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_contact', $idName$
+call generateRbacIdentityViewFromProjection('hs_office_contact', $idName$
target.label
$idName$);
--//
diff --git a/src/main/resources/db/changelog/213-hs-office-person-rbac.sql b/src/main/resources/db/changelog/213-hs-office-person-rbac.sql
index 42eacf2f..fbb1f8e1 100644
--- a/src/main/resources/db/changelog/213-hs-office-person-rbac.sql
+++ b/src/main/resources/db/changelog/213-hs-office-person-rbac.sql
@@ -31,16 +31,16 @@ begin
perform createRoleWithGrants(
hsOfficePersonOwner(NEW),
- permissions => array['*'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()],
userUuids => array[currentUserUuid()],
grantedByRole => globalAdmin()
);
- -- TODO: who is admin? the person itself? is it allowed for the person itself or a representative to edit the data?
+ -- TODO: who is admin? the person itself? is it allowed for the person itself or a representative to update the data?
perform createRoleWithGrants(
hsOfficePersonAdmin(NEW),
- permissions => array['edit'],
+ permissions => array['UPDATE'],
incomingSuperRoles => array[hsOfficePersonOwner(NEW)]
);
@@ -51,7 +51,7 @@ begin
perform createRoleWithGrants(
hsOfficePersonGuest(NEW),
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[hsOfficePersonTenant(NEW)]
);
@@ -73,7 +73,7 @@ execute procedure createRbacRolesForHsOfficePerson();
-- ============================================================================
--changeset hs-office-person-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_person', $idName$
+call generateRbacIdentityViewFromProjection('hs_office_person', $idName$
concat(target.tradeName, target.familyName, target.givenName)
$idName$);
--//
diff --git a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md
index c41de32c..8ffa55ff 100644
--- a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md
+++ b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md
@@ -42,151 +42,3 @@ subgraph hsOfficeRelationship
end
```
- if TG_OP = 'INSERT' then
-
- -- the owner role with full access for admins of the relAnchor global admins
- ownerRole = createRole(
- hsOfficeRelationshipOwner(NEW),
- grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
- beneathRoles(array[
- globalAdmin(),
- hsOfficePersonAdmin(newRelAnchor)])
- );
-
- -- the admin role with full access for the owner
- adminRole = createRole(
- hsOfficeRelationshipAdmin(NEW),
- grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']),
- beneathRole(ownerRole)
- );
-
- -- the tenant role for those related users who can view the data
- perform createRole(
- hsOfficeRelationshipTenant,
- grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']),
- beneathRoles(array[
- hsOfficePersonAdmin(newRelAnchor),
- hsOfficePersonAdmin(newRelHolder),
- hsOfficeContactAdmin(newContact)]),
- withSubRoles(array[
- hsOfficePersonTenant(newRelAnchor),
- hsOfficePersonTenant(newRelHolder),
- hsOfficeContactTenant(newContact)])
- );
-
- -- anchor and holder admin roles need each others tenant role
- -- to be able to see the joined relationship
- call grantRoleToRole(hsOfficePersonTenant(newRelAnchor), hsOfficePersonAdmin(newRelHolder));
- call grantRoleToRole(hsOfficePersonTenant(newRelHolder), hsOfficePersonAdmin(newRelAnchor));
- call grantRoleToRoleIfNotNull(hsOfficePersonTenant(newRelHolder), hsOfficeContactAdmin(newContact));
-
- elsif TG_OP = 'UPDATE' then
-
- if OLD.contactUuid <> NEW.contactUuid then
- -- nothing but the contact can be updated,
- -- in other cases, a new relationship needs to be created and the old updated
-
- select * from hs_office_contact as c where c.uuid = OLD.contactUuid into oldContact;
-
- call revokeRoleFromRole( hsOfficeRelationshipTenant, hsOfficeContactAdmin(oldContact) );
- call grantRoleToRole( hsOfficeRelationshipTenant, hsOfficeContactAdmin(newContact) );
-
- call revokeRoleFromRole( hsOfficeContactTenant(oldContact), hsOfficeRelationshipTenant );
- call grantRoleToRole( hsOfficeContactTenant(newContact), hsOfficeRelationshipTenant );
- end if;
- else
- raise exception 'invalid usage of TRIGGER';
- end if;
-
- return NEW;
-end; $$;
-
-/*
- An AFTER INSERT TRIGGER which creates the role structure for a new customer.
- */
-create trigger createRbacRolesForHsOfficeRelationship_Trigger
- after insert
- on hs_office_relationship
- for each row
-execute procedure hsOfficeRelationshipRbacRolesTrigger();
-
-/*
- An AFTER UPDATE TRIGGER which updates the role structure of a customer.
- */
-create trigger updateRbacRolesForHsOfficeRelationship_Trigger
- after update
- on hs_office_relationship
- for each row
-execute procedure hsOfficeRelationshipRbacRolesTrigger();
---//
-
-
--- ============================================================================
---changeset hs-office-relationship-rbac-IDENTITY-VIEW:1 endDelimiter:--//
--- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_relationship', $idName$
- (select idName from hs_office_person_iv p where p.uuid = target.relAnchorUuid)
- || '-with-' || target.relType || '-' ||
- (select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)
- $idName$);
---//
-
-
--- ============================================================================
---changeset hs-office-relationship-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
--- ----------------------------------------------------------------------------
-call generateRbacRestrictedView('hs_office_relationship',
- '(select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)',
- $updates$
- contactUuid = new.contactUuid
- $updates$);
---//
-
--- TODO: exception if one tries to amend any other column
-
-
--- ============================================================================
---changeset hs-office-relationship-rbac-NEW-RELATHIONSHIP:1 endDelimiter:--//
--- ----------------------------------------------------------------------------
-/*
- Creates a global permission for new-relationship and assigns it to the hostsharing admins role.
- */
-do language plpgsql $$
- declare
- addCustomerPermissions uuid[];
- globalObjectUuid uuid;
- globalAdminRoleUuid uuid ;
- begin
- call defineContext('granting global new-relationship permission to global admin role', null, null, null);
-
- globalAdminRoleUuid := findRoleId(globalAdmin());
- globalObjectUuid := (select uuid from global);
- addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-relationship']);
- call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
- end;
-$$;
-
-/**
- Used by the trigger to prevent the add-customer to current user respectively assumed roles.
- */
-create or replace function addHsOfficeRelationshipNotAllowedForCurrentSubjects()
- returns trigger
- language PLPGSQL
-as $$
-begin
- raise exception '[403] new-relationship not permitted for %',
- array_to_string(currentSubjects(), ';', 'null');
-end; $$;
-
-/**
- Checks if the user or assumed roles are allowed to create a new customer.
- */
-create trigger hs_office_relationship_insert_trigger
- before insert
- on hs_office_relationship
- for each row
- -- TODO.spec: who is allowed to create new relationships
- when ( not hasAssumedRole() )
-execute procedure addHsOfficeRelationshipNotAllowedForCurrentSubjects();
---//
-
diff --git a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql
index 928af48c..126664a4 100644
--- a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql
+++ b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql
@@ -45,7 +45,7 @@ begin
perform createRoleWithGrants(
hsOfficeRelationshipOwner(NEW),
- permissions => array['*'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[
globalAdmin(),
hsOfficePersonAdmin(newRelAnchor)]
@@ -53,14 +53,14 @@ begin
perform createRoleWithGrants(
hsOfficeRelationshipAdmin(NEW),
- permissions => array['edit'],
+ permissions => array['UPDATE'],
incomingSuperRoles => array[hsOfficeRelationshipOwner(NEW)]
);
-- the tenant role for those related users who can view the data
perform createRoleWithGrants(
hsOfficeRelationshipTenant,
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[
hsOfficeRelationshipAdmin(NEW),
hsOfficePersonAdmin(newRelAnchor),
@@ -124,7 +124,7 @@ execute procedure hsOfficeRelationshipRbacRolesTrigger();
-- ============================================================================
--changeset hs-office-relationship-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_relationship', $idName$
+call generateRbacIdentityViewFromProjection('hs_office_relationship', $idName$
(select idName from hs_office_person_iv p where p.uuid = target.relAnchorUuid)
|| '-with-' || target.relType || '-' ||
(select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)
diff --git a/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql b/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql
index 4b4da009..d16048fd 100644
--- a/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql
+++ b/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql
@@ -48,13 +48,13 @@ begin
perform createRoleWithGrants(
hsOfficePartnerOwner(NEW),
- permissions => array['*'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()]
);
perform createRoleWithGrants(
hsOfficePartnerAdmin(NEW),
- permissions => array['edit'],
+ permissions => array['UPDATE'],
incomingSuperRoles => array[
hsOfficePartnerOwner(NEW)],
outgoingSubRoles => array[
@@ -84,7 +84,7 @@ begin
perform createRoleWithGrants(
hsOfficePartnerGuest(NEW),
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[hsOfficePartnerTenant(NEW)]
);
@@ -98,21 +98,21 @@ begin
--Attention: Cannot be in partner-details because of insert order (partner is not in database yet)
call grantPermissionsToRole(
- getRoleId(hsOfficePartnerOwner(NEW), 'fail'),
- createPermissions(NEW.detailsUuid, array ['*'])
+ getRoleId(hsOfficePartnerOwner(NEW)),
+ createPermissions(NEW.detailsUuid, array ['DELETE'])
);
call grantPermissionsToRole(
- getRoleId(hsOfficePartnerAdmin(NEW), 'fail'),
- createPermissions(NEW.detailsUuid, array ['edit'])
+ getRoleId(hsOfficePartnerAdmin(NEW)),
+ createPermissions(NEW.detailsUuid, array ['UPDATE'])
);
call grantPermissionsToRole(
-- Yes, here hsOfficePartnerAGENT is used, not hsOfficePartnerTENANT.
-- Do NOT grant view permission on partner-details to hsOfficePartnerTENANT!
-- Otherwise package-admins etc. would be able to read the data.
- getRoleId(hsOfficePartnerAgent(NEW), 'fail'),
- createPermissions(NEW.detailsUuid, array ['view'])
+ getRoleId(hsOfficePartnerAgent(NEW)),
+ createPermissions(NEW.detailsUuid, array ['SELECT'])
);
@@ -187,7 +187,7 @@ execute procedure hsOfficePartnerRbacRolesTrigger();
-- ============================================================================
--changeset hs-office-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_partner', $idName$
+call generateRbacIdentityViewFromProjection('hs_office_partner', $idName$
partnerNumber || ':' ||
(select idName from hs_office_person_iv p where p.uuid = target.personuuid)
|| '-' ||
diff --git a/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql
index ab94481e..c4e053b9 100644
--- a/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql
+++ b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql
@@ -7,13 +7,10 @@ call generateRelatedRbacObject('hs_office_partner_details');
--//
-
-
-
-- ============================================================================
--changeset hs-office-partner-details-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_partner_details', $idName$
+call generateRbacIdentityViewFromProjection('hs_office_partner_details', $idName$
(select idName || '-details' from hs_office_partner_iv partner_iv
join hs_office_partner partner on (partner_iv.uuid = partner.uuid)
where partner.detailsUuid = target.uuid)
@@ -38,7 +35,7 @@ call generateRbacRestrictedView('hs_office_partner_details',
-- ============================================================================
---changeset hs-office-partner-details-rbac-NEW-CONTACT:1 endDelimiter:--//
+--changeset hs-office-partner-details-rbac-NEW-PARTNER-DETAILS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates a global permission for new-partner-details and assigns it to the hostsharing admins role.
diff --git a/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.md b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.md
index fc34f147..b2cee782 100644
--- a/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.md
+++ b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.md
@@ -4,14 +4,14 @@
flowchart TB
subgraph global
- style hsOfficeBankAccount fill: #e9f7ef
+ style global fill: lightgray
role:global.admin[global.admin]
end
subgraph hsOfficeBankAccount
direction TB
- style hsOfficeBankAccount fill: #e9f7ef
+ style hsOfficeBankAccount fill: lightgreen
user:hsOfficeBankAccount.creator([bankAccount.creator])
diff --git a/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.sql b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.sql
index 148e0ee2..93b605ce 100644
--- a/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.sql
+++ b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac.sql
@@ -33,7 +33,7 @@ begin
perform createRoleWithGrants(
hsOfficeBankAccountOwner(NEW),
- permissions => array['delete'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()],
userUuids => array[currentUserUuid()],
grantedByRole => globalAdmin()
@@ -51,7 +51,7 @@ begin
perform createRoleWithGrants(
hsOfficeBankAccountGuest(NEW),
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[hsOfficeBankAccountTenant(NEW)]
);
@@ -74,7 +74,7 @@ execute procedure createRbacRolesForHsOfficeBankAccount();
--changeset hs-office-bankaccount-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_bankaccount', $idName$
+call generateRbacIdentityViewFromProjection('hs_office_bankaccount', $idName$
target.holder
$idName$);
--//
diff --git a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql
index 02895c48..da7887cd 100644
--- a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql
+++ b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql
@@ -41,13 +41,13 @@ begin
perform createRoleWithGrants(
hsOfficeSepaMandateOwner(NEW),
- permissions => array['*'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()]
);
perform createRoleWithGrants(
hsOfficeSepaMandateAdmin(NEW),
- permissions => array['edit'],
+ permissions => array['UPDATE'],
incomingSuperRoles => array[hsOfficeSepaMandateOwner(NEW)],
outgoingSubRoles => array[hsOfficeBankAccountTenant(newHsOfficeBankAccount)]
);
@@ -66,7 +66,7 @@ begin
perform createRoleWithGrants(
hsOfficeSepaMandateGuest(NEW),
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[hsOfficeSepaMandateTenant(NEW)]
);
@@ -94,7 +94,7 @@ execute procedure hsOfficeSepaMandateRbacRolesTrigger();
-- ============================================================================
--changeset hs-office-sepamandate-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_sepamandate', idNameExpression => 'target.reference');
+call generateRbacIdentityViewFromProjection('hs_office_sepamandate', 'target.reference');
--//
diff --git a/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql b/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql
index 30573125..5f684f49 100644
--- a/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql
+++ b/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql
@@ -49,7 +49,7 @@ begin
perform createRoleWithGrants(
hsOfficeDebitorOwner(NEW),
- permissions => array['*'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()],
userUuids => array[currentUserUuid()],
grantedByRole => globalAdmin()
@@ -57,7 +57,7 @@ begin
perform createRoleWithGrants(
hsOfficeDebitorAdmin(NEW),
- permissions => array['edit'],
+ permissions => array['UPDATE'],
incomingSuperRoles => array[hsOfficeDebitorOwner(NEW)]
);
@@ -85,7 +85,7 @@ begin
perform createRoleWithGrants(
hsOfficeDebitorGuest(NEW),
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[
hsOfficeDebitorTenant(NEW)]
);
@@ -173,7 +173,7 @@ execute procedure hsOfficeDebitorRbacRolesTrigger();
-- ============================================================================
--changeset hs-office-debitor-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_debitor', $idName$
+call generateRbacIdentityViewFromProjection('hs_office_debitor', $idName$
'#' ||
(select partnerNumber from hs_office_partner p where p.uuid = target.partnerUuid) ||
to_char(debitorNumberSuffix, 'fm00') ||
diff --git a/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql b/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql
index 949f939c..2a4a4a50 100644
--- a/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql
+++ b/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql
@@ -41,13 +41,13 @@ begin
perform createRoleWithGrants(
hsOfficeMembershipOwner(NEW),
- permissions => array['*'],
+ permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()]
);
perform createRoleWithGrants(
hsOfficeMembershipAdmin(NEW),
- permissions => array['edit'],
+ permissions => array['UPDATE'],
incomingSuperRoles => array[hsOfficeMembershipOwner(NEW)]
);
@@ -65,7 +65,7 @@ begin
perform createRoleWithGrants(
hsOfficeMembershipGuest(NEW),
- permissions => array['view'],
+ permissions => array['SELECT'],
incomingSuperRoles => array[hsOfficeMembershipTenant(NEW), hsOfficePartnerTenant(newHsOfficePartner), hsOfficeDebitorTenant(newHsOfficeDebitor)]
);
@@ -93,7 +93,7 @@ execute procedure hsOfficeMembershipRbacRolesTrigger();
-- ============================================================================
--changeset hs-office-membership-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_membership', idNameExpression => $idName$
+call generateRbacIdentityViewFromProjection('hs_office_membership', $idName$
'#' ||
(select partnerNumber from hs_office_partner p where p.uuid = target.partnerUuid) ||
memberNumberSuffix ||
diff --git a/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql b/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql
index dd465d9f..5ee8bfbe 100644
--- a/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql
+++ b/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql
@@ -42,8 +42,8 @@ begin
-- coopsharestransactions cannot be edited nor deleted, just created+viewed
call grantPermissionsToRole(
- getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership), 'fail'),
- createPermissions(NEW.uuid, array ['view'])
+ getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership)),
+ createPermissions(NEW.uuid, array ['SELECT'])
);
else
@@ -68,8 +68,7 @@ execute procedure hsOfficeCoopSharesTransactionRbacRolesTrigger();
-- ============================================================================
--changeset hs-office-coopSharesTransaction-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_coopSharesTransaction',
- idNameExpression => 'target.reference');
+call generateRbacIdentityViewFromProjection('hs_office_coopSharesTransaction', 'target.reference');
--//
diff --git a/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql b/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql
index ac65c141..69920385 100644
--- a/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql
+++ b/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql
@@ -42,8 +42,8 @@ begin
-- coopassetstransactions cannot be edited nor deleted, just created+viewed
call grantPermissionsToRole(
- getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership), 'fail'),
- createPermissions(NEW.uuid, array ['view'])
+ getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership)),
+ createPermissions(NEW.uuid, array ['SELECT'])
);
else
@@ -68,8 +68,7 @@ execute procedure hsOfficeCoopAssetsTransactionRbacRolesTrigger();
-- ============================================================================
--changeset hs-office-coopAssetsTransaction-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-call generateRbacIdentityView('hs_office_coopAssetsTransaction',
- idNameExpression => 'target.reference');
+call generateRbacIdentityViewFromProjection('hs_office_coopAssetsTransaction', 'target.reference');
--//
diff --git a/src/test/java/net/hostsharing/hsadminng/arch/ArchitectureTest.java b/src/test/java/net/hostsharing/hsadminng/arch/ArchitectureTest.java
index fe50ccf1..013b2309 100644
--- a/src/test/java/net/hostsharing/hsadminng/arch/ArchitectureTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/arch/ArchitectureTest.java
@@ -28,6 +28,7 @@ public class ArchitectureTest {
"..test",
"..test.cust",
"..test.pac",
+ "..test.dom",
"..context",
"..generated..",
"..persistence..",
@@ -49,6 +50,8 @@ public class ArchitectureTest {
"..rbac.rbacuser",
"..rbac.rbacgrant",
"..rbac.rbacrole",
+ "..rbac.rbacobject",
+ "..rbac.rbacdef",
"..stringify"
// ATTENTION: Don't simply add packages here, also add arch rules for the new package!
);
@@ -116,7 +119,10 @@ public class ArchitectureTest {
public static final ArchRule hsAdminPackagesRule = classes()
.that().resideInAPackage("..hs.office.(*)..")
.should().onlyBeAccessed().byClassesThat()
- .resideInAnyPackage("..hs.office.(*)..");
+ .resideInAnyPackage(
+ "..hs.office.(*)..",
+ "..rbac.rbacgrant" // TODO: just because of RbacGrantsDiagramServiceIntegrationTest
+ );
@ArchTest
@SuppressWarnings("unused")
diff --git a/src/test/java/net/hostsharing/hsadminng/context/ContextBasedTest.java b/src/test/java/net/hostsharing/hsadminng/context/ContextBasedTest.java
index 1069fa5f..7f08f044 100644
--- a/src/test/java/net/hostsharing/hsadminng/context/ContextBasedTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/context/ContextBasedTest.java
@@ -1,14 +1,37 @@
package net.hostsharing.hsadminng.context;
+import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInfo;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Import;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+
+@Import(RbacGrantsDiagramService.class)
public abstract class ContextBasedTest {
@Autowired
protected Context context;
+ @PersistenceContext
+ protected EntityManager em; // just to be used in subclasses
+
+ /**
+ * To generate a flowchart diagram from the database use something like this in a defined context:
+
+
+ RbacGrantsDiagramService.writeToFile(
+ "title",
+ diagramService.allGrantsToCurrentUser(of(RbacGrantsDiagramService.Include.USERS, RbacGrantsDiagramService.Include.TEST_ENTITIES, RbacGrantsDiagramService.Include.NOT_ASSUMED, RbacGrantsDiagramService.Include.DETAILS, RbacGrantsDiagramService.Include.PERMISSIONS)),
+ "filename.md
+ );
+
+ */
+ @Autowired
+ protected RbacGrantsDiagramService diagramService; // just to be used in subclasses
+
TestInfo test;
@BeforeEach
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java
index f2847290..eb14e634 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java
@@ -109,7 +109,7 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
- "{ grant perm delete on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.owner by system and assume }",
+ "{ grant perm DELETE on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.owner by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.owner to role global#global.admin by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }",
@@ -117,7 +117,7 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
"{ grant role hs_office_bankaccount#sometempaccC.tenant to role hs_office_bankaccount#sometempaccC.admin by system and assume }",
- "{ grant perm view on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.guest by system and assume }",
+ "{ grant perm SELECT on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.guest by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.guest to role hs_office_bankaccount#sometempaccC.tenant by system and assume }",
null
));
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java
index a78b761e..91ee8bde 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java
@@ -111,11 +111,11 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTestWithClean
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.from(
initialGrantNames,
"{ grant role hs_office_contact#anothernewcontact.owner to role global#global.admin by system and assume }",
- "{ grant perm edit on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }",
+ "{ grant perm UPDATE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.tenant to role hs_office_contact#anothernewcontact.admin by system and assume }",
- "{ grant perm * on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
+ "{ grant perm DELETE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.admin to role hs_office_contact#anothernewcontact.owner by system and assume }",
- "{ grant perm view on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.guest by system and assume }",
+ "{ grant perm SELECT on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.guest by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.guest to role hs_office_contact#anothernewcontact.tenant by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }"
));
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java
index f18447df..1f6964b8 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java
@@ -114,7 +114,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
- "{ grant perm view on coopassetstransaction#temprefB to role membership#1000101:....tenant by system and assume }",
+ "{ grant perm SELECT on coopassetstransaction#temprefB to role membership#1000101:....tenant by system and assume }",
null));
}
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java
index 20602661..609e7940 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java
@@ -113,7 +113,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
- "{ grant perm view on coopsharestransaction#temprefB to role membership#1000101:....tenant by system and assume }",
+ "{ grant perm SELECT on coopsharestransaction#temprefB to role membership#1000101:....tenant by system and assume }",
null));
}
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java
index 839039a2..0616e338 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java
@@ -145,8 +145,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
}
@Nested
- @Accepts({ "Debitor:C(Create)" })
- class CreateDebitor {
+ class AddDebitor {
@Test
void globalAdmin_withoutAssumedRole_canAddDebitorWithBankAccount() {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java
index c703c31a..46d0878f 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java
@@ -118,8 +118,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
});
// then
- System.out.println("ok");
-// result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class);
+ result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class);
}
@Test
@@ -167,12 +166,12 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
.containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
// owner
- "{ grant perm * on debitor#1000422:FeG to role debitor#1000422:FeG.owner by system and assume }",
+ "{ grant perm DELETE on debitor#1000422:FeG to role debitor#1000422:FeG.owner by system and assume }",
"{ grant role debitor#1000422:FeG.owner to role global#global.admin by system and assume }",
"{ grant role debitor#1000422:FeG.owner to user superuser-alex by global#global.admin and assume }",
// admin
- "{ grant perm edit on debitor#1000422:FeG to role debitor#1000422:FeG.admin by system and assume }",
+ "{ grant perm UPDATE on debitor#1000422:FeG to role debitor#1000422:FeG.admin by system and assume }",
"{ grant role debitor#1000422:FeG.admin to role debitor#1000422:FeG.owner by system and assume }",
// agent
@@ -187,7 +186,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
"{ grant role partner#10004:FeG.tenant to role debitor#1000422:FeG.tenant by system and assume }",
// guest
- "{ grant perm view on debitor#1000422:FeG to role debitor#1000422:FeG.guest by system and assume }",
+ "{ grant perm SELECT on debitor#1000422:FeG to role debitor#1000422:FeG.guest by system and assume }",
"{ grant role debitor#1000422:FeG.guest to role debitor#1000422:FeG.tenant by system and assume }",
null));
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java
index 6a0cd485..4483304a 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java
@@ -126,11 +126,11 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
initialGrantNames,
// owner
- "{ grant perm * on membership#1000117:First to role membership#1000117:First.owner by system and assume }",
+ "{ grant perm DELETE on membership#1000117:First to role membership#1000117:First.owner by system and assume }",
"{ grant role membership#1000117:First.owner to role global#global.admin by system and assume }",
// admin
- "{ grant perm edit on membership#1000117:First to role membership#1000117:First.admin by system and assume }",
+ "{ grant perm UPDATE on membership#1000117:First to role membership#1000117:First.admin by system and assume }",
"{ grant role membership#1000117:First.admin to role membership#1000117:First.owner by system and assume }",
// agent
@@ -149,7 +149,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
"{ grant role membership#1000117:First.tenant to role partner#10001:First.agent by system and assume }",
// guest
- "{ grant perm view on membership#1000117:First to role membership#1000117:First.guest by system and assume }",
+ "{ grant perm SELECT on membership#1000117:First to role membership#1000117:First.guest by system and assume }",
"{ grant role membership#1000117:First.guest to role membership#1000117:First.tenant by system and assume }",
"{ grant role membership#1000117:First.guest to role partner#10001:First.tenant by system and assume }",
"{ grant role membership#1000117:First.guest to role debitor#1000111:First.tenant by system and assume }",
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java b/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java
index 325317b2..929aa919 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java
@@ -21,7 +21,7 @@ import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType;
import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity;
-import net.hostsharing.hsadminng.persistence.HasUuid;
+import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.test.JpaAttempt;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
@@ -520,7 +520,7 @@ public class ImportOfficeData extends ContextBasedTest {
}
- private void persist(final Integer id, final HasUuid entity) {
+ private void persist(final Integer id, final RbacObject entity) {
try {
//System.out.println("persisting #" + entity.hashCode() + ": " + entity);
em.persist(entity);
@@ -591,7 +591,7 @@ public class ImportOfficeData extends ContextBasedTest {
}).assertSuccessful();
}
- private void updateLegacyIds(
+ private void updateLegacyIds(
Map entities,
final String legacyIdTable,
final String legacyIdColumn) {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java
index 2512a07d..94d06a77 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java
@@ -171,29 +171,29 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#EBess.admin by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.owner to role person#HostsharingeG.admin by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#HostsharingeG.admin by system and assume }",
- "{ grant perm edit on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
+ "{ grant perm UPDATE on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
- "{ grant perm * on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.owner by system and assume }",
+ "{ grant perm DELETE on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.owner by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.admin to role relationship#HostsharingeG-with-PARTNER-EBess.owner by system and assume }",
- "{ grant perm view on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
+ "{ grant perm SELECT on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
"{ grant role contact#4th.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
"{ grant role person#EBess.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
"{ grant role person#HostsharingeG.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
// owner
- "{ grant perm * on partner#20032:EBess-4th to role partner#20032:EBess-4th.owner by system and assume }",
- "{ grant perm * on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.owner by system and assume }",
+ "{ grant perm DELETE on partner#20032:EBess-4th to role partner#20032:EBess-4th.owner by system and assume }",
+ "{ grant perm DELETE on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.owner by system and assume }",
"{ grant role partner#20032:EBess-4th.owner to role global#global.admin by system and assume }",
// admin
- "{ grant perm edit on partner#20032:EBess-4th to role partner#20032:EBess-4th.admin by system and assume }",
- "{ grant perm edit on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.admin by system and assume }",
+ "{ grant perm UPDATE on partner#20032:EBess-4th to role partner#20032:EBess-4th.admin by system and assume }",
+ "{ grant perm UPDATE on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant role partner#20032:EBess-4th.admin to role partner#20032:EBess-4th.owner by system and assume }",
"{ grant role person#EBess.tenant to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant role contact#4th.tenant to role partner#20032:EBess-4th.admin by system and assume }",
// agent
- "{ grant perm view on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.agent by system and assume }",
+ "{ grant perm SELECT on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.agent by system and assume }",
"{ grant role partner#20032:EBess-4th.agent to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant role partner#20032:EBess-4th.agent to role person#EBess.admin by system and assume }",
"{ grant role partner#20032:EBess-4th.agent to role contact#4th.admin by system and assume }",
@@ -204,7 +204,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
"{ grant role contact#4th.guest to role partner#20032:EBess-4th.tenant by system and assume }",
// guest
- "{ grant perm view on partner#20032:EBess-4th to role partner#20032:EBess-4th.guest by system and assume }",
+ "{ grant perm SELECT on partner#20032:EBess-4th to role partner#20032:EBess-4th.guest by system and assume }",
"{ grant role partner#20032:EBess-4th.guest to role partner#20032:EBess-4th.tenant by system and assume }",
null)));
@@ -473,7 +473,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
.contact(givenContact)
.build();
relationshipRepo.save(partnerRole);
- em.flush(); // TODO: why is that necessary?
final var newPartner = HsOfficePartnerEntity.builder()
.partnerNumber(partnerNumber)
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java
index dd3e08c9..d3da9ada 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java
@@ -113,11 +113,11 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTestWithCleanu
Array.from(
initialGrantNames,
"{ grant role hs_office_person#anothernewperson.owner to role global#global.admin by system and assume }",
- "{ grant perm edit on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }",
+ "{ grant perm UPDATE on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }",
"{ grant role hs_office_person#anothernewperson.tenant to role hs_office_person#anothernewperson.admin by system and assume }",
- "{ grant perm * on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.owner by system and assume }",
+ "{ grant perm DELETE on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.owner by system and assume }",
"{ grant role hs_office_person#anothernewperson.admin to role hs_office_person#anothernewperson.owner by system and assume }",
- "{ grant perm view on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.guest by system and assume }",
+ "{ grant perm SELECT on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.guest by system and assume }",
"{ grant role hs_office_person#anothernewperson.guest to role hs_office_person#anothernewperson.tenant by system and assume }",
"{ grant role hs_office_person#anothernewperson.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }"
));
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java
index 8d89479c..46d60a40 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java
@@ -115,14 +115,14 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
- "{ grant perm * on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner by system and assume }",
+ "{ grant perm DELETE on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner to role global#global.admin by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner to role hs_office_person#BesslerAnita.admin by system and assume }",
- "{ grant perm edit on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin by system and assume }",
+ "{ grant perm UPDATE on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner by system and assume }",
- "{ grant perm view on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant by system and assume }",
+ "{ grant perm SELECT on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant to role hs_office_contact#fourthcontact.admin by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant to role hs_office_person#BesslerAnita.admin by system and assume }",
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java
index 04b5b5cf..79910d28 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java
@@ -131,11 +131,11 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTestWithC
initialGrantNames,
// owner
- "{ grant perm * on sepamandate#temprefB to role sepamandate#temprefB.owner by system and assume }",
+ "{ grant perm DELETE on sepamandate#temprefB to role sepamandate#temprefB.owner by system and assume }",
"{ grant role sepamandate#temprefB.owner to role global#global.admin by system and assume }",
// admin
- "{ grant perm edit on sepamandate#temprefB to role sepamandate#temprefB.admin by system and assume }",
+ "{ grant perm UPDATE on sepamandate#temprefB to role sepamandate#temprefB.admin by system and assume }",
"{ grant role sepamandate#temprefB.admin to role sepamandate#temprefB.owner by system and assume }",
"{ grant role bankaccount#Paul....tenant to role sepamandate#temprefB.admin by system and assume }",
@@ -151,7 +151,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTestWithC
"{ grant role bankaccount#Paul....guest to role sepamandate#temprefB.tenant by system and assume }",
// guest
- "{ grant perm view on sepamandate#temprefB to role sepamandate#temprefB.guest by system and assume }",
+ "{ grant perm SELECT on sepamandate#temprefB to role sepamandate#temprefB.guest by system and assume }",
"{ grant role sepamandate#temprefB.guest to role sepamandate#temprefB.tenant by system and assume }",
null));
}
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/test/ContextBasedTestWithCleanup.java b/src/test/java/net/hostsharing/hsadminng/hs/office/test/ContextBasedTestWithCleanup.java
index 9b6c14ed..968e5416 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/test/ContextBasedTestWithCleanup.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/test/ContextBasedTestWithCleanup.java
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantEntity;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantRepository;
+import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleEntity;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository;
import net.hostsharing.test.JpaAttempt;
@@ -43,7 +44,7 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
@Autowired
JpaAttempt jpaAttempt;
- private TreeMap> entitiesToCleanup = new TreeMap<>();
+ private TreeMap> entitiesToCleanup = new TreeMap<>();
private static Long latestIntialTestDataSerialId;
private static boolean countersInitialized = false;
@@ -61,7 +62,7 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
return uuidToCleanup;
}
- public E toCleanup(final E entity) {
+ public E toCleanup(final E entity) {
out.println("toCleanup(" + entity.getClass() + ", " + entity.getUuid());
if ( entity.getUuid() == null ) {
throw new IllegalArgumentException("only persisted entities with valid uuid allowed");
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java
index 6f0abc93..f56baf34 100644
--- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java
@@ -73,14 +73,16 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.contentType("application/json")
.body("", hasItem(
allOf(
- hasEntry("grantedByRoleIdName", "global#global.admin"),
+ // 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")
)
))
.body("", hasItem(
allOf(
- hasEntry("grantedByRoleIdName", "global#global.admin"),
+ // 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")
)
@@ -296,7 +298,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
result.assertThat()
.statusCode(403)
.body("message", containsString("Access to granted role"))
- .body("message", containsString("forbidden for {test_package#xxx00.admin}"));
+ .body("message", containsString("forbidden for test_package#xxx00.admin"));
assertThat(findAllGrantsOf(givenCurrentUserAsPackageAdmin))
.extracting(RbacGrantEntity::getGranteeUserName)
.doesNotContain(givenNewUser.getName());
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java
index 3b09e861..8ce615b7 100644
--- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java
@@ -84,7 +84,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
exactlyTheseRbacGrantsAreReturned(
result,
- "{ grant role test_customer#xxx.admin to user customer-admin@xxx.example.com by role global#global.admin and assume }",
+ "{ grant role test_customer#xxx.admin to user customer-admin@xxx.example.com by role test_customer#xxx.owner and assume }",
"{ grant role test_package#xxx00.admin to user pac-admin-xxx00@xxx.example.com by role test_customer#xxx.admin and assume }",
"{ grant role test_package#xxx01.admin to user pac-admin-xxx01@xxx.example.com by role test_customer#xxx.admin and assume }",
"{ grant role test_package#xxx02.admin to user pac-admin-xxx02@xxx.example.com by role test_customer#xxx.admin and assume }");
@@ -162,8 +162,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
attempt.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
- "ERROR: [403] Access to granted role " + given.packageOwnerRoleUuid
- + " forbidden for {test_package#xxx00.admin}");
+ "ERROR: [403] Access to granted role test_package#xxx00.owner",
+ "forbidden for test_package#xxx00.admin");
jpaAttempt.transacted(() -> {
// finally, we use the new user to make sure, no roles were granted
context(given.arbitraryUser.getName(), null);
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantsDiagramServiceIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantsDiagramServiceIntegrationTest.java
new file mode 100644
index 00000000..0e0421c8
--- /dev/null
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantsDiagramServiceIntegrationTest.java
@@ -0,0 +1,103 @@
+package net.hostsharing.hsadminng.rbac.rbacgrant;
+
+import net.hostsharing.hsadminng.context.Context;
+import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
+import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService.Include;
+import net.hostsharing.test.JpaAttempt;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+
+import jakarta.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.UUID;
+
+import static java.lang.String.join;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DataJpaTest
+@Import( { Context.class, JpaAttempt.class, RbacGrantsDiagramService.class})
+class RbacGrantsDiagramServiceIntegrationTest extends ContextBasedTestWithCleanup {
+
+ @Autowired
+ RbacGrantsDiagramService grantsMermaidService;
+
+ @MockBean
+ HttpServletRequest request;
+
+ @Autowired
+ Context context;
+
+ @Autowired
+ RbacGrantsDiagramService diagramService;
+
+ TestInfo test;
+
+ @BeforeEach
+ void init(TestInfo testInfo) {
+ this.test = testInfo;
+ }
+
+ protected void context(final String currentUser, final String assumedRoles) {
+ context.define(test.getDisplayName(), null, currentUser, assumedRoles);
+ }
+
+ protected void context(final String currentUser) {
+ context(currentUser, null);
+ }
+
+ @Test
+ void allGrantsToCurrentUser() {
+ context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa.owner");
+ final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES));
+
+ assertThat(graph).isEqualTo("""
+ flowchart TB
+
+ role:test_domain#xxx00-aaaa.admin --> role:test_package#xxx00.tenant
+ role:test_domain#xxx00-aaaa.owner --> role:test_domain#xxx00-aaaa.admin
+ role:test_domain#xxx00-aaaa.owner --> role:test_package#xxx00.tenant
+ role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant
+ """.trim());
+ }
+
+ @Test
+ void allGrantsToCurrentUserIncludingPermissions() {
+ context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa.owner");
+ final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES, Include.PERMISSIONS));
+
+ assertThat(graph).isEqualTo("""
+ flowchart TB
+
+ role:test_customer#xxx.tenant --> perm:SELECT:on:test_customer#xxx
+ role:test_domain#xxx00-aaaa.admin --> perm:SELECT:on:test_domain#xxx00-aaaa
+ role:test_domain#xxx00-aaaa.admin --> role:test_package#xxx00.tenant
+ role:test_domain#xxx00-aaaa.owner --> perm:DELETE:on:test_domain#xxx00-aaaa
+ role:test_domain#xxx00-aaaa.owner --> perm:UPDATE:on:test_domain#xxx00-aaaa
+ role:test_domain#xxx00-aaaa.owner --> role:test_domain#xxx00-aaaa.admin
+ role:test_domain#xxx00-aaaa.owner --> role:test_package#xxx00.tenant
+ role:test_package#xxx00.tenant --> perm:SELECT:on:test_package#xxx00
+ role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant
+ """.trim());
+ }
+
+ @Test
+ @Disabled // enable to generate from a real database
+ void print() throws IOException {
+ //context("superuser-alex@hostsharing.net", "hs_office_person#FirbySusan.admin");
+ context("superuser-alex@hostsharing.net");
+
+ //final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.NON_TEST_ENTITIES, Include.PERMISSIONS));
+
+ final var targetObject = (UUID) em.createNativeQuery("SELECT uuid FROM hs_office_coopassetstransaction WHERE reference='ref 1000101-1'").getSingleResult();
+ final var graph = grantsMermaidService.allGrantsFrom(targetObject, "view", EnumSet.of(Include.USERS));
+
+ RbacGrantsDiagramService.writeToFile(join(";", context.getAssumedRoles()), graph, "doc/all-grants.md");
+ }
+}
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RawRbacObjectEntity.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RawRbacObjectEntity.java
new file mode 100644
index 00000000..d4256e56
--- /dev/null
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RawRbacObjectEntity.java
@@ -0,0 +1,31 @@
+package net.hostsharing.hsadminng.rbac.rbacrole;
+
+import lombok.*;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.data.annotation.Immutable;
+
+import jakarta.persistence.*;
+import java.util.List;
+import java.util.UUID;
+
+@Entity
+@Table(name = "rbacobject") // TODO: create view rbacobject_ev
+@Getter
+@Setter
+@ToString
+@Immutable
+@NoArgsConstructor
+@AllArgsConstructor
+public class RawRbacObjectEntity {
+
+ @Id
+ private UUID uuid;
+
+ @Column(name="objecttable")
+ private String objectTable;
+
+ @NotNull
+ public static List objectDisplaysOf(@NotNull final List roles) {
+ return roles.stream().map(e -> e.objectTable+ "#" + e.uuid).sorted().toList();
+ }
+}
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RawRbacObjectRepository.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RawRbacObjectRepository.java
new file mode 100644
index 00000000..ab645316
--- /dev/null
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RawRbacObjectRepository.java
@@ -0,0 +1,11 @@
+package net.hostsharing.hsadminng.rbac.rbacrole;
+
+import org.springframework.data.repository.Repository;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface RawRbacObjectRepository extends Repository {
+
+ List findAll();
+}
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java
index b13bcb76..9d7e16ca 100644
--- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java
@@ -288,19 +288,15 @@ class RbacUserControllerAcceptanceTest {
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy.tenant"),
- hasEntry("op", "view"))
- ))
- .body("", hasItem(
- allOf(
- hasEntry("roleName", "test_package#yyy00.admin"),
- hasEntry("op", "add-domain"))
+ hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
- hasEntry("op", "*"))
+ hasEntry("op", "DELETE"))
))
- .body("size()", is(7));
+ // actual content tested in integration test, so this is enough for here:
+ .body("size()", greaterThanOrEqualTo(6));
// @formatter:on
}
@@ -313,7 +309,7 @@ class RbacUserControllerAcceptanceTest {
RestAssured
.given()
.header("current-user", "superuser-alex@hostsharing.net")
- .header("assumed-roles", "test_package#yyy00.admin")
+ .header("assumed-roles", "test_customer#yyy.admin")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid() + "/permissions")
@@ -323,19 +319,15 @@ class RbacUserControllerAcceptanceTest {
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy.tenant"),
- hasEntry("op", "view"))
- ))
- .body("", hasItem(
- allOf(
- hasEntry("roleName", "test_package#yyy00.admin"),
- hasEntry("op", "add-domain"))
+ hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
- hasEntry("op", "*"))
+ hasEntry("op", "DELETE"))
))
- .body("size()", is(7));
+ // actual content tested in integration test, so this is enough for here:
+ .body("size()", greaterThanOrEqualTo(6));
// @formatter:on
}
@@ -357,19 +349,15 @@ class RbacUserControllerAcceptanceTest {
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy.tenant"),
- hasEntry("op", "view"))
- ))
- .body("", hasItem(
- allOf(
- hasEntry("roleName", "test_package#yyy00.admin"),
- hasEntry("op", "add-domain"))
+ hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
- hasEntry("op", "*"))
+ hasEntry("op", "DELETE"))
))
- .body("size()", is(7));
+ // actual content tested in integration test, so this is enough for here:
+ .body("size()", greaterThanOrEqualTo(6));
// @formatter:on
}
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java
index ea0a3109..c63047ed 100644
--- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java
@@ -20,6 +20,7 @@ import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.UUID;
+import static java.util.Comparator.comparing;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
@@ -181,50 +182,48 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
private static final String[] ALL_USER_PERMISSIONS = Array.of(
// @formatter:off
- "global#global.admin -> global#global: add-customer",
+ "test_customer#xxx.admin -> test_customer#xxx: SELECT",
+ "test_customer#xxx.owner -> test_customer#xxx: DELETE",
+ "test_customer#xxx.tenant -> test_customer#xxx: SELECT",
+ "test_customer#xxx.admin -> test_customer#xxx: INSERT:test_package",
+ "test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
+ "test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
+ "test_package#xxx00.tenant -> test_package#xxx00: SELECT",
+ "test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
+ "test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
+ "test_package#xxx01.tenant -> test_package#xxx01: SELECT",
+ "test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
+ "test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
+ "test_package#xxx02.tenant -> test_package#xxx02: SELECT",
- "test_customer#xxx.admin -> test_customer#xxx: add-package",
- "test_customer#xxx.admin -> test_customer#xxx: view",
- "test_customer#xxx.owner -> test_customer#xxx: *",
- "test_customer#xxx.tenant -> test_customer#xxx: view",
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.tenant -> test_package#xxx00: view",
- "test_package#xxx01.admin -> test_package#xxx01: add-domain",
- "test_package#xxx01.admin -> test_package#xxx01: add-domain",
- "test_package#xxx01.tenant -> test_package#xxx01: view",
- "test_package#xxx02.admin -> test_package#xxx02: add-domain",
- "test_package#xxx02.admin -> test_package#xxx02: add-domain",
- "test_package#xxx02.tenant -> test_package#xxx02: view",
+ "test_customer#yyy.admin -> test_customer#yyy: SELECT",
+ "test_customer#yyy.owner -> test_customer#yyy: DELETE",
+ "test_customer#yyy.tenant -> test_customer#yyy: SELECT",
+ "test_customer#yyy.admin -> test_customer#yyy: INSERT:test_package",
+ "test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
+ "test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
+ "test_package#yyy00.tenant -> test_package#yyy00: SELECT",
+ "test_package#yyy01.admin -> test_package#yyy01: INSERT:test_domain",
+ "test_package#yyy01.admin -> test_package#yyy01: INSERT:test_domain",
+ "test_package#yyy01.tenant -> test_package#yyy01: SELECT",
+ "test_package#yyy02.admin -> test_package#yyy02: INSERT:test_domain",
+ "test_package#yyy02.admin -> test_package#yyy02: INSERT:test_domain",
+ "test_package#yyy02.tenant -> test_package#yyy02: SELECT",
- "test_customer#yyy.admin -> test_customer#yyy: add-package",
- "test_customer#yyy.admin -> test_customer#yyy: view",
- "test_customer#yyy.owner -> test_customer#yyy: *",
- "test_customer#yyy.tenant -> test_customer#yyy: view",
- "test_package#yyy00.admin -> test_package#yyy00: add-domain",
- "test_package#yyy00.admin -> test_package#yyy00: add-domain",
- "test_package#yyy00.tenant -> test_package#yyy00: view",
- "test_package#yyy01.admin -> test_package#yyy01: add-domain",
- "test_package#yyy01.admin -> test_package#yyy01: add-domain",
- "test_package#yyy01.tenant -> test_package#yyy01: view",
- "test_package#yyy02.admin -> test_package#yyy02: add-domain",
- "test_package#yyy02.admin -> test_package#yyy02: add-domain",
- "test_package#yyy02.tenant -> test_package#yyy02: view",
-
- "test_customer#zzz.admin -> test_customer#zzz: add-package",
- "test_customer#zzz.admin -> test_customer#zzz: view",
- "test_customer#zzz.owner -> test_customer#zzz: *",
- "test_customer#zzz.tenant -> test_customer#zzz: view",
- "test_package#zzz00.admin -> test_package#zzz00: add-domain",
- "test_package#zzz00.admin -> test_package#zzz00: add-domain",
- "test_package#zzz00.tenant -> test_package#zzz00: view",
- "test_package#zzz01.admin -> test_package#zzz01: add-domain",
- "test_package#zzz01.admin -> test_package#zzz01: add-domain",
- "test_package#zzz01.tenant -> test_package#zzz01: view",
- "test_package#zzz02.admin -> test_package#zzz02: add-domain",
- "test_package#zzz02.admin -> test_package#zzz02: add-domain",
- "test_package#zzz02.tenant -> test_package#zzz02: view"
- // @formatter:on
+ "test_customer#zzz.admin -> test_customer#zzz: SELECT",
+ "test_customer#zzz.owner -> test_customer#zzz: DELETE",
+ "test_customer#zzz.tenant -> test_customer#zzz: SELECT",
+ "test_customer#zzz.admin -> test_customer#zzz: INSERT:test_package",
+ "test_package#zzz00.admin -> test_package#zzz00: INSERT:test_domain",
+ "test_package#zzz00.admin -> test_package#zzz00: INSERT:test_domain",
+ "test_package#zzz00.tenant -> test_package#zzz00: SELECT",
+ "test_package#zzz01.admin -> test_package#zzz01: INSERT:test_domain",
+ "test_package#zzz01.admin -> test_package#zzz01: INSERT:test_domain",
+ "test_package#zzz01.tenant -> test_package#zzz01: SELECT",
+ "test_package#zzz02.admin -> test_package#zzz02: INSERT:test_domain",
+ "test_package#zzz02.admin -> test_package#zzz02: INSERT:test_domain",
+ "test_package#zzz02.tenant -> test_package#zzz02: SELECT"
+ // @formatter:on
);
@Test
@@ -233,7 +232,9 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("superuser-alex@hostsharing.net");
// when
- final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("superuser-alex@hostsharing.net"));
+ final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("superuser-fran@hostsharing.net"))
+ .stream().filter(p -> p.getObjectTable().contains("test_"))
+ .sorted(comparing(RbacUserPermission::toString)).toList();
// then
allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS);
@@ -251,32 +252,32 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
- "test_customer#xxx.admin -> test_customer#xxx: add-package",
- "test_customer#xxx.admin -> test_customer#xxx: view",
- "test_customer#xxx.tenant -> test_customer#xxx: view",
+ "test_customer#xxx.admin -> test_customer#xxx: INSERT:test_package",
+ "test_customer#xxx.admin -> test_customer#xxx: SELECT",
+ "test_customer#xxx.tenant -> test_customer#xxx: SELECT",
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.tenant -> test_package#xxx00: view",
- "test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: *",
+ "test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
+ "test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
+ "test_package#xxx00.tenant -> test_package#xxx00: SELECT",
+ "test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: DELETE",
- "test_package#xxx01.admin -> test_package#xxx01: add-domain",
- "test_package#xxx01.admin -> test_package#xxx01: add-domain",
- "test_package#xxx01.tenant -> test_package#xxx01: view",
- "test_domain#xxx01-aaaa.owner -> test_domain#xxx01-aaaa: *",
+ "test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
+ "test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
+ "test_package#xxx01.tenant -> test_package#xxx01: SELECT",
+ "test_domain#xxx01-aaaa.owner -> test_domain#xxx01-aaaa: DELETE",
- "test_package#xxx02.admin -> test_package#xxx02: add-domain",
- "test_package#xxx02.admin -> test_package#xxx02: add-domain",
- "test_package#xxx02.tenant -> test_package#xxx02: view",
- "test_domain#xxx02-aaaa.owner -> test_domain#xxx02-aaaa: *"
+ "test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
+ "test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
+ "test_package#xxx02.tenant -> test_package#xxx02: SELECT",
+ "test_domain#xxx02-aaaa.owner -> test_domain#xxx02-aaaa: DELETE"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
- "test_customer#yyy.admin -> test_customer#yyy: add-package",
- "test_customer#yyy.admin -> test_customer#yyy: view",
- "test_customer#yyy.tenant -> test_customer#yyy: view"
+ "test_customer#yyy.admin -> test_customer#yyy: INSERT:test_package",
+ "test_customer#yyy.admin -> test_customer#yyy: SELECT",
+ "test_customer#yyy.tenant -> test_customer#yyy: SELECT"
// @formatter:on
);
}
@@ -311,26 +312,26 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
- "test_customer#xxx.tenant -> test_customer#xxx: view",
+ "test_customer#xxx.tenant -> test_customer#xxx: SELECT",
// "test_customer#xxx.admin -> test_customer#xxx: view" - Not permissions through the customer admin!
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.tenant -> test_package#xxx00: view",
- "test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: *",
- "test_domain#xxx00-aaab.owner -> test_domain#xxx00-aaab: *"
+ "test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
+ "test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
+ "test_package#xxx00.tenant -> test_package#xxx00: SELECT",
+ "test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: DELETE",
+ "test_domain#xxx00-aaab.owner -> test_domain#xxx00-aaab: DELETE"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
- "test_customer#yyy.admin -> test_customer#yyy: add-package",
- "test_customer#yyy.admin -> test_customer#yyy: view",
- "test_customer#yyy.tenant -> test_customer#yyy: view",
- "test_package#yyy00.admin -> test_package#yyy00: add-domain",
- "test_package#yyy00.admin -> test_package#yyy00: add-domain",
- "test_package#yyy00.tenant -> test_package#yyy00: view",
- "test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: *",
- "test_domain#yyy00-aaab.owner -> test_domain#yyy00-aaab: *"
+ "test_customer#yyy.admin -> test_customer#yyy: INSERT:test_package",
+ "test_customer#yyy.admin -> test_customer#yyy: SELECT",
+ "test_customer#yyy.tenant -> test_customer#yyy: SELECT",
+ "test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
+ "test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
+ "test_package#yyy00.tenant -> test_package#yyy00: SELECT",
+ "test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: DELETE",
+ "test_domain#yyy00-aaab.owner -> test_domain#yyy00-aaab: DELETE"
// @formatter:on
);
}
@@ -359,11 +360,10 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
- "test_customer#xxx.tenant -> test_customer#xxx: view",
+ "test_customer#xxx.tenant -> test_customer#xxx: SELECT",
// "test_customer#xxx.admin -> test_customer#xxx: view" - Not permissions through the customer admin!
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.admin -> test_package#xxx00: add-domain",
- "test_package#xxx00.tenant -> test_package#xxx00: view"
+ "test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
+ "test_package#xxx00.tenant -> test_package#xxx00: SELECT"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
@@ -373,13 +373,13 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
"test_customer#xxx.admin -> test_customer#xxx: add-package",
// no permissions on other customer's objects
"test_customer#yyy.admin -> test_customer#yyy: add-package",
- "test_customer#yyy.admin -> test_customer#yyy: view",
- "test_customer#yyy.tenant -> test_customer#yyy: view",
- "test_package#yyy00.admin -> test_package#yyy00: add-domain",
- "test_package#yyy00.admin -> test_package#yyy00: add-domain",
- "test_package#yyy00.tenant -> test_package#yyy00: view",
- "test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: *",
- "test_domain#yyy00-xxxb.owner -> test_domain#yyy00-xxxb: *"
+ "test_customer#yyy.admin -> test_customer#yyy: SELECT",
+ "test_customer#yyy.tenant -> test_customer#yyy: SELECT",
+ "test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
+ "test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
+ "test_package#yyy00.tenant -> test_package#yyy00: SELECT",
+ "test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: DELETE",
+ "test_domain#yyy00-xxxb.owner -> test_domain#yyy00-xxxb: DELETE"
// @formatter:on
);
}
@@ -432,7 +432,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
final List actualResult,
final String... expectedRoleNames) {
assertThat(actualResult)
- .extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
+ .extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp()
+ + (p.getOpTableName() != null ? (":"+p.getOpTableName()) : "" ))
.contains(expectedRoleNames);
}
diff --git a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerControllerAcceptanceTest.java
index 6c695caa..942351c0 100644
--- a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerControllerAcceptanceTest.java
@@ -148,7 +148,7 @@ class TestCustomerControllerAcceptanceTest {
// finally, the new customer can be viewed by its own admin
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
- context.define("customer-admin@uuu.example.com");
+ context.define("superuser-fran@hostsharing.net", "test_customer#uuu.admin");
assertThat(testCustomerRepository.findByUuid(newUserUuid))
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("uuu"));
}
@@ -175,7 +175,7 @@ class TestCustomerControllerAcceptanceTest {
.statusCode(403)
.contentType(ContentType.JSON)
.statusCode(403)
- .body("message", containsString("add-customer not permitted for test_customer#xxx.admin"));
+ .body("message", containsString("insert into test_customer not allowed for current subjects {test_customer#xxx.admin}"));
// @formatter:on
// finally, the new customer was not created
@@ -204,7 +204,7 @@ class TestCustomerControllerAcceptanceTest {
.statusCode(403)
.contentType(ContentType.JSON)
.statusCode(403)
- .body("message", containsString("add-customer not permitted for customer-admin@yyy.example.com"));
+ .body("message", containsString("insert into test_customer not allowed for current subjects {customer-admin@yyy.example.com}"));
// @formatter:on
// finally, the new customer was not created
diff --git a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntityUnitTest.java
new file mode 100644
index 00000000..eca0aec1
--- /dev/null
+++ b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntityUnitTest.java
@@ -0,0 +1,52 @@
+package net.hostsharing.hsadminng.test.cust;
+
+import net.hostsharing.hsadminng.rbac.rbacdef.RbacViewMermaidFlowchartGenerator;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class TestCustomerEntityUnitTest {
+
+ @Test
+ void definesRbac() {
+ final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(TestCustomerEntity.rbac()).toString();
+ assertThat(rbacFlowchart).isEqualTo("""
+ %%{init:{'flowchart':{'htmlLabels':false}}}%%
+ flowchart TB
+
+ subgraph customer["`**customer**`"]
+ direction TB
+ style customer fill:#dd4901,stroke:#274d6e,stroke-width:8px
+
+ subgraph customer:roles[ ]
+ style customer:roles fill:#dd4901,stroke:white
+
+ role:customer:owner[[customer:owner]]
+ role:customer:admin[[customer:admin]]
+ role:customer:tenant[[customer:tenant]]
+ end
+
+ subgraph customer:permissions[ ]
+ style customer:permissions fill:#dd4901,stroke:white
+
+ perm:customer:DELETE{{customer:DELETE}}
+ perm:customer:UPDATE{{customer:UPDATE}}
+ perm:customer:SELECT{{customer:SELECT}}
+ end
+ end
+
+ %% granting roles to users
+ user:creator ==>|XX| role:customer:owner
+
+ %% granting roles to roles
+ role:global:admin ==>|XX| role:customer:owner
+ role:customer:owner ==> role:customer:admin
+ role:customer:admin ==> role:customer:tenant
+
+ %% granting permissions to roles
+ role:customer:owner ==> perm:customer:DELETE
+ role:customer:admin ==> perm:customer:UPDATE
+ role:customer:tenant ==> perm:customer:SELECT
+ """);
+ }
+}
diff --git a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepositoryIntegrationTest.java
index ca535142..27458b14 100644
--- a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepositoryIntegrationTest.java
@@ -10,8 +10,6 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.PersistenceContext;
import jakarta.persistence.PersistenceException;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
@@ -27,9 +25,6 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
TestCustomerRepository testCustomerRepository;
- @PersistenceContext
- EntityManager em;
-
@MockBean
HttpServletRequest request;
@@ -43,7 +38,6 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
final var count = testCustomerRepository.count();
// when
-
final var result = attempt(em, () -> {
final var newCustomer = new TestCustomerEntity(
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
@@ -72,7 +66,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
- "add-customer not permitted for test_customer#xxx.admin");
+ "ERROR: [403] insert into test_customer not allowed for current subjects {test_customer#xxx.admin}");
}
@Test
@@ -90,7 +84,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
- "add-customer not permitted for customer-admin@xxx.example.com");
+ "ERROR: [403] insert into test_customer not allowed for current subjects {customer-admin@xxx.example.com}");
}
@@ -116,15 +110,15 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
}
@Test
- public void globalAdmin_withAssumedglobalAdminRole_canViewAllCustomers() {
+ public void globalAdmin_withAssumedCustomerOwnerRole_canViewExactlyThatCustomer() {
given:
- context("superuser-alex@hostsharing.net", "global#global.admin");
+ context("superuser-alex@hostsharing.net", "test_customer#yyy.owner");
// when
final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null);
then:
- allTheseCustomersAreReturned(result, "xxx", "yyy", "zzz");
+ allTheseCustomersAreReturned(result, "yyy");
}
@Test
@@ -141,6 +135,8 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnCustomer() {
+ context("customer-admin@xxx.example.com");
+
context("customer-admin@xxx.example.com", "test_package#xxx00.admin");
final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null);
diff --git a/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageEntityUnitTest.java
new file mode 100644
index 00000000..c5dccfd3
--- /dev/null
+++ b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageEntityUnitTest.java
@@ -0,0 +1,68 @@
+package net.hostsharing.hsadminng.test.pac;
+
+import net.hostsharing.hsadminng.rbac.rbacdef.RbacViewMermaidFlowchartGenerator;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class TestPackageEntityUnitTest {
+
+ @Test
+ void definesRbac() {
+ final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(TestPackageEntity.rbac()).toString();
+ assertThat(rbacFlowchart).isEqualTo("""
+ %%{init:{'flowchart':{'htmlLabels':false}}}%%
+ flowchart TB
+
+ subgraph package["`**package**`"]
+ direction TB
+ style package fill:#dd4901,stroke:#274d6e,stroke-width:8px
+
+ subgraph package:roles[ ]
+ style package:roles fill:#dd4901,stroke:white
+
+ role:package:owner[[package:owner]]
+ role:package:admin[[package:admin]]
+ role:package:tenant[[package:tenant]]
+ end
+
+ subgraph package:permissions[ ]
+ style package:permissions fill:#dd4901,stroke:white
+
+ perm:package:INSERT{{package:INSERT}}
+ perm:package:DELETE{{package:DELETE}}
+ perm:package:UPDATE{{package:UPDATE}}
+ perm:package:SELECT{{package:SELECT}}
+ end
+ end
+
+ subgraph customer["`**customer**`"]
+ direction TB
+ style customer fill:#99bcdb,stroke:#274d6e,stroke-width:8px
+
+ subgraph customer:roles[ ]
+ style customer:roles fill:#99bcdb,stroke:white
+
+ role:customer:owner[[customer:owner]]
+ role:customer:admin[[customer:admin]]
+ role:customer:tenant[[customer:tenant]]
+ end
+ end
+
+ %% granting roles to roles
+ role:global:admin -.->|XX| role:customer:owner
+ role:customer:owner -.-> role:customer:admin
+ role:customer:admin -.-> role:customer:tenant
+ role:customer:admin ==> role:package:owner
+ role:package:owner ==> role:package:admin
+ role:package:admin ==> role:package:tenant
+ role:package:tenant ==> role:customer:tenant
+
+ %% granting permissions to roles
+ role:customer:admin ==> perm:package:INSERT
+ role:package:owner ==> perm:package:DELETE
+ role:package:owner ==> perm:package:UPDATE
+ role:package:tenant ==> perm:package:SELECT
+ """);
+ }
+}
diff --git a/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageRepositoryIntegrationTest.java
index 53d28e0c..a201d79e 100644
--- a/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageRepositoryIntegrationTest.java
@@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.test.pac;
import net.hostsharing.hsadminng.context.Context;
+import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -19,10 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
-class TestPackageRepositoryIntegrationTest {
-
- @Autowired
- Context context;
+class TestPackageRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
TestPackageRepository testPackageRepository;
@@ -40,9 +38,10 @@ class TestPackageRepositoryIntegrationTest {
class FindAllByOptionalNameLike {
@Test
- public void globalAdmin_withoutAssumedRole_canNotViewAnyPackages_becauseThoseGrantsAreNotassumedd() {
+ public void globalAdmin_withoutAssumedRole_canNotViewAnyPackages_becauseThoseGrantsAreNotAssumed() {
// given
- context.define("superuser-alex@hostsharing.net");
+ // alex is not just global-admin but lso the creating user, thus we use fran
+ context.define("superuser-fran@hostsharing.net");
// when
final var result = testPackageRepository.findAllByOptionalNameLike(null);
@@ -52,7 +51,7 @@ class TestPackageRepositoryIntegrationTest {
}
@Test
- public void globalAdmin_withAssumedglobalAdminRole__canNotViewAnyPackages_becauseThoseGrantsAreNotassumedd() {
+ public void globalAdmin_withAssumedglobalAdminRole__canNotViewAnyPackages_becauseThoseGrantsAreNotAssumed() {
given:
context.define("superuser-alex@hostsharing.net", "global#global.admin");
@@ -89,7 +88,7 @@ class TestPackageRepositoryIntegrationTest {
class OptimisticLocking {
@Test
- public void supportsOptimisticLocking() throws InterruptedException {
+ public void supportsOptimisticLocking() {
// given
globalAdminWithAssumedRole("test_package#xxx00.admin");
final var pac = testPackageRepository.findAllByOptionalNameLike("%").get(0);