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-07-01 12:15:20
Message-ID: CAER375O4pGq8xmhsQG9SoVeh6htAiJHGW-MA_2u5C8tN1Z24=g@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

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
0001-Add-continuous-credential-validation-framework.patch application/octet-stream 36.0 KB
0003-Add-OAuth-token-expiry-to-credential-validation.patch application/octet-stream 10.8 KB
0004-Add-GSS-credential-expiry-to-credential-validation.patch application/octet-stream 15.4 KB
0002-Add-TLS-client-certificate-expiry-to-credential-vali.patch application/octet-stream 12.0 KB
0005-Add-LDAP-account-existence-check-to-credential-valid.patch application/octet-stream 17.1 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Tatsuo Ishii 2026-07-01 12:18:05 Re: Row pattern recognition
Previous Message Jonathan Gonzalez V. 2026-07-01 12:12:35 Coverage (lcov) failing with inconsistent error in versions 2.x