How to create a role in a procedure in pl/sql? - oracle

I would like to know how I can create a role to a procedure in oracle. This procedure should (not globally) allow the user to Change the roles and delete them.
create or replace PROCEDUR MY_ROLE(Name VARCHAR2) IS
BEGIN
DBMS_Output.put_line('You've got the right ' || Name );
--EXECUTE IMMEDIATE CONCAT('grant some_role to Username' , Name);
INSERT INTO FG7.ROLE values(Name);
END MY_ROLE;
THanks!

I think the proper approach is to create a role, grant the role to user and then SET the ROLE:
EXECUTE IMMEDIATE 'SET ROLE '||some_role;
Use
EXECUTE IMMEDIATE 'SET ROLE NONE';
to unset the role again. Of course when you grant the role to user it must not set as DEFAULT ROLE.
The issue with GRANT some_role TO ... is, it takes effect only after the user have been logged in again.
You can also use DBMS_SESSION.SET_ROLE('some_role'); and DBMS_SESSION.IS_ROLE_ENABLED('some_role') to check whether a role is enabled. See DBMS_SESSION.SET_ROLE

Related

Insufficient privileges when using create user in procedure Oracle

I try to create user and grant for them some privileges. I try to create without using procedure:
CREATE USER User1 IDENTIFIED BY password;
It works fine.
But for example, i have thousands of users. So I created a procedure to do it:
CREATE OR REPLACE PROCEDURE CreateUser AS
BEGIN
FOR u IN ( SELECT id FROM User )
LOOP
EXECUTE IMMEDIATE 'CREATE USER User_'||d.id || ' IDENTIFIED BY password';
EXECUTE IMMEDIATE 'GRANT SELECT ON UserInfo_'||d.id||' TO User_'||d.id;
END LOOP;
END
But it throws an error:
ORA-01031: insufficient privileges
How can I handle this problem? Thanks for helping in advance
You need to make sure the user running the procedure has the privileges to create users.
Assuming the user that will run the procedure is MyUser, you need to run :
GRANT CREATE USER to MyUser;
if your SQL is directly (i.e not in a procedure ) but not working from a procedure/function it means that you have the Grants through a role. For a statement to work in a procedure or a function we need direct Grants and not through the role.
You can check that you have the Create user by a role by doing the following and trying your SQL, if it fails it means you have access through a role.
SET role none;
CREATE USER User1 IDENTIFIED BY password;

can we provide an oracle privilege to user which can alter only password of other user

I have created a procedure as shown below. This procedure is present in schema1 and trying to modify the password of another schema/user let's say schema2.
To achieve this the user schema1 must have altered user privilege but I cannot provide the alter user privilege to schema1 due to some restrictions on the application level.
I tried to query using ALTER SESSION in the procedure but it is not working.
Can someone help me with the solution?
code:
Procedure p_demo(p_schema in varchar, p_pswd in varchar2)
is
begin
execute immediate 'alter session set current_schema ='||p_schema;
execute immediate 'alter user '||p_schema||' identified by '||p_pswd;
end;
Changing the current_schema has no impact on permissions or what user is currently logged in. It merely changes how object name resolution works. If you query an object foo when current_schema is set to schema1, Oracle looks in the schema1 schema rather than in the current user's schema. It does nothing to give you access to the schema1.foo table.
I'm not quite sure that I understand the goal. If you are trying to ensure that only the schema2 user can change the schema2 user's password, you can define the procedure to use invoker's rights rather than definer's rights.
create or replace procedure change_my_password( p_username in varchar2,
p_password in varchar2 )
authid current_user
is
begin
execute immediate 'alter user '||p_username||' identified by '||p_password;
end;
/
If the goal is to have the procedure owned by schema1 and to give users other than the schema2 user permission to change schema2's password (i.e. to allow an application user or a helpdesk user to reset the user's password), schema1 would likely need to have the alter user permission. Otherwise, it's probably not doable.
If you're really desperate, you could potentially use the undocumented (and I emphasize undocumented here, subject to change at any time, may have weird side effects, may tend to make Oracle Support unhappy) dbms_sys_sql package. That's the package that APEX uses internally to run code as other users. I don't imagine that a sane DBA would consider giving an application user execute access on that package rather than the much (much, much) safer alter user permission but if you're trying to work around some corporate policy and you're not much concerned about actual security...
There are 3 users involved in this example:
scott, who is trying to change someone else's password (that's your schema1)
mike, whose password should be changed (your schema2)
mydba, who is granted DBA role in my database (if you don't have such an user, SYS would do, but - you'd rather have your own "DBA" user, don't mess up with SYS if you don't have to)
Connected as scott, I can't modify mike's password:
SQL> alter user mike identified by lion;
alter user mike identified by lion
*
ERROR at line 1:
ORA-01031: insufficient privileges
I'm going to connect as mydba and create a stored procedure which looks like yours:
SQL> connect mydba/mypwd#c11gt
Connected.
SQL> create or replace procedure p_demo (p_schema in varchar2, p_pswd in varchar2) is
2 begin
3 execute immediate 'alter user ' || p_schema || ' identified by ' || p_pswd;
4 end;
5 /
Procedure created.
SQL> exec p_demo('mike', 'lion');
PL/SQL procedure successfully completed.
OK; it works. I'll grant execute privilege on it to scott:
SQL> grant execute on p_demo to scott;
Grant succeeded.
Back to scott; see what he can do now:
SQL> connect scott/tiger#c11gt
Connected.
SQL> exec mydba.p_demo('mike', 'friday');
PL/SQL procedure successfully completed.
Do mike's credentials work?
SQL> connect mike/friday#c11gt
Connected.
SQL>
Yes, everything's fine.
So: you don't have to grant alter user to schema1; let it use procedure owned by a privileged user who can change someone else's password.
Cant we do as shown below: Tried doing this but it didn't work.
What i am trying to do is basically give alter user privileges to one role and assign that role to my oracle procedure.
Create role role_name;
GRANT ALTER USER TO role_name
grant all on role_name to procedure

Grant permission to trigger from owner account

I have a trigger STUDENT_DATA_UPDATE in my two oracle accounts. One is owner account and another is user account. Below are the details.
Owner account which has all the privileges:
<connection-url>jdbc:oracle:thin:#eu.national.com:15001/STUD</connection-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<user-name>NATIONAL_OWN</user-name>
<password>********</password>
USER account which has no privileges:
<connection-url>jdbc:oracle:thin:#eu.national.com:15001/STUD</connection-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<user-name>NATIONAL_USR</user-name>
<password>********</password>
I am able to change ,Disable or enable the trigger from OWNER account which has permissions. But i am not able to do any changes to the trigger from USER account. My question here is, I want to grant the permission to change the trigger from NATIONAL_OWN to NATIONAL_USR account which can disable and enable the same trigger in it.
A user can only enable or disable another user's trigger if they are granted the powerful alter any trigger privilege, which is probably overkill and dangerous. You could restrict it with a DDL trigger but that just gets more complicated.
You could create wrapper procedures, possibly in a package, e.g. in the NATIONAL_OWN schema:
create package trigger_pkg as
procedure disable_trigger;
procedure enable_trigger;
end trigger_pkg;
/
create package body trigger_pkg as
procedure disable_trigger is
begin
execute immediate 'alter trigger STUDENT_DATA_UPDATE disable';
end disable_trigger;
procedure enable_trigger is
begin
execute immediate 'alter trigger STUDENT_DATA_UPDATE enable';
end enable_trigger;
end trigger_pkg;
/
grant execute on trigger_pkg to NATIONAL_USR;
Then as NATIONAL_USR you can do:
begin
NATIONAL_OWN.trigger_pkg.disable_trigger;
end;
/
and
begin
NATIONAL_OWN.trigger_pkg.enable_trigger;
end;
/
You could have one procedure with an enable/disable flag instead of you prefer.
Is there a way where i could actually call these procedures disable_trigger and enable_trigger from a java code.
You can use a CallableStatement, either with the anonymous block syntax:
stmt = conn.prepareCall("begin NATIONAL_OWN.trigger_pkg.disable_trigger; end;");
stmt.execute();
or the ANSI syntax:
stmt = conn.prepareCall("{ call NATIONAL_OWN.trigger_pkg.disable_trigger }");
stmt.execute();

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.

ORACLE USER role to limit user to view and execute function without modifying it

I am sorry for a newbie question. I am creating a readonly user in oracle. I want to limit him just to view and execute a function or procedure. I dont want him to modify those func or proc. Please help me on how to achieve this.
Thanks a lot
-- As sysdba:
-- 1) create an user account
create user <username> identified by <password>;
-- 2) allow user to log in
grant create session to <username>;
-- 3) allow user to execute a single procedure in other schema
grant execute on <other_schema.procedure_name> to <username>;
From SYSDBA user login (from where you created the user), give the following grant :
GRANT EXECUTE ANY PROCEDURE TO user;
GRANT SELECT ANY TABLE TO user;
where user = the username you just created.
Then ,to ensure the user has only read priviledges, check from session_privs that he doesnot have any other priviledge, specifically any "CREATE" prviledge. To do this , run :
select * from session_privs;
from the user you just created.

Resources