Can I prevent execute immediate from inserting on a read-only user - sql

I have a read-only user that has to have the execute privileges to specific packages.
These packages sometimes use execute immediate to insert values into tables.
I can see why it was built this way, however I need the package to throw an Insufficient Privileges error instead of just executing the modifying statements.
Is it possible to change the behaviour or build a workaround without changing the executed packages?
So read only user has:
GRANT SELECT ON table to READ_ONLY_USER;
GRANT EXECUTE, DEBUG ON package to READ_ONLY_USER;
Package contains:
query = 'INSERT INTO table VALUES (value)';
execute immediate query;
And I need an error when the user executes the package.

Check the following example. Shortly, keyword is AUTHID CURRENT_USER while creating that PL/SQL program unit.
Connected as MIKE (who owns table and procedure and grant SCOTT privileges to use them):
SQL> show user
USER is "MIKE"
SQL>
SQL> create table test (id number);
Table created.
SQL> create or replace procedure p_test
2 authid current_user
3 is
4 begin
5 execute immediate 'insert into mike.test values (1)';
6 end;
7 /
Procedure created.
SQL> exec p_test;
PL/SQL procedure successfully completed.
SQL> select * from test;
ID
----------
1
SQL> grant select on test to scott;
Grant succeeded.
SQL> grant execute on p_test to scott;
Grant succeeded.
SQL>
Connected as SCOTT:
SQL> show user
USER is "SCOTT"
SQL>
SQL> select * From mike.test;
ID
----------
1
SQL> exec mike.p_test;
BEGIN mike.p_test; END;
*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "MIKE.P_TEST", line 5
ORA-06512: at line 1
SQL>
Without it, SCOTT is able to insert values into MIKE's table:
SQL> connect mike/lion#orcl
Connected.
SQL> create or replace procedure p_test
2 is --> no more authid current_user
3 begin
4 execute immediate 'insert into mike.test values (2)';
5 end;
6 /
Procedure created.
SQL> connect scott/tiger#orcl
Connected.
SQL> exec mike.p_test;
PL/SQL procedure successfully completed.
SQL> select * From mike.test;
ID
----------
1
2
SQL>

Related

Why does my query return no records inside a program (PL/SQL), but does when ran manually in SQL?

Hi everyone and thank you for taking the time to help me.
I have the following query:
SELECT owner, object_name
FROM all_objects
WHERE owner IN ('EDI')
ORDER BY object_type, object_name;
As you can see in the screenshot it returns some values.
When I call the query from inside a program, it is not returning any values (see second screenshot).
Test code to illustrate this is:
CREATE OR REPLACE PROCEDURE my_test
AS
BEGIN
DBMS_OUTPUT.put_line('Pre-Loop');
FOR indx IN (SELECT owner, object_name
FROM all_objects
WHERE owner IN ('EDI')
ORDER BY object_type, object_name)
LOOP
DBMS_OUTPUT.put_line('Object: ' || indx.owner || '.' || indx.object_name);
END LOOP;
DBMS_OUTPUT.put_line('Post-Loop');
END;
/
BEGIN
my_test();
END;
/
The EDI schema is brand new, so I suspect this is a grants/privileges issue, but I can't seem to find what I may be missing in order for this to work. I have tried running this as both the EDI user and SYS.
EDIT after getting an answer:
I mentioned in a comment about finding an alternative to the official answer to this question and wanted to make sure it was shared for anyone reading this later so they can weigh the decision the same.
Applying grants like EXECUTE ANY PROCEDURE or SELECT ANY TABLE to the user that is expected to run the code will work, but I am sure there are reasons not to give such wide open grants.
Your stored procedure is a definer's rights stored procedure. That means that it doesn't have access to privileges that are granted via roles only those privileges that are granted directly to the owner of the procedure. Ad hoc SQL, on the other hand, runs with the privileges of whatever roles are enabled for the current session in addition to the user's direct grants. Most likely, the owner of the procedure has access to the tables in question via roles rather than via direct grants.
You can test this by running
set role none;
and then running the ad hoc SQL statement. If my wager is right, the ad hoc SQL will now return 0 rows since you've disabled all the roles for the session.
Depending on what you are going to do with the procedure, you may be able to solve the problem by turning it into an invoker's rights stored procedure.
CREATE OR REPLACE PROCEDURE my_test
AUTHID CURRENT_USER
AS
That will cause the procedure to run with the privileges of the invoker's session (including privileges granted through roles) rather than those of the definer. Assuming that all the users you want to call the procedure will have access to the EDI tables, that should be sufficient.
This is what you have now - no result at all:
SQL> CREATE OR REPLACE PROCEDURE my_test
2 AS
3 BEGIN
4 DBMS_OUTPUT.put_line('Pre-Loop');
5
6 FOR indx IN (SELECT owner, object_name
7 FROM all_objects
8 WHERE owner IN ('SCOTT')
9 AND rownum < 5 -- you don't have that
10 ORDER BY object_type, object_name)
11 LOOP
12 DBMS_OUTPUT.put_line('Object: ' || indx.owner || '.' || indx.object_name);
13 END LOOP;
14
15 DBMS_OUTPUT.put_line('Post-Loop');
16 END;
17 /
Procedure created.
SQL> BEGIN
2 my_test();
3 END;
4 /
PL/SQL procedure successfully completed.
But, if you enable serveroutput, here it is!
SQL> set serveroutput on --> this!
SQL>
SQL> BEGIN
2 my_test();
3 END;
4 /
Pre-Loop
Object: SCOTT.BONUS
Object: SCOTT.DEPT
Object: SCOTT.EMP
Object: SCOTT.SALGRADE
Post-Loop
PL/SQL procedure successfully completed.
SQL>

how to access another user1s table in sql developer database?

BBMA.SALES_BKP TABLE IS THERE IN BBMP SCHEMA(user)
I WANT TO ACCESS "SALES_BKP TABLE" through DUMMY(its different user)
Here's how.
SQL> create user dummy identified by dummy
2 default tablespace user_data
3 temporary tablespace temp
4 quota unlimited on user_data;
User created.
SQL> grant create session, create table to dummy;
Grant succeeded.
SQL> create user bbma identified by bbma
2 default tablespace user_data
3 temporary tablespace temp
4 quota unlimited on user_data;
User created.
SQL> grant create session to bbma;
Grant succeeded.
Now, create table and let another user select from it.
SQL> connect dummy/dummy#orcl
Connected.
SQL> create table sales_bkp(id number, value number);
Table created.
SQL> insert into sales_bkp values (1, 100);
1 row created.
SQL> grant select on sales_bkp to bbma; --> this
Grant succeeded.
SQL> connect bbma/bbma#orcl
Connected.
SQL> select * from dummy.sales_bkp; --> note owner name
ID VALUE
---------- ----------
1 100
SQL>

Prevent Drop View in Oracle

How to prevent a user from not dropping a view even he/she has previlige to do so? I have a view being used by an application. However, it was dropped by a user a couple times. Is there something like REVOKE DROP ANY VIEW? Do I have to use a trigger for that?
A trigger might help. Here's an example.
First, a few objects to be dropped:
SQL> create table test as select * From emp where 1 = 2;
Table created.
SQL> create or replace view v_dept as select * From dept;
View created.
SQL>
I don't want to allow V_DEPT to be dropped, so:
SQL> create or replace trigger trg_drop
2 before drop on schema
3 declare
4 l_name varchar2(30);
5 begin
6 select ora_dict_obj_name
7 into l_name
8 from dual;
9 if l_name = 'V_DEPT' then
10 raise_application_error(-20001, 'Forbidden');
11 end if;
12 end;
13 /
Trigger created.
Testing:
SQL> drop view v_dept;
drop view v_dept
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: Forbidden
ORA-06512: at line 8
SQL> drop table test;
Table dropped.
SQL>

Disable trigger in another db(Oracle)

Can I create a procedure that disables a trigger in another database? I mean, can I disable it with a database link?
I need it for importing data into a data warehouse
Yes, you can do that. Here's how.
In a remote database (called ORCL), I'm creating a table and a trigger:
SQL> create table test (id number);
Table created.
SQL> create or replace trigger trg_test
2 before insert on test
3 for each row
4 begin
5 null;
6 end;
7 /
Trigger created.
Furthermore, in the same (remote) database, I'm creating a procedure which will disable that trigger. It'll use dynamic SQL as you can't execute DDL in PL/SQL just like that:
SQL> create or replace procedure p_disable_trg_test as
2 begin
3 execute immediate 'alter trigger trg_test disable';
4 end;
5 /
Procedure created.
Now, in a local database, I'm creating a database link to the ORCL database:
SQL> create database link dbl_scott_orcl
2 connect to scott
3 identified by tiger
4 using 'orcl';
Database link created.
Does it work?
SQL> select * from dual#dbl_scott_orcl;
D
-
X
Yes, it does. Fine. Now, all you have to do is to call the remote procedure from the local database:
SQL> begin
2 p_disable_trg_test#dbl_scott_orcl;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL>
Let's check the remote database's trigger status:
SQL> select trigger_name, status from user_Triggers where trigger_name = 'TRG_TEST';
TRIGGER_NAME STATUS
------------------------------ --------
TRG_TEST DISABLED
SQL>
DISABLED, as expected.

Oracle 9i auto increment trigger/sequence doesnt work

The following SQL, upon being executed on an Oracle 9i server, yields the the error " ORA-04098: trigger 'DBO.WTF_TRIGGER' is invalid and failed re-validation".
DROP TABLE "DBO".WTF;
CREATE TABLE "DBO".WTF
(id NUMBER PRIMARY KEY,
name VARCHAR2(30));
CREATE SEQUENCE "DBO".WTF_sequence
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER "DBO".WTF_trigger
BEFORE INSERT
ON "DBO".WTF
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT "DBO".WTF_sequence.nextval INTO :NEW.id FROM dual;
END;
INSERT INTO "DBO".WTF (name) VALUES ('asd');
Any ideas?
As APC points out, it would be helpful to do a SHOW ERRORS in SQL*Plus to print out the errors. The code you posted works perfectly for me if I create a DBO user with appropriate privileges.
SQL> conn / as sysdba
Connected.
SQL> create user dbo identified by dbo;
User created.
SQL> grant connect, resource, unlimited tablespace to dbo;
Grant succeeded.
SQL> conn dbo/dbo
Connected.
SQL> DROP TABLE "DBO".WTF;
DROP TABLE "DBO".WTF
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL>
SQL> CREATE TABLE "DBO".WTF
2 (id NUMBER PRIMARY KEY,
3 name VARCHAR2(30));
Table created.
SQL>
SQL> CREATE SEQUENCE "DBO".WTF_sequence
2 START WITH 1
3 INCREMENT BY 1;
Sequence created.
SQL>
SQL> CREATE OR REPLACE TRIGGER "DBO".WTF_trigger
2 BEFORE INSERT
3 ON "DBO".WTF
4 REFERENCING NEW AS NEW
5 FOR EACH ROW
6 BEGIN
7 SELECT "DBO".WTF_sequence.nextval INTO :NEW.id FROM dual;
8 END;
9 /
Trigger created.
SQL> INSERT INTO "DBO".WTF (name) VALUES ('asd');
1 row created.
SQL> select * from wtf;
ID NAME
---------- ------------------------------
1 asd