Skip to content

Commit

Permalink
[identity] Support skip_password_reset in PrivilegedResetUserPassword…
Browse files Browse the repository at this point in the history
… RPC

Summary:
Server-side implementation of [[ https://linear.app/comm/issue/ENG-9628/plan-for-reverting-individual-users-to-v1-login#comment-2ef488a6 | ENG-9628 ]].

Depends on D14199

Test Plan:
Mocked privileged users set locally to include my user ID

- When the flag is false, the PrivilegedResetUserPassword RPC behaves as before
  - Password is reset
  - Returns user not found for wallet users
- When the flag is true
  - Works for both password and wallet users
  - Password is not updated
  - User is still logged out of all devices - device list is reset to unsigned

Reviewers: kamil, tomek

Reviewed By: kamil

Subscribers: ashoat

Differential Revision: https://phab.comm.dev/D14200
  • Loading branch information
barthap committed Jan 14, 2025
1 parent 2860bee commit 7fde3f6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 13 deletions.
44 changes: 31 additions & 13 deletions services/identity/src/grpc_services/authenticated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::device_list::validation::DeviceListValidator;
use crate::device_list::SignedDeviceList;
use crate::error::consume_error;
use crate::log::redact_sensitive_data;
use crate::token::AuthType;
use crate::{
client_service::{handle_db_error, WorkflowInProgress},
constants::{error_types, request_metadata, staff, tonic_status_messages},
Expand Down Expand Up @@ -731,25 +732,39 @@ impl IdentityClientService for AuthenticatedService {
&message.username
);

let user_id_and_password_file = self
.db_client
.get_user_info_and_password_file_from_username(&message.username)
.await?
.ok_or(tonic::Status::not_found(
tonic_status_messages::USER_NOT_FOUND,
))?;
let user_id = if !message.skip_password_reset {
// this returns USER_NOT_FOUND when user is not a password user
self
.db_client
.get_user_info_and_password_file_from_username(&message.username)
.await?
.ok_or(tonic::Status::not_found(
tonic_status_messages::USER_NOT_FOUND,
))?
.user_id
} else {
let username = message.username.clone();
let auth_type = AuthType::from_user_identifier(&username);
self
.db_client
.get_user_id_from_user_info(username, &auth_type)
.await?
.ok_or(tonic::Status::not_found(
tonic_status_messages::USER_NOT_FOUND,
))?
};

let server_registration = comm_opaque2::server::Registration::new();
let registration_response = server_registration
.start(
&CONFIG.server_setup,
&message.opaque_registration_request,
&message.username.to_lowercase().as_bytes(),
message.username.to_lowercase().as_bytes(),
)
.map_err(protocol_error_to_grpc_status)?;

let reset_state =
PrivilegedPasswordResetInfo::new(user_id_and_password_file.user_id);
PrivilegedPasswordResetInfo::new(user_id, message.skip_password_reset);
let session_id = self
.db_client
.insert_workflow(WorkflowInProgress::PrivilegedPasswordReset(Box::new(
Expand Down Expand Up @@ -791,10 +806,12 @@ impl IdentityClientService for AuthenticatedService {
.finish(&message.opaque_registration_upload)
.map_err(protocol_error_to_grpc_status)?;

self
.db_client
.update_user_password(state.user_id.clone(), password_file)
.await?;
if !state.skip_password_reset {
self
.db_client
.update_user_password(state.user_id.clone(), password_file)
.await?;
}

// Delete backups, blob holders and tunnelbroker device tokens.
// This has to be done before resetting device list.
Expand Down Expand Up @@ -1257,4 +1274,5 @@ pub struct UpdatePasswordInfo {
)]
pub struct PrivilegedPasswordResetInfo {
pub user_id: String,
pub skip_password_reset: bool,
}
11 changes: 11 additions & 0 deletions services/identity/src/token.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use chrono::{DateTime, Utc};
use comm_lib::crypto::siwe::is_valid_ethereum_address;
use rand::{
distributions::{Alphanumeric, DistString},
CryptoRng, Rng,
Expand All @@ -12,6 +13,16 @@ pub enum AuthType {
Wallet,
}

impl AuthType {
pub fn from_user_identifier(user_identifier: &str) -> Self {
if is_valid_ethereum_address(user_identifier) {
Self::Wallet
} else {
Self::Password
}
}
}

impl From<Identifier> for AuthType {
fn from(id: Identifier) -> Self {
match id {
Expand Down

0 comments on commit 7fde3f6

Please sign in to comment.