Can only one procedure within a PL/SQL package be run with AUTHID CURRENT_USER? - oracle

I have a PL/SQL package that does not specify an AUTHID (effectively making it AUTHID DEFINER). However, there is precisely one procedure within this package that needs to run as AUTHID CURRENT_USER. Is this possible, or must I create a separate, top-level procedure?

Pretty sure a new package would be needed since the AUTHID can only be specified at the PACKAGE level (to the best of my knowledge anyway)

Though this linked question is slightly off-topic, the answer supplied by JulesLt explains that you can't specify AUTHID in a package at a level below the package level:
Executing an Oracle Stored Proc as Another User

Oracle does not allow the authid clause on a subprogram in a package or type. You will get the following error:
Error: PLS-00157: AUTHID only allowed on schema-level programs

A possible solution might be following:
You create a package with AUTHID CURRENT_USER option;
You grant select, insert, etc. to the objects that reside in the DEFINER schema that you want to use;
You use fully qualified names of the DEFINER objects.
Here is an example:
CREATE PACKAGE pkg1 AUTHID CURRENT_USER
IS
procedure insert_current_user;
procedure insert_definer;
END pkg1;
/
CREATE OR REPLACE PACKAGE BODY pkg1
IS
procedure insert_current_user
is
begin
insert into table1 values(1);
end insert_current_user;
procedure insert_definer
is
begin
insert into DEFINER.table1 values(1);
end insert_definer;
END pkg1;
/
DEFINER is the owner of the table.
As an improvement, you can create a synonym for the DEFINER.table1 table and then use the synonyms in the package.

Related

What does "IS" do in Oracle procedures?

I want to create a procedure in Oracle; however, any sample that I look on the internet, has an "IS" syntax, which I couldn't find any functionality for it.
CREATE [OR REPLACE] PROCEDURE procedure_name
[ (parameter [,parameter]) ]
IS
[declaration_section]
BEGIN
executable_section
[EXCEPTION
exception_section]
END [procedure_name];
Does anyone know what does "IS" do?
IS is part of Create procedure syntax: (can be replace with AS)
It separate the procedure definition from its contents.
The optional declaration section that follows allows you to declare local variables.
IS, in this context, tells us (and the compiler) that what follows is the body of the procedure. Its absence tells us (and the compiler) that it is merely a declaration (e.g. a forward declaration in a package body):
create or replace package body mypkg is
-- this is just a forward declaration for the procedure
procedure myproc (id in number);
-- this is the full definition of the procedure
procedure myproc (id in number)
IS
..body of myproc..;
end mypkg;
In the case of a schema-level procedure, we could (in theory) have a syntax that makes the IS optional since there is no need for forward declarations; but (thankfully) the designers of PL/SQL kept the syntax consistent with the in-package syntax so IS is still required anyway.

Oracle procedure within package with alter table throws ORA-01031:insufficient privileges

I get insufficient privileges error when executing a procedure inside a package, even though appropriate access has been granted.
CREATE OR REPLACE PACKAGE DEVELOPER.DDL_PACKS
AS
PROCEDURE disbcons
AS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TESTER.ADDRESS DISABLE CONSTRAINT PK4';
END;
END;
GRANT ALTER ON TESTER.ADDRESS TO DEVELOPER;
EXEC developer.ddl.disbcons
EDIT:
I tried adding AUTHID DEFINER in package header. But still i get the ORA-01031:insufficient privileges error when executed with DEVELOPER. user
Execution works good if i add AUTHID CURRENT_USER and execute with the same DEVELOPER user. I do not understand why oracle does not consider relevant access when executed with AUTHID DEFINER
#Vivek you can add AUTHID DEFINER/CURRENT_USER within Package specification only, I think it will work after that, below is your package specification should be:
CREATE OR REPLACE PACKAGE DEVELOPER.DDL_PACKS AUTHID CURRENT_USER
AS
PROCEDURE disbcons;
END;

Execute dynamic DDL in PL/SQL procedure through definer role permissions

I want to perform some dynamic DDL in a procedure owned by an admin user. I'd like to execute this procedure with a technical operational user with definer rights (operational user doesn't have the create table role).
The problem is the 'create table' permission is granted to the admin user through use of a role, which doesn't allow me to execute the DDL as it seems that roles don't count in named pl/sql blocks.
create or replace
PROCEDURE test_permissions AUTHID DEFINER AS
v_query_string VARCHAR2(400 CHAR) := 'CREATE TABLE TEST(abcd VARCHAR2(200 CHAR))';
BEGIN
EXECUTE IMMEDIATE v_query_string;
END;
What I tried:
Running the procedure from a function set to AUTHID DEFINER with AUTHID CURRENT_USER on the proc (hoping the function would cascade the definer somehow)
Putting an anonymous block inside the function to execute the DDL (as roles seem to count in anonymous block)
If I set the AUTHID to CURRENT_USER, I can execute the procedure correctly with the admin user.
Is there any way I can work around this without granting CREATE TABLE directly to the admin user?
You can only set a role within a PL/SQL stored procedure/function if it has Invoker's Rights (AUTHID CURRENT_USER)(see doc). Which means that you can't use ops_user to call admin_user's procedure and then access admin_user's roles. If your DBAs insist on using a role to control the CREATE TABLE privilege, here's the approach I've seen before:
create or replace package admin_user.role_test authid current_user is
procedure test_permissions;
end role_test;
/
create or replace package body admin_user.role_test is
procedure test_permissions is
v_query_string VARCHAR2(400 CHAR) := 'begin
dbms_output.put_line(''after'');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
end;';
begin
dbms_output.put_line('before');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
DBMS_SESSION.SET_ROLE('CREATE_TABLE_ROLE IDENTIFIED BY "SECRET_PASSWORD"');
execute immediate v_query_string;
DBMS_SESSION.SET_ROLE('ALL EXCEPT CREATE_TABLE_ROLE'); -- restore defaults
end;
end role_test;
/
grant execute on admin_user.role_test to ops_user;
This will temporarily grant the role to ops_user just to execute your code. By default the ops_user should not be able to view the admin_user's package body source. You could probably wrap the package body to further protect the password. But password security aside, my biggest concern with this approach is that Oracle doesn't provide a nice way to disable a single role, so if ops_user has other password-protected roles, this code might raise an ORA-01979 when it tries to restore them.
So, there's an answer, but I'd still recommend doing what the other commenters suggested and granting CREATE TABLE to your admin user.

What is the difference between stored procedure and standalone procedure in Oracle?

standlone procedure
create procedure proc1
(
begin
end;
)
stored procedure
create package pkg1
(
procedure proc2
begin
end;
)
These are both stored procedures, as they are both stored in the database and can be called later.
Putting procedures in a package is just a neat way to organize them. It helps remembering to update all the relevant procedures together, keep your creation scripts tidy, etc. The main functional difference is the ability to grant and revoke privileges on an entire package, instead of having to manage a dozen "stand-alone" procedures independently.
From the oracle documentation for CREATE PROCEDURE
A standalone procedure is a procedure (a subprogram that performs a specific action) that is stored in the database.
A nested procedure is a procedure that is in a PL/SQL block or a package.
From the CREATE PACKAGE documentation:
The CREATE PACKAGE statement creates or replaces the specification for a stored package, which is an encapsulated collection of related procedures, functions, and other program objects stored as a unit in the database. The package specification declares these objects. The package body, specified subsequently, defines these objects.
Standalone procedures and procedures nested in a package are both stored (compiled) within the database - so are "stored" procedures. Procedures defined in an anonymous PL/SQL block are not "stored" procedures.
This is not a stored procedure:
DECLARE
n NUMBER := 1;
PROCEDURE incr( a IN OUT NUMBER ) IS
BEGIN
a := a + 1;
END;
BEGIN
incr(n);
DBMS_OUTPUT.PUT_LINE(n);
END;
/
There is not a huge difference between nested procedures in packages and standalone procedures:
A standalone procedure is defined using CREATE PROCEDURE ... whereas a nested procedure is defined within the PL/SQL block using PROCEDURE ....
A standalone procedure always requires a procedure definition (the AS BEGIN ... END; part) but a (public) nested procedure in a package only declares the procedure heading (the PROCEDURE NAME(...) part) and then in the package body will restate the heading and define the procedure definition.
Nesting a procedure in a package allows it to be grouped with similar functionality and allows it to access functions, procedures and data which is private to the package (i.e. defined in the package body but not in the public package specification).

What are invoker's rights with respect to Oracle PL/SQL functions?

The first of the result_cache usage restrictions (--link) is - not defined in a module that has invoker's rights or in an anonymous block.
What does "invoker's rights" mean ? Does it mean the user_procedures.AUTHID shouldnt be "DEFINER" for this function ?
Invoker and Definer Rights When Executing Oracle PL/SQL Code
The rule you are interpreting restricts usage of certain kinds of PL/SQL code that is stored in the database cache. The types of PL/SQL code included are segments that are within:
ANONYMOUS BLOCKS (i.e., these are code snippets run through SQL Plus or some other input without actually being a part of a persistent object in the database, such as a stored procedure, function or package)
DEFINED WITH INVOKER's RIGHTS: (See Below for Explanation)
An INVOKER means that whatever USER account that executes a PL/SQL Object, the procedure runs with the privileges of that USER account instead of the customary privileges which are those of the DEFINER (owner of the object).
Tom Kyte has a good discussion thread on the topic of definer vs. invoker rights on his Ask-Tom site.
The most notable comment from the above reference is this example block of code:
In the above, if user1 created:
create or replace procedure proc1
authid current_user
as
begin
for x in ( select * from my_table ) loop
null;
end loop;
end;
/
In the following line: authid current_user, this is the comment for setting an INVOKER's rights. The table my_table in the reference has multiple possibilities:
When PROC1 is executed where the DEFINER and the INVOKER are the same, (i.e., OWNER or USER1) this table will be: USER1.MY_TABLE
When PROC1 is executed by an INVOKER or user other than the OWNER of the procedure PROC1, (i.e., USER2) this table can be one of these possible targets:
A PUBLIC owned table named MY_TABLE
A Private or Publicly owned SYNONYM for a table typed object called MY_TABLE
A local TABLE owned by USER2 (i.e., USER2.MY_TABLE) of the same name, MY_TABLE.
If the above cases are true, then there is a great deal of ambiguity surrounding the reference involved with the procedure USER1.PROC1. The actual, physical table being used are different based on the context of the invoking user identity and the accessibility/existence of aliased pointers (SYNONYMS).
The result is that the usefulness of a cached value for a procedure with INVOKER's rights enabled is questionable given the variable nature of its internal references.

Resources