<entry><structfield>rolbypassrls</structfield></entry>
<entry><type>bool</type></entry>
<entry>
- Role can bypass row level security policies, see
+ Role bypasses every row level security policy, see
<xref linkend="ddl-rowsecurity"> for more information.
</entry>
</row>
<entry><type>bool</type></entry>
<entry></entry>
<entry>
- User can bypass row level security policies, see
+ User bypasses every row level security policy, see
<xref linkend="ddl-rowsecurity"> for more information.
</entry>
</row>
<entry><structfield>usebypassrls</structfield></entry>
<entry><type>bool</type></entry>
<entry>
- User can bypass row level security policies, see
+ User bypasses every row level security policy, see
<xref linkend="ddl-rowsecurity"> for more information.
</entry>
</row>
</term>
<listitem>
<para>
- This variable controls if row security policies are to be applied
- to queries which are run against tables that have row security enabled.
- The default is <literal>on</>. When set to <literal>on</>, all users,
- except superusers and the owner of the table, will have the row
- policies for the table applied to their queries. When set to
- <literal>off</>, queries will bypass row policies for the table, if
- possible, and error if not.
- </para>
-
- <para>
- For a user who is not a superuser and not the table owner to bypass
- row policies for the table, they must have the <literal>BYPASSRLS</>
- role attribute. If this is set to <literal>off</> and the user queries
- a table which has row policies enabled and the user does not have the
- right to bypass row policies then a permission denied error will be
- returned.
+ This variable controls whether to raise an error in lieu of applying a
+ row security policy. When set to <literal>on</>, policies apply
+ normally. When set to <literal>off</>, queries fail which would
+ otherwise apply at least one policy. The default is <literal>on</>.
+ Change to <literal>off</> where limited row visibility could cause
+ incorrect results; for example, <application>pg_dump</> makes that
+ change by default. This variable has no effect on roles which bypass
+ every row security policy, to wit, superusers and roles with
+ the <literal>BYPASSRLS</> attribute.
</para>
<para>
Row security policies can be specific to commands, or to roles, or to
both. The commands available are <literal>ALL</literal>,
<literal>SELECT</>, <literal>INSERT</>, <literal>UPDATE</>, and
- <literal>DELETE</>. Multiple roles can be assigned to a given policy
- and normal role membership and inheritance rules apply.
+ <literal>DELETE</>. Multiple roles can be assigned to a given policy and
+ normal role membership and inheritance rules apply. Table owners,
+ superusers, and roles with the <literal>BYPASSRLS</> attribute bypass the
+ row security system when querying a table. Applications that expect to
+ bypass all row security through those mechanisms should
+ set <xref linkend="guc-row-security"> to <literal>off</>.
</para>
<para>
<xref linkend="sql-altertable"> command.
</para>
- <para>
- The table owners and superusers bypass the row security system when
- querying a table. 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
<term><literal>NOBYPASSRLS</literal></term>
<listitem>
<para>
- These clauses determine whether a role is allowed to bypass row-level security (RLS)
- policies. A role having the <literal>BYPASSRLS</literal> attribute will
- be allowed to bypass row-security policies by setting
- <literal>row_security</literal> to
- <literal>OFF</literal>. <literal>NOBYPASSRLS</literal> is the default.
+ These clauses determine whether a role bypasses every row-level
+ security (RLS) policy. <literal>NOBYPASSRLS</literal> is the default.
Note that pg_dump will set <literal>row_security</literal> to
<literal>OFF</literal> by default, to ensure all contents of a table are
dumped out. If the user running pg_dump does not have appropriate
permissions, an error will be returned. The superuser and owner of the
- table being dumped are considered to always have the right to bypass RLS.
+ table being dumped always bypass RLS.
</para>
</listitem>
</varlistentry>
* for the table and the plan cache needs to be invalidated if the environment
* changes.
*
- * Handle checking as another role via checkAsUser (for views, etc). Note that
- * if *not* checking as another role, the caller should pass InvalidOid rather
- * than GetUserId(). Otherwise the check for row_security = OFF is skipped, and
- * so we may falsely report that RLS is active when the user has bypassed it.
+ * Handle checking as another role via checkAsUser (for views, etc). Pass
+ * InvalidOid to check the current user.
*
* If noError is set to 'true' then we just return RLS_ENABLED instead of doing
* an ereport() if the user has attempted to bypass RLS and they are not
return RLS_NONE;
/*
- * Check permissions
- *
- * Table owners always bypass RLS. Note that superuser is always
- * considered an owner. Return RLS_NONE_ENV to indicate that this
- * decision depends on the environment (in this case, the user_id).
+ * Table owners and BYPASSRLS users bypass RLS. Note that a superuser
+ * qualifies as both. Return RLS_NONE_ENV to indicate that this decision
+ * depends on the environment (in this case, the user_id).
*/
- if (pg_class_ownercheck(relid, user_id))
+ if (pg_class_ownercheck(relid, user_id) ||
+ has_bypassrls_privilege(user_id))
return RLS_NONE_ENV;
- /*
- * If the row_security GUC is 'off', check if the user has permission to
- * bypass RLS. row_security is always considered 'on' when querying
- * through a view or other cases where checkAsUser is valid.
- */
- if (!row_security && !checkAsUser)
- {
- if (has_bypassrls_privilege(user_id))
- /* OK to bypass */
- return RLS_NONE_ENV;
- else if (noError)
- return RLS_ENABLED;
- else
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("insufficient privilege to bypass row security.")));
- }
+ /* row_security GUC says to bypass RLS, but user lacks permission */
+ if (!row_security && !noError)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("insufficient privilege to bypass row security.")));
/* RLS should be fully enabled for this relation. */
return RLS_ENABLED;
bool rolcreatedb; /* allowed to create databases? */
bool rolcanlogin; /* allowed to log in as session user? */
bool rolreplication; /* role used for streaming replication */
- bool rolbypassrls; /* allowed to bypass row level security? */
+ bool rolbypassrls; /* bypasses row level security? */
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
/* remaining fields may be null; use heap_getattr to read them! */
SET row_security TO ON;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
0,cfcd208495d565ef66e7dff9f98764da
+1,c4ca4238a0b923820dcc509a6f75849b
2,c81e728d9d4c2f636f067f89cc14862c
+3,eccbc87e4b5ce2fe28308fd9f2a7baf3
4,a87ff679a2f3e71d9181a67b7542122c
+5,e4da3b7fbbce2345d7772b0674a318d5
6,1679091c5a880faf6fb5e6087eb1b2dc
+7,8f14e45fceea167a5a36dedd4bea2543
8,c9f0f895fb98ab9159f51fd0297e236d
+9,45c48cce2e2d7fbdea1afc51c7c6ad26
10,d3d9446802a44259755d38e6d163e820
-- Check COPY TO as user without permissions. SET row_security TO OFF;
SET SESSION AUTHORIZATION rls_regress_user2;
1,c4ca4238a0b923820dcc509a6f75849b
SET row_security TO ON;
COPY copy_rel_to TO STDOUT WITH DELIMITER ','; --ok
+1,c4ca4238a0b923820dcc509a6f75849b
-- Check COPY TO as user without permissions. SET row_security TO OFF;
SET SESSION AUTHORIZATION rls_regress_user2;
SET row_security TO OFF;
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
ERROR: COPY FROM not supported with row level security.
HINT: Use direct INSERT statements instead.
--- Check COPY TO as user with permissions and BYPASSRLS
+-- Check COPY FROM as user with permissions and BYPASSRLS
SET SESSION AUTHORIZATION rls_regress_exempt_user;
-SET row_security TO OFF;
-COPY copy_t FROM STDIN; --ok
SET row_security TO ON;
-COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
-ERROR: COPY FROM not supported with row level security.
-HINT: Use direct INSERT statements instead.
+COPY copy_t FROM STDIN; --ok
-- Check COPY FROM as user without permissions.
SET SESSION AUTHORIZATION rls_regress_user2;
SET row_security TO OFF;
SET row_security TO ON;
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
--- Check COPY TO as user with permissions and BYPASSRLS
+-- Check COPY FROM as user with permissions and BYPASSRLS
SET SESSION AUTHORIZATION rls_regress_exempt_user;
-SET row_security TO OFF;
+SET row_security TO ON;
COPY copy_t FROM STDIN; --ok
1 abc
2 bcd
3 cde
4 def
\.
-SET row_security TO ON;
-COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
-- Check COPY FROM as user without permissions.
SET SESSION AUTHORIZATION rls_regress_user2;