Skip to content

Commit

Permalink
#1920: support public key authentication using openssh's "~/.ssh/auth…
Browse files Browse the repository at this point in the history
…orized_keys" file

git-svn-id: https://xpra.org/svn/Xpra/trunk@19952 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jul 23, 2018
1 parent 4d2f3e7 commit 5e92715
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
8 changes: 4 additions & 4 deletions src/xpra/server/server_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
from xpra.net.digest import get_salt, gendigest, choose_digest
from xpra.platform import set_name
from xpra.os_util import load_binary_file, get_machine_id, get_user_uuid, platform_name, strtobytes, bytestostr, get_hex_uuid, \
getuid, monotonic_time, get_peercred, hexstr, \
SIGNAMES, WIN32, POSIX, PYTHON3, BITS, get_username_for_uid
getuid, monotonic_time, get_peercred, hexstr, SIGNAMES, WIN32, POSIX, PYTHON3, BITS
from xpra.server.background_worker import stop_worker, get_worker
from xpra.make_thread import start_thread
from xpra.util import csv, merge_dicts, typedict, notypedict, flatten_dict, parse_simple_dict, repr_ellipsized, dump_all_frames, nonl, envint, envbool, envfloat, \
Expand Down Expand Up @@ -934,8 +933,9 @@ def handle_ssh_connection(self, conn):
socktype = conn.socktype_wrapped
sshlog("handle_ssh_connection(%s) socktype wrapped=%s", conn, socktype)
def ssh_password_authenticate(username, password):
if POSIX and getuid()!=0:
sysusername = get_username_for_uid(os.getuid())
if not POSIX or getuid()!=0:
import getpass
sysusername = getpass.getuser()
if sysusername!=username:
sshlog.warn("Warning: ssh password authentication failed")
sshlog.warn(" username does not match: expected '%s', got '%s'", sysusername, username)
Expand Down
38 changes: 36 additions & 2 deletions src/xpra/server/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@

from xpra.net.ssh import SSHSocketConnection
from xpra.util import csv, envint
from xpra.os_util import osexpand, WIN32
from xpra.os_util import osexpand, getuid, WIN32, POSIX


SSH_KEY_DIRS = "/etc/ssh", "/usr/local/etc/ssh", "~/.ssh", "~/ssh/"
SERVER_WAIT = envint("XPRA_SSH_SERVER_WAIT", 20)
AUTHORIZED_KEYS = "~/.ssh/authorized_keys"


class SSHServer(paramiko.ServerInterface):
Expand Down Expand Up @@ -65,7 +66,40 @@ def check_auth_publickey(self, username, key):
log("check_auth_publickey(%s, %r) pubkey_auth=%s", username, key, self.pubkey_auth)
if not self.pubkey_auth:
return paramiko.AUTH_FAILED
#TODO: verify key
if not POSIX or getuid()!=0:
import getpass
sysusername = getpass.getuser()
if sysusername!=username:
log.warn("Warning: ssh password authentication failed")
log.warn(" username does not match: expected '%s', got '%s'", sysusername, username)
return paramiko.AUTH_FAILED
authorized_keys_filename = osexpand(AUTHORIZED_KEYS)
if not os.path.exists(authorized_keys_filename) or not os.path.isfile(authorized_keys_filename):
log("file '%s' does not exist", authorized_keys_filename)
return paramiko.AUTH_FAILED
import base64
import binascii
fingerprint = key.get_fingerprint()
hex_fingerprint = binascii.hexlify(fingerprint)
log("looking for key fingerprint '%s' in '%s'", hex_fingerprint, authorized_keys_filename)
count = 0
with open(authorized_keys_filename, "rb") as f:
for line in f:
if line.startswith("#"):
continue
line = line.strip("\n\r")
try:
key = base64.b64decode(line.strip().split()[1].encode('ascii'))
except Exception as e:
log("ignoring line '%s': %s", line, e)
continue
import hashlib
fp_plain = hashlib.md5(key).hexdigest()
log("key(%s)=%s", line, fp_plain)
if fp_plain==hex_fingerprint:
return paramiko.OPEN_SUCCEEDED
count += 1
log("no match in %i keys from '%s'", count, authorized_keys_filename)
return paramiko.AUTH_FAILED

def check_auth_gssapi_keyex(self, username, gss_authenticated=paramiko.AUTH_FAILED, cc_file=None):
Expand Down

0 comments on commit 5e92715

Please sign in to comment.