Coverage for gws-app/gws/plugin/auth_provider/file/__init__.py: 0%

57 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-17 01:37 +0200

1"""Provider for the file-based authorization. 

2 

3This provider works with a local JSON file, which is expected to contain 

4a list of user "records" (dicts). 

5 

6A record is required to contain fields ``login`` and ``password`` (hashed as per `gws.lib.password.encode`). 

7 

8Other fields, if given, are converted to respective `gws.User` properties. 

9""" 

10 

11import getpass 

12 

13import gws 

14import gws.base.auth 

15import gws.lib.jsonx 

16import gws.lib.password 

17 

18gws.ext.new.authProvider('file') 

19 

20 

21class Config(gws.base.auth.provider.Config): 

22 """File-based authorization provider""" 

23 

24 path: gws.FilePath 

25 """path to the users json file""" 

26 

27 

28class Object(gws.base.auth.provider.Object): 

29 path: str 

30 db: list[dict] 

31 

32 def configure(self): 

33 self.path = self.cfg('path') 

34 self.db = gws.lib.jsonx.from_path(self.path) 

35 

36 def authenticate(self, method, credentials): 

37 wrong_password = 0 

38 found = [] 

39 

40 username = credentials.get('username') 

41 password = credentials.get('password') 

42 if not username or not password: 

43 return 

44 

45 for rec in self.db: 

46 login_ok = gws.lib.password.compare(username, rec['login']) 

47 password_ok = gws.lib.password.check(password, rec['password']) 

48 if login_ok and password_ok: 

49 found.append(rec) 

50 if login_ok and not password_ok: 

51 wrong_password += 1 

52 

53 if wrong_password: 

54 raise gws.ForbiddenError(f'wrong password for {username!r}') 

55 

56 if len(found) > 1: 

57 raise gws.ForbiddenError(f'multiple entries for {username!r}') 

58 

59 if len(found) == 1: 

60 return self._make_user(found[0]) 

61 

62 def get_user(self, local_uid): 

63 for rec in self.db: 

64 if rec['login'] == local_uid: 

65 return self._make_user(rec) 

66 

67 def _make_user(self, rec: dict): 

68 user_rec = dict(rec) 

69 

70 login = user_rec.pop('login', '') 

71 user_rec['localUid'] = user_rec['loginName'] = login 

72 user_rec['displayName'] = user_rec.pop('name', login) 

73 user_rec.pop('password', '') 

74 

75 return gws.base.auth.user.from_record(self, user_rec) 

76 

77 @gws.ext.command.cli('authPassword') 

78 def passwd(self, p: gws.EmptyRequest): 

79 """Encode a password for the authorization file""" 

80 

81 while True: 

82 p1 = getpass.getpass('Password: ') 

83 p2 = getpass.getpass('Repeat : ') 

84 

85 if p1 != p2: 

86 print('passwords do not match') 

87 continue 

88 

89 p = gws.lib.password.encode(p1) 

90 print(p) 

91 break