Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of Xpra. 

2# Copyright (C) 2013-2020 Antoine Martin <antoine@xpra.org> 

3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

4# later version. See the file COPYING for details. 

5 

6import os.path 

7 

8from xpra.net.digest import get_salt, choose_digest 

9from xpra.os_util import strtobytes 

10from xpra.server.auth.sys_auth_base import SysAuthenticator 

11from xpra.log import Logger 

12 

13log = Logger("auth") 

14 

15 

16class FileAuthenticatorBase(SysAuthenticator): 

17 def __init__(self, username, **kwargs): 

18 password_file = kwargs.pop("filename", None) 

19 log("FileAuthenticatorBase password_file=%s", password_file) 

20 if not password_file: 

21 log.warn("Warning: %r authentication module is missing the 'filename' option", self) 

22 log.warn(" all authentication attempts will fail") 

23 elif not os.path.isabs(password_file): 

24 exec_cwd = kwargs.get("exec_cwd", os.getcwd()) 

25 password_file = os.path.join(exec_cwd, password_file) 

26 log("FileAuthenticatorBase filename=%s", password_file) 

27 super().__init__(username, **kwargs) 

28 self.password_filename = password_file 

29 self.password_filedata = None 

30 self.password_filetime = None 

31 self.authenticate_check = self.authenticate_hmac 

32 

33 def requires_challenge(self) -> bool: 

34 return True 

35 

36 def get_challenge(self, digests): 

37 if self.salt is not None: 

38 log.error("challenge already sent!") 

39 if self.salt is not False: 

40 self.salt = False 

41 return None 

42 self.salt = get_salt() 

43 self.digest = choose_digest(digests) 

44 self.challenge_sent = True 

45 return self.salt, self.digest 

46 

47 def get_password(self) -> str: 

48 file_data = self.load_password_file() 

49 if file_data is None: 

50 return None 

51 return strtobytes(file_data) 

52 

53 def parse_filedata(self, data): 

54 return data 

55 

56 def load_password_file(self) -> bytes: 

57 if not self.password_filename: 

58 return None 

59 full_path = os.path.abspath(self.password_filename) 

60 if not os.path.exists(self.password_filename): 

61 log.error("Error: password file '%s' is missing", full_path) 

62 self.password_filedata = None 

63 else: 

64 ptime = self.stat_password_filetime() 

65 if self.password_filedata is None or ptime!=self.password_filetime: 

66 self.password_filetime = None 

67 self.password_filedata = None 

68 try: 

69 with open(self.password_filename, mode='rb') as f: 

70 data = f.read() 

71 log("loaded %s bytes from '%s'", len(data), self.password_filename) 

72 self.password_filedata = self.parse_filedata(data) 

73 self.password_filetime = ptime 

74 except Exception as e: 

75 log.error("Error reading password data from '%s':", self.password_filename, exc_info=True) 

76 log.error(" %s", e) 

77 self.password_filedata = None 

78 return self.password_filedata 

79 

80 def stat_password_filetime(self) -> int: 

81 try: 

82 full_path = os.path.abspath(self.password_filename) 

83 v = os.stat(full_path).st_mtime 

84 log("mtime(%s)=%s", full_path, v) 

85 return v 

86 except Exception as e: 

87 log.error("Error accessing time of password file '%s'", full_path) 

88 log.error(" %s", e) 

89 return 0