since-v33.diff.txt

text/plain

Filename: since-v33.diff.txt
Type: text/plain
Part: 0
Message: Re: [PoC] Federated Authn/z with OAUTHBEARER
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 8d351c2089..c5d1a1fe69 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -2341,7 +2341,7 @@ host ... radius radiusservers="server1,server2" radiussecrets="""secret one"",""
     to enable third-party applications to obtain limited access to a protected
     resource.
 
-    OAuth support has to be enabled when <productname>PostgreSQL</productname>
+    OAuth client support has to be enabled when <productname>PostgreSQL</productname>
     is built, see <xref linkend="installation"/> for more information.
 
     <itemizedlist>
@@ -2353,23 +2353,23 @@ host ... radius radiusservers="server1,server2" radiussecrets="""secret one"",""
      </listitem>
      <listitem>
       <para>
-       Client: The system which accesses to the protected resources using access
+       Client: The system which accesses the protected resources using access
        tokens.  Applications using libpq are the clients in connecting to a
        <productname>PostgreSQL</productname> cluster.
       </para>
      </listitem>
      <listitem>
       <para>
-       Authentication server: The system which recieves requests from, and
-       issues access tokens to, the client upon successful authentication by
-       the resource owner.
+       Authorization server: The system which receives requests from, and
+       issues access tokens to, the client after the authenticated resource
+       owner has given approval.
       </para>
      </listitem>
 
      <listitem>
       <para>
-       Resource server: The system which owns the protected resources and can
-       grant access to them. The <productname>PostgreSQL</productname> cluster
+       Resource server: The system which hosts the protected resources which are
+       accessed by the client. The <productname>PostgreSQL</productname> cluster
        being connected to is the resource server.
       </para>
      </listitem>
@@ -2379,7 +2379,7 @@ host ... radius radiusservers="server1,server2" radiussecrets="""secret one"",""
 
    <para>
     <productname>PostgreSQL</productname> supports bearer tokens, defined in
-    <ulink url="https://datatracker.ietf.org/doc/html/rfc6750">RFC 6750</ulink>
+    <ulink url="https://datatracker.ietf.org/doc/html/rfc6750">RFC 6750</ulink>,
     which are a type of access token used with OAuth 2.0 where the token is an
     opaque string.  The format of the access token is implementation specific
     and is chosen by each authentication server.
@@ -2402,10 +2402,11 @@ host ... radius radiusservers="server1,server2" radiussecrets="""secret one"",""
       <term><literal>scope</literal></term>
       <listitem>
        <para>
-        The OAuth scope required for the server to authenticate and/or authorize
-        the user. The value of the scope is dependent on the OAuth validation
-        module used (see <xref linkend="oauth-validators" /> for more information
-        on validators).  This parameter is required.
+        A space-separated list of the OAuth scopes needed for the server to
+        both authorize the client and authenticate the user.  Appropriate values
+        are determined by the authorization server and the OAuth validation
+        module used (see <xref linkend="oauth-validators" /> for more
+        information on validators).  This parameter is required.
        </para>
       </listitem>
      </varlistentry>
@@ -2416,8 +2417,9 @@ host ... radius radiusservers="server1,server2" radiussecrets="""secret one"",""
        <para>
         Allows for mapping between OAuth identity provider and database user
         names.  See <xref linkend="auth-username-maps"/> for details.  If a
-        map is not specified the user name returned from the OAuth validator
-        must match the role being requested.  This parameter is optional.
+        map is not specified, the user name associated with the token (as
+        determined by the OAuth validator) must exactly match the role name
+        being requested.  This parameter is optional.
        </para>
       </listitem>
      </varlistentry>
@@ -2426,10 +2428,29 @@ host ... radius radiusservers="server1,server2" radiussecrets="""secret one"",""
       <term><literal>trust_validator_authz</literal></term>
       <listitem>
        <para>
-        When set to <literal>1</literal> standard user mapping is skipped. If
-        the OAuth token is validated the user can connect under its desired
-        role.
+        An advanced option which is not intended for common use.
        </para>
+       <para>
+        When set to <literal>1</literal>, standard user mapping is skipped, and
+        the OAuth validator takes full responsibility for mapping end user
+        identities to database roles.  If the validator authorizes the token,
+        the server trusts that the user is allowed to connect under the
+        requested role, and the connection is allowed to proceed regardless of
+        the authentication status of the user.
+       </para>
+       <para>
+        This parameter is incompatible with <literal>map</literal>.
+       </para>
+       <warning>
+        <para>
+         <literal>trust_validator_authz</literal> provides additional
+         flexibility in the design of the authentication system, but it also
+         requires careful implementation of the OAuth validator, which must
+         determine whether the provided token carries sufficient end-user
+         privileges in addition to the <link linkend="oauth-validators">standard
+         checks</link> required of all validators.  Use with caution.
+        </para>
+       </warning>
       </listitem>
      </varlistentry>
     </variablelist>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 73bf21c599..7cb3afb7af 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1202,19 +1202,6 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>
 
-     <varlistentry id="guc-oauth-validator-library" xreflabel="oauth_validator_library">
-      <term><varname>oauth_validator_library</varname> (<type>string</type>)
-      <indexterm>
-       <primary><varname>oauth_validator_library</varname> configuration parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
-       <para>
-	    TODO
-       </para>
-      </listitem>
-     </varlistentry>
-
      <varlistentry id="guc-oauth-validator-library" xreflabel="oauth_validator_library">
       <term><varname>oauth_validator_library</varname> (<type>string</type>)
       <indexterm>
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 86fd146af2..62b8ae3b42 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -2341,7 +2341,12 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       <term><literal>oauth_client_id</literal></term>
       <listitem>
        <para>
-        The client identifier as issued by the authorization server.
+        An OAuth 2.0 client identifier, as issued by the authorization server.
+        If the <productname>PostgreSQL</productname> server
+        <link linkend="auth-oauth">requests an OAuth token</link> for the
+        connection (and if no <link linkend="libpq-oauth">custom OAuth
+        hook</link> is installed to provide one), then this parameter must be
+        set; otherwise, the connection will fail.
        </para>
       </listitem>
      </varlistentry>
@@ -2350,7 +2355,10 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       <term><literal>oauth_client_secret</literal></term>
       <listitem>
        <para>
-        The client password.
+        The client password, if any, to use when contacting the OAuth
+        authorization server. Whether this parameter is required or not is
+        determined by the OAuth provider; "public" clients generally do not use
+        a secret, whereas "confidential" clients generally do.
        </para>
       </listitem>
      </varlistentry>
@@ -2359,7 +2367,27 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       <term><literal>oauth_issuer</literal></term>
       <listitem>
        <para>
-        TODO
+        The HTTPS URL of an issuer to contact if the server requests an OAuth
+        token for the connection. This parameter is optional and intended for
+        advanced usage; see also <xref linkend="libpq-connect-oauth-scope"/>.
+       </para>
+       <para>
+        If no <literal>oauth_issuer</literal> is provided, the client will ask
+        the <productname>PostgreSQL</productname> server to provide an
+        acceptable issuer URL (as configured in its
+        <link linkend="auth-oauth">HBA settings</link>). This is convenient, but
+        it requires two separate network connections to the server per attempt.
+       </para>
+       <para>
+        Providing an explicit <literal>oauth_issuer</literal> (and, typically,
+        an accompanying <literal>oauth_scope</literal>) skips this initial
+        "discovery" phase, which may speed up certain custom OAuth flows.
+        <!-- TODO: note to reviewer: the following is only partially implemented. -->
+        This parameter may also be set defensively, to prevent the backend
+        server from directing the client to arbitrary URLs.
+        <emphasis>However:</emphasis> if the client's issuer setting differs
+        from the server's expected issuer, the server is likely to reject the
+        issued token, and the connection will fail.
        </para>
       </listitem>
      </varlistentry>
@@ -2368,8 +2396,26 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       <term><literal>oauth_scope</literal></term>
       <listitem>
        <para>
-        The scope of the access request sent to the authorization server.
-        This parameter is optional.
+        The scope of the access request sent to the authorization server,
+        specified as a (possibly empty) space-separated list of OAuth scope
+        identifiers. This parameter is optional and intended for advanced usage.
+       </para>
+       <para>
+        <!-- TODO: note to reviewer: the following is only partially implemented. -->
+        If neither <xref linkend="libpq-connect-oauth-issuer"/> nor
+        <literal>oauth_scope</literal> is specified, the client will obtain
+        appropriate scope settings from the
+        <productname>PostgreSQL</productname> server. Otherwise, the value of
+        this parameter will be used. Similarly to
+        <literal>oauth_issuer</literal>, if the client's scope setting does not
+        contain the server's required scopes, the server is likely to reject the
+        issued token, and the connection will fail.
+       </para>
+       <para>
+        The meaning of an empty scope list is provider-dependent. An OAuth
+        authorization server may choose to issue a token with "default scope",
+        whatever that happens to be, or it may reject the token request
+        entirely.
        </para>
       </listitem>
      </varlistentry>
diff --git a/src/backend/libpq/auth-oauth.c b/src/backend/libpq/auth-oauth.c
index cfa5769b10..90e68dbc93 100644
--- a/src/backend/libpq/auth-oauth.c
+++ b/src/backend/libpq/auth-oauth.c
@@ -669,7 +669,7 @@ cleanup:
  *
  * Load the configured validator library in order to perform token validation.
  * There is no built-in fallback since validation is implementation specific. If
- * no validator library is configured, or of it fails to load, then error out
+ * no validator library is configured, or if it fails to load, then error out
  * since token validation won't be possible.
  */
 static void
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index dcb1558ad3..c623b8463d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -2482,20 +2482,17 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
 	}
 	else if (strcmp(name, "issuer") == 0)
 	{
-		if (hbaline->auth_method != uaOAuth)
-			INVALID_AUTH_OPTION("issuer", gettext_noop("oauth"));
+		REQUIRE_AUTH_OPTION(uaOAuth, "issuer", "oauth");
 		hbaline->oauth_issuer = pstrdup(val);
 	}
 	else if (strcmp(name, "scope") == 0)
 	{
-		if (hbaline->auth_method != uaOAuth)
-			INVALID_AUTH_OPTION("scope", gettext_noop("oauth"));
+		REQUIRE_AUTH_OPTION(uaOAuth, "scope", "oauth");
 		hbaline->oauth_scope = pstrdup(val);
 	}
 	else if (strcmp(name, "trust_validator_authz") == 0)
 	{
-		if (hbaline->auth_method != uaOAuth)
-			INVALID_AUTH_OPTION("trust_validator_authz", gettext_noop("oauth"));
+		REQUIRE_AUTH_OPTION(uaOAuth, "trust_validator_authz", "oauth");
 		if (strcmp(val, "1") == 0)
 			hbaline->oauth_skip_usermap = true;
 		else
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index bad13497a3..b64c8dea97 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -53,8 +53,8 @@
 # directly connected to.
 #
 # METHOD can be "trust", "reject", "md5", "password", "scram-sha-256",
-# "gss", "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert".
-# Note that "password" sends passwords in clear text; "md5" or
+# "gss", "sspi", "ident", "peer", "pam", "oauth", "ldap", "radius" or
+# "cert".  Note that "password" sends passwords in clear text; "md5" or
 # "scram-sha-256" are preferred since they send encrypted passwords.
 #
 # OPTIONS are a set of options for the authentication in the format