def __init__(self, environ, start_response): self.ca = CertAuthority(CONFIG['ca']) self.environ = environ self.resp = start_response self.action = self.environ.get('REQUEST_URI').split('/')[2] if not self.action.isalnum(): raise # parse params tmp = environ.get('REQUEST_URI').split('?') self.params = {} if len(tmp) > 1: for exp in '?'.join(tmp[1:]).split('&'): tmp2 = exp.split('=') self.params[tmp2[0]] = '='.join(tmp2[1:])
def submitcsr(self): msg = '' if self.environ.get('REQUEST_METHOD') == 'POST': if int(self.environ.get('CONTENT_LENGTH', 0)) != 0: fd = self.environ['wsgi.input'] params = {} for exp in fd.readline().split('&'): tmp2 = exp.split('=') params[tmp2[0]] = urllib.unquote('='.join( tmp2[1:])).strip() if not csrf(params): msg = "Try again from our fine server please." elif params.get('csr'): ca = CertAuthority(CONFIG['ca']) tmp = params['csr'].split('\n') csr = '\n'.join([ urllib.unquote_plus(tmp[0]), '\n'.join(tmp[1:-1]), urllib.unquote_plus(tmp[-1]) ]) try: self.ca.submit(csr) except: msg = "Fail<br />please submit a valid Certificate Signing Request containing your email." else: msg = "Success<br />Your request will be reviewed soon." return send_template(self.resp, 'certify.html', isadmin=authorized(self.environ, CONFIG['admins']), csrf=getcsrf(), msg=msg)
def __init__(self,environ, start_response): self.ca=CertAuthority(CONFIG['ca']) self.environ=environ self.resp=start_response self.action = self.environ.get('REQUEST_URI').split('/')[2] if not self.action.isalnum(): raise # parse params tmp = environ.get('REQUEST_URI').split('?') self.params = {} if len(tmp)>1: for exp in '?'.join(tmp[1:]).split('&'): tmp2 = exp.split('=') self.params[tmp2[0]]='='.join(tmp2[1:])
#!/usr/bin/env python import shutil, os from tlsauth import CertAuthority, mailsigned, genkeycsr, pkcs12 # DEMO code # initialize your own CA by running # createca.sh CA if os.path.exists('test-ca'): shutil.rmtree('test-ca') ca = CertAuthority.createca('test-ca', 'http://www.example.com/crl.pem', 'example CA', '*****@*****.**', valid=5) # do not try this at home. # warning: irresponsible blind trust in 3rd parties # warning: will be ignored anyway. ca.gencert('joe', '*****@*****.**', 'ACME Inc.') print "dropped correct pkcs12 cert" # even worse (and intentionally ugly) #mail(ca.gencert('s', '*****@*****.**', 'ctrlc'), # "Howdy.\n\n" \ # "Your login certificate from %s is attached.\n\n" \ # "You should import this into your browser, keep a safe\n" \ # "copy and delete this mail and other copies containing it.\n\n" \ # "Have fun and respect", # {'emailAddress': '*****@*****.**', 'CN': 's', 'O': 'ctrlc'}, # ca.dn, # ext='p12')
from cryptography.fernet import Fernet from functools import wraps BASE_PATH = os.path.dirname(os.path.realpath(__file__)) DB_PATH = os.path.join(BASE_PATH, "db.db") UPLOAD_FOLDER = os.path.join(BASE_PATH, "upload") application = Flask(__name__) application.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER application.secret_key = 'CHANGE THIS IN PRODUCTION' application.debug = True from tlsauth import CertAuthority import flask_tlsauth as tlsauth ca = CertAuthority('sub-ca') users = ["Users"] application.jinja_loader = jinja2.ChoiceLoader([ application.jinja_loader, jinja2.FileSystemLoader(os.path.join(BASE_PATH,'templates')), ]) application.add_url_rule('/tlsauth/cert/', 'cert', tlsauth.renderCert(ca)) application.add_url_rule('/tlsauth/test/', 'test', tlsauth.testAuth) def connect_to_database(): return sqlite3.connect(DB_PATH, detect_types=sqlite3.PARSE_DECLTYPES) def get_db():
#!/usr/bin/env python # run with # env/bin/uwsgi --socket 127.0.0.1:8080 --chdir $PWD/demo -pp $PWD -w tlsauth_wsgi -p 1 --virtualenv $PWD/env --py-autoreload 1 # also create a ca in ../../x509-ca - for more info see tlsauth README from flask import Flask, Response import os app = Flask(__name__) app.secret_key = 'zxcvzxcvz' #app.debug = True from tlsauth import CertAuthority import flask_tlsauth as tlsauth ca=CertAuthority('../../x509-ca') app.debug = True adminOs=['CA admins'] tlsauth.tlsauth_init(app, ca, groups=adminOs) @app.route('/hello') @tlsauth.tlsauth(groups=adminOs) def hello(): return Response("hello world")
#!/usr/bin/env python import shutil, os from tlsauth import CertAuthority, mailsigned, genkeycsr, pkcs12 # DEMO code # initialize your own CA by running # createca.sh CA if os.path.exists('test-ca'): shutil.rmtree('test-ca') ca=CertAuthority.createca('test-ca', 'http://www.example.com/crl.pem', 'example CA', '*****@*****.**', valid=5) # do not try this at home. # warning: irresponsible blind trust in 3rd parties # warning: will be ignored anyway. ca.gencert('joe', '*****@*****.**', 'ACME Inc.') print "dropped correct pkcs12 cert" # even worse (and intentionally ugly) #mail(ca.gencert('s', '*****@*****.**', 'ctrlc'), # "Howdy.\n\n" \ # "Your login certificate from %s is attached.\n\n" \ # "You should import this into your browser, keep a safe\n" \ # "copy and delete this mail and other copies containing it.\n\n" \ # "Have fun and respect", # {'emailAddress': '*****@*****.**', 'CN': 's', 'O': 'ctrlc'}, # ca.dn, # ext='p12') # this is the correct - but less automagic - procedure sec, pub, csr = genkeycsr('joe', '*****@*****.**', 'ACME Inc.')
class AdminHandler(object): """ class for handling user registration, and creating new stashes over the web provides similar urls as Flask-TLSAuth /settings/register - using keygen tag /settings/request - submit your own CSR /settings/requests - list all user account requests (admin only) /settings/newstash - create a new stash (admin only) /settings/accept/<certhash> - accept a new user request (admin only) /settings/reject/<certhash> - reject a new user request (admin only) """ def __init__(self,environ, start_response): self.ca=CertAuthority(CONFIG['ca']) self.environ=environ self.resp=start_response self.action = self.environ.get('REQUEST_URI').split('/')[2] if not self.action.isalnum(): raise # parse params tmp = environ.get('REQUEST_URI').split('?') self.params = {} if len(tmp)>1: for exp in '?'.join(tmp[1:]).split('&'): tmp2 = exp.split('=') self.params[tmp2[0]]='='.join(tmp2[1:]) def handle(self): """ main dispatcher of AdminHandler """ if self.action == 'newstash': return self.newstash() elif self.action == 'register': return self.register() elif self.action == 'request': return self.submitcsr() elif self.action == 'requests': return self.showcsrs() elif self.action == 'accept': return self.accept() elif self.action == 'reject': return self.reject() elif self.action == 'stashes': return self.stashes() elif self.action == 'delete': return self.delete() return _404(self.environ,self.resp) def register(self): msg='' if self.environ.get('REQUEST_METHOD') == 'POST': if int(self.environ.get('CONTENT_LENGTH', 0)) != 0: fd=self.environ['wsgi.input'] params={} for exp in fd.readline().split('&'): tmp2 = exp.split('=') params[tmp2[0]]=urllib.unquote('='.join(tmp2[1:])) if not csrf(params): msg="Try again from our fine server please." elif params.get('email') and params.get('key'): csr=spkac2cert(''.join(params['key']), params['email'], name=params.get('name')) self.ca.submit(csr) msg="Success<br />Your request will be reviewed soon." else: msg="Sorry but you must supply an email address" return send_template(self.resp, 'register.html', isadmin=authorized(self.environ, CONFIG['admins']), csrf=getcsrf(), msg=msg) def submitcsr(self): msg='' if self.environ.get('REQUEST_METHOD') == 'POST': if int(self.environ.get('CONTENT_LENGTH', 0)) != 0: fd=self.environ['wsgi.input'] params={} for exp in fd.readline().split('&'): tmp2 = exp.split('=') params[tmp2[0]]=urllib.unquote('='.join(tmp2[1:])).strip() if not csrf(params): msg="Try again from our fine server please." elif params.get('csr'): ca=CertAuthority(CONFIG['ca']) tmp=params['csr'].split('\n') csr='\n'.join([urllib.unquote_plus(tmp[0]), '\n'.join(tmp[1:-1]), urllib.unquote_plus(tmp[-1])]) try: self.ca.submit(csr) except: msg="Fail<br />please submit a valid Certificate Signing Request containing your email." else: msg="Success<br />Your request will be reviewed soon." return send_template(self.resp, 'certify.html', isadmin=authorized(self.environ, CONFIG['admins']), csrf=getcsrf(), msg=msg) def showcsrs(self): email=authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) return send_template(self.resp, 'csrs.html', isadmin=authorized(self.environ, CONFIG['admins']), certs=[(todn(cert.get_subject()), datetime.datetime.fromtimestamp(os.stat(path).st_mtime), os.path.basename(path)) for cert, path in self.ca.incoming()]) def accept(self): """ provides facility for users belonging to `groups` to sign incoming CSRs """ email=authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) path=self.ca._incoming+'/'+self.environ.get('REQUEST_URI').split('/')[3] print "certifying", path cert=self.ca.signcsr(load(path)) mailsigned([cert]) os.unlink(path) status = '302 Found' response_headers = [('Location', '/settings/requests')] self.resp(status, response_headers) return [] def reject(self): """ provides facility for users belonging to `groups` to reject incoming CSRs """ email=authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) path=self.ca._incoming+'/'+self.environ.get('REQUEST_URI').split('/')[3] os.unlink(path) status = '302 Found' response_headers = [('Location', '/settings/requests')] self.resp(status, response_headers) return [] def newstash(self): msg='' email=authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) gpg = gnupg.GPG(gnupghome=CONFIG['gpghome']) knownkeys={x['uids'][0][ x['uids'][0].rfind('<')+1: x['uids'][0].rfind('>')]:x for x in gpg.list_keys()} keyid=knownkeys.get(email, {}).get('keyid') if self.environ.get('REQUEST_METHOD') == 'POST': if int(self.environ.get('CONTENT_LENGTH', 0)) != 0: fd=self.environ['wsgi.input'] params=defaultdict(list) for exp in fd.readline().split('&'): tmp2 = exp.split('=') params[tmp2[0]]=urllib.unquote('='.join(tmp2[1:])).strip() if not csrf(params): msg="Try again from our fine server please." elif keyid or params.get('keyid') or params.get('pk'): if params.get('pk'): gpg.import_keys(params.get('pk')) knownkeys={x['uids'][0][ x['uids'][0].rfind('<')+1: x['uids'][0].rfind('>')]:x for x in gpg.list_keys()} elif params.get('keyid'): f = urllib.urlopen('http://pool.sks-keyservers.net:11371/pks/lookup?op=get&search=%s' % params.get('keyid')) key = f.read() gpg.import_keys(key) knownkeys={x['uids'][0][ x['uids'][0].rfind('<')+1: x['uids'][0].rfind('>')]:x for x in gpg.list_keys()} keyid=knownkeys.get(email)['keyid'] if not keyid: msg="Couldn't locate PGP key for owner, try uploading one" elif not params.get('invited'): msg="You must invite someone to share this stash with" else: stashid=Dropper.newstash([knownkeys[email]['keyid']], urllib.unquote_plus(params['invited']).split('\n'), urllib.unquote_plus(params.get('name'))) # todo sent invitation mail to uploaders status = '302 Found' response_headers = [('Location', '/%s/' % stashid )] self.resp(status, response_headers) return [] else: msg="You must supply a PGP public key for enabling encryption of stored data" return send_template(self.resp, 'newstash.html', isadmin=authorized(self.environ, CONFIG['admins']), msg=msg, csrf=getcsrf(), knownkey=keyid) def stashes(self): """ lists all stashes for admins """ email=authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) gpg = gnupg.GPG(gnupghome=CONFIG['gpghome']) knownkeys={x['keyid']: x['uids'][0][ x['uids'][0].rfind('<')+1: x['uids'][0].rfind('>')] for x in gpg.list_keys()} stashes=[] for fname in os.listdir(CONFIG['root']+'/drop'): if not fname.endswith('.cfg'): continue with open(CONFIG['root']+'/drop/'+fname,'r') as fd: owner=[knownkeys[kid] for kid in fd.readline().strip().split()] friends=[x.strip() for x in fd.readlines()] files=[os.stat(CONFIG['root']+'/drop/'+fname[:-4]+'/'+f).st_size for f in os.listdir(CONFIG['root']+'/drop/'+fname[:-4]) if not f.endswith('.meta')] stashes.append((fname[:-4], owner, friends, sizeof_fmt(sum(files)), len(files))) return send_template(self.resp, 'stashes.html', isadmin=authorized(self.environ, CONFIG['admins']), stashes=stashes) def delete(self): """ provides facility for users belonging to `groups` to reject incoming CSRs """ email=authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) stashid=self.environ.get('REQUEST_URI').split('/')[3] if stashid.isalnum(): path=CONFIG['root']+'/drop/'+stashid os.unlink(path+'.cfg') shutil.rmtree(path) status = '302 Found' response_headers = [('Location', '/settings/stashes')] self.resp(status, response_headers) return []
class AdminHandler(object): """ class for handling user registration, and creating new stashes over the web provides similar urls as Flask-TLSAuth /settings/register - using keygen tag /settings/request - submit your own CSR /settings/requests - list all user account requests (admin only) /settings/newstash - create a new stash (admin only) /settings/accept/<certhash> - accept a new user request (admin only) /settings/reject/<certhash> - reject a new user request (admin only) """ def __init__(self, environ, start_response): self.ca = CertAuthority(CONFIG['ca']) self.environ = environ self.resp = start_response self.action = self.environ.get('REQUEST_URI').split('/')[2] if not self.action.isalnum(): raise # parse params tmp = environ.get('REQUEST_URI').split('?') self.params = {} if len(tmp) > 1: for exp in '?'.join(tmp[1:]).split('&'): tmp2 = exp.split('=') self.params[tmp2[0]] = '='.join(tmp2[1:]) def handle(self): """ main dispatcher of AdminHandler """ if self.action == 'newstash': return self.newstash() elif self.action == 'register': return self.register() elif self.action == 'request': return self.submitcsr() elif self.action == 'requests': return self.showcsrs() elif self.action == 'accept': return self.accept() elif self.action == 'reject': return self.reject() elif self.action == 'stashes': return self.stashes() elif self.action == 'delete': return self.delete() return _404(self.environ, self.resp) def register(self): msg = '' if self.environ.get('REQUEST_METHOD') == 'POST': if int(self.environ.get('CONTENT_LENGTH', 0)) != 0: fd = self.environ['wsgi.input'] params = {} for exp in fd.readline().split('&'): tmp2 = exp.split('=') params[tmp2[0]] = urllib.unquote('='.join(tmp2[1:])) if not csrf(params): msg = "Try again from our fine server please." elif params.get('email') and params.get('key'): csr = spkac2cert(''.join(params['key']), params['email'], name=params.get('name')) self.ca.submit(csr) msg = "Success<br />Your request will be reviewed soon." else: msg = "Sorry but you must supply an email address" return send_template(self.resp, 'register.html', isadmin=authorized(self.environ, CONFIG['admins']), csrf=getcsrf(), msg=msg) def submitcsr(self): msg = '' if self.environ.get('REQUEST_METHOD') == 'POST': if int(self.environ.get('CONTENT_LENGTH', 0)) != 0: fd = self.environ['wsgi.input'] params = {} for exp in fd.readline().split('&'): tmp2 = exp.split('=') params[tmp2[0]] = urllib.unquote('='.join( tmp2[1:])).strip() if not csrf(params): msg = "Try again from our fine server please." elif params.get('csr'): ca = CertAuthority(CONFIG['ca']) tmp = params['csr'].split('\n') csr = '\n'.join([ urllib.unquote_plus(tmp[0]), '\n'.join(tmp[1:-1]), urllib.unquote_plus(tmp[-1]) ]) try: self.ca.submit(csr) except: msg = "Fail<br />please submit a valid Certificate Signing Request containing your email." else: msg = "Success<br />Your request will be reviewed soon." return send_template(self.resp, 'certify.html', isadmin=authorized(self.environ, CONFIG['admins']), csrf=getcsrf(), msg=msg) def showcsrs(self): email = authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) return send_template(self.resp, 'csrs.html', isadmin=authorized(self.environ, CONFIG['admins']), certs=[(todn(cert.get_subject()), datetime.datetime.fromtimestamp( os.stat(path).st_mtime), os.path.basename(path)) for cert, path in self.ca.incoming()]) def accept(self): """ provides facility for users belonging to `groups` to sign incoming CSRs """ email = authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) path = self.ca._incoming + '/' + self.environ.get('REQUEST_URI').split( '/')[3] print "certifying", path cert = self.ca.signcsr(load(path)) mailsigned([cert]) os.unlink(path) status = '302 Found' response_headers = [('Location', '/settings/requests')] self.resp(status, response_headers) return [] def reject(self): """ provides facility for users belonging to `groups` to reject incoming CSRs """ email = authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) path = self.ca._incoming + '/' + self.environ.get('REQUEST_URI').split( '/')[3] os.unlink(path) status = '302 Found' response_headers = [('Location', '/settings/requests')] self.resp(status, response_headers) return [] def newstash(self): msg = '' email = authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) gpg = gnupg.GPG(gnupghome=CONFIG['gpghome']) knownkeys = { x['uids'][0][x['uids'][0].rfind('<') + 1:x['uids'][0].rfind('>')]: x for x in gpg.list_keys() } keyid = knownkeys.get(email, {}).get('keyid') if self.environ.get('REQUEST_METHOD') == 'POST': if int(self.environ.get('CONTENT_LENGTH', 0)) != 0: fd = self.environ['wsgi.input'] params = defaultdict(list) for exp in fd.readline().split('&'): tmp2 = exp.split('=') params[tmp2[0]] = urllib.unquote('='.join( tmp2[1:])).strip() if not csrf(params): msg = "Try again from our fine server please." elif keyid or params.get('keyid') or params.get('pk'): if params.get('pk'): gpg.import_keys(params.get('pk')) knownkeys = { x['uids'][0][x['uids'][0].rfind('<') + 1:x['uids'][0].rfind('>')]: x for x in gpg.list_keys() } elif params.get('keyid'): f = urllib.urlopen( 'http://pool.sks-keyservers.net:11371/pks/lookup?op=get&search=%s' % params.get('keyid')) key = f.read() gpg.import_keys(key) knownkeys = { x['uids'][0][x['uids'][0].rfind('<') + 1:x['uids'][0].rfind('>')]: x for x in gpg.list_keys() } keyid = knownkeys.get(email)['keyid'] if not keyid: msg = "Couldn't locate PGP key for owner, try uploading one" elif not params.get('invited'): msg = "You must invite someone to share this stash with" else: stashid = Dropper.newstash( [knownkeys[email]['keyid']], urllib.unquote_plus(params['invited']).split('\n'), urllib.unquote_plus(params.get('name'))) # todo sent invitation mail to uploaders status = '302 Found' response_headers = [('Location', '/%s/' % stashid)] self.resp(status, response_headers) return [] else: msg = "You must supply a PGP public key for enabling encryption of stored data" return send_template(self.resp, 'newstash.html', isadmin=authorized(self.environ, CONFIG['admins']), msg=msg, csrf=getcsrf(), knownkey=keyid) def stashes(self): """ lists all stashes for admins """ email = authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) gpg = gnupg.GPG(gnupghome=CONFIG['gpghome']) knownkeys = { x['keyid']: x['uids'][0][x['uids'][0].rfind('<') + 1:x['uids'][0].rfind('>')] for x in gpg.list_keys() } stashes = [] for fname in os.listdir(CONFIG['root'] + '/drop'): if not fname.endswith('.cfg'): continue with open(CONFIG['root'] + '/drop/' + fname, 'r') as fd: owner = [ knownkeys[kid] for kid in fd.readline().strip().split() ] friends = [x.strip() for x in fd.readlines()] files = [ os.stat(CONFIG['root'] + '/drop/' + fname[:-4] + '/' + f).st_size for f in os.listdir(CONFIG['root'] + '/drop/' + fname[:-4]) if not f.endswith('.meta') ] stashes.append((fname[:-4], owner, friends, sizeof_fmt(sum(files)), len(files))) return send_template(self.resp, 'stashes.html', isadmin=authorized(self.environ, CONFIG['admins']), stashes=stashes) def delete(self): """ provides facility for users belonging to `groups` to reject incoming CSRs """ email = authorized(self.environ, CONFIG['admins']) if not email: return _404(self.environ, self.resp) stashid = self.environ.get('REQUEST_URI').split('/')[3] if stashid.isalnum(): path = CONFIG['root'] + '/drop/' + stashid os.unlink(path + '.cfg') shutil.rmtree(path) status = '302 Found' response_headers = [('Location', '/settings/stashes')] self.resp(status, response_headers) return []