def auth_cookie(): config = utils.user_config() if keyring: log.debug("Use keyring module. Great!") cookie = keyring.get_password("cookie:api.pytheon.net", config.pytheon.username) else: config = utils.user_config() cookie = config.pytheon.auth_cookie or None if cookie is not None: return {"Cookie": "auth_tkt=%s" % cookie} return None
def save_cookie(headers): config = utils.user_config() for k, v in headers: if k.lower() == "set-cookie": cookie = SimpleCookie(v) auth_cookie = cookie["auth_tkt"].value log.debug("Cookie: %s", auth_cookie) if keyring: keyring.set_password("cookie:api.pytheon.net", config.pytheon.username, auth_cookie) else: config.pytheon.auth_cookie = auth_cookie config.write()
def auth_basic(retry=False): config = utils.user_config() username = config.pytheon.username or utils.get_input("Username") password = None if keyring: log.debug("Use keyring module. Great!") password = keyring.get_password("basic:api.pytheon.net", username) if password == None or retry: password = utils.get_input("Password", password=True) if keyring: keyring.set_password("basic:api.pytheon.net", username, password) auth = base64.encodestring("%s:%s" % (username, password)) return {"Authorization": "Basic " + auth.strip()}
def create(parser, options, args): """create your pytheon project""" binary = utils.vcs_binary() global_config = utils.user_config() if not os.path.isfile(global_config._filename): global_config.pytheon = dict( username=options.username or utils.get_input('Username'), ) global_config.write() rc = global_config.pytheon config = utils.project_config(filename=options.buildout) if not os.path.isfile(config._filename): if not options.project_name: options.project_name = utils.get_input('Project name', default=os.path.basename(os.getcwd())) config.deploy = dict( version='1', use='gunicorn', project_name=options.project_name, ) if options.project_name: config.deploy.project_name = options.project_name config.write() kw = dict(username=rc.username, project_name=config.deploy.project_name) if binary == 'git': remote = os.environ.get('PYTHEON_REMOTE', '[email protected]:%(project_name)s.git').rstrip('/') remote = remote % kw utils.call(binary, 'remote', 'add', 'pytheon', remote, silent=True) else: remote = os.environ.get('PYTHEON_REMOTE', '[email protected]/%(project_name)s').rstrip('/') remote = remote % kw filename = '.hg/hgrc' config = Config.from_file(filename) config.paths.pytheon = remote config.write() commit(binary, config._filename) return http.request('/v1/applications', name=config.deploy.project_name)
def register(parser, options, args): """register on pytheon""" if options.key and options.reset: parser.error("You can't reset a password with a confirmation key") config = utils.user_config() if options.username: config.pytheon.username = options.username config.write() if not config.pytheon.username: parser.error('Please specify a valid email') if options.key: return http.request('/v1/set_password/%s' % options.key.strip('/'), auth=False, password=utils.get_input('Password', password=True)) elif options.reset: return http.request('/v1/reset_password/', auth=False, email=options.username) else: return http.request('/v1/register', auth=False, email=options.username)
def request(path, method="GET", auth=True, host=None, json=False, **params): config = utils.user_config() headers = {} if params: method = "POST" params = urlencode(params) headers["Content-Type"] = "application/x-www-form-urlencoded" else: params = None if json: headers["Accept"] = "application/json" else: headers["Accept"] = "text/plain" if auth: cookie_auth = auth_cookie() if cookie_auth is not None: log.debug("Use cookie: %s" % cookie_auth) headers.update(cookie_auth) else: log.debug("Use auth basic") headers.update(auth_basic()) def get_conn(host): host, port = host.split(":") port = int(port) if port == 443: ## This HTTPSConnection *REQUIRES* a file containing concatenated ## PEM certificates of the authorities you trust. This means you ## *HAVE TO* bundle certificates with your application ## (as firefox does). ## ## If you are running on a debian/ubuntu system, ## mozilla certificates are located in ## /usr/share/ca-certificates/mozilla/ .You can concatenate ## them with the command : ## for cert in /usr/share/ca-certificates/mozilla/*crt; \ ## do cat $cert >> mozcerts.pem; done ## ## You may want to bundle *only* your server certificate/your ca ## certificate with your application to make it more secure. conn = HTTPSConnection(host, ca_certs) else: conn = httplib.HTTPConnection(host, port) return conn host = host or config.pytheon.api_host or "api.pytheon.net:443" try: conn = get_conn(host) conn.request(method, path, params, headers) resp = conn.getresponse() except socket.error: raise raise OSError("Unable to contact %s" % host) if resp.status == 401 and cookie_auth is not None: log.info("Invalid password or session is expired") headers.update(auth_basic(retry=True)) del headers["Cookie"] conn = get_conn(host) conn.request(method, path, params, headers) resp = conn.getresponse() data = resp.read() if resp.status != 200: log.error("%d - %s " % (resp.status, resp.reason)) if resp.status == 500: sys.exit(1) save_cookie(resp.getheaders()) if resp.getheader("Content-Type", "text/plain") == "application/json": return json.loads(data) return data
def test_cli(self): out = run('register', '-e', self.email) self.assertIn('check', out.lower()) u = self.get_user().fetchone() out = run('register', '-e', self.email) self.assertIn(' is already used', out.lower()) # avoid prompt os.environ['TEST_PASSWORD'] = '******' key = '%s/%s' % (u.id, u.register_key) out = run('register', '-e', self.email, '-k', key) self.assertIn('password set', out.lower()) # init git server gitolite = join(self.home, '.gitolite') os.makedirs(gitolite) self.writeFile(''' [git] url = %(repos)s ''' % dict(repos=join(self.home, 'repos')), gitolite, 'pytheon.ini') repo = join(self.home, 'repos', 'test-project.git') os.makedirs(repo) self.runCommand(['git', 'init', '--bare', repo]) self.writeFile('''#!/bin/sh %s --app-name=www --git-url=%s --testing ''' % (post_receive, repo), repo, 'hooks', 'post-receive') self.runCommand(['chmod', '+x', join(repo, 'hooks', 'post-receive')]) os.environ['PYTHEON_REMOTE'] = join(self.home, 'repos', '%(project_name)s.git') # init git config and project repo self.runCommand(['git', 'init']) self.runCommand(['git', 'config', 'user.name', '"Your Name"']) self.runCommand(['git', 'config', 'user.email', '*****@*****.**']) self.writeFile('''DATABASES = {}; URLS='urls.py''', 'settings.py') self.runCommand(['git', 'add', '-A']) self.runCommand(['git', 'commit', '-m', 'changes']) # create project on pytheon with invalid name #out = run('create', '-n', 'test_project') #self.assertIn('Applications names must be composed of only letters, ' # 'digits and hyphens and cannot start with a hyphen', out) # create project on pytheon out = run('create', '-n', 'test-project') self.assertIn('Application test-project created', out) # now we can use the cookie config = utils.user_config() self.assertIn('auth_cookie', config.pytheon) del os.environ['TEST_PASSWORD'] # deploy self.runCommand(['git', 'status']) run('deploy') # api calls out = run('apps', '-l') self.assertIn('- test-project', out) out = run('addons', '--all') self.assertIn('- mysql', out) out = run('addons', '-l') self.assertIn('- No addons', out) out = run('addons', '--add', 'mysql:premium') self.assertIn('You cannot access this resource', out) resp = self.wsgi_app.get('/update_model', dict(model='User', field='email', value=self.email, payment_ok='true')) out = run('addons', '--add', 'mysql:basic') self.assertIn('Addon added', out) out = run('addons', '--upgrade', 'mysql:premium') self.assertIn('Addon plan changed', out) out = run('addons', '--delete', 'mysql') self.assertIn('Addon removed', out) out = run('addons', '--add', 'mysql:premium') self.assertIn('Addon added', out) out = run('addons', '-l') self.assertIn('- mysql', out) out = run('apps', '--delete', 'test-project') self.assertIn('Application deleted', out) out = run('apps', '-l') self.assertIn('- No application', out) ## Test ssh keys key_file = self.writeFile("ssh-rsa sdfsdfsdf\n", self.wd, "pytheon-key1") key_file2 = self.writeFile("ssh-rsa 2sdfsdfsdf\n", self.wd, "pytheon-key2") key_file3 = self.writeFile("ssh-rsa 3sdfsdfsdf\n", self.wd, "pytheon-key3") key_file4 = self.writeFile("ssh-rsa 4sdfsdfsdf\n", self.wd, "pytheon-key4") fake_key = self.writeFile("fake file\n", self.wd, "pytheon-fake-key") out = run('add_key', fake_key) #self.assertIn('File %s does not seems to be a public key.', out) out = run('add_key', key_file) self.assertIn('Key added', out) out = run('add_key', key_file2) self.assertIn('Key added', out) out = run('add_key', key_file) self.assertIn('Key added', out) out = run('add_key', '-n', '*****@*****.**', key_file3) self.assertIn('Key added', out) out = run('add_key', '-n', '*****@*****.**', key_file4) self.assertIn('A key with this name already exists', out)
from __future__ import with_statement import os import os.path import sys import logging as log import functools from pytheon import http from pytheon import utils from pytheon.utils import Config from optparse import OptionParser # totot commands = [] project_commands = [] filename = os.path.expanduser('~/.pytheonrc') global_config = utils.user_config() def with_project(func): @functools.wraps(func) def wrapped(parser, options, args): config = utils.project_config() if not os.path.isfile(config._filename): parser.error('It look like you are not in a valid pytheon project') elif not config.deploy.project_name: parser.error('It look like you are not in a valid pytheon project') return func(parser, options, args, config) wrapped.project_command = True return wrapped