use crate::auth::policy::Policy;
use crate::auth::token_repository::ManageTokens;
use reduct_base::error::ReductError;
use std::net::IpAddr;
pub(crate) struct TokenAuthorization {
api_token: String,
}
impl TokenAuthorization {
pub fn new(api_token: &str) -> Self {
Self {
api_token: api_token.to_string(),
}
}
pub async fn check<Plc>(
&self,
authorization_header: Option<&str>,
client_ip: Option<IpAddr>,
repo: &mut (dyn ManageTokens + Send),
policy: Plc,
) -> Result<(), ReductError>
where
Plc: Policy,
{
if self.api_token.is_empty() {
return Ok(());
}
let token = repo.validate_token(authorization_header, client_ip).await;
policy.validate(token)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::auth::policy::{AnonymousPolicy, FullAccessPolicy};
use crate::auth::token_repository::BoxedTokenRepository;
use crate::auth::token_repository::TokenRepositoryBuilder;
use crate::cfg::Cfg;
use tempfile::tempdir;
#[tokio::test]
async fn test_anonymous_policy() {
let (mut repo, auth) = setup().await;
let result = auth
.check(Some("invalid"), None, repo.as_mut(), AnonymousPolicy {})
.await;
assert!(result.is_ok());
let result = auth
.check(
Some("Bearer invalid"),
None,
repo.as_mut(),
AnonymousPolicy {},
)
.await;
assert!(result.is_ok());
let result = auth
.check(Some("Bearer test"), None, repo.as_mut(), AnonymousPolicy {})
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_full_access_policy() {
let (mut repo, auth) = setup().await;
let result = auth
.check(Some("invalid"), None, repo.as_mut(), FullAccessPolicy {})
.await;
assert_eq!(
result,
Err(ReductError::unauthorized(
"No bearer token in request header"
))
);
let result = auth
.check(
Some("Bearer invalid"),
None,
repo.as_mut(),
FullAccessPolicy {},
)
.await;
assert_eq!(result, Err(ReductError::unauthorized("Invalid token")));
let result = auth
.check(
Some("Bearer test"),
None,
repo.as_mut(),
FullAccessPolicy {},
)
.await;
assert!(result.is_ok());
}
async fn setup() -> (BoxedTokenRepository, TokenAuthorization) {
let cfg = Cfg {
api_token: "test".to_string(),
..Cfg::default()
};
let repo = TokenRepositoryBuilder::new(cfg)
.build(tempdir().unwrap().keep())
.await;
let auth = TokenAuthorization::new("test");
(repo, auth)
}
}