use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum Effect {
Allow,
Deny,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AccessDecision {
Allow,
Deny,
NoMatch,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct PolicyStatement {
#[serde(skip_serializing_if = "Option::is_none")]
pub sid: Option<String>,
pub effect: Effect,
pub action: Vec<String>,
pub resource: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<PolicyCondition>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct PolicyCondition {
#[serde(skip_serializing_if = "Option::is_none")]
pub ip_address: Option<IpAddressCondition>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date_time: Option<DateTimeCondition>,
#[serde(skip_serializing_if = "Option::is_none")]
pub string_like: Option<HashMap<String, Vec<String>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub numeric: Option<NumericCondition>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bool: Option<HashMap<String, bool>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IpAddressCondition {
#[serde(skip_serializing_if = "Option::is_none")]
pub source_ip: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub not_source_ip: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DateTimeCondition {
#[serde(skip_serializing_if = "Option::is_none")]
pub date_greater_than: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date_less_than: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub days_of_week: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hours_of_day: Option<Vec<u8>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NumericCondition {
#[serde(skip_serializing_if = "Option::is_none")]
pub greater_than: Option<HashMap<String, i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub less_than: Option<HashMap<String, i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub equals: Option<HashMap<String, i64>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct AbacPolicy {
pub version: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub statement: Vec<PolicyStatement>,
}
impl AbacPolicy {
pub fn new() -> Self {
Self {
version: "2012-10-17".to_string(),
id: None,
statement: Vec::new(),
}
}
pub fn add_statement(&mut self, statement: PolicyStatement) {
self.statement.push(statement);
}
pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(json)
}
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(self)
}
}
impl Default for AbacPolicy {
fn default() -> Self {
Self::new()
}
}
impl PolicyStatement {
pub fn new(effect: Effect, action: Vec<String>, resource: Vec<String>) -> Self {
Self {
sid: None,
effect,
action,
resource,
condition: None,
}
}
pub fn with_condition(mut self, condition: PolicyCondition) -> Self {
self.condition = Some(condition);
self
}
pub fn with_sid(mut self, sid: String) -> Self {
self.sid = Some(sid);
self
}
}
impl PolicyCondition {
pub fn new() -> Self {
Self {
ip_address: None,
date_time: None,
string_like: None,
numeric: None,
bool: None,
}
}
pub fn with_ip_whitelist(mut self, ips: Vec<String>) -> Self {
self.ip_address = Some(IpAddressCondition {
source_ip: Some(ips),
not_source_ip: None,
});
self
}
pub fn with_ip_blacklist(mut self, ips: Vec<String>) -> Self {
self.ip_address = Some(IpAddressCondition {
source_ip: None,
not_source_ip: Some(ips),
});
self
}
pub fn with_time_window(
mut self,
after: Option<DateTime<Utc>>,
before: Option<DateTime<Utc>>,
) -> Self {
self.date_time = Some(DateTimeCondition {
date_greater_than: after,
date_less_than: before,
days_of_week: None,
hours_of_day: None,
});
self
}
pub fn with_days_of_week(mut self, days: Vec<u8>) -> Self {
if let Some(ref mut dt) = self.date_time {
dt.days_of_week = Some(days);
} else {
self.date_time = Some(DateTimeCondition {
date_greater_than: None,
date_less_than: None,
days_of_week: Some(days),
hours_of_day: None,
});
}
self
}
pub fn with_hours_of_day(mut self, hours: Vec<u8>) -> Self {
if let Some(ref mut dt) = self.date_time {
dt.hours_of_day = Some(hours);
} else {
self.date_time = Some(DateTimeCondition {
date_greater_than: None,
date_less_than: None,
days_of_week: None,
hours_of_day: Some(hours),
});
}
self
}
}
impl Default for PolicyCondition {
fn default() -> Self {
Self::new()
}
}