introduce separate database schema test and amend generators to be able to use schema

This commit is contained in:
Michael Hoennig 2024-09-16 16:29:18 +02:00
parent 1eed0e9b21
commit ca899b7c0d
52 changed files with 923 additions and 394 deletions

View File

@ -82,7 +82,7 @@ If you have at least Docker and the Java JDK installed in appropriate versions a
# the following command should return a JSON array with just all packages visible for the admin of the customer yyy:
curl \
-H 'current-subject: superuser-alex@hostsharing.net' -H 'assumed-roles: test_customer#yyy:ADMIN' \
-H 'current-subject: superuser-alex@hostsharing.net' -H 'assumed-roles: rbactest.customer#yyy:ADMIN' \
http://localhost:8080/api/test/packages
# add a new customer

View File

@ -3,14 +3,14 @@
-- --------------------------------------------------------
select rbac.isGranted(rbac.findRoleId('administrators'), rbac.findRoleId('test.package#aaa00:OWNER'));
select rbac.isGranted(rbac.findRoleId('test.package#aaa00:OWNER'), rbac.findRoleId('administrators'));
-- call rbac.grantRoleToRole(findRoleId('test.package#aaa00:OWNER'), findRoleId('administrators'));
-- call rbac.grantRoleToRole(findRoleId('administrators'), findRoleId('test.package#aaa00:OWNER'));
select rbac.isGranted(rbac.findRoleId('administrators'), rbac.findRoleId('rbactest.package#aaa00:OWNER'));
select rbac.isGranted(rbac.findRoleId('rbactest.package#aaa00:OWNER'), rbac.findRoleId('administrators'));
-- call rbac.grantRoleToRole(findRoleId('rbactest.package#aaa00:OWNER'), findRoleId('administrators'));
-- call rbac.grantRoleToRole(findRoleId('administrators'), findRoleId('rbactest.package#aaa00:OWNER'));
select count(*)
FROM rbac.queryAllPermissionsOfSubjectIdForObjectUuids(rbac.findRbacSubject('superuser-fran@hostsharing.net'),
ARRAY(select uuid from test.customer where reference < 1100000));
ARRAY(select uuid from rbactest.customer where reference < 1100000));
select count(*)
FROM rbac.queryAllPermissionsOfSubjectId(findRbacSubject('superuser-fran@hostsharing.net'));
select *

View File

@ -20,7 +20,7 @@ CREATE POLICY customer_policy ON customer
TO restricted
USING (
-- id=1000
rbac.isPermissionGrantedToSubject(rbac.findEffectivePermissionId('test.customer', id, 'SELECT'), rbac.currentSubjectUuid())
rbac.isPermissionGrantedToSubject(rbac.findEffectivePermissionId('rbactest.customer', id, 'SELECT'), rbac.currentSubjectUuid())
);
SET SESSION AUTHORIZATION restricted;
@ -31,28 +31,28 @@ SELECT * from customer;
SET SESSION SESSION AUTHORIZATION DEFAULT;
DROP VIEW cust_view;
CREATE VIEW cust_view AS
SELECT * FROM test.customer;
SELECT * FROM rbactest.customer;
CREATE OR REPLACE RULE "_RETURN" AS
ON SELECT TO cust_view
DO INSTEAD
SELECT * FROM test.customer WHERE rbac.isPermissionGrantedToSubject(rbac.findEffectivePermissionId('test.customer', id, 'SELECT'), rbac.currentSubjectUuid());
SELECT * FROM rbactest.customer WHERE rbac.isPermissionGrantedToSubject(rbac.findEffectivePermissionId('rbactest.customer', id, 'SELECT'), rbac.currentSubjectUuid());
SELECT * from cust_view LIMIT 10;
select rbac.queryAllPermissionsOfSubjectId(findRbacSubject('superuser-alex@hostsharing.net'));
-- access control via view-rule with join to recursive permissions - really fast (38ms for 1 million rows)
SET SESSION SESSION AUTHORIZATION DEFAULT;
ALTER TABLE test.customer ENABLE ROW LEVEL SECURITY;
ALTER TABLE rbactest.customer ENABLE ROW LEVEL SECURITY;
DROP VIEW IF EXISTS cust_view;
CREATE OR REPLACE VIEW cust_view AS
SELECT *
FROM test.customer;
FROM rbactest.customer;
CREATE OR REPLACE RULE "_RETURN" AS
ON SELECT TO cust_view
DO INSTEAD
SELECT c.uuid, c.reference, c.prefix FROM test.customer AS c
SELECT c.uuid, c.reference, c.prefix FROM rbactest.customer AS c
JOIN rbac.queryAllPermissionsOfSubjectId(rbac.currentSubjectUuid()) AS p
ON p.objectTable='test.customer' AND p.objectUuid=c.uuid;
ON p.objectTable='rbactest.customer' AND p.objectUuid=c.uuid;
GRANT ALL PRIVILEGES ON cust_view TO restricted;
SET SESSION SESSION AUTHORIZATION restricted;
@ -81,9 +81,9 @@ select rr.uuid, rr.type from rbac.RbacGrants g
join rbac.RbacReference RR on g.ascendantUuid = RR.uuid
where g.descendantUuid in (
select uuid from rbac.queryAllPermissionsOfSubjectId(findRbacSubject('alex@example.com'))
where objectTable='test.customer');
where objectTable='rbactest.customer');
call rbac.grantRoleToUser(rbac.findRoleId('test.customer#aaa:ADMIN'), rbac.findRbacSubject('aaaaouq@example.com'));
call rbac.grantRoleToUser(rbac.findRoleId('rbactest.customer#aaa:ADMIN'), rbac.findRbacSubject('aaaaouq@example.com'));
select rbac.queryAllPermissionsOfSubjectId(findRbacSubject('aaaaouq@example.com'));

View File

@ -100,7 +100,7 @@ public class InsertTriggerGenerator {
/**
Grants ${rawSubTable} INSERT permission to specified role of new ${rawSuperTable} rows.
*/
create or replace function ${rawSuperTableSchemaName}new_${rawSubTableShortName}_grants_insert_to_${rawSuperTableShortName}_tf()
create or replace function ${rawSubTableSchemaPrefix}new_${rawSubTableShortName}_grants_insert_to_${rawSuperTableShortName}_tf()
returns trigger
language plpgsql
strict as $$
@ -114,10 +114,10 @@ public class InsertTriggerGenerator {
end; $$;
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
create trigger z_new_${rawSubTable}_grants_after_insert_tg
create trigger z_new_${rawSubTableName}_grants_after_insert_tg
after insert on ${rawSuperTableWithSchema}
for each row
execute procedure ${rawSuperTableSchemaName}new_${rawSubTableShortName}_grants_insert_to_${rawSuperTableShortName}_tf();
execute procedure ${rawSubTableSchemaPrefix}new_${rawSubTableShortName}_grants_insert_to_${rawSuperTableShortName}_tf();
""",
with("ifConditionThen", g.getSuperRoleDef().getEntityAlias().isCaseDependent()
// TODO.impl: .type needs to be dynamically generated
@ -130,8 +130,9 @@ public class InsertTriggerGenerator {
with("rawSuperTableWithSchema", g.getSuperRoleDef().getEntityAlias().getRawTableNameWithSchema()),
with("rawSuperTableShortName", g.getSuperRoleDef().getEntityAlias().getRawTableShortName()),
with("rawSuperTable", g.getSuperRoleDef().getEntityAlias().getRawTableName()),
with("rawSuperTableSchemaName", g.getSuperRoleDef().getEntityAlias().getRawTableSchemaPrefix()),
with("rawSubTable", g.getPermDef().getEntityAlias().getRawTableNameWithSchema()),
with("rawSubTableSchemaPrefix", g.getPermDef().getEntityAlias().getRawTableSchemaPrefix()),
with("rawSubTableName", g.getPermDef().getEntityAlias().getRawTableName()),
with("rawSubTableShortName", g.getPermDef().getEntityAlias().getRawTableShortName()));
});
@ -154,15 +155,16 @@ public class InsertTriggerGenerator {
returns trigger
language plpgsql as $$
begin
raise exception '[403] insert into ${rawSubTable} values(%) not allowed regardless of current subject, no insert permissions granted at all', NEW;
raise exception '[403] insert into ${rawSubTableWithSchema} values(%) not allowed regardless of current subject, no insert permissions granted at all', NEW;
end; $$;
create trigger ${rawSubTable}_insert_permission_check_tg
before insert on ${rawSubTable}
for each row
execute procedure ${rawSubTable}_insert_permission_missing_tf();
execute procedure ${rawSubTableWithSchema}_insert_permission_missing_tf();
""",
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableNameWithSchema()));
with("rawSubTableWithSchema", rbacDef.getRootEntityAlias().getRawTableNameWithSchema()),
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()));
plPgSql.writeLn("--//");
}
@ -183,7 +185,7 @@ public class InsertTriggerGenerator {
private void generateInsertPermissionsCheckHeader(final StringWriter plPgSql) {
plPgSql.writeLn("""
-- ============================================================================
--changeset InsertTriggerGenerator:${rawSubTable}-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:${liquibaseTagPrefix}-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**
@ -196,6 +198,7 @@ public class InsertTriggerGenerator {
superObjectUuid uuid;
begin
""",
with("liquibaseTagPrefix", liquibaseTagPrefix),
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableNameWithSchema()));
plPgSql.chopEmptyLines();
}
@ -258,17 +261,18 @@ public class InsertTriggerGenerator {
private void generateInsertPermissionsChecksFooter(final StringWriter plPgSql) {
plPgSql.writeLn();
plPgSql.writeLn("""
raise exception '[403] insert into ${rawSubTable} values(%) not allowed for current subjects % (%)',
raise exception '[403] insert into ${rawSubTableWithSchema} values(%) not allowed for current subjects % (%)',
NEW, base.currentSubjects(), rbac.currentSubjectOrAssumedRolesUuids();
end; $$;
create trigger ${rawSubTable}_insert_permission_check_tg
before insert on ${rawSubTable}
before insert on ${rawSubTableWithSchema}
for each row
execute procedure ${rawSubTable}_insert_permission_check_tf();
execute procedure ${rawSubTableWithSchema}_insert_permission_check_tf();
--//
""",
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableNameWithSchema()));
with("rawSubTableWithSchema", rbacDef.getRootEntityAlias().getRawTableNameWithSchema()),
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()));
}
private String toStringList(final Set<RbacView.CaseDef> cases) {

View File

@ -90,11 +90,11 @@ public class RbacView {
* @param <E>
* a JPA entity class extending RbacObject
*/
public static <E extends BaseEntity> RbacView rbacViewFor(final String alias, final Class<E> entityClass) {
public static <E extends BaseEntity<?>> RbacView rbacViewFor(final String alias, final Class<E> entityClass) {
return new RbacView(alias, entityClass);
}
RbacView(final String alias, final Class<? extends BaseEntity> entityClass) {
RbacView(final String alias, final Class<? extends BaseEntity<?>> entityClass) {
rootEntityAlias = new EntityAlias(alias, entityClass);
entityAliases.put(alias, rootEntityAlias);
new RbacSubjectReference(CREATOR);
@ -121,7 +121,7 @@ public class RbacView {
* <p>An identity view is a view which maps an objectUuid to an idName.
* The idName should be a human-readable representation of the row, but as short as possible.
* The idName must only consist of letters (A-Z, a-z), digits (0-9), dash (-), dot (.) and unserscore '_'.
* It's used to create the object-specific-role-names like test_customer#abc:ADMIN - here 'abc' is the idName.
* It's used to create the object-specific-role-names like rbactest.customer#abc:ADMIN - here 'abc' is the idName.
* The idName not necessarily unique in a table, but it should be avoided.
* </p>
*
@ -287,9 +287,9 @@ public class RbacView {
* @param <EC>
* a JPA entity class extending RbacObject
*/
public <EC extends BaseEntity> RbacView importRootEntityAliasProxy(
public <EC extends BaseEntity<?>> RbacView importRootEntityAliasProxy(
final String aliasName,
final Class<? extends BaseEntity> entityClass,
final Class<? extends BaseEntity<?>> entityClass,
final ColumnValue forCase,
final SQL fetchSql,
final Column dependsOnColum) {
@ -313,7 +313,7 @@ public class RbacView {
* a JPA entity class extending RbacObject
*/
public RbacView importSubEntityAlias(
final String aliasName, final Class<? extends BaseEntity> entityClass,
final String aliasName, final Class<? extends BaseEntity<?>> entityClass,
final SQL fetchSql, final Column dependsOnColum) {
importEntityAliasImpl(aliasName, entityClass, usingDefaultCase(), fetchSql, dependsOnColum, true, NOT_NULL);
return this;
@ -350,14 +350,14 @@ public class RbacView {
* a JPA entity class extending RbacObject
*/
public RbacView importEntityAlias(
final String aliasName, final Class<? extends BaseEntity> entityClass, final ColumnValue usingCase,
final String aliasName, final Class<? extends BaseEntity<?>> entityClass, final ColumnValue usingCase,
final Column dependsOnColum, final SQL fetchSql, final Nullable nullable) {
importEntityAliasImpl(aliasName, entityClass, usingCase, fetchSql, dependsOnColum, false, nullable);
return this;
}
private EntityAlias importEntityAliasImpl(
final String aliasName, final Class<? extends BaseEntity> entityClass, final ColumnValue usingCase,
final String aliasName, final Class<? extends BaseEntity<?>> entityClass, final ColumnValue usingCase,
final SQL fetchSql, final Column dependsOnColum, boolean asSubEntity, final Nullable nullable) {
final var entityAlias = ofNullable(entityAliases.get(aliasName))
@ -911,13 +911,13 @@ public class RbacView {
return distinctGrantDef;
}
record EntityAlias(String aliasName, Class<? extends BaseEntity> entityClass, ColumnValue usingCase, SQL fetchSql, Column dependsOnColum, boolean isSubEntity, Nullable nullable) {
record EntityAlias(String aliasName, Class<? extends BaseEntity<?>> entityClass, ColumnValue usingCase, SQL fetchSql, Column dependsOnColum, boolean isSubEntity, Nullable nullable) {
public EntityAlias(final String aliasName) {
this(aliasName, null, null, null, null, false, null);
}
public EntityAlias(final String aliasName, final Class<? extends BaseEntity> entityClass) {
public EntityAlias(final String aliasName, final Class<? extends BaseEntity<?>> entityClass) {
this(aliasName, entityClass, null, null, null, false, null);
}
@ -964,7 +964,7 @@ public class RbacView {
if ( aliasName.equals("rbac.global")) {
return "rbac.global"; // TODO: maybe we should introduce a GlobalEntity class?
}
return withoutRvSuffix(entityClass.getAnnotation(Table.class).name());
return qualifiedRealTableName(entityClass);
}
String getRawTableSchemaPrefix() {
@ -1010,8 +1010,12 @@ public class RbacView {
}
}
public static String withoutRvSuffix(final String tableName) {
return tableName.substring(0, tableName.length() - "_rv".length());
public static String qualifiedRealTableName(final Class<? extends BaseEntity<?>> entityClass) {
final var tableAnnotation = entityClass.getAnnotation(Table.class);
final var schema = tableAnnotation.schema();
final var tableName = tableAnnotation.name();
final var realTableName = tableName.substring(0, tableName.length() - "_rv".length());
return (schema.isEmpty() ? "" : (schema + ".")) + realTableName;
}
public enum Role {

View File

@ -17,7 +17,7 @@ public class RbacViewPostgresGenerator {
public RbacViewPostgresGenerator(final RbacView forRbacDef) {
rbacDef = forRbacDef;
liqibaseTagPrefix = rbacDef.getRootEntityAlias().getRawTableNameWithSchema().replace("_", "-");
liqibaseTagPrefix = rbacDef.getRootEntityAlias().getRawTableNameWithSchema().replace("_", "-").replace(".", "-");
plPgSql.writeLn("""
--liquibase formatted sql
-- This code generated was by ${generator}, do not amend manually.

View File

@ -516,7 +516,7 @@ class RolesGrantsAndPermissionsGenerator {
/*
AFTER INSERT TRIGGER to create the role+grant structure for a new ${rawTableName} row.
*/
create or replace function insertTriggerFor${simpleEntityName}_tf()
returns trigger
language plpgsql
@ -525,7 +525,7 @@ class RolesGrantsAndPermissionsGenerator {
call buildRbacSystemFor${simpleEntityName}(NEW);
return NEW;
end; $$;
create trigger insertTriggerFor${simpleEntityName}_tg
after insert on ${rawTableName}
for each row

View File

@ -19,9 +19,11 @@ public class StringWriter {
writeLn();
}
void writeLn(final String text, final VarDef... varDefs) {
string.append( indented( new VarReplacer(varDefs).apply(text) ));
String writeLn(final String text, final VarDef... varDefs) {
final var insertText = indented(new VarReplacer(varDefs).apply(text));
string.append(insertText);
writeLn();
return insertText;
}
void writeLn() {

View File

@ -79,10 +79,10 @@ public class RbacGrantsDiagramService {
return;
}
if ( !g.getDescendantIdName().startsWith("role:rbac.global")) {
if (!includes.contains(TEST_ENTITIES) && g.getDescendantIdName().contains(":test_")) {
if (!includes.contains(TEST_ENTITIES) && g.getDescendantIdName().contains(":rbactest.")) {
return;
}
if (!includes.contains(NON_TEST_ENTITIES) && !g.getDescendantIdName().contains(":test_")) {
if (!includes.contains(NON_TEST_ENTITIES) && !g.getDescendantIdName().contains(":rbactest.")) {
return;
}
}

View File

@ -20,7 +20,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
@Entity
@Table(name = "test_customer_rv")
@Table(schema = "rbactest", name = "customer_rv")
@Getter
@Setter
@NoArgsConstructor
@ -62,6 +62,6 @@ public class TestCustomerEntity implements BaseEntity<TestCustomerEntity> {
}
public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("2-test/201-test-customer/2013-test-customer-rbac");
rbac().generateWithBaseFileName("2-rbactest/201-rbactest-customer/2013-rbactest-customer-rbac");
}
}

View File

@ -22,7 +22,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetc
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
@Entity
@Table(name = "test_domain_rv")
@Table(schema = "rbactest", name = "domain_rv")
@Getter
@Setter
@NoArgsConstructor
@ -68,6 +68,6 @@ public class TestDomainEntity implements BaseEntity<TestDomainEntity> {
}
public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("2-test/203-test-domain/2033-test-domain-rbac");
rbac().generateWithBaseFileName("2-rbactest/203-rbactest-domain/2033-rbactest-domain-rbac");
}
}

View File

@ -22,7 +22,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
@Entity
@Table(name = "test_package_rv")
@Table(schema = "rbactest", name = "package_rv")
@Getter
@Setter
@NoArgsConstructor
@ -69,6 +69,6 @@ public class TestPackageEntity implements BaseEntity<TestPackageEntity> {
}
public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("2-test/202-test-package/2023-test-package-rbac");
rbac().generateWithBaseFileName("2-rbactest/202-rbactest-package/2023-rbactest-package-rbac");
}
}

View File

@ -4,5 +4,16 @@
-- ============================================================================
--changeset michael.hoennig:base-SCHEMA endDelimiter:--//
-- ----------------------------------------------------------------------------
-- FIXME: remove this block
do $$
declare
changesetCount int;
begin
changesetCount := (select count(*) from databasechangelog);
assert changesetCount = 0, 'total changesets executed: ' || changesetCount;
end;
$$;
CREATE SCHEMA base;
--//

View File

@ -6,15 +6,31 @@
--changeset michael.hoennig:table-columns-function endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace function base.tableColumnNames( tableName text )
create or replace function base.tableColumnNames( ofTableName text )
returns text
stable
language 'plpgsql' as $$
declare columns text[];
declare
tableName text;
tableSchema text;
columns text[];
begin
tableSchema := CASE
WHEN position('.' in ofTableName) > 0 THEN split_part(ofTableName, '.', 1)
ELSE 'public'
END;
tableName := CASE
WHEN position('.' in ofTableName) > 0 THEN split_part(ofTableName, '.', 2)
ELSE ofTableName
END;
columns := (select array(select column_name::text
from information_schema.columns
where table_name = tableName));
from information_schema.columns
where table_name = tableName
and table_schema = tableSchema));
assert cardinality(columns) > 0, 'cannot determine columns of table ' || ofTableName ||
'("' || tableSchema || '"."' || tableName || '")';
return array_to_string(columns, ', ');
end; $$
--//

View File

@ -127,6 +127,7 @@ begin
end; $$;
--//
-- ============================================================================
--changeset michael.hoennig:context-base.ASSUMED-ROLES endDelimiter:--//
-- ----------------------------------------------------------------------------

View File

@ -0,0 +1,18 @@
--liquibase formatted sql
-- ============================================================================
--changeset michael.hoennig:base-COMBINE-TABLE-SCHEMA-AND-NAME endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace function base.combine_table_schema_and_name(tableSchema name, tableName name)
returns text
language plpgsql as $$
begin
if tableSchema is null or tableSchema = 'public' or tableSchema = '' then
return tableName::text;
else
return tableSchema::text || '.' || tableName::text;
end if;
end; $$;
--//

View File

@ -77,9 +77,11 @@ create or replace function base.tx_journal_trigger()
declare
curTask text;
curTxId xid8;
tableSchemaAndName text;
begin
curTask := base.currentTask();
curTxId := pg_current_xact_id();
tableSchemaAndName := base.combine_table_schema_and_name(tg_table_schema, tg_table_name);
insert
into base.tx_context (txId, txTimestamp, currentSubject, assumedRoles, currentTask, currentRequest)
@ -90,20 +92,20 @@ begin
case tg_op
when 'INSERT' then insert
into base.tx_journal
values (curTxId,
tg_table_name, new.uuid, tg_op::base.tx_operation,
values (curTxId, tableSchemaAndName,
new.uuid, tg_op::base.tx_operation,
to_jsonb(new));
when 'UPDATE' then insert
into base.tx_journal
values (curTxId,
tg_table_name, old.uuid, tg_op::base.tx_operation,
values (curTxId, tableSchemaAndName,
old.uuid, tg_op::base.tx_operation,
base.jsonb_changes_delta(to_jsonb(old), to_jsonb(new)));
when 'DELETE' then insert
into base.tx_journal
values (curTxId,
tg_table_name, old.uuid, 'DELETE'::base.tx_operation,
values (curTxId,tableSchemaAndName,
old.uuid, 'DELETE'::base.tx_operation,
null::jsonb);
else raise exception 'Trigger op % not supported for %.', tg_op, tg_table_name;
else raise exception 'Trigger op % not supported for %.', tg_op, tableSchemaAndName;
end case;
return null;
end; $$;

View File

@ -81,8 +81,8 @@ begin
"alive" := false;
end if;
sql := format('INSERT INTO %3$I_ex VALUES (DEFAULT, pg_current_xact_id(), %1$L, %2$L, $1.*)', TG_OP, alive, TG_TABLE_NAME);
raise notice 'sql: %', sql;
sql := format('INSERT INTO %3$I_ex VALUES (DEFAULT, pg_current_xact_id(), %1$L, %2$L, $1.*)',
TG_OP, alive, base.combine_table_schema_and_name(tg_table_schema, tg_table_name)::name);
execute sql using "row";
return "row";

View File

@ -3,9 +3,7 @@
-- ============================================================================
--changeset michael.hoennig:rbac-base-REFERENCE endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
*/
create type rbac.ReferenceType as enum ('rbac.subject', 'rbac.role', 'rbac.permission');
create table rbac.reference
@ -120,18 +118,20 @@ create or replace function rbac.insert_related_object()
strict as $$
declare
objectUuid uuid;
tableSchemaAndName text;
begin
tableSchemaAndName := base.combine_table_schema_and_name(TG_TABLE_SCHEMA, TG_TABLE_NAME);
if TG_OP = 'INSERT' then
if NEW.uuid is null then
insert
into rbac.object (objectTable)
values (TG_TABLE_NAME)
values (tableSchemaAndName)
returning uuid into objectUuid;
NEW.uuid = objectUuid;
else
insert
into rbac.object (uuid, objectTable)
values (NEW.uuid, TG_TABLE_NAME)
values (NEW.uuid, tableSchemaAndName)
returning uuid into objectUuid;
end if;
return NEW;

View File

@ -20,7 +20,7 @@ begin
return currentSubjectOrAssumedRolesUuids[1];
end; $$;
create or replace procedure rbac.grantRoleToSubjectUnchecked(grantedByRoleUuid uuid, grantedRoleUuid uuid, subjectUuid uuid, doAssume boolean = true)
create or replace procedure rbac.grantRoleToUserUnchecked(grantedByRoleUuid uuid, grantedRoleUuid uuid, subjectUuid uuid, doAssume boolean = true)
language plpgsql as $$
begin
perform rbac.assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'rbac.role');

View File

@ -57,7 +57,7 @@ begin
end if;
foreach subjectUuid in array subjectUuids
loop
call rbac.grantRoleToSubjectUnchecked(userGrantsByRoleUuid, roleUuid, subjectUuid);
call rbac.grantRoleToUserUnchecked(userGrantsByRoleUuid, roleUuid, subjectUuid);
end loop;
end if;

View File

@ -8,26 +8,40 @@
create or replace procedure rbac.generateRelatedRbacObject(targetTable varchar)
language plpgsql as $$
declare
targetTableName text;
targetSchemaPrefix text;
createInsertTriggerSQL text;
createDeleteTriggerSQL text;
begin
if POSITION('.' IN targetTable) > 0 then
targetSchemaPrefix := SPLIT_PART(targetTable, '.', 1) || '.';
targetTableName := SPLIT_PART(targetTable, '.', 2);
else
targetSchemaPrefix := '';
targetTableName := targetTable;
end if;
if targetSchemaPrefix = '' and targetTableName = 'customer' then
raise exception 'missing targetShemaPrefix: %', targetTable;
end if;
createInsertTriggerSQL = format($sql$
create trigger createRbacObjectFor_%s_Trigger
before insert on %s
create trigger createRbacObjectFor_%s_insert_tg_1058_25
before insert on %s%s
for each row
execute procedure rbac.insert_related_object();
$sql$, targetTable, targetTable);
$sql$, targetTableName, targetSchemaPrefix, targetTableName);
execute createInsertTriggerSQL;
createDeleteTriggerSQL = format($sql$
create trigger delete_related_rbac_rules_for_%s_tg
after delete
on %s
create trigger createRbacObjectFor_%s_delete_tg_1058_35
after delete on %s%s
for each row
execute procedure rbac.delete_related_rbac_rules_tf();
$sql$, targetTable, targetTable);
$sql$, targetTableName, targetSchemaPrefix, targetTableName);
execute createDeleteTriggerSQL;
end; $$;
end;
$$;
--//
@ -176,7 +190,7 @@ begin
*/
sql := format($sql$
create or replace view %1$s_rv as
with accessible_%1$s_uuids as (
with accessible_uuids as (
with recursive
recursive_grants as
(select distinct rbac.grants.descendantuuid,
@ -209,7 +223,7 @@ begin
)
select target.*
from %1$s as target
where target.uuid in (select * from accessible_%1$s_uuids)
where target.uuid in (select * from accessible_uuids)
order by %2$s;
grant all privileges on %1$s_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
@ -219,9 +233,9 @@ begin
/**
Instead of insert trigger function for the restricted view.
*/
newColumns := 'new.' || replace(columnNames, ',', ', new.');
newColumns := 'new.' || replace(columnNames, ', ', ', new.');
sql := format($sql$
create or replace function %1$sInsert()
create function %1$s_instead_of_insert_tf()
returns trigger
language plpgsql as $f$
declare
@ -240,11 +254,11 @@ begin
Creates an instead of insert trigger for the restricted view.
*/
sql := format($sql$
create trigger %1$sInsert_tg
create trigger instead_of_insert_tg
instead of insert
on %1$s_rv
for each row
execute function %1$sInsert();
execute function %1$s_instead_of_insert_tf();
$sql$, targetTable);
execute sql;
@ -252,7 +266,7 @@ begin
Instead of delete trigger function for the restricted view.
*/
sql := format($sql$
create or replace function %1$sDelete()
create function %1$s_instead_of_delete_tf()
returns trigger
language plpgsql as $f$
begin
@ -269,11 +283,11 @@ begin
Creates an instead of delete trigger for the restricted view.
*/
sql := format($sql$
create trigger %1$sDelete_tg
create trigger instead_of_delete_tg
instead of delete
on %1$s_rv
for each row
execute function %1$sDelete();
execute function %1$s_instead_of_delete_tf();
$sql$, targetTable);
execute sql;
@ -283,7 +297,7 @@ begin
*/
if columnUpdates is not null then
sql := format($sql$
create or replace function %1$sUpdate()
create function %1$s_instead_of_update_tf()
returns trigger
language plpgsql as $f$
begin
@ -302,11 +316,11 @@ begin
Creates an instead of delete trigger for the restricted view.
*/
sql = format($sql$
create trigger %1$sUpdate_tg
create trigger instead_of_update_tg
instead of update
on %1$s_rv
for each row
execute function %1$sUpdate();
execute function %1$s_instead_of_update_tf();
$sql$, targetTable);
execute sql;
end if;

View File

@ -158,8 +158,8 @@ do language plpgsql $$
call base.defineContext('creating fake test-realm admin users', null, null, null);
admins = rbac.findRoleId(rbac.globalAdmin());
call rbac.grantRoleToSubjectUnchecked(admins, admins, rbac.create_subject('superuser-alex@hostsharing.net'));
call rbac.grantRoleToSubjectUnchecked(admins, admins, rbac.create_subject('superuser-fran@hostsharing.net'));
call rbac.grantRoleToUserUnchecked(admins, admins, rbac.create_subject('superuser-alex@hostsharing.net'));
call rbac.grantRoleToUserUnchecked(admins, admins, rbac.create_subject('superuser-fran@hostsharing.net'));
perform rbac.create_subject('selfregistered-user-drew@hostsharing.org');
perform rbac.create_subject('selfregistered-test-user@hostsharing.org');
end;

View File

@ -0,0 +1,8 @@
--liquibase formatted sql
-- ============================================================================
--changeset michael.hoennig:rbactest-SCHEMA endDelimiter:--//
-- ----------------------------------------------------------------------------
CREATE SCHEMA rbactest; -- just 'test' does not work, databasechangelog gets emptied or deleted
--//

View File

@ -181,7 +181,7 @@ $$;
/**
Grants hs_office_partner INSERT permission to specified role of new global rows.
*/
create or replace function rbac.new_hsof_partner_grants_insert_to_global_tf()
create or replace function new_hsof_partner_grants_insert_to_global_tf()
returns trigger
language plpgsql
strict as $$
@ -198,11 +198,11 @@ end; $$;
create trigger z_new_hs_office_partner_grants_after_insert_tg
after insert on rbac.global
for each row
execute procedure rbac.new_hsof_partner_grants_insert_to_global_tf();
execute procedure new_hsof_partner_grants_insert_to_global_tf();
-- ============================================================================
--changeset InsertTriggerGenerator:hs_office_partner-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:hs-office-partner-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**

View File

@ -85,7 +85,7 @@ $$;
/**
Grants hs_office_partner_details INSERT permission to specified role of new global rows.
*/
create or replace function rbac.new_hsof_partner_details_grants_insert_to_global_tf()
create or replace function new_hsof_partner_details_grants_insert_to_global_tf()
returns trigger
language plpgsql
strict as $$
@ -102,11 +102,11 @@ end; $$;
create trigger z_new_hs_office_partner_details_grants_after_insert_tg
after insert on rbac.global
for each row
execute procedure rbac.new_hsof_partner_details_grants_insert_to_global_tf();
execute procedure new_hsof_partner_details_grants_insert_to_global_tf();
-- ============================================================================
--changeset InsertTriggerGenerator:hs_office_partner_details-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:hs-office-partner-details-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**

View File

@ -154,7 +154,7 @@ $$;
/**
Grants hs_office_debitor INSERT permission to specified role of new global rows.
*/
create or replace function rbac.new_hsof_debitor_grants_insert_to_global_tf()
create or replace function new_hsof_debitor_grants_insert_to_global_tf()
returns trigger
language plpgsql
strict as $$
@ -171,11 +171,11 @@ end; $$;
create trigger z_new_hs_office_debitor_grants_after_insert_tg
after insert on rbac.global
for each row
execute procedure rbac.new_hsof_debitor_grants_insert_to_global_tf();
execute procedure new_hsof_debitor_grants_insert_to_global_tf();
-- ============================================================================
--changeset InsertTriggerGenerator:hs_office_debitor-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:hs-office-debitor-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**

View File

@ -150,7 +150,7 @@ execute procedure new_hsof_sepamandate_grants_insert_to_hsof_relation_tf();
-- ============================================================================
--changeset InsertTriggerGenerator:hs_office_sepamandate-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:hs-office-sepamandate-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**

View File

@ -116,7 +116,7 @@ $$;
/**
Grants hs_office_membership INSERT permission to specified role of new global rows.
*/
create or replace function rbac.new_hsof_membership_grants_insert_to_global_tf()
create or replace function new_hsof_membership_grants_insert_to_global_tf()
returns trigger
language plpgsql
strict as $$
@ -133,11 +133,11 @@ end; $$;
create trigger z_new_hs_office_membership_grants_after_insert_tg
after insert on rbac.global
for each row
execute procedure rbac.new_hsof_membership_grants_insert_to_global_tf();
execute procedure new_hsof_membership_grants_insert_to_global_tf();
-- ============================================================================
--changeset InsertTriggerGenerator:hs_office_membership-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:hs-office-membership-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**

View File

@ -113,7 +113,7 @@ execute procedure new_hsof_coopsharetx_grants_insert_to_hsof_membership_tf();
-- ============================================================================
--changeset InsertTriggerGenerator:hs_office_coopsharestransaction-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:hs-office-coopsharestransaction-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**

View File

@ -113,7 +113,7 @@ execute procedure new_hsof_coopassettx_grants_insert_to_hsof_membership_tf();
-- ============================================================================
--changeset InsertTriggerGenerator:hs_office_coopassetstransaction-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
--changeset InsertTriggerGenerator:hs-office-coopassetstransaction-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**

View File

@ -0,0 +1,47 @@
--liquibase formatted sql
-- ============================================================================
--changeset michael.hoennig:booking-item-MAIN-TABLE endDelimiter:--//
-- ----------------------------------------------------------------------------
create type HsBookingItemType as enum (
'PRIVATE_CLOUD',
'CLOUD_SERVER',
'MANAGED_SERVER',
'MANAGED_WEBSPACE',
'DOMAIN_SETUP'
);
CREATE CAST (character varying as HsBookingItemType) WITH INOUT AS IMPLICIT;
create table if not exists hs_booking_item
(
uuid uuid unique references rbac.object (uuid),
version int not null default 0,
projectUuid uuid null references hs_booking_project(uuid),
type HsBookingItemType not null,
parentItemUuid uuid null references hs_booking_item(uuid) initially deferred,
validity daterange not null,
caption varchar(80) not null,
resources jsonb not null,
constraint chk_hs_booking_item_has_project_or_parent_asset
check (projectUuid is not null or parentItemUuid is not null)
);
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-MAIN-TABLE-JOURNAL endDelimiter:--//
-- ----------------------------------------------------------------------------
call base.create_journal('hs_booking_item');
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-MAIN-TABLE-HISTORIZATION endDelimiter:--//
-- ----------------------------------------------------------------------------
call base.tx_create_historicization('hs_booking_item');
--//

View File

@ -0,0 +1,63 @@
### rbac bookingItem
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
```mermaid
%%{init:{'flowchart':{'htmlLabels':false}}}%%
flowchart TB
subgraph bookingItem["`**bookingItem**`"]
direction TB
style bookingItem fill:#dd4901,stroke:#274d6e,stroke-width:8px
subgraph bookingItem:roles[ ]
style bookingItem:roles fill:#dd4901,stroke:white
role:bookingItem:OWNER[[bookingItem:OWNER]]
role:bookingItem:ADMIN[[bookingItem:ADMIN]]
role:bookingItem:AGENT[[bookingItem:AGENT]]
role:bookingItem:TENANT[[bookingItem:TENANT]]
end
subgraph bookingItem:permissions[ ]
style bookingItem:permissions fill:#dd4901,stroke:white
perm:bookingItem:INSERT{{bookingItem:INSERT}}
perm:bookingItem:DELETE{{bookingItem:DELETE}}
perm:bookingItem:UPDATE{{bookingItem:UPDATE}}
perm:bookingItem:SELECT{{bookingItem:SELECT}}
end
end
subgraph project["`**project**`"]
direction TB
style project fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph project:roles[ ]
style project:roles fill:#99bcdb,stroke:white
role:project:OWNER[[project:OWNER]]
role:project:ADMIN[[project:ADMIN]]
role:project:AGENT[[project:AGENT]]
role:project:TENANT[[project:TENANT]]
end
end
%% granting roles to roles
role:project:OWNER -.-> role:project:ADMIN
role:project:ADMIN -.-> role:project:AGENT
role:project:AGENT -.-> role:project:TENANT
role:project:AGENT ==> role:bookingItem:OWNER
role:bookingItem:OWNER ==> role:bookingItem:ADMIN
role:bookingItem:ADMIN ==> role:bookingItem:AGENT
role:bookingItem:AGENT ==> role:bookingItem:TENANT
role:bookingItem:TENANT ==> role:project:TENANT
%% granting permissions to roles
role:rbac.global:ADMIN ==> perm:bookingItem:INSERT
role:rbac.global:ADMIN ==> perm:bookingItem:DELETE
role:project:ADMIN ==> perm:bookingItem:INSERT
role:bookingItem:ADMIN ==> perm:bookingItem:UPDATE
role:bookingItem:TENANT ==> perm:bookingItem:SELECT
```

View File

@ -0,0 +1,277 @@
--liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-rbac-OBJECT endDelimiter:--//
-- ----------------------------------------------------------------------------
call rbac.generateRelatedRbacObject('hs_booking_item');
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-rbac-ROLE-DESCRIPTORS endDelimiter:--//
-- ----------------------------------------------------------------------------
call rbac.generateRbacRoleDescriptors('hsBookingItem', 'hs_booking_item');
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-rbac-insert-trigger endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
*/
create or replace procedure buildRbacSystemForHsBookingItem(
NEW hs_booking_item
)
language plpgsql as $$
declare
newProject hs_booking_project;
newParentItem hs_booking_item;
begin
call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_booking_project WHERE uuid = NEW.projectUuid INTO newProject;
SELECT * FROM hs_booking_item WHERE uuid = NEW.parentItemUuid INTO newParentItem;
perform rbac.defineRoleWithGrants(
hsBookingItemOWNER(NEW),
incomingSuperRoles => array[
hsBookingItemAGENT(newParentItem),
hsBookingProjectAGENT(newProject)]
);
perform rbac.defineRoleWithGrants(
hsBookingItemADMIN(NEW),
permissions => array['UPDATE'],
incomingSuperRoles => array[hsBookingItemOWNER(NEW)]
);
perform rbac.defineRoleWithGrants(
hsBookingItemAGENT(NEW),
incomingSuperRoles => array[hsBookingItemADMIN(NEW)]
);
perform rbac.defineRoleWithGrants(
hsBookingItemTENANT(NEW),
permissions => array['SELECT'],
incomingSuperRoles => array[hsBookingItemAGENT(NEW)],
outgoingSubRoles => array[
hsBookingItemTENANT(newParentItem),
hsBookingProjectTENANT(newProject)]
);
call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'DELETE'), rbac.globalAdmin());
call rbac.leaveTriggerForObjectUuid(NEW.uuid);
end; $$;
/*
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_booking_item row.
*/
create or replace function insertTriggerForHsBookingItem_tf()
returns trigger
language plpgsql
strict as $$
begin
call buildRbacSystemForHsBookingItem(NEW);
return NEW;
end; $$;
create trigger insertTriggerForHsBookingItem_tg
after insert on hs_booking_item
for each row
execute procedure insertTriggerForHsBookingItem_tf();
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-rbac-GRANTING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
-- granting INSERT permission to global ----------------------------
/*
Grants INSERT INTO hs_booking_item permissions to specified role of pre-existing global rows.
*/
do language plpgsql $$
declare
row rbac.global%ROWTYPE;
begin
call base.defineContext('create INSERT INTO hs_booking_item permissions for pre-exising rbac.global rows');
FOR row IN SELECT * FROM rbac.global
-- unconditional for all rows in that table
LOOP
call rbac.grantPermissionToRole(
rbac.createPermission(row.uuid, 'INSERT', 'hs_booking_item'),
rbac.globalAdmin());
END LOOP;
end;
$$;
/**
Grants hs_booking_item INSERT permission to specified role of new rbac.global rows.
*/
create or replace function new_hs_booking_item_grants_insert_to_global_tf()
returns trigger
language plpgsql
strict as $$
begin
-- unconditional for all rows in that table
call rbac.grantPermissionToRole(
rbac.createPermission(NEW.uuid, 'INSERT', 'hs_booking_item'),
rbac.globalAdmin());
-- end.
return NEW;
end; $$;
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
create trigger z_new_hs_booking_item_grants_insert_to_global_tg
after insert on rbac.global
for each row
execute procedure new_hs_booking_item_grants_insert_to_global_tf();
-- granting INSERT permission to hs_booking_project ----------------------------
/*
Grants INSERT INTO hs_booking_item permissions to specified role of pre-existing hs_booking_project rows.
*/
do language plpgsql $$
declare
row hs_booking_project;
begin
call base.defineContext('create INSERT INTO hs_booking_item permissions for pre-exising hs_booking_project rows');
FOR row IN SELECT * FROM hs_booking_project
-- unconditional for all rows in that table
LOOP
call rbac.grantPermissionToRole(
rbac.createPermission(row.uuid, 'INSERT', 'hs_booking_item'),
hsBookingProjectADMIN(row));
END LOOP;
end;
$$;
/**
Grants hs_booking_item INSERT permission to specified role of new hs_booking_project rows.
*/
create or replace function new_hs_booking_item_grants_insert_to_hs_booking_project_tf()
returns trigger
language plpgsql
strict as $$
begin
-- unconditional for all rows in that table
call rbac.grantPermissionToRole(
rbac.createPermission(NEW.uuid, 'INSERT', 'hs_booking_item'),
hsBookingProjectADMIN(NEW));
-- end.
return NEW;
end; $$;
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
create trigger z_new_hs_booking_item_grants_insert_to_hs_booking_project_tg
after insert on hs_booking_project
for each row
execute procedure new_hs_booking_item_grants_insert_to_hs_booking_project_tf();
-- granting INSERT permission to hs_booking_item ----------------------------
-- Granting INSERT INTO hs_hosting_asset permissions to specified role of pre-existing hs_hosting_asset rows slipped,
-- because there cannot yet be any pre-existing rows in the same table yet.
/**
Grants hs_booking_item INSERT permission to specified role of new hs_booking_item rows.
*/
create or replace function new_hs_booking_item_grants_insert_to_hs_booking_item_tf()
returns trigger
language plpgsql
strict as $$
begin
-- unconditional for all rows in that table
call rbac.grantPermissionToRole(
rbac.createPermission(NEW.uuid, 'INSERT', 'hs_booking_item'),
hsBookingItemADMIN(NEW));
-- end.
return NEW;
end; $$;
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
create trigger z_new_hs_booking_item_grants_insert_to_hs_booking_item_tg
after insert on hs_booking_item
for each row
execute procedure new_hs_booking_item_grants_insert_to_hs_booking_item_tf();
-- ============================================================================
--changeset michael.hoennig:hs_booking_item-rbac-CHECKING-INSERT-PERMISSION endDelimiter:--//
-- ----------------------------------------------------------------------------
/**
Checks if the user respectively the assumed roles are allowed to insert a row to hs_booking_item.
*/
create or replace function hs_booking_item_insert_permission_check_tf()
returns trigger
language plpgsql as $$
declare
superObjectUuid uuid;
begin
-- check INSERT INSERT if rbac.Global ADMIN
if rbac.isGlobalAdmin() then
return NEW;
end if;
-- check INSERT permission via direct foreign key: NEW.projectUuid
if rbac.hasInsertPermission(NEW.projectUuid, 'hs_booking_item') then
return NEW;
end if;
-- check INSERT permission via direct foreign key: NEW.parentItemUuid
if rbac.hasInsertPermission(NEW.parentItemUuid, 'hs_booking_item') then
return NEW;
end if;
raise exception '[403] insert into hs_booking_item values(%) not allowed for current subjects % (%)',
NEW, base.currentSubjects(), rbac.currentSubjectOrAssumedRolesUuids();
end; $$;
create trigger hs_booking_item_insert_permission_check_tg
before insert on hs_booking_item
for each row
execute procedure hs_booking_item_insert_permission_check_tf();
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-rbac-IDENTITY-VIEW endDelimiter:--//
-- ----------------------------------------------------------------------------
call rbac.generateRbacIdentityViewFromProjection('hs_booking_item',
$idName$
caption
$idName$);
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-rbac-RESTRICTED-VIEW endDelimiter:--//
-- ----------------------------------------------------------------------------
call rbac.generateRbacRestrictedView('hs_booking_item',
$orderBy$
validity
$orderBy$,
$updates$
version = new.version,
caption = new.caption,
validity = new.validity,
resources = new.resources
$updates$);
--//

View File

@ -0,0 +1,57 @@
--liquibase formatted sql
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-TEST-DATA-GENERATOR endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates a single hs_booking_item test record.
*/
create or replace procedure createHsBookingItemTransactionTestData(
givenPartnerNumber numeric,
givenDebitorSuffix char(2)
)
language plpgsql as $$
declare
relatedProject hs_booking_project;
privateCloudUuid uuid;
managedServerUuid uuid;
begin
select project.* into relatedProject
from hs_booking_project project
where project.caption = 'D-' || givenPartnerNumber || givenDebitorSuffix || ' default project';
raise notice 'creating test booking-item: %', givenPartnerNumber::text || givenDebitorSuffix::text;
raise notice '- using project (%): %', relatedProject.uuid, relatedProject;
privateCloudUuid := uuid_generate_v4();
managedServerUuid := uuid_generate_v4();
insert
into hs_booking_item (uuid, projectuuid, type, parentitemuuid, caption, validity, resources)
values (privateCloudUuid, relatedProject.uuid, 'PRIVATE_CLOUD', null, 'some PrivateCloud', daterange('20240401', null, '[]'), '{ "CPU": 10, "RAM": 32, "SSD": 4000, "HDD": 10000, "Traffic": 2000 }'::jsonb),
(uuid_generate_v4(), null, 'MANAGED_SERVER', privateCloudUuid, 'some ManagedServer', daterange('20230115', '20240415', '[)'), '{ "CPU": 2, "RAM": 4, "SSD": 500, "Traffic": 500 }'::jsonb),
(uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'test CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPU": 2, "RAM": 4, "SSD": 750, "Traffic": 500 }'::jsonb),
(uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'prod CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPU": 4, "RAM": 16, "SSD": 1000, "Traffic": 500 }'::jsonb),
(managedServerUuid, relatedProject.uuid, 'MANAGED_SERVER', null, 'separate ManagedServer', daterange('20221001', null, '[]'), '{ "CPU": 2, "RAM": 8, "SSD": 500, "Traffic": 500 }'::jsonb),
(uuid_generate_v4(), null, 'MANAGED_WEBSPACE', managedServerUuid, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 50, "Traffic": 20, "Daemons": 2, "Multi": 4 }'::jsonb),
(uuid_generate_v4(), relatedProject.uuid, 'MANAGED_WEBSPACE', null, 'separate ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 100, "Traffic": 50, "Daemons": 0, "Multi": 1 }'::jsonb);
end; $$;
--//
-- ============================================================================
--changeset michael.hoennig:hs-booking-item-TEST-DATA-GENERATION context=dev,tc endDelimiter:--//
-- ----------------------------------------------------------------------------
do language plpgsql $$
declare
currentTask text;
begin
call base.defineContext('creating booking-item test-data', null, 'superuser-alex@hostsharing.net', 'rbac.global#global:ADMIN');
call createHsBookingItemTransactionTestData(10001, '11');
call createHsBookingItemTransactionTestData(10002, '12');
call createHsBookingItemTransactionTestData(10003, '13');
end;
$$;
--//

View File

@ -21,6 +21,8 @@ databaseChangeLog:
file: db/changelog/0-base/009-check-environment.sql
- include:
file: db/changelog/0-base/010-context.sql
- include:
file: db/changelog/0-base/011-table-schema-and-name.sql
- include:
file: db/changelog/0-base/020-audit-log.sql
- include:
@ -48,23 +50,25 @@ databaseChangeLog:
- include:
file: db/changelog/1-rbac/1080-rbac-global.sql
- include:
file: db/changelog/2-test/201-test-customer/2010-test-customer.sql
file: db/changelog/2-rbactest/200-rbactest-schema.sql
- include:
file: db/changelog/2-test/201-test-customer/2013-test-customer-rbac.sql
file: db/changelog/2-rbactest/201-rbactest-customer/2010-rbactest-customer.sql
- include:
file: db/changelog/2-test/201-test-customer/2018-test-customer-test-data.sql
file: db/changelog/2-rbactest/201-rbactest-customer/2013-rbactest-customer-rbac.sql
- include:
file: db/changelog/2-test/202-test-package/2020-test-package.sql
file: db/changelog/2-rbactest/201-rbactest-customer/2018-rbactest-customer-test-data.sql
- include:
file: db/changelog/2-test/202-test-package/2023-test-package-rbac.sql
file: db/changelog/2-rbactest/202-rbactest-package/2020-rbactest-package.sql
- include:
file: db/changelog/2-test/202-test-package/2028-test-package-test-data.sql
file: db/changelog/2-rbactest/202-rbactest-package/2023-rbactest-package-rbac.sql
- include:
file: db/changelog/2-test/203-test-domain/2030-test-domain.sql
file: db/changelog/2-rbactest/202-rbactest-package/2028-rbactest-package-test-data.sql
- include:
file: db/changelog/2-test/203-test-domain/2033-test-domain-rbac.sql
file: db/changelog/2-rbactest/203-rbactest-domain/2030-rbactest-domain.sql
- include:
file: db/changelog/2-test/203-test-domain/2038-test-domain-test-data.sql
file: db/changelog/2-rbactest/203-rbactest-domain/2033-rbactest-domain-rbac.sql
- include:
file: db/changelog/2-rbactest/203-rbactest-domain/2038-rbactest-domain-test-data.sql
- include:
file: db/changelog/5-hs-office/501-contact/5010-hs-office-contact.sql
- include:
@ -148,7 +152,7 @@ databaseChangeLog:
- include:
file: db/changelog/6-hs-booking/630-booking-item/6300-hs-booking-item.sql
- include:
file: db/changelog/6-hs-booking/630-booking-item/6303-hs-booking-item-rbac.sql
file: db/changelog/6-hs-booking/630-booking-item/6203-hs-booking-item-rbac.sql
- include:
file: db/changelog/6-hs-booking/630-booking-item/6308-hs-booking-item-test-data.sql
- include:

View File

@ -289,9 +289,9 @@ public class CsvDataImport extends ContextBasedTest {
protected void deleteFromTestTables() {
jpaAttempt.transacted(() -> {
context(rbacSuperuser);
em.createNativeQuery("delete from test_domain where true").executeUpdate();
em.createNativeQuery("delete from test_package where true").executeUpdate();
em.createNativeQuery("delete from test_customer where true").executeUpdate();
em.createNativeQuery("delete from rbactest.domain where true").executeUpdate();
em.createNativeQuery("delete from rbactest.package where true").executeUpdate();
em.createNativeQuery("delete from rbactest.customer where true").executeUpdate();
}).assertSuccessful();
}

View File

@ -62,13 +62,13 @@ class ContextIntegrationTests {
void defineWithoutcurrentSubjectButWithAssumedRoles() {
// when
final var result = jpaAttempt.transacted(() ->
context.define(null, "test_package#yyy00:ADMIN")
context.define(null, "rbactest.package#yyy00:ADMIN")
);
// then
result.assertExceptionWithRootCauseMessage(
jakarta.persistence.PersistenceException.class,
"ERROR: [403] undefined has no permission to assume role test_package#yyy00:ADMIN");
"ERROR: [403] undefined has no permission to assume role rbactest.package#yyy00:ADMIN");
}
@Test
@ -88,7 +88,7 @@ class ContextIntegrationTests {
@Transactional
void defineWithcurrentSubjectAndAssumedRoles() {
// given
context.define("superuser-alex@hostsharing.net", "test_customer#xxx:OWNER;test_customer#yyy:OWNER");
context.define("superuser-alex@hostsharing.net", "rbactest.customer#xxx:OWNER;rbactest.customer#yyy:OWNER");
// when
final var currentSubject = context.fetchCurrentSubject();
@ -96,7 +96,7 @@ class ContextIntegrationTests {
// then
assertThat(context.fetchAssumedRoles())
.isEqualTo(Array.of("test_customer#xxx:OWNER", "test_customer#yyy:OWNER"));
.isEqualTo(Array.of("rbactest.customer#xxx:OWNER", "rbactest.customer#yyy:OWNER"));
assertThat(context.fetchCurrentSubjectOrAssumedRolesUuids()).hasSize(2);
}
@ -104,12 +104,12 @@ class ContextIntegrationTests {
public void defineContextWithcurrentSubjectAndAssumeInaccessibleRole() {
// when
final var result = jpaAttempt.transacted(() ->
context.define("customer-admin@xxx.example.com", "test_package#yyy00:ADMIN")
context.define("customer-admin@xxx.example.com", "rbactest.package#yyy00:ADMIN")
);
// then
result.assertExceptionWithRootCauseMessage(
jakarta.persistence.PersistenceException.class,
"ERROR: [403] subject customer-admin@xxx.example.com has no permission to assume role test_package#yyy00:ADMIN");
"ERROR: [403] subject customer-admin@xxx.example.com has no permission to assume role rbactest.package#yyy00:ADMIN");
}
}

View File

@ -71,16 +71,16 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.body("", hasItem(
allOf(
// TODO: should there be a grantedByRole or just a grantedByTrigger?
hasEntry("grantedByRoleIdName", "test_customer#xxx:OWNER"),
hasEntry("grantedRoleIdName", "test_customer#xxx:ADMIN"),
hasEntry("grantedByRoleIdName", "rbactest.customer#xxx:OWNER"),
hasEntry("grantedRoleIdName", "rbactest.customer#xxx:ADMIN"),
hasEntry("granteeSubjectName", "customer-admin@xxx.example.com")
)
))
.body("", hasItem(
allOf(
// TODO: should there be a grantedByRole or just a grantedByTrigger?
hasEntry("grantedByRoleIdName", "test_customer#yyy:OWNER"),
hasEntry("grantedRoleIdName", "test_customer#yyy:ADMIN"),
hasEntry("grantedByRoleIdName", "rbactest.customer#yyy:OWNER"),
hasEntry("grantedRoleIdName", "rbactest.customer#yyy:ADMIN"),
hasEntry("granteeSubjectName", "customer-admin@yyy.example.com")
)
))
@ -93,15 +93,15 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "test_customer#xxx:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#xxx00:ADMIN"),
hasEntry("grantedByRoleIdName", "rbactest.customer#xxx:ADMIN"),
hasEntry("grantedRoleIdName", "rbactest.package#xxx00:ADMIN"),
hasEntry("granteeSubjectName", "pac-admin-xxx00@xxx.example.com")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "test_customer#zzz:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#zzz02:ADMIN"),
hasEntry("grantedByRoleIdName", "rbactest.customer#zzz:ADMIN"),
hasEntry("grantedRoleIdName", "rbactest.package#zzz02:ADMIN"),
hasEntry("granteeSubjectName", "pac-admin-zzz02@zzz.example.com")
)
))
@ -114,7 +114,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
RestAssured // @formatter:off
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_package#yyy00:ADMIN")
.header("assumed-roles", "rbactest.package#yyy00:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/grants")
@ -123,8 +123,8 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "test_customer#yyy:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#yyy00:ADMIN"),
hasEntry("grantedByRoleIdName", "rbactest.customer#yyy:ADMIN"),
hasEntry("grantedRoleIdName", "rbactest.package#yyy00:ADMIN"),
hasEntry("granteeSubjectName", "pac-admin-yyy00@yyy.example.com")
)
))
@ -145,13 +145,13 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "test_customer#yyy:ADMIN"),
hasEntry("grantedRoleIdName", "test_package#yyy00:ADMIN"),
hasEntry("grantedByRoleIdName", "rbactest.customer#yyy:ADMIN"),
hasEntry("grantedRoleIdName", "rbactest.package#yyy00:ADMIN"),
hasEntry("granteeSubjectName", "pac-admin-yyy00@yyy.example.com")
)
))
.body("[0].grantedByRoleIdName", is("test_customer#yyy:ADMIN"))
.body("[0].grantedRoleIdName", is("test_package#yyy00:ADMIN"))
.body("[0].grantedByRoleIdName", is("rbactest.customer#yyy:ADMIN"))
.body("[0].grantedRoleIdName", is("rbactest.package#yyy00:ADMIN"))
.body("[0].granteeSubjectName", is("pac-admin-yyy00@yyy.example.com"));
// @formatter:on
}
@ -165,7 +165,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// given
final var givencurrentSubjectAsPackageAdmin = new Subject("customer-admin@xxx.example.com");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
final var givenGrantedRole = getRbacRoleByName("rbactest.package#xxx00:ADMIN");
// when
final var grant = givencurrentSubjectAsPackageAdmin.getGrantById()
@ -174,8 +174,8 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// then
grant.assertThat()
.statusCode(200)
.body("grantedByRoleIdName", is("test_customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("grantedByRoleIdName", is("rbactest.customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("rbactest.package#xxx00:ADMIN"))
.body("granteeSubjectName", is("pac-admin-xxx00@xxx.example.com"));
}
@ -184,7 +184,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// given
final var givencurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
final var givenGrantedRole = getRbacRoleByName("rbactest.package#xxx00:ADMIN");
// when
final var grant = givencurrentSubjectAsPackageAdmin.getGrantById()
@ -193,8 +193,8 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// then
grant.assertThat()
.statusCode(200)
.body("grantedByRoleIdName", is("test_customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("grantedByRoleIdName", is("rbactest.customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("rbactest.package#xxx00:ADMIN"))
.body("granteeSubjectName", is("pac-admin-xxx00@xxx.example.com"));
}
@ -203,9 +203,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// given
final var givencurrentSubjectAsPackageAdmin = new Subject(
"pac-admin-xxx00@xxx.example.com",
"test_package#xxx00:ADMIN");
"rbactest.package#xxx00:ADMIN");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
final var givenGrantedRole = getRbacRoleByName("rbactest.package#xxx00:ADMIN");
// when
final var grant = givencurrentSubjectAsPackageAdmin.getGrantById()
@ -214,8 +214,8 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// then
grant.assertThat()
.statusCode(200)
.body("grantedByRoleIdName", is("test_customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("grantedByRoleIdName", is("rbactest.customer#xxx:ADMIN"))
.body("grantedRoleIdName", is("rbactest.package#xxx00:ADMIN"))
.body("granteeSubjectName", is("pac-admin-xxx00@xxx.example.com"));
}
@ -225,9 +225,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// given
final var givencurrentSubjectAsPackageAdmin = new Subject(
"pac-admin-xxx00@xxx.example.com",
"test_package#xxx00:TENANT");
"rbactest.package#xxx00:TENANT");
final var givenGranteeUser = findRbacSubjectByName("pac-admin-xxx00@xxx.example.com");
final var givenGrantedRole = getRbacRoleByName("test_package#xxx00:ADMIN");
final var givenGrantedRole = getRbacRoleByName("rbactest.package#xxx00:ADMIN");
final var grant = givencurrentSubjectAsPackageAdmin.getGrantById()
.forGrantedRole(givenGrantedRole).toGranteeUser(givenGranteeUser);
@ -245,7 +245,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// given
final var givenNewUser = createRbacSubject();
final var givenRoleToGrant = "test_package#xxx00:ADMIN";
final var givenRoleToGrant = "rbactest.package#xxx00:ADMIN";
final var givencurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com", givenRoleToGrant);
final var givenOwnPackageAdminRole =
getRbacRoleByName(givencurrentSubjectAsPackageAdmin.assumedRole);
@ -258,9 +258,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// then
response.assertThat()
.statusCode(201)
.body("grantedByRoleIdName", is("test_package#xxx00:ADMIN"))
.body("grantedByRoleIdName", is("rbactest.package#xxx00:ADMIN"))
.body("assumed", is(true))
.body("grantedRoleIdName", is("test_package#xxx00:ADMIN"))
.body("grantedRoleIdName", is("rbactest.package#xxx00:ADMIN"))
.body("granteeSubjectName", is(givenNewUser.getName()));
assertThat(findAllGrantsOf(givencurrentSubjectAsPackageAdmin))
.extracting(RbacGrantEntity::toDisplay)
@ -274,9 +274,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// given
final var givenNewUser = createRbacSubject();
final var givenRoleToGrant = "test_package#xxx00:ADMIN";
final var givenRoleToGrant = "rbactest.package#xxx00:ADMIN";
final var givencurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com", givenRoleToGrant);
final var givenAlienPackageAdminRole = getRbacRoleByName("test_package#yyy00:ADMIN");
final var givenAlienPackageAdminRole = getRbacRoleByName("rbactest.package#yyy00:ADMIN");
// when
final var result = givencurrentSubjectAsPackageAdmin
@ -287,7 +287,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 rbactest.package#xxx00:ADMIN"));
assertThat(findAllGrantsOf(givencurrentSubjectAsPackageAdmin))
.extracting(RbacGrantEntity::getGranteeSubjectName)
.doesNotContain(givenNewUser.getName());
@ -303,9 +303,9 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
// given
final var givenArbitraryUser = createRbacSubject();
final var givenRoleToGrant = "test_package#xxx00:ADMIN";
final var givenRoleToGrant = "rbactest.package#xxx00:ADMIN";
final var givenCurrentSubjectAsPackageAdmin = new Subject("pac-admin-xxx00@xxx.example.com", givenRoleToGrant);
final var givenOwnPackageAdminRole = getRbacRoleByName("test_package#xxx00:ADMIN");
final var givenOwnPackageAdminRole = getRbacRoleByName("rbactest.package#xxx00:ADMIN");
// and given an existing grant
assumeCreated(givenCurrentSubjectAsPackageAdmin

View File

@ -67,7 +67,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
exactlyTheseRbacGrantsAreReturned(
result,
"{ grant role:test_package#xxx00:ADMIN to user:pac-admin-xxx00@xxx.example.com by role:test_customer#xxx:ADMIN and assume }");
"{ grant role:rbactest.package#xxx00:ADMIN to user:pac-admin-xxx00@xxx.example.com by role:rbactest.customer#xxx:ADMIN and assume }");
}
@Test
@ -81,16 +81,16 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
exactlyTheseRbacGrantsAreReturned(
result,
"{ 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 }");
"{ grant role:rbactest.customer#xxx:ADMIN to user:customer-admin@xxx.example.com by role:rbactest.customer#xxx:OWNER and assume }",
"{ grant role:rbactest.package#xxx00:ADMIN to user:pac-admin-xxx00@xxx.example.com by role:rbactest.customer#xxx:ADMIN and assume }",
"{ grant role:rbactest.package#xxx01:ADMIN to user:pac-admin-xxx01@xxx.example.com by role:rbactest.customer#xxx:ADMIN and assume }",
"{ grant role:rbactest.package#xxx02:ADMIN to user:pac-admin-xxx02@xxx.example.com by role:rbactest.customer#xxx:ADMIN and assume }");
}
@Test
public void customerAdmin_withAssumedRole_canOnlyViewRbacGrantsVisibleByAssumedRole() {
// given:
context("customer-admin@xxx.example.com", "test_package#xxx00:ADMIN");
context("customer-admin@xxx.example.com", "rbactest.package#xxx00:ADMIN");
// when
final var result = rbacGrantRepository.findAll();
@ -98,7 +98,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
exactlyTheseRbacGrantsAreReturned(
result,
"{ grant role:test_package#xxx00:ADMIN to user:pac-admin-xxx00@xxx.example.com by role:test_customer#xxx:ADMIN and assume }");
"{ grant role:rbactest.package#xxx00:ADMIN to user:pac-admin-xxx00@xxx.example.com by role:rbactest.customer#xxx:ADMIN and assume }");
}
}
@ -108,9 +108,9 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void customerAdmin_canGrantOwnPackageAdminRole_toArbitraryUser() {
// given
context("customer-admin@xxx.example.com", "test_customer#xxx:ADMIN");
context("customer-admin@xxx.example.com", "rbactest.customer#xxx:ADMIN");
final var givenArbitrarySubjectUuid = rbacSubjectRepository.findByName("pac-admin-zzz00@zzz.example.com").getUuid();
final var givenOwnPackageRoleUuid = rbacRoleRepository.findByRoleName("test_package#xxx00:ADMIN").getUuid();
final var givenOwnPackageRoleUuid = rbacRoleRepository.findByRoleName("rbactest.package#xxx00:ADMIN").getUuid();
// when
final var grant = RbacGrantEntity.builder()
@ -126,7 +126,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
assertThat(rbacGrantRepository.findAll())
.extracting(RbacGrantEntity::toDisplay)
.contains(
"{ grant role:test_package#xxx00:ADMIN to user:pac-admin-zzz00@zzz.example.com by role:test_customer#xxx:ADMIN and assume }");
"{ grant role:rbactest.package#xxx00:ADMIN to user:pac-admin-zzz00@zzz.example.com by role:rbactest.customer#xxx:ADMIN and assume }");
}
@Test
@ -139,14 +139,14 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
context("customer-admin@xxx.example.com", null);
return new Given(
createNewUser(),
rbacRoleRepository.findByRoleName("test_package#xxx00:OWNER").getUuid()
rbacRoleRepository.findByRoleName("rbactest.package#xxx00:OWNER").getUuid()
);
}).assumeSuccessful().returnedValue();
// when
final var attempt = jpaAttempt.transacted(() -> {
// now we try to use these uuids as a less privileged user
context("pac-admin-xxx00@xxx.example.com", "test_package#xxx00:ADMIN");
context("pac-admin-xxx00@xxx.example.com", "rbactest.package#xxx00:ADMIN");
final var grant = RbacGrantEntity.builder()
.granteeSubjectUuid(given.arbitraryUser.getUuid())
.grantedRoleUuid(given.packageOwnerRoleUuid)
@ -158,8 +158,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
attempt.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"ERROR: [403] Access to granted role test_package#xxx00:OWNER",
"forbidden for test_package#xxx00:ADMIN");
"ERROR: [403] Access to granted role rbactest.package#xxx00:OWNER",
"forbidden for rbactest.package#xxx00:ADMIN");
jpaAttempt.transacted(() -> {
// finally, we use the new user to make sure, no roles were granted
context(given.arbitraryUser.getName(), null);
@ -176,16 +176,16 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
public void customerAdmin_canRevokeSelfGrantedPackageAdminRole() {
// given
final var grant = create(grant()
.byUser("customer-admin@xxx.example.com").withAssumedRole("test_customer#xxx:ADMIN")
.grantingRole("test_package#xxx00:ADMIN").toUser("pac-admin-zzz00@zzz.example.com"));
.byUser("customer-admin@xxx.example.com").withAssumedRole("rbactest.customer#xxx:ADMIN")
.grantingRole("rbactest.package#xxx00:ADMIN").toUser("pac-admin-zzz00@zzz.example.com"));
// when
context("customer-admin@xxx.example.com", "test_customer#xxx:ADMIN");
context("customer-admin@xxx.example.com", "rbactest.customer#xxx:ADMIN");
final var revokeAttempt = attempt(em, () ->
rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()));
// then
context("customer-admin@xxx.example.com", "test_customer#xxx:ADMIN");
context("customer-admin@xxx.example.com", "rbactest.customer#xxx:ADMIN");
assertThat(revokeAttempt.caughtExceptionsRootCause()).isNull();
assertThat(rbacGrantRepository.findAll())
.extracting(RbacGrantEntity::getGranteeSubjectName)
@ -197,17 +197,17 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// given
final var newUser = createNewUserTransacted();
final var grant = create(grant()
.byUser("customer-admin@xxx.example.com").withAssumedRole("test_package#xxx00:ADMIN")
.grantingRole("test_package#xxx00:ADMIN").toUser(newUser.getName()));
.byUser("customer-admin@xxx.example.com").withAssumedRole("rbactest.package#xxx00:ADMIN")
.grantingRole("rbactest.package#xxx00:ADMIN").toUser(newUser.getName()));
// when
context("pac-admin-xxx00@xxx.example.com", "test_package#xxx00:ADMIN");
context("pac-admin-xxx00@xxx.example.com", "rbactest.package#xxx00:ADMIN");
final var revokeAttempt = attempt(em, () ->
rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()));
// then
assertThat(revokeAttempt.caughtExceptionsRootCause()).isNull();
context("customer-admin@xxx.example.com", "test_customer#xxx:ADMIN");
context("customer-admin@xxx.example.com", "rbactest.customer#xxx:ADMIN");
assertThat(rbacGrantRepository.findAll())
.extracting(RbacGrantEntity::getGranteeSubjectName)
.doesNotContain("pac-admin-zzz00@zzz.example.com");
@ -217,19 +217,19 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
public void packageAdmin_canNotRevokeOwnPackageAdminRoleGrantedByOwnerRoleOfThatPackage() {
// given
final var grant = create(grant()
.byUser("customer-admin@xxx.example.com").withAssumedRole("test_package#xxx00:OWNER")
.grantingRole("test_package#xxx00:ADMIN").toUser("pac-admin-zzz00@zzz.example.com"));
final var grantedByRole = rbacRoleRepository.findByRoleName("test_package#xxx00:OWNER");
.byUser("customer-admin@xxx.example.com").withAssumedRole("rbactest.package#xxx00:OWNER")
.grantingRole("rbactest.package#xxx00:ADMIN").toUser("pac-admin-zzz00@zzz.example.com"));
final var grantedByRole = rbacRoleRepository.findByRoleName("rbactest.package#xxx00:OWNER");
// when
context("pac-admin-xxx00@xxx.example.com", "test_package#xxx00:ADMIN");
context("pac-admin-xxx00@xxx.example.com", "rbactest.package#xxx00:ADMIN");
final var revokeAttempt = attempt(em, () ->
rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()));
// then
revokeAttempt.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"ERROR: [403] Revoking role created by %s is forbidden for {test_package#xxx00:ADMIN}.".formatted(
"ERROR: [403] Revoking role created by %s is forbidden for {rbactest.package#xxx00:ADMIN}.".formatted(
grantedByRole.getUuid()
));
}

View File

@ -54,36 +54,36 @@ class RbacGrantsDiagramServiceIntegrationTest extends ContextBasedTestWithCleanu
@Test
void allGrantsTocurrentSubject() {
context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa:OWNER");
context("superuser-alex@hostsharing.net", "rbactest.domain#xxx00-aaaa:OWNER");
final var graph = grantsMermaidService.allGrantsTocurrentSubject(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
role:rbactest.domain#xxx00-aaaa:ADMIN --> role:rbactest.package#xxx00:TENANT
role:rbactest.domain#xxx00-aaaa:OWNER --> role:rbactest.domain#xxx00-aaaa:ADMIN
role:rbactest.domain#xxx00-aaaa:OWNER --> role:rbactest.package#xxx00:TENANT
role:rbactest.package#xxx00:TENANT --> role:rbactest.customer#xxx:TENANT
""".trim());
}
@Test
void allGrantsTocurrentSubjectIncludingPermissions() {
context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa:OWNER");
context("superuser-alex@hostsharing.net", "rbactest.domain#xxx00-aaaa:OWNER");
final var graph = grantsMermaidService.allGrantsTocurrentSubject(EnumSet.of(Include.TEST_ENTITIES, Include.PERMISSIONS));
assertThat(graph).isEqualTo("""
flowchart TB
role:test_customer#xxx:TENANT --> perm:test_customer#xxx:SELECT
role:test_domain#xxx00-aaaa:ADMIN --> perm:test_domain#xxx00-aaaa:SELECT
role:test_domain#xxx00-aaaa:ADMIN --> role:test_package#xxx00:TENANT
role:test_domain#xxx00-aaaa:OWNER --> perm:test_domain#xxx00-aaaa:DELETE
role:test_domain#xxx00-aaaa:OWNER --> perm:test_domain#xxx00-aaaa:UPDATE
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:test_package#xxx00:SELECT
role:test_package#xxx00:TENANT --> role:test_customer#xxx:TENANT
role:rbactest.customer#xxx:TENANT --> perm:rbactest.customer#xxx:SELECT
role:rbactest.domain#xxx00-aaaa:ADMIN --> perm:rbactest.domain#xxx00-aaaa:SELECT
role:rbactest.domain#xxx00-aaaa:ADMIN --> role:rbactest.package#xxx00:TENANT
role:rbactest.domain#xxx00-aaaa:OWNER --> perm:rbactest.domain#xxx00-aaaa:DELETE
role:rbactest.domain#xxx00-aaaa:OWNER --> perm:rbactest.domain#xxx00-aaaa:UPDATE
role:rbactest.domain#xxx00-aaaa:OWNER --> role:rbactest.domain#xxx00-aaaa:ADMIN
role:rbactest.domain#xxx00-aaaa:OWNER --> role:rbactest.package#xxx00:TENANT
role:rbactest.package#xxx00:TENANT --> perm:rbactest.package#xxx00:SELECT
role:rbactest.package#xxx00:TENANT --> role:rbactest.customer#xxx:TENANT
""".trim());
}

View File

@ -42,14 +42,14 @@ class RbacRoleControllerAcceptanceTest {
.then().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", hasItem(hasEntry("roleName", "test_customer#xxx:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_customer#xxx:OWNER")))
.body("", hasItem(hasEntry("roleName", "test_customer#xxx:TENANT")))
.body("", hasItem(hasEntry("roleName", "rbactest.customer#xxx:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.customer#xxx:OWNER")))
.body("", hasItem(hasEntry("roleName", "rbactest.customer#xxx:TENANT")))
// ...
.body("", hasItem(hasEntry("roleName", "rbac.global#global:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_customer#yyy:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_package#yyy00:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_domain#yyy00-aaaa:OWNER")))
.body("", hasItem(hasEntry("roleName", "rbactest.customer#yyy:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.package#yyy00:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.domain#yyy00-aaaa:OWNER")))
.body( "size()", greaterThanOrEqualTo(73)); // increases with new test data
// @formatter:on
}
@ -61,7 +61,7 @@ class RbacRoleControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_package#yyy00:ADMIN")
.header("assumed-roles", "rbactest.package#yyy00:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/roles")
@ -71,18 +71,18 @@ class RbacRoleControllerAcceptanceTest {
.statusCode(200)
.contentType("application/json")
.body("", hasItem(hasEntry("roleName", "test_customer#yyy:TENANT")))
.body("", hasItem(hasEntry("roleName", "test_domain#yyy00-aaaa:OWNER")))
.body("", hasItem(hasEntry("roleName", "test_domain#yyy00-aaaa:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_domain#yyy00-aaab:OWNER")))
.body("", hasItem(hasEntry("roleName", "test_domain#yyy00-aaab:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_package#yyy00:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_package#yyy00:TENANT")))
.body("", hasItem(hasEntry("roleName", "rbactest.customer#yyy:TENANT")))
.body("", hasItem(hasEntry("roleName", "rbactest.domain#yyy00-aaaa:OWNER")))
.body("", hasItem(hasEntry("roleName", "rbactest.domain#yyy00-aaaa:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.domain#yyy00-aaab:OWNER")))
.body("", hasItem(hasEntry("roleName", "rbactest.domain#yyy00-aaab:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.package#yyy00:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.package#yyy00:TENANT")))
.body("", not(hasItem(hasEntry("roleName", "test_customer#xxx:TENANT"))))
.body("", not(hasItem(hasEntry("roleName", "test_domain#xxx00-aaaa:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "test_package#xxx00:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "test_package#xxx00:TENANT"))))
.body("", not(hasItem(hasEntry("roleName", "rbactest.customer#xxx:TENANT"))))
.body("", not(hasItem(hasEntry("roleName", "rbactest.domain#xxx00-aaaa:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "rbactest.package#xxx00:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "rbactest.package#xxx00:TENANT"))))
;
// @formatter:on
}
@ -101,15 +101,15 @@ class RbacRoleControllerAcceptanceTest {
.statusCode(200)
.contentType("application/json")
.body("", hasItem(hasEntry("roleName", "test_customer#zzz:TENANT")))
.body("", hasItem(hasEntry("roleName", "test_domain#zzz00-aaaa:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_package#zzz00:ADMIN")))
.body("", hasItem(hasEntry("roleName", "test_package#zzz00:TENANT")))
.body("", hasItem(hasEntry("roleName", "rbactest.customer#zzz:TENANT")))
.body("", hasItem(hasEntry("roleName", "rbactest.domain#zzz00-aaaa:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.package#zzz00:ADMIN")))
.body("", hasItem(hasEntry("roleName", "rbactest.package#zzz00:TENANT")))
.body("", not(hasItem(hasEntry("roleName", "test_customer#yyy:TENANT"))))
.body("", not(hasItem(hasEntry("roleName", "test_domain#yyy00-aaaa:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "test_package#yyy00:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "test_package#yyy00:TENANT"))));
.body("", not(hasItem(hasEntry("roleName", "rbactest.customer#yyy:TENANT"))))
.body("", not(hasItem(hasEntry("roleName", "rbactest.domain#yyy00-aaaa:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "rbactest.package#yyy00:ADMIN"))))
.body("", not(hasItem(hasEntry("roleName", "rbactest.package#yyy00:TENANT"))));
// @formatter:on
}
}

View File

@ -74,8 +74,8 @@ class RbacRoleControllerRestTest {
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$[0].roleName", is("rbac.global#global:ADMIN")))
.andExpect(jsonPath("$[1].roleName", is("test_customer#xxx:OWNER")))
.andExpect(jsonPath("$[2].roleName", is("test_customer#xxx:ADMIN")))
.andExpect(jsonPath("$[1].roleName", is("rbactest.customer#xxx:OWNER")))
.andExpect(jsonPath("$[2].roleName", is("rbactest.customer#xxx:ADMIN")))
.andExpect(jsonPath("$[2].uuid", is(customerXxxAdmin.getUuid().toString())))
.andExpect(jsonPath("$[2].objectUuid", is(customerXxxAdmin.getObjectUuid().toString())))
.andExpect(jsonPath("$[2].objectTable", is(customerXxxAdmin.getObjectTable().toString())))

View File

@ -40,18 +40,18 @@ class RbacRoleRepositoryIntegrationTest {
private static final String[] ALL_TEST_DATA_ROLES = Array.of(
// @formatter:off
"rbac.global#global:ADMIN",
"test_customer#xxx:ADMIN", "test_customer#xxx:OWNER", "test_customer#xxx:TENANT",
"test_package#xxx00:ADMIN", "test_package#xxx00:OWNER", "test_package#xxx00:TENANT",
"test_package#xxx01:ADMIN", "test_package#xxx01:OWNER", "test_package#xxx01:TENANT",
"test_package#xxx02:ADMIN", "test_package#xxx02:OWNER", "test_package#xxx02:TENANT",
"test_customer#yyy:ADMIN", "test_customer#yyy:OWNER", "test_customer#yyy:TENANT",
"test_package#yyy00:ADMIN", "test_package#yyy00:OWNER", "test_package#yyy00:TENANT",
"test_package#yyy01:ADMIN", "test_package#yyy01:OWNER", "test_package#yyy01:TENANT",
"test_package#yyy02:ADMIN", "test_package#yyy02:OWNER", "test_package#yyy02:TENANT",
"test_customer#zzz:ADMIN", "test_customer#zzz:OWNER", "test_customer#zzz:TENANT",
"test_package#zzz00:ADMIN", "test_package#zzz00:OWNER", "test_package#zzz00:TENANT",
"test_package#zzz01:ADMIN", "test_package#zzz01:OWNER", "test_package#zzz01:TENANT",
"test_package#zzz02:ADMIN", "test_package#zzz02:OWNER", "test_package#zzz02:TENANT"
"rbactest.customer#xxx:ADMIN", "rbactest.customer#xxx:OWNER", "rbactest.customer#xxx:TENANT",
"rbactest.package#xxx00:ADMIN", "rbactest.package#xxx00:OWNER", "rbactest.package#xxx00:TENANT",
"rbactest.package#xxx01:ADMIN", "rbactest.package#xxx01:OWNER", "rbactest.package#xxx01:TENANT",
"rbactest.package#xxx02:ADMIN", "rbactest.package#xxx02:OWNER", "rbactest.package#xxx02:TENANT",
"rbactest.customer#yyy:ADMIN", "rbactest.customer#yyy:OWNER", "rbactest.customer#yyy:TENANT",
"rbactest.package#yyy00:ADMIN", "rbactest.package#yyy00:OWNER", "rbactest.package#yyy00:TENANT",
"rbactest.package#yyy01:ADMIN", "rbactest.package#yyy01:OWNER", "rbactest.package#yyy01:TENANT",
"rbactest.package#yyy02:ADMIN", "rbactest.package#yyy02:OWNER", "rbactest.package#yyy02:TENANT",
"rbactest.customer#zzz:ADMIN", "rbactest.customer#zzz:OWNER", "rbactest.customer#zzz:TENANT",
"rbactest.package#zzz00:ADMIN", "rbactest.package#zzz00:OWNER", "rbactest.package#zzz00:TENANT",
"rbactest.package#zzz01:ADMIN", "rbactest.package#zzz01:OWNER", "rbactest.package#zzz01:TENANT",
"rbactest.package#zzz02:ADMIN", "rbactest.package#zzz02:OWNER", "rbactest.package#zzz02:TENANT"
// @formatter:on
);
@ -91,49 +91,49 @@ class RbacRoleRepositoryIntegrationTest {
allTheseRbacRolesAreReturned(
result,
// @formatter:off
"test_customer#xxx:ADMIN",
"test_customer#xxx:TENANT",
"test_package#xxx00:ADMIN",
"test_package#xxx00:OWNER",
"test_package#xxx00:TENANT",
"test_package#xxx01:ADMIN",
"test_package#xxx01:OWNER",
"test_package#xxx01:TENANT",
"rbactest.customer#xxx:ADMIN",
"rbactest.customer#xxx:TENANT",
"rbactest.package#xxx00:ADMIN",
"rbactest.package#xxx00:OWNER",
"rbactest.package#xxx00:TENANT",
"rbactest.package#xxx01:ADMIN",
"rbactest.package#xxx01:OWNER",
"rbactest.package#xxx01:TENANT",
// ...
"test_domain#xxx00-aaaa:ADMIN",
"test_domain#xxx00-aaaa:OWNER",
"rbactest.domain#xxx00-aaaa:ADMIN",
"rbactest.domain#xxx00-aaaa:OWNER",
// ..
"test_domain#xxx01-aaab:ADMIN",
"test_domain#xxx01-aaab:OWNER"
"rbactest.domain#xxx01-aaab:ADMIN",
"rbactest.domain#xxx01-aaab:OWNER"
// @formatter:on
);
noneOfTheseRbacRolesIsReturned(
result,
// @formatter:off
"rbac.global#global:ADMIN",
"test_customer#xxx:OWNER",
"test_package#yyy00:ADMIN",
"test_package#yyy00:OWNER",
"test_package#yyy00:TENANT"
"rbactest.customer#xxx:OWNER",
"rbactest.package#yyy00:ADMIN",
"rbactest.package#yyy00:OWNER",
"rbactest.package#yyy00:TENANT"
// @formatter:on
);
}
@Test
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnRbacRole() {
context.define("customer-admin@xxx.example.com", "test_package#xxx00:ADMIN");
context.define("customer-admin@xxx.example.com", "rbactest.package#xxx00:ADMIN");
final var result = rbacRoleRepository.findAll();
exactlyTheseRbacRolesAreReturned(
result,
"test_customer#xxx:TENANT",
"test_package#xxx00:ADMIN",
"test_package#xxx00:TENANT",
"test_domain#xxx00-aaaa:ADMIN",
"test_domain#xxx00-aaaa:OWNER",
"test_domain#xxx00-aaab:ADMIN",
"test_domain#xxx00-aaab:OWNER");
"rbactest.customer#xxx:TENANT",
"rbactest.package#xxx00:ADMIN",
"rbactest.package#xxx00:TENANT",
"rbactest.domain#xxx00-aaaa:ADMIN",
"rbactest.domain#xxx00-aaaa:OWNER",
"rbactest.domain#xxx00-aaab:ADMIN",
"rbactest.domain#xxx00-aaab:OWNER");
}
@Test
@ -157,10 +157,10 @@ class RbacRoleRepositoryIntegrationTest {
void customerAdmin_withoutAssumedRole_canFindItsOwnRolesByName() {
context.define("customer-admin@xxx.example.com");
final var result = rbacRoleRepository.findByRoleName("test_customer#xxx:ADMIN");
final var result = rbacRoleRepository.findByRoleName("rbactest.customer#xxx:ADMIN");
assertThat(result).isNotNull();
assertThat(result.getObjectTable()).isEqualTo("test_customer");
assertThat(result.getObjectTable()).isEqualTo("rbactest.customer");
assertThat(result.getObjectIdName()).isEqualTo("xxx");
assertThat(result.getRoleType()).isEqualTo(RbacRoleType.ADMIN);
}
@ -169,7 +169,7 @@ class RbacRoleRepositoryIntegrationTest {
void customerAdmin_withoutAssumedRole_canNotFindAlienRolesByName() {
context.define("customer-admin@xxx.example.com");
final var result = rbacRoleRepository.findByRoleName("test_customer#bbb:ADMIN");
final var result = rbacRoleRepository.findByRoleName("rbactest.customer#bbb:ADMIN");
assertThat(result).isNull();
}

View File

@ -5,8 +5,8 @@ import static java.util.UUID.randomUUID;
public class TestRbacRole {
public static final RbacRoleEntity hostmasterRole = rbacRole("rbac.global", "global", RbacRoleType.ADMIN);
static final RbacRoleEntity customerXxxOwner = rbacRole("test_customer", "xxx", RbacRoleType.OWNER);
static final RbacRoleEntity customerXxxAdmin = rbacRole("test_customer", "xxx", RbacRoleType.ADMIN);
static final RbacRoleEntity customerXxxOwner = rbacRole("rbactest.customer", "xxx", RbacRoleType.OWNER);
static final RbacRoleEntity customerXxxAdmin = rbacRole("rbactest.customer", "xxx", RbacRoleType.ADMIN);
static public RbacRoleEntity rbacRole(final String objectTable, final String objectIdName, final RbacRoleType roleType) {
return new RbacRoleEntity(randomUUID(), randomUUID(), objectTable, objectIdName, roleType, objectTable+'#'+objectIdName+':'+roleType);

View File

@ -100,7 +100,7 @@ class RbacSubjectControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#yyy:ADMIN")
.header("assumed-roles", "rbactest.customer#yyy:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid())
@ -201,7 +201,7 @@ class RbacSubjectControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#yyy:ADMIN")
.header("assumed-roles", "rbactest.customer#yyy:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/subjects")
@ -275,12 +275,12 @@ class RbacSubjectControllerAcceptanceTest {
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy:TENANT"),
hasEntry("roleName", "rbactest.customer#yyy:TENANT"),
hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa:OWNER"),
hasEntry("roleName", "rbactest.domain#yyy00-aaaa:OWNER"),
hasEntry("op", "DELETE"))
))
// actual content tested in integration test, so this is enough for here:
@ -296,7 +296,7 @@ class RbacSubjectControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#yyy:ADMIN")
.header("assumed-roles", "rbactest.customer#yyy:ADMIN")
.port(port)
.when()
.get("http://localhost/api/rbac/subjects/" + givenUser.getUuid() + "/permissions")
@ -305,12 +305,12 @@ class RbacSubjectControllerAcceptanceTest {
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy:TENANT"),
hasEntry("roleName", "rbactest.customer#yyy:TENANT"),
hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa:OWNER"),
hasEntry("roleName", "rbactest.domain#yyy00-aaaa:OWNER"),
hasEntry("op", "DELETE"))
))
// actual content tested in integration test, so this is enough for here:
@ -334,12 +334,12 @@ class RbacSubjectControllerAcceptanceTest {
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy:TENANT"),
hasEntry("roleName", "rbactest.customer#yyy:TENANT"),
hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa:OWNER"),
hasEntry("roleName", "rbactest.domain#yyy00-aaaa:OWNER"),
hasEntry("op", "DELETE"))
))
// actual content tested in integration test, so this is enough for here:

View File

@ -128,7 +128,7 @@ class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void globalAdmin_withAssumedCustomerAdminRole_canViewOnlyUsersHavingRolesInThatCustomersRealm() {
given:
context("superuser-alex@hostsharing.net", "test_customer#xxx:ADMIN");
context("superuser-alex@hostsharing.net", "rbactest.customer#xxx:ADMIN");
// when
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
@ -159,7 +159,7 @@ class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyUsersHavingRolesInThatPackage() {
context("customer-admin@xxx.example.com", "test_package#xxx00:ADMIN");
context("customer-admin@xxx.example.com", "rbactest.package#xxx00:ADMIN");
final var result = rbacSubjectRepository.findByOptionalNameLike(null);
@ -182,47 +182,47 @@ class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
private static final String[] ALL_USER_PERMISSIONS = Array.of(
// @formatter:off
"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",
"rbactest.customer#xxx:ADMIN -> rbactest.customer#xxx: SELECT",
"rbactest.customer#xxx:OWNER -> rbactest.customer#xxx: DELETE",
"rbactest.customer#xxx:TENANT -> rbactest.customer#xxx: SELECT",
"rbactest.customer#xxx:ADMIN -> rbactest.customer#xxx: INSERT:rbactest.package",
"rbactest.package#xxx00:ADMIN -> rbactest.package#xxx00: INSERT:rbactest.domain",
"rbactest.package#xxx00:ADMIN -> rbactest.package#xxx00: INSERT:rbactest.domain",
"rbactest.package#xxx00:TENANT -> rbactest.package#xxx00: SELECT",
"rbactest.package#xxx01:ADMIN -> rbactest.package#xxx01: INSERT:rbactest.domain",
"rbactest.package#xxx01:ADMIN -> rbactest.package#xxx01: INSERT:rbactest.domain",
"rbactest.package#xxx01:TENANT -> rbactest.package#xxx01: SELECT",
"rbactest.package#xxx02:ADMIN -> rbactest.package#xxx02: INSERT:rbactest.domain",
"rbactest.package#xxx02:ADMIN -> rbactest.package#xxx02: INSERT:rbactest.domain",
"rbactest.package#xxx02:TENANT -> rbactest.package#xxx02: SELECT",
"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",
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: SELECT",
"rbactest.customer#yyy:OWNER -> rbactest.customer#yyy: DELETE",
"rbactest.customer#yyy:TENANT -> rbactest.customer#yyy: SELECT",
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: INSERT:rbactest.package",
"rbactest.package#yyy00:ADMIN -> rbactest.package#yyy00: INSERT:rbactest.domain",
"rbactest.package#yyy00:ADMIN -> rbactest.package#yyy00: INSERT:rbactest.domain",
"rbactest.package#yyy00:TENANT -> rbactest.package#yyy00: SELECT",
"rbactest.package#yyy01:ADMIN -> rbactest.package#yyy01: INSERT:rbactest.domain",
"rbactest.package#yyy01:ADMIN -> rbactest.package#yyy01: INSERT:rbactest.domain",
"rbactest.package#yyy01:TENANT -> rbactest.package#yyy01: SELECT",
"rbactest.package#yyy02:ADMIN -> rbactest.package#yyy02: INSERT:rbactest.domain",
"rbactest.package#yyy02:ADMIN -> rbactest.package#yyy02: INSERT:rbactest.domain",
"rbactest.package#yyy02:TENANT -> rbactest.package#yyy02: SELECT",
"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"
"rbactest.customer#zzz:ADMIN -> rbactest.customer#zzz: SELECT",
"rbactest.customer#zzz:OWNER -> rbactest.customer#zzz: DELETE",
"rbactest.customer#zzz:TENANT -> rbactest.customer#zzz: SELECT",
"rbactest.customer#zzz:ADMIN -> rbactest.customer#zzz: INSERT:rbactest.package",
"rbactest.package#zzz00:ADMIN -> rbactest.package#zzz00: INSERT:rbactest.domain",
"rbactest.package#zzz00:ADMIN -> rbactest.package#zzz00: INSERT:rbactest.domain",
"rbactest.package#zzz00:TENANT -> rbactest.package#zzz00: SELECT",
"rbactest.package#zzz01:ADMIN -> rbactest.package#zzz01: INSERT:rbactest.domain",
"rbactest.package#zzz01:ADMIN -> rbactest.package#zzz01: INSERT:rbactest.domain",
"rbactest.package#zzz01:TENANT -> rbactest.package#zzz01: SELECT",
"rbactest.package#zzz02:ADMIN -> rbactest.package#zzz02: INSERT:rbactest.domain",
"rbactest.package#zzz02:ADMIN -> rbactest.package#zzz02: INSERT:rbactest.domain",
"rbactest.package#zzz02:TENANT -> rbactest.package#zzz02: SELECT"
// @formatter:on
);
@ -233,7 +233,7 @@ class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = rbacSubjectRepository.findPermissionsOfUserByUuid(subjectUuid("superuser-fran@hostsharing.net"))
.stream().filter(p -> p.getObjectTable().contains("test_"))
.stream().filter(p -> p.getObjectTable().contains("rbactest."))
.sorted(comparing(RbacSubjectPermission::toString)).toList();
// then
@ -252,32 +252,32 @@ class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"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",
"rbactest.customer#xxx:ADMIN -> rbactest.customer#xxx: INSERT:rbactest.package",
"rbactest.customer#xxx:ADMIN -> rbactest.customer#xxx: SELECT",
"rbactest.customer#xxx:TENANT -> rbactest.customer#xxx: SELECT",
"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",
"rbactest.package#xxx00:ADMIN -> rbactest.package#xxx00: INSERT:rbactest.domain",
"rbactest.package#xxx00:ADMIN -> rbactest.package#xxx00: INSERT:rbactest.domain",
"rbactest.package#xxx00:TENANT -> rbactest.package#xxx00: SELECT",
"rbactest.domain#xxx00-aaaa:OWNER -> rbactest.domain#xxx00-aaaa: DELETE",
"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",
"rbactest.package#xxx01:ADMIN -> rbactest.package#xxx01: INSERT:rbactest.domain",
"rbactest.package#xxx01:ADMIN -> rbactest.package#xxx01: INSERT:rbactest.domain",
"rbactest.package#xxx01:TENANT -> rbactest.package#xxx01: SELECT",
"rbactest.domain#xxx01-aaaa:OWNER -> rbactest.domain#xxx01-aaaa: DELETE",
"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"
"rbactest.package#xxx02:ADMIN -> rbactest.package#xxx02: INSERT:rbactest.domain",
"rbactest.package#xxx02:ADMIN -> rbactest.package#xxx02: INSERT:rbactest.domain",
"rbactest.package#xxx02:TENANT -> rbactest.package#xxx02: SELECT",
"rbactest.domain#xxx02-aaaa:OWNER -> rbactest.domain#xxx02-aaaa: DELETE"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"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"
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: INSERT:rbactest.package",
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: SELECT",
"rbactest.customer#yyy:TENANT -> rbactest.customer#yyy: SELECT"
// @formatter:on
);
}
@ -312,26 +312,26 @@ class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"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: 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"
"rbactest.customer#xxx:TENANT -> rbactest.customer#xxx: SELECT",
// "rbactest.customer#xxx:ADMIN -> rbactest.customer#xxx: view" - Not permissions through the customer admin!
"rbactest.package#xxx00:ADMIN -> rbactest.package#xxx00: INSERT:rbactest.domain",
"rbactest.package#xxx00:ADMIN -> rbactest.package#xxx00: INSERT:rbactest.domain",
"rbactest.package#xxx00:TENANT -> rbactest.package#xxx00: SELECT",
"rbactest.domain#xxx00-aaaa:OWNER -> rbactest.domain#xxx00-aaaa: DELETE",
"rbactest.domain#xxx00-aaab:OWNER -> rbactest.domain#xxx00-aaab: DELETE"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"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"
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: INSERT:rbactest.package",
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: SELECT",
"rbactest.customer#yyy:TENANT -> rbactest.customer#yyy: SELECT",
"rbactest.package#yyy00:ADMIN -> rbactest.package#yyy00: INSERT:rbactest.domain",
"rbactest.package#yyy00:ADMIN -> rbactest.package#yyy00: INSERT:rbactest.domain",
"rbactest.package#yyy00:TENANT -> rbactest.package#yyy00: SELECT",
"rbactest.domain#yyy00-aaaa:OWNER -> rbactest.domain#yyy00-aaaa: DELETE",
"rbactest.domain#yyy00-aaab:OWNER -> rbactest.domain#yyy00-aaab: DELETE"
// @formatter:on
);
}
@ -360,26 +360,26 @@ class RbacSubjectRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"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: INSERT:test_domain",
"test_package#xxx00:TENANT -> test_package#xxx00: SELECT"
"rbactest.customer#xxx:TENANT -> rbactest.customer#xxx: SELECT",
// "rbactest.customer#xxx:ADMIN -> rbactest.customer#xxx: view" - Not permissions through the customer admin!
"rbactest.package#xxx00:ADMIN -> rbactest.package#xxx00: INSERT:rbactest.domain",
"rbactest.package#xxx00:TENANT -> rbactest.package#xxx00: SELECT"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
// no customer admin permissions
"test_customer#xxx:ADMIN -> test_customer#xxx: add-package",
"rbactest.customer#xxx:ADMIN -> rbactest.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: 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"
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: add-package",
"rbactest.customer#yyy:ADMIN -> rbactest.customer#yyy: SELECT",
"rbactest.customer#yyy:TENANT -> rbactest.customer#yyy: SELECT",
"rbactest.package#yyy00:ADMIN -> rbactest.package#yyy00: INSERT:rbactest.domain",
"rbactest.package#yyy00:ADMIN -> rbactest.package#yyy00: INSERT:rbactest.domain",
"rbactest.package#yyy00:TENANT -> rbactest.package#yyy00: SELECT",
"rbactest.domain#yyy00-aaaa:OWNER -> rbactest.domain#yyy00-aaaa: DELETE",
"rbactest.domain#yyy00-xxxb:OWNER -> rbactest.domain#yyy00-xxxb: DELETE"
// @formatter:on
);
}

View File

@ -89,7 +89,7 @@ class TestCustomerControllerAcceptanceTest {
RestAssured // @formatter:off
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#yyy:ADMIN")
.header("assumed-roles", "rbactest.customer#yyy:ADMIN")
.port(port)
.when()
.get("http://localhost/api/test/customers")
@ -148,7 +148,7 @@ class TestCustomerControllerAcceptanceTest {
// finally, the new customer can be viewed by its own admin
final var newSubjectUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.define("superuser-fran@hostsharing.net", "test_customer#uuu:ADMIN");
context.define("superuser-fran@hostsharing.net", "rbactest.customer#uuu:ADMIN");
assertThat(testCustomerRepository.findByUuid(newSubjectUuid))
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("uuu"));
}
@ -159,7 +159,7 @@ class TestCustomerControllerAcceptanceTest {
RestAssured // @formatter:off
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#xxx:ADMIN")
.header("assumed-roles", "rbactest.customer#xxx:ADMIN")
.contentType(ContentType.JSON)
.body("""
{
@ -175,8 +175,8 @@ class TestCustomerControllerAcceptanceTest {
.statusCode(403)
.contentType(ContentType.JSON)
.statusCode(403)
.body("message", containsString("ERROR: [403] insert into test_customer "))
.body("message", containsString(" not allowed for current subjects {test_customer#xxx:ADMIN}"));
.body("message", containsString("ERROR: [403] insert into rbactest.customer "))
.body("message", containsString(" not allowed for current subjects {rbactest.customer#xxx:ADMIN}"));
// @formatter:on
// finally, the new customer was not created
@ -205,7 +205,7 @@ class TestCustomerControllerAcceptanceTest {
.statusCode(403)
.contentType(ContentType.JSON)
.statusCode(403)
.body("message", containsString("ERROR: [403] insert into test_customer "))
.body("message", containsString("ERROR: [403] insert into rbactest.customer "))
.body("message", containsString(" not allowed for current subjects"));
// @formatter:on

View File

@ -54,7 +54,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void globalAdmin_withAssumedCustomerRole_cannotCreateNewCustomer() {
// given
context("superuser-alex@hostsharing.net", "test_customer#xxx:ADMIN");
context("superuser-alex@hostsharing.net", "rbactest.customer#xxx:ADMIN");
// when
final var result = attempt(em, () -> {
@ -66,8 +66,8 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"ERROR: [403] insert into test_customer ",
"not allowed for current subjects {test_customer#xxx:ADMIN}");
"ERROR: [403] insert into rbactest.customer ",
"not allowed for current subjects {rbactest.customer#xxx:ADMIN}");
}
@Test
@ -85,7 +85,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"ERROR: [403] insert into test_customer ",
"ERROR: [403] insert into rbactest.customer ",
" not allowed for current subjects {customer-admin@xxx.example.com}");
}
@ -114,7 +114,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void globalAdmin_withAssumedCustomerOwnerRole_canViewExactlyThatCustomer() {
given:
context("superuser-alex@hostsharing.net", "test_customer#yyy:OWNER");
context("superuser-alex@hostsharing.net", "rbactest.customer#yyy:OWNER");
// when
final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null);
@ -139,7 +139,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnCustomer() {
context("customer-admin@xxx.example.com");
context("customer-admin@xxx.example.com", "test_package#xxx00:ADMIN");
context("customer-admin@xxx.example.com", "rbactest.package#xxx00:ADMIN");
final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null);

View File

@ -44,7 +44,7 @@ class TestPackageControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#xxx:ADMIN")
.header("assumed-roles", "rbactest.customer#xxx:ADMIN")
.port(port)
.when()
.get("http://localhost/api/test/packages")
@ -66,7 +66,7 @@ class TestPackageControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#xxx:ADMIN")
.header("assumed-roles", "rbactest.customer#xxx:ADMIN")
.port(port)
.when()
.get("http://localhost/api/test/packages?name=xxx01")
@ -95,7 +95,7 @@ class TestPackageControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#xxx:ADMIN")
.header("assumed-roles", "rbactest.customer#xxx:ADMIN")
.contentType(ContentType.JSON)
.body(format("""
{
@ -126,7 +126,7 @@ class TestPackageControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#xxx:ADMIN")
.header("assumed-roles", "rbactest.customer#xxx:ADMIN")
.contentType(ContentType.JSON)
.body("""
{
@ -156,7 +156,7 @@ class TestPackageControllerAcceptanceTest {
RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#xxx:ADMIN")
.header("assumed-roles", "rbactest.customer#xxx:ADMIN")
.contentType(ContentType.JSON)
.body("{}")
.port(port)
@ -176,7 +176,7 @@ class TestPackageControllerAcceptanceTest {
return UUID.fromString(RestAssured
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_customer#xxx:ADMIN")
.header("assumed-roles", "rbactest.customer#xxx:ADMIN")
.port(port)
.when()
.get("http://localhost/api/test/packages?name={packageName}", packageName)
@ -188,7 +188,7 @@ class TestPackageControllerAcceptanceTest {
}
String getDescriptionOfPackage(final String packageName) {
context.define("superuser-alex@hostsharing.net","test_customer#xxx:ADMIN");
context.define("superuser-alex@hostsharing.net","rbactest.customer#xxx:ADMIN");
return testPackageRepository.findAllByOptionalNameLike(packageName).get(0).getDescription();
}
}

View File

@ -76,7 +76,7 @@ class TestPackageRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnPackages() {
context.define("customer-admin@xxx.example.com", "test_package#xxx00:ADMIN");
context.define("customer-admin@xxx.example.com", "rbactest.package#xxx00:ADMIN");
final var result = testPackageRepository.findAllByOptionalNameLike(null);
@ -90,17 +90,17 @@ class TestPackageRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void supportsOptimisticLocking() {
// given
globalAdminWithAssumedRole("test_package#xxx00:ADMIN");
globalAdminWithAssumedRole("rbactest.package#xxx00:ADMIN");
final var pac = testPackageRepository.findAllByOptionalNameLike("%").get(0);
// when
final var result1 = jpaAttempt.transacted(() -> {
globalAdminWithAssumedRole("test_package#xxx00:OWNER");
globalAdminWithAssumedRole("rbactest.package#xxx00:OWNER");
pac.setDescription("description set by thread 1");
testPackageRepository.save(pac);
});
final var result2 = jpaAttempt.transacted(() -> {
globalAdminWithAssumedRole("test_package#xxx00:OWNER");
globalAdminWithAssumedRole("rbactest.package#xxx00:OWNER");
pac.setDescription("description set by thread 2");
testPackageRepository.save(pac);
sleep(1500);

View File

@ -5,6 +5,7 @@ spring:
datasource:
url-tc: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
url-tcx: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers?TC_REUSABLE=true&TC_DAEMON=true
url-local: jdbc:postgresql://localhost:5432/postgres
url: ${spring.datasource.url-tc}
username: postgres