fixed #1381 - skip password auth in postgres if not required (#1383)

This commit is contained in:
Eugene 2025-06-18 20:03:46 +02:00 committed by GitHub
parent 70bbb97f6d
commit 972880a6bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 42 additions and 43 deletions

View file

@ -91,6 +91,9 @@ class Test:
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
) )
# First message comes as soon as an authstate is created
msg = await ws.receive(5)
# Second message is once password is accepted
msg = await ws.receive(5) msg = await ws.receive(5)
auth_id = msg.data auth_id = msg.data

View file

@ -91,31 +91,7 @@ impl PostgresSession {
self.username = username.clone(); self.username = username.clone();
self.database = startup.parameters.get("database").cloned(); self.database = startup.parameters.get("database").cloned();
let password = if let AuthSelector::Ticket { .. } = self.run_authorization(startup, &username.unwrap_or("".into()))
AuthSelector::from(username.as_deref().unwrap_or(""))
{
Secret::from("".to_string())
} else {
self.stream
.push(pgwire::messages::startup::Authentication::CleartextPassword)?;
self.stream.flush().await?;
let Some(PgWireGenericFrontendMessage(PgWireFrontendMessage::PasswordMessageFamily(
message,
))) = self.stream.recv::<PgWireGenericFrontendMessage>().await?
else {
return Err(PostgresError::Eof);
};
Secret::from(
message
.into_password()
.map_err(PostgresError::from)?
.password,
)
};
self.run_authorization(startup, &username.unwrap_or("".into()), password)
.await .await
} }
@ -123,7 +99,6 @@ impl PostgresSession {
mut self, mut self,
startup: pgwire::messages::startup::Startup, startup: pgwire::messages::startup::Startup,
username: &String, username: &String,
password: Secret<String>,
) -> Result<(), PostgresError> { ) -> Result<(), PostgresError> {
let selector: AuthSelector = username.into(); let selector: AuthSelector = username.into();
@ -159,17 +134,6 @@ impl PostgresSession {
.await? .await?
.1; .1;
{
let mut state = state_arc.lock().await;
let credential = AuthCredential::Password(password);
let mut cp = self.services.config_provider.lock().await;
if cp.validate_credential(&username, &credential).await? {
state.add_valid_credential(credential);
}
}
let mut auth_ok_sent = false; let mut auth_ok_sent = false;
loop { loop {
@ -204,8 +168,44 @@ impl PostgresSession {
return self.run_authorized(startup, username, target_name).await; return self.run_authorized(startup, username, target_name).await;
} }
AuthResult::Need(kinds) => { AuthResult::Need(kinds) => {
if kinds.len() == 1 && kinds.contains(&CredentialKind::WebUserApproval) if kinds.contains(&CredentialKind::Password) {
{ self.stream.push(
pgwire::messages::startup::Authentication::CleartextPassword,
)?;
self.stream.flush().await?;
let Some(PgWireGenericFrontendMessage(
PgWireFrontendMessage::PasswordMessageFamily(message),
)) = self.stream.recv::<PgWireGenericFrontendMessage>().await?
else {
return Err(PostgresError::Eof);
};
let password = Secret::from(
message
.into_password()
.map_err(PostgresError::from)?
.password,
);
let mut state = state_arc.lock().await;
let credential = AuthCredential::Password(password);
if {
self.services
.config_provider
.lock()
.await
.validate_credential(&username, &credential)
.await?
} {
state.add_valid_credential(credential);
} else {
// Postgres CLI will just send the same password in a loop without prompting the user again
return fail(&mut self).await;
}
} else if kinds.contains(&CredentialKind::WebUserApproval) {
// Only WebUserApproval is needed, i.e. the password was either correct or not required, otherwise just fail early // Only WebUserApproval is needed, i.e. the password was either correct or not required, otherwise just fail early
let identification_string = let identification_string =

View file

@ -31,10 +31,6 @@ const labels = {
const tips: Record<ProtocolID, Map<[CredentialKind, boolean], string>> = { const tips: Record<ProtocolID, Map<[CredentialKind, boolean], string>> = {
postgres: new Map([ postgres: new Map([
[
[CredentialKind.Password, false],
'Since the PostgreSQL protocol requires a password, the user can just supply an empty password when connecting.',
],
[ [
[CredentialKind.WebUserApproval, true], [CredentialKind.WebUserApproval, true],
'Not all clients will show the 2FA auth prompt. The user might need to log in to the Warpgate UI to see the prompt.', 'Not all clients will show the 2FA auth prompt. The user might need to log in to the Warpgate UI to see the prompt.',