Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/auth/file_auth_base.py : 100%
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.
6import os.path
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
13log = Logger("auth")
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
33 def requires_challenge(self) -> bool:
34 return True
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
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)
53 def parse_filedata(self, data):
54 return data
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
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