Saving User Role Assignments - oracle-apex

It is possible to save User Role Assignments? When I replace application or remove it and add new with same application id, Apex removes User Role Assignments from APEX_APPL_ACL_USERS table. Actually I can create custom table to store User Role Assigments and later use to insert in APEX_APPL_ACL_USERS table, but I think isn't good solution.

There currently isn't. The safest way is to backup your user roles before replacing the app. I found that when I do an import through the UI the users are preserved, when you delete the app the users are gone. There is a great blog about how to generate a script to restore user roles.
For a single app, here is a script (mostly taken from above blog). Replace the 12345 with your application id. It generates a script that you have to execute after you have recreated your application.
WITH application_id (app_id) AS
(SELECT 12345 FROM dual)
SELECT txt
FROM (SELECT 1 x, 'BEGIN' txt FROM DUAL
UNION ALL
SELECT 2,
RPAD(' ', 3)
|| CASE
WHEN rn = 1 THEN REPLACE(q'[APEX_UTIL.set_workspace('~workspace~');]', '~workspace~', workspace)
END
|| REPLACE(
REPLACE(
REPLACE(
q'[APEX_ACL.ADD_USER_ROLE(p_application_id=>~app~,p_user_name=>'~user~',p_role_static_id=>'~role~');]',
'~app~',
application_id),
'~user~',
user_name),
'~role~',
role_static_id) txt
FROM (SELECT workspace,
ROW_NUMBER() OVER(PARTITION BY workspace ORDER BY application_id, user_name, role_static_id) rn,
application_id,
user_name,
role_static_id
FROM apex_appl_acl_user_roles
JOIN application_id a ON a.app_id = application_id)
UNION ALL
SELECT 3, ' COMMIT;' FROM DUAL
UNION ALL
SELECT 4, 'END;' FROM DUAL)
ORDER BY x;

Related

Redshift - Group Level Permissions on a Schema

I created two Groups (Confirmed using SELECT groname FROM pg_group)
Test_Group_A
Test_Group_AB
Created two External Schemas (Confirmed using SELECT schemaname FROM svv_external_schemas)
External_Schema_A
External_Schema_B
Granted permissions to these groups on external schemas, as follows:
GRANT USAGE ON SCHEMA External_Schema_A TO GROUP Test_Group_A;
GRANT USAGE ON SCHEMA External_Schema_A TO GROUP Test_Group_AB;
GRANT USAGE ON SCHEMA External_Schema_B TO GROUP Test_Group_AB;
Using metadata, how do I get the list of
Schemas that Test_Group_X and Test_Group_XY can access
OR
Groups that have access to External_Schema_X and External_Schema_Y
Thanks!
The easiest way I would think would be to operate as a member of these groups and test the permissions. The easiest way to "become" another user (while connected as a superuser) is "set session authorization 'user_name';". This will give you the rights and authorization of this user. When done you can "reset session authorization;".
SELECT
*
FROM
(
SELECT
pg_get_userbyid(b.nspowner)::text AS objowner,
b.nspname::text AS objname,
TRIM(SPLIT_PART(array_to_string(b.nspacl, ','), ',', NS.n))::text AS access_control_list_string
FROM
(
SELECT
oid,
generate_series(1, array_upper(nspacl, 1)) AS n
FROM
pg_catalog.pg_namespace
)
ns
INNER JOIN
pg_catalog.pg_namespace B
ON b.oid = ns.oid
AND ns.n <= array_upper(b.nspacl, 1)
)
WHERE
objname = '<external_schema_name>'

redshift - Not able to apply listagg function

I am getting error when trying to use listagg function.
Query
select
a.user_name,
listagg(a.group_name::text)
within group (order by a.group_name) as group_name
from (
SELECT
usename as user_name,
groname as group_name
FROM
pg_user
join
pg_group
on
pg_user.usesysid = ANY(pg_group.grolist) AND
pg_group.groname in (SELECT DISTINCT pg_group.groname from pg_group)
)a
group by user_name
Error
[Code: 500310, SQL State: XX000] Amazon Invalid operation: One or more of the used functions must be applied on at least one user created tables. Examples of user table only functions are LISTAGG, MEDIAN, PERCENTILE_CONT, etc;
None of the value is null.
Just like there are some functions that can only be run on the leader node there are some that can only be run on compute nodes - listagg() is one of these. If you need to run listagg() on leader data there are a few approaches you can use: (sorry I'm not on a cluster now so cannot test these directly - I saw your question was aging and thought I'd get you started. Grain of salt as I also cannot directly observe your issue but I think I've know what is going on.)
You can use a cursor to save the data from the leader node and use
this as the source for listagg(). A stored procedure can
streamline this. There are examples of this on stackoverflow.
You can make a temp table out of the leader node data and use this
in listagg() but I expect you will need to exit(unload) and
reenter(copy) the cluster to do this.
There just isn't a direct path from leader-node-only results to the compute nodes without some sort of this kind of push-up. Consequence of the large networked cluster architecture of Redshift.
UPDATE
I got some cluster time and there are several unexpected issues with this one. grolist is an array type that isn't generally support cluster wide and the need to user pg_group as source are key ones. So this is going to require #1 AND #2 from above.
The process goes like this:
Define cursor to hold the result of the pg_user / pg_group join select statement
Move cursor results to temp table
Use temp table as source to outer (list_agg()) select
A stored procedure can be written to do #1 and #2 which streamlines things. So you end up with the following SQL:
CREATE OR REPLACE procedure make_user_group()
AS
$$
DECLARE
row record;
BEGIN
create temp table user_group (user_name varchar(256),group_name varchar(256));
for row in SELECT
usename::text as user_name,
groname::text as group_name
FROM
pg_user
join
pg_group
on
pg_user.usesysid = ANY(pg_group.grolist) AND
pg_group.groname in (SELECT DISTINCT pg_group.groname from pg_group)
LOOP
INSERT INTO user_group(user_name,group_name) VALUES (row.user_name,row.group_name);
END LOOP;
END;
$$ LANGUAGE plpgsql;
call make_user_group();
select
user_name,
listagg(group_name::text, ', ')
within group (order by group_name) as group_name
from user_group
group by user_name;
Clearly the stored procedure only needs to be created once but called every time the temp table needs to be created.

How to give access to multiple users for same row in Data Studio for databases other than BigQuery?

To enable row level security, I used Filter By Email option as suggested here. But I want to know can I enable access to same row for multiple users and also how to enable super users who can see all rows. For example if below is the sample data then I want to have different output based on who is logged in.
userId age email
A 20 usera#gmail.com
B 15 userb#gmail.com
C 25 userc#gmail.com
Z 30 admin#gmail.com
When A is logged in
userId age email
A 20 usera#gmail.com
When B is logged in
userId age email
A 20 usera#gmail.com
B 15 userb#gmail.com
When Z is logged in
userId age email
A 20 usera#gmail.com
B 15 userb#gmail.com
C 25 userc#gmail.com
Z 30 admin#gmail.com
Update1 : I am using postgres instance for reporting (not bigQuery), so solution which make use of #DS_USER_EMAIL will not work
The filter by email simply provide you the email of the current logged user. You have to use it to filter your query. I designed a simple test like this
with sample as (
select "a" as userId, 10 as age, "usera#gmail.com" as email
UNION ALL
select "b" as userId, 20 as age, "userb#gmail.com" as email
UNION ALL
select "c" as userId, 30 as age, "userc#gmail.com" as email
), auth as (
select "usera#gmail.com" as user, "usera#gmail.com" as permission
UNION ALL
select "userb#gmail.com" as user, "usera#gmail.com" as permission
UNION ALL
select "userb#gmail.com" as user, "userb#gmail.com" as permission
UNION ALL
select "admin#gmail.com" as user, ".*" as permission
)
select * from sample
where REGEXP_CONTAINS(email,(select STRING_AGG(permission,"|") from auth where auth.user = #DS_USER_EMAIL))
I have the sample table with your data. I created a auth table with the link between the user email and the view authorization.
In the final request, I use a regex to check if the row is authorized or not. The admin has the value .* to view all the data. The other is simple an aggregation of all the rows, separated by a pipe | (OR in regex language)
EDIT
The power of BigQuery is the compliance with the SQL2011 standard, and a working query in postgres is similar. For the regex pattern use SIMILAR TO. Look at the admin regex pattern, it's not regex conventional, but it works
string_agg is an existing function
with sample as (
select 'a' as userId, 10 as age, 'usera#gmail.com' as email
UNION ALL
select 'b' as userId, 20 as age, 'userb#gmail.com' as email
UNION ALL
select 'c' as userId, 30 as age, 'userc#gmail.com' as email
), auth as (
select 'usera#gmail.com' as user, 'usera#gmail.com' as permission
UNION ALL
select 'userb#gmail.com' as user, 'usera#gmail.com' as permission
UNION ALL
select 'userb#gmail.com' as user, 'userb#gmail.com' as permission
UNION ALL
select 'admin#gmail.com' as user, '%' as permission
)
select * from sample
where email SIMILAR TO (select STRING_AGG(permission,'|') from auth where auth.user = #DS_USER_EMAIL)
The query works, but it's not usable with Datastudio because the #DS_USER_EMAIL exists only with BigQuery
The workaround is to use Cloud SQL federated query. And the final request is a mix between both db engine
with sample as (
SELECT * FROM EXTERNAL_QUERY("gbl-imt-homerider-basguillaueb.us.vertx-postgres", """ select 'a' as userId, 10 as age, 'usera#gmail.com' as email
UNION ALL
select 'b' as userId, 20 as age, 'userb#gmail.com' as email
UNION ALL
select 'c' as userId, 30 as age, 'userc#gmail.com' as email""")), auth as (
SELECT * FROM EXTERNAL_QUERY("gbl-imt-homerider-basguillaueb.us.vertx-postgres", """ select 'usera#gmail.com' as user, 'usera#gmail.com' as permission
UNION ALL
select 'userb#gmail.com' as user, 'usera#gmail.com' as permission
UNION ALL
select 'userb#gmail.com' as user, 'userb#gmail.com' as permission
UNION ALL
select 'admin#gmail.com' as user, '.*' as permission"""))
select * from sample
where REGEXP_CONTAINS(email,(select STRING_AGG(permission,"|") from auth where auth.user = #DS_USER_EMAIL))

Redshift: How to list all users in a group

Getting the list of users belonging to a group in Redshift seems to be a fairly common task but I don't know how to interpret BLOB in grolist field.
I am literally getting "BLOB" in grolist field from TeamSQL. Not so sure this is specific to TeamSQL but I kind of remember thatI got a list of IDs there instead previously in other tool
This worked for me:
select usename
from pg_user , pg_group
where pg_user.usesysid = ANY(pg_group.grolist) and
pg_group.groname='<YOUR_GROUP_NAME>';
SELECT usename, groname
FROM pg_user, pg_group
WHERE pg_user.usesysid = ANY(pg_group.grolist)
AND pg_group.groname in (SELECT DISTINCT pg_group.groname from pg_group);
This will provide the usernames along with the respective groups.
this worked better for me:
SELECT
pu.usename,
pg.groname
FROM
pg_user pu
left join pg_group pg
on pu.usesysid = ANY(pg.grolist)
order by pu.usename

How to add multiple customers to one group on opencart at once?

Is there any way to add many customers to one group at once on opencart? Its too much of a work to add 7500 customers to different groups by one by one.
If you need to add all customers to one group while you know the group ID, you can execute this SQL query in your preferred MySQL administration tool:
INSERT INTO <DB_PREFIX>customer_to_group (customer_id, group_id)
SELECT customer_id, <GROUP_ID>
FROM <DB_PREFIX>customer
Replace <DB_PREFIX> with your DB table name prefix (or none if you are not using it).
Replace <GROUP_ID> by the numeric representation of the group you want the customers to be assigned to.
You can use a similar approach if you want to insert only few customers - but again you need to know their ID's or email addresses (i.e. some unique value that could identify each customer):
INSERT INTO <DB_PREFIX>customer_to_group (customer_id, group_id)
SELECT customer_id, <GROUP_ID>
FROM <DB_PREFIX>customer
WHERE customer_id IN (<ID1>, <ID2>, <ID3>, '<ID...>')
or
INSERT INTO <DB_PREFIX>customer_to_group (customer_id, group_id)
SELECT customer_id, <GROUP_ID>
FROM <DB_PREFIX>customer
WHERE email IN ('email#address.1', 'email#address.2', 'email#address.3', '...')
Let's say you want to assign only those customers living in USA (where the country ID is <COUNTRY_ID>):
INSERT INTO <DB_PREFIX>customer_to_group (customer_id, group_id)
SELECT c.customer_id, <GROUP_ID>
FROM <DB_PREFIX>customer c
LEFT JOIN <DB_PREFIX>customer_address ca ON ca.customer_id = c.customer_id
WHERE ca.country_id = <COUNTRY_ID>
GROUP BY c.customer_id