zookeeper_async/
acl.rs

1use std::fmt;
2use std::ops;
3
4use std::string::ToString;
5
6use lazy_static::lazy_static;
7
8/// Describes the ability of a user to perform a certain action.
9///
10/// Permissions can be mixed together like integers with `|` and `&`.
11#[derive(Clone, Copy, Debug, PartialEq)]
12pub struct Permission(u32);
13
14impl Permission {
15    /// No permissions are set (server could have been configured without ACL support).
16    pub const NONE: Permission = Permission(0b00000);
17
18    /// You can access the data of a node and can list its children.
19    pub const READ: Permission = Permission(0b00001);
20
21    /// You can set the data of a node.
22    pub const WRITE: Permission = Permission(0b00010);
23
24    /// You can create a child node.
25    pub const CREATE: Permission = Permission(0b00100);
26
27    /// You can delete a child node (but not necessarily this one).
28    pub const DELETE: Permission = Permission(0b01000);
29
30    /// You can alter permissions on this node.
31    pub const ADMIN: Permission = Permission(0b10000);
32
33    /// You can do anything.
34    pub const ALL: Permission = Permission(0b11111);
35
36    /// Extract a permission value from raw `bits`.
37    pub(crate) fn from_raw(bits: u32) -> Permission {
38        Permission(bits)
39    }
40
41    pub(crate) fn code(&self) -> u32 {
42        self.0
43    }
44
45    /// Check that all `permissions` are set.
46    ///
47    /// ```
48    /// use zookeeper_async::Permission;
49    ///
50    /// (Permission::READ | Permission::WRITE).can(Permission::WRITE); // -> true
51    /// Permission::ADMIN.can(Permission::CREATE); // -> false
52    /// ```
53    pub fn can(self, permissions: Permission) -> bool {
54        (self & permissions) == permissions
55    }
56}
57
58impl ops::BitAnd for Permission {
59    type Output = Self;
60
61    fn bitand(self, rhs: Self) -> Self {
62        Permission::from_raw(self.0 & rhs.0)
63    }
64}
65
66impl ops::BitOr for Permission {
67    type Output = Self;
68
69    fn bitor(self, rhs: Self) -> Self {
70        Permission::from_raw(self.0 | rhs.0)
71    }
72}
73
74impl fmt::Display for Permission {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        if *self == Permission::ALL {
77            write!(f, "ALL")
78        } else if *self == Permission::NONE {
79            write!(f, "NONE")
80        } else {
81            let mut first = true;
82            let mut tick = || {
83                if first {
84                    first = false;
85                    ""
86                } else {
87                    "|"
88                }
89            };
90
91            if self.can(Permission::READ) {
92                write!(f, "{}READ", tick())?;
93            }
94            if self.can(Permission::WRITE) {
95                write!(f, "{}WRITE", tick())?;
96            }
97            if self.can(Permission::CREATE) {
98                write!(f, "{}CREATE", tick())?;
99            }
100            if self.can(Permission::DELETE) {
101                write!(f, "{}DELETE", tick())?;
102            }
103            if self.can(Permission::ADMIN) {
104                write!(f, "{}ADMIN", tick())?;
105            }
106            Ok(())
107        }
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn permission_bitor() {
117        let all = Permission::READ
118            | Permission::WRITE
119            | Permission::CREATE
120            | Permission::DELETE
121            | Permission::ADMIN;
122        assert_eq!(Permission::ALL, all);
123    }
124
125    #[test]
126    fn permission_can() {
127        assert!(Permission::ALL.can(Permission::WRITE));
128        assert!(!Permission::WRITE.can(Permission::READ));
129    }
130
131    #[test]
132    fn permission_format() {
133        assert_eq!("ALL", Permission::ALL.to_string());
134        assert_eq!("NONE", Permission::NONE.to_string());
135        assert_eq!(
136            "READ|WRITE",
137            (Permission::READ | Permission::WRITE).to_string()
138        );
139        assert_eq!(
140            "CREATE|DELETE",
141            (Permission::CREATE | Permission::DELETE).to_string()
142        );
143        assert_eq!("ADMIN", Permission::ADMIN.to_string());
144    }
145}
146
147/// An access control list.
148///
149/// In general, the ACL system is similar to UNIX file access permissions, where znodes act as
150/// files. Unlike UNIX, each znode can have any number of ACLs to correspond with the potentially
151/// limitless (and pluggable) authentication schemes. A more surprising difference is that ACLs are
152/// not recursive: If `/path` is only readable by a single user, but `/path/sub` is world-readable,
153/// then anyone will be able to read `/path/sub`.
154///
155/// See the [ZooKeeper Programmer's Guide](https://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#sc_ZooKeeperAccessControl)
156/// for more information.
157#[derive(Clone, Debug, PartialEq)]
158pub struct Acl {
159    /// The permissions associated with this ACL.
160    pub perms: Permission,
161    /// The authentication scheme this list is used for. The most common scheme is `"auth"`, which
162    /// allows any authenticated user to do anything (see `creator_all`).
163    pub scheme: String,
164    /// The ID of the user under the `scheme`. For example, with the `"ip"` `scheme`, this is an IP
165    /// address or CIDR netmask.
166    pub id: String,
167}
168
169impl Acl {
170    /// Create a new ACL with the given `permissions`, `scheme`, and `id`.
171    pub fn new<T, U>(permissions: Permission, scheme: T, id: U) -> Acl
172    where
173        T: ToString,
174        U: ToString,
175    {
176        Acl {
177            perms: permissions,
178            scheme: scheme.to_string(),
179            id: id.to_string(),
180        }
181    }
182
183    /// This ACL gives the creators authentication id's all permissions.
184    pub fn creator_all() -> &'static Vec<Acl> {
185        &ACL_CREATOR_ALL
186    }
187
188    /// This is a completely open ACL.
189    pub fn open_unsafe() -> &'static Vec<Acl> {
190        &ACL_OPEN_UNSAFE
191    }
192
193    /// This ACL gives the world the ability to read.
194    pub fn read_unsafe() -> &'static Vec<Acl> {
195        &ACL_READ_UNSAFE
196    }
197}
198
199lazy_static! {
200    static ref ACL_CREATOR_ALL: Vec<Acl> = vec![Acl::new(Permission::ALL, "auth", "")];
201    static ref ACL_OPEN_UNSAFE: Vec<Acl> = vec![Acl::new(Permission::ALL, "world", "anyone")];
202    static ref ACL_READ_UNSAFE: Vec<Acl> = vec![Acl::new(Permission::READ, "world", "anyone")];
203}
204
205impl fmt::Display for Acl {
206    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207        write!(f, "({}:{}, {})", self.scheme, self.id, self.perms)
208    }
209}