use crate::io::Buf;
use crate::postgres::protocol::Decode;
use byteorder::NetworkEndian;
use std::io;
#[derive(Debug)]
pub enum Authentication {
Ok,
KerberosV5,
ClearTextPassword,
Md5Password { salt: [u8; 4] },
ScmCredential,
Gss,
Sspi,
GssContinue { data: Box<[u8]> },
Sasl { mechanisms: Box<[Box<str>]> },
SaslContinue { data: Box<[u8]> },
SaslFinal { data: Box<[u8]> },
}
impl Decode for Authentication {
fn decode(mut buf: &[u8]) -> crate::Result<Self> {
Ok(match buf.get_u32::<NetworkEndian>()? {
0 => Authentication::Ok,
2 => Authentication::KerberosV5,
3 => Authentication::ClearTextPassword,
5 => {
let mut salt = [0_u8; 4];
salt.copy_from_slice(&buf);
Authentication::Md5Password { salt }
}
6 => Authentication::ScmCredential,
7 => Authentication::Gss,
8 => {
let mut data = Vec::with_capacity(buf.len());
data.extend_from_slice(buf);
Authentication::GssContinue {
data: data.into_boxed_slice(),
}
}
9 => Authentication::Sspi,
10 => {
let mut mechanisms = Vec::new();
while buf[0] != 0 {
mechanisms.push(buf.get_str_nul()?.into());
}
Authentication::Sasl {
mechanisms: mechanisms.into_boxed_slice(),
}
}
11 => {
let mut data = Vec::with_capacity(buf.len());
data.extend_from_slice(buf);
Authentication::SaslContinue {
data: data.into_boxed_slice(),
}
}
12 => {
let mut data = Vec::with_capacity(buf.len());
data.extend_from_slice(buf);
Authentication::SaslFinal {
data: data.into_boxed_slice(),
}
}
id => {
return Err(protocol_err!("unknown authentication response: {}", id).into());
}
})
}
}
#[cfg(test)]
mod tests {
use super::{Authentication, Decode};
use matches::assert_matches;
const AUTH_OK: &[u8] = b"\0\0\0\0";
const AUTH_MD5: &[u8] = b"\0\0\0\x05\x93\x189\x98";
#[test]
fn it_decodes_auth_ok() {
let m = Authentication::decode(AUTH_OK).unwrap();
assert_matches!(m, Authentication::Ok);
}
#[test]
fn it_decodes_auth_md5_password() {
let m = Authentication::decode(AUTH_MD5).unwrap();
assert_matches!(
m,
Authentication::Md5Password {
salt: [147, 24, 57, 152]
}
);
}
}