rust-xacml
๐ฏSkillfrom huiali/rust-skills
Implements a flexible Rust-based policy decision engine for XACML authorization, supporting RBAC, policy chaining, and context-based access control.
Part of
huiali/rust-skills(30 items)
Installation
npx skills add huiali/rust-skills --skill rust-xacmlSkill Details
"็ญ็ฅๅผๆใๆ้ๅณ็ญใRBACใ็ญ็ฅๆจกๅผใ่ดฃไปป้พ"
Overview
# Rust XACML - ็ญ็ฅๅผๆๆ่ฝ
> ๆฌๆ่ฝๆไพ็ญ็ฅๅณ็ญๅผๆ็้็จ่งฃๅณๆนๆก๏ผๅ ๆฌ RBACใ่ดฃไปป้พใ็ญ็ฅๆจกๅผ็ญใ
ๆ ธๅฟๆฆๅฟต
1. ็ญ็ฅๅผๆๆถๆ
```
็ญ็ฅๅณ็ญๆต็จ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ่ฏทๆฑไธไธๆ โ
โ (ไธปไฝใ่ตๆบใๆไฝใ็ฏๅข) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ็ญ็ฅๅณ็ญ็น (PDP) โ
โ โโโ ็ญ็ฅๅ ่ฝฝ โ
โ โโโ ็ญ็ฅ่ฏไผฐ โ
โ โโโ ๅณ็ญ็ปๅ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅณ็ญ็ปๆ โ
โ (Permit / Deny / NotApplicable / Indeterminate) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
2. ๅณ็ญ็ฑปๅ
| ็ปๆ | ๅซไน | ๅค็ |
|-----|------|-----|
| Permit | ๅ ่ฎธ่ฎฟ้ฎ | ๆง่กๆไฝ |
| Deny | ๆ็ป่ฎฟ้ฎ | ่ฟๅ 403 |
| NotApplicable | ๆ ๅน้ ็ญ็ฅ | ไฝฟ็จ้ป่ฎค่งๅ |
| Indeterminate | ่ฏไผฐ้่ฏฏ | ่ฟๅ 500 |
---
ๆ ธๅฟๆจกๅผ
1. ็ญ็ฅ่ฏไผฐๅจ
```rust
//! ็ญ็ฅ่ฏไผฐๅจ
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// ่ฏทๆฑไธไธๆ
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestContext {
pub subject: Subject, // ไธปไฝ
pub resource: Resource, // ่ตๆบ
pub action: String, // ๆไฝ
pub environment: HashMap
}
/// ไธปไฝ
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Subject {
pub id: String,
pub roles: Vec
pub attributes: HashMap
}
/// ่ตๆบ
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Resource {
pub id: String,
pub r#type: String,
pub attributes: HashMap
}
/// ๅณ็ญ็ปๆ
#[derive(Debug, Clone, PartialEq)]
pub enum Decision {
Permit,
Deny,
NotApplicable,
Indeterminate(String),
}
/// ็ญ็ฅๅฎไน
#[derive(Debug, Clone)]
pub struct Policy {
pub id: String,
pub target: PolicyTarget,
pub rules: Vec
pub combining_algorithm: CombiningAlgorithm,
}
/// ็ญ็ฅ็ฎๆ ๏ผๅน้ ๆกไปถ๏ผ
#[)]
pub struct PolicyTarget {
pubderive(Debug, Clone subjects: Vec
pub resources: Vec
pub actions: Vec
}
/// ่ฎฟ้ฎ่งๅ
#[derive(Debug, Clone)]
pub struct Rule {
pub id: String,
pub effect: RuleEffect,
pub condition: Option
}
#[derive(Debug, Clone, Copy)]
pub enum RuleEffect {
Permit,
Deny,
}
/// ็ญ็ฅ็ปๅ็ฎๆณ
#[derive(Debug, Clone, Copy)]
pub enum CombiningAlgorithm {
DenyOverrides, // Deny ไผๅ
PermitOverrides, // Permit ไผๅ
FirstApplicable, // ้ฆไธช้็จ
OnlyOneApplicable, // ไป ไธไธช้็จ
}
/// ็ญ็ฅ่ฏไผฐๅจ
pub struct PolicyEvaluator {
policies: Vec
}
impl PolicyEvaluator {
pub fn new(policies: Vec
Self { policies }
}
/// ่ฏไผฐ่ฏทๆฑ
pub fn evaluate(&self, context: &RequestContext) -> Decision {
let mut applicable_policies: Vec<&Policy> = self.policies
.iter()
.filter(|p| self.is_target_matched(p, context))
.collect();
if applicable_policies.is_empty() {
return Decision::NotApplicable;
}
// ๆ นๆฎ็ปๅ็ฎๆณ่ฎก็ฎๆ็ปๅณ็ญ
match applicable_policies.first().map(|p| p.combining_algorithm).unwrap_or(CombiningAlgorithm::FirstApplicable) {
CombiningAlgorithm::DenyOverrides => self.deny_overrides(&applicable_policies, context),
CombiningAlgorithm::PermitOverrides => self.permit_overrides(&applicable_policies, context),
CombiningAlgorithm::FirstApplicable => self.first_applicable(&applicable_policies, context),
CombiningAlgorithm::OnlyOneApplicable => {
if applicable_policies.len() == 1 {
self.evaluate_policy(applicable_policies[0], context)
} else {
Decision::Indeterminate("Multiple applicable policies".to_string())
}
}
}
}
fn is_target_matched(&self, policy: &Policy, context: &RequestContext) -> bool {
// ๆฃๆฅ Subjects
let subject_matches = policy.target.subjects.is_empty() ||
policy.target.subjects.iter().any(|roles| {
roles.iter().all(|r| context.subject.roles.contains(r))
});
// ๆฃๆฅ Resources
let resource_matches = policy.target.resources.is_empty() ||
policy.target.resources.contains(&context.resource.r#type);
// ๆฃๆฅ Actions
let action_matches = policy.target.actions.is_empty() ||
policy.target.actions.contains(&context.action);
subject_matches && resource_matches && action_matches
}
fn deny_overrides(&self, policies: &[&Policy], context: &RequestContext) -> Decision {
let mut has_error = false;
let mut error_msg = String::new();
for policy in policies {
match self.evaluate_policy(policy, context) {
Decision::Deny => return Decision::Deny,
Decision::Indeterminate(msg) => {
has_error = true;
error_msg = msg;
}
_ => {}
}
}
if has_error {
Decision::Indeterminate(error_msg)
} else {
Decision::Permit
}
}
fn permit_overrides(&self, policies: &[&Policy], context: &RequestContext) -> Decision {
let mut has_error = false;
let mut error_msg = String::new();
for policy in policies {
match self.evaluate_policy(policy, context) {
Decision::Permit => return Decision::Permit,
Decision::Indeterminate(msg) => {
has_error = true;
error_msg = msg;
}
_ => {}
}
}
if has_error {
Decision::Indeterminate(error_msg)
} else {
Decision::Deny
}
}
fn first_applicable(&self, policies: &[&Policy], context: &RequestContext) -> Decision {
for policy in policies {
let decision = self.evaluate_policy(policy, context);
if decision != Decision::NotApplicable {
return decision;
}
}
Decision::Deny
}
fn evaluate_policy(&self, policy: &Policy, context: &RequestContext) -> Decision {
for rule in &policy.rules {
if let Some(ref condition) = rule.condition {
if !condition(context) {
continue;
}
}
return match rule.effect {
RuleEffect::Permit => Decision::Permit,
RuleEffect::Deny => Decision::Deny,
};
}
Decision::NotApplicable
}
}
```
2. RBAC ๆ้ๆฃๆฅ
```rust
//! RBAC ๆ้ๆฃๆฅ
use std::collections::HashMap;
/// RBAC ้ ็ฝฎ
#[derive(Debug, Clone)]
pub struct RbacConfig {
/// ่ง่ฒๅฑ็บง
pub role_hierarchy: HashMap
/// ่ง่ฒๆ้ๆ ๅฐ
pub role_permissions: HashMap
/// ๆ้ๅฎไน
pub permissions: HashMap
}
/// ๆ้ๅฎไน
#[derive(Debug, Clone)]
pub struct PermissionDef {
pub resource: String,
pub actions: Vec
}
/// RBAC ๆฃๆฅๅจ
pub struct RbacChecker {
config: RbacConfig,
}
impl RbacChecker {
pub fn new(config: RbacConfig) -> Self {
Self { config }
}
/// ๆฃๆฅ็จๆทๆฏๅฆๆๆ้
pub fn check_permission(
&self,
user_roles: &[String],
resource: &str,
action: &str,
) -> bool {
// ่ทๅๆๆ็ปงๆฟ็่ง่ฒ
let all_roles = self.expand_roles(user_roles);
// ๆฃๆฅๆฏๅฆๆๆ้
for role in &all_roles {
if let Some(perms) = self.config.role_permissions.get(role) {
for perm_id in perms {
if let Some(perm) = self.config.permissions.get(perm_id) {
if perm.resource == resource && perm.actions.contains(&action) {
return true;
}
}
}
}
}
false
}
/// ๅฑๅผ่ง่ฒๅฑ็บง
fn expand_roles(&self, roles: &[String]) -> Vec
let mut expanded = Vec::new();
let mut visited = std::collections::HashSet::new();
let mut queue = Vec::new();
for role in roles {
if !visited.contains(role) {
queue.push(role.clone());
visited.insert(role.clone());
}
}
while let Some(role) = queue.pop() {
expanded.push(role.clone());
if let Some(parents) = self.config.role_hierarchy.get(&role) {
for parent in parents {
if !visited.contains(parent) {
visited.insert(parent.clone());
queue.push(parent.clone());
}
}
}
}
expanded
}
/// ่ทๅ็จๆท็ๆๆๆ้
pub fn get_user_permissions(&self, user_roles: &[String]) -> Vec
let all_roles = self.expand_roles(user_roles);
let mut permissions = std::collections::HashSet::new();
for role in &all_roles {
if let Some(role_perms) = self.config.role_permissions.get(role) {
for perm in role_perms {
permissions.insert(perm.clone());
}
}
}
permissions.into_iter().collect()
}
}
```
3. ็ญ็ฅ็ผๅญ
```rust
//! ็ญ็ฅ็ผๅญ
use crate::{Policy, PolicyEvaluator};
use std::sync::Arc;
use tokio::sync::RwLock;
use std::time::{Duration, Instant};
/// ็ผๅญ้ ็ฝฎ
#[derive(Debug, Clone)]
pub struct PolicyCacheConfig {
pub ttl: Duration,
pub max_size: usize,
}
/// ็ผๅญๆก็ฎ
struct CacheEntry {
policy: Policy,
inserted_at: Instant,
}
/// ็ญ็ฅ็ผๅญ
pub struct PolicyCache {
config: PolicyCacheConfig,
cache: Arc
}
impl PolicyCache {
pub fn new(config: PolicyCacheConfig) -> Self {
Self {
config,
cache: Arc::new(RwLock::new(HashMap::new())),
}
}
/// ่ทๅ็ญ็ฅ
pub async fn get(&self, policy_id: &str) -> Option
let cache = self.cache.read().await;
cache.get(policy_id).map(|entry| entry.policy.clone())
}
/// ๅญๅจ็ญ็ฅ
pub async fn set(&self, policy: Policy) {
let mut cache = self.cache.write().await;
// ๆธ ็่ฟๆๆก็ฎ
let now = Instant::now();
cache.retain(|_, v| now.duration_since(v.inserted_at) < self.config.ttl);
// ๆธ ็่ถ ๅบๅคงๅฐ็ๆก็ฎ
if cache.len() >= self.config.max_size {
let to_remove = cache.len() - self.config.max_size + 1;
let keys: Vec
for key in keys {
cache.remove(&key);
}
}
cache.insert(policy.id.clone(), CacheEntry {
policy,
inserted_at: Instant::now(),
});
}
/// ๅคฑๆ็ญ็ฅ
pub async fn invalidate(&self, policy_id: &str) {
let mut cache = self.cache.write().await;
cache.remove(policy_id);
}
/// ๆธ ็ๆๆ
pub async fn clear(&self) {
let mut cache = self.cache.write().await;
cache.clear();
}
}
```
---
ๆไฝณๅฎ่ทต
1. ็ญ็ฅๅฎไน DSL
```rust
//! ็ญ็ฅๆๅปบๅจ
use crate::{Policy, PolicyTarget, Rule, RuleEffect, CombiningAlgorithm};
/// ็ญ็ฅๆๅปบๅจ
pub struct PolicyBuilder {
policy: Policy,
}
impl PolicyBuilder {
pub fn new(id: &str) -> Self {
Self {
policy: Policy {
id: id.to_string(),
target: PolicyTarget {
subjects: Vec::new(),
resources: Vec::new(),
actions: Vec::new(),
},
rules: Vec::new(),
combining_algorithm: CombiningAlgorithm::DenyOverrides,
},
}
}
pub fn with_subject_roles(mut self, roles: &[&str]) -> Self {
self.policy.target.subjects = vec![roles.iter().map(|s| s.to_string()).collect()];
self
}
pub fn with_resource(mut self, resource: &str) -> Self {
self.policy.target.resources = vec![resource.to_string()];
self
}
pub fn with_action(mut self, action: &str) -> Self {
self.policy.target.actions = vec![action.to_string()];
self
}
pub fn add_rule(
mut self,
id: &str,
effect: RuleEffect,
condition: impl Fn(&crate::RequestContext) -> bool + Send + 'static,
) -> Self {
self.policy.rules.push(Rule {
id: id.to_string(),
effect,
condition: Some(Box::new(condition)),
});
self
}
pub fn with_combining_algorithm(mut self, algo: CombiningAlgorithm) -> Self {
self.policy.combining_algorithm = algo;
self
}
pub fn build(self) -> Policy {
self.policy
}
}
/// ไฝฟ็จ็คบไพ
fn example_policy() -> Policy {
PolicyBuilder::new("read-policy")
.with_subject_roles(&["user", "admin"])
.with_resource("document")
.with_action("read")
.add_rule("own-document", RuleEffect::Permit, |ctx| {
// ่ชๅทฑๅๅปบ็ๆๆกฃๅฏไปฅ่ฏปๅ
ctx.resource.attributes.get("owner") == Some(&ctx.subject.id)
})
.add_rule("public-document", RuleEffect::Permit, |ctx| {
// ๅ ฌๅผๆๆกฃๅฏไปฅ่ฏปๅ
ctx.resource.attributes.get("visibility") == Some(&"public".to_string())
})
.with_combining_algorithm(CombiningAlgorithm::DenyOverrides)
.build()
}
```
---
ๅธธ่ง้ฎ้ข
| ้ฎ้ข | ๅๅ | ่งฃๅณๆนๆก |
|-----|------|---------|
| ๅณ็ญไธไธ่ด | ็ปๅ็ฎๆณ้ๆฉไธๅฝ | ๆ นๆฎไธๅก้ๆฉๅ้็็ฎๆณ |
| ๆง่ฝๅทฎ | ็ญ็ฅ่ฟๅค | ไฝฟ็จ็ผๅญๅ็ดขๅผ |
| ๆ้็ป่ฟ | ่งๅ้กบๅบ้ฎ้ข | DenyOverrides ไผๅ |
---
ๅ ณ่ๆ่ฝ
rust-auth- ่ฎค่ฏๆๆrust-web- Web ้ๆrust-cache- ็ญ็ฅ็ผๅญrust-performance- ๆง่ฝไผๅ
More from this repository10
Provides expert Rust programming assistance, solving compilation errors, ownership, lifetimes, concurrency, and performance optimization challenges.
Indexes and provides quick navigation for 35 Rust skills across core, advanced, and expert categories.
Expertly handles Rust error scenarios by providing comprehensive guidance on Result, Option, error types, propagation, and panic strategies.
Handles advanced Rust async patterns like Stream processing, backpressure, select, cancellation, and concurrency management with Tokio.
Expertly handles Rust concurrency challenges by safely managing threads, async operations, and preventing race conditions and deadlocks.
Identifies and helps refactor Rust anti-patterns like unnecessary cloning, unwrapping, and inefficient iterations to improve code quality.
Builds robust Rust web services using frameworks like axum and actix, handling routing, database interactions, and API design with type-safe, performant code.
Skill
Analyzes and optimizes Rust generic abstractions and dispatch strategies for zero-cost performance and compile-time flexibility.
Expertly manages Rust mutability challenges, resolving borrowing conflicts and providing safe interior mutability strategies across different contexts.