Grant select on a table forcing WHERE - oracle

I have a table with users data (email, name, surname, username, password..) and I want to grant each user to see only his own data (like seeing his profile). I have been trying to do it this way:
create or replace
PROCEDURE PR_OWNDATA AS
BEGIN
FOR userRow IN (SELECT COD_USUARIO, USERNAME FROM CAMP.USERS) LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON CAMP.USERS TO "' || userRow.USERNAME || '" WHERE COD_USUARIO = ' || userRow.COD_USUARIO || ';';
END LOOP;
END PR_OWNDATA;
It doesn't work (ORA 06550 "line %s, column %s:\n%s"). But I can't see where is the problem..
I have think about create a VIEW per USER in this way
CREATE VIEW userRow.USERNAME.V_DATOSALUMNO AS SELECT * FROM CAMP.USERS WHERE COD_USUARIO = ' || userRow.COD_USUARIO || ';';
But I don't know if it is the correct way..
Thank you in advance.

I don't understand the name you're giving to the view, but the code should be:
CREATE VIEW my_view_name
AS
SELECT *
FROM CAMP.USERS
WHERE COD_USUARIO = SYS_CONTEXT('USERENV', 'SESSION_USER')
Of course if you're not salting and hashing that password then you're doing it all wrong.

Related

Creating a synonym for all objects in another schema

I am interested in creating a SYNONYM for another schema and all objects in them (Tables, View, Procedures, Packages, etc). Currently users are getting an error that a certain table doesn't exist. It's happening because they are running a query like SELECT * FROM mytable. If the query were SELECT * FROM myschema.mytable it would work.
Does creating public synonym make the schema available to all users or roles? Are there any security issues with granting a public synonym? Should I use a non-public synonym? We are allocating permissions to the schema via roles.
Is there a query or script that would enable this?
Yes, you probably want a public synonym. From the docs:
Specify PUBLIC to create a public synonym. Public synonyms are
accessible to all users. However each user must have appropriate
privileges on the underlying object in order to use the synonym.
I think the main security issue they mention is to not create a public synonym with the same name as an existing schema.
See also object name resolution.
There's not a simple command, but you could script it with something like this:
begin
for r in (select owner, table_name from all_tables where owner = 'MYSCHEMA')
loop
execute immediate 'create public synonym ' || r.table_name || ' for ' || r.owner || '.' || r.table_name;
end loop;
end;
/
Edit: if you want more than just tables, you can change the query to loop over all_objects instead and pick the object types you want:
begin
for r in (select owner, object_name from all_objects
where owner = 'MYSCHEMA'
and object_type in ('TABLE','VIEW','PROCEDURE','FUNCTION','PACKAGE'))
loop
execute immediate 'create public synonym ' || r.object_name
|| ' for ' || r.owner || '.' || r.object_name;
end loop;
end;
/

Oracle: Change SDO_GEOMETRY's SRID for all tables in a schema

I need to change the SRID (set it to NULL) in the geometry objects of all tables in a specific schema (for a specific user)
The command:
UPDATE my_table t SET t.geometrie.sdo_srid = null;
works fine for a single table.
When I try to do it in a loop for all tables of a specific owner:
BEGIN
FOR my_tables IN (
SELECT TABLE_NAME from all_tables where OWNER = 'LANDWERTZONEN' AND TABLE_NAME NOT LIKE 'GOOM%' AND TABLE_NAME NOT LIKE '%BKP'
)
LOOP
DBMS_OUTPUT.PUT_LINE('UPDATE ' || my_tables || ' t SET t.geometrie.sdo_srid = null');
END LOOP;
END;
I get the error:
pls-00306 wrong number or types of arguments in call to '||'
What could be the problem here?
Wrong concatenation? Wrong call?
Any suggestions are very welcome.
Besides the syntax error that Littlefoot pointed out, you may extend the logic to actually perform the update rather than printing out the UPDATE statement:
DECLARE
sql_stmt varchar2(256);
BEGIN
FOR st IN (
SELECT OWNER, TABLE_NAME, COLUMN_NAME
FROM all_tab_columns
WHERE OWNER = 'LANDWERTZONEN'
AND TABLE_NAME NOT LIKE 'GOOM%'
AND TABLE_NAME NOT LIKE '%BKP'
AND DATA_TYPE = 'SDO_GEOMETRY'
)
LOOP
sql_stmt := 'UPDATE ' || st.owner ||'.' || st.table_name || ' t SET t.'|| st.column_name ||'.sdo_srid = null';
DBMS_OUTPUT.PUT_LINE('Executing ' || sql_stmt);
execute immediate sql_stmt;
COMMIT;
END LOOP;
END;
/
This actually restricts the change to actual spatial tables / columns.
Note that you must make sure the spatial indexes are dropped before execution (and update metadata and recreate the spatial indexes after execution).
BUT I would question the reason for setting the SRIDs to NULL. This will seriously remove functionality: you will no longer be able to perform any measurements (area, length, distances). Also you will no longer be able to relate the data with data that has explicit SRIDs (like a GPS point). And if the data is actually geodetic (long/lat) then operations like within_distance, buffer generation ... are essentially no longer possible.
Our advice is to always explicitly use the correct SRIDs.
How about this:
DBMS_OUTPUT.PUT_LINE('UPDATE ' || my_tables.table_name || ' t SET t.geometrie.sdo_srid = null');
-----------
You forgot to add table name from a cursor.

How to test if a variable contains special characters other than numbers , letters and # and _ and $?

There is a variable representing a string :
create or replace procedure create_user(login varchar2)
is
begin
execute immediate 'create user "' || login || '" identified by 1 default tablespace tbs_sse';
execute immediate 'grant create session to "' || login || '"';
execute immediate 'grant select any sequence to "' || login || '"';
end;
How to test if the variable login contains special characters other than numbers , letters and # and _ and $ ?
Just you can check using regexp. Create your regexp based on what you are expecting.
SELECT count(1) into counter
FROM dual
WHERE NOT REGEXP_LIKE (LOGIN_VAR , '^[a-zA-Z0-9_$#]+$');
IF (counter != 0) THEN
--Invalid Login alert, error return
END IF;
For more idea about oracle object naming rules please check link
You test - probably - in an IF statement. If so, you can use something like
........
if regexp_like(login, '[^a-zA-Z0-9_#$]')
then ........
........
Since your actual purpose is to check that the name is suitable as an Oracle identifier, you're probably better off using the built-in function dbms_assert.simple_sql_name, e.g.:
dbms_assert.simple_sql_name(login);
execute immediate 'create user "' || login ...
This will raise ORA-44003 string is not a simple SQL name if login has an unsuitable value.

Parameters on Execute Immediate Sentence (Inside a procedure)

I'm triyin to create a ORACLE USER from my User table inside a procedure. The problem is that I don't know how to call a specific column. I've tried with Camp.user.username and that stuff.
create or replace
PROCEDURE PR_USERPASS AS
BEGIN
UPDATE CAMP.USERS
SET USERNAME = (DBMS_RANDOM.string('x',15)), PASS = DBMS_RANDOM.string('x',12);
EXECUTE IMMEDIATE 'CREATE USER ' || USERNAME || ' IDENTIFIED BY ' || PASSWORD;
EXECUTE IMMEDIATE 'Grant connect to ' || USERNAME;
END PR_USERPASS;
Is there anyway to call that references in the same procedure?
Thank you in advance.
Use a cursor to loop through the Camp.Users table and access its columns. Your code would go something like this (untested):
create or replace
PROCEDURE PR_USERPASS AS
BEGIN
UPDATE CAMP.USERS
SET USERNAME = (DBMS_RANDOM.string('u',15)), PASS = DBMS_RANDOM.string('x',12);
FOR userRow IN (SELECT Username, Pass FROM Camp.Users) LOOP
EXECUTE IMMEDIATE 'CREATE USER ' || userRow.Username || ' IDENTIFIED BY ' || userRow.Pass;
EXECUTE IMMEDIATE 'GRANT CONNECT TO ' || userRow.Username;
END LOOP;
END PR_USERPASS;
Addendum: The original answer generated USERNAME as DBMS_Random.String('x', 15), which allows digits and numbers for the username and password. This caused trouble when the username began with a digit. The answer was changed to use DBMS_Random.String('u', 15) to generate only Oracle-acceptable username values. The password seemed to be OK with the leading digit.
If usernames beginning with a digit are wanted, just surround the username with double quotes:
EXECUTE IMMEDIATE 'CREATE USER "' || userRow.Username || '" IDENTIFIED BY ' || userRow.Pass;
EXECUTE IMMEDIATE 'GRANT CONNECT TO "' || userRow.Username || '"';
That said, I'm not sure if having non-standard usernames is such a good idea.
Documentation for DBMS_Random.String can be found here.

Delete an oracle-user with single quotes in the username

Through a faulty script I have created a user with single quotes around his username (i.e. his username is 'username', not username) on an Oracle 9i system. Now I want to remove that user. Neither "DROP USER 'username'" nor "DROP USER \'username\'" nor "DROP USER (SELECT username FROM all_users where user_id = 123)" worked. How do I get rid of that user?
create user "'bla'" identified by bla;
drop user "'bla'";
According to Oracle's Documentation...
"A quoted identifier begins and ends
with double quotation marks ("). If
you name a schema object using a
quoted identifier, then you must use
the double quotation marks whenever
you refer to that object."
So this...
DROP USER "username" CASCADE;
I know this is an old post, but for anyone stumbling across this as the result of a search on this problem - the issue appears to be that a database trigger is firing on drop user.
I've posted the solution I found for Oracle XE ( probably the same for other 10g releases)
here
Hope someone finds this useful,
Mike
Try DROP USER "'username'" or DROP USER ''username''. (Note that those last quotes are all single quotes)
I don't know Oracle off-hand, but might you try enclosing it in double quotes?
(I'll delete this answer if its wrong)
The following code might help you :
declare
sel_username varchar2(30);
r_user_id varchar2(30);
r_username varchar2(30);
user_cmd varchar2(200);
BEGIN
/*
This procedure will delete a single user_id and can be used to delete a user
with none displayable characters in the name
**Replace** the user_id in this script to that you want to delete !!
Author: Ulrich Henkenjohann - March 2010 / tested on ORACLE 10.2.0.4
*/
-- select the username for a special user_id. Ther username may contain none displayed characters
select username into sel_username from dba_users where user_id = 34;
select user_id, username into r_user_id , r_username from dba_users where username = sel_username ;
DBMS_OUTPUT.PUT_LINE('Selected user: ' || r_user_id || ' ' || r_username);
-- If a test is needed, an alter passwort command may be usefull
-- user_cmd := 'ALTER USER "' || r_username || '" IDENTIFIED BY PASSWORDX ';
-- Drop the selected user
user_cmd := 'DROP USER "' || r_username || '" CASCADE ';
DBMS_OUTPUT.PUT_LINE('Executing user_cmd: ' || user_cmd );
execute immediate user_cmd ;
END;
/
Once again with better format:
declare
sel_username varchar2(30);
r_user_id varchar2(30);
r_username varchar2(30);
user_cmd varchar2(200);
BEGIN
/*
This procedure will delete a single userid and can be used to delete a user
with none displayable characters in the name
**Replace the user_id in this script !!**
Author: Ulrich Henkenjohann - March 2010 / tested on ORACLE 10.2.0.4
*/
-- select the username for a special user_id. Ther username may contain none displayed characters
select username into sel_username from dba_users where user_id = 34;
select user_id, username into r_user_id , r_username from dba_users where username = sel_username ;
DBMS_OUTPUT.PUT_LINE('Selected user: ' || r_user_id || ' ' || r_username);
-- If a test is needed, an alter passwort command may be usefull
-- user_cmd := 'ALTER USER "' || r_username || '" IDENTIFIED BY PASSWORDX ';
-- Drop the selected user
user_cmd := 'DROP USER "' || r_username || '" CASCADE ';
DBMS_OUTPUT.PUT_LINE('Executing user_cmd: ' || user_cmd );
execute immediate user_cmd ;
END;
/

Resources