dijksterhuis
dijksterhuis

Reputation: 1271

Provide only GRANT EXECUTE 'procedure' to a user (No select or insert permissions)

I was wondering if it's possible to grant EXECUTE permissions to a user without granting SELECT, INSERT etc. permissions on the table that a procedure runs on?

Using it for a Logins table for a webapp. MySQL is running in a Docker container. SQL for creating procedures is copied across as part of the docker build process (when run, the sql is used in entrypoint.sh). Login_db is created when running the container (-e flag).

I'd like to remove the GRANT SELECT line from below so, no matter what happens, the webapp server can never run a SELECT query - such as doing SELECT * FROM logins.

CREATE USER 'logins'@'172.24.0.7' IDENTIFIED BY 'some-password';
GRANT SELECT, INSERT, UPDATE on logins_db.login TO 'logins'@'172.24.0.7';
GRANT EXECUTE ON PROCEDURE logins_db.sp_login16 TO 'logins'@'172.24.0.7';
FLUSH PRIVILEGES;

This doesn't solve it - as being the table owner would expose the same privileges:

Execute stored proc fails with GRANT EXECUTE because of table permissions

This might explain why I can't, but the table names are a bit odd to me (MySQL newbie - I'm under the impression that mysql.proc is a system table, so not sure if it applies):

How to grant execute on specific stored procedure to user

Could it be that root doesn't have SELECT privileges when creating the procedure and so the the logins user cannot run it? (Because Docker MySQL runs entrypoint.sh and then the environment variable)?

The procedure code is here (I know, not the most elegant) - could I GRANT and then REVOKE privileges for the logins user within this, considering the DEFINER is root ?

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_login16`(
IN p_email VARCHAR(120),
IN p_password VARCHAR(120))
BEGIN
SELECT user_id,user_password FROM login WHERE user_email = p_email;

Upvotes: 3

Views: 5685

Answers (2)

dijksterhuis
dijksterhuis

Reputation: 1271

Added a new user ADMIN@localhost with SELECT, INSERT and UPDATE privileges. ADMIN then became the DEFINER for all the procedures, with 'logins'@'172.24.0.7' only being granted EXECUTE permissions. Runs perfectly now!

Apparently you can't use root in the way I was trying to. Kudos to @Shadow for pointing me in the right direction.

Setting up the admin user:

CREATE USER 'admin'@'localhost' IDENTIFIED BY '<password>';
GRANT SELECT, INSERT, UPDATE, DELETE ON db.table_name TO 'admin'@'localhost';
GRANT ALTER ROUTINE, CREATE ROUTINE, EXECUTE ON *.* TO 'admin'@'localhost'; 
FLUSH PRIVILEGES;

Defining a stored procedure that creates a entry using the limited admin user

DELIMITER $$
CREATE DEFINER=`admin`@`localhost` PROCEDURE `sp_createTableEntry`(

    IN value_one VARCHAR(120),
    IN value_two VARCHAR(200)
)
BEGIN
    IF ( select exists (select 1 from table_name where column_one = value_one) ) THEN
     
        select 'Column One Exists !!';
     
    ELSE
     
        insert into table_name
        (  
            column_one,
            column_two
        )
        values
        (
            value_one,
            value_two
        );
    END IF ;
END $$
DELIMITER ;

Upvotes: 1

Shadow
Shadow

Reputation: 34231

Yes, you can do this by using sql security definer while declaring the stored procedure:

The SQL SECURITY characteristic can be DEFINER or INVOKER to specify the security context; that is, whether the routine executes using the privileges of the account named in the routine DEFINER clause or the user who invokes it. This account must have permission to access the database with which the routine is associated. The default value is DEFINER. The user who invokes the routine must have the EXECUTE privilege for it, as must the DEFINER account if the routine executes in definer security context.

The DEFINER clause specifies the MySQL account to be used when checking access privileges at routine execution time for routines that have the SQL SECURITY DEFINER characteristic.

If a user value is given for the DEFINER clause, it should be a MySQL account specified as 'user_name'@'host_name', CURRENT_USER, or CURRENT_USER(). The default DEFINER value is the user who executes the CREATE PROCEDURE or CREATE FUNCTION statement. This is the same as specifying DEFINER = CURRENT_USER explicitly.

To sum it up: the user in the definer clause has to have the select / insert privileges to the underlying table in this ase, while the user who executes the stored proc must have execute privileges to the stored proc.

Upvotes: 3

Related Questions