Esempio n. 1
0
async def verify_signature(data, signature, key_name, iam_client):
    key_data = await iam_client.get_public_key(key_name)
    cert = x509.load_pem_x509_certificate(decode(key_data['publicKeyData']),
                                          backend=default_backend())
    pubkey = cert.public_key()

    # raises on failure
    pubkey.verify(decode(signature), data.encode(), padding.PKCS1v15(),
                  hashes.SHA256())
Esempio n. 2
0
    async def get_signed_url(  # pylint: disable=too-many-locals
            self,
            expiration: int,
            headers: Optional[dict] = None,
            query_params: Optional[dict] = None,
            http_method: str = 'GET',
            iam_client: Optional[IamClient] = None,
            service_account_email: Optional[str] = None,
            service_file: Optional[str] = None,
            token: Optional[Token] = None,
            session: Optional[aiohttp.ClientSession] = None) -> str:
        """
        Create a temporary access URL for Storage Blob accessible by anyone
        with the link.

        Adapted from Google Documentation:
        https://cloud.google.com/storage/docs/access-control/signing-urls-manually#python-sample
        """
        if expiration > 604800:
            raise ValueError("expiration time can't be longer than 604800 "
                             'seconds (7 days)')

        iam_client = iam_client or IamClient(
            service_file=service_file, token=token, session=session)

        quoted_name = quote(self.name, safe='')
        canonical_uri = f'/{self.bucket.name}/{quoted_name}'

        datetime_now = datetime.datetime.utcnow()
        request_timestamp = datetime_now.strftime('%Y%m%dT%H%M%SZ')
        datestamp = datetime_now.strftime('%Y%m%d')

        service_account_email = (service_account_email
                                 or iam_client.service_account_email)
        credential_scope = f'{datestamp}/auto/storage/goog4_request'
        credential = f'{service_account_email}/{credential_scope}'

        headers = headers or {}
        headers['host'] = HOST

        ordered_headers = collections.OrderedDict(sorted(headers.items()))
        canonical_headers = ''.join(f'{str(k).lower()}:{str(v).lower()}\n'
                                    for k, v in ordered_headers.items())

        signed_headers = ';'.join(f'{str(k).lower()}'
                                  for k in ordered_headers.keys())

        query_params = query_params or {}
        query_params['X-Goog-Algorithm'] = 'GOOG4-RSA-SHA256'
        query_params['X-Goog-Credential'] = credential
        query_params['X-Goog-Date'] = request_timestamp
        query_params['X-Goog-Expires'] = expiration
        query_params['X-Goog-SignedHeaders'] = signed_headers

        ordered_query_params = collections.OrderedDict(
            sorted(query_params.items()))

        canonical_query_str = '&'.join(
            f'{quote(str(k), safe="")}={quote(str(v), safe="")}'
            for k, v in ordered_query_params.items())

        canonical_req = '\n'.join([
            http_method, canonical_uri, canonical_query_str, canonical_headers,
            signed_headers, 'UNSIGNED-PAYLOAD'
        ])
        canonical_req_hash = hashlib.sha256(canonical_req.encode()).hexdigest()

        str_to_sign = '\n'.join([
            'GOOG4-RSA-SHA256', request_timestamp, credential_scope,
            canonical_req_hash
        ])
        signed_resp = await iam_client.sign_blob(
            str_to_sign,
            service_account_email=service_account_email,
            session=session)

        signature = binascii.hexlify(decode(
            signed_resp['signedBlob'])).decode()

        return (f'https://{HOST}{canonical_uri}?{canonical_query_str}'
                f'&X-Goog-Signature={signature}')