-
-
Notifications
You must be signed in to change notification settings - Fork 173
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#1796: modularize client authentication handlers
git-svn-id: https://xpra.org/svn/Xpra/trunk@22711 3bb7dfac-3a0b-4e04-842a-767bc560f471
- Loading branch information
Showing
11 changed files
with
394 additions
and
225 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
import os | ||
|
||
|
||
class Handler(object): | ||
|
||
def __init__(self, client, **kwargs): | ||
self.client = client | ||
self.var_name = kwargs.pop("name", "XPRA_PASSWORD") | ||
|
||
def __repr__(self): | ||
return "env" | ||
|
||
def get_digest(self): | ||
return None | ||
|
||
def handle(self, packet): | ||
password = os.environ.get(self.var_name) | ||
if not password: | ||
return False | ||
self.client.send_challenge_reply(packet, password) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
import os | ||
|
||
from xpra.os_util import load_binary_file | ||
|
||
|
||
class Handler(object): | ||
|
||
def __init__(self, client, **kwargs): | ||
self.client = client | ||
self.password_file = kwargs.get("filename", None) | ||
if not self.password_file and client.password_file: | ||
self.password_file = client.password_file[0] | ||
client.password_file = client.password_file[1:] | ||
|
||
def __repr__(self): | ||
return "file" | ||
|
||
def get_digest(self): | ||
return None | ||
|
||
def handle(self, packet): | ||
if not self.password_file: | ||
return False | ||
filename = os.path.expanduser(self.password_file) | ||
data = load_binary_file(filename) | ||
if not data: | ||
return False | ||
self.client.send_challenge_reply(packet, data) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
import os | ||
|
||
from xpra.util import csv | ||
from xpra.os_util import bytestostr, OSX | ||
from xpra.log import Logger | ||
|
||
log = Logger("auth") | ||
|
||
|
||
class Handler(object): | ||
|
||
def __init__(self, client, **_kwargs): | ||
self.client = client | ||
self.services = os.environ.get("XPRA_GSS_SERVICES", "*").split(",") | ||
import gssapi #@UnresolvedImport | ||
self.gssapi = gssapi | ||
if OSX and False: | ||
from gssapi.raw import (cython_converters, cython_types, oids) # @UnresolvedImport | ||
assert cython_converters and cython_types and oids | ||
|
||
def __repr__(self): | ||
return "gss" | ||
|
||
def get_digest(self): | ||
return "gss" | ||
|
||
def handle(self, packet): | ||
digest = bytestostr(packet[3]) | ||
if not digest.startswith("gss:"): | ||
#not a gss challenge | ||
log("%s is not a gss challenge", digest) | ||
return False | ||
service = bytestostr(digest.split(b":", 1)[1]) | ||
if service not in self.services and "*" not in self.services: | ||
log.warn("Warning: invalid GSS request for service '%s'", service) | ||
log.warn(" services supported: %s", csv(self.services)) | ||
return False | ||
log("gss service=%s", service) | ||
service_name = self.gssapi.Name(service) | ||
try: | ||
ctx = self.gssapi.SecurityContext(name=service_name, usage="initiate") | ||
token = ctx.step() | ||
except Exception as e: | ||
log("gssapi failure", exc_info=True) | ||
log.error("Error: gssapi client authentication failure:") | ||
try: | ||
for x in str(e).split(":", 2): | ||
log.error(" %s", x.lstrip(" ")) | ||
except Exception: | ||
log.error(" %s", e) | ||
return False | ||
log("gss token=%s", repr(token)) | ||
self.client.send_challenge_reply(packet, token) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
import os | ||
|
||
from xpra.util import csv | ||
from xpra.os_util import bytestostr, WIN32 | ||
from xpra.log import Logger | ||
|
||
log = Logger("auth") | ||
|
||
|
||
def log_kerberos_exception(e): | ||
try: | ||
for x in e.args: | ||
if isinstance(x, (list, tuple)): | ||
try: | ||
log.error(" %s", csv(x)) | ||
continue | ||
except Exception: | ||
pass | ||
log.error(" %s", x) | ||
except Exception: | ||
log.error(" %s", e) | ||
|
||
class Handler(object): | ||
|
||
def __init__(self, client, **_kwargs): | ||
self.client = client | ||
self.services = os.environ.get("XPRA_KERBEROS_SERVICES", "*").split(",") | ||
if WIN32: | ||
import winkerberos #@UnresolvedImport | ||
self.kerberos = winkerberos | ||
else: | ||
import kerberos #@UnresolvedImport | ||
self.kerberos = kerberos | ||
|
||
def __repr__(self): | ||
return "kerberos" | ||
|
||
def get_digest(self): | ||
return "kerberos" | ||
|
||
def handle(self, packet): | ||
digest = bytestostr(packet[3]) | ||
if not digest.startswith("kerberos:"): | ||
log("%s is not a kerberos challenge", digest) | ||
#not a kerberos challenge | ||
return False | ||
service = digest.split(":", 1)[1] | ||
if service not in self.services and "*" not in self.services: | ||
log.warn("Warning: invalid kerberos request for service '%s'", service) | ||
log.warn(" services supported: %s", csv(self.services)) | ||
return False | ||
log("kerberos service=%s", service) | ||
try: | ||
r, ctx = self.kerberos.authGSSClientInit(service) | ||
assert r==1, "return code %s" % r | ||
except Exception as e: | ||
log("kerberos.authGSSClientInit(%s)", service, exc_info=True) | ||
log.error("Error: cannot initialize kerberos client:") | ||
log_kerberos_exception(e) | ||
return False | ||
try: | ||
self.kerberos.authGSSClientStep(ctx, "") | ||
except Exception as e: | ||
log("kerberos.authGSSClientStep", exc_info=True) | ||
log.error("Error: kerberos client authentication failure:") | ||
log_kerberos_exception(e) | ||
return False | ||
token = self.kerberos.authGSSClientResponse(ctx) | ||
log("kerberos token=%s", token) | ||
self.client.send_challenge_reply(packet, token) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
from xpra.util import std | ||
from xpra.os_util import bytestostr | ||
|
||
|
||
class Handler(object): | ||
|
||
def __init__(self, client, **_kwargs): | ||
self.client = client | ||
|
||
def __repr__(self): | ||
return "prompt" | ||
|
||
def get_digest(self): | ||
return None | ||
|
||
def handle(self, packet): | ||
prompt = "password" | ||
digest = bytestostr(packet[3]) | ||
if digest.startswith("gss:") or digest.startswith("kerberos:"): | ||
prompt = "%s token" % (digest.split(":", 1)[0]) | ||
if len(packet)>=6: | ||
prompt = std(bytestostr(packet[5])) | ||
return self.client.do_process_challenge_prompt(packet, prompt) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
import os | ||
import logging | ||
import binascii | ||
|
||
from xpra.os_util import bytestostr, load_binary_file, osexpand | ||
from xpra.log import Logger, is_debug_enabled | ||
|
||
log = Logger("auth") | ||
|
||
|
||
class Handler(object): | ||
|
||
def __init__(self, client, **_kwargs): | ||
self.client = client | ||
import pyu2f #@UnresolvedImport @UnusedImport | ||
|
||
def __repr__(self): | ||
return "u2f" | ||
|
||
def get_digest(self): | ||
return "u2f" | ||
|
||
def handle(self, packet): | ||
digest = bytestostr(packet[3]) | ||
if not digest.startswith("u2f:"): | ||
log("%s is not a u2f challenge", digest) | ||
return False | ||
if not is_debug_enabled("auth"): | ||
logging.getLogger("pyu2f.hardware").setLevel(logging.INFO) | ||
logging.getLogger("pyu2f.hidtransport").setLevel(logging.INFO) | ||
from pyu2f import model #@UnresolvedImport | ||
from pyu2f.u2f import GetLocalU2FInterface #@UnresolvedImport | ||
dev = GetLocalU2FInterface() | ||
APP_ID = os.environ.get("XPRA_U2F_APP_ID", "Xpra") | ||
key_handle_str = os.environ.get("XPRA_U2F_KEY_HANDLE") | ||
log("process_challenge_u2f XPRA_U2F_KEY_HANDLE=%s", key_handle_str) | ||
if not key_handle_str: | ||
#try to load the key handle from the user conf dir(s): | ||
from xpra.platform.paths import get_user_conf_dirs | ||
info = self.client._protocol.get_info(False) | ||
key_handle_filenames = [] | ||
for hostinfo in ("-%s" % info.get("host", ""), ""): | ||
for d in get_user_conf_dirs(): | ||
key_handle_filenames.append(os.path.join(d, "u2f-keyhandle%s.hex" % hostinfo)) | ||
for filename in key_handle_filenames: | ||
p = osexpand(filename) | ||
key_handle_str = load_binary_file(p) | ||
log("key_handle_str(%s)=%s", p, key_handle_str) | ||
if key_handle_str: | ||
key_handle_str = key_handle_str.rstrip(b" \n\r") | ||
break | ||
if not key_handle_str: | ||
log.warn("Warning: no U2F key handle found") | ||
return False | ||
log("process_challenge_u2f key_handle=%s", key_handle_str) | ||
key_handle = binascii.unhexlify(key_handle_str) | ||
key = model.RegisteredKey(key_handle) | ||
#use server salt as challenge directly | ||
challenge = packet[1] | ||
log.info("activate your U2F device for authentication") | ||
response = dev.Authenticate(APP_ID, challenge, [key]) | ||
sig = response.signature_data | ||
client_data = response.client_data | ||
log("process_challenge_u2f client data=%s, signature=%s", client_data, binascii.hexlify(sig)) | ||
self.client.do_send_challenge_reply(bytes(sig), client_data.origin) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2019 Antoine Martin <[email protected]> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
|
||
class Handler(object): | ||
|
||
def __init__(self, client, **_kwargs): | ||
self.client = client | ||
|
||
def __repr__(self): | ||
return "uri" | ||
|
||
def get_digest(self): | ||
return None | ||
|
||
def handle(self, packet): | ||
if not self.client.password: | ||
return False | ||
self.client.send_challenge_reply(packet, self.client.password) | ||
return True |
Oops, something went wrong.