diff options
Diffstat (limited to 'lockchain-core/src/users')
-rw-r--r-- | lockchain-core/src/users/keystore.rs | 5 | ||||
-rw-r--r-- | lockchain-core/src/users/mod.rs | 70 | ||||
-rw-r--r-- | lockchain-core/src/users/rights.rs | 7 | ||||
-rw-r--r-- | lockchain-core/src/users/secrets.rs | 2 | ||||
-rw-r--r-- | lockchain-core/src/users/store.rs | 39 | ||||
-rw-r--r-- | lockchain-core/src/users/user.rs | 80 | ||||
-rw-r--r-- | lockchain-core/src/users/userstore.rs | 54 |
7 files changed, 154 insertions, 103 deletions
diff --git a/lockchain-core/src/users/keystore.rs b/lockchain-core/src/users/keystore.rs index 71d7be2..7da77ec 100644 --- a/lockchain-core/src/users/keystore.rs +++ b/lockchain-core/src/users/keystore.rs @@ -5,12 +5,17 @@ //! - Adding keys for a user //! - Removing keys //! - Retrieving keys +//! +//! **This module is meant to be used by lockchain-library implementations** + +#![deprecated(since="0.10.0", note="Use the `userstore::UserStore` structure instead")] use traits::{AutoEncoder, Base64AutoEncoder}; use {crypto::Key, meta::MetaDomain}; use std::collections::HashMap; +/// A utility wrapper around a Username -> Key collection #[derive(Serialize, Deserialize)] pub struct KeyStore { keys: HashMap<String, Key>, diff --git a/lockchain-core/src/users/mod.rs b/lockchain-core/src/users/mod.rs index e9205d1..bad4256 100644 --- a/lockchain-core/src/users/mod.rs +++ b/lockchain-core/src/users/mod.rs @@ -12,18 +12,21 @@ //! //! `User` is also a serialisable struct which contains important //! data to load and store them into a metadata store. +#![allow(deprecated)] mod auth; +mod user; mod rights; mod tokens; mod keystore; -mod store; mod secrets; +mod userstore; pub use self::auth::pam_authenticate; pub use self::keystore::KeyStore; pub use self::tokens::Token; +pub use self::user::User; pub use errors::AuthError; pub use self::rights::{Access, Role}; @@ -35,69 +38,6 @@ use { traits::{AutoEncoder, Base64AutoEncoder}, }; -/// A generic user representation -/// -/// A user has an identify check built in that can verify a passphrase -/// but is ultimately only a metadata item for a API layer. Any layer is -/// free to disregard these access rights (as such, they should not be -/// considered security, only obscurity/ management control) -/// -/// A company might not want allow non-admins to create new vaults or -/// users to delete records. This does not cryptographically stop anyone -/// from breaking into the company server, swapping the source code and -/// changing the rules! -/// -/// An user can have multiple role-access pairs -#[derive(Serialize, Deserialize, Clone)] -pub struct User { - name: String, - pw_hash: String, - rights: HashMap<Access, Role>, - token: Option<String>, -} - -impl User { - /// Register a new user with a name and password - pub fn register(name: &str, pw: &str) -> Self { - Self { - name: name.into(), - pw_hash: encoding::base64_encode(&hashing::blake2(pw, name).to_vec()), - rights: HashMap::new(), - token: None, - } - } - /// Verify a user password input - pub fn verify(&self, pw: &str) -> bool { - self.pw_hash == encoding::base64_encode(&hashing::blake2(pw, &self.name).to_vec()) - } - /// Provides a hook to use second-factor authentication to authorise - /// - /// This is meant to be used with an external Yubikey - pub fn second_auth_verify(&mut self) -> bool { - unimplemented!() - } - /// Generate a token unique to this user (or return the existing one) - pub fn token(&mut self) -> String { - if self.token.is_none() { - self.token = Some(encoding::base64_encode(&random::bytes(256))); - } - - self.token.as_ref().unwrap().clone() - } - /// Verify that a user is allowed access to a piece of data - /// - /// `None` means "no access of any kind" - pub fn has_access(&self, item: Access) -> Option<Role> { - self.rights.get(&item).map(|i| i.clone()) - } - /// Modify access to an item for a role or create a new access entry - pub fn give_access(&mut self, item: Access, role: Role) { - self.rights.insert(item, role); - } -} - -impl AutoEncoder for User {} - /// A utility structure that manages users and can be derived /// from/into a metadata object. By default this process uses /// base64 encoding. @@ -106,6 +46,8 @@ impl AutoEncoder for User {} /// users and then use `meta_push_domain` and give it the /// `UserStore::into()` which is then encoded automatically. /// The reverse action works the same way +#[deprecated(since="0.10.0", note="Use the `userstore::UserStore` structure instead")] +#[allow(deprecated)] #[derive(Serialize, Deserialize)] pub struct UserStore { /// A map between username – user item diff --git a/lockchain-core/src/users/rights.rs b/lockchain-core/src/users/rights.rs index 4404253..b9ea6cd 100644 --- a/lockchain-core/src/users/rights.rs +++ b/lockchain-core/src/users/rights.rs @@ -1,8 +1,12 @@ +//! Permission and access system for lockchain + use traits::AutoEncoder; /// Specifies access to a resource #[derive(Hash, Serialize, Deserialize, Clone, PartialEq, Eq)] pub enum Access { + /// A key that is only used to re-encrypt sub-keys + Root, /// Allows access to vault metadata & index files Vault(Role), /// Allows access to a record resource inside a vault @@ -14,8 +18,11 @@ impl AutoEncoder for Access {} /// Specifies the capabilities of a user #[derive(Hash, Serialize, Deserialize, Clone, PartialEq, Eq)] pub enum Role { + /// Only has read access Reader, + /// Can edit any field in a record Editor, + /// Can modify base structure, squash and delete records Admin, } diff --git a/lockchain-core/src/users/secrets.rs b/lockchain-core/src/users/secrets.rs index 8210a09..2b4d45a 100644 --- a/lockchain-core/src/users/secrets.rs +++ b/lockchain-core/src/users/secrets.rs @@ -1,3 +1,5 @@ +//! A secrets type module that wraps around some user content with metadata + use traits::AutoEncoder; /// Specifies the type of secret that's used to derive a vault user secret diff --git a/lockchain-core/src/users/store.rs b/lockchain-core/src/users/store.rs deleted file mode 100644 index d400668..0000000 --- a/lockchain-core/src/users/store.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::rights::Access; -use super::secrets::SecretType; -use crypto::Key; -use std::collections::HashMap; - -/// A thin user keystore -/// -/// It's implementation can manage multiple keys per user, of various -/// types and constrained for limited access rights. -pub struct KeyStore { - store: HashMap<String, StoreUser>, -} - -struct StoreUser { - name: String, - keys: HashMap<Access, Key>, -} - -impl KeyStore { - /// Create a new, empty keystore - /// - /// This is most likely *not* what you want. Instead, transform - /// a `MetaData` object into a keystore. - pub fn new() -> Self { - Self { - store: HashMap::new(), - } - } - - pub fn add_user(&mut self) {} - - pub fn rm_user(&mut self) {} - - pub fn add_key(&mut self, user: String, k: Key, access: Access) {} - - pub fn get_key(&self, user: String, access: Access) -> &Key { - unimplemented!() - } -} diff --git a/lockchain-core/src/users/user.rs b/lockchain-core/src/users/user.rs new file mode 100644 index 0000000..1f7c9a5 --- /dev/null +++ b/lockchain-core/src/users/user.rs @@ -0,0 +1,80 @@ +//! User representation module + +use super::rights::{Access, Role}; +use crypto::{encoding, hashing, random}; +use std::collections::HashMap; +use traits::AutoEncoder; + +/// A generic user representation +/// +/// A user has an identify check built in +/// that can verify a passphrase +/// but is ultimately only a metadata item for a API layers. +/// Any layer is free to disregard these access rights +/// (as such, they should not be considered security, +/// only obscurity/ management control) +/// +/// A company might not want to allow non-admins +/// to create new vaults or users to delete records. +/// This does not cryptographically stop anyone +/// from breaking into the company server, +/// swapping the source code and +/// changing the rules! +/// +/// An user can have multiple role-access pairs. +/// +/// A user can be stored in a `UserStore`, +/// along-side authorised keys +#[derive(Serialize, Deserialize, Clone)] +pub struct User { + #[doc(hidden)] + pub name: String, + #[doc(hidden)] + pub pw_hash: String, + #[doc(hidden)] + pub rights: HashMap<Access, Role>, + #[doc(hidden)] + pub token: Option<String>, +} + +impl User { + /// Register a new user with a name and password + pub fn register(name: &str, pw: &str) -> Self { + Self { + name: name.into(), + pw_hash: encoding::base64_encode(&hashing::blake2(pw, name).to_vec()), + rights: HashMap::new(), + token: None, + } + } + /// Verify a user password input + pub fn verify(&self, pw: &str) -> bool { + self.pw_hash == encoding::base64_encode(&hashing::blake2(pw, &self.name).to_vec()) + } + /// Provides a hook to use second-factor authentication to authorise + /// + /// This is meant to be used with an external Yubikey + pub fn second_auth_verify(&mut self) -> bool { + unimplemented!() + } + /// Generate a token unique to this user (or return the existing one) + pub fn token(&mut self) -> String { + if self.token.is_none() { + self.token = Some(encoding::base64_encode(&random::bytes(256))); + } + + self.token.as_ref().unwrap().clone() + } + /// Verify that a user is allowed access to a piece of data + /// + /// `None` means "no access of any kind" + pub fn has_access(&self, item: Access) -> Option<Role> { + self.rights.get(&item).map(|i| i.clone()) + } + /// Modify access to an item for a role or create a new access entry + pub fn give_access(&mut self, item: Access, role: Role) { + self.rights.insert(item, role); + } +} + +impl AutoEncoder for User {} diff --git a/lockchain-core/src/users/userstore.rs b/lockchain-core/src/users/userstore.rs new file mode 100644 index 0000000..60fee0b --- /dev/null +++ b/lockchain-core/src/users/userstore.rs @@ -0,0 +1,54 @@ +use super::rights::Access; +use super::secrets::SecretType; +use crypto::Key; +use std::collections::HashMap; + +/// A thin user keystore +/// +/// It's implementation can manage multiple keys per user, of various +/// types and constrained for limited access rights. +pub struct KeyStore { + store: HashMap<String, StoreUser>, +} + +struct StoreUser { + name: String, + keys: HashMap<Access, Key>, +} + +impl KeyStore { + /// Create a new, empty keystore + /// + /// This is most likely *not* what you want. Instead, transform + /// a `MetaData` object into a keystore. + pub fn new() -> Self { + Self { + store: HashMap::new(), + } + } + /// Adds a new user to the store, with a root-key + pub fn add_user(&mut self, name: String, key: Key) { + let mut user = StoreUser { + name: name.clone(), + keys: HashMap::new(), + }; + user.keys.insert(Access::Root, key); + self.store.insert(name, user); + } + /// Delete a user from this store + pub fn del_user(&mut self, name: &str) { + self.store.remove(name); + } + /// Add a key to an existing user + pub fn add_key(&mut self, user: String, k: Key, access: Access) { + if !self.store.contains_key(&user) { + return; + } + + self.store.get_mut(&user).unwrap().keys.insert(access, k); + } + + pub fn get_key(&self, user: String, access: Access) -> Option<&Key> { + self.store.get(&user).map_or(None, |u| u.keys.get(&access)) + } +} |