Is it possible to change the postgresql role a user is using when interacting with postgres after the initial connection?
The database(s) will be used in a web application and I'd like to employ database level rules on tables and schemas with connection pooling. From reading the postgresql documentation it appears I can switch roles if I originally connect as a user with the superuser role, but I would prefer to initially connect as a user with minimal permissions and switch as necessary. Having to specify the user's password when switching would be fine (in fact I'd prefer it).
What am I missing?
Update: I've tried both SET ROLE
and SET SESSION AUTHORIZATION
as suggested by @Milen however neither command seems to work if the user is not a superuser:
$ psql -U test psql (8.4.4) Type "help" for help. test=> \du test List of roles Role name | Attributes | Member of -----------+------------+---------------- test | | {connect_only} test=> \du test2 List of roles Role name | Attributes | Member of -----------+------------+---------------- test2 | | {connect_only} test=> set role test2; ERROR: permission denied to set role "test2" test=> \q
We need to make the current session user a member of the role: create role myrole; set role myrole; grant myrole to myuser; set role myrole; produces: Role ROLE created.
Switching between databases is another way of saying you are closing one connection and opening another. When you need to change between databases, you'll use the “connect” command, which is conveniently shortened to \c, followed by the database name.
CREATE ROLE sa WITH LOGIN PASSWORD 'some-password. '; CREATE DATABASE master WITH OWNER sa; \c master; Now you are running this script using "psql" command line interface (CLI), so you get the message as below... CREATE ROLE CREATE DATABASE You are now connected to database "master" as user "postgres".
--create a user that you want to use the database as: create role neil; --create the user for the web server to connect as: create role webgui noinherit login password 's3cr3t'; --let webgui set role to neil: grant neil to webgui; --this looks backwards but is correct.
webgui
is now in the neil
group, so webgui
can call set role neil
. However, webgui
did not inherit neil
's permissions.
Later, login as webgui:
psql -d some_database -U webgui (enter s3cr3t as password) set role neil;
webgui
does not need superuser
permission for this.
You want to set role
at the beginning of a database session and reset it at the end of the session. In a web app, this corresponds to getting a connection from your database connection pool and releasing it, respectively. Here's an example using Tomcat's connection pool and Spring Security:
public class SetRoleJdbcInterceptor extends JdbcInterceptor { @Override public void reset(ConnectionPool connectionPool, PooledConnection pooledConnection) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(authentication != null) { try { /* use OWASP's ESAPI to encode the username to avoid SQL Injection. Can't use parameters with SET ROLE. Need to write PG codec. Or use a whitelist-map approach */ String username = ESAPI.encoder().encodeForSQL(MY_CODEC, authentication.getName()); Statement statement = pooledConnection.getConnection().createStatement(); statement.execute("set role \"" + username + "\""); statement.close(); } catch(SQLException exp){ throw new RuntimeException(exp); } } } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("close".equals(method.getName())){ Statement statement = ((Connection)proxy).createStatement(); statement.execute("reset role"); statement.close(); } return super.invoke(proxy, method, args); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With