def test_image_member_list(self):
        with mock.patch('glanceclient.v2.image_members.Controller.list',
                        return_value=self.members_image_members):
            serialized = self.plugin.serialize(self.members_image)

        # Admin context
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=True
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Expect to see all three tenants
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant1 can see the image but doesn't own it
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT2, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant2 owns the image and should see all three members
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))
    def test_image_member_list(self):
        with mock.patch('glanceclient.v2.image_members.Controller.list',
                        return_value=self.members_image_members):
            serialized = self.plugin.serialize(self.members_image)

        # Admin context
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=True
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Expect to see all three tenants
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant1 can see the image but doesn't own it
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT2, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant2 owns the image and should see all three members
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))
    def test_facets_all_projects(self):
        # For non admins, all_projects should have no effect
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        # Don't really care about the return values
        mock_engine.search.return_value = {'aggregations': {}}

        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search/facets',
                                                        is_admin=False)

        self.plugin.get_facets(fake_request.context, all_projects=True)

        expected_agg_query_filter = {
            'filtered': {
                'filter': {
                    'and': [{
                        'term': {
                            ROLE_USER_FIELD: 'user'
                        }
                    }, {
                        'term': {
                            'tenant_id': TENANT1
                        }
                    }]
                }
            }
        }

        # Call args are a tuple (name, posargs, kwargs)
        search_call = mock_engine.search.mock_calls[0]
        search_call_body = search_call[2]['body']
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))

        # The aggregation query's tested elsewhere, just check the query filter
        self.assertEqual(expected_agg_query_filter, search_call_body['query'])

        # Admins can request all_projects
        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search/facets',
                                                        is_admin=True)

        self.plugin.get_facets(fake_request.context, all_projects=True)

        # Test the SECOND call to the mock
        search_call = mock_engine.search.mock_calls[1]
        search_call_body = search_call[2]['body']

        # We don't expect any filter query here, just the aggregations.
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))
    def test_facets_all_projects(self):
        # For non admins, all_projects should have no effect
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        # Don't really care about the return values
        mock_engine.search.return_value = {
            'aggregations': {}
        }

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search/facets', is_admin=False
        )

        self.plugin.get_facets(fake_request.context, all_projects=True)

        expected_agg_query_filter = {
            'filtered': {
                'filter': {
                    'and': [
                        {'term': {ROLE_USER_FIELD: 'user'}},
                        {'term': {'tenant_id': TENANT1}}
                    ]
                }
            }
        }

        # Call args are a tuple (name, posargs, kwargs)
        search_call = mock_engine.search.mock_calls[0]
        search_call_body = search_call[2]['body']
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))

        # The aggregation query's tested elsewhere, just check the query filter
        self.assertEqual(expected_agg_query_filter, search_call_body['query'])

        # Admins can request all_projects
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search/facets', is_admin=True
        )

        self.plugin.get_facets(fake_request.context, all_projects=True)

        # Test the SECOND call to the mock
        search_call = mock_engine.search.mock_calls[1]
        search_call_body = search_call[2]['body']

        # We don't expect any filter query here, just the aggregations.
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))
    def test_protected_properties(self):
        with mock.patch(nova_server_getter, return_value=self.instance1):
            serialized = self.plugin.serialize(self.instance1.id)

        elasticsearch_results = {
            "hits": {
                "hits": [
                    {
                        "_source": copy.deepcopy(serialized),
                        "_type": self.plugin.get_document_type(),
                        "_index": self.plugin.get_index_name(),
                    }
                ]
            }
        }

        protected_fields = (u"OS-EXT-SRV-ATTR:host", u"OS-EXT-SRV-ATTR:hypervisor_hostname")

        fake_request = unit_test_utils.get_fake_request(USER1, TENANT1, "/v1/search", is_admin=True)
        self.plugin.filter_result(elasticsearch_results["hits"]["hits"][0], fake_request.context)

        # Result should contain all the fields
        single_result = elasticsearch_results["hits"]["hits"][0]["_source"]
        self.assertEqual(serialized, single_result)
        for field in protected_fields:
            self.assertTrue(field in single_result)

        # Refresh the mock results since they can be modified in-place
        elasticsearch_results = {
            "hits": {
                "hits": [
                    {
                        "_source": copy.deepcopy(serialized),
                        "_type": self.plugin.get_document_type(),
                        "_index": self.plugin.get_index_name(),
                    }
                ]
            }
        }
        # Make the same request as a non-admin
        fake_request = unit_test_utils.get_fake_request(USER1, TENANT1, "/v1/search", is_admin=False)

        self.plugin.filter_result(elasticsearch_results["hits"]["hits"][0], fake_request.context)

        single_result = elasticsearch_results["hits"]["hits"][0]["_source"]

        for field in protected_fields:
            self.assertFalse(field in single_result)
Example #6
0
    def test_facets(self):
        request = unit_test_utils.get_fake_request()
        doc_types = ["OS::Glance::Image", "OS::Nova::Server"]
        gf_path = 'searchlight.elasticsearch.plugins.base.IndexBase.get_facets'
        with mock.patch(gf_path) as mock_facets:
            mock_facets.return_value = [{"name": "fake", "type": "string"}], 0

            default_response = self.search_controller.facets(
                request, doc_type=doc_types)

            expected = {
                "OS::Nova::Server": {
                    "doc_count": 0,
                    "facets": [{"name": "fake", "type": "string"}]
                },
                "OS::Glance::Image": {
                    "doc_count": 0,
                    "facets": [{"name": "fake", "type": "string"}]
                }
            }
            self.assertEqual(expected, default_response)

            totals_only_response = self.search_controller.facets(
                request, doc_type=doc_types, include_fields=False)

            expected = {"OS::Nova::Server": {"doc_count": 0},
                        "OS::Glance::Image": {"doc_count": 0}}
            self.assertEqual(expected, totals_only_response)
Example #7
0
    def test_policy_all_disallowed(self):
        request = unit_test_utils.get_fake_request(is_admin=False)
        search_deserializer = search.RequestDeserializer(
            utils.get_search_plugins(), policy_enforcer=self.enforcer)

        types = ['OS::Glance::Image']
        self.enforcer.add_rules(
            policy.policy.Rules.from_dict({
                'resource:OS::Glance::Image': '!',
                'resource:OS::Nova::Server': '!',
            }))

        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image")
        self.assertRaisesRegex(webob.exc.HTTPForbidden, expected_message,
                               search_deserializer._filter_types_by_policy,
                               request.context, types)

        types = ['OS::Glance::Image', 'OS::Nova::Server']
        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image, OS::Nova::Server")
        self.assertRaisesRegex(webob.exc.HTTPForbidden, expected_message,
                               search_deserializer._filter_types_by_policy,
                               request.context, types)
    def test_facets_no_mapping(self):
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search/facets',
                                                        is_admin=True)

        mock_engine.search.return_value = {
            'aggregations': {
                'status': {
                    'buckets': []
                },
                'image.id': {
                    'doc_count': 0
                }
            }
        }

        facets = self.plugin.get_facets(fake_request.context)

        status_facet = list(filter(lambda f: f['name'] == 'status', facets))[0]
        image_facet = list(filter(lambda f: f['name'] == 'image.id',
                                  facets))[0]
        expected_status = {'name': 'status', 'options': [], 'type': 'string'}
        expected_image = {
            'name': 'image.id',
            'options': [],
            'type': 'string',
            'resource_type': 'OS::Glance::Image'
        }

        self.assertEqual(expected_status, status_facet)
        self.assertEqual(expected_image, image_facet)
 def test_rbac_filter(self):
     fake_request = unit_test_utils.get_fake_request(USER1,
                                                     TENANT1,
                                                     '/v1/search',
                                                     is_admin=False)
     rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)
     self.assertEqual([{
         'bool': {
             'should': [{
                 'term': {
                     'tenant_id': TENANT1
                 }
             }, {
                 'terms': {
                     'members': [TENANT1, '*']
                 }
             }, {
                 'term': {
                     'router:external': True
                 }
             }, {
                 'term': {
                     'shared': True
                 }
             }]
         }
     }], rbac_terms)
    def test_facets(self):
        fake_request = unit_test_utils.get_fake_request(USER1, TENANT1, "/v1/search/facets", is_admin=False)

        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        mock_engine.search.return_value = {
            "aggregations": {
                "status": {"buckets": [{"key": "pending", "doc_count": 2}]},
                "type": {"buckets": [{"key": "PRIMARY", "doc_count": 2}]},
            }
        }

        facets = self.plugin.get_facets(fake_request.context)

        status_facet = list(filter(lambda f: f["name"] == "status", facets))[0]
        expected_status = {"name": "status", "options": [{"key": "pending", "doc_count": 2}], "type": "string"}
        self.assertEqual(expected_status, status_facet)

        expected_agg_query = {
            "aggs": dict(unit_test_utils.simple_facet_field_agg(name) for name in ("status", "type")),
            "query": {"filtered": {"filter": {"and": [{"term": {"project_id": TENANT1}}]}}},
        }
        mock_engine.search.assert_called_with(
            index=self.plugin.get_index_name(),
            doc_type=self.plugin.get_document_type(),
            body=expected_agg_query,
            ignore_unavailable=True,
            search_type="count",
        )
Example #11
0
    def test_policy_all_disallowed(self):
        request = unit_test_utils.get_fake_request(is_admin=False)
        search_deserializer = search.RequestDeserializer(
            utils.get_search_plugins(),
            policy_enforcer=self.enforcer)

        types = ['OS::Glance::Image']
        self.enforcer.add_rules(policy.policy.Rules.from_dict({
            'resource:OS::Glance::Image': '!',
            'resource:OS::Nova::Server': '!',
        }))

        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image")
        self.assertRaisesRegex(
            webob.exc.HTTPForbidden, expected_message,
            search_deserializer._filter_types_by_policy,
            request.context, types)

        types = ['OS::Glance::Image', 'OS::Nova::Server']
        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image, OS::Nova::Server")
        self.assertRaisesRegex(
            webob.exc.HTTPForbidden, expected_message,
            search_deserializer._filter_types_by_policy,
            request.context, types)
Example #12
0
    def test_resource_policy_allows_admin(self):
        request = unit_test_utils.get_fake_request(is_admin=True)
        search_deserializer = search.RequestDeserializer(
            utils.get_search_plugins(),
            policy_enforcer=self.enforcer)
        types = ['OS::Glance::Image', 'OS::Nova::Server']

        self.enforcer.add_rules(policy.policy.Rules.from_dict({
            'resource:OS::Glance::Image:allow': 'role:admin',
            'resource:OS::Nova::Server:query': 'role:admin'
        }))

        request = unit_test_utils.get_fake_request(is_admin=True)
        filtered_types = search_deserializer._filter_types_by_policy(
            request.context, types, "query")
        self.assertEqual(types, filtered_types)
Example #13
0
    def test_empty_request(self):
        """Tests that ALL registered resource types are searched"""
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({}))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])

        types = [
            'OS::Designate::RecordSet',
            'OS::Designate::Zone',
            'OS::Glance::Image',
            'OS::Glance::Metadef',
            'OS::Ironic::Chassis',
            'OS::Ironic::Node',
            'OS::Ironic::Port',
            'OS::Nova::Flavor',
            'OS::Nova::Server',
            'OS::Nova::ServerGroup',
            'OS::Nova::Hypervisor',
            'OS::Neutron::FloatingIP',
            'OS::Neutron::Net',
            'OS::Neutron::Port',
            'OS::Neutron::Subnet',
            'OS::Neutron::Router',
            'OS::Neutron::SecurityGroup',
            'OS::Cinder::Volume',
            'OS::Cinder::Snapshot'
        ]

        self.assertEqual(['searchlight-search'], output['index'])
        self.assertEqual(sorted(types), sorted(output['doc_type']))
Example #14
0
    def test_filter_result(self):
        """Verify that any highlighted query results will filter out
           the ROLE_USER_FIELD field.
        """
        request = unit_test_utils.get_fake_request(is_admin=True)
        mock_engine = mock.Mock()
        simple_plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)

        # Verify with ROLE_USER_FIELD
        hit = {"_source": {"owner": "<em>admin</em>"},
               "highlight": {
                   "owner": "<em>admin</em>",
                   "__searchlight-user-role": "<em>admin</em>"}}

        simple_plugin.filter_result(hit, request.context)
        self.assertNotIn('__searchlight-user-role', hit['highlight'])

        # Verify without ROLE_USER_FIELD
        hit = {"_source": {"owner": "<em>admin</em>"},
               "highlight": {
                   "owner": "<em>admin</em>"}}

        original_hit = copy.deepcopy(hit)
        simple_plugin.filter_result(hit, request.context)
        self.assertEqual(original_hit, hit)
Example #15
0
    def test_create_multiple(self):
        actions = [
            _image_fixture('create', '1'),
            _image_fixture('create', '2', data={'name': 'image-2'}),
        ]

        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': actions,
        }))

        output = self.deserializer.index(request)
        expected = {
            'actions': [
                {
                    '_id': '1',
                    '_index': 'searchlight',
                    '_op_type': 'create',
                    '_source': {'disk_format': 'raw', 'name': 'image-1'},
                    '_type': 'OS::Glance::Image'
                },
                {
                    '_id': '2',
                    '_index': 'searchlight',
                    '_op_type': 'create',
                    '_source': {'disk_format': 'raw', 'name': 'image-2'},
                    '_type': 'OS::Glance::Image'
                },
            ],
            'default_index': None,
            'default_type': None
        }
        self.assertEqual(expected, output)
Example #16
0
    def test_multiple_sort(self):
        """Test multiple sort fields"""
        request = unit_test_utils.get_fake_request()
        request.body = six.b(
            jsonutils.dumps({
                'query': {
                    'match_all': {}
                },
                'sort': [
                    'status', {
                        'created_at': 'desc'
                    }, {
                        'members': {
                            'order': 'asc',
                            'mode': 'max'
                        }
                    }
                ]
            }))

        output = self.deserializer.search(request)
        expected = [
            'status', {
                'created_at': 'desc'
            }, {
                'members': {
                    'order': 'asc',
                    'mode': 'max'
                }
            }
        ]
        self.assertEqual(expected, output['query']['sort'])
Example #17
0
    def test_plugins_info_not_found(self):
        request = unit_test_utils.get_fake_request()
        repo = searchlight.elasticsearch.CatalogSearchRepo
        repo.plugins_info = mock.Mock(side_effect=exception.NotFound)

        self.assertRaises(webob.exc.HTTPNotFound,
                          self.search_controller.plugins_info, request)
Example #18
0
    def test_plugins_info_internal_server_error(self):
        request = unit_test_utils.get_fake_request()
        repo = searchlight.elasticsearch.CatalogSearchRepo
        repo.plugins_info = mock.Mock(side_effect=Exception)

        self.assertRaises(webob.exc.HTTPInternalServerError,
                          self.search_controller.plugins_info, request)
Example #19
0
    def test_global_aggregation_not_allowed(self):
        """The 'global' aggregation type bypasses the search query (thus
        bypassing RBAC). This is Bad, so we won't allow it. It can only occur
        as a top level aggregation.
        """
        request = unit_test_utils.get_fake_request()

        aggs = {
            'cheating_rbac': {
                'global': {},
                'aggregations': {
                    'name': {
                        'terms': {
                            'field': 'name'
                        }
                    }
                }
            }
        }
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                'aggregations': aggs
            }))

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Example #20
0
    def test_delete_multiple(self):
        action_1 = _image_fixture('delete', '1')
        action_1.pop('data')
        action_2 = _image_fixture('delete', '2')
        action_2.pop('data')

        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [action_1, action_2],
        }))

        output = self.deserializer.index(request)
        expected = {
            'actions': [
                {
                    '_id': '1',
                    '_index': 'searchlight',
                    '_op_type': 'delete',
                    '_source': {},
                    '_type': 'OS::Glance::Image'
                },
                {
                    '_id': '2',
                    '_index': 'searchlight',
                    '_op_type': 'delete',
                    '_source': {},
                    '_type': 'OS::Glance::Image'
                },
            ],
            'default_index': None,
            'default_type': None
        }
        self.assertEqual(expected, output)
Example #21
0
    def test_search_aggregations(self):
        request = unit_test_utils.get_fake_request()
        with mock.patch(REPO_SEARCH, return_value={}) as mock_search:
            query = {
                "query": {
                    "match_all": {}
                },
                "aggs": {
                    "test": {
                        "terms": {
                            "field": "some_field"
                        }
                    }
                }
            }
            index_name = "searchlight"
            limit = 10
            offset = 0
            doc_type = "OS::Glance::Image"

            self.search_controller.search(request,
                                          query,
                                          index_name,
                                          doc_type,
                                          offset,
                                          limit,
                                          version=True)

            mock_search.assert_called_once_with(index_name,
                                                doc_type,
                                                query,
                                                offset,
                                                limit,
                                                ignore_unavailable=True,
                                                version=True)
Example #22
0
    def test_nested_object_facets(self):
        """Check 'nested' and 'object' types are treated the same for facets"""
        mock_engine = mock.Mock()
        plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)
        fake_request = unit_test_utils.get_fake_request(
            'a', 'b', '/v1/search/facets', is_admin=True
        )

        mock_engine.search.return_value = {
            "hits": {"total": 1}
        }

        fake_mapping = {
            "properties": {
                "nested": {
                    "type": "nested",
                    "properties": {"inner": {"type": "string"}}
                },
                "object": {
                    "type": "object",
                    "properties": {"inner": {"type": "string"}}
                }
            }
        }
        with mock.patch.object(plugin, 'get_mapping',
                               return_value=fake_mapping):
            facets, _ = plugin.get_facets(fake_request.context)
            facets = sorted(facets, key=operator.itemgetter("name"))
            expected = [
                {"name": "nested.inner", "type": "string", "nested": True},
                {"name": "object.inner", "type": "string", "nested": False},
            ]

            self.assertEqual(expected, facets)
Example #23
0
    def test_rbac_non_admin(self):
        """Test that a non-admin request results in an RBACed query"""
        request = unit_test_utils.get_fake_request(is_admin=False)
        request.body = jsonutils.dumps({
            'query': {
                'match_all': {}
            },
            'type': 'OS::Nova::Server',
        }).encode("latin-1")
        output = self.deserializer.search(request)
        tenant_id = '6838eb7b-6ded-dead-beef-b344c77fe8df'

        nova_rbac_filter = {
            'indices': {
                'query': {
                    'bool': {
                        'filter': {
                            'bool': {
                                'must': {
                                    'type': {
                                        'value': 'OS::Nova::Server'
                                    }
                                },
                                'should': [{
                                    'term': {
                                        'tenant_id': tenant_id
                                    }
                                }],
                                'minimum_should_match': 1
                            }
                        }
                    }
                },
                'index': 'searchlight-search',
                'no_match_query': 'none'
            }
        }

        role_field = searchlight.elasticsearch.ROLE_USER_FIELD
        expected_query = {
            'query': {
                'bool': {
                    'filter': {
                        'bool': {
                            'must': {
                                'term': {
                                    role_field: 'user'
                                }
                            },
                            'should': [nova_rbac_filter],
                            'minimum_should_match': 1
                        }
                    },
                    'must': {
                        'match_all': {}
                    }
                }
            }
        }
        self.assertEqual(expected_query, output['query'])
Example #24
0
    def test_plugins_info(self):
        request = unit_test_utils.get_fake_request()
        expected = {
            "plugins": [
                {
                    "index": "searchlight",
                    "type": "OS::Designate::RecordSet",
                    "name": "OS::Designate::RecordSet"
                },
                {
                    "index": "searchlight",
                    "type": "OS::Designate::Zone",
                    "name": "OS::Designate::Zone"
                },
                {
                    "index": "searchlight", "type": "OS::Glance::Image",
                    "name": "OS::Glance::Image"
                },
                {
                    "index": "searchlight", "type": "OS::Glance::Metadef",
                    "name": "OS::Glance::Metadef"
                },
                {
                    "index": "searchlight", "type": "OS::Nova::Server",
                    "name": "OS::Nova::Server"
                }
            ]
        }

        actual = self.search_controller.plugins_info(request)
        self.assertEqual(sorted(expected), sorted(actual))
Example #25
0
    def test_filter_result(self):
        """Verify that any highlighted query results will filter out
           the ROLE_USER_FIELD field.
        """
        request = unit_test_utils.get_fake_request(is_admin=True)
        mock_engine = mock.Mock()
        simple_plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)

        # Verify with ROLE_USER_FIELD
        hit = {
            "_source": {
                "owner": "<em>admin</em>"
            },
            "highlight": {
                "owner": "<em>admin</em>",
                "__searchlight-user-role": "<em>admin</em>"
            }
        }

        simple_plugin.filter_result(hit, request.context)
        self.assertNotIn('__searchlight-user-role', hit['highlight'])

        # Verify without ROLE_USER_FIELD
        hit = {
            "_source": {
                "owner": "<em>admin</em>"
            },
            "highlight": {
                "owner": "<em>admin</em>"
            }
        }

        original_hit = copy.deepcopy(hit)
        simple_plugin.filter_result(hit, request.context)
        self.assertEqual(original_hit, hit)
Example #26
0
    def test_search_policy_check(self, _):
        request = unit_test_utils.get_fake_request()
        with mock.patch.object(self.search_controller.policy,
                               'enforce') as mock_enforce:

            self.search_controller.search(request, query={"match_all": {}})
            mock_enforce.assert_called_with(request.context, 'query', {})
 def test_metadef_rbac(self):
     """Test metadefs RBAC query terms"""
     fake_request = unit_test_utils.get_fake_request(
         USER1, TENANT1, '/v1/search'
     )
     rbac_filter = self.plugin.get_query_filters(fake_request.context)
     expected_fragment = {
         "indices": {
             "index": "searchlight-search",
             "no_match_query": "none",
             "query": {
                 "bool": {
                     "filter": {
                         "bool": {
                             "must": {
                                 "type": {"value": "OS::Glance::Metadef"}
                             },
                             "should": [
                                 {"term": {"owner": TENANT1}},
                                 {"term": {"visibility": "public"}},
                             ],
                             "minimum_should_match": 1
                         }
                     }
                 }
             }
         }
     }
     self.assertEqual(expected_fragment, rbac_filter)
    def test_image_rbac(self):
        """Test the image plugin RBAC query terms"""
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search'
        )
        rbac_query_fragment = self.plugin.get_query_filters(
            fake_request.context)
        expected_fragment = {
            "indices": {
                "index": "searchlight-search",
                "no_match_filter": "none",
                "filter": {
                    "and": [
                        {
                            "type": {"value": "OS::Glance::Image"}
                        },
                        {
                            "or": [
                                {"term": {"owner": TENANT1}},
                                {"term": {"visibility": "public"}},
                                {"term": {"members": TENANT1}}
                            ]
                        }
                    ]
                },
            }
        }

        self.assertEqual(expected_fragment, rbac_query_fragment)
    def test_image_rbac(self):
        """Test the image plugin RBAC query terms"""
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search'
        )
        rbac_query_fragment = self.plugin.get_rbac_filter(fake_request.context)
        expected_fragment = [{
            "indices": {
                "index": "searchlight",
                "no_match_filter": "none",
                "filter": {
                    "and": [
                        {
                            "or": [
                                {"term": {"owner": TENANT1}},
                                {"term": {"visibility": "public"}},
                                {"term": {"members": TENANT1}}
                            ]
                        },
                        {
                            "type": {"value": "OS::Glance::Image"}
                        },
                    ]
                },
            }
        }]

        self.assertEqual(expected_fragment, rbac_query_fragment)
 def test_rbac_filters(self):
     fake_request = unit_test_utils.get_fake_request(
         USER1, TENANT1, '/v1/search', is_admin=False
     )
     self.assertEqual(
         [{"term": {"project_id": TENANT1}}],
         self.plugin._get_rbac_field_filters(fake_request.context))
    def test_image_rbac(self):
        """Test the image plugin RBAC query terms"""
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search'
        )
        rbac_query_fragment = self.plugin.get_query_filters(
            fake_request.context)
        expected_fragment = {
            "indices": {
                "index": "searchlight-search",
                "no_match_query": "none",
                "query": {
                    "bool": {
                        "filter": {
                            "bool": {
                                "must": {
                                    "type": {"value": "OS::Glance::Image"}
                                },
                                "should": [
                                    {"term": {"owner": TENANT1}},
                                    {"term": {"visibility": "public"}},
                                    {"term": {"members": TENANT1}}
                                ],
                                'minimum_should_match': 1
                            }
                        }
                    }
                },
            }
        }

        self.assertEqual(expected_fragment, rbac_query_fragment)
    def test_facets_no_mapping(self):
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search/facets', is_admin=True
        )

        mock_engine.search.return_value = {
            'aggregations': {
                'status': {'buckets': []},
                'image.id': {'doc_count': 0}
            }
        }

        facets = self.plugin.get_facets(fake_request.context)

        status_facet = list(filter(lambda f: f['name'] == 'status',
                                   facets))[0]
        image_facet = list(filter(lambda f: f['name'] == 'image.id',
                                  facets))[0]
        expected_status = {'name': 'status', 'options': [], 'type': 'string'}
        expected_image = {'name': 'image.id', 'options': [], 'type': 'string'}

        self.assertEqual(expected_status, status_facet)
        self.assertEqual(expected_image, image_facet)
Example #33
0
    def test_nested_object_facets(self):
        """Check 'nested' and 'object' types are treated the same for facets"""
        mock_engine = mock.Mock()
        plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)
        fake_request = unit_test_utils.get_fake_request(
            'a', 'b', '/v1/search/facets', is_admin=True
        )

        mock_engine.search.return_value = {
            "hits": {"total": 1}
        }

        fake_mapping = {
            "properties": {
                "nested": {
                    "type": "nested",
                    "properties": {"inner": {"type": "string"}}
                },
                "object": {
                    "type": "object",
                    "properties": {"inner": {"type": "string"}}
                }
            }
        }
        with mock.patch.object(plugin, 'get_mapping',
                               return_value=fake_mapping):
            facets, _ = plugin.get_facets(fake_request.context)
            facets = sorted(facets, key=operator.itemgetter("name"))
            expected = [
                {"name": "nested.inner", "type": "string", "nested": True},
                {"name": "object.inner", "type": "string", "nested": False},
            ]

            self.assertEqual(expected, facets)
Example #34
0
    def test_search_policy_check(self, _):
        request = unit_test_utils.get_fake_request()
        with mock.patch.object(self.search_controller.policy,
                               'enforce') as mock_enforce:

            self.search_controller.search(request, query={"match_all": {}})
            mock_enforce.assert_called_with(request.context, 'query', {})
 def test_rbac_filter(self):
     fake_request = unit_test_utils.get_fake_request(USER1,
                                                     TENANT1,
                                                     '/v1/search',
                                                     is_admin=False)
     rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)
     self.assertEqual([{"term": {"id": AUTH_PREFIX + TENANT1}}], rbac_terms)
Example #36
0
    def test_default_facet_options(self):
        request = unit_test_utils.get_fake_request(path='/v1/search/facets')
        output = self.deserializer.facets(request)

        expected = {'index_name': None, 'doc_type': None,
                    'all_projects': False, 'limit_terms': 0}
        self.assertEqual(expected, output)
Example #37
0
 def test_facets(self):
     """If you have a weak constitution, we may want to avert your eyes
        now. We want to verify that the "exclude_options" parameter for
        facets will not result in any aggregation in the Elasticsearch
        query. The actual ES query is buried in the bowels of Searchlight.
        Instead of trying to call it directly through the searchcontroller
        and mock mutliple levels of Servers/Requests/Catalogs/etc we will
        go directly to the IndexBase call.
     """
     request = unit_test_utils.get_fake_request(is_admin=True)
     mock_engine = mock.Mock()
     simple_plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)
     mock_engine.search.return_value = {"hits": {"total": 0}}
     simple_plugin._get_facet_terms(fields={},
                                    request_context=request.context,
                                    all_projects=False, limit_terms=False,
                                    exclude_options=True)
     # Verify there is no aggregation when searching Elasticsearch.
     body = {'query': {
             'filtered': {'filter': {'and':
                          [{'term': {
                            '__searchlight-user-role': 'admin'}}]}}}
             }
     mock_engine.search.assert_called_with(body=body,
                                           doc_type='fake-simple',
                                           ignore_unavailable=True,
                                           index='searchlight-search',
                                           size=0)
Example #38
0
 def test_rbac_filter_admin_role(self):
     fake_request = unit_test_utils.get_fake_request(
         USER1, TENANT1, '/v1/search', is_admin=True
     )
     rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)
     expected_rbac = [
         {
             "or": [
                 {
                     'term': {'tenant_id': TENANT1}
                 },
                 {
                     'has_parent': {
                         'type': self.plugin.parent_plugin_type(),
                         'query': {
                             "bool": {
                                 "should": [
                                     {'term': {'shared': True}},
                                     {'term': {'router:external': True}}
                                 ]
                             }
                         }
                     }
                 }
             ]
         }
     ]
     self.assertEqual(expected_rbac, rbac_terms)
Example #39
0
    def test_plugins_info(self):
        request = unit_test_utils.get_fake_request()
        expected = {
            "plugins": [{
                "index": "searchlight-search",
                "type": "OS::Designate::RecordSet",
                "name": "OS::Designate::RecordSet"
            }, {
                "index": "searchlight-search",
                "type": "OS::Designate::Zone",
                "name": "OS::Designate::Zone"
            }, {
                "index": "searchlight-search",
                "type": "OS::Glance::Image",
                "name": "OS::Glance::Image"
            }, {
                "index": "searchlight-search",
                "type": "OS::Glance::Metadef",
                "name": "OS::Glance::Metadef"
            }, {
                "index": "searchlight-search",
                "type": "OS::Nova::Server",
                "name": "OS::Nova::Server"
            }]
        }

        # Simulate policy filtering
        doc_types = [p['name'] for p in expected['plugins']]
        actual = self.search_controller.plugins_info(request, doc_types)
        self.assertEqual(['plugins'], list(actual.keys()))

        self.assertEqual(
            sorted(expected['plugins'], key=operator.itemgetter('name')),
            sorted(actual['plugins'], key=operator.itemgetter('name')))
Example #40
0
    def test_invalid_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'type': 'invalid',
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Example #41
0
 def test_facet_policy(self):
     request = unit_test_utils.get_fake_request()
     search_repo = mock.Mock()
     with mock.patch.object(self.enforcer, 'enforce') as mock_enforce:
         repo = policy.CatalogSearchRepoProxy(search_repo, request.context,
                                              self.enforcer)
         repo.facets()
         mock_enforce.assert_called_with(request.context, 'facets', {})
Example #42
0
    def test_forbidden_self(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'self': {},
        }))

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Example #43
0
    def test_forbidden_schema(self):
        request = unit_test_utils.get_fake_request()
        request.body = jsonutils.dumps({
            'schema': {},
        }).encode("latin-1")

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Example #44
0
    def test_empty_operation_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [_image_fixture('', '1')]
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Example #45
0
    def test_single_index(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'index': 'searchlight-search',
        }))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])
Example #46
0
 def test_context_policy_target(self):
     request = unit_test_utils.get_fake_request()
     expected = {
         'user_id': unit_test_utils.SOMEUSER,
         'project_id': unit_test_utils.SOMETENANT,
         'tenant_id': unit_test_utils.SOMETENANT
     }
     self.assertEqual(expected, request.context.policy_target)
Example #47
0
    def test_forbidden_self(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'self': {},
        }))

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Example #48
0
    def test_create_invalid_index(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [_image_fixture('create', index='invalid')]
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Example #49
0
    def test_create_missing_doc_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [_image_fixture('create', '1', doc_type=None)]
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Example #50
0
    def test_single_index(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'index': 'searchlight-search',
        }))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])
Example #51
0
    def test_missing_actions(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'default_type': 'OS::Glance::Image'
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Example #52
0
 def test_search_version(self):
     request = unit_test_utils.get_fake_request(is_admin=True)
     request.body = six.b(jsonutils.dumps({
         'query': {'match_all': {}},
         'version': True
     }))
     output = self.deserializer.search(request)
     self.assertEqual(True, output['version'])
Example #53
0
    def test_rbac_filter(self):
        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search',
                                                        is_admin=False)
        rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)

        expected = [{"term": {"tenant_id": TENANT1}}]
        self.assertEqual(expected, rbac_terms)
Example #54
0
    def test_single_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'type': 'OS::Glance::Image',
        }))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])
        self.assertEqual(['OS::Glance::Image'], output['doc_type'])
Example #55
0
    def test_admin_or_owner(self):
        """Since this a commonly used rule, check that it works"""
        self.enforcer.add_rules(
            policy.policy.Rules.from_dict({
                'admin_or_owner': 'role:admin or project_id:%(project_id)s',
                'test_rule': 'rule:admin_or_owner'
            }))

        request = unit_test_utils.get_fake_request(is_admin=False)
        self.assertTrue(
            self.enforcer.check(request.context, 'test_rule',
                                request.context.policy_target))

        request = unit_test_utils.get_fake_request(is_admin=False)
        self.assertFalse(self.enforcer.check(request.context, 'test_rule', {}))

        request = unit_test_utils.get_fake_request(is_admin=True)
        self.assertTrue(self.enforcer.check(request.context, 'test_rule', {}))
Example #56
0
    def test_fields_exclude_rbac(self):
        """Test various forms for source_exclude"""
        role_field = searchlight.elasticsearch.ROLE_USER_FIELD
        request = unit_test_utils.get_fake_request()
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': {
                    'exclude': ['something', 'other thing']
                }
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field, 'something', 'other thing'],
                         output['_source_exclude'])

        # Test with a single field
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': {
                    'exclude': "something"
                }
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field, 'something'], output['_source_exclude'])

        # Test with a single field
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': "includeme"
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field], output['_source_exclude'])
        self.assertEqual("includeme", output['_source_include'])

        # Test with a single field
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': ["includeme", "andme"]
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field], output['_source_exclude'])
        self.assertEqual(["includeme", "andme"], output['_source_include'])