def do_check_peercred(self, connection, allow_uids=None, allow_gids=None): try: from xpra.net.bytestreams import SocketConnection if connection and isinstance(connection, SocketConnection): sock = connection._socket peercred = get_peercred(sock) log("get_peercred(%s)=%s", sock, peercred) if not peercred: log.warn("Warning: failed to get peer credentials on %s", sock) return _, uid, gid = peercred if allow_uids is not None and uid not in allow_uids: log.warn("Warning: peercred access denied,") log.warn(" uid %i is not in the whitelist: %s", uid, csv(allow_uids)) elif allow_gids is not None and gid not in allow_gids: log.warn("Warning: peercred access denied,") log.warn(" gid %i is not in the whitelist: %s", gid, csv(allow_gids)) else: self.peercred_check = True self.uid = uid self.gid = gid else: log( "peercred: invalid connection '%s' (not a socket connection)", connection) except Exception as e: log("peercred", exc_info=True) log.error("Error: cannot get peer uid") log.error(" %s", e)
def check(self, token) -> bool: log("check(%r)", token) assert self.challenge_sent try: if WIN32: import winkerberos as kerberos #@UnresolvedImport @UnusedImport else: import kerberos #@UnresolvedImport @Reimport except ImportError as e: log("check(..)", exc_info=True) log.warn("Warning: cannot use kerberos token authentication:") log.warn(" %s", e) return False v, ctx = kerberos.authGSSServerInit(self.service) if v != 1: log.error( "Error: kerberos GSS server init failed for service '%s'", self.service) return False try: r = kerberos.authGSSServerStep(ctx, token) log("kerberos auth server step result: %s", r == 1) if r != 1: return False targetname = kerberos.authGSSServerTargetName(ctx) #response = kerberos.authGSSServerResponse(ctx) principal = kerberos.authGSSServerUserName(ctx) #ie: user1@LOCALDOMAIN #maybe we should validate the realm? log("kerberos targetname=%s, principal=%s", targetname, principal) return True finally: kerberos.authGSSServerClean(ctx)
def get_challenge(self, digests): assert not self.challenge_sent if "kerberos" not in digests: log.error("Error: client does not support kerberos authentication") return None self.salt = get_salt() self.challenge_sent = True return self.salt, "kerberos:%s" % self.service
def get_challenge(self, digests): if "u2f" not in digests: log.error("Error: client does not support u2f authentication") return None self.salt = get_salt() self.digest = "u2f:xor" self.challenge_sent = True return self.salt, self.digest
def db_cursor(self, *sqlargs): if not os.path.exists(self.filename): log.error("Error: sqlauth cannot find the database file '%s'", self.filename) return None import sqlite3 db = sqlite3.connect(self.filename) db.row_factory = sqlite3.Row cursor = db.cursor() cursor.execute(*sqlargs) log("db_cursor(%s)=%s", sqlargs, cursor) return cursor
def check(self, password): log("check(%s)", obsc(password)) try: from ldap3 import Server, Connection, Tls, ALL, SIMPLE, SASL, NTLM #@UnresolvedImport except ImportError as e: log("check(..)", exc_info=True) log.warn("Warning: cannot use ldap3 authentication:") log.warn(" %s", e) return False try: MECHANISM = { "SIMPLE": SIMPLE, "SASL": SASL, "NTLM": NTLM, } authentication = MECHANISM[self.authentication] tls = None if self.tls: tls = Tls(validate=self.tls_validate, version=self.tls_version, ca_certs_file=self.cacert) log("TLS=%s", tls) server = Server(self.host, port=self.port, tls=tls, use_ssl=self.tls, get_info=ALL) log("ldap3 Server(%s)=%s", (self.host, self.port, self.tls), server) conn = Connection(server, user=self.username, password=password, authentication=authentication, receive_timeout=10) log("ldap3 Connection(%s, %s, %s)=%s", server, self.username, self.authentication, conn) if self.tls: conn.start_tls() r = conn.bind() log("ldap3 %s.bind()=%s", conn, r) if not r: return False if is_debug_enabled("auth"): log("ldap3 server info:") for l in server.info.splitlines(): log(" %s", l) log("ldap3 who_am_i()=%s", conn.extend.standard.who_am_i()) return True except Exception as e: log("ldap3 check(..)", exc_info=True) log.error("Error: ldap3 authentication failed:") log.error(" %s", e) return False
def check(self, password): token = HANDLE() domain = '' #os.environ.get('COMPUTERNAME') status = LogonUser(self.username, domain, password, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, byref(token)) error = GetLastError() if status: CloseHandle(token) return True log.error("Error: win32 authentication failed:") log.error(" %s", FormatError(error)) return False
def create(filename): if os.path.exists(filename): log.error("Error: database file '%s' already exists", filename) return 1 sql = ("CREATE TABLE users (" "username VARCHAR NOT NULL, " "password VARCHAR, " "uid VARCHAR, " "gid VARCHAR, " "displays VARCHAR, " "env_options VARCHAR, " "session_options VARCHAR)") return exec_database_sql_script(None, filename, sql)
def check(username, password): log("PAM check(%s, [..])", username) auth = PAM.pam() auth.start(PAM_SERVICE) auth.set_item(PAM.PAM_USER, username) conv = PAM_conv(password) auth.set_item(PAM.PAM_CONV, conv.pam_conv_password) try: auth.authenticate() return True #auth.acct_mgmt() except PAM.error, resp: log.error("PAM.authenticate() error: %s", resp) return False
def pam_conv_password(self, auth, query_list, *args): try: resp = [] for i in range(len(query_list)): query, pam_type = query_list[i] if pam_type == PAM.PAM_PROMPT_ECHO_ON or pam_type == PAM.PAM_PROMPT_ECHO_OFF: resp.append((self.password, 0)) elif pam_type == PAM_PROMPT_ERROR_MSG or pam_type == PAM_PROMPT_TEXT_INFO: log("pam_conf_password: ERROR/INFO: '%s'", query) resp.append(('', 0)) else: log.error("pam_conf_password unknown type: '%s'", pam_type) except Exception, e: log.error("pam_conv_password error: %s", e)
def pam_conv_password(self, auth, query_list, *args): try: resp = [] for i in range(len(query_list)): query, pam_type = query_list[i] if pam_type == PAM.PAM_PROMPT_ECHO_ON or pam_type == PAM.PAM_PROMPT_ECHO_OFF: resp.append((self.password, 0)) elif pam_type == PAM.PAM_PROMPT_ERROR_MSG or pam_type == PAM.PAM_PROMPT_TEXT_INFO: log("pam_conf_password: ERROR/INFO: '%s'", query) resp.append(('', 0)) else: log.error("pam_conf_password unknown type: '%s'", pam_type) except Exception, e: log.error("pam_conv_password error: %s", e)
def get_sessions(self): import sqlite3 try: conn = sqlite3.connect(self.filename) conn.row_factory = sqlite3.Row cursor = conn.cursor() cursor.execute(self.sessions_query, [self.username, self.password_used or ""]) data = cursor.fetchone() except sqlite3.DatabaseError as e: log("get_sessions()", exc_info=True) log.error("Error: sqlauth database access problem:") log.error(" %s", e) return None try: uid = parse_uid(data["uid"]) gid = parse_gid(data["gid"]) displays = [] env_options = {} session_options = {} if data["displays"]: displays = [x.strip() for x in str(data[2]).split(",")] if data["env_options"]: env_options = parse_simple_dict(str(data[3]), ";") if data["session_options"]: session_options = parse_simple_dict(str(data[4]), ";") except Exception as e: log("get_sessions() error on row %s", data, exc_info=True) log.error("Error: sqlauth database row parsing problem:") log.error(" %s", e) return None return uid, gid, displays, env_options, session_options
def exec_database_sql_script(cursor_cb, filename, *sqlargs): log("exec_database_sql_script%s", (cursor_cb, filename, sqlargs)) try: conn = sqlite3.connect(filename) cursor = conn.cursor() cursor.execute(*sqlargs) if cursor_cb: cursor_cb(cursor) conn.commit() conn.close() return 0 except sqlite3.DatabaseError as e: log.error("Error: database access problem:") log.error(" %s", e) return 1
def check(self, password): token = HANDLE() domain = '' #os.environ.get('COMPUTERNAME') password_str = bytestostr(password) if LOG_CREDENTIALS: log("LogonUser(%s, %s, %s, CLEARTEXT, DEFAULT, %#x)", self.username, domain, password_str, addressof(token)) status = LogonUser(self.username, domain, password_str, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, byref(token)) log("LogonUser(..)=%#x", status) if status: CloseHandle(token) return True log.error("Error: win32 authentication failed:") log.error(" %s", FormatError(GetLastError())) return False
def check(self, password): try: if WIN32: import winkerberos as kerberos #@UnresolvedImport @UnusedImport else: import kerberos #@UnresolvedImport @Reimport except ImportError as e: log("check(..)", exc_info=True) log.warn("Warning: cannot use kerberos password authentication:") log.warn(" %s", e) return False try: kerberos.checkPassword(self.username, password, self.service, self.realm) return True except kerberos.KrbError as e: log("check(..)", exc_info=True) log.error("Error: kerberos authentication failed:") log.error(" %s", e) return False
def parse_session_data(self, data): try: uid = data[0] gid = data[1] displays = [] env_options = {} session_options = {} if len(data)>2: displays = [x.strip() for x in str(data[2]).split(",")] if len(data)>3: env_options = parse_simple_dict(str(data[3]), ";") if len(data)>4: session_options = parse_simple_dict(str(data[4]), ";") except Exception as e: log("parse_session_data() error on row %s", data, exc_info=True) log.error("Error: sqlauth database row parsing problem:") log.error(" %s", e) return None return uid, gid, displays, env_options, session_options
def parse_session_data(self, data): try: uid = parse_uid(data["uid"]) gid = parse_gid(data["gid"]) displays = [] env_options = {} session_options = {} if data["displays"]: displays = [x.strip() for x in str(data["displays"]).split(",")] if data["env_options"]: env_options = parse_simple_dict(str(data["env_options"]), ";") if data["session_options"]: session_options=parse_simple_dict(str(data["session_options"]), ";") except Exception as e: log("get_sessions() error on row %s", data, exc_info=True) log.error("Error: sqlauth database row parsing problem:") log.error(" %s", e) return None return uid, gid, displays, env_options, session_options
def __init__(self, username, **kwargs): log("hosts.Authenticator(%s, %s)", username, kwargs) if not POSIX: log.warn("Warning: hosts authentication is not supported on %s", os.name) return connection = kwargs.get("connection", None) try: from xpra.net.bytestreams import SocketConnection if not connection and isinstance(connection, SocketConnection): raise Exception("hosts: invalid connection '%s' (not a socket connection)" % connection) info = connection.get_info() log("hosts.Authenticator(..) connection info=%s", info) host = info.get("remote")[0] peername = info.get("endpoint")[0] except Exception as e: log.error("Error: cannot get host from connection") log.error(" %s", e) raise self.peername = peername self.host = host super().__init__(username, **kwargs)
def main(argv): from xpra.platform import program_context from xpra.log import enable_color with program_context("Auth-Test", "Auth-Test"): enable_color() for x in ("-v", "--verbose"): if x in tuple(argv): log.enable_debug() argv.remove(x) if len(argv) != 3: log.warn("invalid number of arguments") log.warn("usage: %s [--verbose] username password", argv[0]) return 1 username = argv[1] password = argv[2] a = Authenticator(username=username) if a.check(password): log.info("authentication succeeded") return 0 log.error("authentication failed") return 1
def authenticate_check(self, challenge_response: str, client_salt: str = None) -> bool: log("authenticate_check(%s, %s)", repr(challenge_response), repr(client_salt)) user_presence, counter = struct.unpack( b">BI", strtobytes(challenge_response)[:5]) sig = strtobytes(challenge_response[5:]) log("u2f user_presence=%s, counter=%s, signature=%s", user_presence, counter, hexstr(sig)) app_param = sha256(self.app_id.encode('utf8')).digest() server_challenge_b64 = base64.urlsafe_b64encode(self.salt).decode() server_challenge_b64 = server_challenge_b64.rstrip('=') log("challenge_b64(%s)=%s", repr(self.salt), server_challenge_b64) client_data = { "challenge": server_challenge_b64, "origin": client_salt, "typ": "navigator.id.getAssertion", } client_param = sha256( json.dumps(client_data, sort_keys=True).encode('utf8')).digest() param = app_param + \ struct.pack(b'>B', user_presence) + \ struct.pack(b'>I', counter) + \ client_param #check all the public keys: #pylint: disable=import-outside-toplevel from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec errors = {} for origin, public_key in self.public_keys.items(): verifier = public_key.verifier(sig, ec.ECDSA(hashes.SHA256())) verifier.update(param) try: verifier.verify() log("ECDSA SHA256 verification passed for '%s'", origin) return True except Exception as e: log("authenticate failed for '%s' / %s", origin, public_key, exc_info=True) errors[origin] = str(e) or type(e) log.error("Error: authentication failed,") log.error(" checked against %i key%s", len(self.public_keys), engs(self.public_keys)) for origin, error in errors.items(): log.error(" '%s': %s", origin, error) return False
def get_password(self): if not os.path.exists(self.filename): log.error("Error: sqlauth cannot find the database file '%s'", self.filename) return None log("sqlauth.get_password() found database file '%s'", self.filename) try: conn = sqlite3.connect(self.filename) cursor = conn.cursor() cursor.execute(self.password_query, [self.username]) data = cursor.fetchone() except sqlite3.DatabaseError as e: log("get_password()", exc_info=True) log.error("Error: sqlauth database access problem:") log.error(" %s", e) return None if not data: log.info("username '%s' not found in sqlauth database", self.username) return None return str(data[0])
def __init__(self, username, **kwargs): log("peercred.Authenticator(%s, %s)", username, kwargs) if not POSIX: log.warn("Warning: peercred authentication is not supported on %s", os.name) return self.uid = -1 self.gid = -1 self.peercred_check = False connection = kwargs.get("connection", None) uids = kwargs.pop("uid", None) gids = kwargs.pop("gid", None) allow_uids = None allow_gids = None if uids: allow_uids = [] for x in uids.split(","): x = osexpand(x.strip()) try: allow_uids.append(int(x)) except ValueError: import pwd try: pw = pwd.getpwnam(x) uids.append(pw.pw_uid) except KeyError: log.warn("Warning: unknown username '%s'", x) log("peercred: allow_uids(%s)=%s", uids, allow_uids) if gids: allow_gids = [] for x in gids.split(","): x = osexpand(x.strip()) try: allow_gids.append(int(x)) except ValueError: gid = get_group_id(x) if gid >= 0: allow_gids.append(gid) else: log.warn("Warning: unknown group '%s'", x) log("peercred: allow_gids(%s)=%s", gids, allow_gids) try: from xpra.net.bytestreams import SocketConnection if connection and isinstance(connection, SocketConnection): sock = connection._socket peercred = get_peercred(sock) log("get_peercred(%s)=%s", sock, peercred) if not peercred: log.warn("Warning: failed to get peer credentials on %s", sock) return _, uid, gid = peercred if allow_uids is not None and uid not in allow_uids: log.warn("Warning: peercred access denied,") log.warn(" uid %i is not in the whitelist: %s", uid, csv(allow_uids)) elif allow_gids is not None and gid not in allow_gids: log.warn("Warning: peercred access denied,") log.warn(" gid %i is not in the whitelist: %s", gid, csv(allow_gids)) else: self.peercred_check = True self.uid = uid self.gid = gid else: log( "peercred: invalid connection '%s' (not a socket connection)", connection) except Exception as e: log.error("Error: cannot get peer uid") log.error(" %s", e) SysAuthenticator.__init__(self, username, **kwargs)
def get_challenge(self, digests): if "xor" not in digests: log.error("Error: ldap authentication requires the 'xor' digest") return None return SysAuthenticatorBase.get_challenge(self, ["xor"])
def check(username, password): log("PAM check(%s, [..])", username) auth = PAM.pam() auth.start(PAM_SERVICE) auth.set_item(PAM.PAM_USER, username) conv = PAM_conv(password) auth.set_item(PAM.PAM_CONV, conv.pam_conv_password) try: auth.authenticate() return True #auth.acct_mgmt() except PAM.error, resp: log.error("PAM.authenticate() error: %s", resp) return False except Exception, e: log.error("PAM.authenticate() internal error: %s", e) return False except Exception, e: log("PAM module not available: %s", e) try: from xpra.server.auth import pam assert pam def check(username, password): log("pam check(%s, [..])", username) return pam.authenticate(username, password) except: log("pam module not available: %s", e) if check is None:
def get_challenge(self, digests): if "xor" not in digests: log.error("Error: pam authentication requires the 'xor' digest") return None return super().get_challenge(["xor"])