Skip to Main Content
  • Questions
  • How does invoker´s rights solve the PL/SQL privs problem

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Andre.

Asked: October 26, 2000 - 8:21 am UTC

Last updated: April 28, 2009 - 10:54 am UTC

Version: 8.1.6

Viewed 1000+ times

You Asked

Hi Tom !

In a previous question, I asked:

........................................................

I have both MDA and CORPORATE schemas. MDA has been granted
"ALL" table privileges to access CORPORATE through a role. When
I compile a procedure as MDA, accessing a table in CORPORATE´s
schema I get an error. What can be wrong ?

SQL> show useruser is "MDA"
SQL> desc CORPORATE.DIRECT_CAD Name Null? Type
------------------------------- -------- ----
CUR_ACCT_NBR NOT NULL NUMBER(11)
EFF_DATE NOT NULL DATE
ESTAB_DATE DATE
CHNNL_SALES_CODE VARCHAR2(2)
KIT_FLAG_CODE CHAR(1)
FIRST_MOV_DATE DATE
LAST_MOV_DATE DATE
CONNECT_MTH_AVG VARCHAR2(5)
ACTV_CUST_ID CHAR(1)

SQL> CREATE OR REPLACE PROCEDURE MDA.TRUNCATE_TABLE ......

IF p_Eff_Date = '0' THEN
SELECT max(EFF_DATE)
INTO DtCurr_RepDate
FROM CORPORATE.DIRECT_CAD;
-- Only place CORPORATE.DIRECT_CAD referenced
ELSE...
END TRUNCATE_TABLE;
/

Warning: Procedure created with compilation errors.

SQL> show err

Errors for PROCEDURE MDA.TRUNCATE_TABLE:
LINE/COL ERROR--------
-----------------------------------------------------------------
15/9 PL/SQL: SQL Statement ignored
17/16 PLS-00201: identifier 'CORPORATE.DIRECT_CAD' must be declared

................................................

You answered:

see
</code> http://asktom.oracle.com/~tkyte/Misc/RolesAndProcedures.html <code>

.................................................

Thanks ! A read about this "phenomenon": The PL/SQL block´s owner must be explicitly granted the privileges, and not through a role.

However, this same article says that invoker´s rights bypass this problem.

Could you please elaborate on that ?

Thanks again !!!

and Tom said...

Prior to Oracle8i, all compiled stored objects executed with the privileges and namespace of the definer of the object. That is, the set of privileges granted directly to the definer (owner) of the stored object were used at compile time to figure out

ć What objects (tables and so on) to access.
ć Whether you were in fact allowed to access them.

This static compile time binding went as far as to limit the set of privileges to on the privileges granted to the definer directly (eg: no roles were ever enabled during the compilation or execution of a stored procedure, trigger or view). This is predominantly a performance optimization and typically is not a burden (it is truly a feature).

Beginning in Oracle8i, we have a feature called Invokers rights which allows us to create procedures that do not follow these rules. We can now develop a stored procedure that executes with the privilege set of the INVOKER (the currently logged in user) at runtime. This allows us to create a stored procedure that might execute properly and correctly for one user (they had access to all of the relevant objects) but not for another (who didn¡¦t). This is because the access to the underlying objects is not defined at compile time (although the definer must have access to these objects ¡V or at least objects with those names in order to compile the PLSQL code) but rather at runtime ¡V based on the current user.


In your case above however -- it will not solve the issue. When we compile a procedure (definer or invoker) we will check that:

ć All of the objects it statically accesses (anything not accessed via dynamic SQL) are verified for existence. Names are resolved via the standard scoping rules as they apply to the definer of the procedure. ROLES are not enabled.

ƒá All of the objects it accesses are verified to ensure that the required access mode will be available. That is, if an attempt to UPDATE T is made ¡V Oracle will verify the definer or PUBLIC has the ability to UPDATE T without use of any ROLES.

ć A dependency between this procedure and the referenced objects is setup and maintained. If this procedure SELECTS FROM T, then a dependency between T and this procedure is recorded


What this means is that a invokers rights routine, at compile time, is treated exactly the same as a definers rights routine. This is an area of confusion for many. They have heard ¡§roles are enabled in invokers rights routines¡¨ and that statement is in fact accurate HOWEVER (and this is a big however), they are not in effect during the compilation process. That means that the person who compiles the stored procedure, the owner of the stored procedure, still needs to have direct access to all statically referenced tables. The rules spelled out in the Application Developers Guide on ¡§Privileges Required to Create Procedures and Functions¡¨ remain in place. You need direct access to the underlying objects.


What is changes is the runtime behavior. Let's say you compiled your procedure above (after getting direct access). You grant execute on it to BOB. When BOB runs it -- the access to CORPORATE.DIRECT_CAD will be evaluated under BOB's account -- not MDA's account. Even though MDA can access it -- it does not mean that BOB can via this procedure. Therein lies the MAJOR difference for IR (invokers rights) over DR (definers rights) routines.

Now, if you coded the above routine as:


execute immediate 'SELECT max(EFF_DATE)
FROM CORPORATE.DIRECT_CAD'
INTO DtCurr_RepDate;

Then, we would be in business. MDA would not need access to corporate.direct_cad at all (ever) but anyone who RAN the procedure would access to it either directly OR via a role.





Rating

  (6 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

What the problem?

Yushiyin, January 23, 2002 - 6:14 am UTC

1.
ysy1@DB28> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle8i Enterprise Edition Release 8.1.6.0.0 - 64bit Production
PL/SQL Release 8.1.6.0.0 - Production
CORE 8.1.6.0.0 Production
TNS for Solaris: Version 8.1.6.0.0 - Production
NLSRTL Version 3.4.0.0.0 - Production

ysy1@DB28>

2.
ysy1@DB28> conn ysy/ysy@db28
connected.
ysy1@DB28> create table t1 (a varchar2(10));

3.
ysy1@DB28> create user ysy1 identified by ysy1
2 default tablespace ysy
3 temporary tablespace temp;

ysy1@DB28> grant create session to ysy1;
ysy1@DB28> grant create procedure to ysy1;
ysy1@DB28> grant select any table to ysy1;

4.
ysy1@DB28> conn ysy1/ysy1@db28
ysy1@DB28> create or replace procedure p1
2 as
3 num number;
4 begin
5 select count(*) into num from ysy.t1;
6 end;
7 /
procedure created.


what's the problem?! why not show PLS-00201 ERROR?
(PLS-00201: identifier 'YSY.T1' must be declared.)
One of my database can create the procedure without the problem,but the other can create the error! what's the problem?



Tom Kyte
January 23, 2002 - 7:32 am UTC

you granted select any table directly to ysy1.

that is why you can create the procedure, ysy1 can select from ANY table.


I will guess that in your other database, the user does not have select any table or, if they do, they have it via a role and as described -- thats not good enough.

select any table is too powerful for my tastes, suggest you use finer grained privs.

On a similar note.....

RP, March 02, 2006 - 8:10 am UTC

Hi Tom,

there's alot of material on the site about definer/invoker rights but its still not going into my head!!!

User a creates a package with a single proc:

PROCEDURE get_roles(p_roles OUT SYS_REFCURSOR) IS
BEGIN
OPEN p_roles FOR
SELECT granted_role
FROM user_role_privs;

END get_roles;

The account a has no roles, only direct grants.

The dba account creates a role called ROLE_YOURROLES. Grant execute on the proc is given to the role.

User b is given the role ROLE_YOURROLES.

b runs the proc and gets - no rows. I need it to return b's roles (in this case ROLE_YOURROLES).

So i'm guessing its geting the roles for user a (ie no roles). I did a select user from dual and it returns b which is why i'm getting confused.

This is an important package in my app as every user will be running it (via a role)so the java app can find out what they can do.

what do i do?

Thanks

RP

Tom Kyte
March 02, 2006 - 12:32 pm UTC

the USER_ views all use "userenv('schemaid')" in them to restrict the data returned.

Therefore, if you access a USER_ (or ALL_) - you get the information for the current schema - which in that definers rights procedure - is the OWNER of the procedure.

that view for example has:

where sa.grantee# in (userenv('SCHEMAID'),1) and sa.grantee#=ud.user#(+)
and sa.privilege#=ud.role#(+) and u1.user#=sa.grantee#
and u2.user#=sa.privilege#
group by decode(sa.grantee#,1,'PUBLIC',u1.name),u2.name


in it - it goes after the current schema, the authorization schema - which is not the invoker.


You would have to use the DBA_ views and restrict the rows as you see appropriate, not the USER and ALL views.

an update

RP, March 02, 2006 - 8:19 am UTC

Hi Tom,

i checked the developers manual and added the AUTHID CURRENT_USER clause to the package spec and it now works.

It is ok like this right?

Cheers

RP

Tom Kyte
March 02, 2006 - 12:38 pm UTC

well, if someone calls that procedure from another procedure that is a definers rights procedure, back to square one :)

depends on what you define as being the right answer.

Use case for invokers rights

Tom, January 03, 2007 - 10:49 am UTC

Hi tom,

As part of our applications we have a common set of utility packages to make common operations simpler. For maintenance and performance reasons we obviously want to move these packages into a shared schema so we only have one copy to maintain. These packages are to be used from definer's rights packages in the individual applications.

The one problem I have is that some of the packages are used to make using dynamic sql easier. Am I right in thinking the following

1. Any package in the shared schema which is intended for dynamic sql [i.e. accessing tables in the schema containing the definers rights procedure] will have to be authid current_schema
2. Any package in the shared schema which uses any of these packages must also be authid current_user [since the invoker is then that procedure] and so on down the dependency chain.
2. I cannot make individual procedures authid current_user inside a package

For example, I have a package "A" which contains a function which allows me to pass in an array of variables to bind. I then have a package "B" which exports a given table to CSV [which uses the original package]. In this case, both package "A" and package "B" must be authid current_user.

Finally, would you suggest this is the correct approach for shared library functions?

What object types inherits the privileges of the current user?

Lise, February 23, 2009 - 7:04 am UTC

Hi,
Imagine I have procedure A in schema A that calls procedure B in schema B, where procedure B has been defined with invoker rights.
Schema A holds a synonym to schema B pointing to procedure B.
When I execute procedure A in schema A, and it calls procedure B, any DDL statements will be executed on the tables held in schema A.
However, I also thought that this would be the case for any PLSQL that is being called within procedure B.
So, if procedure B called procedure C that was declared in both schema A and B, when procedure A run it would use procedure C in schema A and not schema B.

Sorry, this sounds perhaps a bit confusing.

Thanks
Tom Kyte
February 23, 2009 - 7:13 am UTC

code is linked at compile time, not run time.

So, when procedure B was compiled, the linkage to C would be figured out right then, right there.


DDL??? you cannot do DDL in plsql directly, you would use dynamic sql and that is always done "at runtime"


So, if procedure B had:

procedure b
is
begin
C; <<-- statically compiled and figured out at COMPILE time.
execute immediate 'begin c; end;'; <<=== dynamically figured out at RUNTIME, since this was invokers rights - it would be the procedure the invoker sees.

Different behaviour with AUTONOMOUS_TRANSACTION

Isaac Chocron, April 28, 2009 - 10:27 am UTC

Hello,

I checked a similar case to Lise (with DDL statement) , but if the procedure B was defined with pragma autonomous_transaction, I think that B run with Definer rights and not with Invoker rights.
Tom Kyte
April 28, 2009 - 10:54 am UTC

what does autonomous transaction have to do with anything????!@?

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library