Example #1
0
def _get_expiration_seconds(expiration):
    """Convert 'expiration' to a number of seconds in the future.

    :type expiration: int, long, datetime.datetime, datetime.timedelta
    :param expiration: When the signed URL should expire.

    :raises TypeError: When expiration is not an integer.

    :rtype: int
    :returns: a timestamp as an absolute number of seconds.
    """
    # If it's a timedelta, add it to `now` in UTC.
    if isinstance(expiration, datetime.timedelta):
        now = _NOW().replace(tzinfo=UTC)
        expiration = now + expiration

    # If it's a datetime, convert to a timestamp.
    if isinstance(expiration, datetime.datetime):
        micros = _microseconds_from_datetime(expiration)
        expiration = micros // 10**6

    if not isinstance(expiration, six.integer_types):
        raise TypeError('Expected an integer timestamp, datetime, or '
                        'timedelta. Got %s' % type(expiration))
    return expiration
Example #2
0
def _get_expiration_seconds(expiration):
    """Convert 'expiration' to a number of seconds in the future.

    :type expiration: int, long, datetime.datetime, datetime.timedelta
    :param expiration: When the signed URL should expire.

    :raises TypeError: When expiration is not an integer.

    :rtype: int
    :returns: a timestamp as an absolute number of seconds.
    """
    # If it's a timedelta, add it to `now` in UTC.
    if isinstance(expiration, datetime.timedelta):
        now = _NOW().replace(tzinfo=UTC)
        expiration = now + expiration

    # If it's a datetime, convert to a timestamp.
    if isinstance(expiration, datetime.datetime):
        micros = _microseconds_from_datetime(expiration)
        expiration = micros // 10**6

    if not isinstance(expiration, six.integer_types):
        raise TypeError('Expected an integer timestamp, datetime, or '
                        'timedelta. Got %s' % type(expiration))
    return expiration
Example #3
0
    def generateUploadPolicy(self, conditions):
        """
		Our implementation of bucket.generate_upload_policy - which works with default token credentials
		Create a signed upload policy for uploading objects.

		This method generates and signs a policy document. You can use
		`policy documents`_ to allow visitors to a website to upload files to
		Google Cloud Storage without giving them direct write access.

		For example:

		.. literalinclude:: snippets.py
			:start-after: [START policy_document]
			:end-before: [END policy_document]

		.. _policy documents:
			https://cloud.google.com/storage/docs/xml-api\
			/post-object#policydocument

		:type expiration: datetime
		:param expiration: Optional expiration in UTC. If not specified, the
						   policy will expire in 1 hour.

		:type conditions: list
		:param conditions: A list of conditions as described in the
						  `policy documents`_ documentation.

		:type client: :class:`~google.cloud.storage.client.Client`
		:param client: Optional. The client to use.  If not passed, falls back
					   to the ``client`` stored on the current bucket.

		:rtype: dict
		:returns: A dictionary of (form field name, form field value) of form
				  fields that should be added to your HTML upload form in order
				  to attach the signature.
		"""
        global credentials, bucket
        auth_request = requests.Request()
        sign_cred = compute_engine.IDTokenCredentials(
            auth_request,
            "",
            service_account_email=credentials.service_account_email)
        expiration = _NOW() + timedelta(hours=1)
        conditions = conditions + [{"bucket": bucket.name}]
        policy_document = {
            "expiration": _datetime_to_rfc3339(expiration),
            "conditions": conditions,
        }
        encoded_policy_document = base64.b64encode(
            json.dumps(policy_document).encode("utf-8"))
        signature = base64.b64encode(
            sign_cred.sign_bytes(encoded_policy_document))
        fields = {
            "bucket": bucket.name,
            "GoogleAccessId": sign_cred.signer_email,
            "policy": encoded_policy_document.decode("utf-8"),
            "signature": signature.decode("utf-8"),
        }
        return fields
    def _timestamp_message(self, attrs):
        """Add a timestamp to ``attrs``, if the topic is so configured.

        If ``attrs`` already has the key, do nothing.

        Helper method for ``publish``/``Batch.publish``.
        """
        if self.timestamp_messages and 'timestamp' not in attrs:
            attrs['timestamp'] = _datetime_to_rfc3339(_NOW())
Example #5
0
    def _timestamp_message(self, attrs):
        """Add a timestamp to ``attrs``, if the topic is so configured.

        If ``attrs`` already has the key, do nothing.

        Helper method for ``publish``/``Batch.publish``.
        """
        if self.timestamp_messages and 'timestamp' not in attrs:
            attrs['timestamp'] = _datetime_to_rfc3339(_NOW())
Example #6
0
    def _setUpConstants(self):
        from google.cloud._helpers import UTC
        from google.cloud._helpers import _NOW

        self.WHEN = _NOW().replace(tzinfo=UTC)
Example #7
0
    def generate_signed_post_policy_v4(
        self,
        bucket_name,
        blob_name,
        expiration,
        conditions=None,
        fields=None,
        credentials=None,
        virtual_hosted_style=False,
        bucket_bound_hostname=None,
        scheme="http",
        service_account_email=None,
        access_token=None,
    ):
        """Generate a V4 signed policy object.

        .. note::

            Assumes ``credentials`` implements the
            :class:`google.auth.credentials.Signing` interface. Also assumes
            ``credentials`` has a ``service_account_email`` property which
            identifies the credentials.

        Generated policy object allows user to upload objects with a POST request.

        :type bucket_name: str
        :param bucket_name: Bucket name.

        :type blob_name: str
        :param blob_name: Object name.

        :type expiration: Union[Integer, datetime.datetime, datetime.timedelta]
        :param expiration: Policy expiration time. If a ``datetime`` instance is
                           passed without an explicit ``tzinfo`` set,  it will be
                           assumed to be ``UTC``.

        :type conditions: list
        :param conditions: (Optional) List of POST policy conditions, which are
                           used to restrict what is allowed in the request.

        :type fields: dict
        :param fields: (Optional) Additional elements to include into request.

        :type credentials: :class:`google.auth.credentials.Signing`
        :param credentials: (Optional) Credentials object with an associated private
                            key to sign text.

        :type virtual_hosted_style: bool
        :param virtual_hosted_style: (Optional) If True, construct the URL relative to the bucket
                                     virtual hostname, e.g., '<bucket-name>.storage.googleapis.com'.

        :type bucket_bound_hostname: str
        :param bucket_bound_hostname:
            (Optional) If passed, construct the URL relative to the bucket-bound hostname.
            Value can be bare or with a scheme, e.g., 'example.com' or 'http://example.com'.
            See: https://cloud.google.com/storage/docs/request-endpoints#cname

        :type scheme: str
        :param scheme:
            (Optional) If ``bucket_bound_hostname`` is passed as a bare hostname, use
            this value as a scheme. ``https`` will work only when using a CDN.
            Defaults to ``"http"``.

        :type service_account_email: str
        :param service_account_email: (Optional) E-mail address of the service account.

        :type access_token: str
        :param access_token: (Optional) Access token for a service account.

        :rtype: dict
        :returns: Signed POST policy.

        Example:
            Generate signed POST policy and upload a file.

            >>> from google.cloud import storage
            >>> import pytz
            >>> client = storage.Client()
            >>> tz = pytz.timezone('America/New_York')
            >>> policy = client.generate_signed_post_policy_v4(
                "bucket-name",
                "blob-name",
                expiration=datetime.datetime(2020, 3, 17, tzinfo=tz),
                conditions=[
                    ["content-length-range", 0, 255]
                ],
                fields=[
                    "x-goog-meta-hello" => "world"
                ],
            )
            >>> with open("bucket-name", "rb") as f:
                files = {"file": ("bucket-name", f)}
                requests.post(policy["url"], data=policy["fields"], files=files)
        """
        credentials = self._credentials if credentials is None else credentials
        ensure_signed_credentials(credentials)

        # prepare policy conditions and fields
        timestamp, datestamp = get_v4_now_dtstamps()

        x_goog_credential = "{email}/{datestamp}/auto/storage/goog4_request".format(
            email=credentials.signer_email, datestamp=datestamp
        )
        required_conditions = [
            {"bucket": bucket_name},
            {"key": blob_name},
            {"x-goog-date": timestamp},
            {"x-goog-credential": x_goog_credential},
            {"x-goog-algorithm": "GOOG4-RSA-SHA256"},
        ]

        conditions = conditions or []
        policy_fields = {}
        for key, value in sorted((fields or {}).items()):
            if not key.startswith("x-ignore-"):
                policy_fields[key] = value
                conditions.append({key: value})

        conditions += required_conditions

        # calculate policy expiration time
        now = _NOW()
        if expiration is None:
            expiration = now + datetime.timedelta(hours=1)

        policy_expires = now + datetime.timedelta(
            seconds=get_expiration_seconds_v4(expiration)
        )

        # encode policy for signing
        policy = json.dumps(
            collections.OrderedDict(
                sorted(
                    {
                        "conditions": conditions,
                        "expiration": policy_expires.isoformat() + "Z",
                    }.items()
                )
            ),
            separators=(",", ":"),
        )
        str_to_sign = base64.b64encode(policy.encode("utf-8"))

        # sign the policy and get its cryptographic signature
        if access_token and service_account_email:
            signature = _sign_message(str_to_sign, access_token, service_account_email)
            signature_bytes = base64.b64decode(signature)
        else:
            signature_bytes = credentials.sign_bytes(str_to_sign)

        # get hexadecimal representation of the signature
        signature = binascii.hexlify(signature_bytes).decode("utf-8")

        policy_fields.update(
            {
                "key": blob_name,
                "x-goog-algorithm": "GOOG4-RSA-SHA256",
                "x-goog-credential": x_goog_credential,
                "x-goog-date": timestamp,
                "x-goog-signature": signature,
                "policy": str_to_sign.decode("utf-8"),
            }
        )
        # designate URL
        if virtual_hosted_style:
            url = "https://{}.storage.googleapis.com/".format(bucket_name)
        elif bucket_bound_hostname:
            url = _bucket_bound_hostname_url(bucket_bound_hostname, scheme)
        else:
            url = "https://storage.googleapis.com/{}/".format(bucket_name)

        return {"url": url, "fields": policy_fields}
Example #8
0
    def generate_upload_policy(self, conditions, expiration=None, client=None):
        """Create a signed upload policy for uploading objects.

        This method generates and signs a policy document. You can use
        `policy documents`_ to allow visitors to a website to upload files to
        Google Cloud Storage without giving them direct write access.

        For example:

        .. literalinclude:: storage_snippets.py
          :start-after: [START policy_document]
          :end-before: [END policy_document]

        .. _policy documents:
            https://cloud.google.com/storage/docs/xml-api\
            /post-object#policydocument

        :type expiration: datetime
        :param expiration: Optional expiration in UTC. If not specified, the
                           policy will expire in 1 hour.

        :type conditions: list
        :param conditions: A list of conditions as described in the
                          `policy documents`_ documentation.

        :type client: :class:`~google.cloud.storage.client.Client`
        :param client: Optional. The client to use.  If not passed, falls back
                       to the ``client`` stored on the current bucket.

        :rtype: dict
        :returns: A dictionary of (form field name, form field value) of form
                  fields that should be added to your HTML upload form in order
                  to attach the signature.
        """
        client = self._require_client(client)
        credentials = client._base_connection.credentials

        if not isinstance(credentials, google.auth.credentials.Signing):
            auth_uri = ('http://google-cloud-python.readthedocs.io/en/latest/'
                        'google-cloud-auth.html#setting-up-a-service-account')
            raise AttributeError('you need a private key to sign credentials.'
                                 'the credentials you are currently using %s '
                                 'just contains a token. see %s for more '
                                 'details.' % (type(credentials), auth_uri))

        if expiration is None:
            expiration = _NOW() + datetime.timedelta(hours=1)

        conditions = conditions + [
            {
                'bucket': self.name
            },
        ]

        policy_document = {
            'expiration': _datetime_to_rfc3339(expiration),
            'conditions': conditions,
        }

        encoded_policy_document = base64.b64encode(
            json.dumps(policy_document).encode('utf-8'))
        signature = base64.b64encode(
            credentials.sign_bytes(encoded_policy_document))

        fields = {
            'bucket': self.name,
            'GoogleAccessId': credentials.signer_email,
            'policy': encoded_policy_document.decode('utf-8'),
            'signature': signature.decode('utf-8'),
        }

        return fields
Example #9
0
    def generate_upload_policy(self, conditions, expiration=None, client=None):
        """Create a signed upload policy for uploading objects.

        This method generates and signs a policy document. You can use
        `policy documents`_ to allow visitors to a website to upload files to
        Google Cloud Storage without giving them direct write access.

        For example:

        .. literalinclude:: snippets.py
            :start-after: [START policy_document]
            :end-before: [END policy_document]

        .. _policy documents:
            https://cloud.google.com/storage/docs/xml-api\
            /post-object#policydocument

        :type expiration: datetime
        :param expiration: Optional expiration in UTC. If not specified, the
                           policy will expire in 1 hour.

        :type conditions: list
        :param conditions: A list of conditions as described in the
                          `policy documents`_ documentation.

        :type client: :class:`~google.cloud.storage.client.Client`
        :param client: Optional. The client to use.  If not passed, falls back
                       to the ``client`` stored on the current bucket.

        :rtype: dict
        :returns: A dictionary of (form field name, form field value) of form
                  fields that should be added to your HTML upload form in order
                  to attach the signature.
        """
        client = self._require_client(client)
        credentials = client._base_connection.credentials
        _signing.ensure_signed_credentials(credentials)

        if expiration is None:
            expiration = _NOW() + datetime.timedelta(hours=1)

        conditions = conditions + [
            {
                'bucket': self.name
            },
        ]

        policy_document = {
            'expiration': _datetime_to_rfc3339(expiration),
            'conditions': conditions,
        }

        encoded_policy_document = base64.b64encode(
            json.dumps(policy_document).encode('utf-8'))
        signature = base64.b64encode(
            credentials.sign_bytes(encoded_policy_document))

        fields = {
            'bucket': self.name,
            'GoogleAccessId': credentials.signer_email,
            'policy': encoded_policy_document.decode('utf-8'),
            'signature': signature.decode('utf-8'),
        }

        return fields
Example #10
0
    def generate_upload_policy(
            self, conditions, expiration=None, client=None):
        """Create a signed upload policy for uploading objects.

        This method generates and signs a policy document. You can use
        `policy documents`_ to allow visitors to a website to upload files to
        Google Cloud Storage without giving them direct write access.

        For example:

        .. literalinclude:: snippets.py
            :start-after: [START policy_document]
            :end-before: [END policy_document]

        .. _policy documents:
            https://cloud.google.com/storage/docs/xml-api\
            /post-object#policydocument

        :type expiration: datetime
        :param expiration: Optional expiration in UTC. If not specified, the
                           policy will expire in 1 hour.

        :type conditions: list
        :param conditions: A list of conditions as described in the
                          `policy documents`_ documentation.

        :type client: :class:`~google.cloud.storage.client.Client`
        :param client: Optional. The client to use.  If not passed, falls back
                       to the ``client`` stored on the current bucket.

        :rtype: dict
        :returns: A dictionary of (form field name, form field value) of form
                  fields that should be added to your HTML upload form in order
                  to attach the signature.
        """
        client = self._require_client(client)
        credentials = client._base_connection.credentials
        _signing.ensure_signed_credentials(credentials)

        if expiration is None:
            expiration = _NOW() + datetime.timedelta(hours=1)

        conditions = conditions + [
            {'bucket': self.name},
        ]

        policy_document = {
            'expiration': _datetime_to_rfc3339(expiration),
            'conditions': conditions,
        }

        encoded_policy_document = base64.b64encode(
            json.dumps(policy_document).encode('utf-8'))
        signature = base64.b64encode(
            credentials.sign_bytes(encoded_policy_document))

        fields = {
            'bucket': self.name,
            'GoogleAccessId': credentials.signer_email,
            'policy': encoded_policy_document.decode('utf-8'),
            'signature': signature.decode('utf-8'),
        }

        return fields