Beispiel #1
0
  def testServiceAccountImpersonation(self):
    # This is the logged in credential, but it will not be used to make the call
    # because of the impersonation.
    store.Store(self.fake_cred)
    properties.VALUES.auth.impersonate_service_account.Set('*****@*****.**')

    # Expect a call to get a temp access token for impersonation.
    fake_token = 'impersonation-token'
    self.mock_client.projects_serviceAccounts.GenerateAccessToken.Expect(
        self.gen_request_msg(
            name='projects/-/serviceAccounts/[email protected]',
            generateAccessTokenRequest=self.messages.GenerateAccessTokenRequest(
                scope=config.CLOUDSDK_SCOPES)),
        self.messages.GenerateAccessTokenResponse(
            accessToken=fake_token, expireTime='2016-01-08T00:00:00Z')
    )

    request_mock = self.StartObjectPatch(
        httplib2.Http, 'request',
        return_value=(httplib2.Response({'status': 200}), b''))
    try:
      store.IMPERSONATION_TOKEN_PROVIDER = (
          util.ImpersonationAccessTokenProvider())
      http.Http().request('http://foo.com', 'GET', None, {})
      access_token = request_mock.call_args[0][3][b'Authorization']
      self.assertEqual(access_token, b'Bearer ' + fake_token.encode('utf8'))
    finally:
      store.IMPERSONATION_TOKEN_PROVIDER = None
Beispiel #2
0
    def SetUp(self):
        properties.VALUES.core.account.Set('fakeuser')
        fake_creds = self.MakeUserAccountCredentialsGoogleAuth()
        fake_creds.token = 'access-token'
        store.Store(fake_creds)
        properties.VALUES.auth.impersonate_service_account.Set(
            '*****@*****.**')

        self.refresh_mock = self.StartObjectPatch(
            google_auth_credentials.UserCredWithReauth, 'refresh')
        self.StartObjectPatch(client.OAuth2Credentials, 'refresh')

        self.request_mock = self.StartObjectPatch(
            httplib2.Http,
            'request',
            autospec=True,
            return_value=(httplib2.Response({'status': 200}), b''))
        self.impersonation_token = 'impersonation-token'
        self.StartObjectPatch(impersonated_credentials,
                              '_make_iam_token_request',
                              return_value=(self.impersonation_token,
                                            datetime.datetime(
                                                9999, 2, 3, 14, 15, 16)))

        store.IMPERSONATION_TOKEN_PROVIDER = (
            util.ImpersonationAccessTokenProvider())
Beispiel #3
0
  def testRefreshImpersonationAccountId(self):
    # Store test credential
    store.Store(self.fake_cred)
    properties.VALUES.auth.impersonate_service_account.Set('*****@*****.**')
    try:
      # Set Token Provider
      store.IMPERSONATION_TOKEN_PROVIDER = (
          util.ImpersonationAccessTokenProvider())
      # Mock response from util.GenerateAccessToken
      self.mock_client.projects_serviceAccounts.GenerateAccessToken.Expect(
          self.gen_request_msg(
              name='projects/-/serviceAccounts/[email protected]',
              generateAccessTokenRequest=(
                  self.messages.GenerateAccessTokenRequest(
                      scope=config.CLOUDSDK_SCOPES))),
          self.messages.GenerateAccessTokenResponse(
              accessToken='impersonation-token',
              expireTime='2016-01-08T00:00:00Z'))

      # Load test impersonation token
      loaded = store.Load(allow_account_impersonation=True)
      loaded.token_response = {'id_token': 'old-id-token'}
      audience = 'https://service-hash-uc.a.run.app'
      config.CLOUDSDK_CLIENT_ID = audience

      # Refresh the credential
      # Mock response from util.GenerateAccessToken (2nd call from Refresh)
      self.mock_client.projects_serviceAccounts.GenerateAccessToken.Expect(
          self.gen_request_msg(
              name='projects/-/serviceAccounts/[email protected]',
              generateAccessTokenRequest=(
                  self.messages.GenerateAccessTokenRequest(
                      scope=config.CLOUDSDK_SCOPES))),
          self.messages.GenerateAccessTokenResponse(
              accessToken='impersonation-token',
              expireTime='2016-01-08T00:00:00Z'))

      # Mock response from util.GenerateIdToken
      new_token_id = 'new-id-token'
      self.mock_client.projects_serviceAccounts.GenerateIdToken.Expect(
          self.gen_id_msg(
              name='projects/-/serviceAccounts/[email protected]',
              generateIdTokenRequest=self.messages.GenerateIdTokenRequest(
                  audience=audience, includeEmail=False)),
          self.messages.GenerateIdTokenResponse(token=new_token_id)
      )
      # Load test impersonation token
      loaded = store.Load(allow_account_impersonation=True)
      loaded.token_response = {'id_token': 'old-id-token'}
      audience = 'https://service-hash-uc.a.run.app'
      config.CLOUDSDK_CLIENT_ID = audience
      store.Refresh(loaded, is_impersonated_credential=True)
      self.assertEqual(loaded.token_response['id_token'], new_token_id)
    finally:  # Clean-Up
      store.IMPERSONATION_TOKEN_PROVIDER = None
Beispiel #4
0
  def __enter__(self):
    """Registers sources for credentials and project for use by commands."""
    self._credential_providers = self._credential_providers or [
        store.GceCredentialProvider(),
    ]
    for provider in self._credential_providers:
      provider.Register()

    # Register support for service account impersonation.
    store.IMPERSONATION_TOKEN_PROVIDER = (
        iamcred_util.ImpersonationAccessTokenProvider())
    return self
Beispiel #5
0
def main(gcloud_cli=None, credential_providers=None):
    if not platforms.PythonVersion().IsCompatible(
            allow_py3=properties.VALUES.core.allow_py3.GetBool()):
        sys.exit(1)
    metrics.Started(START_TIME)
    # TODO(b/36049857): Put a real version number here
    metrics.Executions(
        'gcloud',
        local_state.InstallationState.VersionForInstalledComponent('core'))
    if gcloud_cli is None:
        gcloud_cli = CreateCLI([])

    # Register some other sources for credentials and project.
    credential_providers = credential_providers or [
        creds_store.DevShellCredentialProvider(),
        creds_store.GceCredentialProvider(),
    ]
    for provider in credential_providers:
        provider.Register()
    # Register support for service account impersonation.
    creds_store.IMPERSONATION_TOKEN_PROVIDER = (
        iamcred_util.ImpersonationAccessTokenProvider())

    try:
        try:
            gcloud_cli.Execute()
        except IOError as err:
            # We want to ignore EPIPE IOErrors.
            # By default, Python ignores SIGPIPE (see
            # http://utcc.utoronto.ca/~cks/space/blog/python/SignalExceptionSurprise).
            # This means that attempting to write any output to a closed pipe (e.g. in
            # the case of output piped to `head` or `grep -q`) will result in an
            # IOError, which gets reported as a gcloud crash. We don't want this
            # behavior, so we ignore EPIPE (it's not a real error; it's a normal thing
            # to occur).
            # Before, we restore the SIGPIPE signal handler, but that caused issues
            # with scripts/programs that wrapped gcloud.
            if err.errno != errno.EPIPE:
                raise
    except Exception as err:  # pylint:disable=broad-except
        crash_handling.HandleGcloudCrash(err)
        if properties.VALUES.core.print_unhandled_tracebacks.GetBool():
            # We want to see the traceback as normally handled by Python
            raise
        else:
            # This is the case for most non-Cloud SDK developers. They shouldn't see
            # the full stack trace, but just the nice "gcloud crashed" message.
            sys.exit(1)
    finally:
        for provider in credential_providers:
            provider.UnRegister()
    def testImpersonation(self):

        self.request_mock.return_value = (httplib2.Response({'status': 200}),
                                          b'{"projects": []}')

        try:
            store.IMPERSONATION_TOKEN_PROVIDER = (
                util.ImpersonationAccessTokenProvider())
            self.Run(
                '--impersonate-service-account [email protected] projects list')
            access_token = self.request_mock.call_args[1]['headers'][
                b'authorization']
            # Make sure the request was made with the service account token.
            self.assertEqual(access_token, b'Bearer impersonation-token')
        finally:
            store.IMPERSONATION_TOKEN_PROVIDER = None
Beispiel #7
0
    def __enter__(self):
        self._orig_account = properties.VALUES.core.account.Get()
        self._orig_project = properties.VALUES.core.project.Get()
        self._orig_impersonate_service_account = (
            properties.VALUES.auth.impersonate_service_account.Get())

        user_creds = c_store.AcquireFromToken(self._refresh_token)
        c_store.ActivateCredentials(self._account, user_creds)
        if self._project_override:
            properties.VALUES.core.project.Set(self._project_override)
        properties.VALUES.auth.impersonate_service_account.Set(
            self._service_account_email)

        self._orig_impersonate_provider = c_store.IMPERSONATION_TOKEN_PROVIDER
        c_store.IMPERSONATION_TOKEN_PROVIDER = (
            iamcred_util.ImpersonationAccessTokenProvider())
        return self
Beispiel #8
0
  def testRefreshImpersonationAccountImpersonationBadCred(self):
    self.StartObjectPatch(util, 'GenerateAccessToken')

    def refresh(fake_client):
      del fake_client

    bad_credential = client.OAuth2Credentials(None, None, None, None, None,
                                              None, None)
    bad_credential.refresh = refresh

    try:
      store.IMPERSONATION_TOKEN_PROVIDER = (
          util.ImpersonationAccessTokenProvider())
      with self.assertRaisesRegex(store.AccountImpersonationError,
                                  'Invalid impersonation account for refresh'):
        store.Refresh(bad_credential, is_impersonated_credential=True)
    finally:  # Clean-Up
      store.IMPERSONATION_TOKEN_PROVIDER = None
    def testImpersonation(self):
        self.mock_client.projects_serviceAccounts.GenerateAccessToken.Expect(
            self.gen_request_msg(
                name='projects/-/serviceAccounts/[email protected]',
                generateAccessTokenRequest=self.messages.
                GenerateAccessTokenRequest(scope=config.CLOUDSDK_SCOPES)),
            self.messages.GenerateAccessTokenResponse(
                accessToken='impersonation-token',
                expireTime='2016-01-08T00:00:00Z'))

        self.request_mock.return_value = (httplib2.Response({'status': 200}),
                                          b'{"projects": []}')

        try:
            store.IMPERSONATION_TOKEN_PROVIDER = (
                util.ImpersonationAccessTokenProvider())
            self.Run(
                'alpha --impersonate-service-account [email protected] projects list'
            )
            access_token = self.request_mock.call_args[0][4][b'Authorization']
            # Make sure the request was made with the service account token.
            self.assertEqual(access_token, b'Bearer impersonation-token')
        finally:
            store.IMPERSONATION_TOKEN_PROVIDER = None
def main(gcloud_cli=None, credential_providers=None):
    if not platforms.PythonVersion().IsCompatible(
            allow_py3=properties.VALUES.core.allow_py3.GetBool()):
        sys.exit(1)
    metrics.Started(START_TIME)
    # TODO(b/36049857): Put a real version number here
    metrics.Executions(
        'gcloud',
        local_state.InstallationState.VersionForInstalledComponent('core'))
    if gcloud_cli is None:
        gcloud_cli = CreateCLI([])

    # Register some other sources for credentials and project.
    credential_providers = credential_providers or [
        creds_store.DevShellCredentialProvider(),
        creds_store.GceCredentialProvider(),
    ]
    for provider in credential_providers:
        provider.Register()
    # Register support for service account impersonation.
    creds_store.IMPERSONATION_TOKEN_PROVIDER = (
        iamcred_util.ImpersonationAccessTokenProvider())

    try:
        try:
            gcloud_cli.Execute()
            # Flush stdout so that if we've received a SIGPIPE we handle the broken
            # pipe within this try block, instead of potentially during interpreter
            # shutdown.
            sys.stdout.flush()
        except IOError as err:
            # We want to ignore EPIPE IOErrors (as of Python 3.3 these can be caught
            # specifically with BrokenPipeError, but we do it this way for Python 2
            # compatibility).
            #
            # By default, Python ignores SIGPIPE (see
            # http://utcc.utoronto.ca/~cks/space/blog/python/SignalExceptionSurprise).
            # This means that attempting to write any output to a closed pipe (e.g. in
            # the case of output piped to `head` or `grep -q`) will result in an
            # IOError, which gets reported as a gcloud crash. We don't want this
            # behavior, so we ignore EPIPE (it's not a real error; it's a normal thing
            # to occur).
            #
            # Before, we restored the SIGPIPE signal handler, but that caused issues
            # with scripts/programs that wrapped gcloud.
            if err.errno == errno.EPIPE:
                # At this point we've caught the broken pipe, but since Python flushes
                # standard streams on exit, it's still possible for a broken pipe error
                # to happen during interpreter shutdown. The interpreter will catch this
                # but in Python 3 it still prints a warning to stderr saying that the
                # exception was ignored (see https://bugs.python.org/issue11380):
                #
                # Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w'
                # encoding='UTF-8'>
                # BrokenPipeError: [Errno 32] Broken pipe
                #
                # To prevent this from happening, we redirect any remaining output to
                # devnull as recommended here:
                # https://docs.python.org/3/library/signal.html#note-on-sigpipe.
                devnull = os.open(os.devnull, os.O_WRONLY)
                os.dup2(devnull, sys.stdout.fileno())
            else:
                raise
    except Exception as err:  # pylint:disable=broad-except
        crash_handling.HandleGcloudCrash(err)
        if properties.VALUES.core.print_unhandled_tracebacks.GetBool():
            # We want to see the traceback as normally handled by Python
            raise
        else:
            # This is the case for most non-Cloud SDK developers. They shouldn't see
            # the full stack trace, but just the nice "gcloud crashed" message.
            sys.exit(1)
    finally:
        for provider in credential_providers:
            provider.UnRegister()