improved role structure including comprised tenant sub roles
This commit is contained in:
parent
377b63ca3d
commit
d4eeb35e91
8
.run/00-util.sql.run.xml
Normal file
8
.run/00-util.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="00-util.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/00-util.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/10-rbac-base.sql.run.xml
Normal file
8
.run/10-rbac-base.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="10-rbac-base.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/10-rbac-base.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/12-rbac-role-builder.sql.run.xml
Normal file
8
.run/12-rbac-role-builder.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="12-rbac-role-builder.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/12-rbac-role-builder.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/18--rbac-all.sql.run.xml
Normal file
8
.run/18--rbac-all.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="18--rbac-all.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/18--rbac-all.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/20-hs-base.sql.run.xml
Normal file
8
.run/20-hs-base.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="20-hs-base.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/20-hs-base.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/21-hs-customer.sql.run.xml
Normal file
8
.run/21-hs-customer.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="21-hs-customer.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/21-hs-customer.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/22-hs-packages.sql.run.xml
Normal file
8
.run/22-hs-packages.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="22-hs-packages.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/22-hs-packages.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/23-hs-unixuser.sql.run.xml
Normal file
8
.run/23-hs-unixuser.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="23-hs-unixuser.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/23-hs-unixuser.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/24-hs-domain.sql.run.xml
Normal file
8
.run/24-hs-domain.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="24-hs-domain.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/24-hs-domain.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/25-hs-emailaddress.sql.run.xml
Normal file
8
.run/25-hs-emailaddress.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="25-hs-emailaddress.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/25-hs-emailaddress.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/29-hs-statistics.sql.run.xml
Normal file
8
.run/29-hs-statistics.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="29-hs-statistics.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/29-hs-statistics.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/30-run-all.sql.run.xml
Normal file
8
.run/30-run-all.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="30-run-all.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/30-run-all.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
18
.run/run all up to emailaddresses.run.xml
Normal file
18
.run/run all up to emailaddresses.run.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="run all up to statistics" type="DatabaseScript" editBeforeRun="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/00-util.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/10-rbac-base.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/12-rbac-role-builder.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/18-rbac-statistics.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/20-hs-base.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/21-hs-customer.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/22-hs-packages.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/23-hs-unixuser.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/24-hs-domain.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/25-hs-emailaddress.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/29-hs-statistics.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
@ -35,4 +35,15 @@ ELSE
|
|||||||
RETURN partial;
|
RETURN partial;
|
||||||
END IF;
|
END IF;
|
||||||
END; $$;
|
END; $$;
|
||||||
SELECT * FROM intToVarChar(211, 4);
|
|
||||||
|
select * from intToVarChar(211, 4);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION randomInRange(min INTEGER, max INTEGER)
|
||||||
|
RETURNS INT
|
||||||
|
RETURNS NULL ON NULL INPUT
|
||||||
|
language 'plpgsql' AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN floor(random() * (max-min + 1) + min);
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
select * from randomInRange(0, 4);
|
||||||
|
@ -45,7 +45,7 @@ CREATE TABLE RbacGrants
|
|||||||
CREATE INDEX ON RbacGrants (ascendantUuid);
|
CREATE INDEX ON RbacGrants (ascendantUuid);
|
||||||
CREATE INDEX ON RbacGrants (descendantUuid);
|
CREATE INDEX ON RbacGrants (descendantUuid);
|
||||||
|
|
||||||
DROP DOMAIN IF EXISTS RbacOp CASCADE;
|
-- DROP DOMAIN IF EXISTS RbacOp CASCADE;
|
||||||
CREATE DOMAIN RbacOp AS VARCHAR(67)
|
CREATE DOMAIN RbacOp AS VARCHAR(67)
|
||||||
CHECK(
|
CHECK(
|
||||||
VALUE = '*'
|
VALUE = '*'
|
||||||
@ -56,7 +56,7 @@ CREATE DOMAIN RbacOp AS VARCHAR(67)
|
|||||||
OR VALUE ~ '^add-[a-z]+$'
|
OR VALUE ~ '^add-[a-z]+$'
|
||||||
);
|
);
|
||||||
|
|
||||||
DROP TABLE IF EXISTS RbacObject;
|
-- DROP TABLE IF EXISTS RbacObject;
|
||||||
CREATE TABLE RbacObject
|
CREATE TABLE RbacObject
|
||||||
(
|
(
|
||||||
uuid uuid UNIQUE DEFAULT uuid_generate_v4(),
|
uuid uuid UNIQUE DEFAULT uuid_generate_v4(),
|
||||||
@ -80,7 +80,7 @@ BEGIN
|
|||||||
END; $$;
|
END; $$;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS RbacPermission;
|
-- DROP TABLE IF EXISTS RbacPermission;
|
||||||
CREATE TABLE RbacPermission
|
CREATE TABLE RbacPermission
|
||||||
( uuid uuid primary key references RbacReference (uuid) ON DELETE CASCADE,
|
( uuid uuid primary key references RbacReference (uuid) ON DELETE CASCADE,
|
||||||
objectUuid uuid not null,
|
objectUuid uuid not null,
|
||||||
@ -111,13 +111,15 @@ BEGIN
|
|||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION findRbacUser(userName varchar) -- TODO: rename to ...Id
|
CREATE OR REPLACE FUNCTION findRbacUserId(userName varchar)
|
||||||
RETURNS uuid
|
RETURNS uuid
|
||||||
RETURNS NULL ON NULL INPUT
|
RETURNS NULL ON NULL INPUT
|
||||||
LANGUAGE sql AS $$
|
LANGUAGE sql AS $$
|
||||||
SELECT uuid FROM RbacUser WHERE name = userName
|
SELECT uuid FROM RbacUser WHERE name = userName
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
CREATE TYPE RbacWhenNotExists AS ENUM ('fail', 'create');
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION getRbacUserId(userName varchar, whenNotExists RbacWhenNotExists)
|
CREATE OR REPLACE FUNCTION getRbacUserId(userName varchar, whenNotExists RbacWhenNotExists)
|
||||||
RETURNS uuid
|
RETURNS uuid
|
||||||
RETURNS NULL ON NULL INPUT
|
RETURNS NULL ON NULL INPUT
|
||||||
@ -125,7 +127,7 @@ CREATE OR REPLACE FUNCTION getRbacUserId(userName varchar, whenNotExists RbacWhe
|
|||||||
DECLARE
|
DECLARE
|
||||||
userUuid uuid;
|
userUuid uuid;
|
||||||
BEGIN
|
BEGIN
|
||||||
userUuid = findRbacUser(userName);
|
userUuid = findRbacUserId(userName);
|
||||||
IF ( userUuid IS NULL ) THEN
|
IF ( userUuid IS NULL ) THEN
|
||||||
IF ( whenNotExists = 'fail') THEN
|
IF ( whenNotExists = 'fail') THEN
|
||||||
RAISE EXCEPTION 'RbacUser with name="%" not found', userName;
|
RAISE EXCEPTION 'RbacUser with name="%" not found', userName;
|
||||||
@ -169,8 +171,6 @@ CREATE OR REPLACE FUNCTION findRoleId(roleName varchar)
|
|||||||
SELECT uuid FROM RbacRole WHERE name = roleName
|
SELECT uuid FROM RbacRole WHERE name = roleName
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
CREATE TYPE RbacWhenNotExists AS ENUM ('fail', 'create');
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION getRoleId(roleName varchar, whenNotExists RbacWhenNotExists)
|
CREATE OR REPLACE FUNCTION getRoleId(roleName varchar, whenNotExists RbacWhenNotExists)
|
||||||
RETURNS uuid
|
RETURNS uuid
|
||||||
RETURNS NULL ON NULL INPUT
|
RETURNS NULL ON NULL INPUT
|
||||||
@ -265,7 +265,7 @@ BEGIN
|
|||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- INSERT INTO RbacGrants (ascendantUuid, descendantUuid, apply) VALUES (superRoleId, subRoleId, doapply); -- assumeV1
|
-- INSERT INTO RbacGrants (ascendantUuid, descendantUuid, apply) VALUES (superRoleId, subRoleId, doapply); -- assumeV1
|
||||||
INSERT INTO RbacGrants (ascendantUuid, descendantUuid, follow)VALUES (superRoleId, subRoleId, doFollow)
|
INSERT INTO RbacGrants (ascendantUuid, descendantUuid, follow) VALUES (superRoleId, subRoleId, doFollow)
|
||||||
ON CONFLICT DO NOTHING ; -- TODO: remove?
|
ON CONFLICT DO NOTHING ; -- TODO: remove?
|
||||||
END; $$;
|
END; $$;
|
||||||
|
|
||||||
@ -288,7 +288,7 @@ BEGIN
|
|||||||
|
|
||||||
-- INSERT INTO RbacGrants (ascendantUuid, descendantUuid, apply) VALUES (userId, roleId, true); -- assumeV1
|
-- INSERT INTO RbacGrants (ascendantUuid, descendantUuid, apply) VALUES (userId, roleId, true); -- assumeV1
|
||||||
INSERT INTO RbacGrants (ascendantUuid, descendantUuid) VALUES (userId, roleId)
|
INSERT INTO RbacGrants (ascendantUuid, descendantUuid) VALUES (userId, roleId)
|
||||||
ON CONFLICT DO NOTHING ; -- TODO: remove
|
ON CONFLICT DO NOTHING ; -- TODO: remove?
|
||||||
END; $$;
|
END; $$;
|
||||||
|
|
||||||
abort;
|
abort;
|
||||||
@ -306,9 +306,12 @@ CREATE OR REPLACE FUNCTION nextLevel(level integer, maxDepth integer)
|
|||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|
||||||
|
abort;
|
||||||
|
set local session authorization default;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION queryAccessibleObjectUuidsOfSubjectIds(
|
CREATE OR REPLACE FUNCTION queryAccessibleObjectUuidsOfSubjectIds(
|
||||||
requiredOp RbacOp,
|
requiredOp RbacOp,
|
||||||
forObjectTable varchar, -- TODO: test perforamance in joins!
|
forObjectTable varchar, -- TODO: test performance in joins!
|
||||||
subjectIds uuid[],
|
subjectIds uuid[],
|
||||||
maxObjects integer = 16000)
|
maxObjects integer = 16000)
|
||||||
RETURNS SETOF uuid
|
RETURNS SETOF uuid
|
||||||
@ -345,12 +348,18 @@ CREATE OR REPLACE FUNCTION queryAccessibleObjectUuidsOfSubjectIds(
|
|||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
SET SESSION AUTHORIZATION DEFAULT;
|
||||||
|
CREATE ROLE admin;
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO admin;
|
||||||
|
CREATE ROLE restricted;
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO restricted;
|
||||||
|
|
||||||
abort;
|
abort;
|
||||||
set local session authorization restricted;
|
set local session authorization restricted;
|
||||||
begin transaction;
|
begin transaction;
|
||||||
set local statement_timeout TO '5s';
|
set local statement_timeout TO '15s';
|
||||||
select count(*)
|
select count(*)
|
||||||
from queryAccessibleObjectUuidsOfSubjectIds('view', 'customer', ARRAY[findRbacUser('mike@hostsharing.net')], 10000);
|
from queryAccessibleObjectUuidsOfSubjectIds('view', 'customer', ARRAY[findRbacUserId('mike@hostsharing.net')], 10000);
|
||||||
end transaction;
|
end transaction;
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -389,7 +398,7 @@ set local session authorization restricted;
|
|||||||
begin transaction;
|
begin transaction;
|
||||||
-- set local statement_timeout TO '5s';
|
-- set local statement_timeout TO '5s';
|
||||||
set local statement_timeout TO '5min';
|
set local statement_timeout TO '5min';
|
||||||
select count(*) from queryRequiredPermissionsOfSubjectIds('view', ARRAY[findRbacUser('mike@hostsharing.net')]);
|
select count(*) from queryRequiredPermissionsOfSubjectIds('view', ARRAY[findRbacUserId('mike@hostsharing.net')]);
|
||||||
end transaction;
|
end transaction;
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -424,7 +433,7 @@ abort;
|
|||||||
set local session authorization restricted;
|
set local session authorization restricted;
|
||||||
begin transaction;
|
begin transaction;
|
||||||
set local statement_timeout TO '5s';
|
set local statement_timeout TO '5s';
|
||||||
select count(*) from queryAllPermissionsOfSubjectIds(ARRAY[findRbacUser('mike@hostsharing.net')]);
|
select count(*) from queryAllPermissionsOfSubjectIds(ARRAY[findRbacUserId('mike@hostsharing.net')]);
|
||||||
end transaction;
|
end transaction;
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -564,18 +573,10 @@ CREATE OR REPLACE FUNCTION isPermissionGrantedToSubject(permissionId uuid, subje
|
|||||||
);
|
);
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
SET SESSION AUTHORIZATION DEFAULT;
|
|
||||||
CREATE ROLE admin;
|
|
||||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO admin;
|
|
||||||
CREATE ROLE restricted;
|
|
||||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO restricted;
|
|
||||||
|
|
||||||
|
|
||||||
-- ========================================================
|
-- ========================================================
|
||||||
-- Current User
|
-- current user + assumed roles
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION currentUser()
|
CREATE OR REPLACE FUNCTION currentUser()
|
||||||
RETURNS varchar(63)
|
RETURNS varchar(63)
|
||||||
STABLE LEAKPROOF
|
STABLE LEAKPROOF
|
||||||
|
208
sql/12-rbac-role-builder.sql
Normal file
208
sql/12-rbac-role-builder.sql
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- Role-Hierarcy helper functions
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE TYPE RbacRoleType AS ENUM ('owner', 'admin', 'tenant');
|
||||||
|
|
||||||
|
-- PERMISSIONS --------------------------------------------
|
||||||
|
|
||||||
|
-- drop type RbacPermissions;
|
||||||
|
CREATE TYPE RbacPermissions AS
|
||||||
|
(
|
||||||
|
permissionUuids uuid[]
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION grantingPermissions(forObjectUuid uuid, permitOps RbacOp[])
|
||||||
|
RETURNS RbacPermissions
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN ROW(createPermissions(forObjectUuid, permitOps))::RbacPermissions;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- SUPER ROLES --------------------------------------------
|
||||||
|
|
||||||
|
-- drop type RbacSuperRoles;
|
||||||
|
CREATE TYPE RbacSuperRoles AS
|
||||||
|
(
|
||||||
|
roleUuids uuid[]
|
||||||
|
);
|
||||||
|
|
||||||
|
-- drop function beneathRoles(roleName varchar);
|
||||||
|
CREATE OR REPLACE FUNCTION beneathRoles(roleNames varchar[])
|
||||||
|
RETURNS RbacSuperRoles
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
DECLARE
|
||||||
|
superRoleName varchar;
|
||||||
|
superRoleUuids uuid[] := ARRAY[]::uuid[];
|
||||||
|
BEGIN
|
||||||
|
FOREACH superRoleName IN ARRAY roleNames LOOP
|
||||||
|
superRoleUuids := superRoleUuids || getRoleId(superRoleName, 'fail');
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN ROW(superRoleUuids)::RbacSuperRoles;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- drop function beneathRole(roleName varchar);
|
||||||
|
CREATE OR REPLACE FUNCTION beneathRole(roleName varchar)
|
||||||
|
RETURNS RbacSuperRoles
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN beneathRoles(ARRAY[roleName]);
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- drop function beneathRole(roleUuid uuid);
|
||||||
|
CREATE OR REPLACE FUNCTION beneathRole(roleUuid uuid)
|
||||||
|
RETURNS RbacSuperRoles
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN ROW(ARRAY[roleUuid]::uuid[])::RbacSuperRoles;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- drop function asTopLevelRole(roleName varchar);
|
||||||
|
CREATE OR REPLACE FUNCTION asTopLevelRole()
|
||||||
|
RETURNS RbacSuperRoles
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN ROW(ARRAY[]::uuid[])::RbacSuperRoles;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- SUB ROLES ----------------------------------------------
|
||||||
|
|
||||||
|
CREATE TYPE RbacSubRoles AS
|
||||||
|
(
|
||||||
|
roleUuids uuid[]
|
||||||
|
);
|
||||||
|
|
||||||
|
-- drop FUNCTION beingItselfA(roleUuid uuid)
|
||||||
|
CREATE OR REPLACE FUNCTION beingItselfA(roleUuid uuid)
|
||||||
|
RETURNS RbacSubRoles
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN ROW(ARRAY[roleUuid]::uuid[])::RbacSubRoles;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- drop FUNCTION beingItselfA(roleName varchar)
|
||||||
|
CREATE OR REPLACE FUNCTION beingItselfA(roleName varchar)
|
||||||
|
RETURNS RbacSubRoles
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN beingItselfA(getRoleId(roleName, 'fail'));
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- USERS --------------------------------------------------
|
||||||
|
|
||||||
|
-- drop type RbacUsers;
|
||||||
|
CREATE TYPE RbacUsers AS
|
||||||
|
(
|
||||||
|
userUuids uuid[]
|
||||||
|
);
|
||||||
|
|
||||||
|
-- drop function withUsers(userNames varchar);
|
||||||
|
CREATE OR REPLACE FUNCTION withUsers(userNames varchar[])
|
||||||
|
RETURNS RbacUsers
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
DECLARE
|
||||||
|
userName varchar;
|
||||||
|
userUuids uuid[] := ARRAY[]::uuid[];
|
||||||
|
BEGIN
|
||||||
|
FOREACH userName IN ARRAY userNames LOOP
|
||||||
|
userUuids := userUuids || getRbacUserId(userName, 'fail');
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN ROW(userUuids)::RbacUsers;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
|
||||||
|
-- DROP FUNCTION withUser(userName varchar, whenNotExists RbacWhenNotExists);
|
||||||
|
CREATE OR REPLACE FUNCTION withUser(userName varchar, whenNotExists RbacWhenNotExists = 'fail')
|
||||||
|
RETURNS RbacUsers
|
||||||
|
RETURNS NULL ON NULL INPUT
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN ROW(ARRAY[getRbacUserId(userName, whenNotExists )]);
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
-- ROLE NAME BUILDER --------------------------------------
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION roleName(objectTable varchar, objectName varchar, roleType RbacRoleType )
|
||||||
|
RETURNS varchar
|
||||||
|
RETURNS NULL ON NULL INPUT
|
||||||
|
STABLE LEAKPROOF
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN objectTable || '#' || objectName || '.' || roleType;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
|
||||||
|
-- CREATE ROLE MAIN FUNCTION ------------------------------
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION createRole(
|
||||||
|
roleName varchar,
|
||||||
|
permissions RbacPermissions,
|
||||||
|
superRoles RbacSuperRoles,
|
||||||
|
subRoles RbacSubRoles = null,
|
||||||
|
users RbacUsers = null
|
||||||
|
)
|
||||||
|
RETURNS uuid
|
||||||
|
CALLED ON NULL INPUT
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
DECLARE
|
||||||
|
roleUuid uuid;
|
||||||
|
superRoleUuid uuid;
|
||||||
|
subRoleUuid uuid;
|
||||||
|
userUuid uuid;
|
||||||
|
BEGIN
|
||||||
|
RAISE NOTICE 'creating role: %', roleName;
|
||||||
|
roleUuid = createRole(roleName);
|
||||||
|
|
||||||
|
call grantPermissionsToRole(roleUuid, permissions.permissionUuids);
|
||||||
|
|
||||||
|
IF superRoles IS NOT NULL THEN
|
||||||
|
FOREACH superRoleUuid IN ARRAY superRoles.roleuUids LOOP
|
||||||
|
call grantRoleToRole(roleUuid, superRoleUuid);
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF subRoles IS NOT NULL THEN
|
||||||
|
FOREACH subRoleUuid IN ARRAY subRoles.roleuUids LOOP
|
||||||
|
call grantRoleToRole(subRoleUuid, roleUuid);
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF users IS NOT NULL THEN
|
||||||
|
FOREACH userUuid IN ARRAY users.useruUids LOOP
|
||||||
|
call grantRoleToUser(roleUuid, userUuid);
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN roleUuid;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION createRole(
|
||||||
|
roleName varchar,
|
||||||
|
permissions RbacPermissions,
|
||||||
|
users RbacUsers = null
|
||||||
|
)
|
||||||
|
RETURNS uuid
|
||||||
|
CALLED ON NULL INPUT
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN createRole(roleName, permissions, null, null, users);
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION createRole(
|
||||||
|
roleName varchar,
|
||||||
|
permissions RbacPermissions,
|
||||||
|
subRoles RbacSubRoles,
|
||||||
|
users RbacUsers = null
|
||||||
|
)
|
||||||
|
RETURNS uuid
|
||||||
|
CALLED ON NULL INPUT
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN createRole(roleName, permissions, null, subRoles, users);
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
DROP VIEW "RbacStatisticsV";
|
DROP VIEW IF EXISTS "RbacStatisticsV";
|
||||||
CREATE VIEW "RbacStatisticsV" AS
|
CREATE VIEW "RbacStatisticsV" AS
|
||||||
SELECT no, to_char("count", '9 999 999 999') as "count", "table"
|
SELECT no, to_char("count", '9 999 999 999') as "count", "table"
|
||||||
FROM (
|
FROM (
|
@ -17,40 +17,62 @@ CREATE TRIGGER createRbacObjectForCustomer_Trigger
|
|||||||
BEFORE INSERT ON customer
|
BEFORE INSERT ON customer
|
||||||
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION customerOwner(customerName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('customer', customerName, 'owner');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION customerAdmin(customerName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('customer', customerName, 'admin');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION customerTenant(customerName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('customer', customerName, 'tenant');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION createRbacRulesForCustomer()
|
CREATE OR REPLACE FUNCTION createRbacRulesForCustomer()
|
||||||
RETURNS trigger
|
RETURNS trigger
|
||||||
LANGUAGE plpgsql STRICT AS $$
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
adminUserNameUuid uuid;
|
customerOwnerUuid uuid;
|
||||||
customerOwnerRoleId uuid;
|
customerAdminUuid uuid;
|
||||||
customerAdminRoleId uuid;
|
|
||||||
BEGIN
|
BEGIN
|
||||||
IF TG_OP <> 'INSERT' THEN
|
IF TG_OP <> 'INSERT' THEN
|
||||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- an owner role is created and assigned to the administrators group
|
-- the owner role with full access for Hostsharing administrators
|
||||||
customerOwnerRoleId = createRole('customer#'||NEW.prefix||'.owner');
|
customerOwnerUuid = createRole(
|
||||||
call grantRoleToRole(customerOwnerRoleId, getRoleId('administrators', 'create'));
|
customerOwner(NEW.prefix),
|
||||||
-- ... and permissions for all ops are assigned
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||||
call grantPermissionsToRole(customerOwnerRoleId,
|
beneathRole('administrators')
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']));
|
);
|
||||||
|
|
||||||
-- ... also a customer admin role is created and granted to the customer owner role
|
-- the admin role for the customer's admins, who can view and add products
|
||||||
customerAdminRoleId = createRole('customer#'||NEW.prefix||'.admin');
|
customerAdminUuid = createRole(
|
||||||
call grantRoleToRole(customerAdminRoleId, customerOwnerRoleId, false);
|
customerAdmin(NEW.prefix),
|
||||||
-- ... to which a permission with view and add- ops is assigned
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['view', 'add-package']),
|
||||||
call grantPermissionsToRole(customerAdminRoleId,
|
-- NO auto follow for customer owner to avoid exploding permissions for administrators
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['view', 'add-package']));
|
withUser(NEW.adminUserName, 'create') -- implicitly ignored if null
|
||||||
-- if a admin user is given for the customer,
|
);
|
||||||
IF (NEW.adminUserName IS NOT NULL) THEN
|
|
||||||
-- ... the customer admin role is also assigned to the admin user of the customer
|
-- allow the customer owner role (thus administrators) to assume the customer admin role
|
||||||
adminUserNameUuid = findRoleId(NEW.adminUserName);
|
call grantRoleToRole(customerAdminUuid, customerOwnerUuid, FALSE);
|
||||||
IF ( adminUserNameUuid IS NULL ) THEN
|
|
||||||
adminUserNameUuid = createRbacUser(NEW.adminUserName);
|
-- the tenant role which later can be used by owners+admins of sub-objects
|
||||||
END IF;
|
perform createRole(
|
||||||
call grantRoleToUser(customerAdminRoleId, adminUserNameUuid);
|
customerTenant(NEW.prefix),
|
||||||
END IF;
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['view'])
|
||||||
|
);
|
||||||
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END; $$;
|
END; $$;
|
||||||
@ -109,7 +131,7 @@ DO LANGUAGE plpgsql $$
|
|||||||
BEGIN
|
BEGIN
|
||||||
SET hsadminng.currentUser TO '';
|
SET hsadminng.currentUser TO '';
|
||||||
|
|
||||||
FOR t IN 0..9999 LOOP
|
FOR t IN 0..69 LOOP
|
||||||
currentTask = 'creating RBAC test customer #' || t;
|
currentTask = 'creating RBAC test customer #' || t;
|
||||||
SET LOCAL hsadminng.currentUser TO 'mike@hostsharing.net';
|
SET LOCAL hsadminng.currentUser TO 'mike@hostsharing.net';
|
||||||
SET LOCAL hsadminng.assumedRoles = '';
|
SET LOCAL hsadminng.assumedRoles = '';
|
||||||
|
@ -11,6 +11,28 @@ CREATE TABLE IF NOT EXISTS package (
|
|||||||
customerUuid uuid REFERENCES customer(uuid)
|
customerUuid uuid REFERENCES customer(uuid)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION packageOwner(packageName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('package', packageName, 'owner');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION packageAdmin(packageName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('package', packageName, 'admin');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION packageTenant(packageName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('package', packageName, 'tenant');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS createRbacObjectForPackage_Trigger ON package;
|
DROP TRIGGER IF EXISTS createRbacObjectForPackage_Trigger ON package;
|
||||||
CREATE TRIGGER createRbacObjectForPackage_Trigger
|
CREATE TRIGGER createRbacObjectForPackage_Trigger
|
||||||
BEFORE INSERT ON package
|
BEFORE INSERT ON package
|
||||||
@ -21,8 +43,8 @@ CREATE OR REPLACE FUNCTION createRbacRulesForPackage()
|
|||||||
LANGUAGE plpgsql STRICT AS $$
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
parentCustomer customer;
|
parentCustomer customer;
|
||||||
packageOwnerRoleId uuid;
|
packageOwnerRoleUuid uuid;
|
||||||
packageTenantRoleId uuid;
|
packageAdminRoleUuid uuid;
|
||||||
BEGIN
|
BEGIN
|
||||||
IF TG_OP <> 'INSERT' THEN
|
IF TG_OP <> 'INSERT' THEN
|
||||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||||
@ -30,21 +52,27 @@ BEGIN
|
|||||||
|
|
||||||
SELECT * FROM customer AS c WHERE c.uuid=NEW.customerUuid INTO parentCustomer;
|
SELECT * FROM customer AS c WHERE c.uuid=NEW.customerUuid INTO parentCustomer;
|
||||||
|
|
||||||
-- an owner role is created and assigned to the customer's admin group
|
-- an owner role is created and assigned to the customer's admin role
|
||||||
packageOwnerRoleId = createRole('package#'||NEW.name||'.owner');
|
packageOwnerRoleUuid = createRole(
|
||||||
call grantRoleToRole(packageOwnerRoleId, getRoleId('customer#'||parentCustomer.prefix||'.admin', 'fail'));
|
packageOwner(NEW.name),
|
||||||
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||||
|
beneathRole(customerAdmin(parentCustomer.prefix))
|
||||||
|
);
|
||||||
|
|
||||||
-- ... and permissions for all ops are assigned
|
-- an owner role is created and assigned to the package owner role
|
||||||
call grantPermissionsToRole(packageOwnerRoleId,
|
packageAdminRoleUuid = createRole(
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']));
|
packageAdmin(NEW.name),
|
||||||
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['edit', 'add-unixuser']),
|
||||||
|
beneathRole(packageOwnerRoleUuid)
|
||||||
|
);
|
||||||
|
|
||||||
-- ... also a package tenant role is created and assigned to the package owner as well
|
-- and a package tenant role is created and assigned to the package admin as well
|
||||||
packageTenantRoleId = createRole('package#'||NEW.name||'.tenant');
|
perform createRole(
|
||||||
call grantRoleToRole(packageTenantRoleId, packageOwnerRoleId);
|
packageTenant(NEW.name),
|
||||||
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY ['view']),
|
||||||
-- ... to which a permission with view operation is assigned
|
beneathRole(packageAdminRoleUuid),
|
||||||
call grantPermissionsToRole(packageTenantRoleId,
|
beingItselfA(customerTenant(parentCustomer.prefix))
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['view']));
|
);
|
||||||
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END; $$;
|
END; $$;
|
||||||
@ -96,7 +124,7 @@ DO LANGUAGE plpgsql $$
|
|||||||
SET hsadminng.currentUser TO '';
|
SET hsadminng.currentUser TO '';
|
||||||
|
|
||||||
FOR cust IN (SELECT * FROM customer) LOOP
|
FOR cust IN (SELECT * FROM customer) LOOP
|
||||||
FOR t IN 0..9 LOOP
|
FOR t IN 0..randominrange(1, 2) LOOP
|
||||||
pacName = cust.prefix || TO_CHAR(t, 'fm00');
|
pacName = cust.prefix || TO_CHAR(t, 'fm00');
|
||||||
currentTask = 'creating RBAC test package #'|| pacName || ' for customer ' || cust.prefix || ' #' || cust.uuid;
|
currentTask = 'creating RBAC test package #'|| pacName || ' for customer ' || cust.prefix || ' #' || cust.uuid;
|
||||||
RAISE NOTICE 'task: %', currentTask;
|
RAISE NOTICE 'task: %', currentTask;
|
||||||
|
@ -11,6 +11,49 @@ CREATE TABLE IF NOT EXISTS UnixUser (
|
|||||||
packageUuid uuid REFERENCES package(uuid)
|
packageUuid uuid REFERENCES package(uuid)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION unixUserOwner(unixUserName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('unixuser', unixUserName, 'owner');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION unixUserAdmin(unixUserName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('unixuser', unixUserName, 'admin');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION unixUserTenant(unixUserName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('unixuser', unixUserName, 'tenant');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION createUnixUserTenantRoleIfNotExists(unixUser UnixUser)
|
||||||
|
RETURNS uuid
|
||||||
|
RETURNS NULL ON NULL INPUT
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
DECLARE
|
||||||
|
unixUserTenantRoleName varchar;
|
||||||
|
unixUserTenantRoleUuid uuid;
|
||||||
|
BEGIN
|
||||||
|
unixUserTenantRoleName = unixUserTenant(unixUser.name);
|
||||||
|
unixUserTenantRoleUuid = findRoleId(unixUserTenantRoleName);
|
||||||
|
IF unixUserTenantRoleUuid IS NOT NULL THEN
|
||||||
|
RETURN unixUserTenantRoleUuid;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN createRole(
|
||||||
|
unixUserTenantRoleName,
|
||||||
|
grantingPermissions(forObjectUuid => unixUser.uuid, permitOps => ARRAY['edit', 'add-domain']),
|
||||||
|
beneathRole(unixUserAdmin(unixUser.name))
|
||||||
|
);
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS createRbacObjectForUnixUser_Trigger ON UnixUser;
|
DROP TRIGGER IF EXISTS createRbacObjectForUnixUser_Trigger ON UnixUser;
|
||||||
CREATE TRIGGER createRbacObjectForUnixUser_Trigger
|
CREATE TRIGGER createRbacObjectForUnixUser_Trigger
|
||||||
BEFORE INSERT ON UnixUser
|
BEFORE INSERT ON UnixUser
|
||||||
@ -23,7 +66,6 @@ DECLARE
|
|||||||
parentPackage package;
|
parentPackage package;
|
||||||
unixuserOwnerRoleId uuid;
|
unixuserOwnerRoleId uuid;
|
||||||
unixuserAdminRoleId uuid;
|
unixuserAdminRoleId uuid;
|
||||||
unixuserTenantRoleId uuid;
|
|
||||||
BEGIN
|
BEGIN
|
||||||
IF TG_OP <> 'INSERT' THEN
|
IF TG_OP <> 'INSERT' THEN
|
||||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||||
@ -31,26 +73,22 @@ BEGIN
|
|||||||
|
|
||||||
SELECT * FROM package WHERE uuid=NEW.packageUuid into parentPackage;
|
SELECT * FROM package WHERE uuid=NEW.packageUuid into parentPackage;
|
||||||
|
|
||||||
-- an owner role is created and assigned to the package owner group
|
-- an owner role is created and assigned to the package's admin group
|
||||||
unixuserOwnerRoleId = createRole('unixuser#'||NEW.name||'.owner');
|
unixuserOwnerRoleId = createRole(
|
||||||
call grantRoleToRole(unixuserOwnerRoleId, getRoleId('package#'||parentPackage.name||'.owner', 'fail'));
|
unixUserOwner(NEW.name),
|
||||||
-- ... and permissions for all ops are assigned
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||||
call grantPermissionsToRole(unixuserOwnerRoleId,
|
beneathRole(packageAdmin(parentPackage.name))
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']));
|
);
|
||||||
|
|
||||||
-- ... also a unixuser admin role is created and assigned to the unixuser owner as well
|
-- and a unixuser admin role is created and assigned to the unixuser owner as well
|
||||||
unixuserAdminRoleId = createRole('unixuser#'||NEW.name||'.admin');
|
unixuserAdminRoleId = createRole(
|
||||||
call grantRoleToRole(unixuserAdminRoleId, unixuserOwnerRoleId);
|
unixUserAdmin(NEW.name),
|
||||||
-- ... to which a permission with view operation is assigned
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['edit', 'add-domain']),
|
||||||
call grantPermissionsToRole(unixuserAdminRoleId,
|
beneathRole(unixuserOwnerRoleId),
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['edit', 'add-domain']));
|
beingItselfA(packageTenant(parentPackage.name))
|
||||||
|
);
|
||||||
|
|
||||||
-- ... also a unixuser tenant role is created and assigned to the unixuser admin
|
-- a tenent role is only created on demand
|
||||||
unixuserTenantRoleId = createRole('unixuser#'||NEW.name||'.tenant');
|
|
||||||
call grantRoleToRole(unixuserTenantRoleId, unixuserAdminRoleId);
|
|
||||||
-- ... to which a permission with view operation is assigned
|
|
||||||
call grantPermissionsToRole(unixuserTenantRoleId,
|
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['view']));
|
|
||||||
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END; $$;
|
END; $$;
|
||||||
|
@ -16,12 +16,35 @@ CREATE TRIGGER createRbacObjectForDomain_Trigger
|
|||||||
BEFORE INSERT ON Domain
|
BEFORE INSERT ON Domain
|
||||||
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION domainOwner(unixUserName varchar, domainName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('domain', unixUserName || '/' || domainName, 'owner');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION domainAdmin(unixUserName varchar, domainName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('domain', unixUserName || '/' || domainName, 'admin');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION domainTenant(unixUserName varchar, domainName varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('domain', unixUserName || '/' || domainName, 'tenant');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION createRbacRulesForDomain()
|
CREATE OR REPLACE FUNCTION createRbacRulesForDomain()
|
||||||
RETURNS trigger
|
RETURNS trigger
|
||||||
LANGUAGE plpgsql STRICT AS $$
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
parentUser unixuser;
|
parentUser unixuser;
|
||||||
domainOwnerRoleId uuid;
|
domainOwnerRoleUuid uuid;
|
||||||
|
domainAdminRoleUuid uuid;
|
||||||
BEGIN
|
BEGIN
|
||||||
IF TG_OP <> 'INSERT' THEN
|
IF TG_OP <> 'INSERT' THEN
|
||||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||||
@ -29,13 +52,27 @@ BEGIN
|
|||||||
|
|
||||||
SELECT * FROM unixuser WHERE uuid=NEW.unixUserUuid into parentUser;
|
SELECT * FROM unixuser WHERE uuid=NEW.unixUserUuid into parentUser;
|
||||||
|
|
||||||
-- an owner role is created and assigned to the unix user admin
|
-- a domain owner role is created and assigned to the unixuser's admin role
|
||||||
RAISE NOTICE 'creating domain owner role: %', 'domain#'||NEW.name||'.owner';
|
domainOwnerRoleUuid = createRole(
|
||||||
domainOwnerRoleId = getRoleId('domain#'||NEW.name||'.owner', 'create');
|
domainOwner(parentUser.name, NEW.name),
|
||||||
call grantRoleToRole(domainOwnerRoleId, getRoleId('unixuser#'||parentUser.name||'.admin', 'fail'));
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||||
-- ... and permissions for all ops are assigned
|
beneathRole(unixUserAdmin(parentUser.name))
|
||||||
call grantPermissionsToRole(domainOwnerRoleId,
|
);
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']));
|
|
||||||
|
-- a domain admin role is created and assigned to the domain's owner role
|
||||||
|
domainAdminRoleUuid = createRole(
|
||||||
|
domainAdmin(parentUser.name, NEW.name),
|
||||||
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['edit', 'add-emailaddress']),
|
||||||
|
beneathRole(domainOwnerRoleUuid)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- and a domain tenant role is created and assigned to the domain's admiin role
|
||||||
|
perform createRole(
|
||||||
|
domainTenant(parentUser.name, NEW.name),
|
||||||
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||||
|
beneathRole(domainAdminRoleUuid),
|
||||||
|
beingItselfA(createUnixUserTenantRoleIfNotExists(parentUser))
|
||||||
|
);
|
||||||
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END; $$;
|
END; $$;
|
||||||
@ -74,7 +111,7 @@ DO LANGUAGE plpgsql $$
|
|||||||
|
|
||||||
FOR uu IN (SELECT * FROM unixuser) LOOP
|
FOR uu IN (SELECT * FROM unixuser) LOOP
|
||||||
IF ( random() < 0.3 ) THEN
|
IF ( random() < 0.3 ) THEN
|
||||||
FOR t IN 0..2 LOOP
|
FOR t IN 0..1 LOOP
|
||||||
currentTask = 'creating RBAC test Domain #' || t || ' for UnixUser ' || uu.name|| ' #' || uu.uuid;
|
currentTask = 'creating RBAC test Domain #' || t || ' for UnixUser ' || uu.name|| ' #' || uu.uuid;
|
||||||
RAISE NOTICE 'task: %', currentTask;
|
RAISE NOTICE 'task: %', currentTask;
|
||||||
|
|
||||||
@ -85,7 +122,7 @@ DO LANGUAGE plpgsql $$
|
|||||||
SET LOCAL hsadminng.currentTask TO currentTask;
|
SET LOCAL hsadminng.currentTask TO currentTask;
|
||||||
|
|
||||||
INSERT INTO Domain (name, unixUserUuid)
|
INSERT INTO Domain (name, unixUserUuid)
|
||||||
VALUES ('dom-' || t || '.' || pac.name || '.example.org' , uu.uuid);
|
VALUES ('dom-' || t || '.' || uu.name || '.example.org' , uu.uuid);
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
@ -16,35 +16,51 @@ CREATE TRIGGER createRbacObjectForEMailAddress_Trigger
|
|||||||
BEFORE INSERT ON EMailAddress
|
BEFORE INSERT ON EMailAddress
|
||||||
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION emailAddressOwner(emailAddress varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('emailaddress', emailAddress, 'owner');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION emailAddressAdmin(emailAddress varchar)
|
||||||
|
RETURNS varchar
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
begin
|
||||||
|
return roleName('emailaddress', emailAddress, 'admin');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION createRbacRulesForEMailAddress()
|
CREATE OR REPLACE FUNCTION createRbacRulesForEMailAddress()
|
||||||
RETURNS trigger
|
RETURNS trigger
|
||||||
LANGUAGE plpgsql STRICT AS $$
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
|
parentDomain record;
|
||||||
eMailAddress varchar;
|
eMailAddress varchar;
|
||||||
parentDomain domain;
|
eMailAddressOwnerRoleUuid uuid;
|
||||||
eMailAddressOwnerRoleId uuid;
|
|
||||||
eMailAddressTenantRoleId uuid;
|
|
||||||
BEGIN
|
BEGIN
|
||||||
IF TG_OP <> 'INSERT' THEN
|
IF TG_OP <> 'INSERT' THEN
|
||||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
SELECT * FROM domain WHERE uuid=NEW.domainUuid into parentDomain;
|
SELECT d.name as name, u.name as unixUserName FROM domain d
|
||||||
|
LEFT JOIN unixuser u ON u.uuid = d.unixuseruuid
|
||||||
|
WHERE d.uuid=NEW.domainUuid into parentDomain;
|
||||||
eMailAddress = NEW.localPart || '@' || parentDomain.name;
|
eMailAddress = NEW.localPart || '@' || parentDomain.name;
|
||||||
|
|
||||||
-- an owner role is created and assigned to the domain owner
|
-- an owner role is created and assigned to the domains's admin group
|
||||||
eMailAddressOwnerRoleId = getRoleId('emailaddress#'||eMailAddress||'.owner', 'create');
|
eMailAddressOwnerRoleUuid = createRole(
|
||||||
call grantRoleToRole(eMailAddressOwnerRoleId, getRoleId('domain#'||parentDomain.name||'.owner', 'fail'));
|
emailAddressOwner(eMailAddress),
|
||||||
-- ... and permissions for all ops are assigned
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||||
call grantPermissionsToRole(eMailAddressOwnerRoleId,
|
beneathRole(domainAdmin( parentDomain.unixUserName, parentDomain.name))
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']));
|
);
|
||||||
|
|
||||||
-- a tenant role is created and assigned to a user with the new email address
|
-- and an admin role is created and assigned to the unixuser owner as well
|
||||||
eMailAddressTenantRoleId = getRoleId('emailaddress#'||eMailAddress||'.tenant', 'create');
|
perform createRole(
|
||||||
call grantRoleToUser(eMailAddressTenantRoleId, getRbacUserId(eMailAddress, 'create'));
|
emailAddressAdmin(eMailAddress),
|
||||||
-- ... and permissions for all ops are assigned
|
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['edit']),
|
||||||
call grantPermissionsToRole(eMailAddressTenantRoleId,
|
beneathRole(eMailAddressOwnerRoleUuid),
|
||||||
createPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*'])); -- TODO '*' -> 'edit', 'view'
|
beingItselfA(domainTenant(parentDomain.unixUserName, parentDomain.name))
|
||||||
|
);
|
||||||
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END; $$;
|
END; $$;
|
||||||
@ -59,22 +75,6 @@ CREATE TRIGGER createRbacRulesForEMailAddress_Trigger
|
|||||||
|
|
||||||
-- create RBAC restricted view
|
-- create RBAC restricted view
|
||||||
|
|
||||||
abort;
|
|
||||||
set session authorization default ;
|
|
||||||
START TRANSACTION;
|
|
||||||
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
|
||||||
SET LOCAL hsadminng.assumedRoles = 'customer#bbb.owner;customer#bbc.owner';
|
|
||||||
-- SET LOCAL hsadminng.assumedRoles = 'package#bbb00.owner;package#bbb01.owner';
|
|
||||||
|
|
||||||
select count(*) from queryAccessibleObjectUuidsOfSubjectIds( 'view', currentSubjectIds(), 7) as a
|
|
||||||
join rbacobject as o on a=o.uuid;
|
|
||||||
|
|
||||||
/* SELECT DISTINCT target.*
|
|
||||||
FROM EMailAddress AS target
|
|
||||||
JOIN queryAccessibleObjectUuidsOfSubjectIds( 'view', currentSubjectIds()) AS allowedObjId
|
|
||||||
ON target.uuid = allowedObjId;*/
|
|
||||||
END TRANSACTION;
|
|
||||||
|
|
||||||
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||||
ALTER TABLE EMailAddress ENABLE ROW LEVEL SECURITY;
|
ALTER TABLE EMailAddress ENABLE ROW LEVEL SECURITY;
|
||||||
DROP VIEW IF EXISTS EMailAddress_rv;
|
DROP VIEW IF EXISTS EMailAddress_rv;
|
||||||
@ -99,7 +99,7 @@ DO LANGUAGE plpgsql $$
|
|||||||
SET hsadminng.currentUser TO '';
|
SET hsadminng.currentUser TO '';
|
||||||
|
|
||||||
FOR dom IN (SELECT * FROM domain) LOOP
|
FOR dom IN (SELECT * FROM domain) LOOP
|
||||||
FOR t IN 0..5 LOOP
|
FOR t IN 0..4 LOOP
|
||||||
currentTask = 'creating RBAC test EMailAddress #' || t || ' for Domain ' || dom.name;
|
currentTask = 'creating RBAC test EMailAddress #' || t || ' for Domain ' || dom.name;
|
||||||
RAISE NOTICE 'task: %', currentTask;
|
RAISE NOTICE 'task: %', currentTask;
|
||||||
|
|
||||||
|
@ -35,16 +35,18 @@ ROLLBACK;
|
|||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
SET SESSION SESSION AUTHORIZATION restricted;
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
SET LOCAL hsadminng.assumedRoles = 'customer#bbb.admin;customer#bbc.admin';
|
SET LOCAL hsadminng.assumedRoles = 'customer#aab.admin;customer#aac.admin';
|
||||||
SELECT * FROM package_rv p;
|
SELECT * FROM package_rv p;
|
||||||
END TRANSACTION;
|
END TRANSACTION;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
-- hostsharing admin assuming two customer admin role and listing all accessible unixusers
|
-- hostsharing admin assuming two customer admin role and listing all accessible unixusers
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
SET SESSION SESSION AUTHORIZATION restricted;
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
SET LOCAL hsadminng.assumedRoles = 'customer#bbb.admin;customer#bbc.admin';
|
SET LOCAL hsadminng.assumedRoles = 'customer#aab.admin;customer#aac.admin';
|
||||||
|
|
||||||
SELECT c.prefix, c.reference, uu.*
|
SELECT c.prefix, c.reference, uu.*
|
||||||
FROM unixuser_rv uu
|
FROM unixuser_rv uu
|
||||||
@ -52,10 +54,12 @@ FROM unixuser_rv uu
|
|||||||
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
||||||
END TRANSACTION;
|
END TRANSACTION;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
SET SESSION SESSION AUTHORIZATION restricted;
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
SET LOCAL hsadminng.assumedRoles = 'customer#bbb.admin;customer#bbc.admin';
|
SET LOCAL hsadminng.assumedRoles = 'customer#aab.admin;customer#aac.admin';
|
||||||
|
|
||||||
SELECT p.name, uu.name, dom.name
|
SELECT p.name, uu.name, dom.name
|
||||||
FROM domain_rv dom
|
FROM domain_rv dom
|
||||||
@ -64,24 +68,26 @@ FROM domain_rv dom
|
|||||||
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
||||||
END TRANSACTION;
|
END TRANSACTION;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
SET SESSION SESSION AUTHORIZATION restricted;
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
SET LOCAL hsadminng.assumedRoles = 'customer#bbb.admin;customer#bbc.admin';
|
SET LOCAL hsadminng.assumedRoles = 'customer#aab.admin;customer#aac.admin';
|
||||||
-- TODO: we need tenant roles on parent objects
|
|
||||||
-- SET LOCAL hsadminng.assumedRoles = 'package#bbb03.owner;package#bbb08.owner';
|
|
||||||
|
|
||||||
SELECT p.name as "package", ema.localPart || '@' || dom.name as "email-address"
|
SELECT c.prefix, p.name as "package", ema.localPart || '@' || dom.name as "email-address"
|
||||||
FROM emailaddress_rv ema
|
FROM emailaddress_rv ema
|
||||||
JOIN domain_rv dom ON dom.uuid = ema.domainuuid
|
JOIN domain_rv dom ON dom.uuid = ema.domainuuid
|
||||||
JOIN unixuser_rv uu ON uu.uuid = dom.unixuseruuid
|
JOIN unixuser_rv uu ON uu.uuid = dom.unixuseruuid
|
||||||
JOIN package_rv p ON p.uuid = uu.packageuuid
|
JOIN package_rv p ON p.uuid = uu.packageuuid
|
||||||
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
||||||
END TRANSACTION;
|
END TRANSACTION;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
SET SESSION SESSION AUTHORIZATION restricted;
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
select * from customer_rv c where c.prefix='bbb';
|
select * from customer_rv c where c.prefix='aab';
|
||||||
END TRANSACTION;
|
END TRANSACTION;
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
DROP VIEW IF EXISTS "BusinessTableStatisticsV";
|
DROP VIEW IF EXISTS "BusinessTableStatisticsV";
|
||||||
CREATE VIEW "BusinessTableStatisticsV" AS
|
CREATE VIEW "BusinessTableStatisticsV" AS
|
||||||
SELECT no, to_char("count", '999 999 999') as "count", to_char("required", '999 999 999') as "required", to_char("count"::float/"required"::float, '990.9') as "factor", "table"
|
SELECT no, to_char("count", '999 999 999') as "count", to_char("required", '999 999 999') as "required", to_char("count"::float/"required"::float, '990.999') as "factor", "table"
|
||||||
FROM (select 1 as no, count(*) as "count", 7000 as "required", 'customers' as "table"
|
FROM (select 1 as no, count(*) as "count", 7000 as "required", 'customers' as "table"
|
||||||
from customer
|
from customer
|
||||||
UNION
|
UNION
|
||||||
@ -22,3 +22,5 @@ FROM (select 1 as no, count(*) as "count", 7000 as "required", 'customers' as "
|
|||||||
from emailaddress
|
from emailaddress
|
||||||
) totals
|
) totals
|
||||||
ORDER BY totals.no;
|
ORDER BY totals.no;
|
||||||
|
|
||||||
|
SELECT * FROM "BusinessTableStatisticsV";
|
||||||
|
Loading…
Reference in New Issue
Block a user