From 7af61698522568680b74698751325044e6b10736 Mon Sep 17 00:00:00 2001 From: Aravind Vasudevan Date: Mon, 9 Jan 2023 23:15:15 +0000 Subject: [PATCH] Update gsutil.py to use luci-auth for authentication The change updates gsutil.py to internally use luci-auth for authentication. It redirects `gsutil.py config` to `luci-auth login` and wraps gsutil.py calls using `luci-auth context`. The change is mainly done to ensure users have a way to authenticate once OOB authentication flow is deprecated. This patch falls back to using the .boto file when that is provided. Design Document: go/gsutil-oauth-issue-resolved Bug: 959170, 1359383 Change-Id: Icc6df1d8b93424ac0f6e2df84afdebc869763ede Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4109192 Commit-Queue: Aravind Vasudevan Reviewed-by: Joanna Wang Reviewed-by: Vadim Shtayura --- gsutil.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/gsutil.py b/gsutil.py index 4b2867b066..3bff1888c3 100755 --- a/gsutil.py +++ b/gsutil.py @@ -5,6 +5,7 @@ """Run a pinned gsutil.""" +from __future__ import print_function import argparse import base64 @@ -36,6 +37,15 @@ IS_WINDOWS = os.name == 'nt' VERSION = '4.68' +# Environment variable to enable LUCI auth feature. +GSUTIL_ENABLE_LUCI_AUTH = 'GSUTIL_ENABLE_LUCI_AUTH' + +# Google OAuth Context required by gsutil. +LUCI_AUTH_SCOPES = [ + 'https://www.googleapis.com/auth/devstorage.full_control', + 'https://www.googleapis.com/auth/userinfo.email', +] + class InvalidGsutilError(Exception): pass @@ -138,7 +148,54 @@ def ensure_gsutil(version, target, clean): return gsutil_bin +def _is_luci_context(): + """Returns True if the script is run within luci-context""" + luci_context_env = os.getenv('LUCI_CONTEXT') + if not luci_context_env: + return False + + try: + with open(luci_context_env) as f: + luci_context_json = json.load(f) + return 'local_auth' in luci_context_json + except (ValueError, FileNotFoundError): + return False + + +def luci_context(cmd): + """Helper to call`luci-auth context`.""" + return _luci_auth_cmd('context', wrapped_cmds=cmd) + + +def luci_login(): + """Helper to run `luci-auth login`.""" + _luci_auth_cmd('login') + + +def _luci_auth_cmd(luci_cmd, wrapped_cmds=None): + """Helper to call luci-auth command.""" + print('WARNING: OOB authentication flow has been deprecated.') + print('Using luci-auth login instead.') + print('Override luci-auth by setting `BOTO_CONFIG` or ' + '`AWS_CREDENTIAL_FILE` in your env.\n') + + cmd = ['luci-auth', luci_cmd, '-scopes', ' '.join(LUCI_AUTH_SCOPES)] + if wrapped_cmds: + cmd += ['--'] + wrapped_cmds + + return _run_subprocess(cmd) + + +def _run_subprocess(cmd): + """Wrapper to run the given command within a subprocess.""" + return subprocess.call(cmd, shell=IS_WINDOWS) + + def run_gsutil(target, args, clean=False): + # Redirect gsutil config calls to luci-auth. + if os.getenv(GSUTIL_ENABLE_LUCI_AUTH) == '1' and 'config' in args: + return luci_login() + gsutil_bin = ensure_gsutil(VERSION, target, clean) args_opt = ['-o', 'GSUtil:software_update_check_period=0'] @@ -167,7 +224,14 @@ def run_gsutil(target, args, clean=False): '--', gsutil_bin ] + args_opt + args - return subprocess.call(cmd, shell=IS_WINDOWS) + + # Bypass luci-auth when run within a bot or .boto file is set. + if (os.getenv(GSUTIL_ENABLE_LUCI_AUTH) != '1' or _is_luci_context() + or os.getenv('SWARMING_HEADLESS') == '1' or os.getenv('BOTO_CONFIG') + or os.getenv('AWS_CREDENTIAL_FILE')): + return _run_subprocess(cmd) + + return luci_context(cmd) def parse_args():