mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 16:28:15 +00:00
364 lines
11 KiB
Rust
364 lines
11 KiB
Rust
use crate::policy;
|
|
|
|
pub type Result<T> = core::result::Result<T, Error>;
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
pub enum Error {
|
|
#[error(transparent)]
|
|
PolicyError(#[from] policy::Error),
|
|
|
|
#[error("{0}")]
|
|
StringError(String),
|
|
|
|
#[error("crypto: {0}")]
|
|
CryptoError(#[from] crypto::Error),
|
|
|
|
#[error("user '{0}' does not exist")]
|
|
NoSuchUser(String),
|
|
|
|
#[error("account '{0}' does not exist")]
|
|
NoSuchAccount(String),
|
|
|
|
#[error("service account '{0}' does not exist")]
|
|
NoSuchServiceAccount(String),
|
|
|
|
#[error("temp account '{0}' does not exist")]
|
|
NoSuchTempAccount(String),
|
|
|
|
#[error("group '{0}' does not exist")]
|
|
NoSuchGroup(String),
|
|
|
|
#[error("policy does not exist")]
|
|
NoSuchPolicy,
|
|
|
|
#[error("policy in use")]
|
|
PolicyInUse,
|
|
|
|
#[error("group not empty")]
|
|
GroupNotEmpty,
|
|
|
|
#[error("invalid arguments specified")]
|
|
InvalidArgument,
|
|
|
|
#[error("not initialized")]
|
|
IamSysNotInitialized,
|
|
|
|
#[error("invalid service type: {0}")]
|
|
InvalidServiceType(String),
|
|
|
|
#[error("malformed credential")]
|
|
ErrCredMalformed,
|
|
|
|
#[error("CredNotInitialized")]
|
|
CredNotInitialized,
|
|
|
|
#[error("invalid access key length")]
|
|
InvalidAccessKeyLength,
|
|
|
|
#[error("invalid secret key length")]
|
|
InvalidSecretKeyLength,
|
|
|
|
#[error("access key contains reserved characters =,")]
|
|
ContainsReservedChars,
|
|
|
|
#[error("group name contains reserved characters =,")]
|
|
GroupNameContainsReservedChars,
|
|
|
|
#[error("jwt err {0}")]
|
|
JWTError(#[from] jsonwebtoken::errors::Error),
|
|
|
|
#[error("no access key")]
|
|
NoAccessKey,
|
|
|
|
#[error("invalid token")]
|
|
InvalidToken,
|
|
|
|
#[error("invalid access_key")]
|
|
InvalidAccessKey,
|
|
#[error("action not allowed")]
|
|
IAMActionNotAllowed,
|
|
|
|
#[error("invalid expiration")]
|
|
InvalidExpiration,
|
|
|
|
#[error("no secret key with access key")]
|
|
NoSecretKeyWithAccessKey,
|
|
|
|
#[error("no access key with secret key")]
|
|
NoAccessKeyWithSecretKey,
|
|
|
|
#[error("policy too large")]
|
|
PolicyTooLarge,
|
|
|
|
#[error("io error: {0}")]
|
|
Io(std::io::Error),
|
|
}
|
|
|
|
impl Error {
|
|
pub fn other<E>(error: E) -> Self
|
|
where
|
|
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
|
{
|
|
Error::Io(std::io::Error::other(error))
|
|
}
|
|
}
|
|
|
|
impl From<std::io::Error> for Error {
|
|
fn from(e: std::io::Error) -> Self {
|
|
Error::Io(e)
|
|
}
|
|
}
|
|
|
|
impl From<time::error::ComponentRange> for Error {
|
|
fn from(e: time::error::ComponentRange) -> Self {
|
|
Error::other(e)
|
|
}
|
|
}
|
|
|
|
impl From<serde_json::Error> for Error {
|
|
fn from(e: serde_json::Error) -> Self {
|
|
Error::other(e)
|
|
}
|
|
}
|
|
|
|
// impl From<jsonwebtoken::errors::Error> for Error {
|
|
// fn from(e: jsonwebtoken::errors::Error) -> Self {
|
|
// Error::JWTError(e)
|
|
// }
|
|
// }
|
|
|
|
impl From<regex::Error> for Error {
|
|
fn from(e: regex::Error) -> Self {
|
|
Error::other(e)
|
|
}
|
|
}
|
|
|
|
// pub fn is_err_no_such_user(e: &Error) -> bool {
|
|
// matches!(e, Error::NoSuchUser(_))
|
|
// }
|
|
|
|
pub fn is_err_no_such_policy(err: &Error) -> bool {
|
|
matches!(err, Error::NoSuchPolicy)
|
|
}
|
|
|
|
pub fn is_err_no_such_user(err: &Error) -> bool {
|
|
matches!(err, Error::NoSuchUser(_))
|
|
}
|
|
|
|
pub fn is_err_no_such_account(err: &Error) -> bool {
|
|
matches!(err, Error::NoSuchAccount(_))
|
|
}
|
|
|
|
pub fn is_err_no_such_temp_account(err: &Error) -> bool {
|
|
matches!(err, Error::NoSuchTempAccount(_))
|
|
}
|
|
|
|
pub fn is_err_no_such_group(err: &Error) -> bool {
|
|
matches!(err, Error::NoSuchGroup(_))
|
|
}
|
|
|
|
pub fn is_err_no_such_service_account(err: &Error) -> bool {
|
|
matches!(err, Error::NoSuchServiceAccount(_))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use std::io::{Error as IoError, ErrorKind};
|
|
|
|
#[test]
|
|
fn test_policy_error_from_io_error() {
|
|
let io_error = IoError::new(ErrorKind::PermissionDenied, "permission denied");
|
|
let policy_error: Error = io_error.into();
|
|
|
|
match policy_error {
|
|
Error::Io(inner_io) => {
|
|
assert_eq!(inner_io.kind(), ErrorKind::PermissionDenied);
|
|
assert!(inner_io.to_string().contains("permission denied"));
|
|
}
|
|
_ => panic!("Expected Io variant"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_policy_error_other_function() {
|
|
let custom_error = "Custom policy error";
|
|
let policy_error = Error::other(custom_error);
|
|
|
|
match policy_error {
|
|
Error::Io(io_error) => {
|
|
assert!(io_error.to_string().contains(custom_error));
|
|
assert_eq!(io_error.kind(), ErrorKind::Other);
|
|
}
|
|
_ => panic!("Expected Io variant"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_policy_error_from_crypto_error() {
|
|
// Test conversion from crypto::Error - use an actual variant
|
|
let crypto_error = crypto::Error::ErrUnexpectedHeader;
|
|
let policy_error: Error = crypto_error.into();
|
|
|
|
match policy_error {
|
|
Error::CryptoError(_) => {
|
|
// Verify the conversion worked
|
|
assert!(policy_error.to_string().contains("crypto"));
|
|
}
|
|
_ => panic!("Expected CryptoError variant"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_policy_error_from_jwt_error() {
|
|
use jsonwebtoken::{Algorithm, DecodingKey, Validation, decode};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
struct Claims {
|
|
sub: String,
|
|
exp: usize,
|
|
}
|
|
|
|
// Create an invalid JWT to generate a JWT error
|
|
let invalid_token = "invalid.jwt.token";
|
|
let key = DecodingKey::from_secret(b"secret");
|
|
let validation = Validation::new(Algorithm::HS256);
|
|
|
|
let jwt_result = decode::<Claims>(invalid_token, &key, &validation);
|
|
assert!(jwt_result.is_err());
|
|
|
|
let jwt_error = jwt_result.unwrap_err();
|
|
let policy_error: Error = jwt_error.into();
|
|
|
|
match policy_error {
|
|
Error::JWTError(_) => {
|
|
// Verify the conversion worked
|
|
assert!(policy_error.to_string().contains("jwt err"));
|
|
}
|
|
_ => panic!("Expected JWTError variant"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_policy_error_from_serde_json() {
|
|
// Test conversion from serde_json::Error
|
|
let invalid_json = r#"{"invalid": json}"#;
|
|
let json_error = serde_json::from_str::<serde_json::Value>(invalid_json).unwrap_err();
|
|
let policy_error: Error = json_error.into();
|
|
|
|
match policy_error {
|
|
Error::Io(io_error) => {
|
|
assert_eq!(io_error.kind(), ErrorKind::Other);
|
|
}
|
|
_ => panic!("Expected Io variant"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_policy_error_from_time_component_range() {
|
|
use time::{Date, Month};
|
|
|
|
// Create an invalid date to generate a ComponentRange error
|
|
let time_result = Date::from_calendar_date(2023, Month::January, 32); // Invalid day
|
|
assert!(time_result.is_err());
|
|
|
|
let time_error = time_result.unwrap_err();
|
|
let policy_error: Error = time_error.into();
|
|
|
|
match policy_error {
|
|
Error::Io(io_error) => {
|
|
assert_eq!(io_error.kind(), ErrorKind::Other);
|
|
}
|
|
_ => panic!("Expected Io variant"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[allow(clippy::invalid_regex)]
|
|
fn test_policy_error_from_regex_error() {
|
|
use regex::Regex;
|
|
|
|
// Create an invalid regex to generate a regex error (unclosed bracket)
|
|
let regex_result = Regex::new("[");
|
|
assert!(regex_result.is_err());
|
|
|
|
let regex_error = regex_result.unwrap_err();
|
|
let policy_error: Error = regex_error.into();
|
|
|
|
match policy_error {
|
|
Error::Io(io_error) => {
|
|
assert_eq!(io_error.kind(), ErrorKind::Other);
|
|
}
|
|
_ => panic!("Expected Io variant"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_helper_functions() {
|
|
// Test helper functions for error type checking
|
|
assert!(is_err_no_such_policy(&Error::NoSuchPolicy));
|
|
assert!(!is_err_no_such_policy(&Error::NoSuchUser("test".to_string())));
|
|
|
|
assert!(is_err_no_such_user(&Error::NoSuchUser("test".to_string())));
|
|
assert!(!is_err_no_such_user(&Error::NoSuchAccount("test".to_string())));
|
|
|
|
assert!(is_err_no_such_account(&Error::NoSuchAccount("test".to_string())));
|
|
assert!(!is_err_no_such_account(&Error::NoSuchUser("test".to_string())));
|
|
|
|
assert!(is_err_no_such_temp_account(&Error::NoSuchTempAccount("test".to_string())));
|
|
assert!(!is_err_no_such_temp_account(&Error::NoSuchAccount("test".to_string())));
|
|
|
|
assert!(is_err_no_such_group(&Error::NoSuchGroup("test".to_string())));
|
|
assert!(!is_err_no_such_group(&Error::NoSuchUser("test".to_string())));
|
|
|
|
assert!(is_err_no_such_service_account(&Error::NoSuchServiceAccount("test".to_string())));
|
|
assert!(!is_err_no_such_service_account(&Error::NoSuchAccount("test".to_string())));
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_display_format() {
|
|
let test_cases = vec![
|
|
(Error::NoSuchUser("testuser".to_string()), "user 'testuser' does not exist"),
|
|
(Error::NoSuchAccount("testaccount".to_string()), "account 'testaccount' does not exist"),
|
|
(
|
|
Error::NoSuchServiceAccount("service1".to_string()),
|
|
"service account 'service1' does not exist",
|
|
),
|
|
(Error::NoSuchTempAccount("temp1".to_string()), "temp account 'temp1' does not exist"),
|
|
(Error::NoSuchGroup("group1".to_string()), "group 'group1' does not exist"),
|
|
(Error::NoSuchPolicy, "policy does not exist"),
|
|
(Error::PolicyInUse, "policy in use"),
|
|
(Error::GroupNotEmpty, "group not empty"),
|
|
(Error::InvalidArgument, "invalid arguments specified"),
|
|
(Error::IamSysNotInitialized, "not initialized"),
|
|
(Error::InvalidServiceType("invalid".to_string()), "invalid service type: invalid"),
|
|
(Error::ErrCredMalformed, "malformed credential"),
|
|
(Error::CredNotInitialized, "CredNotInitialized"),
|
|
(Error::InvalidAccessKeyLength, "invalid access key length"),
|
|
(Error::InvalidSecretKeyLength, "invalid secret key length"),
|
|
(Error::ContainsReservedChars, "access key contains reserved characters =,"),
|
|
(Error::GroupNameContainsReservedChars, "group name contains reserved characters =,"),
|
|
(Error::NoAccessKey, "no access key"),
|
|
(Error::InvalidToken, "invalid token"),
|
|
(Error::InvalidAccessKey, "invalid access_key"),
|
|
(Error::IAMActionNotAllowed, "action not allowed"),
|
|
(Error::InvalidExpiration, "invalid expiration"),
|
|
(Error::NoSecretKeyWithAccessKey, "no secret key with access key"),
|
|
(Error::NoAccessKeyWithSecretKey, "no access key with secret key"),
|
|
(Error::PolicyTooLarge, "policy too large"),
|
|
];
|
|
|
|
for (error, expected_message) in test_cases {
|
|
assert_eq!(error.to_string(), expected_message);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_error_variant() {
|
|
let custom_message = "Custom error message";
|
|
let error = Error::StringError(custom_message.to_string());
|
|
assert_eq!(error.to_string(), custom_message);
|
|
}
|
|
}
|