Still working on sftp server

resolved_file
Chris Truncer 2015-01-02 19:25:10 -05:00
parent 8bf8fae1a5
commit 5497c2a6b7
2 changed files with 243 additions and 0 deletions

View File

@ -0,0 +1,243 @@
import base64
import os
import paramiko
import socket
import tempfile
import threading
import time
from StringIO import StringIO
class User(object):
def __init__(self, username, password,
chroot=True, home=None, public_key=None):
self.username = username
self.password = password
self.chroot = chroot
self.public_key = public_key
if type(self.public_key) in (str, unicode):
bits = base64.decodestring(self.public_key.split(' ')[1])
msg = paramiko.Message(bits)
key = paramiko.RSAKey(msg)
self.public_key = key
self.home = home
if self.home is None:
self.home = self.username
class SFTPHandle(paramiko.SFTPHandle):
def __init__(self, flags=0, path=None):
paramiko.SFTPHandle.__init__(self, flags)
self.path = path
if(flags == 0):
self.readfile = open(path, "r")
else:
self.writefile = open(path, "w")
class SvnSFTPHandle(SFTPHandle):
def __init__(self, flags=0, path=None):
paramiko.SFTPHandle.__init__(self, flags)
self.path = path
if(flags == 0):
self.readfile = open(path, "r")
else:
self.writefile = open(path, "w")
def close(self):
paramiko.SFTPHandle.close(self)
writefile = getattr(self, 'writefile', None)
if writefile is not None:
writefile.close()
os.system("svn add %s" % self.path)
os.system("svn commit -m 'auto add' %s" % (self.path))
class SimpleSftpServer(paramiko.SFTPServerInterface):
def __init__(self, server, transport, fs_root, users, *largs, **kwargs):
self.transport = transport
self.root = fs_root
self.user_name = self.transport.get_username()
self.users = users
if self.users[self.user_name].chroot:
self.root = "%s/%s" % (self.root, self.users[self.user_name].home)
def get_fs_path(self, sftp_path):
real_path = "%s/%s" % (self.root, sftp_path)
real_path = real_path.replace('//', '/')
if not os.path.realpath(real_path).startswith(self.root):
raise Exception("Invalid path")
return(real_path)
def open(self, path, flags, attr):
real_path = self.get_fs_path(path)
return(SFTPHandle(flags, real_path))
def list_folder(self, path):
real_path = self.get_fs_path(path)
rc = []
for filename in os.listdir(real_path):
full_name = ("%s/%s" % (real_path, filename)).replace("//", "/")
rc.append(paramiko.SFTPAttributes.from_stat(os.stat(full_name), filename.replace(self.root, '')))
return rc
def stat(self, path):
real_path = self.get_fs_path(path)
return paramiko.SFTPAttributes.from_stat(os.stat(real_path), path)
def lstat(self, path):
real_path = self.get_fs_path(path)
return paramiko.SFTPAttributes.from_stat(os.stat(real_path), path)
def remove(self, path):
real_path = self.get_fs_path(path)
os.remove(real_path)
return 0
def rename(self, oldpath, newpath):
real_oldpath = self.get_fs_path(oldpath)
real_newpath = self.get_fs_path(newpath)
os.rename(real_oldpath, real_newpath)
return 0
def mkdir(self, path, attr):
real_path = self.get_fs_path(path)
os.makedirs(real_path)
return 0
def rmdir(self, path):
return
def chattr(self, path, attr):
return
def readlink(self, path):
return
def symlink(self, target_path, path):
return
class SubversionSftpServer(SimpleSftpServer):
def __init__(self, *largs, **kwargs):
SimpleSftpServer.__init__(self, *largs, **kwargs)
def open(self, path, flags, attr):
real_path = self.get_fs_path(path)
return(SvnSFTPHandle(flags, real_path))
def remove(self, path):
real_path = self.get_fs_path(path)
os.system("svn del %s" % real_path)
os.system("svn commit -m 'auto commit for %s' %s" % (self.user_name, real_path))
return 0
def rename(self, oldpath, newpath):
real_oldpath = SimpleSftpServer.get_fs_path(self, oldpath)
real_newpath = SimpleSftpServer.get_fs_path(self, newpath)
os.system("svn mv %s %s" % (real_oldpath, real_newpath))
os.system("svn commit -m 'auto commit for %s' %s %s" % (self.user_name, real_oldpath, real_newpath))
return 0
class IntegrationTestSftpServer(SimpleSftpServer):
def __init__(self, *largs, **kwargs):
SimpleSftpServer.__init__(self, *largs, **kwargs)
tempdir = tempfile.mkdtemp()
os.system("cp -r %s/* %s" % (self.root, tempdir))
self.root = tempdir
def session_ended(self):
#logger.info("Session ended, cleaning up %s" % self.root)
os.system("rm -rf %s" % self.root)
class SimpleSSHServer(paramiko.ServerInterface):
def __init__(self, users):
self.event = threading.Event()
self.users = users
self.authenticated_user = None
def check_channel_request(self, kind, chanid):
return paramiko.OPEN_SUCCEEDED
def check_auth_password(self, username, password):
if username in self.users:
if self.users[username].password == password:
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
def check_auth_publickey(self, username, key):
if username in self.users:
u = self.users[username]
if u.public_key is not None:
if u.public_key.get_base64() == key.get_base64():
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
def get_allowed_auths(self, username):
return 'password,publickey'
def get_authenticated_user(self):
return self.authenticated_user
def check_channel_shell_request(self, channel):
self.event.set()
return True
def accept_client(client, addr, root_dir, users, host_rsa_key, conf={}):
usermap = {}
for u in users:
usermap[u.username] = u
host_key_file = StringIO(host_rsa_key)
host_key = paramiko.RSAKey(file_obj=host_key_file)
transport = paramiko.Transport(client)
transport.load_server_moduli()
transport.add_server_key(host_key)
if conf.has_key("sftp_implementation"):
mod_name, class_name = conf['sftp_implementation'].split(':')
fromlist = None
try:
parent = mod_name[0:mod_name.rindex('.')]
fromlist = [parent]
except:
pass
mod = __import__(mod_name, fromlist=fromlist)
impl = getattr(mod, class_name)
#logger.info("Custom implementation: %s" % conf['sftp_implementation'])
else:
impl = SimpleSftpServer
transport.set_subsystem_handler("sftp", paramiko.SFTPServer, sftp_si=impl, transport=transport, fs_root=root_dir, users=usermap)
server = SimpleSSHServer(users=usermap)
transport.start_server(server=server)
channel = transport.accept()
while(transport.is_active()):
time.sleep(3)
username = server.get_authenticated_user()
if username is not None:
user = usermap[username]
os.system("svn commit -m 'committing user session for %s' %s" % (username, root_dir + "/" + user.home))
def start_service(configuration):
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('', configuration['port']))
server_socket.listen(10)
while True:
client, addr = server_socket.accept()
t = threading.Thread(target=accept_client, args=[
client, addr, configuration['root_dir'], configuration['users'],
configuration['host_rsa_key'], configuration, ])
t.start()