2
2
# pylint: disable=too-many-arguments,too-many-return-statements
3
3
# pylint: disable=too-many-branches, too-many-locals, too-many-statements
4
4
5
+ import base64
5
6
import errno
7
+ import hashlib
8
+ import hmac
6
9
import json
7
10
import logging
11
+ import os
8
12
import re
9
13
import threading
10
14
import time
11
15
from datetime import datetime , timedelta
12
16
from string import ascii_lowercase , ascii_uppercase , digits , punctuation
13
17
from typing import List , Optional , Sequence
14
18
15
- import bcrypt
16
19
from mgr_module import CLICheckNonemptyFileInput , CLIReadCommand , CLIWriteCommand
17
- from mgr_util import password_hash
18
20
19
21
from .. import mgr
20
22
from ..exceptions import PasswordPolicyException , PermissionNotValid , \
26
28
27
29
logger = logging .getLogger ('access_control' )
28
30
DEFAULT_FILE_DESC = 'password/secret'
29
-
31
+ SCRYPT_SALT_LEN = 29
30
32
31
33
_P = Permission # short alias
32
34
@@ -353,8 +355,17 @@ def enabled(self, value):
353
355
self ._enabled = value
354
356
self .refresh_last_update ()
355
357
358
+ @staticmethod
359
+ def calculate_password_hash (password : str , input_salt : Optional [str ] = None ) -> str :
360
+ if input_salt is None :
361
+ salt = os .urandom (SCRYPT_SALT_LEN )
362
+ else :
363
+ salt = base64 .b64decode (salt )[:SCRYPT_SALT_LEN ]
364
+ hash = hashlib .scrypt (password .encode ('utf8' ), salt = salt , n = 2 ** 14 , r = 8 , p = 1 )
365
+ return base64 .b64encode (salt + hash ).decode ('utf8' )
366
+
356
367
def set_password (self , password ):
357
- self .set_password_hash (password_hash (password ))
368
+ self .set_password_hash (self . calculate_password_hash (password ))
358
369
359
370
def set_password_hash (self , hashed_password ):
360
371
self .invalid_auth_attempt = 0
@@ -371,8 +382,8 @@ def compare_password(self, password):
371
382
:return: `True` if the passwords are equal, otherwise `False`.
372
383
:rtype: bool
373
384
"""
374
- pass_hash = password_hash (password , salt_password = self .password )
375
- return pass_hash == self .password
385
+ pass_hash = self . calculate_password_hash (password , salt_password = self .password )
386
+ return hmac . compare_digest ( pass_hash , self .password )
376
387
377
388
def is_pwd_expired (self ):
378
389
if self .pwd_expiration_date :
@@ -501,7 +512,7 @@ def create_user(self, username, password, name, email, enabled=True,
501
512
if pwd_expiration_date and \
502
513
(pwd_expiration_date < int (time .mktime (datetime .utcnow ().timetuple ()))):
503
514
raise PwdExpirationDateNotValid ()
504
- user = User (username , password_hash (password ), name , email , enabled = enabled ,
515
+ user = User (username , User . calculate_password_hash (password ), name , email , enabled = enabled ,
505
516
pwd_expiration_date = pwd_expiration_date ,
506
517
pwd_update_required = pwd_update_required )
507
518
self .users [username ] = user
@@ -906,27 +917,6 @@ def ac_user_set_password(_, username: str, inbuf: str,
906
917
return - errno .ENOENT , '' , str (ex )
907
918
908
919
909
- @CLIWriteCommand ('dashboard ac-user-set-password-hash' )
910
- @CLICheckNonemptyFileInput (desc = DEFAULT_FILE_DESC )
911
- def ac_user_set_password_hash (_ , username : str , inbuf : str ):
912
- '''
913
- Set user password bcrypt hash from -i <file>
914
- '''
915
- hashed_password = inbuf
916
- try :
917
- # make sure the hashed_password is actually a bcrypt hash
918
- bcrypt .checkpw (b'' , hashed_password .encode ('utf-8' ))
919
- user = mgr .ACCESS_CTRL_DB .get_user (username )
920
- user .set_password_hash (hashed_password )
921
-
922
- mgr .ACCESS_CTRL_DB .save ()
923
- return 0 , json .dumps (user .to_dict ()), ''
924
- except ValueError :
925
- return - errno .EINVAL , '' , 'Invalid password hash'
926
- except UserDoesNotExist as ex :
927
- return - errno .ENOENT , '' , str (ex )
928
-
929
-
930
920
@CLIWriteCommand ('dashboard ac-user-set-info' )
931
921
def ac_user_set_info (_ , username : str , name : str , email : str ):
932
922
'''
0 commit comments