From 7869d07d30d453146c22fd152c4a7ab914e7e7df Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Sun, 14 Aug 2022 16:44:26 +0200 Subject: [PATCH] add unixuser prototype as preparation for testability of grants --- .../db/changelog/2022-07-28-005-rbac-base.sql | 26 ++- .../changelog/2022-07-28-007-rbac-views.sql | 4 +- .../changelog/2022-07-29-070-hs-package.sql | 2 +- .../changelog/2022-08-14-080-hs-unixuser.sql | 14 ++ .../2022-08-14-081-hs-unixuser-rbac.sql | 211 ++++++++++++++++++ .../2022-08-14-082-hs-unixuser-test-data.sql | 62 +++++ .../resources/db/changelog/23-hs-unixuser.sql | 159 ------------- .../db/changelog/db.changelog-master.yaml | 8 +- .../RbacRoleControllerAcceptanceTest.java | 37 +-- .../RbacRoleRepositoryIntegrationTest.java | 56 ++++- .../RbacUserRepositoryIntegrationTest.java | 70 +++++- 11 files changed, 443 insertions(+), 206 deletions(-) create mode 100644 src/main/resources/db/changelog/2022-08-14-080-hs-unixuser.sql create mode 100644 src/main/resources/db/changelog/2022-08-14-081-hs-unixuser-rbac.sql create mode 100644 src/main/resources/db/changelog/2022-08-14-082-hs-unixuser-test-data.sql delete mode 100644 src/main/resources/db/changelog/23-hs-unixuser.sql diff --git a/src/main/resources/db/changelog/2022-07-28-005-rbac-base.sql b/src/main/resources/db/changelog/2022-07-28-005-rbac-base.sql index 0e233f8c..a3ddbccc 100644 --- a/src/main/resources/db/changelog/2022-07-28-005-rbac-base.sql +++ b/src/main/resources/db/changelog/2022-07-28-005-rbac-base.sql @@ -629,19 +629,21 @@ create or replace function queryAllRbacUsersWithPermissionsFor(objectId uuid) language sql as $$ select * from RbacUser - where uuid in (with recursive grants as (select descendantUuid, - ascendantUuid - from RbacGrants - where descendantUuid = objectId - union all - select "grant".descendantUuid, - "grant".ascendantUuid - from RbacGrants "grant" - inner join grants recur on recur.ascendantUuid = "grant".descendantUuid) - select ascendantUuid - from grants); + where uuid in ( + -- @formatter:off + with recursive grants as ( + select descendantUuid, ascendantUuid + from RbacGrants + where descendantUuid = objectId + union all + select "grant".descendantUuid, "grant".ascendantUuid + from RbacGrants "grant" + inner join grants recur on recur.ascendantUuid = "grant".descendantUuid + ) + -- @formatter:on + select ascendantUuid + from grants); $$; - --// diff --git a/src/main/resources/db/changelog/2022-07-28-007-rbac-views.sql b/src/main/resources/db/changelog/2022-07-28-007-rbac-views.sql index 2cb82e58..85e0f922 100644 --- a/src/main/resources/db/changelog/2022-07-28-007-rbac-views.sql +++ b/src/main/resources/db/changelog/2022-07-28-007-rbac-views.sql @@ -19,7 +19,7 @@ select * where isGranted(currentSubjectIds(), r.uuid) ) as unordered -- @formatter:on - order by objectIdName; + order by objectTable || '#' || objectIdName || '.' || roleType; grant all privileges on rbacrole_rv to restricted; --// @@ -49,7 +49,7 @@ select userName, objectTable||'#'||objectIdName||'.'||roletype as roleIdName, where isGranted(currentSubjectIds(), r.uuid) ) as unordered -- @formatter:on - order by objectIdName; + order by roleIdName; grant all privileges on rbacrole_rv to restricted; --// diff --git a/src/main/resources/db/changelog/2022-07-29-070-hs-package.sql b/src/main/resources/db/changelog/2022-07-29-070-hs-package.sql index 5f7ba39e..488d64b2 100644 --- a/src/main/resources/db/changelog/2022-07-29-070-hs-package.sql +++ b/src/main/resources/db/changelog/2022-07-29-070-hs-package.sql @@ -9,6 +9,6 @@ create table if not exists package uuid uuid unique references RbacObject (uuid), customerUuid uuid references customer (uuid), name varchar(5), - description varchar(80) + description varchar(96) ); --// diff --git a/src/main/resources/db/changelog/2022-08-14-080-hs-unixuser.sql b/src/main/resources/db/changelog/2022-08-14-080-hs-unixuser.sql new file mode 100644 index 00000000..6bee836c --- /dev/null +++ b/src/main/resources/db/changelog/2022-08-14-080-hs-unixuser.sql @@ -0,0 +1,14 @@ +--liquibase formatted sql + +-- ============================================================================ +--changeset hs-unixuser-MAIN-TABLE:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +create table if not exists UnixUser +( + uuid uuid unique references RbacObject (uuid), + packageUuid uuid references package (uuid), + name character varying(32), + description character varying(96) +); +--// diff --git a/src/main/resources/db/changelog/2022-08-14-081-hs-unixuser-rbac.sql b/src/main/resources/db/changelog/2022-08-14-081-hs-unixuser-rbac.sql new file mode 100644 index 00000000..1e2dc917 --- /dev/null +++ b/src/main/resources/db/changelog/2022-08-14-081-hs-unixuser-rbac.sql @@ -0,0 +1,211 @@ +--liquibase formatted sql + +-- ============================================================================ +--changeset hs-package-rbac-CREATE-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +/* + Creates the related RbacObject through a BEFORE INSERT TRIGGER. + */ +drop trigger if exists createRbacObjectForUnixUser_Trigger on UnixUser; +create trigger createRbacObjectForUnixUser_Trigger + before insert + on UnixUser + for each row +execute procedure createRbacObject(); +--// + + +-- ============================================================================ +--changeset hs-unixuser-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +create or replace function unixUserOwner(uu UnixUser) + returns RbacRoleDescriptor + returns null on null input + language plpgsql as $$ +begin + return roleDescriptor('unixuser', uu.uuid, 'owner'); +end; $$; + +create or replace function unixUserAdmin(uu UnixUser) + returns RbacRoleDescriptor + returns null on null input + language plpgsql as $$ +begin + return roleDescriptor('unixuser', uu.uuid, 'admin'); +end; $$; + +create or replace function unixUserTenant(uu UnixUser) + returns RbacRoleDescriptor + returns null on null input + language plpgsql as $$ +begin + return roleDescriptor('unixuser', uu.uuid, 'tenant'); +end; $$; + +create or replace function createUnixUserTenantRoleIfNotExists(unixUser UnixUser) + returns uuid + returns null on null input + language plpgsql as $$ +declare + unixUserTenantRoleDesc RbacRoleDescriptor; + unixUserTenantRoleUuid uuid; +begin + unixUserTenantRoleDesc = unixUserTenant(unixUser); + unixUserTenantRoleUuid = findRoleId(unixUserTenantRoleDesc); + if unixUserTenantRoleUuid is not null then + return unixUserTenantRoleUuid; + end if; + + return createRole( + unixUserTenantRoleDesc, + grantingPermissions(forObjectUuid => unixUser.uuid, permitOps => array ['view']), + beneathRole(unixUserAdmin(unixUser)) + ); +end; $$; +--// + + +-- ============================================================================ +--changeset hs-unixuser-rbac-ROLES-CREATION:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +/* + Creates the roles and their assignments for a new UnixUser for the AFTER INSERT TRIGGER. + */ + +create or replace function createRbacRulesForUnixUser() + returns trigger + language plpgsql + strict as $$ +declare + parentPackage package; + unixuserOwnerRoleId uuid; + unixuserAdminRoleId uuid; +begin + if TG_OP <> 'INSERT' then + raise exception 'invalid usage of TRIGGER AFTER INSERT'; + end if; + + select * from package where uuid = NEW.packageUuid into parentPackage; + + -- an owner role is created and assigned to the package's admin group + unixuserOwnerRoleId = createRole( + unixUserOwner(NEW), + grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']), + beneathRole(packageAdmin(parentPackage)) + ); + + -- and a unixuser admin role is created and assigned to the unixuser owner as well + unixuserAdminRoleId = createRole( + unixUserAdmin(NEW), + grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']), + beneathRole(unixuserOwnerRoleId), + beingItselfA(packageTenant(parentPackage)) + ); + + -- a tenent role is only created on demand + + return NEW; +end; $$; + + +/* + An AFTER INSERT TRIGGER which creates the role structure for a new UnixUser. + */ +drop trigger if exists createRbacRulesForUnixUser_Trigger on UnixUser; +create trigger createRbacRulesForUnixUser_Trigger + after insert + on UnixUser + for each row +execute procedure createRbacRulesForUnixUser(); +--// + + +-- ============================================================================ +--changeset hs-unixuser-rbac-ROLES-REMOVAL:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Deletes the roles and their assignments of a deleted UnixUser for the BEFORE DELETE TRIGGER. + */ + +create or replace function deleteRbacRulesForUnixUser() + returns trigger + language plpgsql + strict as $$ +begin + if TG_OP = 'DELETE' then + call deleteRole(findRoleId(unixUserOwner(OLD))); + call deleteRole(findRoleId(unixUserAdmin(OLD))); + call deleteRole(findRoleId(unixUserTenant(OLD))); + else + raise exception 'invalid usage of TRIGGER BEFORE DELETE'; + end if; +end; $$; + +/* + An BEFORE DELETE TRIGGER which deletes the role structure of a UnixUser. + */ + +drop trigger if exists deleteRbacRulesForUnixUser_Trigger on package; +create trigger deleteRbacRulesForUnixUser_Trigger + before delete + on UnixUser + for each row +execute procedure deleteRbacRulesForUnixUser(); +--// + + +-- ============================================================================ +--changeset hs-unixuser-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates a view to the UnixUser main table which maps the identifying name + (in this case, actually the column `name`) to the objectUuid. + */ +drop view if exists UnixUser_iv; +create or replace view UnixUser_iv as +select distinct target.uuid, target.name as idName + from UnixUser as target; +-- TODO: Is it ok that everybody has access to this information? +grant all privileges on UnixUser_iv to restricted; + +/* + Returns the objectUuid for a given identifying name (in this case, actually the column `name`). + */ +create or replace function unixUserUuidByIdName(idName varchar) + returns uuid + language sql + strict as $$ +select uuid from UnixUser_iv iv where iv.idName = unixUserUuidByIdName.idName; +$$; + +/* + Returns the identifying name for a given objectUuid (in this case the name). + */ +create or replace function unixUserIdNameByUuid(uuid uuid) + returns varchar + stable leakproof + language sql + strict as $$ +select idName from UnixUser_iv iv where iv.uuid = unixUserIdNameByUuid.uuid; +$$; +--// + + +-- ============================================================================ +--changeset hs-package-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates a view to the customer main table which maps the identifying name + (in this case, the prefix) to the objectUuid. + */ +drop view if exists unixuser_rv; +create or replace view unixuser_rv as +select target.* + from unixuser as target + where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'unixuser', currentSubjectIds())); +grant all privileges on unixuser_rv to restricted; +--// diff --git a/src/main/resources/db/changelog/2022-08-14-082-hs-unixuser-test-data.sql b/src/main/resources/db/changelog/2022-08-14-082-hs-unixuser-test-data.sql new file mode 100644 index 00000000..cc7803f3 --- /dev/null +++ b/src/main/resources/db/changelog/2022-08-14-082-hs-unixuser-test-data.sql @@ -0,0 +1,62 @@ +--liquibase formatted sql + +-- ============================================================================ +--changeset hs-unixuser-TEST-DATA-GENERATOR:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +/* + Creates test data for the package main table. + */ +create or replace procedure createUnixUserTestData( + minCustomerReference integer, -- skip customers with reference below this + unixUserPerPackage integer, -- create this many unix users for each package + doCommitAfterEach boolean -- only for mass data creation outside of Liquibase +) + language plpgsql as $$ +declare + pac record; + pacAdmin varchar; + currentTask varchar; +begin + set hsadminng.currentUser to ''; + + for pac in + (select p.uuid, p.name + from package p + join customer c on p.customeruuid = c.uuid + where c.reference >= minCustomerReference) + loop + + for t in 0..(unixUserPerPackage-1) + loop + currentTask = 'creating RBAC test unixuser #' || t || ' for package ' || pac.name || ' #' || pac.uuid; + raise notice 'task: %', currentTask; + pacAdmin = 'admin@' || pac.name || '.example.com'; + set local hsadminng.currentUser to 'mike@hostsharing.net'; -- TODO: use a package-admin + set local hsadminng.assumedRoles = ''; + set local hsadminng.currentTask to currentTask; + + insert + into unixuser (name, packageUuid) + values (pac.name || '-' || intToVarChar(t, 4), pac.uuid); + + if doCommitAfterEach then + commit; + end if; + end loop; + end loop; + +end; +$$; +--// + + +-- ============================================================================ +--changeset hs-unixuser-TEST-DATA-GENERATION:1 –context=dev,tc endDelimiter:--// +-- ---------------------------------------------------------------------------- + +do language plpgsql $$ + begin + call createUnixUserTestData(0, 2, false); + end; +$$; +--// diff --git a/src/main/resources/db/changelog/23-hs-unixuser.sql b/src/main/resources/db/changelog/23-hs-unixuser.sql deleted file mode 100644 index 233ef5a8..00000000 --- a/src/main/resources/db/changelog/23-hs-unixuser.sql +++ /dev/null @@ -1,159 +0,0 @@ --- ======================================================== --- UnixUser example with RBAC --- -------------------------------------------------------- - -set session session authorization default; - -create table if not exists UnixUser -( - uuid uuid unique references RbacObject (uuid), - name character varying(32), - comment character varying(96), - packageUuid uuid references package (uuid) -); - -create or replace function unixUserOwner(uu UnixUser) - returns RbacRoleDescriptor - returns null on null input - language plpgsql as $$ -begin - return roleDescriptor('unixuser', uu.uuid, 'owner'); -end; $$; - -create or replace function unixUserAdmin(uu UnixUser) - returns RbacRoleDescriptor - returns null on null input - language plpgsql as $$ -begin - return roleDescriptor('unixuser', uu.uuid, 'admin'); -end; $$; - -create or replace function unixUserTenant(uu UnixUser) - returns RbacRoleDescriptor - returns null on null input - language plpgsql as $$ -begin - return roleDescriptor('unixuser', uu.uuid, 'tenant'); -end; $$; - -create or replace function createUnixUserTenantRoleIfNotExists(unixUser UnixUser) - returns uuid - returns null on null input - language plpgsql as $$ -declare - unixUserTenantRoleDesc RbacRoleDescriptor; - unixUserTenantRoleUuid uuid; -begin - unixUserTenantRoleDesc = unixUserTenant(unixUser); - unixUserTenantRoleUuid = findRoleId(unixUserTenantRoleDesc); - if unixUserTenantRoleUuid is not null then - return unixUserTenantRoleUuid; - end if; - - return createRole( - unixUserTenantRoleDesc, - grantingPermissions(forObjectUuid => unixUser.uuid, permitOps => array ['view']), - beneathRole(unixUserAdmin(unixUser)) - ); -end; $$; - - -drop trigger if exists createRbacObjectForUnixUser_Trigger on UnixUser; -create trigger createRbacObjectForUnixUser_Trigger - before insert - on UnixUser - for each row -execute procedure createRbacObject(); - -create or replace function createRbacRulesForUnixUser() - returns trigger - language plpgsql - strict as $$ -declare - parentPackage package; - unixuserOwnerRoleId uuid; - unixuserAdminRoleId uuid; -begin - if TG_OP <> 'INSERT' then - raise exception 'invalid usage of TRIGGER AFTER INSERT'; - end if; - - select * from package where uuid = NEW.packageUuid into parentPackage; - - -- an owner role is created and assigned to the package's admin group - unixuserOwnerRoleId = createRole( - unixUserOwner(NEW), - grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']), - beneathRole(packageAdmin(parentPackage)) - ); - - -- and a unixuser admin role is created and assigned to the unixuser owner as well - unixuserAdminRoleId = createRole( - unixUserAdmin(NEW), - grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']), - beneathRole(unixuserOwnerRoleId), - beingItselfA(packageTenant(parentPackage)) - ); - - -- a tenent role is only created on demand - - return NEW; -end; $$; - -drop trigger if exists createRbacRulesForUnixUser_Trigger on UnixUser; -create trigger createRbacRulesForUnixUser_Trigger - after insert - on UnixUser - for each row -execute procedure createRbacRulesForUnixUser(); - --- TODO: CREATE OR REPLACE FUNCTION deleteRbacRulesForUnixUser() - - --- create RBAC-restricted view -set session session authorization default; --- ALTER TABLE unixuser ENABLE ROW LEVEL SECURITY; -drop view if exists unixuser_rv; -create or replace view unixuser_rv as -select target.* - from unixuser as target - where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'unixuser', currentSubjectIds())); -grant all privileges on unixuser_rv to restricted; - - --- generate UnixUser test data - -do language plpgsql $$ - declare - pac record; - pacAdmin varchar; - currentTask varchar; - begin - set hsadminng.currentUser to ''; - - for pac in (select p.uuid, p.name - from package p - join customer c on p.customeruuid = c.uuid - -- WHERE c.reference >= 18000 - ) - loop - - for t in 0..9 - loop - currentTask = 'creating RBAC test unixuser #' || t || ' for package ' || pac.name || ' #' || pac.uuid; - raise notice 'task: %', currentTask; - pacAdmin = 'admin@' || pac.name || '.example.com'; - set local hsadminng.currentUser to 'mike@hostsharing.net'; -- TODO: use a package-admin - set local hsadminng.assumedRoles = ''; - set local hsadminng.currentTask to currentTask; - - insert - into unixuser (name, packageUuid) - values (pac.name || '-' || intToVarChar(t, 4), pac.uuid); - - commit; - end loop; - end loop; - - end; -$$; diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index b86d0f2e..5c3a63ac 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -30,6 +30,12 @@ databaseChangeLog: - include: file: db/changelog/2022-07-29-070-hs-package-rbac.sql - include: - file: db/changelog/2022-07-29-070-hs-package-test-data.sql + file: db/changelog/2022-07-29-070-hs-package-test-data.sql + - include: + file: db/changelog/2022-08-14-080-hs-unixuser.sql + - include: + file: db/changelog/2022-08-14-081-hs-unixuser-rbac.sql + - include: + file: db/changelog/2022-08-14-082-hs-unixuser-test-data.sql diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java index 1338ac2d..3cbee13b 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java @@ -12,7 +12,7 @@ import org.springframework.boot.test.web.server.LocalServerPort; import javax.persistence.EntityManager; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, @@ -50,14 +50,15 @@ class RbacRoleControllerAcceptanceTest { .then().assertThat() .statusCode(200) .contentType("application/json") - .body("[0].roleName", is("customer#aaa.owner")) - .body("[1].roleName", is("customer#aaa.admin")) + .body("[0].roleName", is("customer#aaa.admin")) + .body("[1].roleName", is("customer#aaa.owner")) .body("[2].roleName", is("customer#aaa.tenant")) - .body("[3].roleName", is("package#aaa00.owner")) - .body("[4].roleName", is("package#aaa00.tenant")) // ... - .body("[36].roleName", is("global#hostsharing.admin")) - .body( "size()", is(37)); + .body("", hasItem(hasEntry("roleName", "global#hostsharing.admin"))) + .body("", hasItem(hasEntry("roleName", "customer#aab.admin"))) + .body("", hasItem(hasEntry("roleName", "package#aab00.admin"))) + .body("", hasItem(hasEntry("roleName", "unixuser#aab00-aaaa.owner"))) + .body( "size()", is(73)); // increases with new test data // @formatter:on } @@ -69,17 +70,18 @@ class RbacRoleControllerAcceptanceTest { RestAssured .given() .header("current-user", "mike@hostsharing.net") - .header("assumed-roles", "package#aaa00.admin") + .header("assumed-roles", "package#aab00.admin") .port(port) .when() .get("http://localhost/api/rbac-roles") .then().assertThat() .statusCode(200) .contentType("application/json") - .body("[0].roleName", is("customer#aaa.tenant")) - .body("[1].roleName", is("package#aaa00.admin")) - .body("[2].roleName", is("package#aaa00.tenant")) - .body("size()", is(3)); + .body("[0].roleName", is("customer#aab.tenant")) + .body("[1].roleName", is("package#aab00.admin")) + .body("[2].roleName", is("package#aab00.tenant")) + .body("[3].roleName", is("unixuser#aab00-aaaa.admin")) + .body("size()", is(7)); // increases with new test data // @formatter:on } @@ -90,17 +92,18 @@ class RbacRoleControllerAcceptanceTest { // @formatter:off RestAssured .given() - .header("current-user", "aaa00@aaa.example.com") + .header("current-user", "aac00@aac.example.com") .port(port) .when() .get("http://localhost/api/rbac-roles") .then().assertThat() .statusCode(200) .contentType("application/json") - .body("[0].roleName", is("customer#aaa.tenant")) - .body("[1].roleName", is("package#aaa00.admin")) - .body("[2].roleName", is("package#aaa00.tenant")) - .body("size()", is(3));; + .body("[0].roleName", is("customer#aac.tenant")) + .body("[1].roleName", is("package#aac00.admin")) + .body("[2].roleName", is("package#aac00.tenant")) + .body("[3].roleName", is("unixuser#aac00-aaaa.admin")) + .body("size()", is(7)); // increases with new test data // @formatter:on } diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleRepositoryIntegrationTest.java index 979cfdc1..d39491a7 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleRepositoryIntegrationTest.java @@ -59,7 +59,7 @@ class RbacRoleRepositoryIntegrationTest { final var result = rbacRoleRepository.findAll(); // then - exactlyTheseRbacRolesAreReturned(result, ALL_TEST_DATA_ROLES); + allTheseRbacRolesAreReturned(result, ALL_TEST_DATA_ROLES); } @Test @@ -72,7 +72,7 @@ class RbacRoleRepositoryIntegrationTest { final var result = rbacRoleRepository.findAll(); then: - exactlyTheseRbacRolesAreReturned(result, ALL_TEST_DATA_ROLES); + allTheseRbacRolesAreReturned(result, ALL_TEST_DATA_ROLES); } @Test @@ -84,13 +84,33 @@ class RbacRoleRepositoryIntegrationTest { final var result = rbacRoleRepository.findAll(); // then: - exactlyTheseRbacRolesAreReturned( + allTheseRbacRolesAreReturned( result, // @formatter:off - "customer#aaa.admin", "customer#aaa.tenant", - "package#aaa00.admin", "package#aaa00.owner", "package#aaa00.tenant", - "package#aaa01.admin", "package#aaa01.owner", "package#aaa01.tenant", - "package#aaa02.admin", "package#aaa02.owner", "package#aaa02.tenant" + "customer#aaa.admin", + "customer#aaa.tenant", + "package#aaa00.admin", + "package#aaa00.owner", + "package#aaa00.tenant", + "package#aaa01.admin", + "package#aaa01.owner", + "package#aaa01.tenant", + // ... + "unixuser#aaa00-aaaa.admin", + "unixuser#aaa00-aaaa.owner", + // .. + "unixuser#aaa01-aaaa.admin", + "unixuser#aaa01-aaaa.owner" + // @formatter:on + ); + noneOfTheseRbacRolesIsReturned( + result, + // @formatter:off + "global#hostsharing.admin", + "customer#aaa.owner", + "package#aab00.admin", + "package#aab00.owner", + "package#aab00.tenant" // @formatter:on ); } @@ -102,7 +122,15 @@ class RbacRoleRepositoryIntegrationTest { final var result = rbacRoleRepository.findAll(); - exactlyTheseRbacRolesAreReturned(result, "customer#aaa.tenant", "package#aaa00.tenant", "package#aaa00.admin"); + exactlyTheseRbacRolesAreReturned( + result, + "customer#aaa.tenant", + "package#aaa00.admin", + "package#aaa00.tenant", + "unixuser#aaa00-aaaa.admin", + "unixuser#aaa00-aaaa.owner", + "unixuser#aaa00-aaab.admin", + "unixuser#aaa00-aaab.owner"); } @Test @@ -191,4 +219,16 @@ class RbacRoleRepositoryIntegrationTest { .containsExactlyInAnyOrder(expectedRoleNames); } + void allTheseRbacRolesAreReturned(final List actualResult, final String... expectedRoleNames) { + assertThat(actualResult) + .extracting(RbacRoleEntity::getRoleName) + .contains(expectedRoleNames); + } + + void noneOfTheseRbacRolesIsReturned(final List actualResult, final String... unexpectedRoleNames) { + assertThat(actualResult) + .extracting(RbacRoleEntity::getRoleName) + .doesNotContain(unexpectedRoleNames); + } + } diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java index 182b9c5e..7519d5ad 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java @@ -237,7 +237,7 @@ class RbacUserRepositoryIntegrationTest { final var result = rbacUserRepository.findPermissionsOfUser("mike@hostsharing.net"); // then - exactlyTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS); + allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS); } @Test @@ -266,7 +266,7 @@ class RbacUserRepositoryIntegrationTest { final var result = rbacUserRepository.findPermissionsOfUser("admin@aaa.example.com"); // then - exactlyTheseRbacPermissionsAreReturned( + allTheseRbacPermissionsAreReturned( result, // @formatter:off "customer#aaa.admin -> customer#aaa: add-package", @@ -276,14 +276,25 @@ class RbacUserRepositoryIntegrationTest { "package#aaa00.admin -> package#aaa00: add-domain", "package#aaa00.admin -> package#aaa00: add-unixuser", "package#aaa00.tenant -> package#aaa00: view", + "unixuser#aaa00-aaaa.owner -> unixuser#aaa00-aaaa: *", "package#aaa01.admin -> package#aaa01: add-domain", "package#aaa01.admin -> package#aaa01: add-unixuser", "package#aaa01.tenant -> package#aaa01: view", + "unixuser#aaa01-aaaa.owner -> unixuser#aaa01-aaaa: *", "package#aaa02.admin -> package#aaa02: add-domain", "package#aaa02.admin -> package#aaa02: add-unixuser", - "package#aaa02.tenant -> package#aaa02: view" + "package#aaa02.tenant -> package#aaa02: view", + "unixuser#aaa02-aaaa.owner -> unixuser#aaa02-aaaa: *" + // @formatter:on + ); + noneOfTheseRbacPermissionsAreReturned( + result, + // @formatter:off + "customer#aab.admin -> customer#aab: add-package", + "customer#aab.admin -> customer#aab: view", + "customer#aab.tenant -> customer#aab: view" // @formatter:on ); } @@ -313,14 +324,29 @@ class RbacUserRepositoryIntegrationTest { final var result = rbacUserRepository.findPermissionsOfUser("aaa00@aaa.example.com"); // then - exactlyTheseRbacPermissionsAreReturned( + allTheseRbacPermissionsAreReturned( result, // @formatter:off "customer#aaa.tenant -> customer#aaa: view", // "customer#aaa.admin -> customer#aaa: view" - Not permissions through the customer admin! "package#aaa00.admin -> package#aaa00: add-unixuser", "package#aaa00.admin -> package#aaa00: add-domain", - "package#aaa00.tenant -> package#aaa00: view" + "package#aaa00.tenant -> package#aaa00: view", + "unixuser#aaa00-aaaa.owner -> unixuser#aaa00-aaaa: *", + "unixuser#aaa00-aaab.owner -> unixuser#aaa00-aaab: *" + // @formatter:on + ); + noneOfTheseRbacPermissionsAreReturned( + result, + // @formatter:off + "customer#aab.admin -> customer#aab: add-package", + "customer#aab.admin -> customer#aab: view", + "customer#aab.tenant -> customer#aab: view", + "package#aab00.admin -> package#aab00: add-unixuser", + "package#aab00.admin -> package#aab00: add-domain", + "package#aab00.tenant -> package#aab00: view", + "unixuser#aab00-aaaa.owner -> unixuser#aab00-aaaa: *", + "unixuser#aab00-aaab.owner -> unixuser#aab00-aaab: *" // @formatter:on ); } @@ -346,7 +372,7 @@ class RbacUserRepositoryIntegrationTest { final var result = rbacUserRepository.findPermissionsOfUser("aaa00@aaa.example.com"); // then - exactlyTheseRbacPermissionsAreReturned( + allTheseRbacPermissionsAreReturned( result, // @formatter:off "customer#aaa.tenant -> customer#aaa: view", @@ -356,6 +382,22 @@ class RbacUserRepositoryIntegrationTest { "package#aaa00.tenant -> package#aaa00: view" // @formatter:on ); + noneOfTheseRbacPermissionsAreReturned( + result, + // @formatter:off + // no customer admin permissions + "customer#aaa.admin -> customer#aaa: add-package", + // no permissions on other customer's objects + "customer#aab.admin -> customer#aab: add-package", + "customer#aab.admin -> customer#aab: view", + "customer#aab.tenant -> customer#aab: view", + "package#aab00.admin -> package#aab00: add-unixuser", + "package#aab00.admin -> package#aab00: add-domain", + "package#aab00.tenant -> package#aab00: view", + "unixuser#aab00-aaaa.owner -> unixuser#aab00-aaaa: *", + "unixuser#aab00-aaab.owner -> unixuser#aab00-aaab: *" + // @formatter:on + ); } } @@ -391,4 +433,20 @@ class RbacUserRepositoryIntegrationTest { .containsExactlyInAnyOrder(expectedRoleNames); } + void allTheseRbacPermissionsAreReturned( + final List actualResult, + final String... expectedRoleNames) { + assertThat(actualResult) + .extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp()) + .contains(expectedRoleNames); + } + + void noneOfTheseRbacPermissionsAreReturned( + final List actualResult, + final String... unexpectedRoleNames) { + assertThat(actualResult) + .extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp()) + .doesNotContain(unexpectedRoleNames); + } + }