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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
use std::fmt;
use std::ops;

use std::string::ToString;

/// Describes the ability of a user to perform a certain action.
///
/// Permissions can be mixed together like integers with `|` and `&`.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Permission(u32);

impl Permission {
    /// No permissions are set (server could have been configured without ACL support).
    pub const NONE: Permission = Permission(0b00000);

    /// You can access the data of a node and can list its children.
    pub const READ: Permission = Permission(0b00001);

    /// You can set the data of a node.
    pub const WRITE: Permission = Permission(0b00010);

    /// You can create a child node.
    pub const CREATE: Permission = Permission(0b00100);

    /// You can delete a child node (but not necessarily this one).
    pub const DELETE: Permission = Permission(0b01000);

    /// You can alter permissions on this node.
    pub const ADMIN: Permission = Permission(0b10000);

    /// You can do anything.
    pub const ALL: Permission = Permission(0b11111);

    /// Extract a permission value from raw `bits`.
    pub(crate) fn from_raw(bits: u32) -> Permission {
        Permission(bits)
    }

    pub(crate) fn code(&self) -> u32 {
        self.0
    }

    /// Check that all `permissions` are set.
    ///
    /// ```
    /// use zookeeper::Permission;
    ///
    /// (Permission::READ | Permission::WRITE).can(Permission::WRITE); // -> true
    /// Permission::ADMIN.can(Permission::CREATE); // -> false
    /// ```
    pub fn can(self, permissions: Permission) -> bool {
        (self & permissions) == permissions
    }
}

impl ops::BitAnd for Permission {
    type Output = Self;

    fn bitand(self, rhs: Self) -> Self {
        Permission::from_raw(self.0 & rhs.0)
    }
}

impl ops::BitOr for Permission {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Permission::from_raw(self.0 | rhs.0)
    }
}


impl fmt::Display for Permission {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if *self == Permission::ALL {
            write!(f, "ALL")
        } else if *self == Permission::NONE {
            write!(f, "NONE")
        } else {
            let mut first = true;
            let mut tick = || {
                if first {
                    first = false;
                    ""
                } else {
                    "|"
                }
            };

            if self.can(Permission::READ)   { write!(f, "{}READ", tick())?; }
            if self.can(Permission::WRITE)  { write!(f, "{}WRITE", tick())?; }
            if self.can(Permission::CREATE) { write!(f, "{}CREATE", tick())?; }
            if self.can(Permission::DELETE) { write!(f, "{}DELETE", tick())?; }
            if self.can(Permission::ADMIN)  { write!(f, "{}ADMIN", tick())?; }
            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn permission_bitor() {
        let all = Permission::READ
                | Permission::WRITE
                | Permission::CREATE
                | Permission::DELETE
                | Permission::ADMIN;
        assert_eq!(Permission::ALL, all);
    }

    #[test]
    fn permission_can() {
        assert!(Permission::ALL.can(Permission::WRITE));
        assert!(!Permission::WRITE.can(Permission::READ));
    }

    #[test]
    fn permission_format() {
        assert_eq!("ALL", Permission::ALL.to_string());
        assert_eq!("NONE", Permission::NONE.to_string());
        assert_eq!("READ|WRITE", (Permission::READ | Permission::WRITE).to_string());
        assert_eq!("CREATE|DELETE", (Permission::CREATE | Permission::DELETE).to_string());
        assert_eq!("ADMIN", Permission::ADMIN.to_string());
    }
}

/// An access control list.
///
/// In general, the ACL system is similar to UNIX file access permissions, where znodes act as
/// files. Unlike UNIX, each znode can have any number of ACLs to correspond with the potentially
/// limitless (and pluggable) authentication schemes. A more surprising difference is that ACLs are
/// not recursive: If `/path` is only readable by a single user, but `/path/sub` is world-readable,
/// then anyone will be able to read `/path/sub`.
///
/// See the [ZooKeeper Programmer's Guide](https://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#sc_ZooKeeperAccessControl)
/// for more information.
#[derive(Clone, Debug, PartialEq)]
pub struct Acl {
    /// The permissions associated with this ACL.
    pub perms: Permission,
    /// The authentication scheme this list is used for. The most common scheme is `"auth"`, which
    /// allows any authenticated user to do anything (see `creator_all`).
    pub scheme: String,
    /// The ID of the user under the `scheme`. For example, with the `"ip"` `scheme`, this is an IP
    /// address or CIDR netmask.
    pub id: String,
}

impl Acl {
    /// Create a new ACL with the given `permissions`, `scheme`, and `id`.
    pub fn new<T, U>(permissions: Permission, scheme: T, id: U) -> Acl
            where T: ToString, U: ToString {
        Acl {
            perms: permissions,
            scheme: scheme.to_string(),
            id: id.to_string(),
        }
    }

    /// This ACL gives the creators authentication id's all permissions.
    pub fn creator_all() -> &'static Vec<Acl> {
        &ACL_CREATOR_ALL
    }

    /// This is a completely open ACL.
    pub fn open_unsafe() -> &'static Vec<Acl> {
        &ACL_OPEN_UNSAFE
    }

    /// This ACL gives the world the ability to read.
    pub fn read_unsafe() -> &'static Vec<Acl> {
        &ACL_READ_UNSAFE
    }
}

lazy_static! {
    static ref ACL_CREATOR_ALL: Vec<Acl> = vec![Acl::new(Permission::ALL, "auth", "")];
    static ref ACL_OPEN_UNSAFE: Vec<Acl> = vec![Acl::new(Permission::ALL, "world", "anyone")];
    static ref ACL_READ_UNSAFE: Vec<Acl> = vec![Acl::new(Permission::READ, "world", "anyone")];
}

impl fmt::Display for Acl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}:{}, {})", self.scheme, self.id, self.perms)
    }
}