Privileges on views/synonyms vs on underlying tables - oracle

Referring to here and here
Would a user need both SELECT /INSERT/DELETE/UPDATE, etc. privileges on the view AND on the underlying table to be able to perform these actions ? Or privileges on EITHER table/view is enough ?
In other words, consider a user A owning the table T and the view V (constructed from T). Can a user B with SELECT right on V execute a SELECT if he does not SELECT right on T, and vice-versa ? If he could, wouldn't that mean the View privilege "overrides" the table privilege, as A does not give him right over T ?
Update
In a related question, how about synonym ? From what I understand in a book, users need both SELECT privileges on the synonym and the underlying table. This will be different from views.
On the other hand, Oracle seems to indicate that synonyms behave similar to views.
A user can be granted the SELECT privilege on a synonym or a view
without being explicitly granted the SELECT privilege on the
originating table
Update 2
Following everyone's answer that we only need the privileges on view to select the table (at least what the view sees from the table) and no privilege on table is needed, let's consider this scenario :
Table T belongs to A
A GRANT SELECT ON T to B (without GRANT OPTION)
B CREATE VIEW V AS SELECT * FROM A.T
B GRANT SELECT ON V TO C
C performing SELECT * FROM B.V
According to what you have said, C will be able to select from V, therefore equivalent to selecting from T. Is it that cheating ? B is effectively letting C seeing A.T although C does not have the right on T and B does not have GRANT OPTION. Is there a security hole somewhere ?

One of the fundamental uses of views is to protect privacy. A base table may have confidential information that some users don't need to see (for example, in an employee table, you may have salary). Some users need access to query (select), or to update, only certain fields from the base table, without having access to the full information. For example: select phone number, or update address (but no access to see salary or bonus). Then one would create a view and give those users "select" and "update" privileges on the view only, and not on the base table. (The select still goes against the base table, but the COLUMNS will be limited to those included in the view... updates can/will be made to the base table, but again, only for values in the columns included in the view.) The view can limit not only the columns, but also the rows - for example, with a WHERE clause in the view, you may exclude the CEO from the view completely.
So, one of the main uses of views is based exactly on that: some users may have privileges on the view, but not on the base table.

Yes. Usually the view runs as the view owner, and the user runs with permission on the view. So user b only needs access to the view.
However when looking at this sort of question, you may want to look into row level security as well. This works by granting access to a portion of the table to a given user or group (i.e. effectively enforcing where clauses at the end of queries). Depending on your use case, it may be simpler or more complex to manage.

Related

Whats the privilege required to access ALL_ARGUMENTS in Oracle?

I want to know which privilege is required to access the table ALL_ARGUMENTS in Oracle? There is any specific one?
Example:
SELECT * FROM ALL_ARGUMENTS
Searched on web but found nothing.
The ALL_ARGUMENTS table is returned when we execute this:
SELECT * FROM sys.dba_tab_privs WHERE grantee='PUBLIC' and table_name like 'ALL_ARGUMENTS'
We see a value of PUBLIC as the grantee. That means, PUBLIC has SELECT privilege.
Reference: https://docs.oracle.com/database/121/TTSYS/systemtables.htm#TTSYS348
There may be other tables in SYS, for which this is not true: Then, ADMIN or SELECT ANY TABLE privileges are needed.
Typically, anyone can see ALL_ARGUMENTS. For that matter, anyone can see any ALL_ data dictionary view.
It will show you YOUR arguments, and any argument for an object you are also able to view based on your privilege level.
This security check is why querying DBA_ views is always (generally) faster than querying ALL_ views - because it just shows EVERY SINGLE ARGUMENT regardless of object privileges.
Not every view has an ALL_ and a DBA_ version.
From the DOCS

Synonyms & materialized view

I have two tables. a) student b) restricted_student.
two users a) admin b) user
one synonyms stu for both the users. in admin it refer to student but for user it refer to restricted_student.
I want to create a materialized view MV .
The code of materialized view look like
CREATE MATERIALIZED VIEW SELECT TABLE_NAME,COLUMN_NAME FROM USER_TAB_COLUMNS;
such that if i am connected to admin then it should refer to student and for user it should refer to restricted_student by passing the only synonyms name stu.
something like
SELECT TABLE_NAME,COLUMN_NAME FROM USER_TAB_COLUMNS E='st';
the result i wanted when i connected to user it should give the restricted_student table columns. whereas whenever i connected to admin it should give the student table columns.
I created all the above objects.but materialized view is not giving the expected result as i want.
You can use a normal view where you can union these 2 tables and filter by the user logged in.
Also check Oracle RLS (row level security), https://docs.oracle.com/cd/B28359_01/network.111/b28529/intro.htm
Irrespective of the application and user, you can control how the where clause should be. That way you have a much higher control over the records that is queries.
For example,
Admin user
select * from stu;
Normal user
select * from stu;
Would have completely different results, based on the predicate you set for RLS.

Make a column a view

To be brief, I won't explain why I want to do this, just what I want to do.
I have two users (which I use as schemas) A and B. Both have a table USERS. Both USERS tables have a columns ID. Every A.USERS.ID is found in B.USERS.ID and every B.USERS.ID is found in A.USERS.ID (I put constraints on that). The only other shared columns between A.USERS and B.USERS is NAME and AGE.
EDIT: To make this clearer... The problem I have is that the values of NAME and AGE are not the same between schemas A and B. For example, user ID 723 in A has A.NAME='John Vincent'. In B, the B.NAME='JJ Vincent'. I want NAME and AGE to be the same at all times. So, I figure that I need to store it in one place and make it visible in two places.
When I let someone query B.USERS, I want B.USERS.NAME and B.USERS.AGE to actually be A.USERS.NAME and A.USERS.AGE. This is the query that I could use if I had permission to query both A and B:
select B.ID, A.NAME, A.AGE from B.USERS join A.USERS on B.USERS.ID=A.USERS.ID
However, I don't want to grant access to A to everyone. I only want to grant access to B (similarly, some people only have access to A and those people are the only ones I want to update the values of NAME and AGE).
I know I can't make just 2 columns be a view. Is there some other trick to make NAME and AGE be a view of A, but have permissions of B? I hope that I've explained enough to make sense. Just trying to avoid writing a dissertation.
You can grant update, insert, delete on B and A to whomever should be able to get to either or. If you want limited view based on your query, you can grant access solely to a view without granting access to the tables.
If you need column specific update access to B, then you can do "column level security" in oracle.
Something like "grant update (column_name) on table_name to user_name", and you'll have granted access to update only "column_name" in that table.

Checking snapshots out of refresh groups in Oracle

I have an Oracle Database with a schema A, which has select privilege on DBA_* views.
I also have an schema B that doesn't have these privilege, but it has a lot of materialized views.
In schema A, there are three refresh groups, each one having some materialized views from schema B.
I'd like to check whether there are snapshots out of the refresh groups, but I'd like to do this check connected as B.
I'm using the following query to perform this check in schema A:
SELECT OWNER, NAME FROM DBA_SNAPSHOTS WHERE OWNER = 'B'
MINUS
SELECT OWNER, NAME FROM DBA_REFRESH_CHILDREN WHERE RNAME IN ('REFRESH_G1','REFRESH_G2','REFRESH_G3');
The problems:
B doesn't have privileges on DBA_* views (and It can't have)
If I change DBA_* views for ALL_* views, B can't see the refresh groups (and I can not grant alter any materialized view to B)
So:
Is there another way to perform this check in B?
Or is there another way to make B see the refresh groups?
Or is there a way to "freeze" the result of the query using ALL_* views, such as B will see the result of the query as A?
Thanks!
On A
CREATE OR REPLACE VIEW V_REFRESH_SNAPSHOT AS
SELECT OWNER, NAME FROM DBA_SNAPSHOTS WHERE OWNER = 'B'
MINUS
SELECT OWNER, NAME FROM DBA_REFRESH_CHILDREN WHERE RNAME IN ('REFRESH_G1','REFRESH_G2','REFRESH_G3');
GRANT SELECT ON A.V_REFRESH_SNAPSHOT TO B;
From B
SELECT * FROM A.V_REFRESH_SNAPSHOT;

Granting permission to users on different schema

I have tables in Schema A. I created views in Schema B using the tables in schema A.
I want to grant permissions to a user to select the data from view in Schema B.
For this to work i know we have to enable the grant option on tables in Schema A to user B.
But I want to do it in a single script (This script has to be in schema B). Is there a way to do this using the user name/password of schema A.
It's not unusual to want to have a single script to deploy a change. The thing is, such a script needs to be run by a power user, because it needs to have system privileges at the ANY level. This usually means a DBA account, preferably an application account but otherwise SYSTEM or SYS.
So the script you want would look like this:
grant select on user_a.t23 to user_b
/
grant select on user_a.t42 to user_b
/
create view user_b.v_69 as
select t23.col1, t42.col2
from user_a.t42
join user_a.t23
on (t42.id = t23.id)
/
grant select on user_b.v_69 to user_c
/
A common scenario is that we have a suite of individual scripts which have been written to be run by different users but which we now need to bundle up into a single deployment. The original scripts don't contain the schema names, and there are many good reasons why we wouldn't want to hardcode them in the scripts.
One way to build that master script is to use change the CURRENT_SCHEMA syntax:
alter session set current_schema=USER_A
/
#run_grants_to_userb.sql
alter session set current_schema=USER_B
/
#create_view69.sql
#run_grants_to_userc.sql
We still need a DBA user to run the master script. One advantage of switching the current schema is that it allows us to deploy objects like database links, which through a quirk of syntax cannot have the schema name in their declaration. One gotcha is that the user doesn't change, so a script which employs the USER pseudo-column may produce unwanted results.
Simply Run the query
GRANT INSERT, SELECT, UPDATE, DELETE ON TABLE1 TO SCHEMA2;
Only by connecting as user A at some point. You can still do it in one script if you really want to:
connect userA/passwordA
grant select on my_table to userB;
connect userB/passwordB
create view my_view as select * from userA.my_table;
Of course now you have a script lying around which exposes two sets of user credentials to anyone who can read it. So something to think hard about before doing in production, for example.
If you want other users to be able to select from the view, you don't need to grant explicit permissions on userA.my_table to them; as long as the view owner can see the underlying table, other users just need to be able to see the view. Which is often kinda the point (or one of them) as you can restrict the view to only expose selected data from the underlying table to the rest of the world. I assume you have a reason for not creating the view in schema A.
I'm not sure if you're really asking about granting select to user B with admin option so that user B can then grant select on user A's table to other people. If that's possible, it doesn't sound like a good idea, and isn't necessary for the view to work.
Let user A grant select on his tables to B and include the 'grant option'.
As user A:
GRANT select ON table TO user_b WITH GRANT OPTION;
Let user B grant select on his views to user A and include the 'grant option'.
As user B:
GRANT select ON view TO user_a WITH GRANT OPTION;
As user A:
GRANT select on user_b.view TO user_c;
This allows user A to pass this grant on to other users.

Resources