1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>50.1. Safely Designing a Validator Module</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="oauth-validators.html" title="Chapter 50. OAuth Validator Modules" /><link rel="next" href="oauth-validator-init.html" title="50.2. Initialization Functions" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">50.1. Safely Designing a Validator Module</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="oauth-validators.html" title="Chapter 50. OAuth Validator Modules">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="oauth-validators.html" title="Chapter 50. OAuth Validator Modules">Up</a></td><th width="60%" align="center">Chapter 50. OAuth Validator Modules</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="oauth-validator-init.html" title="50.2. Initialization Functions">Next</a></td></tr></table><hr /></div><div class="sect1" id="OAUTH-VALIDATOR-DESIGN"><div class="titlepage"><div><div><h2 class="title" style="clear: both">50.1. Safely Designing a Validator Module <a href="#OAUTH-VALIDATOR-DESIGN" class="id_link">#</a></h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="oauth-validator-design.html#OAUTH-VALIDATOR-DESIGN-RESPONSIBILITIES">50.1.1. Validator Responsibilities</a></span></dt><dt><span class="sect2"><a href="oauth-validator-design.html#OAUTH-VALIDATOR-DESIGN-GUIDELINES">50.1.2. General Coding Guidelines</a></span></dt><dt><span class="sect2"><a href="oauth-validator-design.html#OAUTH-VALIDATOR-DESIGN-USERMAP-DELEGATION">50.1.3. Authorizing Users (Usermap Delegation)</a></span></dt></dl></div><div class="warning"><h3 class="title">Warning</h3><p>
3 Read and understand the entirety of this section before implementing a
4 validator module. A malfunctioning validator is potentially worse than no
5 authentication at all, both because of the false sense of security it
6 provides, and because it may contribute to attacks against other pieces of
8 </p></div><div class="sect2" id="OAUTH-VALIDATOR-DESIGN-RESPONSIBILITIES"><div class="titlepage"><div><div><h3 class="title">50.1.1. Validator Responsibilities <a href="#OAUTH-VALIDATOR-DESIGN-RESPONSIBILITIES" class="id_link">#</a></h3></div></div></div><p>
9 Although different modules may take very different approaches to token
10 validation, implementations generally need to perform three separate
12 </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">Validate the Token</span></dt><dd><p>
13 The validator must first ensure that the presented token is in fact a
14 valid Bearer token for use in client authentication. The correct way to
15 do this depends on the provider, but it generally involves either
16 cryptographic operations to prove that the token was created by a trusted
17 party (offline validation), or the presentation of the token to that
18 trusted party so that it can perform validation for you (online
21 Online validation, usually implemented via
22 <a class="ulink" href="https://datatracker.ietf.org/doc/html/rfc7662" target="_top">OAuth Token
23 Introspection</a>, requires fewer steps of a validator module and
24 allows central revocation of a token in the event that it is stolen
25 or misissued. However, it does require the module to make at least one
26 network call per authentication attempt (all of which must complete
27 within the configured <a class="xref" href="runtime-config-connection.html#GUC-AUTHENTICATION-TIMEOUT">authentication_timeout</a>).
28 Additionally, your provider may not provide introspection endpoints for
29 use by external resource servers.
31 Offline validation is much more involved, typically requiring a validator
32 to maintain a list of trusted signing keys for a provider and then
33 check the token's cryptographic signature along with its contents.
34 Implementations must follow the provider's instructions to the letter,
35 including any verification of issuer ("where is this token from?"),
36 audience ("who is this token for?"), and validity period ("when can this
37 token be used?"). Since there is no communication between the module and
38 the provider, tokens cannot be centrally revoked using this method;
39 offline validator implementations may wish to place restrictions on the
40 maximum length of a token's validity period.
42 If the token cannot be validated, the module should immediately fail.
43 Further authentication/authorization is pointless if the bearer token
44 wasn't issued by a trusted party.
45 </p></dd><dt><span class="term">Authorize the Client</span></dt><dd><p>
46 Next the validator must ensure that the end user has given the client
47 permission to access the server on their behalf. This generally involves
48 checking the scopes that have been assigned to the token, to make sure
49 that they cover database access for the current HBA parameters.
51 The purpose of this step is to prevent an OAuth client from obtaining a
52 token under false pretenses. If the validator requires all tokens to
53 carry scopes that cover database access, the provider should then loudly
54 prompt the user to grant that access during the flow. This gives them the
55 opportunity to reject the request if the client isn't supposed to be
56 using their credentials to connect to databases.
58 While it is possible to establish client authorization without explicit
59 scopes by using out-of-band knowledge of the deployed architecture, doing
60 so removes the user from the loop, which prevents them from catching
61 deployment mistakes and allows any such mistakes to be exploited
62 silently. Access to the database must be tightly restricted to only
64 <a href="#ftn.id-1.8.17.6.3.3.2.2.3.1" class="footnote"><sup class="footnote" id="id-1.8.17.6.3.3.2.2.3.1">[17]</sup></a>
65 if users are not prompted for additional scopes.
67 Even if authorization fails, a module may choose to continue to pull
68 authentication information from the token for use in auditing and
70 </p></dd><dt><span class="term">Authenticate the End User</span></dt><dd><p>
71 Finally, the validator should determine a user identifier for the token,
72 either by asking the provider for this information or by extracting it
73 from the token itself, and return that identifier to the server (which
74 will then make a final authorization decision using the HBA
75 configuration). This identifier will be available within the session via
76 <a class="link" href="functions-info.html#FUNCTIONS-INFO-SESSION-TABLE" title="Table 9.71. Session Information Functions"><code class="function">system_user</code></a>
77 and recorded in the server logs if <a class="xref" href="runtime-config-logging.html#GUC-LOG-CONNECTIONS">log_connections</a>
80 Different providers may record a variety of different authentication
81 information for an end user, typically referred to as
82 <span class="emphasis"><em>claims</em></span>. Providers usually document which of these
83 claims are trustworthy enough to use for authorization decisions and
84 which are not. (For instance, it would probably not be wise to use an
85 end user's full name as the identifier for authentication, since many
86 providers allow users to change their display names arbitrarily.)
87 Ultimately, the choice of which claim (or combination of claims) to use
88 comes down to the provider implementation and application requirements.
90 Note that anonymous/pseudonymous login is possible as well, by enabling
91 usermap delegation; see
92 <a class="xref" href="oauth-validator-design.html#OAUTH-VALIDATOR-DESIGN-USERMAP-DELEGATION" title="50.1.3. Authorizing Users (Usermap Delegation)">Section 50.1.3</a>.
93 </p></dd></dl></div></div><div class="sect2" id="OAUTH-VALIDATOR-DESIGN-GUIDELINES"><div class="titlepage"><div><div><h3 class="title">50.1.2. General Coding Guidelines <a href="#OAUTH-VALIDATOR-DESIGN-GUIDELINES" class="id_link">#</a></h3></div></div></div><p>
94 Developers should keep the following in mind when implementing token
96 </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">Token Confidentiality</span></dt><dd><p>
97 Modules should not write tokens, or pieces of tokens, into the server
98 log. This is true even if the module considers the token invalid; an
99 attacker who confuses a client into communicating with the wrong provider
100 should not be able to retrieve that (otherwise valid) token from the
103 Implementations that send tokens over the network (for example, to
104 perform online token validation with a provider) must authenticate the
105 peer and ensure that strong transport security is in use.
106 </p></dd><dt><span class="term">Logging</span></dt><dd><p>
107 Modules may use the same <a class="link" href="error-message-reporting.html" title="55.2. Reporting Errors Within the Server">logging
108 facilities</a> as standard extensions; however, the rules for emitting
109 log entries to the client are subtly different during the authentication
110 phase of the connection. Generally speaking, modules should log
111 verification problems at the <code class="symbol">COMMERROR</code> level and return
112 normally, instead of using <code class="symbol">ERROR</code>/<code class="symbol">FATAL</code>
113 to unwind the stack, to avoid leaking information to unauthenticated
115 </p></dd><dt><span class="term">Interruptibility</span></dt><dd><p>
116 Modules must remain interruptible by signals so that the server can
117 correctly handle authentication timeouts and shutdown signals from
118 <span class="application">pg_ctl</span>. For example, blocking calls on sockets
119 should generally be replaced with code that handles both socket events
120 and interrupts without races (see <code class="function">WaitLatchOrSocket()</code>,
121 <code class="function">WaitEventSetWait()</code>, et al), and long-running loops
122 should periodically call <code class="function">CHECK_FOR_INTERRUPTS()</code>.
123 Failure to follow this guidance may result in unresponsive backend
125 </p></dd><dt><span class="term">Testing</span></dt><dd><p>
126 The breadth of testing an OAuth system is well beyond the scope of this
127 documentation, but at minimum, negative testing should be considered
128 mandatory. It's trivial to design a module that lets authorized users in;
129 the whole point of the system is to keep unauthorized users out.
130 </p></dd><dt><span class="term">Documentation</span></dt><dd><p>
131 Validator implementations should document the contents and format of the
132 authenticated ID that is reported to the server for each end user, since
133 DBAs may need to use this information to construct pg_ident maps. (For
134 instance, is it an email address? an organizational ID number? a UUID?)
135 They should also document whether or not it is safe to use the module in
136 <code class="symbol">delegate_ident_mapping=1</code> mode, and what additional
137 configuration is required in order to do so.
138 </p></dd></dl></div></div><div class="sect2" id="OAUTH-VALIDATOR-DESIGN-USERMAP-DELEGATION"><div class="titlepage"><div><div><h3 class="title">50.1.3. Authorizing Users (Usermap Delegation) <a href="#OAUTH-VALIDATOR-DESIGN-USERMAP-DELEGATION" class="id_link">#</a></h3></div></div></div><p>
139 The standard deliverable of a validation module is the user identifier,
140 which the server will then compare to any configured
141 <a class="link" href="auth-username-maps.html" title="20.2. User Name Maps"><code class="filename">pg_ident.conf</code>
142 mappings</a> and determine whether the end user is authorized to connect.
143 However, OAuth is itself an authorization framework, and tokens may carry
144 information about user privileges. For example, a token may be associated
145 with the organizational groups that a user belongs to, or list the roles
146 that a user may assume, and duplicating that knowledge into local usermaps
147 for every server may not be desirable.
149 To bypass username mapping entirely, and have the validator module assume
150 the additional responsibility of authorizing user connections, the HBA may
151 be configured with <a class="xref" href="auth-oauth.html#AUTH-OAUTH-DELEGATE-IDENT-MAPPING">delegate_ident_mapping</a>.
152 The module may then use token scopes or an equivalent method to decide
153 whether the user is allowed to connect under their desired role. The user
154 identifier will still be recorded by the server, but it plays no part in
155 determining whether to continue the connection.
157 Using this scheme, authentication itself is optional. As long as the module
158 reports that the connection is authorized, login will continue even if there
159 is no recorded user identifier at all. This makes it possible to implement
160 anonymous or pseudonymous access to the database, where the third-party
161 provider performs all necessary authentication but does not provide any
162 user-identifying information to the server. (Some providers may create an
163 anonymized ID number that can be recorded instead, for later auditing.)
165 Usermap delegation provides the most architectural flexibility, but it turns
166 the validator module into a single point of failure for connection
167 authorization. Use with caution.
168 </p></div><div class="footnotes"><br /><hr style="width:100; text-align:left;margin-left: 0" /><div id="ftn.id-1.8.17.6.3.3.2.2.3.1" class="footnote"><p><a href="#id-1.8.17.6.3.3.2.2.3.1" class="para"><sup class="para">[17] </sup></a>
169 That is, "trusted" in the sense that the OAuth client and the
170 <span class="productname">PostgreSQL</span> server are controlled by the same
171 entity. Notably, the Device Authorization client flow supported by
172 libpq does not usually meet this bar, since it's designed for use by
173 public/untrusted clients.
174 </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="oauth-validators.html" title="Chapter 50. OAuth Validator Modules">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="oauth-validators.html" title="Chapter 50. OAuth Validator Modules">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="oauth-validator-init.html" title="50.2. Initialization Functions">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 50. OAuth Validator Modules </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 50.2. Initialization Functions</td></tr></table></div></body></html>