use crate::errors;
use crate::{Host, Result, WasccEntity};
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::RwLock;
use wascap::jwt::Token;
use wascap::prelude::*;
pub(crate) type ClaimsMap = Arc<RwLock<HashMap<String, Claims<wascap::jwt::Actor>>>>;
pub trait Authorizer: Sync + Send {
fn can_load(&self, claims: &Claims<Actor>) -> bool;
fn can_invoke(&self, claims: &Claims<Actor>, target: &WasccEntity, operation: &str) -> bool;
}
pub(crate) struct DefaultAuthorizer {}
impl DefaultAuthorizer {
pub fn new() -> impl Authorizer {
DefaultAuthorizer {}
}
}
impl Authorizer for DefaultAuthorizer {
fn can_load(&self, _claims: &Claims<Actor>) -> bool {
true
}
fn can_invoke(&self, _claims: &Claims<Actor>, target: &WasccEntity, _operation: &str) -> bool {
match target {
WasccEntity::Actor(_a) => true,
WasccEntity::Capability { .. } => true,
}
}
}
pub(crate) fn get_all_claims(map: ClaimsMap) -> Vec<(String, Claims<wascap::jwt::Actor>)> {
map.read()
.unwrap()
.iter()
.map(|(pk, claims)| (pk.clone(), claims.clone()))
.collect()
}
pub(crate) fn can_invoke(
claims: &Claims<wascap::jwt::Actor>,
capability_id: &str,
_operation: &str,
) -> bool {
if claims.subject == capability_id {
return true;
}
claims
.metadata
.as_ref()
.unwrap()
.caps
.as_ref()
.map_or(false, |caps| caps.contains(&capability_id.to_string()))
}
pub(crate) fn extract_claims(buf: &[u8]) -> Result<wascap::jwt::Token<wascap::jwt::Actor>> {
let token = wascap::wasm::extract_claims(buf)?;
match token {
Some(token) => {
let claims = token.claims.clone();
let caps = claims.metadata.as_ref().unwrap().caps.clone();
info!(
"Actor claims loaded for {} - {}",
&claims.subject,
caps.unwrap_or(vec![]).join(",")
);
Ok(token)
}
None => Err(errors::new(errors::ErrorKind::Authorization(
"No embedded JWT in actor module".to_string(),
))),
}
}
pub(crate) fn enforce_validation(jwt: &str) -> Result<()> {
let v = validate_token::<wascap::jwt::Actor>(jwt)?;
if v.expired {
Err(errors::new(errors::ErrorKind::Authorization(
"Expired token".to_string(),
)))
} else if v.cannot_use_yet {
Err(errors::new(errors::ErrorKind::Authorization(format!(
"Module cannot be used before {}",
v.not_before_human
))))
} else {
Ok(())
}
}
pub(crate) fn register_claims(
claims_map: ClaimsMap,
subject: &str,
claims: Claims<wascap::jwt::Actor>,
) {
claims_map
.write()
.unwrap()
.insert(subject.to_string(), claims);
}
pub(crate) fn unregister_claims(claims_map: ClaimsMap, subject: &str) {
{
let mut lock = claims_map.write().unwrap();
let _ = lock.remove(subject);
}
}
impl Host {
pub(crate) fn check_auth(&self, token: &Token<wascap::jwt::Actor>) -> bool {
self.authorizer.read().unwrap().can_load(&token.claims)
}
}