add RbacUserController/-Entity/-Repository
This commit is contained in:
parent
18f3234272
commit
06996e4dc4
@ -0,0 +1,46 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@RestController
|
||||
public class RbacUserController {
|
||||
|
||||
@Autowired
|
||||
private Context context;
|
||||
|
||||
@Autowired
|
||||
private RbacUserRepository rbacUserRepository;
|
||||
|
||||
@GetMapping(value = "/api/rbacuser")
|
||||
@Transactional
|
||||
public Iterable<RbacUserEntity> listUsers(
|
||||
@RequestHeader(name = "current-user") String currentUserName,
|
||||
@RequestHeader(name = "assumed-roles", required = false) String assumedRoles,
|
||||
@RequestParam(name="name", required = false) String userName
|
||||
) {
|
||||
context.setCurrentUser(currentUserName);
|
||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
||||
context.assumeRoles(assumedRoles);
|
||||
}
|
||||
return rbacUserRepository.findByOptionalNameLike(userName);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/api/rbacuser/{userName}/permissions")
|
||||
@Transactional
|
||||
public Iterable<RbacUserPermission> listUserPermissions(
|
||||
@RequestHeader(name = "current-user") String currentUserName,
|
||||
@RequestHeader(name = "assumed-roles", required = false) String assumedRoles,
|
||||
@PathVariable(name= "userName") String userName
|
||||
) {
|
||||
context.setCurrentUser(currentUserName);
|
||||
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
||||
context.assumeRoles(assumedRoles);
|
||||
}
|
||||
return rbacUserRepository.findPermissionsOfUser(userName);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
|
||||
import lombok.*;
|
||||
import org.springframework.data.annotation.Immutable;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "rbacuser_rv")
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Immutable
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
//@SqlResultSetMapping(
|
||||
// name = "rbacUserPermissionMapping",
|
||||
// classes = {
|
||||
// @ConstructorResult(
|
||||
// targetClass = RbacUserPermission.class,
|
||||
// columns = {
|
||||
// @ColumnResult(name = "roleUuid", type = UUID.class),
|
||||
// @ColumnResult(name = "oleName", type = String.class),
|
||||
// @ColumnResult(name = "permissionUuid", type = UUID.class),
|
||||
// @ColumnResult(name = "op", type=String.class),
|
||||
// @ColumnResult(name = "objectTable", type=String.class),
|
||||
// @ColumnResult(name = "objectIdName", type =String.class),
|
||||
// @ColumnResult(name = "objectUuid", type = UUID.class),
|
||||
// @ColumnResult(name = "campId", type = Integer.class),
|
||||
// @ColumnResult(name = "userCount", type = Byte.class)
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
//)
|
||||
//@NamedNativeQuery(
|
||||
// name = "grantedPermissions",
|
||||
// query = "SELECT * FROM grantedPermissions(:userName)",
|
||||
// resultSetMapping = "rbacUserPermissionMapping"
|
||||
//)
|
||||
public class RbacUserEntity {
|
||||
|
||||
@Id
|
||||
private UUID uuid;
|
||||
|
||||
private String name;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface RbacUserPermission {
|
||||
|
||||
UUID getRoleUuid();
|
||||
String getRoleName();
|
||||
UUID getPermissionUuid();
|
||||
String getOp();
|
||||
String getObjectTable();
|
||||
String getObjectIdName();
|
||||
UUID getObjectUuid();
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface RbacUserRepository extends Repository<RbacUserEntity, UUID> {
|
||||
|
||||
@Query("SELECT u FROM RbacUserEntity u WHERE :userName is null or u.name like concat(:userName, '%')")
|
||||
List<RbacUserEntity> findByOptionalNameLike(final String userName);
|
||||
|
||||
@Query(value = "SELECT * FROM grantedPermissions(:userName)", nativeQuery = true)
|
||||
Iterable<RbacUserPermission> findPermissionsOfUser(@Param("userName") String userName);
|
||||
}
|
@ -501,36 +501,37 @@ $$;
|
||||
--changeset rbac-base-QUERY-GRANTED-PERMISSIONS:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
Returns all permissions accessible to the given subject UUID (user or role).
|
||||
*/
|
||||
create or replace function queryGrantedPermissionsOfSubjectIds(requiredOp RbacOp, subjectIds uuid[])
|
||||
create or replace function queryPermissionsGrantedToSubjectId(subjectId uuid)
|
||||
returns setof RbacPermission
|
||||
strict
|
||||
language sql as $$
|
||||
select distinct *
|
||||
-- @formatter:off
|
||||
select *
|
||||
from RbacPermission
|
||||
where op = '*'
|
||||
or op = requiredOp
|
||||
and uuid in (with recursive grants as (select distinct descendantUuid,
|
||||
ascendantUuid
|
||||
where uuid in (
|
||||
with recursive grants as (
|
||||
select distinct descendantUuid, ascendantUuid
|
||||
from RbacGrants
|
||||
where ascendantUuid = any (subjectIds)
|
||||
where ascendantUuid = subjectId
|
||||
union all
|
||||
select "grant".descendantUuid,
|
||||
"grant".ascendantUuid
|
||||
select "grant".descendantUuid, "grant".ascendantUuid
|
||||
from RbacGrants "grant"
|
||||
inner join grants recur on recur.descendantUuid = "grant".ascendantUuid)
|
||||
inner join grants recur on recur.descendantUuid = "grant".ascendantUuid
|
||||
)
|
||||
select descendantUuid
|
||||
from grants);
|
||||
from grants
|
||||
);
|
||||
-- @formatter:on
|
||||
$$;
|
||||
|
||||
--//
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-base-QUERY-USERS-WITH-PERMISSION-FOR-OBJECT:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
Returns all user UUIDs which have any permission for the given object UUID.
|
||||
*/
|
||||
|
||||
create or replace function queryAllRbacUsersWithPermissionsFor(objectId uuid)
|
||||
@ -554,190 +555,6 @@ $$;
|
||||
|
||||
--//
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-CURRENT-USER:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
*/
|
||||
create or replace function currentUser()
|
||||
returns varchar(63)
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentUser varchar(63);
|
||||
begin
|
||||
begin
|
||||
currentUser := current_setting('hsadminng.currentUser');
|
||||
exception
|
||||
when others then
|
||||
currentUser := null;
|
||||
end;
|
||||
if (currentUser is null or currentUser = '') then
|
||||
raise exception 'hsadminng.currentUser must be defined, please use "SET LOCAL ...;"';
|
||||
end if;
|
||||
return currentUser;
|
||||
end; $$;
|
||||
|
||||
create or replace function currentUserId()
|
||||
returns uuid
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentUser varchar(63);
|
||||
currentUserId uuid;
|
||||
begin
|
||||
currentUser := currentUser();
|
||||
currentUserId = (select uuid from RbacUser where name = currentUser);
|
||||
if currentUserId is null then
|
||||
raise exception 'hsadminng.currentUser defined as %, but does not exists', currentUser;
|
||||
end if;
|
||||
return currentUserId;
|
||||
end; $$;
|
||||
--//
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-ASSUMED-ROLES:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
*/
|
||||
create or replace function assumedRoles()
|
||||
returns varchar(63)[]
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentSubject varchar(63);
|
||||
begin
|
||||
begin
|
||||
currentSubject := current_setting('hsadminng.assumedRoles');
|
||||
exception
|
||||
when others then
|
||||
return array []::varchar[];
|
||||
end;
|
||||
if (currentSubject = '') then
|
||||
return array []::varchar[];
|
||||
end if;
|
||||
return string_to_array(currentSubject, ';');
|
||||
end; $$;
|
||||
|
||||
create or replace function pureIdentifier(rawIdentifier varchar)
|
||||
returns varchar
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return regexp_replace(rawIdentifier, '\W+', '');
|
||||
end; $$;
|
||||
|
||||
-- TODO: rename to findObjectUuidByIdName
|
||||
create or replace function findUuidByIdName(objectTable varchar, objectIdName varchar)
|
||||
returns uuid
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
declare
|
||||
sql varchar;
|
||||
uuid uuid;
|
||||
begin
|
||||
objectTable := pureIdentifier(objectTable);
|
||||
objectIdName := pureIdentifier(objectIdName);
|
||||
sql := format('select * from %sUuidByIdName(%L);', objectTable, objectIdName);
|
||||
begin
|
||||
raise notice 'sql: %', sql;
|
||||
execute sql into uuid;
|
||||
exception
|
||||
when others then
|
||||
raise exception 'function %UuidByIdName(...) not found, add identity view support for table %', objectTable, objectTable;
|
||||
end;
|
||||
return uuid;
|
||||
end ; $$;
|
||||
|
||||
create or replace function findIdNameByObjectUuid(objectTable varchar, objectUuid uuid)
|
||||
returns varchar
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
declare
|
||||
sql varchar;
|
||||
idName varchar;
|
||||
begin
|
||||
objectTable := pureIdentifier(objectTable);
|
||||
sql := format('select * from %sIdNameByUuid(%L::uuid);', objectTable, objectUuid);
|
||||
begin
|
||||
raise notice 'sql: %', sql;
|
||||
execute sql into idName;
|
||||
exception
|
||||
when others then
|
||||
raise exception 'function %IdNameByUuid(...) not found, add identity view support for table %', objectTable, objectTable;
|
||||
end;
|
||||
return idName;
|
||||
end ; $$;
|
||||
|
||||
create or replace function currentSubjects()
|
||||
returns varchar(63)[]
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
assumedRoles varchar(63)[];
|
||||
begin
|
||||
assumedRoles := assumedRoles();
|
||||
if array_length(assumedRoles(), 1) > 0 then
|
||||
return assumedRoles();
|
||||
else
|
||||
return array [currentUser()]::varchar(63)[];
|
||||
end if;
|
||||
end; $$;
|
||||
|
||||
create or replace function currentSubjectIds()
|
||||
returns uuid[]
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentUserId uuid;
|
||||
roleNames varchar(63)[];
|
||||
roleName varchar(63);
|
||||
objectTableToAssume varchar(63);
|
||||
objectNameToAssume varchar(63);
|
||||
objectUuidToAssume uuid;
|
||||
roleTypeToAssume RbacRoleType;
|
||||
roleIdsToAssume uuid[];
|
||||
roleUuidToAssume uuid;
|
||||
begin
|
||||
currentUserId := currentUserId();
|
||||
if currentUserId is null then
|
||||
raise exception 'user % does not exist', currentUser();
|
||||
end if;
|
||||
|
||||
roleNames := assumedRoles();
|
||||
if cardinality(roleNames) = 0 then
|
||||
return array [currentUserId];
|
||||
end if;
|
||||
|
||||
raise notice 'assuming roles: %', roleNames;
|
||||
|
||||
foreach roleName in array roleNames
|
||||
loop
|
||||
roleName = overlay(roleName placing '#' from length(roleName) + 1 - strpos(reverse(roleName), '.'));
|
||||
objectTableToAssume = split_part(roleName, '#', 1);
|
||||
objectNameToAssume = split_part(roleName, '#', 2);
|
||||
roleTypeToAssume = split_part(roleName, '#', 3);
|
||||
|
||||
objectUuidToAssume = findUuidByIdName(objectTableToAssume, objectNameToAssume);
|
||||
|
||||
-- TODO: either the result needs to be cached at least per transaction or we need to get rid of SELCT in a loop
|
||||
select uuid as roleuuidToAssume
|
||||
from RbacRole r
|
||||
where r.objectUuid = objectUuidToAssume
|
||||
and r.roleType = roleTypeToAssume
|
||||
into roleUuidToAssume;
|
||||
if (not isGranted(currentUserId, roleUuidToAssume)) then
|
||||
raise exception 'user % (%) has no permission to assume role % (%)', currentUser(), currentUserId, roleName, roleUuidToAssume;
|
||||
end if;
|
||||
roleIdsToAssume := roleIdsToAssume || roleUuidToAssume;
|
||||
end loop;
|
||||
|
||||
return roleIdsToAssume;
|
||||
end; $$;
|
||||
--//
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-base-PGSQL-ROLES:1 endDelimiter:--//
|
||||
@ -750,21 +567,3 @@ create role restricted;
|
||||
grant all privileges on all tables in schema public to restricted;
|
||||
|
||||
--//
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-base-ROLE-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Creates a view to the role table with row-level limitation
|
||||
based on the grants of the current user or assumed roles.
|
||||
*/
|
||||
drop view if exists rbacrole_rv;
|
||||
create or replace view rbacrole_rv as
|
||||
select DISTINCT r.*, o.objectTable,
|
||||
findIdNameByObjectUuid(o.objectTable, o.uuid) as objectIdName
|
||||
from rbacrole as r
|
||||
join rbacobject as o on o.uuid=r.objectuuid
|
||||
where isGranted(currentSubjectIds(), r.uuid);
|
||||
grant all privileges on rbacrole_rv to restricted;
|
||||
--//
|
||||
|
187
src/main/resources/db/changelog/2022-07-28-006-rbac-current.sql
Normal file
187
src/main/resources/db/changelog/2022-07-28-006-rbac-current.sql
Normal file
@ -0,0 +1,187 @@
|
||||
--liquibase formatted sql
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-current-CURRENT-USER:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Returns the current user as set by `hsadminng.currentUser`.
|
||||
Raises exception if not set.
|
||||
*/
|
||||
create or replace function currentUser()
|
||||
returns varchar(63)
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentUser varchar(63);
|
||||
begin
|
||||
begin
|
||||
currentUser := current_setting('hsadminng.currentUser');
|
||||
exception
|
||||
when others then
|
||||
currentUser := null;
|
||||
end;
|
||||
if (currentUser is null or currentUser = '') then
|
||||
raise exception 'hsadminng.currentUser must be defined, please use "SET LOCAL ...;"';
|
||||
end if;
|
||||
return currentUser;
|
||||
end; $$;
|
||||
|
||||
create or replace function currentUserId()
|
||||
returns uuid
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentUser varchar(63);
|
||||
currentUserId uuid;
|
||||
begin
|
||||
currentUser := currentUser();
|
||||
currentUserId = (select uuid from RbacUser where name = currentUser);
|
||||
if currentUserId is null then
|
||||
raise exception 'hsadminng.currentUser defined as %, but does not exists', currentUser;
|
||||
end if;
|
||||
return currentUserId;
|
||||
end; $$;
|
||||
--//
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-current-ASSUMED-ROLES:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Returns assumed role names as set in `hsadminng.assumedRoles`
|
||||
or empty array, if not set.
|
||||
*/
|
||||
create or replace function assumedRoles()
|
||||
returns varchar(63)[]
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentSubject varchar(63);
|
||||
begin
|
||||
begin
|
||||
currentSubject := current_setting('hsadminng.assumedRoles');
|
||||
exception
|
||||
when others then
|
||||
return array []::varchar[];
|
||||
end;
|
||||
if (currentSubject = '') then
|
||||
return array []::varchar[];
|
||||
end if;
|
||||
return string_to_array(currentSubject, ';');
|
||||
end; $$;
|
||||
|
||||
create or replace function pureIdentifier(rawIdentifier varchar)
|
||||
returns varchar
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return regexp_replace(rawIdentifier, '\W+', '');
|
||||
end; $$;
|
||||
|
||||
create or replace function findObjectUuidByIdName(objectTable varchar, objectIdName varchar)
|
||||
returns uuid
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
declare
|
||||
sql varchar;
|
||||
uuid uuid;
|
||||
begin
|
||||
objectTable := pureIdentifier(objectTable);
|
||||
objectIdName := pureIdentifier(objectIdName);
|
||||
sql := format('select * from %sUuidByIdName(%L);', objectTable, objectIdName);
|
||||
begin
|
||||
raise notice 'sql: %', sql;
|
||||
execute sql into uuid;
|
||||
exception
|
||||
when others then
|
||||
raise exception 'function %UuidByIdName(...) not found, add identity view support for table %', objectTable, objectTable;
|
||||
end;
|
||||
return uuid;
|
||||
end ; $$;
|
||||
|
||||
create or replace function findIdNameByObjectUuid(objectTable varchar, objectUuid uuid)
|
||||
returns varchar
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
declare
|
||||
sql varchar;
|
||||
idName varchar;
|
||||
begin
|
||||
objectTable := pureIdentifier(objectTable);
|
||||
sql := format('select * from %sIdNameByUuid(%L::uuid);', objectTable, objectUuid);
|
||||
begin
|
||||
raise notice 'sql: %', sql;
|
||||
execute sql into idName;
|
||||
exception
|
||||
when others then
|
||||
raise exception 'function %IdNameByUuid(...) not found, add identity view support for table %', objectTable, objectTable;
|
||||
end;
|
||||
return idName;
|
||||
end ; $$;
|
||||
|
||||
create or replace function currentSubjects()
|
||||
returns varchar(63)[]
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
assumedRoles varchar(63)[];
|
||||
begin
|
||||
assumedRoles := assumedRoles();
|
||||
if array_length(assumedRoles(), 1) > 0 then
|
||||
return assumedRoles();
|
||||
else
|
||||
return array [currentUser()]::varchar(63)[];
|
||||
end if;
|
||||
end; $$;
|
||||
|
||||
create or replace function currentSubjectIds()
|
||||
returns uuid[]
|
||||
stable leakproof
|
||||
language plpgsql as $$
|
||||
declare
|
||||
currentUserId uuid;
|
||||
roleNames varchar(63)[];
|
||||
roleName varchar(63);
|
||||
objectTableToAssume varchar(63);
|
||||
objectNameToAssume varchar(63);
|
||||
objectUuidToAssume uuid;
|
||||
roleTypeToAssume RbacRoleType;
|
||||
roleIdsToAssume uuid[];
|
||||
roleUuidToAssume uuid;
|
||||
begin
|
||||
currentUserId := currentUserId();
|
||||
if currentUserId is null then
|
||||
raise exception 'user % does not exist', currentUser();
|
||||
end if;
|
||||
|
||||
roleNames := assumedRoles();
|
||||
if cardinality(roleNames) = 0 then
|
||||
return array [currentUserId];
|
||||
end if;
|
||||
|
||||
raise notice 'assuming roles: %', roleNames;
|
||||
|
||||
foreach roleName in array roleNames
|
||||
loop
|
||||
roleName = overlay(roleName placing '#' from length(roleName) + 1 - strpos(reverse(roleName), '.'));
|
||||
objectTableToAssume = split_part(roleName, '#', 1);
|
||||
objectNameToAssume = split_part(roleName, '#', 2);
|
||||
roleTypeToAssume = split_part(roleName, '#', 3);
|
||||
|
||||
objectUuidToAssume = findObjectUuidByIdName(objectTableToAssume, objectNameToAssume);
|
||||
|
||||
-- TODO: either the result needs to be cached at least per transaction or we need to get rid of SELCT in a loop
|
||||
select uuid as roleuuidToAssume
|
||||
from RbacRole r
|
||||
where r.objectUuid = objectUuidToAssume
|
||||
and r.roleType = roleTypeToAssume
|
||||
into roleUuidToAssume;
|
||||
if (not isGranted(currentUserId, roleUuidToAssume)) then
|
||||
raise exception 'user % (%) has no permission to assume role % (%)', currentUser(), currentUserId, roleName, roleUuidToAssume;
|
||||
end if;
|
||||
roleIdsToAssume := roleIdsToAssume || roleUuidToAssume;
|
||||
end loop;
|
||||
|
||||
return roleIdsToAssume;
|
||||
end; $$;
|
||||
--//
|
||||
|
@ -0,0 +1,91 @@
|
||||
--liquibase formatted sql
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-views-ROLE-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Creates a view to the role table with row-level limitation
|
||||
based on the grants of the current user or assumed roles.
|
||||
*/
|
||||
drop view if exists rbacrole_rv;
|
||||
create or replace view rbacrole_rv as
|
||||
select DISTINCT r.*, o.objectTable,
|
||||
findIdNameByObjectUuid(o.objectTable, o.uuid) as objectIdName
|
||||
from rbacrole as r
|
||||
join rbacobject as o on o.uuid=r.objectuuid
|
||||
where isGranted(currentSubjectIds(), r.uuid);
|
||||
grant all privileges on rbacrole_rv to restricted;
|
||||
--//
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-views-USER-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Creates a view to the users table with row-level limitation
|
||||
based on the grants of the current user or assumed roles.
|
||||
*/
|
||||
drop view if exists RbacUser_rv;
|
||||
create or replace view RbacUser_rv as
|
||||
select u.*
|
||||
from RbacUser as u
|
||||
join RbacGrants as g on g.ascendantuuid = u.uuid
|
||||
join rbacrole_rv as r on r.uuid = g.descendantuuid;
|
||||
grant all privileges on RbacUser_rv to restricted;
|
||||
--//
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-views-OWN-GRANTED-PERMISSIONS-VIEW:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Creates a view to all permissions granted to the current user or
|
||||
based on the grants of the current user or assumed roles.
|
||||
*/
|
||||
-- @formatter:off
|
||||
drop view if exists RbacOwnGrantedPermissions_rv;
|
||||
create or replace view RbacOwnGrantedPermissions_rv as
|
||||
select r.uuid as roleuuid, p.uuid as permissionUuid,
|
||||
(r.objecttable || '#' || r.objectidname || '.' || r.roletype) as roleName, p.op,
|
||||
o.objecttable, r.objectidname, o.uuid as objectuuid
|
||||
from rbacrole_rv r
|
||||
join rbacgrants g on g.ascendantuuid = r.uuid
|
||||
join rbacpermission p on p.uuid = g.descendantuuid
|
||||
join rbacobject o on o.uuid = p.objectuuid;
|
||||
grant all privileges on RbacOwnGrantedPermissions_rv to restricted;
|
||||
-- @formatter:om
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-views-GRANTED-PERMISSIONS:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Returns all permissions granted to the given user,
|
||||
which are also visible to the current user or assumed roles.
|
||||
*/
|
||||
create or replace function grantedPermissions(userName varchar)
|
||||
returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, objectTable varchar, objectIdName varchar, objectUuid uuid)
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
-- @formatter:off
|
||||
if cardinality(assumedRoles()) > 0 then
|
||||
raise exception 'grantedPermissions(...) does not support assumed roles';
|
||||
end if;
|
||||
|
||||
return query select
|
||||
xp.roleUuid,
|
||||
(xp.objecttable || '#' || xp.objectidname || '.' || xp.roletype) as roleName,
|
||||
xp.permissionUuid, xp.op, xp.objecttable, xp.objectIdName, xp.objectuuid
|
||||
from (select
|
||||
r.uuid as roleUuid, r.roletype,
|
||||
p.uuid as permissionUuid, p.op, o.objecttable,
|
||||
findIdNameByObjectUuid(o.objectTable, o.uuid) as objectIdName,
|
||||
o.uuid as objectuuid
|
||||
from queryPermissionsGrantedToSubjectId( findRbacUserId(userName)) p
|
||||
join rbacgrants g on g.descendantuuid = p.uuid
|
||||
join rbacobject o on o.uuid = p.objectuuid
|
||||
join rbacrole r on r.uuid = g.ascendantuuid
|
||||
where isGranted(currentUserId(), r.uuid)
|
||||
) xp;
|
||||
-- @formatter:on
|
||||
end; $$;
|
@ -168,6 +168,7 @@ $$;
|
||||
*/
|
||||
create or replace function packageIdNameByUuid(uuid uuid)
|
||||
returns varchar
|
||||
stable leakproof
|
||||
language sql
|
||||
strict as $$
|
||||
select idName from package_iv iv where iv.uuid = packageIdNameByUuid.uuid;
|
||||
|
@ -9,6 +9,10 @@ databaseChangeLog:
|
||||
file: db/changelog/2022-07-28-004-uuid-ossp-extension.sql
|
||||
- include:
|
||||
file: db/changelog/2022-07-28-005-rbac-base.sql
|
||||
- include:
|
||||
file: db/changelog/2022-07-28-006-rbac-current.sql
|
||||
- include:
|
||||
file: db/changelog/2022-07-28-007-rbac-views.sql
|
||||
- include:
|
||||
file: db/changelog/2022-07-28-020-rbac-role-builder.sql
|
||||
- include:
|
||||
|
Loading…
Reference in New Issue
Block a user