def get_cdn_presigned(file_name):
    print 'Getting presigned url for {} from CDN - {}'.format(file_name, cdn_name)
    cdn_key_name, cdn_key_data = _get_cdn_data()
    print 'Got key name {} data {}'.format(cdn_key_name, cdn_key_data)

    def _rsa_signer(message):
        private_key = serialization.load_pem_private_key(cdn_key_data, password=None, backend=default_backend())
        signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
        signer.update(message)
        return signer.finalize()

    if not hasattr(get_cdn_presigned, 'cdn_domain'):
        client = boto3.client('cloudfront')
        response = client.get_distribution(Id=cdn_name)
        print 'CDN {} got distribution info {}'.format(cdn_name, response)

        get_cdn_presigned.cdn_domain = response.get('Distribution',{}).get('DomainName')

    if not get_cdn_presigned.cdn_domain:
        print 'No domain on cdn {} to get signed url from'.format(cdn_name)

    current_time = datetime.utcnow()
    expire_time = current_time + timedelta(seconds=_cloudfront_url_duration())

    cloudfront_signer = CloudFrontSigner(cdn_key_name, _rsa_signer)

    url = 'https://' + get_cdn_presigned.cdn_domain + '/' + file_name
    print 'Retrieving signed url for {}'.format(url)

    signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_time)

    print 'Got signed url of {}'.format(signed_url)
    return signed_url
    def create_signed_cookies(self, resource, expire_minutes=3):
        """
        generate the Cloudfront download distirbution signed cookies
        @resource   path to the file, path, or wildcard pattern to generate policy for
        @expire_minutes  number of minutes until expiration
        return      tuple with domain used within policy (so it matches 
                    cookie domain), and dict of cloudfront cookies you
                    should set in request header
        """
        http_resource = self.get_http_resource_url(
            resource, secure=True
        )  #per-file access #NOTE secure should match security settings of cloudfront distribution

        cloudfront_signer = CloudFrontSigner(
            settings.CLOUDFRONT_SIGNED_COOKIES_KEY_PAIR_ID, rsa_signer)
        expires = SignedCookiedCloudfrontDistribution.get_expires(
            expire_minutes)
        policy = cloudfront_signer.build_policy(
            http_resource, datetime.fromtimestamp(expires))
        encoded_policy = cloudfront_signer._url_b64encode(
            policy.encode('utf-8')).decode('utf-8')

        #assemble the 3 Cloudfront cookies
        signature = rsa_signer(policy.encode('utf-8'))
        encoded_signature = cloudfront_signer._url_b64encode(signature).decode(
            'utf-8')
        cookies = {
            "CloudFront-Policy":
            encoded_policy,
            "CloudFront-Signature":
            encoded_signature,
            "CloudFront-Key-Pair-Id":
            settings.CLOUDFRONT_SIGNED_COOKIES_KEY_PAIR_ID,
        }
        return cookies
Esempio n. 3
0
def lambda_handler(event, context):
    if 'recordingPath' not in event or not event['recordingPath'] or event['recordingPath'] == 'null':
        logger.info("No recordingPath in event; returning.")
        return None
    # retrieve secrets
    logger.info("Retrieving cloudfront credentials")
    session = boto3.session.Session()
    client = session.client(service_name='secretsmanager')
    sf_credentials_secrets_manager_arn = get_arg(os.environ,
            'SF_CREDENTIALS_SECRETS_MANAGER_ARN')
    secrets = json.loads(client.get_secret_value(SecretId=sf_credentials_secrets_manager_arn)['SecretString'])
    private_key = secrets['CloudFrontPrivateKey']
    access_key_id = secrets['CloudFrontAccessKeyID']
    logger.info("Cloudfront credentials retrieved")

    # construct url to audio recording
    recordingPath = event['recordingPath'] # need to remove bucket name, connect dir from path
    if("/connect/" in recordingPath):
        recordingPath = "connect/" + recordingPath.split("/connect/", 1)[1]
    elif("/Analysis/" in recordingPath):
        recordingPath = "Analysis/" + recordingPath.split("/Analysis/", 1)[1]
    cloudfront_domain = get_arg(os.environ, 'CLOUDFRONT_DISTRIBUTION_DOMAIN_NAME')
    url = 'https://' + cloudfront_domain + '/' + recordingPath
    logger.info('Unsigned audio recording url: %s' % url)

    # sign url
    expire_date = datetime.datetime.utcnow() + datetime.timedelta(minutes=60)
    cloudfront_signer = CloudFrontSigner(access_key_id, rsa_signer(private_key))
    signed_url = cloudfront_signer.generate_presigned_url(
        url, date_less_than=expire_date)
    logger.info('Signed audio recording url: %s' % signed_url)
    return signed_url
def create_cloudfront_signed_url(
        object_name: str, expiration_date: datetime) -> str:
    """Generate a cloudfront signed URL to share an s3 object

    Arguments:
        object_name {str} -- Required. s3 object to share
        expiration_date {datetime} -- Required. Expiration datetime object of
                                        some future datetime

    Returns:
        str -- cloudfront signed URL
    """
    key_id = environ.get('AWS_CLOUDFRONT_USER_ACCESS_ID')
    url = '{cloudfront_domain}/{object_name}'.format(
        cloudfront_domain=environ.get('AWS_CLOUDFRONT_DOMAIN'),
        object_name=object_name
    )

    cloudfront_signer = CloudFrontSigner(key_id, rsa_signer)

    # Create a signed url that will be valid until the specfic expiry date
    # provided using a canned policy.
    signed_url = cloudfront_signer.generate_presigned_url(
        url, date_less_than=expiration_date)
    return signed_url
Esempio n. 5
0
def get_presigned_url() -> str:
    """
    Two query parameters are required:
    * url: Base URL for the file
    * resource: URL or stream name of the file

    This code uses botocore.signers.CloudFrontSigner to generate presigned URLs
    using a custom policy.

    See Amazon CloudFront documentation for more details on the signing process:
    https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html

    Example using cURL:
    curl 'http://localhost:8000/presigned-url?url=https://www.example.com/images/image.jpg&resource=https://www.example.com/images/*'

    :return str: The signed URL
    """
    config_file_path = os.path.join(os.path.dirname(__file__), 'config.json')
    with open(config_file_path) as config_file:
        config = json.load(config_file)
    private_key_id = config['private_key_id']

    request = app.current_request
    url = request.query_params['url']
    resource = request.query_params['resource']

    expire_date = datetime.now() + timedelta(minutes=+5)

    cf_signer = CloudFrontSigner(private_key_id, rsa_signer)
    cf_policy = cf_signer.build_policy(resource=resource,
                                       date_less_than=expire_date)
    presigned_url = cf_signer.generate_presigned_url(url, policy=cf_policy)

    return presigned_url
Esempio n. 6
0
    def get_url(self, obj):
        """Url of the Document.

        Parameters
        ----------
        obj : Type[models.Document]
            The document that we want to serialize

        Returns
        -------
        String or None
            the url to fetch the document on CloudFront
            None if the document is still not uploaded to S3 with success

        """
        if obj.uploaded_on is None:
            return None

        url = (
            f"{settings.AWS_S3_URL_PROTOCOL}://{settings.CLOUDFRONT_DOMAIN}/{obj.pk}/document/"
            f"{time_utils.to_timestamp(obj.uploaded_on)}{self._get_extension_string(obj)}?response"
            f"-content-disposition={quote_plus('attachment; filename=' + self.get_filename(obj))}"
        )

        # Sign the document urls only if the functionality is activated
        if settings.CLOUDFRONT_SIGNED_URLS_ACTIVE:
            date_less_than = timezone.now() + timedelta(
                seconds=settings.CLOUDFRONT_SIGNED_URLS_VALIDITY)
            cloudfront_signer = CloudFrontSigner(
                settings.CLOUDFRONT_SIGNED_PUBLIC_KEY_ID,
                cloudfront_utils.rsa_signer)
            url = cloudfront_signer.generate_presigned_url(
                url, date_less_than=date_less_than)

        return url
Esempio n. 7
0
class TestCloudfrontSigner(BaseSignerTest):
    def setUp(self):
        super(TestCloudfrontSigner, self).setUp()
        self.signer = CloudFrontSigner("MY_KEY_ID", lambda message: b'signed')
        # It helps but the long string diff will still be slightly different on
        # Python 2.6/2.7/3.x. We won't soly rely on that anyway, so it's fine.
        self.maxDiff = None

    def test_build_canned_policy(self):
        policy = self.signer.build_policy('foo', datetime.datetime(2016, 1, 1))
        expected = (
            '{"Statement":[{"Resource":"foo",'
            '"Condition":{"DateLessThan":{"AWS:EpochTime":1451606400}}}]}')
        self.assertEqual(json.loads(policy), json.loads(expected))
        self.assertEqual(policy, expected)  # This is to ensure the right order

    def test_build_custom_policy(self):
        policy = self.signer.build_policy(
            'foo', datetime.datetime(2016, 1, 1),
            date_greater_than=datetime.datetime(2015, 12, 1),
            ip_address='12.34.56.78/9')
        expected = {
            "Statement": [{
                "Resource": "foo",
                "Condition": {
                    "DateGreaterThan": {"AWS:EpochTime": 1448928000},
                    "DateLessThan": {"AWS:EpochTime": 1451606400},
                    "IpAddress": {"AWS:SourceIp": "12.34.56.78/9"}
                },
            }]
        }
        self.assertEqual(json.loads(policy), expected)

    def test_generate_presign_url_with_expire_time(self):
        signed_url = self.signer.generate_presigned_url(
            'http://test.com/foo.txt',
            date_less_than=datetime.datetime(2016, 1, 1))
        expected = (
            'http://test.com/foo.txt?Expires=1451606400&Signature=c2lnbmVk'
            '&Key-Pair-Id=MY_KEY_ID')
        assert_url_equal(signed_url, expected)

    def test_generate_presign_url_with_custom_policy(self):
        policy = self.signer.build_policy(
            'foo', datetime.datetime(2016, 1, 1),
            date_greater_than=datetime.datetime(2015, 12, 1),
            ip_address='12.34.56.78/9')
        signed_url = self.signer.generate_presigned_url(
            'http://test.com/index.html?foo=bar', policy=policy)
        expected = (
            'http://test.com/index.html?foo=bar'
            '&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiZm9vIiwiQ29uZ'
            'Gl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIj'
            'oxNDUxNjA2NDAwfSwiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI'
            '6IjEyLjM0LjU2Ljc4LzkifSwiRGF0ZUdyZWF0ZXJUaGFuIjp7IkFX'
            'UzpFcG9jaFRpbWUiOjE0NDg5MjgwMDB9fX1dfQ__'
            '&Signature=c2lnbmVk&Key-Pair-Id=MY_KEY_ID')
        assert_url_equal(signed_url, expected)
Esempio n. 8
0
class TestCloudfrontSigner(BaseSignerTest):
    def setUp(self):
        super(TestCloudfrontSigner, self).setUp()
        self.signer = CloudFrontSigner("MY_KEY_ID", lambda message: b'signed')
        # It helps but the long string diff will still be slightly different on
        # Python 2.6/2.7/3.x. We won't soly rely on that anyway, so it's fine.
        self.maxDiff = None

    def test_build_canned_policy(self):
        policy = self.signer.build_policy('foo', datetime.datetime(2016, 1, 1))
        expected = (
            '{"Statement":[{"Resource":"foo",'
            '"Condition":{"DateLessThan":{"AWS:EpochTime":1451606400}}}]}')
        self.assertEqual(json.loads(policy), json.loads(expected))
        self.assertEqual(policy, expected)  # This is to ensure the right order

    def test_build_custom_policy(self):
        policy = self.signer.build_policy(
            'foo', datetime.datetime(2016, 1, 1),
            date_greater_than=datetime.datetime(2015, 12, 1),
            ip_address='12.34.56.78/9')
        expected = {
            "Statement": [{
                "Resource": "foo",
                "Condition": {
                    "DateGreaterThan": {"AWS:EpochTime": 1448928000},
                    "DateLessThan": {"AWS:EpochTime": 1451606400},
                    "IpAddress": {"AWS:SourceIp": "12.34.56.78/9"}
                },
            }]
        }
        self.assertEqual(json.loads(policy), expected)

    def test_generate_presign_url_with_expire_time(self):
        signed_url = self.signer.generate_presigned_url(
            'http://test.com/foo.txt',
            date_less_than=datetime.datetime(2016, 1, 1))
        expected = (
            'http://test.com/foo.txt?Expires=1451606400&Signature=c2lnbmVk'
            '&Key-Pair-Id=MY_KEY_ID')
        self.assert_url_equal(signed_url, expected)

    def test_generate_presign_url_with_custom_policy(self):
        policy = self.signer.build_policy(
            'foo', datetime.datetime(2016, 1, 1),
            date_greater_than=datetime.datetime(2015, 12, 1),
            ip_address='12.34.56.78/9')
        signed_url = self.signer.generate_presigned_url(
            'http://test.com/index.html?foo=bar', policy=policy)
        expected = (
            'http://test.com/index.html?foo=bar'
            '&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiZm9vIiwiQ29uZ'
            'Gl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIj'
            'oxNDUxNjA2NDAwfSwiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI'
            '6IjEyLjM0LjU2Ljc4LzkifSwiRGF0ZUdyZWF0ZXJUaGFuIjp7IkFX'
            'UzpFcG9jaFRpbWUiOjE0NDg5MjgwMDB9fX1dfQ__'
            '&Signature=c2lnbmVk&Key-Pair-Id=MY_KEY_ID')
        self.assert_url_equal(signed_url, expected)
Esempio n. 9
0
def main():
    key_id = 'KF4ZWB2OGIN4A'
    url = 'https://d1za37rregmkz7.cloudfront.net/app1/var3.json'
    current_time = datetime.datetime.utcnow()
    expire_date = current_time + datetime.timedelta(minutes=2)
    cloudfront_signer = CloudFrontSigner(key_id, rsa_signer)
    signed_url = cloudfront_signer.generate_presigned_url(
        url, date_less_than=expire_date)
    print(signed_url)
Esempio n. 10
0
def get_image(event, context):
    event_string = json.dumps(event)
    print(event_string)
    image_name = event["queryStringParameters"]["image_name"]
    user_name = event["queryStringParameters"]["user_name"]
    if user_name != 'king-kong':
        return {
            "statusCode": 404,
            "body": json.dumps({
                "message": "You are trying to access premium property images, you need to subscribe for premium membership.",
            }),
              "headers":{ 'Access-Control-Allow-Origin' : '*' }
        }

    bucket_name = getImagesBucketName()
    print("Bucket name is {0}".format(bucket_name))
    
    try:
        #key_id = 'xxxxxxxxxxxxxxxxxxx'
        # reading value from parameter store
        key_id = getCloudFrontKeyId()
        print("Cloudfront Access key id is {0}".format(key_id))

        # reading value from parameter store    
        cf_distribution_name = getCloudFrontDistributionName()
        print("Cloudfront distribution name is {0}".format(cf_distribution_name))

        url = "https://" + cf_distribution_name + "/" + image_name
        expire_date = datetime.datetime(2020, 10, 10)
        cloudfront_signer = CloudFrontSigner(key_id, rsa_signer)

        # Create a signed url that will be valid until the specfic expiry date
        # provided using a canned policy.
        signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date)
        print("Pre-signed URL is {0}".format(signed_url))
                
        s3 = boto3.resource('s3')
        object = s3.Object(bucket_name,image_name).load()
        msg = "Image with name : " + image_name + " exists"
        return {
            "statusCode": 200,
            "body": json.dumps({
                "message": signed_url,
            }),
            "headers":{ 'Access-Control-Allow-Origin' : '*' }
        }
    except BaseException as error:
        print("*** Failure to retrieve Car Image - Please check your request ***")
        return {
            "statusCode": 404,
            "body": json.dumps({
                "message": str(error),
            }),
            "headers":{ 'Access-Control-Allow-Origin' : '*' }
        }
        
Esempio n. 11
0
def sign_url(url, expiry, key_id):

    cloudfront_signer = CloudFrontSigner(key_id, rsa_signer)

    # Create a signed url that will be valid until the specfic expiry date
    # provided using a canned policy.
    signed_url = cloudfront_signer.generate_presigned_url(
        url=url, date_less_than=expiry)
    
    return signed_url
Esempio n. 12
0
    def create_cloudfront_signed_url(object_name, expiration_date):
        from app import app

        key_id = app.config['CF_ID']
        url = app.config['CF_DOMAIN'] + object_name

        cloudfront_signer = CloudFrontSigner(key_id,
                                             ImageStorageService.rsa_signer)
        signed_url = cloudfront_signer.generate_presigned_url(
            url, date_less_than=expiration_date)

        return signed_url
Esempio n. 13
0
def get_cdn_presigned_url(url, expiration):
    
    PUBLIC_KEY_ID = config('CF_SIGNER_PUBLIC_KEY')

    cloudront_signer = CloudFrontSigner(PUBLIC_KEY_ID, rsa_signer)

    signed_url = cloudront_signer.generate_presigned_url(
        url,
        date_less_than=expiration
    )

    return signed_url
Esempio n. 14
0
    def __init__(
        self, request=None, domain=None, crypto_pk=None, key_id=None, **kwargs
    ):
        super(CloudFrontS3Storage, self).__init__(request, **kwargs)
        self.domain = domain
        self.crypto_pk = crypto_pk
        self.key_id = key_id

        self.cf_signer = None
        if key_id is not None:
            self.cf_signer = CloudFrontSigner(self.key_id, self._rsa_signer)

        self.client = boto3.client("cloudfront")
Esempio n. 15
0
    def get_urls(self, obj):
        """Urls of the video for each type of encoding and in each resolution.

        Parameters
        ----------
        obj : Type[models.Video]
            The video that we want to serialize

        Returns
        -------
        Dictionary or None
            A dictionary of all urls for:
                - mp4 encodings of the video in each resolution
                - jpeg thumbnails of the video in each resolution
            None if the video is still not uploaded to S3 with success

        """
        if obj.uploaded_on is None or obj.state != Video.READY:
            return None

        urls = {"mp4": {}, "thumbnails": {}}
        base = "{cloudfront:s}/{playlist!s}/{video!s}".format(
            cloudfront=settings.CLOUDFRONT_URL,
            playlist=obj.playlist.id,
            video=obj.id)

        date_less_than = timezone.now() + timedelta(
            seconds=settings.CLOUDFRONT_SIGNED_URLS_VALIDITY)
        for resolution in settings.VIDEO_RESOLUTIONS:
            # MP4
            mp4_url = "{base:s}/videos/{stamp:s}_{resolution:d}.mp4".format(
                base=base, stamp=obj.active_stamp, resolution=resolution)

            # Thumbnails
            thumbnail_url = "{base:s}/thumbnails/{stamp:s}_{resolution:d}.0000000.jpg".format(
                base=base, stamp=obj.active_stamp, resolution=resolution)

            # Sign urls if the functionality is activated
            if settings.CLOUDFRONT_SIGNED_URLS_ACTIVE:
                cloudfront_signer = CloudFrontSigner(
                    settings.CLOUDFRONT_ACCESS_KEY_ID,
                    cloudfront_utils.rsa_signer)
                mp4_url = cloudfront_signer.generate_presigned_url(
                    mp4_url, date_less_than=date_less_than)
                thumbnail_url = cloudfront_signer.generate_presigned_url(
                    thumbnail_url, date_less_than=date_less_than)

            urls["mp4"][resolution] = mp4_url
            urls["thumbnails"][resolution] = thumbnail_url

        return json.dumps(urls)
Esempio n. 16
0
    def generate_presigned_cloudfront_url(self, url, expire_time, keypair_id,
                                          private_key_string):
        # From https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#generate-a-signed-url-for-amazon-cloudfront
        def rsa_signer(message):
            private_key = serialization.load_pem_private_key(
                private_key_string, password=None, backend=default_backend())
            return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())

        cloudfront_signer = CloudFrontSigner(keypair_id, rsa_signer)

        # Create a signed url that will be valid until the specfic expiry date
        # provided using a canned policy.
        return cloudfront_signer.generate_presigned_url(
            url, date_less_than=expire_time)
Esempio n. 17
0
def signed_cf_url(bucket, key, expires_in_days=7):
    policy = f"""{{
       "Statement": [
          {{
             "Resource":"https://{bucket}/{key}",
             "Condition":{{
                "DateLessThan":{{"AWS:EpochTime":
                {int((datetime.datetime.today() + datetime.timedelta(days=expires_in_days)).timestamp())}}}
             }}
          }}
       ]
    }}"""
    cloudfront_signer = CloudFrontSigner(settings.CF_ACCESS_KEY, rsa_signer)
    return cloudfront_signer.generate_presigned_url(f'https://{bucket}/{key}', policy=policy)
    def _cloud_front_signer_from_pem(key_id, pem):
        key = load_pem_private_key(pem,
                                   password=None,
                                   backend=default_backend())

        return CloudFrontSigner(
            key_id, lambda x: key.sign(x, padding.PKCS1v15(), hashes.SHA1()))
Esempio n. 19
0
def main():
    sess = session.get_session()
    session.profile = SYSOP
    session.region = REGION

    # JST, not use timezone
    expire = datetime.now() + timedelta(minutes=EXPIRE) - timedelta(hours=9)

    cloudfront_signer = CloudFrontSigner(KEY_ID, get_rsa_signer)

    signed_url = cloudfront_signer.generate_presigned_url(
            URL,
            date_less_than=expire,
    )

    print(signed_url)
Esempio n. 20
0
def get_signed_url(url, config_map):
    """ Convenience function for getting cloudfront signed URL given a saved URL

    cjshaw, Jan 7, 2015

    Follows:
        http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/
            private-content-creating-signed-url-canned-policy.html#private-
            content-creating-signed-url-canned-policy-procedure
        http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/
            PrivateContent.html
        http://boto.readthedocs.org/en/latest/ref/cloudfront.html

    May 25, 2017: Switch to boto3

    """

    # From https://stackoverflow.com/a/34322915
    def rsa_signer(message):
        private_key = open(config_map['cloudfront_private_key_file'],
                           'r').read()
        return rsa.sign(message,
                        rsa.PrivateKey.load_pkcs1(private_key.encode('utf8')),
                        'SHA-1')  # CloudFront requires SHA-1 hash

    if any(config_map[key] == '' for key in [
            's3_bucket', 'cloudfront_distro', 'cloudfront_private_key_file',
            'cloudfront_keypair_id'
    ]):
        # This is a test configuration
        return 'You are missing S3 and CF configs: https:///?Expires=X&Signature=X&Key-Pair-Id='

    expires = datetime.datetime.utcnow() + datetime.timedelta(days=7)
    s3_bucket = config_map['s3_bucket']

    url = url.replace(s3_bucket + '.s3.amazonaws.com',
                      config_map['cloudfront_distro'])

    if not AWS_CLIENT.is_aws_cf_client_set():
        cf_signer = CloudFrontSigner(config_map['cloudfront_keypair_id'],
                                     rsa_signer)
        AWS_CLIENT.set_aws_cf_client(cf_signer)
    else:
        cf_signer = AWS_CLIENT.cf
    signed_url = cf_signer.generate_presigned_url(url, date_less_than=expires)
    return signed_url
Esempio n. 21
0
    def __init__(self,
                 request=None,
                 domain=None,
                 private_key=None,
                 key_id=None,
                 **kwargs):
        super(CloudFrontS3Storage, self).__init__(request, **kwargs)
        self.domain = domain
        self.private_key = private_key
        self.key_id = key_id
        self.private_key = private_key

        self.cf_signer = None
        if key_id is not None:
            self.cf_signer = CloudFrontSigner(self.key_id, self._rsa_signer)

        self.client = boto3.client('cloudfront')
Esempio n. 22
0
 def _run_main(self, args, parsed_globals):
     signer = CloudFrontSigner(
         args.key_pair_id, RSASigner(args.private_key).sign)
     date_less_than = parse_to_aware_datetime(args.date_less_than)
     date_greater_than = args.date_greater_than
     if date_greater_than is not None:
         date_greater_than = parse_to_aware_datetime(date_greater_than)
     if date_greater_than is not None or args.ip_address is not None:
         policy = signer.build_policy(
             args.url, date_less_than, date_greater_than=date_greater_than,
             ip_address=args.ip_address)
         sys.stdout.write(signer.generate_presigned_url(
             args.url, policy=policy))
     else:
         sys.stdout.write(signer.generate_presigned_url(
             args.url, date_less_than=date_less_than))
     return 0
Esempio n. 23
0
def generate_cloudfront_urls_signed_parameters(resource, date_less_than):
    """
    Generate all parameters use by a cloudfront signed url.
    Mainly extracted from CloudFrontSigner class.
    """
    cloudfront_signer = CloudFrontSigner(
        settings.CLOUDFRONT_SIGNED_PUBLIC_KEY_ID,
        rsa_signer,
    )
    policy = cloudfront_signer.build_policy(
        resource=resource, date_less_than=date_less_than).encode("utf8")
    signature = cloudfront_signer.rsa_signer(policy)
    return [
        f"Policy={_url_b64encode(policy).decode('utf8')}",
        f"Signature={_url_b64encode(signature).decode('utf8')}",
        f"Key-Pair-Id={cloudfront_signer.key_id}",
    ]
Esempio n. 24
0
    def generate_cloudfront_url(self,
                                key,
                                cloudfront_domain,
                                cloudfront_key_id,
                                cloudfront_private_key,
                                url_expiration_time=60 * 60 * 24 * 90,
                                force_http_url=False
                                ):
        """
        Generate presigned url for object on bucket
        :param url_expiration_time: time until url expires in seconds
        :type url_expiration_time: int
        :param key:  path to object on bucket
        :return: url
        :rtype str
        """
        if key is None:
            return

        key = ensure_unicode(key)

        key = key.lstrip('/')

        url = 'https://{}/{}'.format(cloudfront_domain, key)

        def rsa_signer(message):
            private_key = cloudfront_private_key
            return rsa.sign(
                message,
                rsa.PrivateKey.load_pkcs1(private_key.encode('utf8')),
                'SHA-1'
            )  # CloudFront requires SHA-1 hash

        cloudfront_signer = CloudFrontSigner(cloudfront_key_id,
                                             rsa_signer)
        expiry_datetime = (
            datetime.utcnow() +
            timedelta(seconds=url_expiration_time)
        )
        presigned_url = cloudfront_signer.generate_presigned_url(
            url, date_less_than=expiry_datetime
        )

        if force_http_url:
            presigned_url = presigned_url.replace('https://', 'http://')
        return presigned_url
Esempio n. 25
0
    def _cloud_front_signer_from_pem(key_id, pem):
        if isinstance(pem, str):
            pem = pem.encode('ascii')
        key = load_pem_private_key(
            pem, password=None, backend=default_backend())

        return CloudFrontSigner(
            key_id, lambda x: key.sign(x, padding.PKCS1v15(), hashes.SHA1()))
Esempio n. 26
0
    def get_url(self, obj):
        """Url of the Document.

        Parameters
        ----------
        obj : Type[models.Document]
            The document that we want to serialize

        Returns
        -------
        String or None
            the url to fetch the document on CloudFront
            None if the document is still not uploaded to S3 with success

        """
        if obj.uploaded_on is None:
            return None

        url = (
            "{protocol:s}://{cloudfront:s}/{pk!s}/document/{stamp:s}{extension:s}"
            "?response-content-disposition={content_disposition:s}"
        ).format(
            protocol=settings.AWS_S3_URL_PROTOCOL,
            cloudfront=settings.CLOUDFRONT_DOMAIN,
            pk=obj.pk,
            stamp=time_utils.to_timestamp(obj.uploaded_on),
            content_disposition=quote_plus(
                "attachment; filename=" + self.get_filename(obj)
            ),
            extension=self._get_extension_string(obj),
        )

        # Sign the document urls only if the functionality is activated
        if settings.CLOUDFRONT_SIGNED_URLS_ACTIVE:
            date_less_than = timezone.now() + timedelta(
                seconds=settings.CLOUDFRONT_SIGNED_URLS_VALIDITY
            )
            cloudfront_signer = CloudFrontSigner(
                settings.CLOUDFRONT_ACCESS_KEY_ID, cloudfront_utils.rsa_signer
            )
            url = cloudfront_signer.generate_presigned_url(
                url, date_less_than=date_less_than
            )

        return url
Esempio n. 27
0
    def _cloudfront_signer(self):
        with open(settings.CLOUDFRONT_PRIVATE_KEY_PATH, "rb") as key_file:
            private_key = serialization.load_pem_private_key(
                key_file.read(), password=None, backend=default_backend())

        return CloudFrontSigner(
            settings.CLOUDFRONT_KEY_PAIR_ID,
            lambda m: private_key.sign(m, padding.PKCS1v15(), hashes.SHA1()),
        )
Esempio n. 28
0
    def _sign_url(self, url):
        """Generate a presigned cloudfront url.

        Parameters
        ----------
        url: string
            The url to sign

        Returns:
        string
            The signed url

        """
        date_less_than = timezone.now() + timedelta(
            seconds=settings.CLOUDFRONT_SIGNED_URLS_VALIDITY)
        cloudfront_signer = CloudFrontSigner(settings.CLOUDFRONT_ACCESS_KEY_ID,
                                             cloudfront_utils.rsa_signer)
        return cloudfront_signer.generate_presigned_url(
            url, date_less_than=date_less_than)
Esempio n. 29
0
class CloudFrontS3Storage(S3Storage):
    """ Storage backend that uses S3 and CloudFront """
    def __init__(self,
                 request=None,
                 domain=None,
                 private_key=None,
                 key_id=None,
                 **kwargs):
        super(CloudFrontS3Storage, self).__init__(request, **kwargs)
        self.domain = domain
        self.private_key = private_key
        self.key_id = key_id
        self.private_key = private_key

        self.cf_signer = None
        if key_id is not None:
            self.cf_signer = CloudFrontSigner(self.key_id, self._rsa_signer)

        self.client = boto3.client('cloudfront')

    @classmethod
    def configure(cls, settings):
        kwargs = super(CloudFrontS3Storage, cls).configure(settings)
        kwargs['domain'] = settings['storage.cloud_front_domain']
        kwargs['key_id'] = settings.get('storage.cloud_front_key_id')
        private_key = settings.get('storage.cloud_front_key_string')
        if private_key is None:
            key_file = settings.get('storage.cloud_front_key_file')
            if key_file:
                with open(key_file, 'r') as ifile:
                    private_key = ifile.read()
        kwargs['private_key'] = private_key

        return kwargs

    def _rsa_signer(self, message):
        """ Generate a RSA signature for a message """
        return rsa.sign(message,
                        rsa.PrivateKey.load_pkcs1(
                            self.private_key.encode('utf8')),
                        'SHA-1')  # CloudFront requires SHA-1 hash

    def _generate_url(self, package):
        """ Get the fully-qualified CloudFront path for a package """
        path = self.get_path(package)
        url = self.domain + '/' + quote(path)

        # No key id, no signer, so we don't have to sign the URL
        if self.cf_signer is None:
            return url

        # To sign with a canned policy:
        expires = datetime.utcnow() + timedelta(seconds=self.expire_after)
        return self.cf_signer.generate_presigned_url(url,
                                                     date_less_than=expires)
Esempio n. 30
0
class CloudFrontS3Storage(S3Storage):
    """ Storage backend that uses S3 and CloudFront """
    def __init__(self,
                 request=None,
                 domain=None,
                 crypto_pk=None,
                 key_id=None,
                 **kwargs):
        super(CloudFrontS3Storage, self).__init__(request, **kwargs)
        self.domain = domain
        self.crypto_pk = crypto_pk
        self.key_id = key_id

        self.cf_signer = None
        if key_id is not None:
            self.cf_signer = CloudFrontSigner(self.key_id, self._rsa_signer)

        self.client = boto3.client("cloudfront")

    @classmethod
    def configure(cls, settings):
        kwargs = super(CloudFrontS3Storage, cls).configure(settings)
        kwargs["domain"] = settings["storage.cloud_front_domain"]
        kwargs["key_id"] = settings.get("storage.cloud_front_key_id")
        private_key = settings.get("storage.cloud_front_key_string")
        if private_key is None:
            key_file = settings.get("storage.cloud_front_key_file")
            if key_file:
                with open(key_file, "rb") as ifile:
                    private_key = ifile.read()
        else:
            private_key = private_key.encode("utf-8")
        crypto_pk = serialization.load_pem_private_key(
            private_key, password=None, backend=default_backend())
        kwargs["crypto_pk"] = crypto_pk

        return kwargs

    def _rsa_signer(self, message):
        """ Generate a RSA signature for a message """
        return self.crypto_pk.sign(message, padding.PKCS1v15(), hashes.SHA1())

    def _generate_url(self, package):
        """ Get the fully-qualified CloudFront path for a package """
        path = self.get_path(package)
        url = self.domain + "/" + quote(path)

        # No key id, no signer, so we don't have to sign the URL
        if self.cf_signer is None:
            return url

        # To sign with a canned policy:
        expires = utcnow() + timedelta(seconds=self.expire_after)
        return self.cf_signer.generate_presigned_url(url,
                                                     date_less_than=expires)
Esempio n. 31
0
    def get_url(self, obj):
        """Url of the timed text track, signed with a CloudFront key if activated.

        Parameters
        ----------
        obj : Type[models.TimedTextTrack]
            The timed text track that we want to serialize

        Returns
        -------
        string or None
            The url for the timed text track converted to vtt.
            None if the timed text track is still not uploaded to S3 with success.

        """
        if obj.uploaded_on:

            base = "{protocol:s}://{cloudfront:s}/{video!s}".format(
                protocol=settings.AWS_S3_URL_PROTOCOL,
                cloudfront=settings.CLOUDFRONT_DOMAIN,
                video=obj.video.pk,
            )
            url = "{base:s}/timedtext/{stamp:s}_{language:s}{mode:s}.vtt".format(
                base=base,
                stamp=time_utils.to_timestamp(obj.uploaded_on),
                language=obj.language,
                mode="_{:s}".format(obj.mode) if obj.mode else "",
            )

            # Sign the url only if the functionality is activated
            if settings.CLOUDFRONT_SIGNED_URLS_ACTIVE:
                date_less_than = timezone.now() + timedelta(
                    seconds=settings.CLOUDFRONT_SIGNED_URLS_VALIDITY
                )
                cloudfront_signer = CloudFrontSigner(
                    settings.CLOUDFRONT_ACCESS_KEY_ID, cloudfront_utils.rsa_signer
                )
                url = cloudfront_signer.generate_presigned_url(
                    url, date_less_than=date_less_than
                )
            return url
        return None
Esempio n. 32
0
class CloudFrontS3Storage(S3Storage):

    """ Storage backend that uses S3 and CloudFront """

    def __init__(
        self, request=None, domain=None, crypto_pk=None, key_id=None, **kwargs
    ):
        super(CloudFrontS3Storage, self).__init__(request, **kwargs)
        self.domain = domain
        self.crypto_pk = crypto_pk
        self.key_id = key_id

        self.cf_signer = None
        if key_id is not None:
            self.cf_signer = CloudFrontSigner(self.key_id, self._rsa_signer)

        self.client = boto3.client("cloudfront")

    @classmethod
    def configure(cls, settings):
        kwargs = super(CloudFrontS3Storage, cls).configure(settings)
        kwargs["domain"] = settings["storage.cloud_front_domain"]
        kwargs["key_id"] = settings.get("storage.cloud_front_key_id")
        private_key = settings.get("storage.cloud_front_key_string")
        if private_key is None:
            key_file = settings.get("storage.cloud_front_key_file")
            if key_file:
                with open(key_file, "rb") as ifile:
                    private_key = ifile.read()
        else:
            private_key = private_key.encode("utf-8")
        crypto_pk = serialization.load_pem_private_key(
            private_key, password=None, backend=default_backend()
        )
        kwargs["crypto_pk"] = crypto_pk

        return kwargs

    def _rsa_signer(self, message):
        """ Generate a RSA signature for a message """
        return self.crypto_pk.sign(message, padding.PKCS1v15(), hashes.SHA1())

    def _generate_url(self, package):
        """ Get the fully-qualified CloudFront path for a package """
        path = self.get_path(package)
        url = self.domain + "/" + quote(path)

        # No key id, no signer, so we don't have to sign the URL
        if self.cf_signer is None:
            return url

        # To sign with a canned policy:
        expires = datetime.utcnow() + timedelta(seconds=self.expire_after)
        return self.cf_signer.generate_presigned_url(url, date_less_than=expires)
Esempio n. 33
0
def generate_signed_cloudfront_url(path=None,
                                   cloudfront_url=settings.CLOUDFRONT_URL,
                                   *args,
                                   **kwargs):
    if path is None:
        raise ValueError("Must provide a path for the CloudFront url to sign")

    key_id = kwargs.get('key_id') or settings.CLOUDFRONT_KEY_ID
    expiry = kwargs.get('expiry') or 120
    current_time = datetime.datetime.utcnow()
    expire_date = current_time + datetime.timedelta(seconds=expiry)
    rsa_signer_ = kwargs.get('rsa_signer') or rsa_signer

    cloudfront_signer = CloudFrontSigner(key_id, rsa_signer_)
    url = cloudfront_url + path

    # Create a signed url that will be valid until the specific expiry date provided using a canned policy
    signed_url = cloudfront_signer.generate_presigned_url(
        url, date_less_than=expire_date)
    return signed_url
Esempio n. 34
0
    def __init__(
        self, request=None, domain=None, crypto_pk=None, key_id=None, **kwargs
    ):
        super(CloudFrontS3Storage, self).__init__(request, **kwargs)
        self.domain = domain
        self.crypto_pk = crypto_pk
        self.key_id = key_id

        self.cf_signer = None
        if key_id is not None:
            self.cf_signer = CloudFrontSigner(self.key_id, self._rsa_signer)

        self.client = boto3.client("cloudfront")
Esempio n. 35
0
 def setUp(self):
     self.signer = CloudFrontSigner("MY_KEY_ID", lambda message: b'signed')
     # It helps but the long string diff will still be slightly different on
     # Python 2.6/2.7/3.x. We won't soly rely on that anyway, so it's fine.
     self.maxDiff = None
Esempio n. 36
0
class TestCloudfrontSigner(unittest.TestCase):
    def setUp(self):
        self.signer = CloudFrontSigner("MY_KEY_ID", lambda message: b'signed')
        # It helps but the long string diff will still be slightly different on
        # Python 2.6/2.7/3.x. We won't soly rely on that anyway, so it's fine.
        self.maxDiff = None

    def test_build_canned_policy(self):
        policy = self.signer.build_policy('foo', datetime.datetime(2016, 1, 1))
        expected = (
            '{"Statement":[{"Resource":"foo",'
            '"Condition":{"DateLessThan":{"AWS:EpochTime":1451606400}}}]}')
        self.assertEqual(json.loads(policy), json.loads(expected))
        self.assertEqual(policy, expected)  # This is to ensure the right order

    def test_build_custom_policy(self):
        policy = self.signer.build_policy(
            'foo', datetime.datetime(2016, 1, 1),
            date_greater_than=datetime.datetime(2015, 12, 1),
            ip_address='12.34.56.78/9')
        expected = {
            "Statement": [{
                "Resource": "foo",
                "Condition": {
                    "DateGreaterThan": {"AWS:EpochTime": 1448928000},
                    "DateLessThan": {"AWS:EpochTime": 1451606400},
                    "IpAddress": {"AWS:SourceIp": "12.34.56.78/9"}
                },
            }]
        }
        self.assertEqual(json.loads(policy), expected)

    def _urlparse(self, url):
        if isinstance(url, six.binary_type):
            # Not really necessary, but it helps to reduce noise on Python 2.x
            url = url.decode('utf8')
        return dict(urlparse(url)._asdict())  # Needs an unordered dict here

    def assertEqualUrl(self, url1, url2):
        # We compare long urls by their dictionary parts
        parts1 = self._urlparse(url1)
        parts2 = self._urlparse(url2)
        self.assertEqual(
            parse_qs(parts1.pop('query')), parse_qs(parts2.pop('query')))
        self.assertEqual(parts1, parts2)

    def test_generate_presign_url_with_expire_time(self):
        signed_url = self.signer.generate_presigned_url(
            'http://test.com/foo.txt',
            date_less_than=datetime.datetime(2016, 1, 1))
        expected = (
            'http://test.com/foo.txt?Expires=1451606400&Signature=c2lnbmVk'
            '&Key-Pair-Id=MY_KEY_ID')
        self.assertEqualUrl(signed_url, expected)

    def test_generate_presign_url_with_custom_policy(self):
        policy = self.signer.build_policy(
            'foo', datetime.datetime(2016, 1, 1),
            date_greater_than=datetime.datetime(2015, 12, 1),
            ip_address='12.34.56.78/9')
        signed_url = self.signer.generate_presigned_url(
            'http://test.com/index.html?foo=bar', policy=policy)
        expected = (
            'http://test.com/index.html?foo=bar'
            '&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiZm9vIiwiQ29uZ'
            'Gl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIj'
            'oxNDUxNjA2NDAwfSwiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI'
            '6IjEyLjM0LjU2Ljc4LzkifSwiRGF0ZUdyZWF0ZXJUaGFuIjp7IkFX'
            'UzpFcG9jaFRpbWUiOjE0NDg5MjgwMDB9fX1dfQ__'
            '&Signature=c2lnbmVk&Key-Pair-Id=MY_KEY_ID')
        self.assertEqualUrl(signed_url, expected)