예제 #1
0
    def inspect(self, client):
        lines, self._errors = [], []
        for i, (header, body) in enumerate(self._parse_payload()):
            try:
                index_filter, type_filter, _, json = self.inspect_request(
                    client,
                    FilterString.from_list(header['index']),
                    FilterString.from_list(header['type']),
                    json=body)
            except RequestError as error:
                self._errors.append((i, {
                    'status':
                    error.status_code,
                    'error':
                    '[{0}] {1}'.format(APP_NAME, error.reason)
                }))
            else:
                header['index'] = [str(part) for part in index_filter]
                header['type'] = [str(part) for part in type_filter]
                lines.append(self.json_encode(header))
                lines.append(self.json_encode(json or body))

        if not lines:
            response = ElasticResponse()
            response.content = self.json_encode(
                {'responses': [e for p, e in self._errors]},
                not self.query.is_false('pretty'))
            response.headers['Content-Length'] = str(len(response.content))
            response.headers['Content-Type'] = 'application/json'
            response.status_code = 200
            del self._errors
            return response

        self.path = '/_msearch'  # We're enforcing headers with indices and types where applicable
        self.body = '\n'.join(lines) + '\n'
예제 #2
0
    def inspect(self, client):
        lines, self._errors = [], []
        for i, (header, body) in enumerate(self._parse_payload()):
            try:
                index_filter, type_filter, _, json = self.inspect_request(
                    client, FilterString.from_list(header['index']),
                    FilterString.from_list(header['type']), json=body)
            except RequestError as error:
                self._errors.append((i, {
                    'status': error.status_code,
                    'error': '[{0}] {1}'.format(APP_NAME, error.reason)
                }))
            else:
                header['index'] = [str(part) for part in index_filter]
                header['type'] = [str(part) for part in type_filter]
                lines.append(self.json_encode(header))
                lines.append(self.json_encode(json or body))

        if not lines:
            response = ElasticResponse()
            response.content = self.json_encode({'responses': [e for p, e in self._errors]},
                                                not self.query.is_false('pretty'))
            response.headers['Content-Length'] = str(len(response.content))
            response.headers['Content-Type'] = 'application/json'
            response.status_code = 200
            del self._errors
            return response

        self.path = '/_msearch'  # We're enforcing headers with indices and types where applicable
        self.body = '\n'.join(lines) + '\n'
예제 #3
0
    def inspect(self, client):
        restricted_types = client.is_restricted('types')
        requested_indices = FilterString.from_string(self.indices)

        try:
            index_filter = client.create_filter_string('api/indices/get/mappings', requested_indices,
                                                       single=restricted_types)
        except MultipleIncludesError as error:
            raise PermissionError(
                'You are restricted to specific types. To retrieve field mappings, please pick a'
                ' single index from the following list: {0}'.format(', '.join(error.includes)))
        else:
            if index_filter is None:
                raise PermissionError('You are not permitted to access the mappings of the given indices.')

        if restricted_types:
            requested_types = FilterString.from_string(self.get_match('documents', ''))
            requested_index = index_filter.combined[0] if index_filter.combined else index_filter[0]
            type_filter = client.create_filter_string('api/indices/get/mappings', requested_types,
                                                      str(requested_index))
            if type_filter is None:
                raise PermissionError('You are not permitted to access the mappings of the given types.')
        else:
            type_filter = self.get_match('documents')

        if type_filter:
            self.path = '/{0}/_mapping/{1}/field/{2}'.format(index_filter, type_filter, self.fields)
        else:
            self.path = '/{0}/_mapping/field/{1}'.format(index_filter, self.fields)
예제 #4
0
    def inspect(self, client):
        if '__kibanaQueryValidator' in self.path:
            # I have _still_ no explanation for this. Please enlighten
            # me if you think this is security relevant in any way.
            if client.can('api/search/explain', '.kibana'):
                return

            raise PermissionError(self._permission_errors['api/search/explain']['indices'].format('.kibana'))

        index_filter, type_filter, _, json = self.inspect_request(
            client, FilterString.from_string(self.get_match('indices', '')),
            FilterString.from_string(self.get_match('documents', '')), json=self.json)

        if self.query.last('q', '').strip() and self.query.last('q').strip() != '*':
            if client.has_restriction(index_filter, type_filter):
                # TODO: Provide a more sophisticated solution once we've got a parser for query strings!
                raise PermissionError(
                    'You are restricted to specific fields and as such cannot utilize the query string search.')

        if not self.query.is_false('explain'):
            self._check_permission('api/search/explain', client, index_filter, type_filter)

        if index_filter:
            if type_filter:
                self.path = '/{0}/{1}/_validate/query'.format(index_filter, type_filter)
            else:
                self.path = '/{0}/_validate/query'.format(index_filter)

        if json is not None:
            self.body = self.json_encode(json)
예제 #5
0
    def inspect(self, client):
        index_filter, type_filter, source_filter, json = self.inspect_request(
            client, FilterString.from_string(self.get_match('indices', '')),
            FilterString.from_string(self.get_match('documents', '')),
            SourceFilter.from_query(self.query), self.json)

        if self.query.last('q', '').strip() and self.query.last('q').strip() != '*':
            if client.has_restriction(index_filter, type_filter):
                # TODO: Provide a more sophisticated solution once we've got a parser for query strings!
                raise PermissionError(
                    'You are restricted to specific fields and as such cannot utilize the query string search.')

        if not self.query.is_false('explain'):
            self._check_permission('api/search/explain', client, index_filter, type_filter)

        fields_filter = client.create_fields_filter('api/search/documents', index_filter, type_filter,
                                                    FieldsFilter.from_query(self.query))
        if fields_filter is None:
            raise PermissionError('You are not permitted to access any of the requested stored fields.')
        elif fields_filter:
            self.query.update(fields_filter.as_query())

        if index_filter:
            if type_filter:
                self.path = '/{0}/{1}/_search'.format(index_filter, type_filter)
            else:
                self.path = '/{0}/_search'.format(index_filter)

        self.query.discard('_source', '_source_include', '_source_exclude')
        if source_filter:
            self.query.update(source_filter.as_query())

        if json is not None:
            self.body = self.json_encode(json)
예제 #6
0
    def inspect(self, client):
        index_filter = client.create_filter_string('api/indices/get/*', FilterString.from_string(self.indices))
        if index_filter is None:
            raise PermissionError('You are not permitted to access any settings of the given index or indices.')
        elif index_filter:
            self.path = self.path.replace(self.indices, str(index_filter))

        if self.command != 'HEAD':
            keywords = [s.strip() for s in self.get_match('keywords', '').split(',') if s]
            unknown = next((kw for kw in keywords if kw not in self.index_settings), None)
            if unknown is not None:
                raise PermissionError('Unknown index setting: {0}'.format(unknown))

            permitted_settings, missing_permissions = [], {}
            for setting, permission in self.index_settings.iteritems():
                if not keywords or setting in keywords:
                    for index in index_filter.iter_patterns():
                        if client.can(permission, index):
                            permitted_settings.append(setting)
                        elif setting in keywords:
                            missing_permissions.setdefault(permission, []).append(str(index))

            if missing_permissions:
                permission_hint = ', '.join('{0} ({1})'.format(permission, ', '.join(indices))
                                            for permission, indices in missing_permissions.iteritems())
                raise PermissionError('You are missing the following permissions: {0}'.format(permission_hint))
            elif not keywords and len(permitted_settings) < len(self.index_settings):
                self.path = '/'.join((self.path.rstrip('/'), ','.join(permitted_settings)))
예제 #7
0
    def inspect(self, client):
        restricted_types = client.is_restricted('types')
        requested_indices = FilterString.from_string(
            self.get_match('indices', ''))

        try:
            index_filter = client.create_filter_string(
                'api/indices/create/mappings',
                requested_indices,
                single=restricted_types)
        except MultipleIncludesError as error:
            raise PermissionError(
                'You are restricted to specific types. To create type mappings, please pick a'
                ' single index from the following list: {0}'.format(', '.join(
                    error.includes)))
        else:
            if index_filter is None:
                raise PermissionError(
                    'You are not permitted to create mappings in the given indices.'
                )

        if restricted_types:
            requested_index = index_filter.combined[
                0] if index_filter.combined else index_filter[0]
            if not client.can('api/indices/create/mappings',
                              str(requested_index), self.document):
                raise PermissionError(
                    'You are not permitted to create a mapping for this document type.'
                )

        if index_filter:
            self.path = '/{0}/_mappings/{1}'.format(index_filter,
                                                    self.document)
예제 #8
0
 def inspect(self, client):
     requested_indices = FilterString.from_string(self.get_match('indices', ''))
     index_filter = client.create_filter_string('api/indices/refresh', requested_indices)
     if index_filter is None:
         raise PermissionError('You are not permitted to refresh the given indices.')
     elif index_filter:
         self.path = '/{0}/_refresh'.format(index_filter)
예제 #9
0
 def inspect(self, client):
     requested_indices = FilterString.from_string(self.get_match('indices', ''))
     index_filter = client.create_filter_string('api/cluster/health', requested_indices)
     if index_filter is None:
         raise PermissionError('You are not permitted to check the cluster health for the requested indices.')
     elif index_filter:
         self.path = '/_cluster/health/{0}'.format(index_filter)
예제 #10
0
 def inspect(self, client):
     requested_indices = FilterString.from_string(self.get_match('indices', ''))
     index_filter = client.create_filter_string('api/indices/get/warmers', requested_indices)
     if index_filter is None:
         raise PermissionError('You are not permitted to access warmers of the given indices.')
     elif index_filter:
         self.path = '/{0}/_warmers/{1}'.format(index_filter, self.identifiers)
예제 #11
0
 def inspect(self, client):
     requested_indices = FilterString.from_string(self.get_match('indices', ''))
     index_filter = client.create_filter_string('api/indices/get/settings', requested_indices)
     if index_filter is None:
         raise PermissionError(
             'You are not permitted to access the general settings of the given index or indices.')
     elif index_filter:
         self.path = '/{0}/_settings'.format(index_filter)
예제 #12
0
    def inspect(self, client):
        restricted_types = client.is_restricted('types')
        requested_indices = FilterString.from_string(
            self.get_match('indices', ''))

        try:
            index_filter = client.create_filter_string(
                'api/indices/get/mappings',
                requested_indices,
                single=restricted_types)
        except MultipleIncludesError as error:
            raise PermissionError(
                'You are restricted to specific types. To retrieve type mappings, please pick a'
                ' single index from the following list: {0}'.format(', '.join(
                    error.includes)))
        else:
            if index_filter is None:
                raise PermissionError(
                    'You are not permitted to access the mappings of the given indices.'
                )

        if restricted_types:
            requested_types = FilterString.from_string(
                self.get_match('documents', ''))
            requested_index = index_filter.combined[
                0] if index_filter.combined else index_filter[0]
            type_filter = client.create_filter_string(
                'api/indices/get/mappings', requested_types,
                str(requested_index))
            if type_filter is None:
                raise PermissionError(
                    'You are not permitted to access the mappings of the given types.'
                )
        else:
            type_filter = self.get_match('documents')

        if index_filter:
            if type_filter:
                if self.command == 'HEAD':
                    self.path = '/{0}/{1}'.format(index_filter, type_filter)
                else:
                    self.path = '/{0}/_mappings/{1}'.format(
                        index_filter, type_filter)
            else:
                self.path = '/{0}/_mappings'.format(index_filter)
예제 #13
0
 def inspect(self, client):
     requested_indices = FilterString.from_string(
         self.get_match('indices', ''))
     index_filter = client.create_filter_string('api/indices/refresh',
                                                requested_indices)
     if index_filter is None:
         raise PermissionError(
             'You are not permitted to refresh the given indices.')
     elif index_filter:
         self.path = '/{0}/_refresh'.format(index_filter)
예제 #14
0
    def create_filter_string(self,
                             permission,
                             filter_string=None,
                             index=None,
                             single=False):
        """Create and return a filter string based on what this client is permitted or is requesting to access.
        May return a empty filter if the client is not restricted at all and None if the client can't access
        anything. Raises MultipleIncludesError if single is True and multiple includes were found.

        """
        if not self.is_restricted('indices' if index is None else 'types'):
            # Bail out early if the client is not restricted at all
            return (filter_string or FilterString()) if self.can(
                permission, index) else None

        try:
            if index is not None:
                index = index.base_pattern
        except AttributeError:
            pass

        filters = self._collect_filters(permission, index)
        if filters is None:
            return  # None of the client's roles permit access to any index or any document type
        elif not filters:
            return filter_string or FilterString(
            )  # Not a single restriction, congratulations!

        prepared_filter_string = FilterString()
        for include, excludes in filters.iteritems():
            prepared_filter_string.append_include(include)
            for exclude in excludes:
                prepared_filter_string.append_exclude(exclude)

        if filter_string:
            # In case the client provides a filter it may be required to adjust
            # it a little. We'd like to be smart after all, don't we? ;)
            if not filter_string.combine(prepared_filter_string):
                return  # Nothing what the client requested remained

            if single and len(filter_string.combined) > 1:
                # Although the client already provides a filter it does still consist of multiple restrictions
                raise MultipleIncludesError(filter_string.combined)
        elif single and len(filters) > 1:
            # We can obviously only provide multiple filters and since it would be unsafe
            # to make an assumption on what filter to return, we'll refuse to return one
            raise MultipleIncludesError(filters.keys())
        else:
            # The client does not provide a source filter so we can simply return our own
            filter_string = prepared_filter_string

        return filter_string
예제 #15
0
 def inspect(self, client):
     requested_indices = FilterString.from_string(
         self.get_match('indices', ''))
     index_filter = client.create_filter_string('api/indices/get/settings',
                                                requested_indices)
     if index_filter is None:
         raise PermissionError(
             'You are not permitted to access the general settings of the given index or indices.'
         )
     elif index_filter:
         self.path = '/{0}/_settings'.format(index_filter)
예제 #16
0
    def inspect(self, client):
        index_filter, type_filter, source_filter, json = self.inspect_request(
            client, FilterString.from_string(self.get_match('indices', '')),
            FilterString.from_string(self.get_match('documents', '')),
            SourceFilter.from_query(self.query), self.json)

        if self.query.last('q',
                           '').strip() and self.query.last('q').strip() != '*':
            if client.has_restriction(index_filter, type_filter):
                # TODO: Provide a more sophisticated solution once we've got a parser for query strings!
                raise PermissionError(
                    'You are restricted to specific fields and as such cannot utilize the query string search.'
                )

        if not self.query.is_false('explain'):
            self._check_permission('api/search/explain', client, index_filter,
                                   type_filter)

        fields_filter = client.create_fields_filter(
            'api/search/documents', index_filter, type_filter,
            FieldsFilter.from_query(self.query))
        if fields_filter is None:
            raise PermissionError(
                'You are not permitted to access any of the requested stored fields.'
            )
        elif fields_filter:
            self.query.update(fields_filter.as_query())

        if index_filter:
            if type_filter:
                self.path = '/{0}/{1}/_search'.format(index_filter,
                                                      type_filter)
            else:
                self.path = '/{0}/_search'.format(index_filter)

        self.query.discard('_source', '_source_include', '_source_exclude')
        if source_filter:
            self.query.update(source_filter.as_query())

        if json is not None:
            self.body = self.json_encode(json)
예제 #17
0
 def inspect(self, client):
     requested_indices = FilterString.from_string(
         self.get_match('indices', ''))
     index_filter = client.create_filter_string('api/indices/get/warmers',
                                                requested_indices)
     if index_filter is None:
         raise PermissionError(
             'You are not permitted to access warmers of the given indices.'
         )
     elif index_filter:
         self.path = '/{0}/_warmers/{1}'.format(index_filter,
                                                self.identifiers)
예제 #18
0
    def inspect(self, client):
        if '__kibanaQueryValidator' in self.path:
            # I have _still_ no explanation for this. Please enlighten
            # me if you think this is security relevant in any way.
            if client.can('api/search/explain', '.kibana'):
                return

            raise PermissionError(self._permission_errors['api/search/explain']
                                  ['indices'].format('.kibana'))

        index_filter, type_filter, _, json = self.inspect_request(
            client,
            FilterString.from_string(self.get_match('indices', '')),
            FilterString.from_string(self.get_match('documents', '')),
            json=self.json)

        if self.query.last('q',
                           '').strip() and self.query.last('q').strip() != '*':
            if client.has_restriction(index_filter, type_filter):
                # TODO: Provide a more sophisticated solution once we've got a parser for query strings!
                raise PermissionError(
                    'You are restricted to specific fields and as such cannot utilize the query string search.'
                )

        if not self.query.is_false('explain'):
            self._check_permission('api/search/explain', client, index_filter,
                                   type_filter)

        if index_filter:
            if type_filter:
                self.path = '/{0}/{1}/_validate/query'.format(
                    index_filter, type_filter)
            else:
                self.path = '/{0}/_validate/query'.format(index_filter)

        if json is not None:
            self.body = self.json_encode(json)
예제 #19
0
    def inspect(self, client):
        index_filter = client.create_filter_string(
            'api/indices/get/*', FilterString.from_string(self.indices))
        if index_filter is None:
            raise PermissionError(
                'You are not permitted to access any settings of the given index or indices.'
            )
        elif index_filter:
            self.path = self.path.replace(self.indices, str(index_filter))

        if self.command != 'HEAD':
            keywords = [
                s.strip() for s in self.get_match('keywords', '').split(',')
                if s
            ]
            unknown = next(
                (kw for kw in keywords if kw not in self.index_settings), None)
            if unknown is not None:
                raise PermissionError(
                    'Unknown index setting: {0}'.format(unknown))

            permitted_settings, missing_permissions = [], {}
            for setting, permission in self.index_settings.iteritems():
                if not keywords or setting in keywords:
                    for index in index_filter.iter_patterns():
                        if client.can(permission, index):
                            permitted_settings.append(setting)
                        elif setting in keywords:
                            missing_permissions.setdefault(permission,
                                                           []).append(
                                                               str(index))

            if missing_permissions:
                permission_hint = ', '.join(
                    '{0} ({1})'.format(permission, ', '.join(indices))
                    for permission, indices in missing_permissions.iteritems())
                raise PermissionError(
                    'You are missing the following permissions: {0}'.format(
                        permission_hint))
            elif not keywords and len(permitted_settings) < len(
                    self.index_settings):
                self.path = '/'.join(
                    (self.path.rstrip('/'), ','.join(permitted_settings)))
예제 #20
0
    def inspect(self, client):
        restricted_types = client.is_restricted('types')
        requested_indices = FilterString.from_string(self.get_match('indices', ''))

        try:
            index_filter = client.create_filter_string('api/indices/create/mappings', requested_indices,
                                                       single=restricted_types)
        except MultipleIncludesError as error:
            raise PermissionError(
                'You are restricted to specific types. To create type mappings, please pick a'
                ' single index from the following list: {0}'.format(', '.join(error.includes)))
        else:
            if index_filter is None:
                raise PermissionError('You are not permitted to create mappings in the given indices.')

        if restricted_types:
            requested_index = index_filter.combined[0] if index_filter.combined else index_filter[0]
            if not client.can('api/indices/create/mappings', str(requested_index), self.document):
                raise PermissionError('You are not permitted to create a mapping for this document type.')

        if index_filter:
            self.path = '/{0}/_mappings/{1}'.format(index_filter, self.document)
예제 #21
0
    def _inspect_parser(self, client, parser, index_filter, type_filter):
        json_updated = False
        for permission in parser.permissions:
            # TODO: Context changes? Permissions are not only global anymore!
            if permission != 'api/feature/queryString':
                self._check_permission(permission, client, index_filter, type_filter)
            elif client.has_restriction(index_filter, type_filter):
                # TODO: Remove this once we've got a parser for query strings!
                raise PermissionError(
                    'You are restricted to specific fields and as such cannot utilize the query string search.')

        if client.is_restricted('indices'):
            for index in parser.indices:
                if not index_filter.matches(FilterString.from_string(index)):
                    raise RequestError(400, 'Index filter "{0}" does not match the requested scope "{1}".'
                                            ''.format(index, index_filter))

        if client.is_restricted('types'):
            for index, document_type in parser.documents:
                if index and not index_filter.matches(FilterString.from_string(index)):
                    raise RequestError(400, 'Index filter "{0}" does not match the requested scope "{1}".'
                                            ''.format(index, index_filter))
                elif not type_filter.matches(FilterString.from_string(document_type)):
                    raise RequestError(400, 'Type filter "{0}" does not match the requested scope "{1}".'
                                            ''.format(document_type, type_filter))

        if client.is_restricted('fields'):
            for index, document_type, field in parser.fields:
                if index:
                    indices = FilterString.from_string(index)
                    if not index_filter.matches(indices):
                        raise RequestError(400, 'Index filter "{0}" does not match the requested scope "{1}".'
                                                ''.format(index, index_filter))
                else:
                    indices = index_filter

                if document_type:
                    types = FilterString.from_string(document_type)
                    if not type_filter.matches(types):
                        raise RequestError(400, 'Type filter "{0}" does not match the requested scope "{1}".'
                                                ''.format(document_type, type_filter))
                else:
                    types = type_filter

                for index in indices.iter_patterns():
                    for document_type in types.iter_patterns():
                        if not client.can('api/search/documents', index, document_type, field):
                            raise PermissionError('You are not permitted to search for documents of type "{0}" in index'
                                                  ' "{1}" by using field "{2}".'.format(document_type, index, field))

            try:
                document_requests = parser.document_requests
            except AttributeError:
                pass
            else:
                for index, document_type, document_request in document_requests:
                    if index and not index_filter.matches(FilterString.from_string(index)):
                        raise RequestError(400, 'Index filter "{0}" does not match the requested scope "{1}".'
                                                ''.format(index, index_filter))
                    elif document_type and not type_filter.matches(FilterString.from_string(document_type)):
                        raise RequestError(400, 'Type filter "{0}" does not match the requested scope "{1}".'
                                                ''.format(document_type, type_filter))

                    requested_source = SourceFilter.from_json(document_request.get('_source'))
                    source_filter = client.create_source_filter('api/search/documents', index_filter,
                                                                type_filter, requested_source)
                    if source_filter is None:
                        raise PermissionError('You are either not permitted to access the document type'
                                              ' "{0}" or any of the requested fields ({1}) in index "{2}".'
                                              ''.format(document_type or type_filter, requested_source,
                                                        index or index_filter))
                    elif source_filter:
                        document_request['_source'] = source_filter.as_json()
                        json_updated = True

                    if 'fielddata_fields' in document_request:
                        requested_fielddata = FieldsFilter.from_json(document_request['fielddata_fields'])
                        fielddata_filter = client.create_fields_filter('api/search/documents', index_filter,
                                                                       type_filter, requested_fielddata)
                        if fielddata_filter is None:
                            raise PermissionError(
                                'You are not permitted to access any of the requested fielddata fields ({0}) of type'
                                ' "{1}" in index "{2}".'.format(requested_fielddata, document_type or type_filter,
                                                                index or index_filter))
                        elif fielddata_filter:
                            document_request['fielddata_fields'] = fielddata_filter.as_json()
                            json_updated = True

        return json_updated
예제 #22
0
    def _inspect_parser(self, client, parser, index_filter, type_filter):
        json_updated = False
        for permission in parser.permissions:
            # TODO: Context changes? Permissions are not only global anymore!
            if permission != 'api/feature/queryString':
                self._check_permission(permission, client, index_filter,
                                       type_filter)
            elif client.has_restriction(index_filter, type_filter):
                # TODO: Remove this once we've got a parser for query strings!
                raise PermissionError(
                    'You are restricted to specific fields and as such cannot utilize the query string search.'
                )

        if client.is_restricted('indices'):
            for index in parser.indices:
                if not index_filter.matches(FilterString.from_string(index)):
                    raise RequestError(
                        400,
                        'Index filter "{0}" does not match the requested scope "{1}".'
                        ''.format(index, index_filter))

        if client.is_restricted('types'):
            for index, document_type in parser.documents:
                if index and not index_filter.matches(
                        FilterString.from_string(index)):
                    raise RequestError(
                        400,
                        'Index filter "{0}" does not match the requested scope "{1}".'
                        ''.format(index, index_filter))
                elif not type_filter.matches(
                        FilterString.from_string(document_type)):
                    raise RequestError(
                        400,
                        'Type filter "{0}" does not match the requested scope "{1}".'
                        ''.format(document_type, type_filter))

        if client.is_restricted('fields'):
            for index, document_type, field in parser.fields:
                if index:
                    indices = FilterString.from_string(index)
                    if not index_filter.matches(indices):
                        raise RequestError(
                            400,
                            'Index filter "{0}" does not match the requested scope "{1}".'
                            ''.format(index, index_filter))
                else:
                    indices = index_filter

                if document_type:
                    types = FilterString.from_string(document_type)
                    if not type_filter.matches(types):
                        raise RequestError(
                            400,
                            'Type filter "{0}" does not match the requested scope "{1}".'
                            ''.format(document_type, type_filter))
                else:
                    types = type_filter

                for index in indices.iter_patterns():
                    for document_type in types.iter_patterns():
                        if not client.can('api/search/documents', index,
                                          document_type, field):
                            raise PermissionError(
                                'You are not permitted to search for documents of type "{0}" in index'
                                ' "{1}" by using field "{2}".'.format(
                                    document_type, index, field))

            try:
                document_requests = parser.document_requests
            except AttributeError:
                pass
            else:
                for index, document_type, document_request in document_requests:
                    if index and not index_filter.matches(
                            FilterString.from_string(index)):
                        raise RequestError(
                            400,
                            'Index filter "{0}" does not match the requested scope "{1}".'
                            ''.format(index, index_filter))
                    elif document_type and not type_filter.matches(
                            FilterString.from_string(document_type)):
                        raise RequestError(
                            400,
                            'Type filter "{0}" does not match the requested scope "{1}".'
                            ''.format(document_type, type_filter))

                    requested_source = SourceFilter.from_json(
                        document_request.get('_source'))
                    source_filter = client.create_source_filter(
                        'api/search/documents', index_filter, type_filter,
                        requested_source)
                    if source_filter is None:
                        raise PermissionError(
                            'You are either not permitted to access the document type'
                            ' "{0}" or any of the requested fields ({1}) in index "{2}".'
                            ''.format(document_type or type_filter,
                                      requested_source, index or index_filter))
                    elif source_filter:
                        document_request['_source'] = source_filter.as_json()
                        json_updated = True

                    if 'fielddata_fields' in document_request:
                        requested_fielddata = FieldsFilter.from_json(
                            document_request['fielddata_fields'])
                        fielddata_filter = client.create_fields_filter(
                            'api/search/documents', index_filter, type_filter,
                            requested_fielddata)
                        if fielddata_filter is None:
                            raise PermissionError(
                                'You are not permitted to access any of the requested fielddata fields ({0}) of type'
                                ' "{1}" in index "{2}".'.format(
                                    requested_fielddata, document_type
                                    or type_filter, index or index_filter))
                        elif fielddata_filter:
                            document_request[
                                'fielddata_fields'] = fielddata_filter.as_json(
                                )
                            json_updated = True

        return json_updated