use thiserror::Error;
use tonic::Status;
#[derive(Debug, Error)]
pub enum AuthError {
#[error("missing authorization metadata")]
MissingAuthorizationMetadata,
#[error("malformed authorization metadata")]
MalformedAuthorizationMetadata,
#[error("invalid bearer token")]
InvalidToken,
#[error("invalid token issuer")]
InvalidIssuer,
#[error("policy denies all access")]
PolicyDeniesAll,
#[error("access denied by policy")]
PolicyDenied,
#[error("internal authentication error")]
Internal,
}
impl AuthError {
pub fn into_status(self) -> Status {
match self {
AuthError::MissingAuthorizationMetadata => {
Status::unauthenticated("missing authorization metadata")
}
AuthError::MalformedAuthorizationMetadata => {
Status::unauthenticated("malformed authorization metadata")
}
AuthError::InvalidToken => Status::unauthenticated("invalid bearer token"),
AuthError::InvalidIssuer => Status::unauthenticated("invalid token issuer"),
AuthError::PolicyDeniesAll => Status::unauthenticated("access denied"),
AuthError::PolicyDenied => Status::permission_denied("access denied by policy"),
AuthError::Internal => Status::internal("internal error"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tonic::Code;
#[test]
fn unauthenticated_variants() {
let cases = [
AuthError::MissingAuthorizationMetadata,
AuthError::MalformedAuthorizationMetadata,
AuthError::InvalidToken,
AuthError::InvalidIssuer,
AuthError::PolicyDeniesAll,
];
for err in cases {
let status = err.into_status();
assert_eq!(
status.code(),
Code::Unauthenticated,
"expected UNAUTHENTICATED"
);
}
}
#[test]
fn permission_denied_variant() {
let status = AuthError::PolicyDenied.into_status();
assert_eq!(status.code(), Code::PermissionDenied);
}
#[test]
fn internal_variant() {
let status = AuthError::Internal.into_status();
assert_eq!(status.code(), Code::Internal);
}
}