def credentials_from(self, directory_structure, chains, complain_if_missing=False, typ="amazon"): """Yield the credentials from the [location, <repo>, <account>, <user>] chains that are provided""" if not chains and complain_if_missing: raise CredoError("Didn't find any credentials!") for chain in chains: location, repo, account, user = chain credentials_location = os.path.join(location, "credentials.json") if not os.path.exists( credentials_location) and complain_if_missing: raise CredoError( "Trying to find credentials that don't exist!", repo=repo, account=account, user=user) credential_path = CredentialPath(self.crypto) credential_path.fill_out(directory_structure, repo, account, user, typ=typ) credentials = credential_path.credentials credentials.load() yield credentials
def find_config_file(self, config_file=Unspecified): """Find a config file, use the one given if specified""" if config_file in (None, Unspecified): credo_home = os.path.expanduser("~/.credo") config_file = os.path.join(credo_home, "config.json") if os.path.exists(config_file): try: current = json.load(open(config_file)) except (TypeError, ValueError) as error: raise CredoError("Couldn't parse the config file", location=config_file, error=error) else: current = {} if "root_dir" not in current: root_dir = os.path.join(os.path.dirname(config_file), "repos") current["root_dir"] = root_dir if not os.path.exists(os.path.dirname(config_file)): os.makedirs(os.path.dirname(config_file)) json.dump(current, open(config_file, "w")) else: root_dir = current["root_dir"] return config_file, root_dir
def do_switch(credo, port=80, host="169.254.169.254", **kwargs): url = "http://{0}:{1}/latest/meta-data/switch/".format(host, port) chosen = credo._chosen = credo.make_chosen(rotate=False) if not isinstance(chosen, SamlCredentials): raise CredoError("Switch only supports idp roles") request = {"credentials": chosen} while True: response = requests.post( url, data=pickle.dumps(request), headers={"Content-Type": "application/octet-stream"}) if response.status_code == 500: error = response.json()["error"] if error in ("NEED_AUTH", "BAD_PASSWORD"): if error == "BAD_PASSWORD": log.error("Password was incorrect") password = get_response("Password for idp user {0}".format( chosen.keys.idp_username), password=True) request["basic_auth"] = base64.b64encode("{0}:{1}".format( chosen.keys.idp_username, password).encode('utf-8')) else: break else: break print("{0}: {1}".format(response.status_code, response.text))
def start(self): try: from tornado.httpserver import HTTPServer from tornado.wsgi import WSGIContainer from tornado.ioloop import IOLoop except ImportError: raise CredoError("Please pip install tornado") log.info("Starting server on http://%s:%s", self.host, self.port) http_server = HTTPServer(WSGIContainer(self.app)) http_server.listen(self.port, self.host) IOLoop.instance().start()
def app(self): try: from flask import Flask except ImportError: raise CredoError("Please pip install flask") if getattr(self, "_app", None) is None: self._app = Flask("credo.server") self._app.secret_key = uuid1() self.register_routes(self._app) return self._app
def exports(self, role): """Get exports for this account""" if role.role_arn not in [r.role_arn for r in self.arns]: raise CredoError( "Your user doesn't have specified account anymore", username=self.keys.idp_username, provider=self.keys.provider, wanted=self.keys.role.role_arn) result = self.get_result(role) creds = result.credentials return [("AWS_ACCESS_KEY_ID", creds.access_key), ("AWS_SECRET_ACCESS_KEY", creds.secret_key), ("AWS_SESSION_TOKEN", creds.session_token), ("AWS_SECURITY_TOKEN", creds.session_token)]
def determine_driver(location, version_type=None): """Determine what versioning driver to use for some location""" if version_type == "git" or os.path.exists(os.path.join(location, ".git")): if pygit2 is not None: from credo.versioning.git import GitDriver return GitDriver(location) else: log.warning("Can't import pygit2, so not doing any git things") version_type = None if version_type is None: from credo.versioning.base import NoVersioningDriver return NoVersioningDriver(location) raise CredoError("Unknown versioning type", version_type=version_type)
def normalise_half_life(half_life, access_key=None): if half_life is None: if access_key is None: return half_life = ask_user_for_half_life(access_key) if isinstance(half_life, string_types) and not half_life.isdigit(): if half_life == "hour": half_life = 60 * 60 elif half_life == "day": half_life = 60 * 60 * 24 elif half_life == "week": half_life = 60 * 60 * 24 * 7 else: raise CredoError("Unknown half life value", half_life=half_life) return half_life
def make_credo(self, cred_args, expected_action): """Make a Credo object that knows things""" cred_parser = self.cred_parser() cred_args = cred_parser.parse_args(cred_args) setup_logging(verbose=cred_args.verbose, boto_debug=cred_args.boto_debug) if cred_args.action != expected_action: raise CredoError( "Well this is weird, I thought the action was different than it turned out to be", expected=expected_action, parsed=cred_args.action) credo = Credo() credo.setup(**vars(cred_args)) return credo
def find_credential_path_part(self, all_accounts=False, all_users=False, find_user=False, typ=None): """Find a repository, account or user""" directory_structure, shortened = explorer.find_repo_structure( self.root_dir, levels=3) mask = explorer.filtered(shortened, [self.repo, self.account, self.user]) asker = ask_for_choice user_title = explorer.Stop if all_users else "User" account_title = explorer.Stop if all_accounts else "Account" want_any_after = 1 if find_user: want_any_after = None explorer.narrow(mask, ["Repository", account_title, user_title], asker, want_any_after=want_any_after) if not mask: raise CredoError("Couldn't find anything to work with") repo = mask.keys()[0] user = None account = None if mask[repo]: account = mask[repo].keys()[0] if mask[repo][account]: user = mask[repo][account].keys()[0] credential_path = CredentialPath(self.crypto) credential_path.fill_out(directory_structure, repo, account, user, typ=typ) if credential_path.user: return credential_path.user elif credential_path.account: return credential_path.account else: return credential_path.repository
def do_output_extension(credo, output, **kwargs): """Output the Chrome extension for the metadata magic server.""" source = pkg_resources.resource_filename("credo", "ext") try: shutil.copytree(source, output) except OSError as error: raise CredoError("Failed to copy directory", source=source, output=output, error=error) print( dedent(""" Congratulations, you know have the extension. - Please go into Chrome. - Go to chrome://extensions. - Enable developer mode. - Load unpacked extension. - Choose {0} """.format(output)))
def fingerprinted(self, decrypted_vals, **info): """ Return dictionary of {<fingerprint>: {secret: <secret>, data:<data>, verifier:<verifier>} Where <secret> is a randomly generated secret <data> is the original data encrypted with AES using that secret and <verifier> is a signature that says the secret was created using this private key Decrypted_vals is assumed to be a json dictionary """ if not isinstance(decrypted_vals, dict): raise CredoError( "Fingerprinted should only be called with dictionaries", got_type=type(decrypted_vals)) try: data_str = json.dumps(decrypted_vals, sort_keys=True) except (ValueError, TypeError) as error: raise InvalidData("Couldn't dump values for encryption", error_type=error.__class__.__name__, error=error, **info) result = {} for fingerprint in self.public_key_fingerprints: secret = self.generate_secret() verifier = self.create_signature(secret) encrypted_data = self.encrypt_with_secret(data_str, secret) log.info("Encrypting credentials using AES\tfingerprint=%s", fingerprint) encrypted_secret = self.keys.encrypt( secret, fingerprint, key_fingerprint=fingerprint, action="encrypting", value="Secret for encrypting with") result[fingerprint] = dict(secret=encrypted_secret, verifier=verifier, data=encrypted_data) return result
def folder(value): location = os.path.expanduser(value) if not os.path.isfile(location): raise CredoError("Please specify a config file that exists", specified=location) return location