예제 #1
0
def _get_request_header(
    credentials = None
):
  """Gets a request header.

  Args:
    credentials: The credentials to use for GCP services.

  Returns:
    A header dict for requests.
  """
  # If credentials is not given, use the default credentials
  if credentials is None:
    credentials, _ = google.auth.default()

  # Refresh credentials in case it has been expired.
  auth_req = google.auth.transport.requests.Request()
  credentials.refresh(auth_req)

  headers = {}
  # Set user-agent for logging usages.
  headers['user-agent'] = constants.USER_AGENT_FOR_CAIP_TRACKING
  credentials.apply(headers)

  return headers
예제 #2
0
    def _get_credentials_email(self) -> str:
        """
        Returns the email address associated with the currently logged in account

        If a service account is used, it returns the service account.
        If user authentication (e.g. gcloud auth) is used, it returns the e-mail account of that user.
        """
        credentials = self._get_credentials()

        if isinstance(credentials, compute_engine.Credentials):
            try:
                credentials.refresh(_http_client.Request())
            except RefreshError as msg:
                """
                If the Compute Engine metadata service can't be reached in this case the instance has not
                credentials.
                """
                self.log.debug(msg)

        service_account_email = getattr(credentials, 'service_account_email', None)
        if service_account_email:
            return service_account_email

        http_authorized = self._authorize()
        oauth2_client = discovery.build('oauth2', "v1", http=http_authorized, cache_discovery=False)
        return oauth2_client.tokeninfo().execute()['email']
예제 #3
0
 def _get_access_token(self) -> str:
     """Returns a valid access token from Google API Credentials"""
     credentials = self._get_credentials()
     auth_req = google.auth.transport.requests.Request()
     # credentials.token is None
     # Need to refresh credentials to populate the token
     credentials.refresh(auth_req)
     return credentials.token
예제 #4
0
    def create_kubernetes_configuration(
            self,
            credentials: credentials.Credentials,
            project_id: str,
            cluster_name: str,
            zone: str = 'us-west1-a') -> kubernetes.client.Configuration:
        """Create a kubernetes config which has access to the given cluster.

        Args:
            credentials: The credentials object used to generate tokens to
                access kubernetes clusters.
            project_id: GCP project id.
            cluster_name: Name of the kubernetes cluster we want to access.
            zone: Where is the cluster hosted.

        Raises:
            ClusterGetInfoError: When unexpected cluster information is returned
                from GCP.

        Returns:
            A kubernetes configuration which has access to the provided cluster.
        """

        # This function will create a temporary file for cluster ca certificate.
        # Those temporary files should be removed after the program exists.
        if not ContainerClient._temp_ca_files:
            atexit.register(self._cleanup_temp_files)

        # credentials.token is a bearer token that can be used in HTTP headers
        # to make authenticated requests. When the given credentials does not
        # have token, we need to force it to get a new token.
        if not credentials.token:
            credentials.refresh(requests.Request())

        request = self._container_service.projects().zones().clusters().get(
            projectId=project_id, zone=zone, clusterId=cluster_name)
        response = request.execute()
        if ('masterAuth' not in response
                or 'clusterCaCertificate' not in response['masterAuth']):
            raise ClusterGetInfoError(
                ('Unexpected response getting information of cluster "{}" in '
                 'project "{}": {}').format(cluster_name, project_id,
                                            response))

        ca = response['masterAuth']['clusterCaCertificate']

        _, ca_file_path = tempfile.mkstemp()
        # Save temporary file path so that it can be cleaned up after the
        # program exits.
        self._temp_ca_files.append(ca_file_path)
        with open(ca_file_path, 'wb') as ca_file:
            ca_file.write(base64.standard_b64decode(ca))
        configuration = kubernetes.client.Configuration()
        configuration.api_key['authorization'] = credentials.token
        configuration.api_key_prefix['authorization'] = 'Bearer'
        configuration.host = 'https://' + response['endpoint']
        configuration.ssl_ca_cert = ca_file_path
        return configuration
def refresh_credentials(credentials):
    # Refresh must use a new http instance, as the one associated with the
    # credentials could be a AuthorizedHttp or an oauth2client-decorated
    # Http instance which would cause a weird recursive loop of refreshing
    # and likely tear a hole in spacetime.
    refresh_http = httplib2.Http()
    if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
        request = google_auth_httplib2.Request(refresh_http)
        return credentials.refresh(request)
    else:
        return credentials.refresh(refresh_http)
예제 #6
0
    def _create_docker_client(self, credentials: credentials.Credentials):
        # credentials.token is a bearer token that can be used in HTTP headers
        # to make authenticated requests. When the given credentials does not
        # have token, we need to force it to get a new token.
        if not credentials.token:
            credentials.refresh(requests.Request())

        # See https://cloud.google.com/container-registry/docs/advanced-authentication
        self._docker_client = docker.DockerClient()
        self._docker_client.login(username='******',
                                  password=credentials.token,
                                  registry='https://gcr.io')
예제 #7
0
def refresh_credentials(credentials):
    # Refresh must use a new http instance, as the one associated with the
    # credentials could be a AuthorizedHttp or an oauth2client-decorated
    # Http instance which would cause a weird recursive loop of refreshing
    # and likely tear a hole in spacetime.
    refresh_http = httplib2.Http()
    if HAS_GOOGLE_AUTH and isinstance(
            credentials, google.auth.credentials.Credentials):
        request = google_auth_httplib2.Request(refresh_http)
        return credentials.refresh(request)
    else:
        return credentials.refresh(refresh_http)
    def test_apply_without_quota_project_id(self):
        headers = {}
        request = self.make_mock_request(status=http_client.OK,
                                         data=SUCCESS_RESPONSE)
        credentials = self.make_credentials()

        credentials.refresh(request)
        credentials.apply(headers)

        assert headers == {
            "authorization":
            "Bearer {}".format(SUCCESS_RESPONSE["access_token"])
        }
    def test_refresh_source_credentials_refresh_error(self):
        # Initialize downscoped credentials with source credentials that raise
        # an error on refresh.
        credentials = self.make_credentials(
            source_credentials=SourceCredentials(raise_error=True))

        with pytest.raises(exceptions.RefreshError) as excinfo:
            credentials.refresh(mock.sentinel.request)

        assert excinfo.match(
            r"Failed to refresh access token in source credentials.")
        assert not credentials.expired
        assert credentials.token is None
    def test_refresh_token_exchange_error(self):
        request = self.make_mock_request(status=http_client.BAD_REQUEST,
                                         data=ERROR_RESPONSE)
        credentials = self.make_credentials()

        with pytest.raises(exceptions.OAuthError) as excinfo:
            credentials.refresh(request)

        assert excinfo.match(
            r"Error code invalid_grant: Subject token is invalid. - https://tools.ietf.org/html/rfc6749"
        )
        assert not credentials.expired
        assert credentials.token is None
    def test_apply_with_quota_project_id(self):
        headers = {"other": "header-value"}
        request = self.make_mock_request(status=http_client.OK,
                                         data=SUCCESS_RESPONSE)
        credentials = self.make_credentials(quota_project_id=QUOTA_PROJECT_ID)

        credentials.refresh(request)
        credentials.apply(headers)

        assert headers == {
            "other": "header-value",
            "authorization":
            "Bearer {}".format(SUCCESS_RESPONSE["access_token"]),
            "x-goog-user-project": QUOTA_PROJECT_ID,
        }
    def test_refresh_without_response_expires_in(self, unused_utcnow):
        response = SUCCESS_RESPONSE.copy()
        # Simulate the response is missing the expires_in field.
        # The downscoped token expiration should match the source credentials
        # expiration.
        del response["expires_in"]
        expected_expires_in = 1800
        # Simulate the source credentials generates a token with 1800 second
        # expiration time. The generated downscoped token should have the same
        # expiration time.
        source_credentials = SourceCredentials(expires_in=expected_expires_in)
        expected_expiry = datetime.datetime.min + datetime.timedelta(
            seconds=expected_expires_in)
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        request_data = {
            "grant_type":
            GRANT_TYPE,
            "subject_token":
            "ACCESS_TOKEN_1",
            "subject_token_type":
            SUBJECT_TOKEN_TYPE,
            "requested_token_type":
            REQUESTED_TOKEN_TYPE,
            "options":
            urllib.parse.quote(json.dumps(CREDENTIAL_ACCESS_BOUNDARY_JSON)),
        }
        request = self.make_mock_request(status=http_client.OK, data=response)
        credentials = self.make_credentials(
            source_credentials=source_credentials)

        # Spy on calls to source credentials refresh to confirm the expected request
        # instance is used.
        with mock.patch.object(source_credentials,
                               "refresh",
                               wraps=source_credentials.refresh
                               ) as wrapped_souce_cred_refresh:
            credentials.refresh(request)

            self.assert_request_kwargs(request.call_args[1], headers,
                                       request_data)
            assert credentials.valid
            assert credentials.expiry == expected_expiry
            assert not credentials.expired
            assert credentials.token == response["access_token"]
            # Confirm source credentials called with the same request instance.
            wrapped_souce_cred_refresh.assert_called_with(request)
    def test_refresh(self, unused_utcnow):
        response = SUCCESS_RESPONSE.copy()
        # Test custom expiration to confirm expiry is set correctly.
        response["expires_in"] = 2800
        expected_expiry = datetime.datetime.min + datetime.timedelta(
            seconds=response["expires_in"])
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        request_data = {
            "grant_type":
            GRANT_TYPE,
            "subject_token":
            "ACCESS_TOKEN_1",
            "subject_token_type":
            SUBJECT_TOKEN_TYPE,
            "requested_token_type":
            REQUESTED_TOKEN_TYPE,
            "options":
            urllib.parse.quote(json.dumps(CREDENTIAL_ACCESS_BOUNDARY_JSON)),
        }
        request = self.make_mock_request(status=http_client.OK, data=response)
        source_credentials = SourceCredentials()
        credentials = self.make_credentials(
            source_credentials=source_credentials)

        # Spy on calls to source credentials refresh to confirm the expected request
        # instance is used.
        with mock.patch.object(source_credentials,
                               "refresh",
                               wraps=source_credentials.refresh
                               ) as wrapped_souce_cred_refresh:
            credentials.refresh(request)

            self.assert_request_kwargs(request.call_args[1], headers,
                                       request_data)
            assert credentials.valid
            assert credentials.expiry == expected_expiry
            assert not credentials.expired
            assert credentials.token == response["access_token"]
            # Confirm source credentials called with the same request instance.
            wrapped_souce_cred_refresh.assert_called_with(request)