aboutsummaryrefslogtreecommitdiff
path: root/doc/src
diff options
context:
space:
mode:
authorStephen Frost <sfrost@snowman.net>2014-09-24 16:32:22 -0400
committerStephen Frost <sfrost@snowman.net>2014-09-24 16:32:22 -0400
commit6550b901fe7c47c03775400e0c790c6c1234a017 (patch)
treef67c2cabd58ef765f0bcaf4307d73d7eac51e5fc /doc/src
parent3f6f9260e308a331e6809d5309b17d1613ff900f (diff)
downloadpostgresql-6550b901fe7c47c03775400e0c790c6c1234a017.tar.gz
postgresql-6550b901fe7c47c03775400e0c790c6c1234a017.zip
Code review for row security.
Buildfarm member tick identified an issue where the policies in the relcache for a relation were were being replaced underneath a running query, leading to segfaults while processing the policies to be added to a query. Similar to how TupleDesc RuleLocks are handled, add in a equalRSDesc() function to check if the policies have actually changed and, if not, swap back the rsdesc field (using the original instead of the temporairly built one; the whole structure is swapped and then specific fields swapped back). This now passes a CLOBBER_CACHE_ALWAYS for me and should resolve the buildfarm error. In addition to addressing this, add a new chapter in Data Definition under Privileges which explains row security and provides examples of its usage, change \d to always list policies (even if row security is disabled- but note that it is disabled, or enabled with no policies), rework check_role_for_policy (it really didn't need the entire policy, but it did need to be using has_privs_of_role()), and change the field in pg_class to relrowsecurity from relhasrowsecurity, based on Heikki's suggestion. Also from Heikki, only issue SET ROW_SECURITY in pg_restore when talking to a 9.5+ server, list Bypass RLS in \du, and document --enable-row-security options for pg_dump and pg_restore. Lastly, fix a number of minor whitespace and typo issues from Heikki, Dimitri, add a missing #include, per Peter E, fix a few minor variable-assigned-but-not-used and resource leak issues from Coverity and add tab completion for role attribute bypassrls as well.
Diffstat (limited to 'doc/src')
-rw-r--r--doc/src/sgml/catalogs.sgml11
-rw-r--r--doc/src/sgml/config.sgml4
-rw-r--r--doc/src/sgml/ddl.sgml168
-rw-r--r--doc/src/sgml/ref/alter_table.sgml2
-rw-r--r--doc/src/sgml/ref/create_policy.sgml2
-rw-r--r--doc/src/sgml/ref/pg_dump.sgml17
-rw-r--r--doc/src/sgml/ref/pg_restore.sgml23
7 files changed, 218 insertions, 9 deletions
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 76d64050618..a6ca290cb3d 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1941,8 +1941,9 @@
</row>
<row>
- <entry><structfield>relhasrowsecurity</structfield></entry>
+ <entry><structfield>relrowsecurity</structfield></entry>
<entry><type>bool</type></entry>
+ <entry></entry>
<entry>
True if table has row-security enabled; see
<link linkend="catalog-pg-rowsecurity"><structname>pg_rowsecurity</structname></link> catalog
@@ -5415,7 +5416,7 @@
<note>
<para>
- <literal>pg_class.relhasrowsecurity</literal>
+ <literal>pg_class.relrowsecurity</literal>
True if the table has row-security enabled.
Must be true if the table has a row-security policy in this catalog.
</para>
@@ -9228,10 +9229,10 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
<entry>True if table has (or once had) triggers</entry>
</row>
<row>
- <entry><structfield>hasrowsecurity</structfield></entry>
+ <entry><structfield>rowsecurity</structfield></entry>
<entry><type>boolean</type></entry>
- <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relhasrowsecurity</literal></entry>
- <entry>True if table has row security enabled</entry>
+ <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relrowsecurity</literal></entry>
+ <entry>True if row security is enabled on the table</entry>
</row>
</tbody>
</tgroup>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 70e47aaa3a1..949443931cd 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -5457,9 +5457,9 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
<para>
The allowed values of <varname>row_security</> are
- <literal>on</> (apply normally- not to superuser or table owner),
+ <literal>on</> (apply normally - not to superuser or table owner),
<literal>off</> (fail if row security would be applied), and
- <literal>force</> (apply always- even to superuser and table owner).
+ <literal>force</> (apply always - even to superuser and table owner).
</para>
<para>
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index c07f5a203dd..e5ee5910513 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -1508,6 +1508,174 @@ REVOKE ALL ON accounts FROM PUBLIC;
</para>
</sect1>
+ <sect1 id="ddl-rowsecurity">
+ <title>Row Security Policies</title>
+
+ <indexterm zone="ddl-rowsecurity">
+ <primary>rowsecurity</primary>
+ </indexterm>
+
+ <indexterm zone="ddl-rowsecurity">
+ <primary>rls</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>policies</primary>
+ <see>policy</see>
+ </indexterm>
+
+ <indexterm zone="ddl-rowsecurity">
+ <primary>POLICY</primary>
+ </indexterm>
+
+ <para>
+ In addition to the <xref linkend="ddl-priv"> system available through
+ <xref linkend="sql-grant">, tables can have row security policies
+ which limit the rows returned for normal queries and rows which can
+ be added through data modification commands. By default, tables do
+ not have any policies and all rows are visible and able to be added,
+ subject to the regular <xref linkend="ddl-priv"> system. This is
+ also known to as Row Level Security.
+ </para>
+
+ <para>
+ When row security is enabled on a table with
+ <xref linkend="sql-altertable">, all normal access to the table
+ (excluding the owner) for selecting rows or adding rows must be through
+ a policy. If no policy exists for the table, a default-deny policy is
+ used and no rows are visible or can be added. Privileges which operate
+ at the whole table level such as <literal>TRUNCATE</>, and
+ <literal>REFERENCES</> are not subject to row security.
+ </para>
+
+ <para>
+ Row security policies can be specific to commands, or to roles, or to
+ both. The commands available are <literal>SELECT</>, <literal>INSERT</>,
+ <literal>UPDATE</>, and <literal>DELETE</>. Multiple roles can be
+ assigned to a given policy and normal role membership and inheiritance
+ rules apply.
+ </para>
+
+ <para>
+ To specify which rows are visible and what rows can be added to the
+ table with row security, an expression is required which returns a
+ boolean result. This expression will be evaluated for each row prior
+ to other conditionals or functions which are part of the query. The
+ one exception to this rule are <literal>leakproof</literal> functions,
+ which are guaranteed to not leak information. Two expressions may be
+ specified to provide independent control over the rows which are
+ visible and the rows which are allowed to be added. The expression
+ is run as part of the query and with the privileges of the user
+ running the query, however, security definer functions can be used in
+ the expression.
+ </para>
+
+ <para>
+ Enabling and disabling row security, as well as adding policies to a
+ table, is always the privilege of the owner only.
+ </para>
+
+ <para>
+ Policies are created using the <xref linkend="sql-createpolicy">
+ command, altered using the <xref linkend="sql-alterpolicy"> command,
+ and dropped using the <xref linkend="sql-droppolicy"> command. To
+ enable and disable row security for a given table, use the
+ <xref linkend="sql-altertable"> command.
+ </para>
+
+ <para>
+ The table owners and superusers bypass the row security system when
+ querying a table, by default. Row security can be enabled for
+ superusers and table owners by setting
+ <xref linkend="guc-row-security"> to <literal>force</literal>. Any
+ user can request that row security be bypassed by setting
+ <xref linkend="guc-row-security"> to <literal>off</literal>. If
+ the user does not have privileges to bypass row security when
+ querying a given table then an error will be returned instead. Other
+ users can be granted the ability to bypass the row security system
+ with the <literal>BYPASSRLS</literal> role attribute. This
+ attribute can only be set by a superuser.
+ </para>
+
+ <para>
+ Each policy has a name and multiple policies can be defined for a
+ table. As policies are table-specific, each policy for a table must
+ have a unique name. Different tables may have policies with the
+ same name.
+ </para>
+
+ <para>
+ When multiple policies apply to a given query, they are combined using
+ <literal>OR</literal>, similar to how a given role has the privileges
+ of all roles which they are a member of.
+ </para>
+
+ <para>
+ Referential integrity checks, such as unique or primary key constraints
+ and foreign key references, will bypass row security to ensure that
+ data integrity is maintained. Care must be taken when developing
+ schemas and row level policies to avoid a "covert channel" leak of
+ information through these referntial integrity checks.
+ </para>
+
+ <para>
+ To enable row security for a table,
+ the <command>ALTER TABLE</command> is used. For example, to enable
+ row level security for the table accounts, use:
+ </para>
+
+<programlisting>
+-- Create the table first
+CREATE TABLE accounts (manager text, company text, contact_email text);
+ALTER TABLE accounts ENABLE ROW LEVEL SECURITY;
+</programlisting>
+
+ <para>
+ To create a policy on the account relation to allow the managers role
+ to view the rows of their accounts, the <command>CREATE POLICY</command>
+ command can be used:
+ </para>
+
+<programlisting>
+CREATE POLICY account_managers ON accounts TO managers
+ USING (manager = current_user);
+</programlisting>
+
+ <para>
+ If no role is specified, or the special <quote>user</quote> name
+ <literal>PUBLIC</literal> is used, then the policy applies to all
+ users on the system. To allow all users to view their own row in
+ a user table, a simple policy can be used:
+ </para>
+
+<programlisting>
+CREATE POLICY user_policy ON users
+ USING (user = current_user);
+</programlisting>
+
+ <para>
+ To use a different policy for rows which are being added to the
+ table from those rows which are visible, the WITH CHECK clause
+ can be used. This would allow all users to view all rows in the
+ users table, but only modify their own:
+ </para>
+
+<programlisting>
+CREATE POLICY user_policy ON users
+ USING (true)
+ WITH CHECK (user = current_user);
+</programlisting>
+
+ <para>
+ Row security can be disabled with the <command>ALTER TABLE</command>
+ also. Note that disabling row security does not remove the
+ policies which are defined on the table, they are simply ignored
+ and all rows are visible and able to be added, subject to the
+ normal privileges system.
+ </para>
+
+ </sect1>
+
<sect1 id="ddl-schemas">
<title>Schemas</title>
diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index 1b35756c295..b5ef09e6a4a 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -429,7 +429,7 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
These forms control the application of row security policies belonging
to the table. If enabled and no policies exist for the table, then a
default-deny policy is applied. Note that policies can exist for a table
- even if row level security is disabled- in this case, the policies will
+ even if row level security is disabled - in this case, the policies will
NOT be applied and the policies will be ignored.
See also
<xref linkend="SQL-CREATEPOLICY">.
diff --git a/doc/src/sgml/ref/create_policy.sgml b/doc/src/sgml/ref/create_policy.sgml
index c6599eda1c0..3c5bdc69cdc 100644
--- a/doc/src/sgml/ref/create_policy.sgml
+++ b/doc/src/sgml/ref/create_policy.sgml
@@ -240,7 +240,7 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
</varlistentry>
<varlistentry id="SQL-CREATEPOLICY-UPDATE">
- <term><literal>DELETE</></term>
+ <term><literal>UPDATE</></term>
<listitem>
<para>
Using <literal>UPDATE</literal> for a policy means that it will apply
diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index eabdc62f820..c92c6eef5d3 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -688,6 +688,23 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>--enable-row-security</></term>
+ <listitem>
+ <para>
+ This option is relevant only when dumping the contents of a table
+ which has row security. By default, pg_dump will set
+ <literal>ROW_SECURITY</literal> to <literal>OFF</literal>, to ensure
+ that all data is dumped from the table. If the user does not have
+ sufficient privileges to bypass row security, then an error is thrown.
+ This parameter instructs <application>pg_dump</application> to set
+ row_security to 'ON' instead, allowing the user to dump the contents
+ of the table which they have access to.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--exclude-table-data=<replaceable class="parameter">table</replaceable></option></term>
<listitem>
<para>
diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml
index 4bc30ce679b..9f8dc00480c 100644
--- a/doc/src/sgml/ref/pg_restore.sgml
+++ b/doc/src/sgml/ref/pg_restore.sgml
@@ -491,6 +491,29 @@
</varlistentry>
<varlistentry>
+ <term><option>--enable-row-security</></term> <listitem>
+ <para>
+ This option is relevant only when restoring the contents of a table
+ which has row security. By default, pg_restore will set
+ <literal>ROW_SECURITY</literal> to <literal>OFF</literal>, to ensure
+ that all data is restored in to the table. If the user does not have
+ sufficient privileges to bypass row security, then an error is thrown.
+ This parameter instructs <application>pg_restore</application> to set
+ row_security to 'ON' instead, allowing the user to attempt to restore
+ the contents of the table with row security enabled. This may still
+ fail if the user does not have the right to insert the rows from the
+ dump into the table.
+ </para>
+
+ <para>
+ Note that this option currently also requires the dump be in INSERT
+ format as COPY TO does not support row security.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--if-exists</option></term>
<listitem>
<para>