You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds a feature that allows setting auth passthrough for md5 auth.
It adds 3 new (general and pool) config parameters:
- `auth_query`: An string containing a query that will be executed on boot
to obtain the hash of a given user. This query have to use a placeholder `$1`,
so pgcat can replace it with the user its trying to fetch the hash from.
- `auth_query_user`: The user to use for connecting to the server and executing the
auth_query.
- `auth_query_password`: The password to use for connecting to the server and executing the
auth_query.
The configuration can be done either on the general config (so pools share them) or in a per-pool basis.
The behavior is, at boot time, when validating server connections, a hash is fetched per server
and stored in the pool. When new server connections are created, and no cleartext password is specified,
the obtained hash is used for creating them, if the hash could not be obtained for whatever reason, it retries
it.
When client authentication is tried, it uses cleartext passwords if specified, it not, it checks whether
we have query_auth set up, if so, it tries to use the obtained hash for making client auth. If there is no
hash (we could not obtain one when validating the connection), a new fetch is tried.
Once we have a hash, we authenticate using it against whathever the client has sent us, if there is a failure
we refetch the hash and retry auth (so password changes can be done).
The idea with this 'retrial' mechanism is to make it fault tolerant, so if for whatever reason hash could not be
obtained during connection validation, or the password has change, we can still connect later.
"Could not obtain hash for {{ username: {:?}, database: {:?} }}. Auth passthrough not enabled.",
372
+
address.username, address.database
373
+
)))
374
+
}
375
+
362
376
impl<S,T>Client<S,T>
363
377
where
364
378
S: tokio::io::AsyncRead + std::marker::Unpin,
@@ -492,14 +506,68 @@ where
492
506
}
493
507
};
494
508
495
-
// Compare server and client hashes.
496
-
let password_hash = md5_hash_password(username,&pool.settings.user.password,&salt);
509
+
// Obtain the hash to compare, we give preference to that written in cleartext in config
510
+
// if there is nothing set in cleartext and auth passthrough (auth_query) is configured, we use the hash obtained
511
+
// when the pool was created. If there is no hash there, we try to fetch it one more time.
512
+
let password_hash = ifletSome(password) = &pool.settings.user.password{
513
+
Some(md5_hash_password(username, password,&salt))
514
+
}else{
515
+
if !get_config().is_auth_query_configured(){
516
+
returnErr(Error::ClientError(format!("Client auth not possible, no cleartext password set for username: {:?} in config and auth passthrough (query_auth) is not set up.", username)));
format!("No cleartext password set, and no auth passthrough could not obtain the hash from server for {{ username: {:?}, pool_name: {:?}, application_name: {:?} }}, the error was: {:?}",
537
+
username,
538
+
pool_name,
539
+
application_name,
540
+
err)
541
+
)
542
+
);
543
+
}
544
+
}
545
+
};
546
+
547
+
Some(md5_hash_second_pass(&hash.unwrap(),&salt))
548
+
};
549
+
550
+
// Once we have the resulting hash, we compare with what the client gave us.
551
+
// If they do not match and auth query is set up, we try to refetch the hash one more time
552
+
// to see if the password has changed since the pool was created.
553
+
//
554
+
// @TODO: we could end up fetching again the same password twice (see above).
555
+
if password_hash.unwrap() != password_response {
556
+
warn!("Invalid password {{ username: {:?}, pool_name: {:?}, application_name: {:?} }}, will try to refetch it.", username, pool_name, application_name);
557
+
let fetched_hash = refetch_auth_hash(&pool).await?;
558
+
let new_password_hash = md5_hash_second_pass(&fetched_hash,&salt);
559
+
560
+
// Ok password changed in server an auth is possible.
561
+
if new_password_hash == password_response {
562
+
warn!("Password for {{ username: {:?}, pool_name: {:?}, application_name: {:?} }}, changed in server. Updating.", username, pool_name, application_name);
0 commit comments