Warn on password auth with MD5-encrypted passwords

Commit bc60ee860 added a connection warning after successful MD5
authentication, but only for the md5 authentication method. A role with
an MD5-encrypted password can also authenticate via the password method,
which left that path without the same deprecation warning.

Emit the MD5 deprecation connection warning after successful
password authentication as well, when the stored password is
MD5-encrypted.

Backpatch to v19, where the MD5 connection warning was introduced.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Japin Li <japinli@hotmail.com>
Discussion: https://postgr.es/m/CAHGQGwGkWfn5rtHzvdRbVk+PCefQU3gun3hc7QnaMXHFa5Bu3w@mail.gmail.com
Backpatch-through: 19
This commit is contained in:
Fujii Masao 2026-07-01 20:57:28 +09:00
parent 30652b356d
commit f6fdc2a4a7
4 changed files with 45 additions and 23 deletions

View file

@ -1206,7 +1206,8 @@ include_dir 'conf.d'
<listitem>
<para>
Controls whether a <literal>WARNING</literal> about MD5 password
deprecation is produced upon successful MD5 password authentication or
deprecation is produced upon successful authentication using an
MD5-encrypted password or
when a <command>CREATE ROLE</command> or
<command>ALTER ROLE</command> statement sets an MD5-encrypted password.
The default value is <literal>on</literal>.

View file

@ -48,6 +48,8 @@
static void auth_failed(Port *port, int elevel, int status,
const char *logdetail);
static char *recv_password_packet(Port *port);
static bool md5_password_warning_enabled(void);
static void queue_md5_password_warning(void);
/*----------------------------------------------------------------
@ -795,6 +797,7 @@ CheckPasswordAuth(Port *port, const char **logdetail)
char *passwd;
int result;
char *shadow_pass;
bool md5_password = false;
sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
@ -807,6 +810,7 @@ CheckPasswordAuth(Port *port, const char **logdetail)
{
result = plain_crypt_verify(port->user_name, shadow_pass, passwd,
logdetail);
md5_password = (get_password_type(shadow_pass) == PASSWORD_TYPE_MD5);
}
else
result = STATUS_ERROR;
@ -816,7 +820,11 @@ CheckPasswordAuth(Port *port, const char **logdetail)
pfree(passwd);
if (result == STATUS_OK)
{
if (md5_password)
queue_md5_password_warning();
set_authn_id(port, port->user_name);
}
return result;
}
@ -913,9 +921,34 @@ CheckMD5Auth(Port *port, char *shadow_pass, const char **logdetail)
pfree(passwd);
if (result == STATUS_OK)
queue_md5_password_warning();
return result;
}
static bool
md5_password_warning_enabled(void)
{
return md5_password_warnings;
}
static void
queue_md5_password_warning(void)
{
MemoryContext oldcontext;
char *warning;
char *detail;
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
warning = pstrdup(_("authenticated with an MD5-encrypted password"));
detail = pstrdup(_("MD5 password support is deprecated and will be removed in a future release of PostgreSQL."));
StoreConnectionWarning(warning, detail, md5_password_warning_enabled);
MemoryContextSwitchTo(oldcontext);
}
/*----------------------------------------------------------------
* GSSAPI authentication system

View file

@ -32,8 +32,6 @@ int password_expiration_warning_threshold = 604800;
/* Enables deprecation warnings for MD5 passwords. */
bool md5_password_warnings = true;
static bool md5_password_warning_enabled(void);
/*
* Fetch stored password for a user, for authentication.
*
@ -297,21 +295,7 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
if (strlen(client_pass) == strlen(crypt_pwd) &&
timingsafe_bcmp(client_pass, crypt_pwd, strlen(crypt_pwd)) == 0)
{
MemoryContext oldcontext;
char *warning;
char *detail;
retval = STATUS_OK;
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
warning = pstrdup(_("authenticated with an MD5-encrypted password"));
detail = pstrdup(_("MD5 password support is deprecated and will be removed in a future release of PostgreSQL."));
StoreConnectionWarning(warning, detail, md5_password_warning_enabled);
MemoryContextSwitchTo(oldcontext);
}
else
{
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
@ -322,12 +306,6 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
return retval;
}
static bool
md5_password_warning_enabled(void)
{
return md5_password_warnings;
}
/*
* Check given password for given user, and return STATUS_OK or STATUS_ERROR.
*

View file

@ -385,9 +385,19 @@ SKIP:
{
skip "MD5 not supported" unless $md5_works;
test_conn($node, 'user=md5_role', 'password', 0,
expected_stderr => qr/authenticated with an MD5-encrypted password/,
log_like =>
[qr/connection authenticated: identity="md5_role" method=password/]
);
$node->connect_ok(
'user=md5_role_no_warnings',
'password with warnings disabled',
sql => 'SHOW md5_password_warnings',
expected_stdout => qr/^off$/,
log_like => [
qr/connection authenticated: identity="md5_role_no_warnings" method=password/
]);
}
# require_auth succeeds here with a plaintext password.