def _ParseInput(self): """Parse the fields from stdin. Returns: {str: str}, The parsed parameters given on stdin. """ info = {} for line in sys.stdin: if _BLANK_LINE_RE.match(line): continue match = _KEYVAL_RE.match(line) if not match: raise auth_exceptions.GitCredentialHelperError( 'Invalid input line format: [{format}].'.format( format=line.rstrip('\n'))) key, val = match.groups() info[key] = val.strip() if 'protocol' not in info: raise auth_exceptions.GitCredentialHelperError( 'Required key "protocol" missing.') if 'host' not in info: raise auth_exceptions.GitCredentialHelperError( 'Required key "host" missing.') if info.get('protocol') != 'https': raise auth_exceptions.GitCredentialHelperError( 'Invalid protocol [{p}]. "https" expected.'.format( p=info.get('protocol'))) return info
def ValidateHost(host): if args.ignore_unknown: return if host in credentialed_domains: return for suffix in credentialed_domains_suffix: if host.endswith(suffix): return raise auth_exceptions.GitCredentialHelperError( 'Unknown host [{host}].'.format(host=host))
def Run(self, args): """Run the helper command.""" if args.method not in GitHelper.METHODS: if args.ignore_unknown: return raise auth_exceptions.GitCredentialHelperError( 'Unexpected method [{meth}]. One of [{methods}] expected.'. format(meth=args.method, methods=', '.join(GitHelper.METHODS))) info = self._ParseInput() credentialed_domains = [ 'source.developers.google.com', GitHelper.GOOGLESOURCE, # Requires a different username value. ] credentialed_domains_suffix = [ '.' + GitHelper.GOOGLESOURCE, ] extra = properties.VALUES.core.credentialed_hosted_repo_domains.Get() if extra: credentialed_domains.extend(extra.split(',')) host = info.get('host') def _ValidateHost(host): if host in credentialed_domains: return True for suffix in credentialed_domains_suffix: if host.endswith(suffix): return True return False if not _ValidateHost(host): if not args.ignore_unknown: raise auth_exceptions.GitCredentialHelperError( 'Unknown host [{host}].'.format(host=host)) return if args.method == GitHelper.GET: account = properties.VALUES.core.account.Get() try: cred = c_store.Load(account) c_store.Refresh(cred) except c_store.Error as e: sys.stderr.write( textwrap.dedent("""\ ERROR: {error} Run 'gcloud auth login' to log in. """.format(error=str(e)))) return self._CheckNetrc() # For googlesource.com, any username beginning with "git-" is accepted # and the identity of the user is extracted from the token server-side. if (host == GitHelper.GOOGLESOURCE or host.endswith('.' + GitHelper.GOOGLESOURCE)): sent_account = 'git-account' else: sent_account = account sys.stdout.write( textwrap.dedent("""\ username={username} password={password} """).format(username=sent_account, password=cred.access_token)) elif args.method == GitHelper.STORE: # On OSX, there is an additional credential helper that gets called before # ours does. When we return a token, it gets cached there. Git continues # to get it from there first until it expires. That command then fails, # and the token is deleted, but it does not retry the operation. The next # command gets a new token from us and it starts working again, for an # hour. This erases our credential from the other cache whenever 'store' # is called on us. Because they are called first, the token will already # be stored there, and so we can successfully erase it to prevent caching. if (platforms.OperatingSystem.Current() == platforms.OperatingSystem.MACOSX): log.debug('Clearing OSX credential cache.') try: input_string = 'protocol={protocol}\nhost={host}\n\n'.format( protocol=info.get('protocol'), host=info.get('host')) log.debug('Calling erase with input:\n%s', input_string) p = subprocess.Popen( ['git-credential-osxkeychain', 'erase'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = p.communicate(input_string) if p.returncode: log.debug( 'Failed to clear OSX keychain:\nstdout: {%s}\nstderr: {%s}', out, err) # pylint:disable=broad-except, This can fail and should only be done as # best effort. except Exception as e: log.debug('Failed to clear OSX keychain', exc_info=True)