Commit 9971fca9 authored by Chris Hines's avatar Chris Hines
Browse files

ui modifications, change link to share an make path and uri positional arguments

parent f7b36a60
class SSHShare():
def __init__(self,appname,config):
self.appname = appname
self.config = config
def ca_setup(self):
''' Test to see if the necessary files are already setup '''
import appdirs
import os
cadir = appdirs.user_data_dir(self.appname,"")
try:
return os.path.isfile("{}/ca".format(cadir))
except FileNotFoundError:
return False
def initialise_ca(self):
''' Create the Key for the CA and install the CA into the authorised keys file. This is not necessary when using SSHAuthZ. If already initialised, don't do anything'''
import appdirs
cadir = appdirs.user_data_dir(self.appname,"")
import subprocess
import os
try:
os.makedirs(cadir, 0o700)
except FileExistsError:
pass
p = subprocess.Popen(['ssh-keygen','-f',"{}/ca".format(cadir),'-N',''],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
(stdout,stder) = p.communicate()
with open("{}/ca.pub".format(cadir)) as f:
pubkey = f.read()
with open(os.path.expanduser("~/.ssh/authorized_keys"),'a') as f:
f.write("cert-authority {}".format(pubkey))
def save_keys(self,key,cert):
''' Helper function, retrieve keys and save them '''
import tempfile
import os
keyf = tempfile.NamedTemporaryFile(mode='w',delete=False)
keypath = keyf.name
os.chmod(keypath,0o600)
keyf.write(key)
keyf.close()
with open(keypath+'-cert.pub','w') as certf:
certf.write(cert)
import time
time.sleep(1)
return keypath
def make_keys(self):
''' Generate a Keypair and return its path on disk'''
import appdirs
import subprocess
cadir = appdirs.user_data_dir(self.appname,"")
keypath="{}/tmpkey".format(cadir)
self.rm_keys(keypath)
p = subprocess.Popen(['ssh-keygen','-f',keypath,'-N',''],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
(stdout,stderr) = p.communicate()
return keypath
def rm_keys(self,keypath):
''' Helper function: remove a key and its .pub and -cert.pub if they exist'''
import os
try:
os.unlink(keypath)
except Exception as e:
pass
try:
os.unlink("{}.pub".format(keypath))
except:
pass
try:
os.unlink("{}-cert.pub".format(keypath))
except:
pass
def make_cert(self,capath,keypath,expiry,writable,sharepath,singularity=None,img=None):
''' Sign the public key with the approparite force-command and expirty parameters'''
import os
import subprocess
username = os.getlogin()
# force_command = "{singularity} exec -c --bind {sharepath}:{sharepath} {img} /usr/lib/openssh/sftp-server".format(singularity=singularity, img=img, username=username, sharepath=sharepath)
#force_command = "{singularity} exec -c --bind {sharepath}:{sharepath} {img} $SSH_ORIGINAL_COMMAND".format(singularity=singularity, img=img, username=username, sharepath=sharepath)
if writable:
force_command = "cat - > {}".format(sharepath)
else:
force_command = "cat {}".format(sharepath)
# force_command = "{singularity} exec -c --bind {sharepath}:{sharepath} {img} /bin/bash".format(singularity=singularity, img=img, username=username, sharepath=sharepath)
signcmd = ['ssh-keygen','-s',capath,'-I',username,'-n',username,'-V',expiry,
'-O','force-command={}'.format(force_command),
'{}.pub'.format(keypath)]
p = subprocess.Popen(signcmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
(stdout,stderr) = p.communicate()
with open(keypath,'r') as f:
privkey = f.read()
with open("{}-cert.pub".format(keypath),'r') as f:
cert = f.read()
return cert,privkey
def store_credentials(self,cert,privkey,uri):
''' Upload the private key, the public key and the URI to the web server.
recieve and return the URL which this data can be retrieved from'''
import requests
s = requests.Session()
data = {'cert':cert,'key':privkey,'uri':uri}
import yaml
import os
r=s.post(self.config['secretserver'],json=data)
key=r.json()
return self.config['secretserver']+key
def get_credentials(self,url):
''' Given a secret URL, retrieve keys and uri '''
import os
import yaml
import appdirs
import requests
s = requests.Session()
r = s.get(url)
data = r.json()
return(data['key'],data['cert'],data['uri'])
def parse_expiry(self,expiry):
print("sorry custom expiry is not implemented, 1 week expiry only")
return '+1w'
def make_share(self,args):
''' Given a path on disk, create all the credentials for access to that path, store those credentials on the secret server '''
try:
singularity = self.config['singularity']
img = self.config['img']
except KeyError as e:
singularity=None
img=None
if not self.ca_setup():
self.initialise_ca()
import appdirs
import os
cadir = appdirs.user_data_dir(self.appname,"")
capath=os.path.join(cadir,'ca')
keypath = self.make_keys()
expiry = '+1w'
sharepath = os.path.abspath(args.path)
if args.expiry:
try:
expiry = parse_expiry(args.expiry)
except:
pass
(cert,privkey) = self.make_cert(capath,keypath,expiry,args.writable,sharepath=sharepath)
import os
import socket
import requests
username = os.getlogin()
s = requests.Session()
r = s.get(self.config['ipserver'])
ip = r.json()
uri = "{}@{}:{}".format(username,ip,sharepath)
secreturl = self.store_credentials(cert,privkey,uri)
print("The credentials url is {}".format(secreturl))
print("The direct download url is {}?url={}".format(self.config['proxyserver'],secreturl))
self.rm_keys(keypath)
def ssh_get_pipes(self,key,cert,username,host,path,output):
''' retrieve data using openssh and pipes to python file objects
This code is likely to be fragile '''
import subprocess
import os
# Start the agent
agent = subprocess.Popen(['ssh-agent'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
agentout,agenterr = agent.communicate()
environ = os.environ.copy()
for line in agentout.splitlines():
for cmd in line.split(b';'):
try:
(var,value) = cmd.split(b'=')
except:
var=None
value=None
if var is not None:
environ[var.decode()] = value.decode()
if var.decode() == 'SSH_AGENT_PID':
agentpid = int(value)
# Load the keys into the agent
keypath = self.save_keys(key,cert)
addp = subprocess.Popen(['ssh-add',keypath],stdout = subprocess.PIPE,stderr=subprocess.PIPE,env=environ)
stdout,stderr = addp.communicate()
# Star the open ssh process piping straing to the output file object
sshp = subprocess.Popen(['ssh','-l',username,host,'cat',path],stdout = output,stderr=None,stdin=None,env=environ)
sshp.wait()
# Kill the agent
self.rm_keys(keypath)
import signal
os.kill(agentpid,signal.SIGTERM)
def get_file(self,args):
''' retrieve credentials and use those credentials to retrieve a file
consider analysing the contends of the force command in the cert and executing
different functions for different force commands'''
import os
(key,cert,uri) = self.get_credentials(args.url)
username,hostpath = uri.split('@')
host,path = hostpath.split(':')
with open(os.path.basename(uri),'wb') as output:
self.ssh_get_pipes(key,cert,username,host,path,output)
def put_file(self,args):
print("Sorry upload is not implemented")
appname = "sshshare"
appauthor = ""
config = {}
def ca_setup():
import appdirs
import os
cadir = appdirs.user_data_dir(appname,"")
try:
return os.path.isfile("{}/ca".format(cadir))
except FileNotFoundError:
return False
def initialise_ca():
''' Create the Key for the CA and install the CA into the authorised keys file. This is not necessary when using SSHAuthZ. If already initialised, don't do anything'''
import appdirs
cadir = appdirs.user_data_dir(appname,"")
import subprocess
import os
try:
os.makedirs(cadir, 0o700)
except FileExistsError:
pass
p = subprocess.Popen(['ssh-keygen','-f',"{}/ca".format(cadir),'-N',''])
(stdout,stder) = p.communicate()
with open("{}/ca.pub".format(cadir)) as f:
pubkey = f.read()
with open(os.path.expanduser("~/.ssh/authorized_keys"),'a') as f:
f.write("cert-authority {}".format(pubkey))
def save_keys(key,cert):
import tempfile
import os
keyf = tempfile.NamedTemporaryFile(mode='w',delete=False)
keypath = keyf.name
os.chmod(keypath,0o600)
keyf.write(key)
keyf.close()
with open(keypath+'-cert.pub','w') as certf:
certf.write(cert)
import time
time.sleep(1)
return keypath
def make_keys():
''' Generate a Keypair and return its path on disk'''
import appdirs
import subprocess
cadir = appdirs.user_data_dir(appname,"")
p = subprocess.Popen(['ssh-keygen','-f',"{}/tmpkey".format(cadir),'-N',''])
(stdout,stder) = p.communicate()
return "{}/tmpkey".format(cadir)
def rm_keys(keypath):
''' Generate a Keypair and return its path on disk'''
import os
try:
os.unlink(keypath)
except Exception as e:
pass
try:
os.unlink("{}.pub".format(keypath))
except:
pass
try:
os.unlink("{}-cert.pub".format(keypath))
except:
pass
def make_cert(capath,keypath,expiry,writable,sharepath,singularity,img):
''' Sign the public key with the approparite force-command and expirty parameters'''
import os
import subprocess
username = os.getlogin()
# force_command = "{singularity} exec -c --bind {sharepath}:{sharepath} {img} /usr/lib/openssh/sftp-server".format(singularity=singularity, img=img, username=username, sharepath=sharepath)
#force_command = "{singularity} exec -c --bind {sharepath}:{sharepath} {img} $SSH_ORIGINAL_COMMAND".format(singularity=singularity, img=img, username=username, sharepath=sharepath)
if writable:
force_command = "cat - > {}".format(sharepath)
else:
force_command = "cat {}".format(sharepath)
# force_command = "{singularity} exec -c --bind {sharepath}:{sharepath} {img} /bin/bash".format(singularity=singularity, img=img, username=username, sharepath=sharepath)
signcmd = ['ssh-keygen','-s',capath,'-I',username,'-n',username,'-V',expiry,
'-O','force-command={}'.format(force_command),
'{}.pub'.format(keypath)]
# signcmd = ['ssh-keygen','-s',capath,'-I',username,'-n',username,'-V',expiry,
# '{}.pub'.format(keypath)]
p = subprocess.Popen(signcmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
(stdout,stderr) = p.communicate()
with open(keypath,'r') as f:
privkey = f.read()
with open("{}-cert.pub".format(keypath),'r') as f:
cert = f.read()
return cert,privkey
def store_credentials(cert,privkey,uri):
''' Upload the private key, the public key and the URI to the web server.
recieve and return the URL which this data can be retrieved from'''
import requests
s = requests.Session()
data = {'cert':cert,'key':privkey,'uri':uri}
import yaml
import os
r=s.post(config['secretserver'],json=data)
key=r.json()
return config['secretserver']+key
def get_credentials(url):
''' Given a secret URL, retrieve keys and uri '''
import os
import yaml
import appdirs
import requests
s = requests.Session()
r = s.get(url)
data = r.json()
return(data['key'],data['cert'],data['uri'])
def parse_expiry(expiry):
print("sorry custom expiry is not implemented, 1 week expiry only")
return '+1w'
def make_link(args):
### TODO ###
### Get these from the config ###
try:
singularity = config['singularity']
img = config['img']
except KeyError as e:
singularity=None
img=None
if not ca_setup():
initialise_ca()
import appdirs
import os
cadir = appdirs.user_data_dir(appname,"")
capath=os.path.join(cadir,'ca')
keypath = make_keys()
expiry = '+1w'
sharepath = os.path.abspath(args.path)
if args.expiry:
try:
expiry = parse_expiry(args.expiry)
except:
pass
(cert,privkey) = make_cert(capath,keypath,expiry,args.writable,sharepath=sharepath,singularity=singularity,img=img)
import os
import socket
username = os.getlogin()
hostname = socket.gethostbyaddr(socket.gethostname())[0]
uri = "{}@{}:{}".format(username,hostname,sharepath)
secreturl = store_credentials(cert,privkey,uri)
print("The secret url is {}".format(secreturl))
print("The direct download url is {}?url={}".format(config['proxyserver'],secreturl))
rm_keys(keypath)
def ssh_get_pipes(key,cert,username,host,path,output):
import subprocess
import os
# Start the agent
agent = subprocess.Popen(['ssh-agent'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
agentout,agenterr = agent.communicate()
environ = os.environ.copy()
for line in agentout.splitlines():
for cmd in line.split(b';'):
try:
(var,value) = cmd.split(b'=')
except:
var=None
value=None
if var is not None:
environ[var.decode()] = value.decode()
if var.decode() == 'SSH_AGENT_PID':
agentpid = int(value)
# Load the keys into the agent
keypath = save_keys(key,cert)
addp = subprocess.Popen(['ssh-add',keypath],stdout = subprocess.PIPE,stderr=subprocess.PIPE,env=environ)
stdout,stderr = addp.communicate()
# Star the open ssh process piping straing to the output file object
sshp = subprocess.Popen(['ssh','-l',username,host,'cat',path],stdout = output,stderr=None,stdin=None,env=environ)
sshp.wait()
# Kill the agent
rm_keys(keypath)
import signal
os.kill(agentpid,signal.SIGTERM)
def get_file(args):
import os
(key,cert,uri) = get_credentials(args.url)
username,hostpath = uri.split('@')
print(uri)
host,path = hostpath.split(':')
with open(os.path.basename(uri),'wb') as output:
ssh_get_pipes(key,cert,username,host,path,output)
# import paramiko
# import io
# pkey = paramiko.RSAKey.from_private_key(io.StringIO(key))
# pkey.load_certificate(cert)
# username,hostpath = uri.split('@')
# print(uri)
# host,path = hostpath.split(':')
# port=22
#
# ssh = paramiko.SSHClient()
# ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# ssh.connect(host, port, username, pkey=pkey)
# stdin,stdout,stderr = ssh.exec_command('cat {}'.format(path))
# print(stdin)
# with open('output','wb') as f:
# f.write(stdout.read())
# stdin,stdout,stderr = ssh.exec_command('ls')
# print(stdin)
# print(stdout.read())
# from scp import SCPClient
# scp = SCPClient(ssh.get_transport())
# scp.get('/home/chines/test_sftp/script')
# Using the SSH client, create a SFTP client.
# sftp = ssh.open_sftp()
# sftp.get('/home/chines/test_sftp/script/','.')
# t = paramiko.Transport((host,port))
# t.connect(username=username,pkey=pkey)
# sftp = paramiko.SFTPClient.from_transport(t)
# cert = key+"-cert.pub"
# print(key)
# import subprocess
# print(['/home/chines/ssh_cert_download.sh',key,cert,uri])
# p = subprocess.Popen(['/home/chines/ssh_cert_download.sh',key,cert,uri])
# p.communicate()
## pass
def put_file(args):
pass
def main():
import argparse
import logging
from . import SSHShare
logging.basicConfig()
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
import appdirs
import os.path
import yaml
appname = "sshshare"
config = {}
configpath = os.path.join(appdirs.user_config_dir(appname,""),'config.yml')
dirname = os.path.dirname(configpath)
print(dirname)
config = {}
config['secretserver']='https://cw-vm-d034.sa.nectar.org.au/sshshare/share/'
config['ipserver']='https://cw-vm-d034.sa.nectar.org.au/sshshare/getip/'
config['proxyserver']='https://cw-vm-d034.sa.nectar.org.au/download/retrieve'
if not os.path.exists(dirname):
print("making config dir {}".format(dirname))
os.makedirs(dirname,0o700)
if os.path.exists(configpath):
with open(configpath,'r') as f:
configdata = yaml.load(f.read())
config.update(configdata)
else:
configdata = {}
configdata['singularity']='singularity'
configdata['img'] = 'sftp_img.img'
configdata['secretserver']='https://cw-vm-d034.sa.nectar.org.au/sshshare/share/'
configdata['proxyserver']='https://cw-vm-d034.sa.nectar.org.au/download/retrieve'
config.update(configdata)
if not os.path.exists(configpath):
with open(configpath,'w') as f:
f.write(yaml.dump(config))
sshshare = SSHShare(appname,config)
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
subp_link = subparser.add_parser('link')
subp_link.set_defaults(func=make_link)
subp_link.add_argument('--path')
subp_link = subparser.add_parser('share')
subp_link.set_defaults(func=sshshare.make_share)
subp_link.add_argument('path')
subp_link.add_argument('--expiry')
subp_link.add_argument('--writable')
subp_get = subparser.add_parser('get')
subp_get.set_defaults(func=get_file)
subp_get.add_argument('--url')
subp_get.set_defaults(func=sshshare.get_file)
subp_get.add_argument('url')
subp_put = subparser.add_parser('put')
subp_put.set_defaults(func=put_file)
subp_put.add_argument('--url')
subp_put.set_defaults(func=sshshare.put_file)
subp_put.add_argument('url')
args = parser.parse_args()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment