authly_common/policy/
code.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Code definitions for the Authly policy engine.

use int_enum::IntEnum;
use serde::{Deserialize, Serialize};

/// The value/outcome of a policy engine evaluation.
#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
pub enum PolicyValue {
    /// Represents denied access.
    Deny,
    /// Represents allowed access.
    Allow,
}

impl PolicyValue {
    /// Whether self is [Self::Deny],
    pub fn is_deny(self) -> bool {
        matches!(self, Self::Deny)
    }

    /// Whether self is [Self::Allow],
    pub fn is_allow(self) -> bool {
        matches!(self, Self::Allow)
    }
}

impl From<bool> for PolicyValue {
    fn from(value: bool) -> Self {
        match value {
            false => Self::Deny,
            true => Self::Allow,
        }
    }
}

/// typed opcode representation for policy engine instructions.
#[derive(PartialEq, Eq, Debug)]
#[allow(missing_docs)]
pub enum OpCode {
    LoadSubjectId(u128),
    LoadSubjectAttrs,
    LoadResourceId(u128),
    LoadResourceAttrs,
    LoadConstEntityId(u128),
    LoadConstAttrId(u128),
    IsEq,
    SupersetOf,
    IdSetContains,
    And,
    Or,
    Not,
    Return,
}

/// bytecode representation for policy engine instructions.
#[repr(u8)]
#[derive(IntEnum, Debug)]
#[allow(missing_docs)]
pub enum Bytecode {
    LoadSubjectId = 0,
    LoadSubjectAttrs = 1,
    LoadResourceId = 2,
    LoadResourceAttrs = 3,
    LoadConstAttrId = 4,
    LoadConstEntityId = 5,
    IsEq = 6,
    SupersetOf = 7,
    IdSetContains = 8,
    And = 9,
    Or = 10,
    Not = 11,
    Return = 12,
}

/// Convert slice of opcodes to bytecode.
pub fn to_bytecode(opcodes: &[OpCode]) -> Vec<u8> {
    let mut out = Vec::with_capacity(opcodes.len());

    for opcode in opcodes {
        match opcode {
            OpCode::LoadSubjectId(eid) => {
                out.push(Bytecode::LoadSubjectId as u8);
                out.extend(unsigned_varint::encode::u128(*eid, &mut Default::default()));
            }
            OpCode::LoadSubjectAttrs => {
                out.push(Bytecode::LoadSubjectAttrs as u8);
            }
            OpCode::LoadResourceId(eid) => {
                out.push(Bytecode::LoadResourceId as u8);
                out.extend(unsigned_varint::encode::u128(*eid, &mut Default::default()));
            }
            OpCode::LoadResourceAttrs => {
                out.push(Bytecode::LoadResourceAttrs as u8);
            }
            OpCode::LoadConstEntityId(id) => {
                out.push(Bytecode::LoadConstEntityId as u8);
                out.extend(unsigned_varint::encode::u128(*id, &mut Default::default()));
            }
            OpCode::LoadConstAttrId(id) => {
                out.push(Bytecode::LoadConstAttrId as u8);
                out.extend(unsigned_varint::encode::u128(*id, &mut Default::default()));
            }
            OpCode::IsEq => {
                out.push(Bytecode::IsEq as u8);
            }
            OpCode::SupersetOf => {
                out.push(Bytecode::SupersetOf as u8);
            }
            OpCode::IdSetContains => {
                out.push(Bytecode::IdSetContains as u8);
            }
            OpCode::And => {
                out.push(Bytecode::And as u8);
            }
            OpCode::Or => {
                out.push(Bytecode::Or as u8);
            }
            OpCode::Not => {
                out.push(Bytecode::Not as u8);
            }
            OpCode::Return => {
                out.push(Bytecode::Return as u8);
            }
        }
    }

    out
}