I'm looking for a quick easy way to revoke every privilege a user has to tables, views, etc. Is there any simple magic that can do this?
The purpose of doing this is to start fresh on what access should have.
When you find out which privileges user has, e.g.
SQL> select * From user_sys_privs;
USERNAME PRIVILEGE ADM
------------------------------ ---------------------------------------- ---
SCOTT CREATE DATABASE LINK NO
SCOTT CREATE ROLE NO
SCOTT CREATE VIEW NO
SCOTT CREATE TYPE NO
SCOTT CREATE PROCEDURE NO
SCOTT UNLIMITED TABLESPACE NO
SCOTT CREATE PUBLIC SYNONYM NO
SCOTT CREATE TABLE NO
SCOTT CREATE TRIGGER NO
SCOTT CREATE SEQUENCE NO
SCOTT CREATE SESSION NO
11 rows selected.
SQL>
then write query which will write some code for you:
SQL> select 'revoke ' || privilege || ' from scott;'
2 from user_sys_privs;
'REVOKE'||PRIVILEGE||'FROMSCOTT;'
--------------------------------------------------------
revoke CREATE DATABASE LINK from scott;
revoke CREATE VIEW from scott;
revoke CREATE ROLE from scott;
revoke UNLIMITED TABLESPACE from scott;
revoke CREATE PROCEDURE from scott;
revoke CREATE TYPE from scott;
revoke CREATE PUBLIC SYNONYM from scott;
revoke CREATE TABLE from scott;
revoke CREATE TRIGGER from scott;
revoke CREATE SESSION from scott;
revoke CREATE SEQUENCE from scott;
11 rows selected.
SQL>
Now copy/paste those revoke statements and run them.
However, that's not all. User can have additional privileges, so - as a privileged user - query DBA_SYS_PRIVS, DBA_ROLE_PRIVS, DBA_TAB_PRIVS.
In order not to think too much :), have a look at how Pete Finnigan did that. Script dates from 2003, but - it'll give you idea how to do it.
Also, probably the simplest way to do it would be to drop that user (but that's, I suppose, not an option).
I kept thinking there was some sort of REVOKE ALL command
Alas, no. Privileges are revoked (and granted) atomically, which is the way it should be. Wanting to revoke all privileges from a user is a product of the same mindset which lead to granting too many and/or too powerful privileges in the first place.
There are three classes of granted privilege:
role
system (CREATE TABLE, CREATE SESSION, etc)
object access (tables, views, procedures etc in other schemas)
Each has a different set of views over the data dictionary.
USER_ROLE_PRIVS ( also ALL_, DBA_ )
USER_SYS_PRIVS ( also ALL_, DBA_ )
USER_TABLE_PRIVS ( also ALL_, DBA_ )
We can use these views to generate REVOKE statements. It seems peculiar to do this as the user in question. So, a a power user (i.e. a DBA) execute something like this:
begin
dbms_output.put_line('Revoking granted roles ...');
for r in ( select * from dba_role_privs
where grantee = 'JOESOAP' )
loop
dbms_output.put_line('revoke ' || r.granted_role ||' from ' || r.grantee ||';');
end loop;
dbms_output.put_line('Revoking granted system privileges ...');
for r in ( select * from dba_sys_privs
where grantee = 'JOESOAP' )
loop
dbms_output.put_line('revoke ' || r.privilege ||' from ' || r.grantee ||';');
end loop;
dbms_output.put_line('granted access privileges ...');
for r in ( select * from dba_tab_privs
where grantee = 'JOESOAP' )
loop
dbms_output.put_line('revoke ' || r.privilege || ' on ' || r.owner||'.'||r.table_name ||' from ' || r.grantee ||';');
end loop;
end;
/
This will output commands to the screen - use an IDE like SQL Developer to make this less tricky - which you can review and save as an executable script. I suggest you do this rather than have the loops EXECUTE IMMEDIATE simply because you need to have a record of what privileges you've zapped, and also to stop you accidentally de-authorising something or somebody which might come back to bite you later.
In fact, rather than revoking all privileges and re-granting some of them it would be better to see all the privileges the user has and just revoke the ones which shouldn't have been granted.
Related
I use the below to grant select permission to amy on table1:
grant select schema.table1 to amy;
However, the below does not work:
grant select on schema.* to amy;
the error is
ORA-00903: invalid table name
Please advise what is wrong in my command. What I want is grant select to amy on ALL tables.
thanks
The syntax for the GRANT command (as of Oracle 21c) makes it clear that the granted item can only be a specific object:
on_object_clause:
The best you can do is create a role and grant the role to Amy, but you will still have to grant privileges on each individual table to the role.
create role analyst;
grant analyst to amy;
grant read on hr.countries to analyst;
grant read on hr.departments to analyst;
grant read on hr.employees to analyst;
To create a role and grant it to amy:
create role select_all_tables;
grant select_all_tables to amy;
alter user amy default role select_all_tables;
Use the following query to generate a script, which you can copy/paste and run to complete all the grants:
select 'grant select on '|| owner || '.' || table_name ||' to select_all_tables;'
from dba_tables where owner='SCHEMA';
copy and paste the output, and execute it as as script.
grant select on schema.table1 to select_all_tables;
grant select on schema.table2 to select_all_tables;
...
If you would rather grant the privileges directly and not use a role, alter the script query:
select 'grant select on '|| owner || '.' || table_name ||' to amy;'
from dba_tables where owner='SCHEMA';
and then run the output as a script:
grant select on schema.table1 to amy;
grant select on schema.table2 to amy;
...
grant select on table to public;
But be careful when you do that -- make sure it's what you really want to do.
Hi I want to UNLOCK a list of users from dba_users of my Oracle 12C.
I Tried Like:
ALTER USER (SELECT username FROM dba_users WHERE ACCOUNT_STATUS LIKE '%LOCKED%') ACCOUNT UNLOCK;
ERROR at line 1:
ORA-01935: missing user or role name
Any Idea ?
Or I have to do manually for each user?
One option is to write a query which will write query for you. For example:
SQL> select 'alter user ' || username || ' account unlock;' from dba_users;
'ALTERUSER'||USERNAME||'ACCOUNTUNLOCK;'
---------------------------------------------------------
alter user SUPERUSER account unlock;
alter user C##TEST account unlock;
alter user SYS account unlock;
alter user SYSTEM account unlock;
alter user ANONYMOUS account unlock;
alter user SUSHANT account unlock;
alter user SCOTT account unlock;
<snip>
Now, copy/paste the above bunch of ALTER USER statements and you'll unlock everyone.
Another is a simple PL/SQL block which uses dynamic SQL (I'm unlocking only user SCOTT; you'd unlock anyone you want).
SQL> begin
2 for cur_r in (select username from dba_users where username in ('SCOTT')) loop
3 execute immediate 'alter user ' || cur_r.username || ' account unlock';
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
I use the query CTAS to create a new table, however, when CTAS has finished, other users canĀ“t select the new table, but they had access to the old, Is it a way to pass all the users and groups to the new table? because the old table will be deleted.
"A way" is to grant (at least) select privileges to all those users.
If you used a role and granted select privilege to that role, and then granted role to those users, things would be quite simpler - just grant select privilege on the new table to the same role, and everyone will "see" it.
Otherwise, you can write query to create those grant statements for you.
For example, in Scott's schema there's the EMP table. I've previously granted privileges on it to other users in my database, and now I'm going to create a "new" CTAS table and grant privileges to the same set of users.
SQL> create table my_new_table as select * from emp;
Table created.
SQL> select 'grant select on my_new_table to ' || grantee ||';' run_me
2 from all_tab_privs_made
3 where owner = 'SCOTT'
4 and table_name = 'EMP';
RUN_ME
---------------------------------------------------------------
grant select on my_new_table to SYS;
grant select on my_new_table to SUPERUSER;
grant select on my_new_table to MY_ROLE;
grant select on my_new_table to MIKE;
Now simply copy/paste the above bunch of grant statements:
SQL> grant select on my_new_table to SYS;
Grant succeeded.
SQL> grant select on my_new_table to SUPERUSER;
Grant succeeded.
SQL> grant select on my_new_table to MY_ROLE;
Grant succeeded.
SQL> grant select on my_new_table to MIKE;
Grant succeeded.
SQL>
If there's zillion of users, PL/SQL option would be simpler as it would do everything for you (i.e. no copy/pasting):
SQL> begin
2 for cur_r in (select grantee
3 from all_tab_privs_made
4 where owner = 'SCOTT'
5 and table_name = 'EMP'
6 )
7 loop
8 execute immediate 'grant select on my_new_table to ' || cur_r.grantee;
9 end loop;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL>
If you create a table using CTAS from an existing one, the new one is a new segment, therefore it lacks of privileges. You need to recover the permissions granted to the old table and granting to the new one. For that you can use several alternatives ( dbms_metadata, dynamic sql ).
For the purposes , I'd do it like this
SQL> CREATE TABLE T2 AS SELECT * FROM T1 ;
SQL> begin
dbms_metadata.set_transform_param (dbms_metadata.session_transform,
'SQLTERMINATOR', true);
dbms_metadata.set_transform_param (dbms_metadata.session_transform, 'PRETTY',
true);
end;
/
select replace(dbms_metadata.get_dependent_ddl('OBJECT_GRANT', 'T1', 'OWNER_OF_T1' ),'T1','T2') AS ddl
from dual;
The first part is for creating in a nice format the list of necessary grants. The second part retrieves all the privileges granted to T1 and generates the list of grants statements for running to the T2 table. Then you only need to run the list of grants
As I said, there are several alternatives to do this.
Regards
I am using oracle database 11g Release 2
I am able to create user and give it create session privileges, but I am unable to give it select privilege.
create user user1 identified by pass;
User created.
grant create session to user1;
Grant succeeded.
grant select on emp to user1;
Grant succeeded.
After this I connect as user1
Now when I run this statement it say
select * from emp;
oracle reply=
ERROR at line 1:
ORA-00942: table or view does not exist
Than I checked privileges to user1 using
select * from session_privs;
PRIVILEGE
---------------------------------
CREATE SESSION
Which means only create session privilege is available to user1. How can I give select privileges to user1?
Giving a use the SELECT privilege (or any other privilege for that matter) does not create a synonym. As user1, who is not the table's owner, you should still reference the table by its fully qualified name, with the owner.
Assuming the owner is called owner1, user1's query should be:
SELECT * FROM owner1.emp
As for the data dictionary query, this is also to be expected. These privileges are recorded in the [DBA|ALL|USER]_TAB_PRIVS views:
SELECT * FROM all_tab_privs WHERE grantee = 'USER1'
We're rationalising our database user permissions and to that end we'd like to revoke all select permissions across all tables in a schema granted to all users (but not a specific role).
With some regular expressions I've tried creating a universal revoke for each table giving something like:
revoke select on TABLE1 from USER1,USER2,USER3...;
revoke select on TABLE2 from USER1,USER2,USER3...;
However as not all users were granted permissions to all tables, this results in the oracle error:
01927. 00000 - "cannot REVOKE privileges you did not grant"
Which makes sense but isn't helpful.
I also tried using All_Tab_Privs to get a list of all tables with the requisite grants to be revoked, and this works, but I can't see how to easily get from this to actually revoking the permissions.
SELECT * From All_Tab_Privs where grantor = 'GRANTING_USER' and grantee != 'READROLE' and grantee != 'PUBLIC' and grantee != 'SYS';
Any suggestions for how to do this without spending hours in a spreadsheet? I'm guessing some PL/SQL? Thanks.
A general pattern for this kind of job is to use an implicit cursor to return the data you want and then to build the DDL and execute them.
begin
for x in (select attribute_1, attribute_2 ... from ... where ...)
loop
execute immediate 'REVOKE ...'||x.attribute1||' etc';
end loop;
end;
/
A nice alternative is to build the SQL you want to execute in the SELECT and then just execute that. It's easier to test but the SQL then looks a bit clunky.
-- Revoke Privs Granted to Users
BEGIN
FOR r IN (SELECT * FROM all_tab_privs WHERE grantee IN ('USER_1', 'USER_2'))
LOOP
EXECUTE IMMEDIATE 'REVOKE '||r.privilege||' ON '||r.table_name||' FROM '||r.grantee;
END LOOP;
END;
/
Some PL/SQL and dynamic SQL:
begin
for r in (SELECT * From All_Tab_Privs
where grantor = 'GRANTING_USER'
and grantee != 'READROLE'
and grantee != 'PUBLIC'
and grantee != 'SYS')
loop
execute immediate 'revoke '||r.privilege||' from '||r.grantee;
end loop;
end;
I had a quite interesting situation on my database. Oracles own SQL Developer still listed the existing grants for each table, although they were gone from the all_tab_privs table (a SELECT brought no result for the searched grantees).
I've fixed that by using the following construct:
BEGIN
FOR r IN (SELECT owner, table_name FROM dba_tables WHERE owner IN ('owner1', 'owner2'))
LOOP
EXECUTE IMMEDIATE 'REVOKE ALL ON '||r.owner||'.'||r.table_name||' FROM grantee1, grantee2';
END LOOP;
END;
/
This first selects all owners and table names from each table of certain owners. Then it revokes all grants for certain grantees.
The good thing is, that this won't fail if there aren't any grants for one of the listed grantee for one of the selected tables.
Mind that this should be executed from an administrator account, like system, so the current user has the right to revoke grants for tables of another user.