Re: Continuous re-validation of session credentials

From: Ajit Awekar <ajitpostgres(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Jacob Champion <jacob(dot)champion(at)enterprisedb(dot)com>, Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>, Daniel Gustafsson <daniel(at)yesql(dot)se>
Subject: Re: Continuous re-validation of session credentials
Date: 2026-09-17 12:01:41
Message-ID: CAER375N35XAWLhAiokyVs65bFQgq_n_=LgNs61o+ZtYdEmPEqw@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi Hackers,

Attached is v2 of the series, with three fixes folded into 0001 (no
changes to 0002-0005):

1. Standby servers

CheckCredentialValidity() no longer skips validation under
RecoveryInProgress(). Hot-standby sessions run continuously "in
recovery", so this was silently disabling the feature for read
replicas -- all the checks involved are read-only/local, so
there's no reason to exclude them.

2. Set Session Authorization

ValidateRoleValidity() now checks GetAuthenticatedUserId()
instead of GetSessionUserId(), so a superuser can't mask the
login role's expiry/removal by switching session authorization.
This also keeps it consistent with the method-specific
validators, which always check the fixed login identity. Added
regression coverage.

3. Walsenders

EnableCredentialValidationTimeout() and CheckCredentialValidity()
now explicitly skip AmWalSenderProcess()

Request a review.

Thanks & Best Regards,
Ajit

On Wed, 1 Jul 2026 at 17:45, Ajit Awekar <ajitpostgres(at)gmail(dot)com> wrote:

> Hi,
>
> Following up on the ongoing work for continuous credential validation, I
> would like to propose the next two patches in the series.
>
> These patches extend the continuous validation framework to handle both
> GSSAPI/Kerberos and LDAP (Search+Bind) authenticated sessions.
> Patch 4/5: Add GSS credential expiry to credential validation
>
> This patch introduces method-specific validation for GSSAPI/Kerberos
> sessions (CVT_GSS).The GSS security context established at authentication
> carries a lifetime derived from the client's Kerberos ticket. We introduce
> a helper be_gssapi_get_context_expired() which utilizes gss_context_time()
> on the acceptor context retained on the Port. This is a purely local
> check that requires no round-trip to the KDC. If the context lifetime has
> elapsed, the session is safely terminated.
>
>
> postgres=> select system_user;
> system_user
> -----------------------
> gss:test1(at)EXAMPLE(dot)COM
> (1 row)
>
> postgres=> select current_user;
> current_user
> --------------
> test1
>
> postgres=> select current_time;
> FATAL: session credentials have expired
> HINT: Please reconnect to establish a new authenticated session.
> server closed the connection unexpectedly
> This probably means the server terminated abnormally
> before or while processing the request.
> The connection to the server was lost. Attempting reset: Failed.
> The connection to the server was lost. Attempting reset: Failed.
>
> (1 row)
>
> Patch 5/5: Add LDAP account-existence check to credential validation
>
> This patch adds validation support for LDAP sessions (CVT_LDAP).
>
> Unlike token- or certificate-based authentication, an LDAP session does
> not retain a credential with an intrinsic expiry date. Instead, "validity"
> is defined as the account's continued existence within the directory.
>
> During each validation cycle, the backend connects and re-binds using the
> configured search credentials (ldapbinddn / ldapbindpasswd), then re-runs
> the configured search filter. If the search yields exactly zero entries,
> the account is considered deleted or disabled, and the session is
> terminated.
>
>
> postgres=> SELECT current_user;
> current_user
> --------------
> test1
> (1 row)
>
> postgres=> select system_user;
> system_user
> ----------------------------------
> ldap:uid=test1,dc=example,dc=net. <= After this I fired ldapdelete and got validation error on next validation cycle
> (1 row)
>
> postgres=> select current_time;
> FATAL: session credentials have expired
> HINT: Please reconnect to establish a new authenticated session.
> server closed the connection unexpectedly
> This probably means the server terminated abnormally
> before or while processing the request.
> The connection to the server was lost. Attempting reset: Failed.
> The connection to the server was lost. Attempting reset: Failed.
>
> (1 row)
>
> Thanks & Best regards,
>
> Ajit
>
> On Fri, 26 Jun 2026 at 11:21, Ajit Awekar <ajitpostgres(at)gmail(dot)com> wrote:
>
>> Hi,
>>
>> Attached is v2 of the patch set, rebased on the current master.
>>
>> The only functional change from the previous version is a fix for the
>> cfbot failure. The earlier version src/test/modules/test_misc/t/
>> 003_check_guc.pl
>> due to the tab in the trailing spaces.
>>
>> Thanks & Best Regards,
>> Ajit
>>
>>
>> On Tue, 16 Jun 2026 at 17:44, Ajit Awekar <ajitpostgres(at)gmail(dot)com> wrote:
>>
>>> Hi,
>>>
>>> Today PG validates a client's credentials only once, at connection
>>> time. After that the backend runs until the client disconnects, even if
>>> the
>>> basis for the original authentication decision has gone away. In
>>> particular:
>>>
>>> - the role's VALID UNTIL passes, or the role is dropped (ALTER ROLE
>>> ...
>>> VALID UNTIL / DROP ROLE);
>>> - the OAuth bearer token the session authenticated with expires;
>>> - the TLS client certificate the session authenticated with reaches
>>> its
>>> notAfter date.
>>>
>>> In all of these cases a long-lived session keeps running with
>>> credentials that
>>> would be rejected on a fresh connection. For environments with
>>> short-lived
>>> credentials (OAuth tokens, short-lived certs, time-boxed accounts) this
>>> is a
>>> real gap: revoking access has no effect on already-established sessions.
>>>
>>> This patch series adds an optional mechanism to periodically re-validate
>>> the
>>> credentials of an active session and terminate it (FATAL) once they are
>>> no
>>> longer valid.
>>>
>>> A per-backend timer (CREDENTIAL_VALIDATION_TIMEOUT) fires every
>>> credential_validation_interval seconds and sets a pending flag.
>>>
>>> Validation has two layers:
>>> - A baseline, auth-method-independent check (role still exists and
>>> has not
>>> passed rolvaliduntil), applied to every authenticated session.
>>> - Optional method-specific validators, registered via
>>> RegisterCredentialValidator(), for OAuth token expiry and client
>>> certificate expiry.
>>>
>>> The framework is deliberately extensible: adding re-validation for a new
>>> authentication method needs only three small steps -- add a
>>> CredentialValidationType, implement a "bool validator(void)" callback
>>> that
>>> returns whether the credential is still valid, and register it with
>>> RegisterCredentialValidator(). The certificate and OAuth validators in
>>> 0002
>>> and 0003 are themselves examples of plugging into the framework this
>>> way,
>>> so methods such as LDAP, RADIUS, or GSSAPI/Kerberos credential
>>> lifetimes
>>> could be added later without touching the core.
>>>
>>> Two GUCs :
>>> credential_validation_enabled (bool, default off)
>>> credential_validation_interval (int, 5..3600 s, default 60)
>>>
>>> Patch series
>>> ------------
>>>
>>> 0001 Framework + baseline role-validity check (rolvaliduntil / role
>>> existence). Useful on its own for password/md5/scram sessions.
>>> 0002 TLS client certificate expiry. The cert presented at connect
>>> time is
>>> retained on the Port, so its notAfter is re-checked locally with
>>> no
>>> network round-trip.
>>> 0003 OAuth token expiry. This adds an optional expire_cb callback to
>>> OAuthValidatorCallbacks; to stay ABI-compatible the validator
>>> magic is
>>> versioned (V1 = existing layout, V2 = adds expire_cb), and the
>>> server
>>> accepts both.
>>>
>>> Request a review.
>>>
>>>
>>> Thanks & Best Regards,
>>> Ajit
>>>
>>>
>>>

Attachment Content-Type Size
v2-0003-Add-OAuth-token-expiry-to-credential-validation.patch application/octet-stream 10.8 KB
v2-0005-Add-LDAP-account-existence-check-to-credential-valid.patch application/octet-stream 17.1 KB
v2-0001-Add-continuous-credential-validation-framework.patch application/octet-stream 41.3 KB
v2-0004-Add-GSS-credential-expiry-to-credential-validation.patch application/octet-stream 16.0 KB
v2-0002-Add-TLS-client-certificate-expiry-to-credential-vali.patch application/octet-stream 12.0 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Vik Fearing 2026-09-17 12:04:42 Re: ON EMPTY clause for aggregate and window functions
Previous Message Hayato Kuroda (Fujitsu) 2026-09-17 11:35:24 RE: pgoutput: schema cache cleanup after streamed 2PC