edge_schema/schema/
tokens.rs1use std::collections::HashSet;
2
3use serde::{Deserialize, Serialize};
4use time::OffsetDateTime;
5
6#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum NodeApiPermission {
9 #[serde(rename = "all")]
11 All,
12
13 #[serde(rename = "node.health_check")]
15 NodeHealthCheck,
16
17 #[serde(rename = "workload.read")]
19 WorkloadRead,
20
21 #[serde(rename = "workload.write")]
23 WorkloadWrite,
24
25 #[serde(rename = "confdb.entity.read")]
27 ConfDbEntityRead,
28 #[serde(rename = "confdb.entity.delete")]
29 ConfDbEntityDelete,
30
31 #[serde(rename = "tls_cert.read")]
33 TlsCertRead,
34 #[serde(rename = "tls_cert.delete")]
35 TlsCertDelete,
36
37 #[serde(rename = "dns_cache.read")]
38 DnsCacheRead,
39 #[serde(rename = "dns_cache.write")]
40 DnsCacheWrite,
41
42 #[serde(rename = "platform_config.read")]
43 PlatformConfigRead,
44
45 #[serde(rename = "api_token.generate")]
47 ApiTokenGenerate,
48
49 #[serde(rename = "job.read")]
51 JobRead,
52
53 #[serde(rename = "cluster_health.read")]
54 ClusterHealthRead,
55
56 #[serde(rename = "module_cache.read")]
57 ModuleCacheRead,
58 #[serde(rename = "module_cache.write")]
59 ModuleCacheWrite,
60}
61
62impl NodeApiPermission {
63 fn as_str(self) -> &'static str {
64 match self {
65 Self::All => "all",
66 Self::NodeHealthCheck => "node.health_check",
67 Self::WorkloadRead => "workload.read",
68 Self::WorkloadWrite => "workload.write",
69 Self::ConfDbEntityRead => "confdb.entity.read",
70 Self::ConfDbEntityDelete => "confdb.entity.delete",
71 Self::TlsCertRead => "tls_cert.read",
72 Self::TlsCertDelete => "tls_cert.delete",
73 Self::DnsCacheRead => "dns_cache.read",
74 Self::DnsCacheWrite => "dns_cache.write",
75 Self::PlatformConfigRead => "platform_config.read",
76 Self::ApiTokenGenerate => "api_token.generate",
77 Self::JobRead => "job.read",
78 Self::ClusterHealthRead => "cluster_health.read",
79 Self::ModuleCacheRead => "module_cache.read",
80 Self::ModuleCacheWrite => "module_cache.write",
81 }
82 }
83}
84
85impl std::str::FromStr for NodeApiPermission {
86 type Err = anyhow::Error;
87
88 fn from_str(s: &str) -> Result<Self, Self::Err> {
89 match s {
90 "all" => Ok(NodeApiPermission::All),
91 "node.health_check" => Ok(NodeApiPermission::NodeHealthCheck),
92 "workload.read" => Ok(NodeApiPermission::WorkloadRead),
93 "workload.write" => Ok(NodeApiPermission::WorkloadWrite),
94 "confdb.entity.read" => Ok(NodeApiPermission::ConfDbEntityRead),
95 "confdb.entity.delete" => Ok(NodeApiPermission::ConfDbEntityDelete),
96 "tls_cert.read" => Ok(NodeApiPermission::TlsCertRead),
97 "tls_cert.delete" => Ok(NodeApiPermission::TlsCertDelete),
98 "dns_cache.read" => Ok(NodeApiPermission::DnsCacheRead),
99 "dns_cache.write" => Ok(NodeApiPermission::DnsCacheWrite),
100 "platform_config.read" => Ok(NodeApiPermission::PlatformConfigRead),
101 "api_token.generate" => Ok(NodeApiPermission::ApiTokenGenerate),
102 "job.read" => Ok(NodeApiPermission::JobRead),
103 "cluster_health.read" => Ok(NodeApiPermission::ClusterHealthRead),
104 "module_cache.read" => Ok(NodeApiPermission::ModuleCacheRead),
105 "module_cache.write" => Ok(NodeApiPermission::ModuleCacheWrite),
106 _ => Err(anyhow::anyhow!("invalid node api permission: {}", s)),
107 }
108 }
109}
110
111impl std::fmt::Display for NodeApiPermission {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 f.write_str(self.as_str())
114 }
115}
116
117#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
121pub struct BaseClaims {
122 #[serde(with = "time::serde::timestamp")]
124 pub exp: OffsetDateTime,
125
126 #[serde(with = "time::serde::timestamp")]
128 pub iat: OffsetDateTime,
129
130 pub sub: String,
132
133 pub node_api_permissions: Option<HashSet<NodeApiPermission>>,
140}
141
142impl BaseClaims {
143 pub fn has_node_api_permission(&self, perm: NodeApiPermission) -> bool {
144 match &self.node_api_permissions {
145 Some(perms) => perms.contains(&perm) || perms.contains(&NodeApiPermission::All),
146 None => true,
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_base_claims_has_permission() {
157 let c = BaseClaims {
159 exp: OffsetDateTime::now_utc(),
160 iat: OffsetDateTime::now_utc(),
161 sub: "test".to_string(),
162 node_api_permissions: Some(
163 vec![
164 NodeApiPermission::WorkloadRead,
165 NodeApiPermission::ConfDbEntityRead,
166 ]
167 .into_iter()
168 .collect(),
169 ),
170 };
171
172 assert!(c.has_node_api_permission(NodeApiPermission::WorkloadRead));
173 assert!(c.has_node_api_permission(NodeApiPermission::ConfDbEntityRead));
174 assert!(!c.has_node_api_permission(NodeApiPermission::WorkloadWrite));
175 assert!(!c.has_node_api_permission(NodeApiPermission::All));
176
177 let c = BaseClaims {
179 node_api_permissions: Some(vec![NodeApiPermission::All].into_iter().collect()),
180 ..c
181 };
182 assert!(c.has_node_api_permission(NodeApiPermission::WorkloadRead));
183 assert!(c.has_node_api_permission(NodeApiPermission::ConfDbEntityRead));
184 assert!(c.has_node_api_permission(NodeApiPermission::All));
185
186 let c = BaseClaims {
188 node_api_permissions: None,
189 ..c
190 };
191 assert!(c.has_node_api_permission(NodeApiPermission::WorkloadRead));
192 assert!(c.has_node_api_permission(NodeApiPermission::ConfDbEntityRead));
193 assert!(c.has_node_api_permission(NodeApiPermission::All));
194 }
195}