def generate_presigned_url(self, url, date_less_than=None, policy=None): """Creates a signed CloudFront URL based on given parameters. :type url: str :param url: The URL of the protected object :type date_less_than: datetime :param date_less_than: The URL will expire after that date and time :type policy: str :param policy: The custom policy, possibly built by self.build_policy() :rtype: str :return: The signed URL. """ if (date_less_than is not None and policy is not None or date_less_than is None and policy is None): e = 'Need to provide either date_less_than or policy, but not both' raise ValueError(e) if date_less_than is not None: # We still need to build a canned policy for signing purpose policy = self.build_policy(url, date_less_than) if isinstance(policy, six.text_type): policy = policy.encode('utf8') if date_less_than is not None: params = ['Expires=%s' % int(datetime2timestamp(date_less_than))] else: params = ['Policy=%s' % self._url_b64encode(policy).decode('utf8')] signature = self.rsa_signer(policy) params.extend([ 'Signature=%s' % self._url_b64encode(signature).decode('utf8'), 'Key-Pair-Id=%s' % self.key_id, ]) return self._build_url(url, params)
def filter_log_events( self, log_group_name, # type: str start_time=None, # type: Optional[datetime] next_token=None, # type: Optional[str] ): # type: (...) -> LogEventsResponse logs = self._client('logs') kwargs = { 'logGroupName': log_group_name, 'interleaved': True, } if start_time is not None: kwargs['startTime'] = int(datetime2timestamp(start_time) * 1000) if next_token is not None: kwargs['nextToken'] = next_token try: response = logs.filter_log_events(**kwargs) except logs.exceptions.ResourceNotFoundException: # If there's no log messages yet then we'll just return # an empty response. return {'events': []} # We want to convert the individual events that have integer # types over to datetime objects so it's easier for us to # work with. self._convert_types_on_response(response) return response
def to_epoch_millis(self, timestamp): re_match = self._RELATIVE_TIMESTAMP_REGEX.match(timestamp) if re_match: datetime_value = self._relative_timestamp_to_datetime( int(re_match.group('amount')), re_match.group('unit')) else: datetime_value = parse_timestamp(timestamp) return int(datetime2timestamp(datetime_value) * 1000)
def to_epoch_millis(timestamp): regex = re.compile(r"(?P<amount>\d+)(?P<unit>s|m|h|d|w)$") re_match = regex.match(timestamp) if re_match: datetime_value = _relative_timestamp_to_datetime( int(re_match.group('amount')), re_match.group('unit')) else: datetime_value = parse_timestamp(timestamp) return int(datetime2timestamp(datetime_value) * 1000)
def test_sso_source_profile(self): token_cache_key = 'f395038c92f1828cbb3991d2d6152d326b895606' cached_token = { 'accessToken': 'a.token', 'expiresAt': self.some_future_time(), } temp_cache = JSONFileCache(self.tempdir) temp_cache[token_cache_key] = cached_token config = ('[profile A]\n' 'role_arn = arn:aws:iam::123456789:role/RoleA\n' 'source_profile = B\n' '[profile B]\n' 'sso_region = us-east-1\n' 'sso_start_url = https://test.url/start\n' 'sso_role_name = SSORole\n' 'sso_account_id = 1234567890\n') self.write_config(config) session, sts_stubber = self.create_session(profile='A') client_config = Config( region_name='us-east-1', signature_version=UNSIGNED, ) sso_stubber = session.stub('sso', config=client_config) sso_stubber.activate() # The expiration needs to be in milliseconds expiration = datetime2timestamp(self.some_future_time()) * 1000 sso_role_creds = self.create_random_credentials() sso_role_response = { 'roleCredentials': { 'accessKeyId': sso_role_creds.access_key, 'secretAccessKey': sso_role_creds.secret_key, 'sessionToken': sso_role_creds.token, 'expiration': int(expiration), } } sso_stubber.add_response('get_role_credentials', sso_role_response) expected_creds = self.create_random_credentials() assume_role_response = self.create_assume_role_response(expected_creds) sts_stubber.add_response('assume_role', assume_role_response) actual_creds = session.get_credentials() self.assert_creds_equal(actual_creds, expected_creds) sts_stubber.assert_no_pending_responses() # Assert that the client was created with the credentials from the # SSO get role credentials response self.assertEqual(self.mock_client_creator.call_count, 1) _, kwargs = self.mock_client_creator.call_args_list[0] expected_kwargs = { 'aws_access_key_id': sso_role_creds.access_key, 'aws_secret_access_key': sso_role_creds.secret_key, 'aws_session_token': sso_role_creds.token, } self.assertEqual(kwargs, expected_kwargs)
def build_policy(self, resource, date_less_than, date_greater_than=None, ip_address=None): """A helper to build policy. :type resource: str :param resource: The URL or the stream filename of the protected object :type date_less_than: datetime :param date_less_than: The URL will expire after the time has passed :type date_greater_than: datetime :param date_greater_than: The URL will not be valid until this time :type ip_address: str :param ip_address: Use 'x.x.x.x' for an IP, or 'x.x.x.x/x' for a subnet :rtype: str :return: The policy in a compact string. """ # Note: # 1. Order in canned policy is significant. Special care has been taken # to ensure the output will match the order defined by the document. # There is also a test case to ensure that order. # SEE: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-canned-policy.html#private-content-canned-policy-creating-policy-statement # 2. Albeit the order in custom policy is not required by CloudFront, # we still use OrderedDict internally to ensure the result is stable # and also matches canned policy requirement. # SEE: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html moment = int(datetime2timestamp(date_less_than)) condition = OrderedDict({"DateLessThan": {"AWS:EpochTime": moment}}) if ip_address: if '/' not in ip_address: ip_address += '/32' condition["IpAddress"] = {"AWS:SourceIp": ip_address} if date_greater_than: moment = int(datetime2timestamp(date_greater_than)) condition["DateGreaterThan"] = {"AWS:EpochTime": moment} ordered_payload = [('Resource', resource), ('Condition', condition)] custom_policy = {"Statement": [OrderedDict(ordered_payload)]} return json.dumps(custom_policy, separators=(',', ':'))
def _register_client(self): timestamp = datetime2timestamp(self._time_fetcher()) response = self._client.register_client( # NOTE: As far as I know client name will never be returned to the # user. For now we'll just use botocore-client with the timestamp. clientName='botocore-client-%s' % int(timestamp), clientType=self._CLIENT_REGISTRATION_TYPE, ) expires_at = response['clientSecretExpiresAt'] expires_at = datetime.datetime.fromtimestamp(expires_at, tzutc()) registration = { 'clientId': response['clientId'], 'clientSecret': response['clientSecret'], 'expiresAt': expires_at, } return registration
def test_datetime2timestamp_aware(self): tzinfo = tzoffset("BRST", -10800) self.assertEqual( datetime2timestamp(datetime.datetime(1970, 1, 2, tzinfo=tzinfo)), 97200)
def test_datetime2timestamp_naive(self): self.assertEqual( datetime2timestamp(datetime.datetime(1970, 1, 2)), 86400)
def test_datetime2timestamp_naive(self): self.assertEqual(datetime2timestamp(datetime.datetime(1970, 1, 2)), 86400)