Skip to content

Filter function accessibility by role on execute privilege + test #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/sql_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ impl Function {
&& !self.is_function_overloaded(function_name_to_count)
&& !self.has_a_nameless_arg()
&& !self.has_a_default_arg()
&& self.permissions.is_executable
}

fn arg_types_are_supported(&self, types: &HashMap<u32, Arc<Type>>) -> bool {
Expand Down
139 changes: 139 additions & 0 deletions test/expected/permissions_functions.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
begin;
-- Create a new non-superuser role to manipulate permissions
create role api;
grant usage on schema graphql to api;
-- Create minimal Query function
create function public.get_one()
returns int
language sql
immutable
as
$$
select 1;
$$;
savepoint a;
-- Use api role
set role api;
-- Confirm that getOne is visible to the api role
select jsonb_pretty(
graphql.resolve($$
{
__type(name: "Query") {
fields {
name
}
}
}
$$)
);
jsonb_pretty
--------------------------------------
{ +
"data": { +
"__type": { +
"fields": [ +
{ +
"name": "getOne"+
}, +
{ +
"name": "node" +
} +
] +
} +
} +
}
(1 row)

-- Execute
select jsonb_pretty(
graphql.resolve($$
{ getOne }
$$)
);
jsonb_pretty
---------------------
{ +
"data": { +
"getOne": 1+
} +
}
(1 row)

-- revert to superuser
rollback to savepoint a;
select current_user;
current_user
--------------
postgres
(1 row)

-- revoke default access from the public role for new functions
-- this is not actually necessary for this test, but including here
-- as a best practice in case this test is used as a reference
alter default privileges revoke execute on functions from public;
-- explicitly revoke execute from api role
revoke execute on function public.get_one from api;
-- api inherits from the public role, so we need to revoke from public too
revoke execute on function public.get_one from public;
-- Use api role w/o execute permission on get_one
set role api;
-- confirm we're using the api role
select current_user;
current_user
--------------
api
(1 row)

-- confirm that api can not execute get_one()
select pg_catalog.has_function_privilege('api', 'get_one()', 'execute');
has_function_privilege
------------------------
f
(1 row)

-- Confirm getOne is not visible in the Query type
select jsonb_pretty(
graphql.resolve($$
{
__type(name: "Query") {
fields {
name
}
}
}
$$)
);
jsonb_pretty
------------------------------------
{ +
"data": { +
"__type": { +
"fields": [ +
{ +
"name": "node"+
} +
] +
} +
} +
}
(1 row)

-- Confirm getOne can not be executed / is not found during resolution
select jsonb_pretty(
graphql.resolve($$
{ getOne }
$$)
);
jsonb_pretty
-----------------------------------------------------------------
{ +
"data": null, +
"errors": [ +
{ +
"message": "Unknown field \"getOne\" on type Query"+
} +
] +
}
(1 row)

rollback;
84 changes: 84 additions & 0 deletions test/sql/permissions_functions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
begin;

-- Create a new non-superuser role to manipulate permissions
create role api;
grant usage on schema graphql to api;

-- Create minimal Query function
create function public.get_one()
returns int
language sql
immutable
as
$$
select 1;
$$;

savepoint a;

-- Use api role
set role api;

-- Confirm that getOne is visible to the api role
select jsonb_pretty(
graphql.resolve($$
{
__type(name: "Query") {
fields {
name
}
}
}
$$)
);

-- Execute
select jsonb_pretty(
graphql.resolve($$
{ getOne }
$$)
);

-- revert to superuser
rollback to savepoint a;
select current_user;

-- revoke default access from the public role for new functions
-- this is not actually necessary for this test, but including here
-- as a best practice in case this test is used as a reference
alter default privileges revoke execute on functions from public;
-- explicitly revoke execute from api role
revoke execute on function public.get_one from api;
-- api inherits from the public role, so we need to revoke from public too
revoke execute on function public.get_one from public;

-- Use api role w/o execute permission on get_one
set role api;

-- confirm we're using the api role
select current_user;

-- confirm that api can not execute get_one()
select pg_catalog.has_function_privilege('api', 'get_one()', 'execute');

-- Confirm getOne is not visible in the Query type
select jsonb_pretty(
graphql.resolve($$
{
__type(name: "Query") {
fields {
name
}
}
}
$$)
);

-- Confirm getOne can not be executed / is not found during resolution
select jsonb_pretty(
graphql.resolve($$
{ getOne }
$$)
);

rollback;