mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 10:41:31 +00:00
[gerrit_util] Add fallback if missing Gerrit account
Bug: b/366261039 Change-Id: I7d22c4f03ad9bd837190dee7a511af3437a30434 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5869050 Reviewed-by: Josip Sokcevic <sokcevic@chromium.org> Commit-Queue: Allen Li <ayatane@chromium.org>
This commit is contained in:
7
auth.py
7
auth.py
@@ -48,10 +48,15 @@ class Token(collections.namedtuple('Token', [
|
||||
class LoginRequiredError(Exception):
|
||||
"""Interaction with the user is required to authenticate."""
|
||||
def __init__(self, scopes=OAUTH_SCOPE_EMAIL):
|
||||
self.scopes = scopes
|
||||
msg = ('You are not logged in. Please login first by running:\n'
|
||||
' luci-auth login -scopes "%s"' % scopes)
|
||||
' %s' % self.login_command)
|
||||
super(LoginRequiredError, self).__init__(msg)
|
||||
|
||||
@property
|
||||
def login_command(self) -> str:
|
||||
return 'luci-auth login -scopes "%s"' % self.scopes
|
||||
|
||||
|
||||
def has_luci_context_local_auth():
|
||||
"""Returns whether LUCI_CONTEXT should be used for ambient authentication."""
|
||||
|
||||
@@ -287,6 +287,7 @@ class _Authenticator(object):
|
||||
# GCE detection can't distinguish cloud workstations.
|
||||
GceAuthenticator(),
|
||||
LuciAuthAuthenticator(),
|
||||
NoAuthenticator(),
|
||||
]
|
||||
if skip_sso:
|
||||
LOGGER.debug(
|
||||
@@ -812,6 +813,10 @@ class LuciContextAuthenticator(_Authenticator):
|
||||
self._authenticator = auth.Authenticator(' '.join(
|
||||
[auth.OAUTH_SCOPE_EMAIL, auth.OAUTH_SCOPE_GERRIT]))
|
||||
|
||||
@property
|
||||
def luci_auth(self) -> auth.Authenticator:
|
||||
return self._authenticator
|
||||
|
||||
def authenticate(self, conn: HttpConn):
|
||||
conn.req_headers[
|
||||
'Authorization'] = f'Bearer {self._authenticator.get_access_token().token}'
|
||||
@@ -828,10 +833,65 @@ class LuciAuthAuthenticator(LuciContextAuthenticator):
|
||||
non-google.com developer credentials.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def gerrit_account_exists(cls, host: str) -> bool:
|
||||
"""Return True if the Gerrit account exists.
|
||||
|
||||
This checks the user currently logged in with luci-auth.
|
||||
If the user is not logged in with luci-auth, returns False.
|
||||
|
||||
This method caches positive results in the user's Git config.
|
||||
"""
|
||||
cwd = os.getcwd()
|
||||
LOGGER.debug("Checking Gerrit account existence for %r", host)
|
||||
hosts = scm.GIT.GetConfigList(cwd, 'depot-tools.hosthasaccount')
|
||||
if host in hosts:
|
||||
# If a user deletes their Gerrit account, then this cache
|
||||
# might be stale. This should be a rare case and a user can
|
||||
# just delete this from their Git config.
|
||||
LOGGER.debug("Using cached account existence for Gerrit host %r",
|
||||
host)
|
||||
return True
|
||||
try:
|
||||
info = GetAccountDetails(host, authenticator=cls())
|
||||
except auth.LoginRequiredError:
|
||||
LOGGER.debug(
|
||||
"Cannot check Gerrit account existence; missing luci-auth login"
|
||||
)
|
||||
return False
|
||||
except GerritError as e:
|
||||
if e.http_status == 400:
|
||||
# This is likely because the user doesn't have an
|
||||
# account on the Gerrit host.
|
||||
LOGGER.debug(
|
||||
"Gerrit account check returned 400; likely account missing")
|
||||
return False
|
||||
raise
|
||||
if 'email' not in info:
|
||||
LOGGER.debug("Gerrit account does not exist on %r", host)
|
||||
return False
|
||||
LOGGER.debug("Gerrit account exists on %r", host)
|
||||
scm.GIT.SetConfig(cwd, 'depot-tools.hostHasAccount', host, append=True)
|
||||
return True
|
||||
|
||||
def is_applicable(self, *, conn: Optional[HttpConn] = None):
|
||||
return self.gerrit_account_exists(conn.host)
|
||||
|
||||
|
||||
class NoAuthenticator(_Authenticator):
|
||||
"""_Authenticator implementation that does no auth.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def is_applicable(*, conn: Optional[HttpConn] = None):
|
||||
return True
|
||||
|
||||
def authenticate(self, conn: HttpConn):
|
||||
pass
|
||||
|
||||
def debug_summary_state(self) -> str:
|
||||
return ''
|
||||
|
||||
|
||||
class ChainedAuthenticator(_Authenticator):
|
||||
"""_Authenticator that delegates to others in sequence.
|
||||
|
||||
@@ -36,7 +36,7 @@ class ConfigChanger(object):
|
||||
#
|
||||
# Increment this when making changes to the config, so that reliant
|
||||
# code can determine whether the config needs to be re-applied.
|
||||
VERSION: int = 2
|
||||
VERSION: int = 3
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -130,6 +130,9 @@ class ConfigChanger(object):
|
||||
email: str = scm.GIT.GetConfig(cwd, 'user.email') or ''
|
||||
if gerrit_util.ShouldUseSSO(gerrit_host, email):
|
||||
return ConfigMode.NEW_AUTH_SSO
|
||||
if not gerrit_util.LuciAuthAuthenticator.gerrit_account_exists(
|
||||
gerrit_host):
|
||||
return ConfigMode.NO_AUTH
|
||||
return ConfigMode.NEW_AUTH
|
||||
|
||||
def apply(self, cwd: str) -> None:
|
||||
|
||||
17
git_cl.py
17
git_cl.py
@@ -3881,7 +3881,22 @@ def CMDcreds_check(parser, args):
|
||||
_, _ = parser.parse_args(args)
|
||||
|
||||
if newauth.Enabled():
|
||||
git_auth.Configure(os.getcwd(), Changelist())
|
||||
cl = Changelist()
|
||||
git_auth.Configure(os.getcwd(), cl)
|
||||
# Perform some advisory checks
|
||||
email = scm.GIT.GetConfig(os.getcwd(), 'user.email') or ''
|
||||
if not gerrit_util.ShouldUseSSO(cl.GetGerritHost(), email):
|
||||
a = gerrit_util.LuciAuthAuthenticator()
|
||||
try:
|
||||
a.luci_auth.get_access_token()
|
||||
except auth.LoginRequiredError as e:
|
||||
print('NOTE: You are not logged in with luci-auth.')
|
||||
print(
|
||||
'You may not be able to perform some actions without logging in.'
|
||||
)
|
||||
print('If you wish to log in, run:')
|
||||
print(' ' + e.login_command)
|
||||
print('and re-run this command.')
|
||||
return 0
|
||||
if newauth.ExplicitlyDisabled():
|
||||
git_auth.ClearRepoConfig(os.getcwd(), Changelist())
|
||||
|
||||
Reference in New Issue
Block a user