authly_common/policy/
code.rs

1//! Code definitions for the Authly policy engine.
2
3use int_enum::IntEnum;
4use serde::{Deserialize, Serialize};
5
6use crate::id::{AttrId, EntityId, PropId};
7
8/// The value/outcome of a policy engine evaluation.
9#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
10pub enum PolicyValue {
11    /// Represents denied access.
12    Deny,
13    /// Represents allowed access.
14    Allow,
15}
16
17impl PolicyValue {
18    /// Whether self is [Self::Deny],
19    pub fn is_deny(self) -> bool {
20        matches!(self, Self::Deny)
21    }
22
23    /// Whether self is [Self::Allow],
24    pub fn is_allow(self) -> bool {
25        matches!(self, Self::Allow)
26    }
27}
28
29impl From<bool> for PolicyValue {
30    fn from(value: bool) -> Self {
31        match value {
32            false => Self::Deny,
33            true => Self::Allow,
34        }
35    }
36}
37
38/// typed opcode representation for policy engine instructions.
39#[derive(PartialEq, Eq, Debug)]
40#[allow(missing_docs)]
41pub enum OpCode {
42    LoadSubjectId(PropId),
43    LoadSubjectAttrs,
44    LoadResourceId(PropId),
45    LoadResourceAttrs,
46    LoadConstEntityId(EntityId),
47    LoadConstAttrId(AttrId),
48    IsEq,
49    SupersetOf,
50    IdSetContains,
51    And,
52    Or,
53    Not,
54    Return,
55}
56
57/// bytecode representation for policy engine instructions.
58#[repr(u8)]
59#[derive(IntEnum, Debug)]
60#[allow(missing_docs)]
61pub enum Bytecode {
62    LoadSubjectId = 0,
63    LoadSubjectAttrs = 1,
64    LoadResourceId = 2,
65    LoadResourceAttrs = 3,
66    LoadConstAttrId = 4,
67    LoadConstEntityId = 5,
68    IsEq = 6,
69    SupersetOf = 7,
70    IdSetContains = 8,
71    And = 9,
72    Or = 10,
73    Not = 11,
74    Return = 12,
75}
76
77/// Convert slice of opcodes to bytecode.
78pub fn to_bytecode(opcodes: &[OpCode]) -> Vec<u8> {
79    let mut out = Vec::with_capacity(opcodes.len());
80
81    for opcode in opcodes {
82        match opcode {
83            OpCode::LoadSubjectId(prop_id) => {
84                out.push(Bytecode::LoadSubjectId as u8);
85                out.extend(prop_id.to_raw_array());
86            }
87            OpCode::LoadSubjectAttrs => {
88                out.push(Bytecode::LoadSubjectAttrs as u8);
89            }
90            OpCode::LoadResourceId(prop_id) => {
91                out.push(Bytecode::LoadResourceId as u8);
92                out.extend(prop_id.to_raw_array());
93            }
94            OpCode::LoadResourceAttrs => {
95                out.push(Bytecode::LoadResourceAttrs as u8);
96            }
97            OpCode::LoadConstEntityId(eid) => {
98                out.push(Bytecode::LoadConstEntityId as u8);
99                out.push(eid.kind().into());
100                out.extend(eid.id);
101            }
102            OpCode::LoadConstAttrId(prop_id) => {
103                out.push(Bytecode::LoadConstAttrId as u8);
104                out.extend(prop_id.to_raw_array());
105            }
106            OpCode::IsEq => {
107                out.push(Bytecode::IsEq as u8);
108            }
109            OpCode::SupersetOf => {
110                out.push(Bytecode::SupersetOf as u8);
111            }
112            OpCode::IdSetContains => {
113                out.push(Bytecode::IdSetContains as u8);
114            }
115            OpCode::And => {
116                out.push(Bytecode::And as u8);
117            }
118            OpCode::Or => {
119                out.push(Bytecode::Or as u8);
120            }
121            OpCode::Not => {
122                out.push(Bytecode::Not as u8);
123            }
124            OpCode::Return => {
125                out.push(Bytecode::Return as u8);
126            }
127        }
128    }
129
130    out
131}