Exemplo n.º 1
0
    def test_signed_url_wrong_method(self):
        send_mock = mock.Mock()
        self.protocol.sendMessage = send_mock

        data = urls.create_signed_url('secret',
                                      ['/v2/queues/myqueue/messages'],
                                      project=self.project_id,
                                      methods=['GET'])

        headers = self.headers.copy()
        headers.update({
            'URL-Signature': data['signature'],
            'URL-Expires': data['expires'],
            'URL-Methods': ['GET'],
            'URL-Paths': ['/v2/queues/myqueue/messages']
        })
        req = json.dumps({
            'action': 'message_delete',
            'body': {
                'queue_name': 'myqueue',
                'message_id': '123'
            },
            'headers': headers
        })
        self.protocol.onMessage(req, False)

        self.assertEqual(1, send_mock.call_count)
        resp = json.loads(send_mock.call_args[0][0])
        self.assertEqual(403, resp['headers']['status'])
Exemplo n.º 2
0
    def test_create_signed_url_multiple_paths(self):
        timeutils.set_time_override()
        self.addCleanup(timeutils.clear_time_override)

        key = six.b('test')
        methods = ['POST']
        project = 'my-project'
        paths = [
            '/v2/queues/shared/messages', '/v2/queues/shared/subscriptions'
        ]
        expires = timeutils.utcnow() + datetime.timedelta(days=1)
        expires_str = expires.strftime(urls._DATE_FORMAT)

        hmac_body = six.b(
            r'%(paths)s\n%(methods)s\n'
            r'%(project)s\n%(expires)s' % {
                'paths': ','.join(paths),
                'methods': ','.join(methods),
                'project': project,
                'expires': expires_str
            })

        expected = hmac.new(key, hmac_body, hashlib.sha256).hexdigest()
        actual = urls.create_signed_url(key,
                                        paths,
                                        methods=['POST'],
                                        project=project)
        self.assertEqual(expected, actual['signature'])
Exemplo n.º 3
0
    def test_create_signed_url_utc(self):
        """Test that the method converts the TZ to UTC."""
        date_str = '2100-05-31T19:00:17+02'
        date_str_utc = '2100-05-31T17:00:17'

        key = six.b('test')
        project = None
        methods = ['GET']
        paths = ['/v2/queues/shared/messages']
        parsed = timeutils.parse_isotime(date_str_utc)
        expires = timeutils.normalize_time(parsed)
        expires_str = expires.strftime(urls._DATE_FORMAT)

        hmac_body = six.b(
            '%(paths)s\\n%(methods)s\\n'
            '%(project)s\\n%(expires)s' % {
                'paths': ','.join(paths),
                'methods': ','.join(methods),
                'project': project,
                'expires': expires_str
            })

        expected = hmac.new(key, hmac_body, hashlib.sha256).hexdigest()
        actual = urls.create_signed_url(key, paths, expires=date_str)
        self.assertEqual(expected, actual['signature'])
Exemplo n.º 4
0
    def on_post(self, req, resp, project_id, queue_name):
        LOG.debug(u'Pre-Signed URL Creation for queue: %(queue)s, '
                  u'project: %(project)s',
                  {'queue': queue_name, 'project': project_id})

        try:
            document = wsgi_utils.deserialize(req.stream, req.content_length)
        except ValueError as ex:
            LOG.debug(ex)
            raise wsgi_errors.HTTPBadRequestAPI(six.text_type(ex))

        diff = set(document.keys()) - _KNOWN_KEYS
        if diff:
            msg = six.text_type(_LE('Unknown keys: %s') % diff)
            raise wsgi_errors.HTTPBadRequestAPI(msg)

        key = self._conf.signed_url.secret_key
        paths = document.pop('paths', None)
        if not paths:
            paths = [os.path.join(req.path[:-6], 'messages')]
        else:
            diff = set(paths) - _VALID_PATHS
            if diff:
                msg = six.text_type(_LE('Invalid paths: %s') % diff)
                raise wsgi_errors.HTTPBadRequestAPI(msg)
            paths = [os.path.join(req.path[:-6], path) for path in paths]

        try:
            data = urls.create_signed_url(key, paths,
                                          project=project_id,
                                          **document)
        except ValueError as err:
            raise wsgi_errors.HTTPBadRequestAPI(str(err))

        resp.body = utils.to_json(data)
Exemplo n.º 5
0
    def send_confirm_notification(self, queue, subscription, conf,
                                  project=None, expires=None,
                                  api_version=None, is_unsubscribed=False):
        # NOTE(flwang): If the confirmation feature isn't enabled, just do
        # nothing. Here we're getting the require_confirmation from conf
        # object instead of using self.require_confirmation, because the
        # variable from self object really depends on the kwargs when
        # initializing the NotifierDriver object. See bug 1655812 for more
        # information.
        if not conf.notification.require_confirmation:
            return

        key = conf.signed_url.secret_key
        if not key:
            LOG.error("Can't send confirm notification due to the value of"
                      " secret_key option is None")
            return
        url = "/%s/queues/%s/subscriptions/%s/confirm" % (api_version, queue,
                                                          subscription['id'])
        pre_url = urls.create_signed_url(key, [url], project=project,
                                         expires=expires, methods=['PUT'])
        message = None
        if is_unsubscribed:
            message_type = MessageType.UnsubscribeConfirmation.name
            message = ('You have unsubscribed successfully to the queue: %s, '
                       'you can resubscribe it by using confirmed=True.'
                       % queue)
        else:
            message_type = MessageType.SubscriptionConfirmation.name
            message = 'You have chosen to subscribe to the queue: %s' % queue

        messages = {}
        endpoint_dict = auth.get_public_endpoint()
        if endpoint_dict:
            wsgi_endpoint = endpoint_dict.get('zaqar')
            if wsgi_endpoint:
                wsgi_subscribe_url = urllib_parse.urljoin(
                    wsgi_endpoint, url)
                messages['WSGISubscribeURL'] = wsgi_subscribe_url
            websocket_endpoint = endpoint_dict.get('zaqar-websocket')
            if websocket_endpoint:
                websocket_subscribe_url = urllib_parse.urljoin(
                    websocket_endpoint, url)
                messages['WebSocketSubscribeURL'] = websocket_subscribe_url
        messages.update({'Message_Type': message_type,
                         'Message': message,
                         'URL-Signature': pre_url['signature'],
                         'URL-Methods': pre_url['methods'][0],
                         'URL-Paths': pre_url['paths'][0],
                         'X-Project-ID': pre_url['project'],
                         'URL-Expires': pre_url['expires'],
                         'SubscribeBody': {'confirmed': True},
                         'UnsubscribeBody': {'confirmed': False}})
        s_type = urllib_parse.urlparse(subscription['subscriber']).scheme
        LOG.info('Begin to send %(type)s confirm/unsubscribe notification.'
                 ' The request body is %(messages)s',
                 {'type': s_type, 'messages': messages})

        self._execute(s_type, subscription, [messages], conf)
Exemplo n.º 6
0
    def send_confirm_notification(self, queue, subscription, conf,
                                  project=None, expires=None,
                                  api_version=None):
        key = conf.signed_url.secret_key
        if not key:
            LOG.error(_LE("Can't send confirm notification due to the value of"
                          " secret_key option is None"))
            return
        url = "/%s/queues/%s/subscriptions/%s/confirm" % (api_version, queue,
                                                          subscription['id'])
        pre_url = urls.create_signed_url(key, [url], project=project,
                                         expires=expires, methods=['PUT'])
        message_type = MessageType.SubscriptionConfirmation.name

        messages = {}
        endpoint_dict = auth.get_public_endpoint()
        if endpoint_dict:
            wsgi_endpoint = endpoint_dict.get('zaqar', None)
            if wsgi_endpoint:
                wsgi_subscribe_url = urllib_parse.urljoin(
                    wsgi_endpoint, url)
                messages['WSGISubscribeURL'] = wsgi_subscribe_url
            websocket_endpoint = endpoint_dict.get('zaqar-websocket', None)
            if websocket_endpoint:
                websocket_subscribe_url = urllib_parse.urljoin(
                    websocket_endpoint, url)
                messages['WebSocketSubscribeURL'] = websocket_subscribe_url
        messages.update({'Message_Type': message_type,
                         'Message': 'You have chosen to subscribe to the '
                                    'queue: %s' % queue,
                         'URL-Signature': pre_url['signature'],
                         'URL-Methods': pre_url['methods'][0],
                         'URL-Paths': pre_url['paths'][0],
                         'X-Project-ID': pre_url['project'],
                         'URL-Expires': pre_url['expires'],
                         'SubscribeBody': {'confirmed': True},
                         'UnsubscribeBody': {'confirmed': False}})
        s_type = urllib_parse.urlparse(subscription['subscriber']).scheme
        LOG.info(_LI('Begin to send %(type)s confirm notification. The request'
                     'body is %(messages)s'),
                 {'type': s_type, 'messages': messages})

        self._execute(s_type, subscription, [messages], conf)
Exemplo n.º 7
0
    def test_create_signed_url(self):
        timeutils.set_time_override()
        self.addCleanup(timeutils.clear_time_override)

        key = six.b('test')
        methods = ['POST']
        project = 'my-project'
        paths = ['/v2/queues/shared/messages']
        expires = timeutils.utcnow() + datetime.timedelta(days=1)
        expires_str = expires.strftime(urls._DATE_FORMAT)

        hmac_body = six.b(r'%(paths)s\n%(methods)s\n'
                          r'%(project)s\n%(expires)s' %
                          {'paths': ','.join(paths),
                           'methods': ','.join(methods),
                           'project': project, 'expires': expires_str})

        expected = hmac.new(key, hmac_body, hashlib.sha256).hexdigest()
        actual = urls.create_signed_url(key, paths, methods=['POST'],
                                        project=project)
        self.assertEqual(expected, actual['signature'])
Exemplo n.º 8
0
    def test_create_signed_url_utc(self):
        """Test that the method converts the TZ to UTC."""
        date_str = '2100-05-31T19:00:17+02'
        date_str_utc = '2100-05-31T17:00:17'

        key = six.b('test')
        project = None
        methods = ['GET']
        paths = ['/v2/queues/shared/messages']
        parsed = timeutils.parse_isotime(date_str_utc)
        expires = timeutils.normalize_time(parsed)
        expires_str = expires.strftime(urls._DATE_FORMAT)

        hmac_body = six.b('%(paths)s\\n%(methods)s\\n'
                          '%(project)s\\n%(expires)s' %
                          {'paths': ','.join(paths),
                           'methods': ','.join(methods),
                           'project': project, 'expires': expires_str})

        expected = hmac.new(key, hmac_body, hashlib.sha256).hexdigest()
        actual = urls.create_signed_url(key, paths, expires=date_str)
        self.assertEqual(expected, actual['signature'])
Exemplo n.º 9
0
    def on_post(self, req, resp, project_id, queue_name):
        LOG.debug(
            u'Pre-Signed URL Creation for queue: %(queue)s, '
            u'project: %(project)s', {
                'queue': queue_name,
                'project': project_id
            })

        try:
            document = wsgi_utils.deserialize(req.stream, req.content_length)
        except ValueError as ex:
            LOG.debug(ex)
            raise wsgi_errors.HTTPBadRequestAPI(six.text_type(ex))

        diff = set(document.keys()) - _KNOWN_KEYS
        if diff:
            msg = six.text_type(_LE('Unknown keys: %s') % diff)
            raise wsgi_errors.HTTPBadRequestAPI(msg)

        key = self._conf.signed_url.secret_key
        paths = document.pop('paths', None)
        if not paths:
            paths = [os.path.join(req.path[:-6], 'messages')]
        else:
            diff = set(paths) - _VALID_PATHS
            if diff:
                msg = six.text_type(_LE('Invalid paths: %s') % diff)
                raise wsgi_errors.HTTPBadRequestAPI(msg)
            paths = [os.path.join(req.path[:-6], path) for path in paths]

        try:
            data = urls.create_signed_url(key,
                                          paths,
                                          project=project_id,
                                          **document)
        except ValueError as err:
            raise wsgi_errors.HTTPBadRequestAPI(str(err))

        resp.body = utils.to_json(data)
Exemplo n.º 10
0
    def test_signed_url_wrong_queue(self):
        send_mock = mock.Mock()
        self.protocol.sendMessage = send_mock

        data = urls.create_signed_url(
            'secret', ['/v2/queues/myqueue/messages'], project=self.project_id,
            methods=['GET'])

        headers = self.headers.copy()
        headers.update({
            'URL-Signature': data['signature'],
            'URL-Expires': data['expires'],
            'URL-Methods': ['GET'],
            'URL-Paths': ['/v2/queues/otherqueue/messages']
        })
        req = json.dumps({'action': 'message_list',
                          'body': {'queue_name': 'otherqueue'},
                          'headers': headers})
        self.protocol.onMessage(req, False)

        self.assertEqual(1, send_mock.call_count)
        resp = json.loads(send_mock.call_args[0][0])
        self.assertEqual(403, resp['headers']['status'])
Exemplo n.º 11
0
    def send_confirm_notification(self,
                                  queue,
                                  subscription,
                                  conf,
                                  project=None,
                                  expires=None,
                                  api_version=None,
                                  is_unsubscribed=False):
        # NOTE(flwang): If the confirmation feature isn't enabled, just do
        # nothing. Here we're getting the require_confirmation from conf
        # object instead of using self.require_confirmation, because the
        # variable from self object really depends on the kwargs when
        # initializing the NotifierDriver object. See bug 1655812 for more
        # information.
        if not conf.notification.require_confirmation:
            return

        key = conf.signed_url.secret_key
        if not key:
            LOG.error("Can't send confirm notification due to the value of"
                      " secret_key option is None")
            return
        url = "/%s/queues/%s/subscriptions/%s/confirm" % (api_version, queue,
                                                          subscription['id'])
        pre_url = urls.create_signed_url(key, [url],
                                         project=project,
                                         expires=expires,
                                         methods=['PUT'])
        message = None
        if is_unsubscribed:
            message_type = MessageType.UnsubscribeConfirmation.name
            message = ('You have unsubscribed successfully to the queue: %s, '
                       'you can resubscribe it by using confirmed=True.' %
                       queue)
        else:
            message_type = MessageType.SubscriptionConfirmation.name
            message = 'You have chosen to subscribe to the queue: %s' % queue

        messages = {}
        endpoint_dict = auth.get_public_endpoint()
        if endpoint_dict:
            wsgi_endpoint = endpoint_dict.get('zaqar')
            if wsgi_endpoint:
                wsgi_subscribe_url = urllib_parse.urljoin(wsgi_endpoint, url)
                messages['WSGISubscribeURL'] = wsgi_subscribe_url
            websocket_endpoint = endpoint_dict.get('zaqar-websocket')
            if websocket_endpoint:
                websocket_subscribe_url = urllib_parse.urljoin(
                    websocket_endpoint, url)
                messages['WebSocketSubscribeURL'] = websocket_subscribe_url
        messages.update({
            'Message_Type': message_type,
            'Message': message,
            'URL-Signature': pre_url['signature'],
            'URL-Methods': pre_url['methods'][0],
            'URL-Paths': pre_url['paths'][0],
            'X-Project-ID': pre_url['project'],
            'URL-Expires': pre_url['expires'],
            'SubscribeBody': {
                'confirmed': True
            },
            'UnsubscribeBody': {
                'confirmed': False
            }
        })
        s_type = urllib_parse.urlparse(subscription['subscriber']).scheme
        LOG.info(
            'Begin to send %(type)s confirm/unsubscribe notification.'
            ' The request body is %(messages)s', {
                'type': s_type,
                'messages': messages
            })

        self._execute(s_type, subscription, [messages], conf)
Exemplo n.º 12
0
    def send_confirm_notification(self,
                                  queue,
                                  subscription,
                                  conf,
                                  project=None,
                                  expires=None,
                                  api_version=None):
        key = conf.signed_url.secret_key
        if not key:
            LOG.error(
                _LE("Can't send confirm notification due to the value of"
                    " secret_key option is None"))
            return
        url = "/%s/queues/%s/subscriptions/%s/confirm" % (api_version, queue,
                                                          subscription['id'])
        pre_url = urls.create_signed_url(key, [url],
                                         project=project,
                                         expires=expires,
                                         methods=['PUT'])
        message_type = MessageType.SubscriptionConfirmation.name

        messages = {}
        endpoint_dict = auth.get_public_endpoint()
        if endpoint_dict:
            wsgi_endpoint = endpoint_dict.get('zaqar', None)
            if wsgi_endpoint:
                wsgi_subscribe_url = urllib_parse.urljoin(wsgi_endpoint, url)
                messages['WSGISubscribeURL'] = wsgi_subscribe_url
            websocket_endpoint = endpoint_dict.get('zaqar-websocket', None)
            if websocket_endpoint:
                websocket_subscribe_url = urllib_parse.urljoin(
                    websocket_endpoint, url)
                messages['WebSocketSubscribeURL'] = websocket_subscribe_url
        messages.update({
            'Message_Type':
            message_type,
            'Message':
            'You have chosen to subscribe to the '
            'queue: %s' % queue,
            'URL-Signature':
            pre_url['signature'],
            'URL-Methods':
            pre_url['methods'][0],
            'URL-Paths':
            pre_url['paths'][0],
            'X-Project-ID':
            pre_url['project'],
            'URL-Expires':
            pre_url['expires'],
            'SubscribeBody': {
                'confirmed': True
            },
            'UnsubscribeBody': {
                'confirmed': False
            }
        })
        s_type = urllib_parse.urlparse(subscription['subscriber']).scheme
        LOG.info(
            _LI('Begin to send %(type)s confirm notification. The request'
                'body is %(messages)s'), {
                    'type': s_type,
                    'messages': messages
                })

        self._execute(s_type, subscription, [messages], conf)