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
129
130
131
//! Code definitions for the Authly policy engine.

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

use crate::id::{AttrId, EntityId, PropId};

/// 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(PropId),
    LoadSubjectAttrs,
    LoadResourceId(PropId),
    LoadResourceAttrs,
    LoadConstEntityId(EntityId),
    LoadConstAttrId(AttrId),
    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(prop_id) => {
                out.push(Bytecode::LoadSubjectId as u8);
                out.extend(prop_id.to_raw_array());
            }
            OpCode::LoadSubjectAttrs => {
                out.push(Bytecode::LoadSubjectAttrs as u8);
            }
            OpCode::LoadResourceId(prop_id) => {
                out.push(Bytecode::LoadResourceId as u8);
                out.extend(prop_id.to_raw_array());
            }
            OpCode::LoadResourceAttrs => {
                out.push(Bytecode::LoadResourceAttrs as u8);
            }
            OpCode::LoadConstEntityId(eid) => {
                out.push(Bytecode::LoadConstEntityId as u8);
                out.push(eid.kind().into());
                out.extend(eid.id);
            }
            OpCode::LoadConstAttrId(prop_id) => {
                out.push(Bytecode::LoadConstAttrId as u8);
                out.extend(prop_id.to_raw_array());
            }
            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
}