How to restrict DB user to view table data if he has SELECT permission - oracle11g

An Oracle DB user has SELECT permission on all the tables of a DB schema. Can i restrict the user to view the table data.The user should be able to select the table but should not be able to see the data.
This specific requirement is required for user who reviews DB design and generates ALTER script for DB using Oracle Data Modeler 3.3 where he can just see the table design and can compare it with ERD
Can i achieve it using FGAC or RLS?

You can achieve this by granting only references
GRANT references ON schema_a.table TO erd_user;
the erd_user can then use
DESC schema_a.table
to get a definition but not select any data.
This might be preferred to giving the SELECT CATALOGUE where they can see a lot more information that you might like.

Related

Is there a way to force user to only use query they are allowed In Teradata

I am using the query band so the user can connect through the proxy user to the data pool in Teradata. Proxy users have full access to the table. How can I force the external users to see the selective columns? This is my query:
SET QUERY_BAND='PROXYUSER=TheAdmin; PROXYROLE=RoleOne;' FOR TRANSACTION;
SELECT Employee_Id, First_name, Last_Name FROM Project.myTest;
This query works, but the problem is if the external user use SELECT * FROM Project.myTest;
It returns the whole table. I want that user should not be able to see all the columns.
I don't want to use the view as I have a big DB and there I have to create so many views in each table.
Is there any way to do that? Will be great help and thanks in advance.

Grant privileges to users on MonetDB

I am trying to grant admin, i.e. "monetdb" privileges to users, without any success so far (the privileges should extend to all the tables of the sys schema).
As I have a schema with many tables would be very complex to give explicit rights (e.g. SELECT ) to all the users mentioning all the tables: I need to find an efficient way to do this.
I log into MonetDB with SQLWorkbenchJ using the superuser monetdb.
I have also tried to directly send queries using R and the MonetDB.R package (with no difference).
I create a user associated to a schema (e.g. the sys schema) as
CREATE USER "user1" WITH PASSWORD 'user1' NAME 'user one' SCHEMA "sys";
Then I try to GRANT "monetdb" privileges to user1
GRANT monetdb TO "user1";
And I do not get any error.
If I log into MonetDb as user1 and try a simple select (on a pre-existing table of the sys schema) I get:
SELECT * FROM sys.departmentfunctionindex
SELECT: access denied for user1 to table 'sys.departmentfunctionindex'
Clearly I'm missing something.
Any suggestion is welcome.
I think I get it now.
The following works, using SQLWorkbenchJ I log into MonetDB as monetdb (superuser).
I run:
CREATE USER "user20" WITH PASSWORD 'user20' NAME 'user 20' SCHEMA "sys";
CREATE SCHEMA "mschema" AUTHORIZATION "monetdb";
CREATE table "mschema"."mtestTable"(v1 int, v2 int);
INSERT INTO "mschema"."mtestTable" VALUES (4, 4);
GRANT monetdb to "user20"; -- this gives implicit superuser powers to user20 (but not for the "sys" schema)
Now I log out and login again as user "user20".
I run:
SET SCHEMA mschema; -- I was missing this before but it is essential
SET ROLE monetdb;
At this stage user20 has got all the authorisations of the superuser monetdb, e.g.:
SELECT * FROM "mschema"."mtestTable"; -- can use select
DROP TABLE "mschema"."mtestTable"; -- can use drop etc.
Thanks to #Hannes, #Ying & #Dimitar
Here is an working example for granting SELECT privileges to a separate user with MonetDB:
as admin (e.g. monetdbaccount)
CREATE SCHEMA "somedataschema";
CREATE TABLE "somedataschema"."somepersistenttable" (i INTEGER);
INSERT INTO "somedataschema"."somepersistenttable" VALUES (42);
CREATE USER "someuser" WITH PASSWORD 'someuserpass' NAME 'someusername' SCHEMA "sys";
GRANT SELECT ON "somedataschema"."somepersistenttable" TO "someuser";
CREATE SCHEMA "someuserschema" AUTHORIZATION "someuser";
ALTER USER "someuser" SET SCHEMA "someuserschema";
Now, someuser can SELECT from somepersistenttable, but not modify it. Should this user need a table on its own, someuserschema or temporary tables (deleted when user logs out) could be used. Hence, this works:
SELECT * FROM "somedataschema"."somepersistenttable";
CREATE TABLE "someuserschema"."sometemptable" (i integer);
INSERT INTO "someuserschema"."sometemptable" VALUES (84);
SELECT * FROM "sometemptable";
CREATE TEMPORARY TABLE "sometemptable" (i INTEGER) ON COMMIT PRESERVE ROWS;
INSERT INTO "sometemptable" VALUES (42);
SELECT * FROM "sometemptable";
And this will produce an insufficient privileges error (same for update, drop, alter etc.):
INSERT INTO "somedataschema"."somepersistenttable" VALUES (43);
Please have a look at this MonetDB bug report. Grant privilege works for user created schemas, but the bug-fix seems not cover the default "sys" schema.
No, you don't have to explicitly grant access to each individual tables. You can still use GRANT monetdb to "user1". See my previous answer, for now, you just need to create your tables under a user created schema. I just tried it in the "default" branch of MonetDB.

Teradata: Is there a way to generate DDL from a view or select statement?

I am using a global application user account to access database A. This user account does not have permissions to modify database A's schema (ie, create tables, modify tables, etc). This user also has access to database B, but only views. I need to run SQL to feed data from a view in database B into a table in database A.
In a perfect world, I would be able to use this SQL:
create database_a.mytable as (select * from database_b) with no data
However, the user can't create tables in database A. If I could get the DDL of the select statement then I could log in under my personal account (which doesn't have any access to database B) and run the DDL in database A to create the table.
The only other option is to manually write the SQL, but I don't want to do that, especially since this view I am wanting to copy has many columns of varying data types and sizes.
Edit: I may be getting closer. I just experimented with this:
show (select * from database_b.myview)
However, it generated the DLL of every single table that is used in the view itself, as well as the definition for the view. This doesn't really help me since I just want the schema of the select statement itself. In other words, I need what would be generated if I were to use the create table as statement mentioned above.
Edit for Rob: Perhaps "DDL" was the wrong term to use. Using show view db.myview just shows the definition of the view, not the schema it represents. In my above example of create table as, I show how you can create a table that mimics the schema of a result set returned in a select. It generates a DDL on the back end for creating a table and then executes that DDL to actually create the table. You can then say show table db.newtable and see the new table's DDL. I want to get that DDL directly from a select statement so that I can copy it, log out of the app account, into my personal account, and then execute the DDL to create the table.
This is only to save me the headache of having to type out the DDL manually by hand to save time and reduce typing errors, especially since the source view has so many columns. That said, I think hitting up the DBA or writing some snazzy stored procedure to do dynamic stuff would be a bit over the top for my needs. I think there has to be a way to get the DDL for creating a table schema directly from a select statement.
Generate DDL Statements for objects:
SHOW TABLE {DatabaseB}.{Table1};
SHOW VIEW {DatabaseB}.{View1};
Breakdown of columns in a view:
HELP VIEW {DatabaseB}.{View1};
However, without the ability to create the object in the target database DatabaseA your don't have much leverage. Obviously, if the object already existed INSERT INTO SELECT ... FROM DatabaseB.Table1 or MERGE INTO would be options that you already explored.
Alternative Solution
Would it be possible to have a stored procedure created that dynamically created the table based on the view name that is provided? The global application account would simply need privilege to execute the procedure. Generally the user creating the stored procedure would need the permissions to perform the actions contained within the stored procedure. (You have some additional flexibility with this in Teradata 13.10.)
There are some caveats with this approach. You are attempting to materialize views that could reference anywhere from hundreds to billions of records. These aren't simple 1:1 views that are put on top of the target tables. Trying to determine the required space in the target database to materialize the view will be difficult. Performance can and will vary depending on the complexity of the view and the data volumes. This will not be a fast-path or data block optimized operation.
As a DBA, I would be concerned with this approach being taken on by a global application account without fully understanding the intent. I trust you have an open line of communication with the DBA(s) involved for supporting this system. I'm sure there are reasons for your madness that can't be disclosed here.
Possible Solution - VOLATILE TABLE
Unless the implicit privilege for CREATE TABLE has been revoked from the global application account this solution should work.
Volatile tables do not require perm space. There table definitions persist for the duration of the session and any data inserted into them relies on the spool space of the user who instantiated it.
CREATE VOLATILE TABLE {Global Application UserID}.{TableA_Copy} AS
(
SELECT *
FROM {DatabaseB}.{TableA}
)
WITH NO DATA
NO PRIMARY INDEX
ON COMMIT PRESERVE ROWS;
SHOW TABLE {Global Application UserID}.{TableA_Copy};
I opted to use a Teradata 13.10 feature called NO PRIMARY INDEX. By default, CREATE TABLE AS will take the first column of the SELECT statement and make it the PRIMARY INDEX of the table. This could lead to skewing and perm space issues in your testing depending on the data demographics. You can specify an explicit PRIMARY INDEX on your own as you understand the underlying data. (See the DDL manuals for details on the syntax if you're uncertain.)
The use of ON COMMIT PRESERVE ROWS for the intent of this example is probably extraneous. But in reality if you popped any data into that table for testing this clause would be beneficial in Teradata mode as the data would otherwise be lost immediately after the CREATE TABLE or any other data manipulation was performed against the volatile table.

ORA-00955: name is already used by an existing object

In oracle 11G, I want to drop a user PERMANENTLY, ie no trace of that user should remain and I should not get "existing object" errors like this - ORA-00955: name is already used by an existing object, when I try to recreate that User with its tables.
Please help me to do this.
Thanks.
EDIT -
Commands to create user with table and columns
CREATE USER Products identified by discounted
GRANT ALL PRIVILEGES TO Products
CREATE TABLE Cars(Brand varchar(25),Model varchar(25))
The above is followed by,
Commands to drop user completely and re-create it completely
DROP USER PRODUCTS CASCADE
CREATE USER Products identified by discounted
GRANT ALL PRIVILEGES TO Products
CREATE TABLE Cars(Brand varchar(25),Model varchar(25))
Causes the exception-
java.sql.SQLSyntaxErrorException: ORA-00955: name is already used by an existing object
You didn't say what user you were logging in as, but I'll assume it's SYS or someone with pretty much godlike privileges.
In your last line, you are creating table CARS in the current schema, not in the products schema. What you probably want is:
CREATE TABLE products.cars(brand varchar2(25), model varchar2(25));
The cars table probably still exists in the current schema from your previous attempt. You can tell if it exists anywhere with this:
SELECT owner, object_name, object_type FROM all_objects WHERE object_name = 'CARS';
As a side note, it's not really a good idea to grant all privileges to a normal user, but I assume this is for testing procedures. Also, it's preferred to use VARCHAR2 instead of VARCHAR.
Your question is way too generic. Based on what I understood, if you use following script, you can drop all objects created by the user -
drop user USERNAME cascade;
Documentation
And for this to execute successfully you should not have an open connection for this user.

LINQ to SQL for tables across databases. Or View?

I have a Message table and a User table. Both are in separate databases. There is a userID in the Message table that is used to join to the User table to find things like userName.
How can I create this in LINQ to SQL? I can't seem to do a cross database join.
Should I create a View in the database and use that instead? Will that work? What will happen to CRUD against it? E.g. if I delete a message - surely it won't delete the user? I'd imagine it would throw an error.
What to do? I can't move the tables into the same database!
A view will work, if you have granted access to both database to the configured user. You'll need to use the 2-dot notation. This will only work BTW if both databases are on the same server.
create view vwUserMessages as
select * from db1.dbo.Users as users
inner join db2.dbo.Messages as msg on msg.UserID = users.id
For CRUD: a view is (usualy) only for reading: do updates etc directly to the related tables, or use a stored procedure:
create proc pdeleteUserMessages (#UserID int) as
begin trans
delete db2.dbo.Messages where userid = #UserID
delete db1.dbo.Users where id = #UserID
commit trans
go

Resources