mirror of
https://github.com/postgres/postgres.git
synced 2025-07-24 14:22:24 +03:00
Allow plaintext 'password' authentication when user has a SCRAM verifier.
Oversight in the main SCRAM patch.
This commit is contained in:
@ -364,6 +364,52 @@ scram_build_verifier(const char *username, const char *password,
|
|||||||
return psprintf("scram-sha-256:%s:%d:%s:%s", encoded_salt, iterations, storedkey_hex, serverkey_hex);
|
return psprintf("scram-sha-256:%s:%d:%s:%s", encoded_salt, iterations, storedkey_hex, serverkey_hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify a plaintext password against a SCRAM verifier. This is used when
|
||||||
|
* performing plaintext password authentication for a user that has a SCRAM
|
||||||
|
* verifier stored in pg_authid.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
scram_verify_plain_password(const char *username, const char *password,
|
||||||
|
const char *verifier)
|
||||||
|
{
|
||||||
|
char *encoded_salt;
|
||||||
|
char *salt;
|
||||||
|
int saltlen;
|
||||||
|
int iterations;
|
||||||
|
uint8 stored_key[SCRAM_KEY_LEN];
|
||||||
|
uint8 server_key[SCRAM_KEY_LEN];
|
||||||
|
uint8 computed_key[SCRAM_KEY_LEN];
|
||||||
|
|
||||||
|
if (!parse_scram_verifier(verifier, &encoded_salt, &iterations,
|
||||||
|
stored_key, server_key))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The password looked like a SCRAM verifier, but could not be
|
||||||
|
* parsed.
|
||||||
|
*/
|
||||||
|
elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
salt = palloc(pg_b64_dec_len(strlen(encoded_salt)));
|
||||||
|
saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt);
|
||||||
|
if (saltlen == -1)
|
||||||
|
{
|
||||||
|
elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute Server key based on the user-supplied plaintext password */
|
||||||
|
scram_ClientOrServerKey(password, salt, saltlen, iterations,
|
||||||
|
SCRAM_SERVER_KEY_NAME, computed_key);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare the verifier's Server Key with the one computed from the
|
||||||
|
* user-supplied password.
|
||||||
|
*/
|
||||||
|
return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if given verifier can be used for SCRAM authentication.
|
* Check if given verifier can be used for SCRAM authentication.
|
||||||
|
@ -283,7 +283,6 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
|
|||||||
const char *client_pass,
|
const char *client_pass,
|
||||||
char **logdetail)
|
char **logdetail)
|
||||||
{
|
{
|
||||||
int retval;
|
|
||||||
char crypt_client_pass[MD5_PASSWD_LEN + 1];
|
char crypt_client_pass[MD5_PASSWD_LEN + 1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -293,6 +292,21 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
|
|||||||
*/
|
*/
|
||||||
switch (get_password_type(shadow_pass))
|
switch (get_password_type(shadow_pass))
|
||||||
{
|
{
|
||||||
|
case PASSWORD_TYPE_SCRAM:
|
||||||
|
if (scram_verify_plain_password(role,
|
||||||
|
client_pass,
|
||||||
|
shadow_pass))
|
||||||
|
{
|
||||||
|
return STATUS_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
|
||||||
|
role);
|
||||||
|
return STATUS_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PASSWORD_TYPE_MD5:
|
case PASSWORD_TYPE_MD5:
|
||||||
if (!pg_md5_encrypt(client_pass,
|
if (!pg_md5_encrypt(client_pass,
|
||||||
role,
|
role,
|
||||||
@ -307,30 +321,33 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
|
|||||||
*/
|
*/
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
client_pass = crypt_client_pass;
|
if (strcmp(crypt_client_pass, shadow_pass) == 0)
|
||||||
|
return STATUS_OK;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
|
||||||
|
role);
|
||||||
|
return STATUS_ERROR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PASSWORD_TYPE_PLAINTEXT:
|
case PASSWORD_TYPE_PLAINTEXT:
|
||||||
|
if (strcmp(client_pass, shadow_pass) == 0)
|
||||||
|
return STATUS_OK;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
|
||||||
|
role);
|
||||||
|
return STATUS_ERROR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This shouldn't happen. Plain "password" authentication should
|
|
||||||
* be possible with any kind of stored password hash.
|
|
||||||
*/
|
|
||||||
*logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
|
|
||||||
role);
|
|
||||||
return STATUS_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(client_pass, shadow_pass) == 0)
|
/*
|
||||||
retval = STATUS_OK;
|
* This shouldn't happen. Plain "password" authentication is possible
|
||||||
else
|
* with any kind of stored password hash.
|
||||||
{
|
*/
|
||||||
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
|
*logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
|
||||||
role);
|
role);
|
||||||
retval = STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
@ -31,5 +31,7 @@ extern char *scram_build_verifier(const char *username,
|
|||||||
const char *password,
|
const char *password,
|
||||||
int iterations);
|
int iterations);
|
||||||
extern bool is_scram_verifier(const char *verifier);
|
extern bool is_scram_verifier(const char *verifier);
|
||||||
|
extern bool scram_verify_plain_password(const char *username,
|
||||||
|
const char *password, const char *verifier);
|
||||||
|
|
||||||
#endif /* PG_SCRAM_H */
|
#endif /* PG_SCRAM_H */
|
||||||
|
Reference in New Issue
Block a user