mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-12-29 21:00:54 +00:00
feat(postgres): add support for clear and md5 passwords
This commit is contained in:
parent
9cc80af5e4
commit
db1896444d
19
Cargo.lock
generated
19
Cargo.lock
generated
@ -555,6 +555,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.2"
|
||||
@ -639,6 +645,17 @@ version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
@ -1132,7 +1149,9 @@ dependencies = [
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"log",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"percent-encoding",
|
||||
"sqlx-core",
|
||||
|
||||
@ -33,12 +33,14 @@ log = "0.4.11"
|
||||
either = "1.6.1"
|
||||
bytestring = "1.0.0"
|
||||
url = "2.2.0"
|
||||
hex = "0.4.3"
|
||||
percent-encoding = "2.1.0"
|
||||
futures-io = { version = "0.3", optional = true }
|
||||
bytes = "1.0"
|
||||
memchr = "2.3"
|
||||
bitflags = "1.2"
|
||||
base64 = "0.13.0"
|
||||
md-5 = "0.9.1"
|
||||
|
||||
[dev-dependencies]
|
||||
sqlx-core = { version = "0.6.0-pre", path = "../sqlx-core", features = ["_mock"] }
|
||||
|
||||
@ -16,7 +16,7 @@ use sqlx_core::net::Stream as NetStream;
|
||||
use sqlx_core::{Error, Result, Runtime};
|
||||
|
||||
use crate::protocol::backend::{Authentication, BackendMessage, BackendMessageType};
|
||||
use crate::protocol::frontend::Startup;
|
||||
use crate::protocol::frontend::{Password, PasswordMd5, Startup};
|
||||
use crate::{PgClientError, PgConnectOptions, PgConnection};
|
||||
|
||||
impl<Rt: Runtime> PgConnection<Rt> {
|
||||
@ -50,12 +50,17 @@ impl<Rt: Runtime> PgConnection<Rt> {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
Authentication::Md5Password(_) => {
|
||||
todo!("md5")
|
||||
Authentication::Md5Password(data) => {
|
||||
self.stream.write_message(&PasswordMd5 {
|
||||
password: options.get_password().unwrap_or_default(),
|
||||
username: options.get_username().unwrap_or_default(),
|
||||
salt: data.salt,
|
||||
})?;
|
||||
}
|
||||
|
||||
Authentication::CleartextPassword => {
|
||||
todo!("cleartext")
|
||||
self.stream
|
||||
.write_message(&Password(options.get_password().unwrap_or_default()))?;
|
||||
}
|
||||
|
||||
Authentication::Sasl(_) => todo!("sasl"),
|
||||
@ -70,6 +75,8 @@ impl<Rt: Runtime> PgConnection<Rt> {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
mod password;
|
||||
mod startup;
|
||||
mod terminate;
|
||||
|
||||
pub(crate) use password::{Password, PasswordMd5};
|
||||
pub(crate) use startup::Startup;
|
||||
pub(crate) use terminate::Terminate;
|
||||
|
||||
90
sqlx-postgres/src/protocol/frontend/password.rs
Normal file
90
sqlx-postgres/src/protocol/frontend/password.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use crate::io::PgWriteExt;
|
||||
use md5::{Digest, Md5};
|
||||
use sqlx_core::io::Serialize;
|
||||
use sqlx_core::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Password<'a>(pub(crate) &'a str);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PasswordMd5<'a> {
|
||||
pub(crate) password: &'a str,
|
||||
pub(crate) username: &'a str,
|
||||
pub(crate) salt: [u8; 4],
|
||||
}
|
||||
|
||||
impl Serialize<'_> for Password<'_> {
|
||||
fn serialize_with(&self, buf: &mut Vec<u8>, _: ()) -> Result<()> {
|
||||
buf.reserve(1 + 4 + self.0.len() + 1);
|
||||
buf.push(b'p');
|
||||
|
||||
buf.write_len_prefixed(|buf| {
|
||||
buf.extend(self.0.as_bytes());
|
||||
buf.push(b'\0');
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize<'_> for PasswordMd5<'_> {
|
||||
fn serialize_with(&self, buf: &mut Vec<u8>, _: ()) -> Result<()> {
|
||||
buf.reserve(1 + 4 + 3 + 32 + 1);
|
||||
buf.push(b'p');
|
||||
|
||||
buf.write_len_prefixed(|buf| {
|
||||
// the actual `PasswordMessage` can be computed in SQL as:
|
||||
// concat('md5', md5(concat(md5(concat(password, username)), random-salt)))
|
||||
|
||||
// keep in mind the md5() function returns its result as a hex string
|
||||
|
||||
let mut hasher = Md5::new();
|
||||
|
||||
hasher.update(self.password);
|
||||
hasher.update(self.username);
|
||||
|
||||
let offset = buf.len();
|
||||
buf.resize(offset + 32 + 3, 0);
|
||||
|
||||
let hash = hasher.finalize_reset();
|
||||
let _ = hex::encode_to_slice(hash.as_slice(), &mut buf[offset..offset + 32]);
|
||||
|
||||
hasher.update(&buf[offset..offset + 32]);
|
||||
hasher.update(self.salt);
|
||||
|
||||
buf[offset..offset + 3].copy_from_slice(&b"md5"[..]);
|
||||
|
||||
let hash = hasher.finalize();
|
||||
let _ = hex::encode_to_slice(hash.as_slice(), &mut buf[offset + 3..offset + 32 + 3]);
|
||||
|
||||
buf.push(b'\0');
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Password, PasswordMd5, Serialize};
|
||||
|
||||
#[test]
|
||||
fn should_serialize() {
|
||||
let mut buf = Vec::new();
|
||||
let m = Password("password");
|
||||
|
||||
m.serialize(&mut buf).unwrap();
|
||||
|
||||
assert_eq!(buf, b"p\0\0\0\rpassword\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_serialize_md5() {
|
||||
let mut buf = Vec::new();
|
||||
let m = PasswordMd5 { password: "password", username: "root", salt: [147, 24, 57, 152] };
|
||||
|
||||
m.serialize(&mut buf).unwrap();
|
||||
|
||||
assert_eq!(buf, b"p\0\0\0(md53e2c9d99d49b201ef867a36f3f9ed62c\0");
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user