Commit e91c0d09 authored by Chris Hines's avatar Chris Hines
Browse files

initial commit of sshshare

parents
"""A setuptools based setup module.
See:
https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject
"""
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
long_description = 'sshshare creates SSH certificates and manipulates your authorized keys file to allow them. sshshare_ws creates secret urls that you can give to someone else to retrieve the certificate and key. download allows users without openssh tools to pass the url returned to sshshare_ws to a proxy to download the file over http rather than ssh'
setup(
name='sshshare',
version='0.0.1',
description=long_description,
long_description=long_description,
# The project's main homepage.
url='',
# Author details
author='Chris Hines',
author_email='help@massive.org.au',
# Choose your license
license='MIT',
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# Indicate who your project is intended for
'Intended Audience :: Office workers',
'Topic :: Software Development :: Build Tools',
# Pick your license as you wish (should match "license" above)
'License :: OSI Approved :: MIT License',
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
],
# What does your project relate to?
keywords='ssh file sharing certificates',
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
# Alternatively, if you want to distribute just a my_module.py, uncomment
# this:
# py_modules=["my_module"],
# List run-time dependencies here. These will be installed by pip when
# your project is installed. For an analysis of "install_requires" vs pip's
# requirements files see:
# https://packaging.python.org/en/latest/requirements.html
install_requires=[
'requests',
'wheel',
],
data_files = [('',[])],
# To provide executable scripts, use entry points in preference to the
# "scripts" keyword. Entry points provide cross-platform support and allow
# pip to create the appropriate form of executable for the target platform.
entry_points={
'console_scripts': [ 'sshshare=sshshare.__main__:main'],
'gui_scripts': [ ]
},
)
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 ###
singularity = config['singularity']
img = config['img']
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
logging.basicConfig()
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
import appdirs
import os.path
import yaml
configpath = os.path.join(appdirs.user_config_dir(appname,""),'config.yml')
dirname = os.path.dirname(configpath)
print(dirname)
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())
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/'
with open(configpath,'w') as f:
f.write(yaml.dump(config))
config.update(configdata)
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.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_put = subparser.add_parser('put')
subp_put.set_defaults(func=put_file)
subp_put.add_argument('--url')
args = parser.parse_args()
if hasattr(args,'execute'):
if args.execute == True:
import mysubprocess
mysubprocess.debug=False
if hasattr(args,'func'):
args.func(args)
if __name__ == '__main__':
main()
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