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
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())
def _setUpConstants(self): from google.cloud._helpers import UTC from google.cloud._helpers import _NOW self.WHEN = _NOW().replace(tzinfo=UTC)
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}
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
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
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