Skip to content

Commit 873f843

Browse files
authored
Add reset password api (#474)
Also changes the create user api to POST instead of PUT
1 parent ee98b42 commit 873f843

File tree

2 files changed

+54
-46
lines changed

2 files changed

+54
-46
lines changed

server/src/handlers/http.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
195195
.service(
196196
web::resource("/{username}")
197197
// PUT /user/{username} => Create a new user
198-
.route(web::put().to(rbac::put_user).authorize(Action::PutUser))
198+
.route(web::post().to(rbac::post_user).authorize(Action::PutUser))
199199
// DELETE /user/{username} => Delete a user
200200
.route(
201201
web::delete()
@@ -218,6 +218,16 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
218218
.to(rbac::get_role)
219219
.authorize_for_user(Action::GetRole),
220220
),
221+
)
222+
.service(
223+
web::resource("/{username}/generate-new-password")
224+
// POST /user/{username}/generate-new-password => reset password for this user
225+
.route(
226+
web::post()
227+
.to(rbac::post_gen_password)
228+
.authorize(Action::PutUser)
229+
.wrap(DisAllowRootUser),
230+
),
221231
);
222232
// Deny request if username is same as the env variable P_USERNAME.
223233
cfg.service(

server/src/handlers/http/rbac.rs

Lines changed: 43 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,59 @@ pub async fn list_users() -> impl Responder {
4141
web::Json(Users.list_users())
4242
}
4343

44-
// Handler for PUT /api/v1/user/{username}
44+
// Handler for POST /api/v1/user/{username}
4545
// Creates a new user by username if it does not exists
46-
// Otherwise make a call to reset password
47-
// returns password generated for this user
48-
pub async fn put_user(
46+
pub async fn post_user(
4947
username: web::Path<String>,
5048
body: Option<web::Json<serde_json::Value>>,
5149
) -> Result<impl Responder, RBACError> {
5250
let username = username.into_inner();
5351
validator::user_name(&username)?;
5452
let _ = UPDATE_LOCK.lock().await;
5553
if Users.contains(&username) {
56-
reset_password(username).await
57-
} else {
58-
let mut metadata = get_metadata().await?;
59-
if metadata.users.iter().any(|user| user.username == username) {
60-
// should be unreachable given state is always consistent
61-
return Err(RBACError::UserExists);
62-
}
63-
let (user, password) = User::create_new(username.clone());
64-
metadata.users.push(user.clone());
65-
put_metadata(&metadata).await?;
66-
// set this user to user map
67-
Users.put_user(user);
68-
69-
if let Some(body) = body {
70-
put_role(web::Path::<String>::from(username), body).await?;
71-
}
54+
return Err(RBACError::UserExists);
55+
}
56+
let mut metadata = get_metadata().await?;
57+
if metadata.users.iter().any(|user| user.username == username) {
58+
// should be unreachable given state is always consistent
59+
return Err(RBACError::UserExists);
60+
}
61+
let (user, password) = User::create_new(username.clone());
62+
metadata.users.push(user.clone());
63+
put_metadata(&metadata).await?;
64+
// set this user to user map
65+
Users.put_user(user);
66+
67+
if let Some(body) = body {
68+
put_role(web::Path::<String>::from(username), body).await?;
69+
}
70+
71+
Ok(password)
72+
}
7273

73-
Ok(password)
74+
// Handler for POST /api/v1/user/{username}/generate-new-password
75+
// Resets password for the user to a newly generated one and returns it
76+
pub async fn post_gen_password(username: web::Path<String>) -> Result<impl Responder, RBACError> {
77+
let username = username.into_inner();
78+
let _ = UPDATE_LOCK.lock().await;
79+
if !Users.contains(&username) {
80+
return Err(RBACError::UserDoesNotExist);
81+
}
82+
let PassCode { password, hash } = User::gen_new_password();
83+
let mut metadata = get_metadata().await?;
84+
if let Some(user) = metadata
85+
.users
86+
.iter_mut()
87+
.find(|user| user.username == username)
88+
{
89+
user.password_hash.clone_from(&hash);
90+
} else {
91+
// should be unreachable given state is always consistent
92+
return Err(RBACError::UserDoesNotExist);
7493
}
94+
put_metadata(&metadata).await?;
95+
Users.change_password_hash(&username, &hash);
96+
Ok(password)
7597
}
7698

7799
// Handler for GET /api/v1/user/{username}/role
@@ -101,30 +123,6 @@ pub async fn delete_user(username: web::Path<String>) -> Result<impl Responder,
101123
Ok(format!("deleted user: {username}"))
102124
}
103125

104-
// Reset password for given username
105-
// returns new password generated for this user
106-
pub async fn reset_password(username: String) -> Result<String, RBACError> {
107-
// generate new password for this user
108-
let PassCode { password, hash } = User::gen_new_password();
109-
// update parseable.json first
110-
let mut metadata = get_metadata().await?;
111-
if let Some(user) = metadata
112-
.users
113-
.iter_mut()
114-
.find(|user| user.username == username)
115-
{
116-
user.password_hash.clone_from(&hash);
117-
} else {
118-
// should be unreachable given state is always consistent
119-
return Err(RBACError::UserDoesNotExist);
120-
}
121-
put_metadata(&metadata).await?;
122-
123-
// update in mem table
124-
Users.change_password_hash(&username, &hash);
125-
Ok(password)
126-
}
127-
128126
// Put roles for given user
129127
pub async fn put_role(
130128
username: web::Path<String>,

0 commit comments

Comments
 (0)