feat: pub auth_mysql & add auth boxed err (#788)

* chore: minor openup

* chore: open up auth_mysql and return ()

* chore: typo change

* chore: change according to ci

* chore: change according to ci

* chore: remove tonic status in auth error
This commit is contained in:
shuiyisong
2022-12-27 11:04:05 +08:00
committed by GitHub
parent 7829e4a219
commit d589de63ef
2 changed files with 33 additions and 27 deletions

View File

@@ -18,6 +18,7 @@ pub const DEFAULT_USERNAME: &str = "greptime";
use std::sync::Arc;
use common_error::ext::BoxedError;
use common_error::prelude::ErrorExt;
use common_error::status_code::StatusCode;
use snafu::{Backtrace, ErrorCompat, OptionExt, Snafu};
@@ -28,7 +29,7 @@ use crate::auth::user_provider::StaticUserProvider;
pub trait UserProvider: Send + Sync {
fn name(&self) -> &str;
async fn auth(&self, id: Identity<'_>, password: Password<'_>) -> Result<UserInfo, Error>;
async fn auth(&self, id: Identity<'_>, password: Password<'_>) -> Result<UserInfo>;
}
pub type UserProviderRef = Arc<dyn UserProvider>;
@@ -76,7 +77,7 @@ impl UserInfo {
}
}
pub fn user_provider_from_option(opt: &String) -> Result<UserProviderRef, Error> {
pub fn user_provider_from_option(opt: &String) -> Result<UserProviderRef> {
let (name, content) = opt.split_once(':').context(InvalidConfigSnafu {
value: opt.to_string(),
msg: "UserProviderOption must be in format `<option>:<value>`",
@@ -99,23 +100,25 @@ pub fn user_provider_from_option(opt: &String) -> Result<UserProviderRef, Error>
#[snafu(visibility(pub))]
pub enum Error {
#[snafu(display("Invalid config value: {}, {}", value, msg))]
InvalidConfig {
value: String,
msg: String,
InvalidConfig { value: String, msg: String },
#[snafu(display("IO error, source: {}", source))]
Io {
source: std::io::Error,
backtrace: Backtrace,
},
#[snafu(display("Encounter IO error, source: {}", source))]
IOErr { source: std::io::Error },
#[snafu(display("Auth failed, source: {}", source))]
AuthBackend {
#[snafu(backtrace)]
source: BoxedError,
},
#[snafu(display("User not found, username: {}", username))]
UserNotFound { username: String },
#[snafu(display("Unsupported password type: {}", password_type))]
UnsupportedPasswordType {
password_type: String,
backtrace: Backtrace,
},
UnsupportedPasswordType { password_type: String },
#[snafu(display("Username and password does not match, username: {}", username))]
UserPasswordMismatch { username: String },
@@ -125,7 +128,8 @@ impl ErrorExt for Error {
fn status_code(&self) -> StatusCode {
match self {
Error::InvalidConfig { .. } => StatusCode::InvalidArguments,
Error::IOErr { .. } => StatusCode::Internal,
Error::Io { .. } => StatusCode::Internal,
Error::AuthBackend { .. } => StatusCode::Internal,
Error::UserNotFound { .. } => StatusCode::UserNotFound,
Error::UnsupportedPasswordType { .. } => StatusCode::UnsupportedPasswordType,
@@ -142,6 +146,8 @@ impl ErrorExt for Error {
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
pub mod test {
use super::{Identity, Password, UserInfo, UserProvider};

View File

@@ -25,7 +25,7 @@ use sha1::Sha1;
use snafu::{ensure, OptionExt, ResultExt};
use crate::auth::{
Error, HashedPassword, IOErrSnafu, Identity, InvalidConfigSnafu, Password, Salt,
Error, HashedPassword, Identity, InvalidConfigSnafu, IoSnafu, Password, Result, Salt,
UnsupportedPasswordTypeSnafu, UserInfo, UserNotFoundSnafu, UserPasswordMismatchSnafu,
UserProvider,
};
@@ -35,7 +35,7 @@ pub const STATIC_USER_PROVIDER: &str = "static_user_provider";
impl TryFrom<&str> for StaticUserProvider {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
fn try_from(value: &str) -> Result<Self> {
let (mode, content) = value.split_once(':').context(InvalidConfigSnafu {
value: value.to_string(),
msg: "StaticUserProviderOption must be in format `<option>:<value>`",
@@ -49,7 +49,7 @@ impl TryFrom<&str> for StaticUserProvider {
msg: "StaticUserProviderOption file must be a valid file path",
});
let file = File::open(path).context(IOErrSnafu)?;
let file = File::open(path).context(IoSnafu)?;
let credential = io::BufReader::new(file)
.lines()
.filter_map(|line| line.ok())
@@ -78,7 +78,7 @@ impl TryFrom<&str> for StaticUserProvider {
})?;
Ok((k.to_string(), v.as_bytes().to_vec()))
})
.collect::<Result<HashMap<String, Vec<u8>>, Error>>()
.collect::<Result<HashMap<String, Vec<u8>>>>()
.map(|users| StaticUserProvider { users }),
_ => InvalidConfigSnafu {
value: mode.to_string(),
@@ -99,11 +99,7 @@ impl UserProvider for StaticUserProvider {
STATIC_USER_PROVIDER
}
async fn auth(
&self,
input_id: Identity<'_>,
input_pwd: Password<'_>,
) -> Result<UserInfo, Error> {
async fn auth(&self, input_id: Identity<'_>, input_pwd: Password<'_>) -> Result<UserInfo> {
match input_id {
Identity::UserId(username, _) => {
let save_pwd = self.users.get(username).context(UserNotFoundSnafu {
@@ -122,7 +118,8 @@ impl UserProvider for StaticUserProvider {
}
}
Password::MysqlNativePassword(auth_data, salt) => {
auth_mysql(auth_data, salt, username.to_string(), save_pwd)
auth_mysql(auth_data, salt, username, save_pwd)
.map(|_| UserInfo::new(username))
}
Password::PgMD5(_, _) => UnsupportedPasswordTypeSnafu {
password_type: "pg_md5",
@@ -134,12 +131,12 @@ impl UserProvider for StaticUserProvider {
}
}
fn auth_mysql(
pub fn auth_mysql(
auth_data: HashedPassword,
salt: Salt,
username: String,
username: &str,
save_pwd: &[u8],
) -> Result<UserInfo, Error> {
) -> Result<()> {
// ref: https://github.com/mysql/mysql-server/blob/a246bad76b9271cb4333634e954040a970222e0a/sql/auth/password.cc#L62
let hash_stage_2 = double_sha1(save_pwd);
let tmp = sha1_two(salt, &hash_stage_2);
@@ -150,9 +147,12 @@ fn auth_mysql(
}
let candidate_stage_2 = sha1_one(&xor_result);
if candidate_stage_2 == hash_stage_2 {
Ok(UserInfo::new(username))
Ok(())
} else {
UserPasswordMismatchSnafu { username }.fail()
UserPasswordMismatchSnafu {
username: username.to_string(),
}
.fail()
}
}