Grant permission to role if exists in SAP HANA - sql

I have a HANA database deployment set up using Flyway and the HANA JDBC driver that creates and populates a schema. Something I would also like to do as part of the deployment is grant a particular database role read access to that schema. However, in order to avoid migration errors, I'd first like to verify that this role exists, and I can't get this part of the logic to work.
The closest I've come is
DO
BEGIN
DECLARE I INTEGER;
SELECT COUNT(*) INTO I
FROM roles
WHERE role_name = 'MYROLE';
IF I > 0
THEN
GRANT SELECT ON SCHEMA myschema TO MYROLE;
END IF;
END;
but this fails with
SQL State : HY000
Error Code : 7
Message : SAP DBTech JDBC: [7] (at 140): feature not supported: DDL statements other than CREATE/DROP TABLE is/are not supported in anonymous block: line 9 col 9 (at pos 140)
Location : db/migration/V1.10__my_script.sql (snip)
Line : 1
Statement : DO
I also tried this via trying to create a temporary stored procedure and executing that - same problem with DDL statements not being supported.
The problems:
I need to do an IF-THEN-ELSE based on the result of a select query
HANA doesn't seem to support nesting a SELECT statement inside an IF clause, so I need to save the result in a variable and use that instead
Declaring variables is only supported inside blocks, such as anonymous blocks or the bodies of stored procedures
Blocks also forbid executing most DDL statements - GRANT being one of them.
At this point, I'm not sure if what I'm trying to do is even possible. Pointers would be very much appreciated.

Your code should work with a few modifications like the following:
DO
BEGIN
DECLARE I INTEGER;
SELECT COUNT(*) INTO I
FROM roles
WHERE role_name = 'MYROLE';
IF :I > 0 THEN
exec 'GRANT SELECT ON SCHEMA myschema to MYROLE';
END IF;
END;
To access the I variable value in the IF statement you need to use the : notation.
As you mentioned some DDL statements are not directly supported in SQL Script, but you can use the EXEC command to run them as dynamic SQL commands.
Generally speaking, this approach to handle privileges is rather problematic since the outcome of your procedure, that is what privileges exactly are available to MYROLE, is dependent on
if there already exists a role with the same name
what privileges the security context that runs the procedure is allowed to grant
SAP HANA provides HDI (HANA Deployment Infrastructure) repository object type .hdbrole that allows to bundle privileges into roles and have those deployed fully (or not at all) upon installation time. This approach also allows updating privilege assignments to roles even after the role had been assigned to other roles and users without the need for re-assignment.
Dynamically building roles and assigning privileges makes it much harder to understand when, where and why privileges are assigned to roles/users. That is typically not what you want; instead, you like to have privileges assigned at a well-known place in your application and nowhere else. Therefore the pointer is to actually not use your procedure but to use the HANA tools available for role-definition.
All that is explained in a lot more detail in the SAP HANA documentation.

Related

ORACLE - Why does a dynamic SQL statement using DBMS_RANDOM fail when called from a stored procedure but not from an anonymous block

EDIT (8/25)
Thanks to #Alex Poole for providing the answer below but I wanted to share additional detail on these role limitations around PL/SQL objects as it helps explain not only how Oracle is managing things under the hood but why it handles permissions this way.
Now knowing where I was going wrong, I was able to identify this question which discusses the issue at length. This answer describes how the Oracle data structures store the permissions for evaluation.
In addition, someone linked an explanation from Tom Kyte which explains why this behavior was coded intentionally. Long story short: PL/SQL Definer's Rights do not respect role based permissions due to how the Oracle engine compiles these objects. If role based permissions were allowed then any REVOKE statements could have the ability of invalidating large swaths of PL/SQL objects, requiring a costly full database recompile.
Original Question
Could someone help me understand why I can call a dynamic sql script containing a reference to a DBMS_RANDOM procedure when the logic is called from an anonymous block, however, when I take that same logic and drop it into my own stored procedure, the previously runnable script fails to execute with a ORA-00904: "DBMS_RANDOM"."STRING": invalid identifier error?
I feel confident that my privileges are correct. I can run the script that is being passed as a variable directly without issue and run this logic as an anonymous PL/SQL block. Do I need to change my syntax with the stored proc or is it possible that this practice is prevented for security reasons?
Any explanation would be great but if you can point me to the Oracle documentation, I would be ecstatic. I have looked extensively, especially around Oracle's Dynamic SQL documentation but I haven't seen a description of this behavior. I am using Oracle 11g.
To recreate the behavior I am seeing:
Test Data Creation:
SPOOL ON;
SET SERVEROUTPUT ON SIZE UNLIMITED;
--Create Test Table
CREATE TABLE TEST_DYNAMIC_TBL (
ID NUMBER PRIMARY KEY,
MY_COL VARCHAR2(50));
--INSERT a line of data and confirm
INSERT INTO TEST_DYNAMIC_TBL VALUES(1, 'SOME TEXT');
COMMIT;
SELECT MY_COL FROM TEST_DYNAMIC_TBL;
MY_COL
SOME TEXT
PL/SQL Anonymous Block (Successful Example)
DECLARE
l_script VARCHAR2 (32767);
BEGIN
l_script := 'UPDATE TEST_DYNAMIC_TBL SET MY_COL = DBMS_RANDOM.STRING(''U'',5)';
DBMS_OUTPUT.put_line ('Script sent to Exec Immediate: ' || l_script);
EXECUTE IMMEDIATE l_script;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line (' ERROR: ' || SUBSTR (SQLERRM, 1, 64));
ROLLBACK;
END;
/
--Check value (This results in a successful update)
SELECT MY_COL FROM TEST_DYNAMIC_TBL;
Script sent to Exec Immediate: UPDATE TEST_DYNAMIC_TBL SET MY_COL = DBMS_RANDOM.STRING('U',5)
PL/SQL procedure successfully completed.
MY_COL
XFTKV
Your query value will vary depending on the seed that DBMS_RANDOM picked
Stored Procedure Example (Failure Example)
--Procedure created with identical logic
CREATE OR REPLACE PROCEDURE TEST_DYNAMIC
AS
l_script VARCHAR2 (32767);
BEGIN
l_script := 'UPDATE TEST_DYNAMIC_TBL SET MY_COL = DBMS_RANDOM.STRING(''U'',5)';
DBMS_OUTPUT.put_line ('Script sent to Exec Immediate: ' || l_script); -- This string will execute successfully if run directly
EXECUTE IMMEDIATE l_script;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (' ERROR: ' || SUBSTR (SQLERRM, 1, 64));
ROLLBACK;
END;
/
--Reset and verify Data
UPDATE TEST_DYNAMIC_TBL SET MY_COL = 'SOME TEXT';
COMMIT;
SELECT MY_COL FROM TEST_DYNAMIC_TBL;
--Execute through Procedure (Will throw error)
EXECUTE TEST_DYNAMIC;
--Check Value of Table
SELECT MY_COL FROM TEST_DYNAMIC_TBL;
Stored Procedure Results:
MY_COL
SOME TEXT
Script sent to Exec Immediate: UPDATE TEST_DYNAMIC_TBL SET MY_COL = DBMS_RANDOM.STRING('U',5)
ERROR: ORA-00904: DBMS_RANDOM: invalid identifier
PL/SQL procedure successfully completed.
MY_COL
SOME TEXT
It isn't about it being dynamic, it's about the privileges and how they were granted. You would see the same thing if you had a static insert using dbms_random (and in your example anyway there is no need for it to be dynamic).
It appears that you have execute privilege on dbms_random granted through a role, not directly to the package owner. From the documentation (emphasis added):
If the procedure owner grants to another user the right to use the procedure, then the privileges of the procedure owner (on the objects the procedure references) apply to the grantee's exercise of the procedure. The privileges of the procedure's definer must be granted directly to the procedure owner, not granted through roles. These are called definer's rights.
The user of a procedure who is not its owner is called the invoker. Additional privileges on referenced objects are required for an invoker's rights procedure, but not for a definer's rights procedure.
That only applies to stored PL/SQL - i.e. procedures, functions, packages, triggers etc. - not to anonymous blocks.
You can either get the privilege on dbms_random granted directly to the package owner, or change your procedure to use invoker's rights:
CREATE OR REPLACE PROCEDURE TEST_DYNAMIC
AUTHID CURRENT_USER
AS
...
In the latter case, anyone calling your procedure will then need the privilege on dbms_random - but they can have it through a role.
As access to that package is sometimes locked down, a direct grant to the owner might be preferable, but it depends on your security constraints.
The reason it requires a direct grant, I believe, is that roles can be enabled and disabled, and be default or not, and can be nested. If a direct grant is revoked then it's fairly straightforward to figure out that should invalidate the procedure. And that's possibly true if a role is revoked, but quite a lot more complicated.
But what role-derived privileges should be taken into consideration when the procedure is created - only those that are enabled in that session? Only default roles? Or all roles? (And remember there can be a chain of roles to think about to determine privileges, and you can get the same privilege from multiple roles.)
However you do it will confuse or upset someone - if only enabled then the owner logging in a future session might not be able to perform the actions the procedure does, and what if they want to recompile it? If only default then those defaults can change, with the same issues - or should that invalidate the procedure? If all roles then including disabled ones will be confusing and could have security implications.
And for any of those, role revocation would still have to figure out which privileges that removes - which aren't also granted directly or via another role! - and only once it's really sure which privileges have actually gone, see which objects that affects. Which could be a lot of work - think how many individual privileges could be affected by revoking DBA.
It's much simpler for the invoker - you only need to look at the active privileges from the enabled roles at the moment then call the procedure.
So while at first glance it seems odd that privileges granted through roles aren't included for stored PL/SQL, once you look at the implications and complications - both as it's created, but more what happens afterwards - it seems like a sensible restriction.

Error during stored procedure creation in DB2 database

I am struggling with schemas while creating a stored procedure in DB2 database ( 10.5 version ).
My user name is XYZ but I have to create a Stored procedure for schema ABC.
When I am trying to execute the create procedure sql I get error message which looks like Schema related
Create procedure ABC.customInsert(
IN temp INTEGER
)
BEGIN
INSERT INTO ABC.One_Column_table VALUES ( temp );
END
Error Message:
Error:DB2 SQL error:SQLCODE:-551, SQLSTATE: 42501,
SQLERRMC:XYZ;INSERT;ABC.One_Column_table
My current schema was showing XYZ earlier. ( result of select current_Schema from sysibm.sysdummy1).
I have changed it to ABC. ( using SET CURRENT SCHEMA ABC). But still the same problem.
I am able to insert, select, create UDT etc in ABC schema but the problem exists only during stored procedure creation.
Any idea what am I doing wrong ?
Based on your error message, SQLCODE -551 means that the user "XYZ" does not have the "INSERT" privilege on the table "ABC.One_Column_table".
Since you imply that you, when connected as XYZ, can insert into the table by issuing simple INSERT statements, it is possible that you possess the INSERT privilege indirectly, via a group membership. Group privileges are ignored for SQL statements in stored procedures, functions or triggers, as explained in this IBM technote.
You have two options:
Grant the required privileges on ABC.One_Column_table to the user XYZ directly.
Create a role (using the CREATE ROLE statement), grant the table privileges to that role, then grant the role to the user XYZ.
If you are curious, such behaviour is caused by the fact that static SQL statement (e.g. in a stored procedure) authorization is checked only during compilation, and the compiled code can then be executed without additional authorization checks. Groups are maintained outside the DB2 database, by the operating system, and it is possible that group membership changes after the stored procedure is compiled and without the database security administrator's knowledge. If group privileges were effective for static SQL, it would allow users who weren't originally authorized to run particular statements (i.e. were not members of the authorized group at the compilation time) still execute those statements, thus creating a security risk.
Roles, on the other hand, are maintained within the database itself by the database security administrator and thus are part of the same security landscape.

Restrict user to Stored Procedures

I need to restrict user access to SELECT, INSERT, UPDATE and DELETE, so that user should manage data only using stored procedures I provide.
So, for instance
SELECT * FROM Table1
should return
The SELECT permission was denied on the object 'Table1'
however, if there is stored procedure SelectTable1 defined as
CREATE PROCEDURE SelectTable1
AS
BEGIN
SELECT * FROM Table1
END
(the real one contains filtering and parameters, so it is not meaningless, like the one above)
user should execute it successfully and get the resultset.
But obviously, I have no success implementing this set of permissions. Can anybody point me to some specific tutorial? MSDN was not very helpful.
Database is SQL Server 2012 and all objects (tables and stored procedures) are in custom schema.
You can do it using GRANT EXEC either on specific procedures or on schemas or on a database.
The following example grants EXECUTE permission on stored procedure
HumanResources.uspUpdateEmployeeHireInfo to an application role called
Recruiting11.
USE AdventureWorks2012;
GRANT EXECUTE ON OBJECT::HumanResources.uspUpdateEmployeeHireInfo
TO Recruiting11;
GO
Thanks to Igor I've got to the right MSDN page, and followed rights links.
However, using ownership chains suggested was too complicated for me, so I used
WITH EXECUTE AS OWNER
on my stored procedures and that works very good. When I log on using restricted user I see only procedures, no tables at all and I can execute procedures, but not even select from tables.
Also, I want to mention this concept is very similar to setuid and thus was familiar to me.
I mark Igors reply as answer, because ownership chains seem to be more generic way, just wanted to share info I found.

Facing an error : table or view does not exist

I am using insert statement and trying to insert data into the database table. I am using stored procedures.
But I am getting this error while doing so.
Message: ORA-00942: table or view does
not exist ORA-06512
I checked if the tables/stored procedures are present or not and everything is in place. Also there is no typo in table names or in sp. If I run the part of SP from query editor it works fine but when I execute the entire SP it throws an error.
I tried the steps provided by Stephen but since I have logged in with the same user/owner when I run Grant command it gives me an error saying 'Cannot Grant/revoke on own'.
One more addition to this. I have a stored procedure SP1 in which I am using a select statement as
Select a from table_name where condition;
When I execute this seperately, it returns me some results. But when I execute sp it gives an error at the same line where it is written.
Can anyone help me out to resolve this issue. I am using SQL +.
Thanks in advance
Vijay
Justin's answer is correct but let me expand a bit.
Everyone who said that the table doesn't exist didn't read your whole post. Since you are able to:
If I run the part of SP from query editor it works fine
Obviously the table is there.
Obviously you have some access to it. Otherwise this wouldn't work when it clearly does.
but when I execute the entire SP it throws an error.
This is because Oracle distinguishes between permissions granted directly and those granted via a role.
Say I do this:
Create Table TABLE_A
Create Role READ_ONLY
Grant Select on TABLE_A to READ_ONLY
Grant READ_ONLY to VIJAY
In a SQL Window/prompt you could query that table without issue. So now you need to create a view
Create VIJAY.VIEW_A as SELECT * FROM TABLE_A
You'll get the error that TABLE_A does exist. Because a view is compiled, like a procedure it runs without any roles. Since it runs without the READ_ONLY role, it's blind to the fact that TABLE_A exists. Now what I need to do is
Grant Select on TABLE_A to VIJAY.
Now that you have a direct permission, you can compile a view or procedure/package that uses that table.
Does the table exist in the schema where the stored procedure exists? If not, the simplest explanation is that the owner of your procedure has been granted access to the table via a role not via a direct grant. A definer's rights stored procedure needs to have direct access to the objects it accesses. A quick way to test this is to disable roles for the session, i.e.
SQL> set role none;
SQL> <<execute your query>>
If that generates the error, the problem is the lack of a direct grant.
In Oracle you can choose if the stored procedure is executed with the rights of the invoker or the definer: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17126/subprograms.htm#i18574
Check if the AUTHID property of the stored procedure is correct and if the resulting user has appropriate permissions.
Well, put very simply, the table that you are trying to insert data into does not exist in the database you are connected to. You need to check both those things (i.e. what are you connected to, and is the table there and accessible for the user context you are using).
As Joe Stefanelli said .. there are a lot of possibilities for the error being shown here.
Check whether:
You are connecting to the correct Oracle Instance.
You have permissions to query or perform processing on table that you are referencing in your query.
There is a difference between ordinary select statements and procedures. Procedures in oracle do not respect the roles assigned to a user; rather the permission needs to be explicitly granted to the user. For more information read the following linkORA-00942

Stored Procedure Ownership Chaining

I have several stored procedures in my database that are used to load data from a datamart that is housed in a separate database. These procedures are, generally, in the form:
CREATE PROCEDURE load_stuff
WITH EXECUTE AS OWNER AS
INSERT INTO my_db.dbo.report_table
(
column_a
)
SELECT
column_b
FROM data_mart.dbo.source_table
WHERE
foo = 'bar';
These run fine when I execute the query in SQL Server Management Studio. When I try to execute them using EXEC load_stuff, the procedure fails with a security warning:
The server principal "the_user" is not able to access the database "data_mart" under the current security context.
The OWNER of the sproc is dbo, which is the_user (for the sake of our example). The OWNER of both databases is also the_user and the_user is mapped to dbo (which is what SQL Server should do).
Why would I be seeing this error in SQL Server? Is this because the user in question is being aliased as dbo and I should use a different user account for my cross-database data access?
Edit
I understand that this is because SQL Server disables cross database ownership chaining by default, which is good. However, I'm not sure of the best practice in this situation. If anyone has any input on the best practice for this scenario, it would be greatly appreciated.
Edit 2
The eventual solution was to set TRUSTWORTHY ON on both of the databases. This allows for limited ownership chaining between the two databases without resorting to full database ownership chaining.
Why not remove EXECUTE AS OWNER?
Usually, my user executing the SP would have appropriate rights in both databases, and I don't have to do that at all.
There is no need to create login, you can just enable guest user in target DB.
grant connect to guest
This allows executing user to enter DB under guest context, and when "db chaining is ON access will not be checked in target DB.
Actually, DBO is a role (you can consider it as a group of users), not a user in himself. (Unless you can connect to SQL SERVER using dbo:passwordfordbo it's not a user).
Usually, in the wonderful world of SQL Server, if you grant userX right to execute storedprocY then X gets the right to perform all the task Y contains even if he doesn't have all the permission on all the objects used in Y.
That's an extremely useful feature to encapsulate business logic in a stored procedure. (Your user have NO access on the table but they do can EXECUTE one stored proc).
When we talk about "ownership chaining" it means the following (please correct me if I am wrong though)
- If ownership chaining is disabled: the right to execute procedureX will work as long as all the required objects are in the same database
- Of chaining is enabled: That "privilege" will expands towards all databases.
Hope that helps,