Granting Privileges

PostgreSQL maintains a tightly controlled set of access control lists or ACLs. This information describes which users are allowed to select from, update, and otherwise modify objects within a database. A set of access privileges and restrictions exist for each applicable database object in PostgreSQL (e.g., tables, views, and sequences). Superusers and owners of database objects maintain these ACLs through a pair of SQL commands: GRANT and REVOKE.

As stated in Chapter 9, when a user first creates a database, they are implicitly the owner of that database. Similarly, whenever someone creates that database object, it is owned by that individual who issued the related CREATE SQL command.

Aside from PostgreSQL superusers (who may manipulate any database object in any way), only the owners of database objects are allowed to grant and revoke privileges on the objects which they own. Though any user may connect to a database, if they wish access to objects within that database they must have those privileges explicitly granted to them.

Understanding Access Control

As mentioned earlier in this section, access control lists apply to three types of database objects: tables, lists, and sequences. For these objects, there are four general privileges which may be granted to, or revoked from, a user or group. The ability to revoke rights exists only to undo the function of having granted them. Users and groups have no rights to begin with.

From the psql client, you can view ACL permission summaries by using the \z slash command. This command displays all access permissions in the currently connected database. To see permissions on a specific object, specify that object's name as a parameter to the \z command. You can use a regular expression in place of a name to see privileges on a group of objects.

Table 10-2 lists each of the Access Control privileges available within PostgreSQL. Each privilege also has an associated symbol, which appears as a single alphabetical character. These symbols are shorthand for the described privilege, and are used by the psql \z slash command when displaying summaries of access permissions.

Table 10-2. PostgreSQL ACL privileges

KeywordSymbolDescription

SELECT

r

Allows a user to retrieve data from a table, view or sequence (though the nextval() function may not be called with only SELECT rights). Also known as "read" rights.

INSERT

a

Allows a user to insert new rows into a table. Also known as "append" rights.

UPDATE, DELETE

w

Allows a user to modify or remove rows of data from a table. If either the UPDATE or DELETE right is granted, the other is implicitly granted as well. Also known as "write" rights.

RULE

R

Allows a user to create a rewrite rule on a table or view.

ALL

arwR

Represents a shorthand way to grant or revoke all rights at once. ALL is not a right in and of itself. Granting ALL results in the granting of SELECT, INSERT, UPDATE, DELETE, and RULE.

Granting privileges with GRANT

To assign a privilege to a user or group, use SQL's GRANT command. Here is the syntax for GRANT:

  GRANT privilege [, ...] ON object [, ...]
        TO { PUBLIC | username | GROUP groupname }

In this syntax, privilege is any of the privileges listed in Table 10-2, object is the name of the database object (table, view or sequence) that a privilege is being granted on, and the token following the TO keyword describes who the privilege is being granted to. Multiple privileges and objects may be listed, separated from one another by commas.

Only one of the terms following TO may be used in a single GRANT statement. Granting rights with the PUBLIC keyword indiscriminately grants the intended privilege to the special "public" target. PUBLIC privileges are shared by all users. Specifying a username grants the privilege to specific user. Likewise, specifying a groupname grants the privilege to a specific group.

Suppose, for example, that the manager user needs all rights to the customers, books, editions and publishers tables. Example 10-17 gives the manager user those rights, a single GRANT statement.

Example 10-17. Granting user privileges

booktown=# GRANT ALL ON customers, books, editions, publishers
booktown-#           TO manager;
CHANGE

The use of the ALL keyword in Example 10-17 grants all possible ACL rights (SELECT, UPDATE, etc.) for the specified objects to the user manager. The CHANGE message from the server indicates that the privileges were correctly modified. Remember that you can use the \z command in psql in order to verify permissions on a database object.

booktown=# \z publishers
Access permissions for database "booktown"
  Relation  |  Access permissions
------------+----------------------
 publishers | {"=","manager=arwR"}
(1 row)

As another example, let's look at the use of the GROUP keyword to grant privileges to members of a group groupname. For instance, the entire sales department at the Book Town should be given permission to view the customers table, but not to modify it. Example 10-18 grants SELECT access on the customers table to any member of the sales group.

Example 10-18. Granting group privileges

booktown=# GRANT SELECT ON customers TO GROUP sales;
CHANGE
booktown=# \z customers
 Access permissions for database "booktown"
 Relation  |       Access permissions
-----------+---------------------------------
 customers | {"=","manager=arwR","group sales=r"}
(1 row)

Restricting Rights with REVOKE

By default, a normal user has no all privileges on any database object that they do not own. To explicitly revoke a right after it has been granted, the object's owner (or a superuser) can issue the REVOKE command. This command is very similar in form to the GRANT command.

Here is the syntax for REVOKE:

  REVOKE privilege [, ...] ON object [, ...]
         FROM { PUBLIC | username | GROUP groupname }

The structure of the REVOKE command syntax is identical to that of the GRANT command, with the exception that the SQL command itself is REVOKE rather than GRANT, and the keyword FROM is used, rather than the TO keyword.

Note: Revoking privileges from PUBLIC only affects the special "public" group, which includes all users. Revoking rights from PUBLIC will not affect any users who have been explicitly granted those privileges.

Suppose the UPDATE rights on the books table have been granted to the user david. When David is transferred to another department, and no longer needs the ability to modify book information, you should revoke David's UPDATE privilege on the books table.

Example 10-19 uses the \z slash command in psql to check the permissions on the books table, revealing that david has write-access privileges to that table. A REVOKE statement then explicitly revokes the UPDATE and DELETE privileges on the books table from the user david. Finally, another \z slash command is executed to verify the removal of the privilege.

Example 10-19. Revoking rights

booktown=# \z books
Access permissions for database "booktown"
 Relation |       Access permissions
----------+--------------------------------
 books    | {"=","manager=arwR","david=w"}
(1 row)

booktown=# REVOKE UPDATE, DELETE ON books
booktown-#        FROM david;
CHANGE
booktown=# \z books
Access permissions for database "booktown"
 Relation |  Access permissions
----------+----------------------
 books    | {"=","manager=arwR"}
(1 row)

Using Views for Access Control

While you cannot control read-access to specified columns or rows of a table, you can achieve this indirectly through the careful use of views. By creating a view on a table, and forcing users to access the table through that view, you can allow only desired columns or rows to be selected.

You limit columns by specifying a column list in the view's SELECT statement when you create the view. The view will then return only the columns you specify. You limit rows by writing a WHERE clause in the view's SELECT statement. The view will then return only those rows that match the WHERE clause (see Chapter 4, for more about creating views).

As ACL privileges may be applied to views as well as tables, you may then grant SELECT rights to the limited view, but not the table itself. Users will then be able to select from the view even though they don't have access to the underlying table.

For instance, the Book Town store has a stock table correlating a book's ISBN number to its purchase cost, retail price, and the current available stock. The table structure is shown in Table 10-3.

Table 10-3. The stock table

Column

Type

Modifier

isbn

text

NOT NULL

cost

numeric(5,2)

retail

numeric(5,2)

stock

integer

Suppose that the manager of Book Town doesn't want the salespeople to have access to the purchase cost of each book. This information can be restricted by generating a view which retrieves data from only the isbn, retail and stock columns. Example 10-20 creates such a view, grants rights to the sales group, and verifies the rights with the \z psql slash command.

Example 10-20. Controlling SELECT privileges with a view

booktown=# CREATE VIEW stock_view
booktown-#             AS SELECT isbn, retail, stock
booktown-#                FROM stock;
CREATE
booktown=# GRANT SELECT ON stock_view TO GROUP sales;
CHANGE
booktown=# \z stock
      Access permissions for database "booktown"
   Relation   |          Access permissions
--------------+---------------------------------------
 stock        |
 stock_backup |
 stock_view   | {"=","manager=arwR","group sales=r"}
(3 rows)

Example 10-21 demonstrates the addition of a new user, barbara. It grants SELECT rights on the stock_view. Since the barbara user does not have any implicit rights on the stock table, it is inaccessible; this is the case, even though the view on that table is accessible as a result of the GRANT statement.

Example 10-21. Controlling SELECT

booktown=# CREATE USER barbara;
CREATE USER
booktown=# GRANT USER barbara SELECT ON stock_view;
booktown=# \c - barbara
You are now connected as new user barbara.
booktown=> SELECT * FROM stock;
ERROR:  stock: Permission denied.
booktown=> SELECT * FROM stock_view;
    isbn    | retail | stock
------------+--------+-------
 0385121679 |  36.95 |    65
 039480001X |  32.95 |    31
 0394900014 |  23.95 |     0
 044100590X |  45.95 |    89
 0441172717 |  21.95 |    77
 0451160916 |  28.95 |    22
 0451198492 |  46.95 |     0
 0451457994 |  22.95 |     0
 0590445065 |  23.95 |    10
 0679803335 |  24.95 |    18
 0694003611 |  28.95 |    50
 0760720002 |  23.95 |    28
 0823015505 |  28.95 |    16
 0929605942 |  21.95 |    25
 1885418035 |  24.95 |    77
 0394800753 |  16.95 |     4
(16 rows)

Notice that when connected as the barbara user, the SELECT statement from the stock_view is successful, while the stock table presents a Permission denied error.