def _IsServiceAccountCredentials(cred): if creds.IsOauth2ClientCredentials(cred): return creds.CredentialType.FromCredentials( cred) == creds.CredentialType.SERVICE_ACCOUNT else: return creds.CredentialTypeGoogleAuth.FromCredentials( cred) == creds.CredentialTypeGoogleAuth.SERVICE_ACCOUNT
def GetCredentials(access_boundary_json): """Get an access token for the user's current credentials. Args: access_boundary_json: JSON string holding the definition of the access boundary to apply to the credentials. Raises: PersonalAuthError: If no access token could be fetched for the user. Returns: An access token for the user. """ cred = c_store.Load(None, allow_account_impersonation=True, use_google_auth=True) c_store.Refresh(cred) if c_creds.IsOauth2ClientCredentials(cred): token = cred.access_token else: token = cred.token if not token: raise exceptions.PersonalAuthError( 'No access token could be obtained from the current credentials.') return _DownscopeCredentials(token, access_boundary_json)
def Run(self, args): """Run the helper command.""" cred = c_store.Load( args.account, allow_account_impersonation=True, use_google_auth=True) c_store.Refresh(cred) if c_creds.IsOauth2ClientCredentials(cred): token = cred.access_token else: token = cred.token if not token: raise auth_exceptions.InvalidCredentialsError( 'No access token could be obtained from the current credentials.') return DummyCredentials(token)
def WriteGcloudCredentialsToADC(creds, add_quota_project=False): """Writes gclouds's credential from auth login to ADC json.""" if c_creds.IsOauth2ClientCredentials(creds): cred_type = c_creds.CredentialType.FromCredentials(creds).key else: cred_type = c_creds.CredentialTypeGoogleAuth.FromCredentials(creds).key if cred_type != c_creds.USER_ACCOUNT_CREDS_NAME: log.warning('Credentials cannot be written to application default ' 'credentials because it is not a user credential.') return PromptIfADCEnvVarIsSet() if add_quota_project: c_creds.ADC(creds).DumpExtendedADCToFile() else: c_creds.ADC(creds).DumpADCToFile()
def FakeRefresh(cred, http=None, is_impersonated_credential=False, include_email=False, gce_token_format='standard', gce_include_license=False): del http del is_impersonated_credential del include_email del gce_token_format del gce_include_license if cred: if c_creds.IsOauth2ClientCredentials(cred): cred.token_response = {'id_token': fake_id_token} else: cred.id_tokenb64 = fake_id_token
def RevokeCredentials(credentials): """Revokes the token on the server. Args: credentials: user account credentials from either google-auth or oauth2client. Raises: RevokeError: If credentials to revoke is not user account credentials. """ if not c_creds.IsUserAccountCredentials(credentials): raise RevokeError( 'The token cannot be revoked from server because it is ' 'not user account credentials.') http_client = http.Http() if c_creds.IsOauth2ClientCredentials(credentials): credentials.revoke(http_client) else: credentials.revoke(http.GoogleAuthRequest(http_client))
def Run(self, args): """Run the helper command.""" cred = c_store.Load(args.account, allow_account_impersonation=True, use_google_auth=True) if args.scopes: cred_type = c_creds.CredentialTypeGoogleAuth.FromCredentials(cred) if cred_type not in [ c_creds.CredentialTypeGoogleAuth.USER_ACCOUNT, c_creds.CredentialTypeGoogleAuth.SERVICE_ACCOUNT ]: # TODO(b/223649175): Add support for other credential types(e.g GCE). log.warning( '`--scopes` flag may not working as expected and will be ignored ' 'for account type {}.'.format(cred_type.key)) scopes = args.scopes + [ auth_util.OPENID, auth_util.USER_EMAIL_SCOPE ] # non user account credential types if isinstance(cred, credentials.Scoped): cred = cred.with_scopes(scopes) else: requested_scopes = set(args.scopes) trusted_scopes = set(config.CLOUDSDK_SCOPES) if not requested_scopes.issubset(trusted_scopes): raise c_exc.InvalidArgumentException( '--scopes', 'Invalid scopes value. Please make sure the scopes are from [{0}]' .format(config.CLOUDSDK_SCOPES)) # pylint:disable=protected-access cred._scopes = scopes c_store.Refresh(cred) if c_creds.IsOauth2ClientCredentials(cred): token = cred.access_token else: token = cred.token if not token: raise auth_exceptions.InvalidCredentialsError( 'No access token could be obtained from the current credentials.' ) return FakeCredentials(token)
def __init__(self, enable_resource_quota=True, force_resource_quota=False, allow_account_impersonation=True): super(StoredCredentials, self).__init__() self.stored_credentials = store.LoadIfEnabled( allow_account_impersonation=allow_account_impersonation, use_google_auth=True) if self.stored_credentials is None: raise MissingStoredCredentialsError() if creds.IsOauth2ClientCredentials(self.stored_credentials): self.token = self.stored_credentials.access_token else: self.token = self.stored_credentials.token if enable_resource_quota or force_resource_quota: self.quota_project_id = creds.GetQuotaProject( self.stored_credentials, force_resource_quota) else: self.quota_project_id = None
def Refresh(credentials, http_client=None, is_impersonated_credential=False, include_email=False, gce_token_format='standard', gce_include_license=False): """Refresh credentials. Calls credentials.refresh(), unless they're SignedJwtAssertionCredentials. If the credentials correspond to a service account or impersonated credentials issue an additional request to generate a fresh id_token. Args: credentials: oauth2client.client.Credentials or google.auth.credentials.Credentials, The credentials to refresh. http_client: httplib2.Http, The http transport to refresh with. is_impersonated_credential: bool, True treat provided credential as an impersonated service account credential. If False, treat as service account or user credential. Needed to avoid circular dependency on IMPERSONATION_TOKEN_PROVIDER. include_email: bool, Specifies whether or not the service account email is included in the identity token. Only applicable to impersonated service account. gce_token_format: str, Specifies whether or not the project and instance details are included in the identity token. Choices are "standard", "full". gce_include_license: bool, Specifies whether or not license codes for images associated with GCE instance are included in their identity tokens. Raises: TokenRefreshError: If the credentials fail to refresh. TokenRefreshReauthError: If the credentials fail to refresh due to reauth. """ if c_creds.IsOauth2ClientCredentials(credentials): _Refresh(credentials, http_client, is_impersonated_credential, include_email, gce_token_format, gce_include_license) else: _RefreshGoogleAuth(credentials, http_client, is_impersonated_credential, include_email, gce_token_format, gce_include_license)
def generate_login_token_from_gcloud_auth(scopes): """Genearete a down-coped access token with given scopes for IAM DB authentication from gcloud credentials. Args: scopes: scopes to be included in the down-scoped token. Returns: Down-scoped access token. """ cred = c_store.Load(allow_account_impersonation=True, use_google_auth=True) cred = _downscope_credential(cred, scopes) c_store.Refresh(cred) if c_creds.IsOauth2ClientCredentials(cred): token = cred.access_token else: token = cred.token if not token: raise auth_exceptions.InvalidCredentialsError( 'No access token could be obtained from the current credentials.') return token
def __init__(self, cred): if c_creds.IsOauth2ClientCredentials(cred): self.access_token = cred.access_token expiry = getattr(cred, 'token_expiry', None) else: self.access_token = cred.token expiry = getattr(cred, 'expiry', None) self.token_expiry = ( expiry.strftime(Credential._EXPIRY_FORMAT) if expiry else None) # The cache blanks the token_response field, so if it's present that # indicates there's either no cache entry, or we just refreshed tokens. # Either way, the response is fresher. token_response = getattr(cred, 'token_response', None) if token_response: id_token = token_response.get('id_token', None) else: id_token = getattr(cred, 'id_tokenb64', None) self.id_token = id_token
def Store(credentials, account=None, scopes=None): """Store credentials according for an account address. gcloud only stores user account credentials, service account credentials and p12 service account credentials. GCE, IAM impersonation, and Devshell credentials are generated in runtime. Args: credentials: oauth2client.client.Credentials or google.auth.credentials.Credentials, The credentials to be stored. account: str, The account address of the account they're being stored for. If None, the account stored in the core.account property is used. scopes: tuple, Custom auth scopes to request. By default CLOUDSDK_SCOPES are requested. Raises: NoActiveAccountException: If account is not provided and there is no active account. """ if c_creds.IsOauth2ClientCredentials(credentials): cred_type = c_creds.CredentialType.FromCredentials(credentials) else: cred_type = c_creds.CredentialTypeGoogleAuth.FromCredentials( credentials) if not cred_type.is_serializable: return if not account: account = properties.VALUES.core.account.Get() if not account: raise NoActiveAccountException() store = c_creds.GetCredentialStore() store.Store(account, credentials) _LegacyGenerator(account, credentials, scopes).WriteTemplate()
def _RefreshIfAlmostExpire(credentials): """Refreshes credentials if they are expired or will expire soon. For oauth2client credentials, refreshes if they expire within the expiry window. oauth2client credentials may be converted to google-auth credentials later in the call stack. The latter do not currently support reauth. So it is essential to ensure oauth2client credentials will remain valid during a command. For google-auth credentials, refreshes if they are expired. Args: credentials: google.auth.credentials.Credentials or client.OAuth2Credentials, the credentials to refresh. """ if c_creds.IsOauth2ClientCredentials(credentials): almost_expire = not credentials.token_expiry or _TokenExpiresWithinWindow( _CREDENTIALS_EXPIRY_WINDOW, credentials.token_expiry) else: almost_expire = not credentials.valid if almost_expire: Refresh(credentials)
def _is_oauth2client(self): return c_creds.IsOauth2ClientCredentials(self.credentials)
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, use_google_auth=True) 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=six.text_type(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 if c_creds.IsOauth2ClientCredentials(cred): access_token = cred.access_token else: access_token = cred.token sys.stdout.write( textwrap.dedent("""\ username={username} password={password} """).format(username=sent_account, password=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)
def _Refresh(cred): if c_creds.IsOauth2ClientCredentials(cred): cred.access_token = _ACCESS_TOKEN else: cred.token = _ACCESS_TOKEN