Skip to content

Commit 0626261

Browse files
authored
Minor refactor in user flow and add comments (#416)
1 parent 0ad011b commit 0626261

File tree

5 files changed

+32
-20
lines changed

5 files changed

+32
-20
lines changed

server/src/handlers/http.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use rustls::{Certificate, PrivateKey, ServerConfig};
3131
use rustls_pemfile::{certs, pkcs8_private_keys};
3232

3333
use crate::option::CONFIG;
34-
use crate::rbac::get_user_map;
34+
use crate::rbac::user_map;
3535

3636
mod health_check;
3737
mod ingest;
@@ -62,14 +62,14 @@ macro_rules! create_app {
6262
};
6363
}
6464

65-
async fn validator(
65+
async fn authenticate(
6666
req: ServiceRequest,
6767
credentials: BasicAuth,
6868
) -> Result<ServiceRequest, (actix_web::Error, ServiceRequest)> {
6969
let username = credentials.user_id().trim();
7070
let password = credentials.password().unwrap().trim();
7171

72-
if let Some(user) = get_user_map().read().unwrap().get(username) {
72+
if let Some(user) = user_map().read().unwrap().get(username) {
7373
if user.verify(password) {
7474
return Ok(req);
7575
}
@@ -130,6 +130,7 @@ pub async fn run_http(prometheus: PrometheusMetrics) -> anyhow::Result<()> {
130130
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
131131
let generated = generate();
132132

133+
//log stream API
133134
let logstream_api = web::scope("/{logstream}")
134135
.service(
135136
web::resource("")
@@ -163,14 +164,19 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
163164
// GET "/logstream/{logstream}/retention" ==> Get retention for given logstream
164165
.route(web::get().to(logstream::get_retention)),
165166
);
167+
168+
// User API
166169
let user_api = web::scope("/user").service(
167170
web::resource("/{username}")
168171
// POST /user/{username} => Create a new user
169172
.route(web::put().to(rbac::put_user))
170173
// DELETE /user/{username} => Delete a user
171174
.route(web::delete().to(rbac::delete_user))
172175
.wrap_fn(|req, srv| {
173-
// deny request if username is same as username from config
176+
// The credentials set in the env vars (P_USERNAME & P_PASSWORD) are treated
177+
// as root credentials. Any other user is not allowed to modify or delete
178+
// the root user. Deny request if username is same as username
179+
// from env variable P_USERNAME.
174180
let username = req.match_info().get("username").unwrap_or("");
175181
let is_root = username == CONFIG.parseable.username;
176182
let call = srv.call(req);
@@ -210,7 +216,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
210216
),
211217
)
212218
.service(user_api)
213-
.wrap(HttpAuthentication::basic(validator)),
219+
.wrap(HttpAuthentication::basic(authenticate)),
214220
)
215221
// GET "/" ==> Serve the static frontend directory
216222
.service(ResourceFiles::new("/", generated));

server/src/handlers/http/rbac.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
use crate::{
2020
option::CONFIG,
2121
rbac::{
22-
get_user_map,
2322
user::{PassCode, User},
23+
user_map,
2424
},
2525
storage::{self, ObjectStorageError, StorageMetadata},
2626
validator::{self, error::UsernameValidationError},
@@ -38,9 +38,9 @@ static UPDATE_LOCK: Mutex<()> = Mutex::const_new(());
3838
// returns password generated for this user
3939
pub async fn put_user(username: web::Path<String>) -> Result<impl Responder, RBACError> {
4040
let username = username.into_inner();
41-
validator::verify_username(&username)?;
41+
validator::user_name(&username)?;
4242
let _ = UPDATE_LOCK.lock().await;
43-
let user_exists = get_user_map().read().unwrap().contains_key(&username);
43+
let user_exists = user_map().read().unwrap().contains_key(&username);
4444
if user_exists {
4545
reset_password(username).await
4646
} else {
@@ -54,7 +54,7 @@ pub async fn put_user(username: web::Path<String>) -> Result<impl Responder, RBA
5454
metadata.users.push(user.clone());
5555
put_metadata(&metadata).await?;
5656
// set this user to user map
57-
get_user_map().write().unwrap().insert(user);
57+
user_map().write().unwrap().insert(user);
5858

5959
Ok(password)
6060
}
@@ -65,16 +65,16 @@ pub async fn delete_user(username: web::Path<String>) -> Result<impl Responder,
6565
let username = username.into_inner();
6666
let _ = UPDATE_LOCK.lock().await;
6767
// fail this request if the user does not exists
68-
if !get_user_map().read().unwrap().contains_key(&username) {
68+
if !user_map().read().unwrap().contains_key(&username) {
6969
return Err(RBACError::UserDoesNotExist);
7070
};
7171
// delete from parseable.json first
7272
let mut metadata = get_metadata().await?;
7373
metadata.users.retain(|user| user.username != username);
7474
put_metadata(&metadata).await?;
7575
// update in mem table
76-
get_user_map().write().unwrap().remove(&username);
77-
Ok(format!("deleted user: {}", username))
76+
user_map().write().unwrap().remove(&username);
77+
Ok(format!("deleted user: {username}"))
7878
}
7979

8080
// Reset password for given username
@@ -97,7 +97,7 @@ pub async fn reset_password(username: String) -> Result<String, RBACError> {
9797
put_metadata(&metadata).await?;
9898

9999
// update in mem table
100-
get_user_map()
100+
user_map()
101101
.write()
102102
.unwrap()
103103
.get_mut(&username)

server/src/rbac.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub mod user;
2626

2727
pub static USERS: OnceCell<RwLock<UserMap>> = OnceCell::new();
2828

29-
pub fn get_user_map() -> &'static RwLock<UserMap> {
29+
pub fn user_map() -> &'static RwLock<UserMap> {
3030
USERS.get().expect("user map is set")
3131
}
3232

server/src/rbac/user.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ impl User {
4949
)
5050
}
5151

52-
// Verification works because the PasswordHash is in PHC format
53-
// $<id>[$v=<version>][$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
52+
// Take the password and compare with the hash stored internally (PHC format ==>
53+
// $<id>[$v=<version>][$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]])
5454
// ref https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md#specification
5555
pub fn verify(&self, password: &str) -> bool {
5656
let parsed_hash = PasswordHash::new(&self.password_hash).unwrap();
@@ -59,14 +59,16 @@ impl User {
5959
.is_ok()
6060
}
6161

62-
// gen new password
62+
// generate a new password
6363
pub fn gen_new_password() -> PassCode {
6464
let password = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);
6565
let hash = gen_hash(&password);
6666
PassCode { password, hash }
6767
}
6868
}
6969

70+
// generate a one way hash for password to be stored in metadata file
71+
// ref https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
7072
fn gen_hash(password: &str) -> String {
7173
let salt = SaltString::generate(&mut OsRng);
7274
let argon2 = Argon2::default();

server/src/validator.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ pub fn stream_name(stream_name: &str) -> Result<(), StreamNameValidationError> {
114114
Ok(())
115115
}
116116

117-
pub fn verify_username(username: &str) -> Result<(), UsernameValidationError> {
117+
// validate if username is valid
118+
// username should be between 3 and 64 characters long
119+
// username should contain only alphanumeric characters or underscores
120+
// username should be lowercase
121+
pub fn user_name(username: &str) -> Result<(), UsernameValidationError> {
118122
// Check if the username meets the required criteria
119123
if username.len() < 3 || username.len() > 64 {
120124
return Err(UsernameValidationError::InvalidLength);
@@ -254,10 +258,10 @@ pub mod error {
254258

255259
#[derive(Debug, thiserror::Error)]
256260
pub enum UsernameValidationError {
257-
#[error("Username length should be between 3 and 64 chars")]
261+
#[error("Username should be between 3 and 64 chars long")]
258262
InvalidLength,
259263
#[error(
260-
"Username contains invalid characters. Only lowercase aplhanumeric and _ is allowed"
264+
"Username contains invalid characters. Please use lowercase, alphanumeric or underscore"
261265
)]
262266
SpecialChar,
263267
}

0 commit comments

Comments
 (0)