@@ -8,11 +8,13 @@ use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
8
8
#[ cfg( test) ]
9
9
use mockall:: automock;
10
10
use pbkdf2:: password_hash:: rand_core:: OsRng ;
11
+ use rand:: seq:: IteratorRandom ;
11
12
use serde_derive:: Deserialize ;
12
13
use tracing:: { debug, info} ;
13
14
14
15
use super :: authentication:: DbUserAuthenticationRepository ;
15
16
use super :: authorization:: { self , ACTION } ;
17
+ use crate :: config:: v2:: auth:: Auth ;
16
18
use crate :: config:: { Configuration , PasswordConstraints } ;
17
19
use crate :: databases:: database:: { Database , Error } ;
18
20
use crate :: errors:: ServiceError ;
@@ -405,6 +407,44 @@ impl ListingService {
405
407
}
406
408
}
407
409
410
+ pub struct AdminActionsService {
411
+ authorization_service : Arc < authorization:: Service > ,
412
+ user_authentication_repository : Arc < DbUserAuthenticationRepository > ,
413
+ }
414
+
415
+ impl AdminActionsService {
416
+ /// Resets the password of the selected user.
417
+ ///
418
+ /// # Errors
419
+ ///
420
+ /// This function will return a:
421
+ ///
422
+ /// * `ServiceError::InvalidPassword` if the current password supplied is invalid.
423
+ /// * `ServiceError::PasswordsDontMatch` if the supplied passwords do not match.
424
+ /// * `ServiceError::PasswordTooShort` if the supplied password is too short.
425
+ /// * `ServiceError::PasswordTooLong` if the supplied password is too long.
426
+ /// * An error if unable to successfully hash the password.
427
+ /// * An error if unable to change the password in the database.
428
+ /// * An error if it is not possible to authorize the action
429
+ pub async fn reset_user_password ( & self , maybe_user_id : Option < UserId > , user_info : UserProfile ) -> Result < ( ) , ServiceError > {
430
+ self . authorization_service
431
+ . authorize ( ACTION :: ResetUserPassword , maybe_user_id)
432
+ . await ?;
433
+
434
+ info ! ( "Resetting user password for user ID: {}" , user_info. username) ;
435
+
436
+ let new_password = generate_random_password ( ) ;
437
+
438
+ let password_hash = hash_password ( & new_password) ?;
439
+
440
+ self . user_authentication_repository
441
+ . change_password ( user_info. user_id , & password_hash)
442
+ . await ?;
443
+
444
+ Ok ( ( ) )
445
+ }
446
+ }
447
+
408
448
#[ cfg_attr( test, automock) ]
409
449
#[ async_trait]
410
450
pub trait Repository : Sync + Send {
@@ -578,3 +618,23 @@ fn hash_password(password: &str) -> Result<String, ServiceError> {
578
618
579
619
Ok ( password_hash)
580
620
}
621
+
622
+ //Generates a random password with numbers, letters and special characters with a length of the max length allow for users's passwords
623
+ fn generate_random_password ( ) -> String {
624
+ let charset = "2A&,B;C8D!G?HIJ@KL5MN1OPQ#RST]U`VW*XYZ\
625
+ {ab)c~d$ef=g.h<i_jklmn%op>qr/st6u+vw}xyz\
626
+ |0-EF3^4[7(:9\
627
+ ";
628
+
629
+ let mut rng = rand:: thread_rng ( ) ;
630
+
631
+ let password_constraints = Auth :: default ( ) . password_constraints ;
632
+
633
+ let password_length = password_constraints. max_password_length ;
634
+
635
+ let password: String = ( 0 ..password_length)
636
+ . map ( |_| charset. chars ( ) . choose ( & mut rng) . unwrap ( ) )
637
+ . collect ( ) ;
638
+
639
+ password
640
+ }
0 commit comments