While trying to use django-scim2 in a project, I noticed, that the default UserFilterQuery uses a custom SQL query building class under the hood. This is also the case for the default GroupFilterParser. It could also very well be that I overlooked something.
Anyway, I tried to work around this by using a custom filter parsers, would like to share what I tried, and could currently see no better option than filing an issue here 🙂.
The custom parsers look something like this (everything that was needed seemed to be already there in the scim2_filter_parser):
from scim2_filter_parser.lexer import SCIMLexer
from scim2_filter_parser.parser import SCIMParser
from scim2_filter_parser.transpilers.django_q_object import Transpiler as SCIMTranspiler
class CustomFilterParserBase:
attr_map = {}
@classmethod
def search(cls, query, request=None):
return cls.query_to_qs(query, cls.attr_map)
@staticmethod
def query_to_qs(query, attr_map):
tokens = SCIMLexer().tokenize(query)
ast = SCIMParser().parse(tokens)
qs = SCIMTranspiler(attr_map).transpile(ast)
return qs
class UserFilterParser(CustomFilterParserBase):
attr_map = {
# attr, sub attr, uri
("externalId", None, None): "userlicense__external_user_id",
("userName", None, None): "username",
("name", "familyName", None): "last_name",
("familyName", None, None): "last_name",
("name", "givenName", None): "first_name",
("givenName", None, None): "first_name",
("active", None, None): "is_active",
}
class GroupFilterParser(CustomFilterParserBase):
attr_map = {
# attr, sub attr, uri
("externalId", None, None): "external_group_id",
("displayName", None, None): "name",
# ("userName", None, None): "username",
# ("name", "familyName", None): "last_name",
# ("familyName", None, None): "last_name",
# ("name", "givenName", None): "first_name",
# ("givenName", None, None): "first_name",
# ("active", None, None): "is_active",
}
I set them in the SCIM_SERVICE_PROVIDER configuration within settings.py like this:
SCIM_SERVICE_PROVIDER = {
# ...
"USER_FILTER_PARSER": "my_scim.filters.UserFilterParser",
"GROUP_FILTER_PARSER": "my_scim.filters.GroupFilterParser",
# ...
}
And I have a custom UsersView and GroupsView that look something like this:
import json
from django_scim import constants
from django_scim import exceptions as scim_exceptions
from django_scim import views
from scim2_filter_parser.parser import SCIMParserError
class CustomFilterMixin:
def _search(self, request, query, start, count):
qs = self.model_cls.objects.all()
try:
q = self.__class__.parser_getter().search(query, request)
except (ValueError, SCIMParserError) as e:
raise scim_exceptions.BadRequestError(
"Invalid filter/search query: " + str(e)
)
else:
qs = qs.filter(q)
extra_filter_kwargs = self.get_extra_filter_kwargs(request)
qs = qs.filter(**extra_filter_kwargs)
extra_exclude_kwargs = self.get_extra_exclude_kwargs(request)
qs = qs.exclude(**extra_exclude_kwargs)
qs = self.get_queryset_post_processor(request, qs)
qs = qs.order_by(self.lookup_field)
return self._build_response(request, qs, *self._page(request))
class UsersView(CustomFilterMixin, views.UsersView):
pass
class GroupsView(CustomFilterMixin, views.GroupsView):
pass
I hope that this can be of use and If you have any more question, please let me know.
While trying to use
django-scim2in a project, I noticed, that the defaultUserFilterQueryuses a custom SQL query building class under the hood. This is also the case for the defaultGroupFilterParser. It could also very well be that I overlooked something.Anyway, I tried to work around this by using a custom filter parsers, would like to share what I tried, and could currently see no better option than filing an issue here 🙂.
The custom parsers look something like this (everything that was needed seemed to be already there in the
scim2_filter_parser):I set them in the
SCIM_SERVICE_PROVIDERconfiguration withinsettings.pylike this:And I have a custom
UsersViewandGroupsViewthat look something like this:I hope that this can be of use and If you have any more question, please let me know.