diff --git a/ssoauth/app_settings/defaults.py b/ssoauth/app_settings/defaults.py
index 23fb520780e4eaa51526d593b74ad9821292ce03..37339892d14d5d10d87c47a20831a2aa44198617 100644
--- a/ssoauth/app_settings/defaults.py
+++ b/ssoauth/app_settings/defaults.py
@@ -33,6 +33,7 @@ SP_SLS_ENABLED = False  # single log out creates too many problems, so it is dis
 SP_SLS_X_FRAME_OPTIONS = None  # in case you encounter problems with SLS view not allowed inside of an iframe, e.g. "ALLOW-FROM idp-test.it.hs-hannover.de idp.hs-hannover.de"
 
 GROUPS_SAML_ATTRIBUTE = "IDMGroups"  # this SAML attribute is expected to contain list of groups for a user
+GROUP_RESOLVER = "ssoauth.auth_utils.groups_from_saml2_dn_list"  # in case you want to override how groups are resolved for users
 
 """
 Settings you might want to change on development (don't change them for production):
diff --git a/ssoauth/auth_utils.py b/ssoauth/auth_utils.py
index 98b4f7920e01c7733f207a51f93491f663469a67..b528e00a244ed9212cffedbb154a1c332c890c4b 100644
--- a/ssoauth/auth_utils.py
+++ b/ssoauth/auth_utils.py
@@ -7,6 +7,7 @@ from . import models
 from . import logger
 from . import app_settings
 import functools
+import importlib
 
 
 def _validate_username(username):
@@ -92,22 +93,41 @@ def update_user_data(user, surname=None, forename=None, email=None):
     user.save()
 
 
-def set_user_groups(user, group_dn_list):
+def set_user_groups(user, saml2_groups):
     """ Updates groups for the user. """
+    # get the group resolver method
+    try:
+        resolver_path = app_settings.GROUP_RESOLVER.split(".")
+        assert len(resolver_path) >= 2, "need full path of the resolver method"
+        resolver_module_name = ".".join(resolver_path[:-1])
+        resolver_method_name = resolver_path[-1]
+        resolver_module = importlib.import_module(resolver_module_name)
+        resolver_method = getattr(resolver_module, resolver_method_name)
+    except Exception as e:
+        raise ImportError("Could not import {r}. {e.__class__.__name__}: {e}".format(r=app_settings.GROUP_RESOLVER, e=e))
+    # resolve the groups
+    groups = resolver_method(user, saml2_groups)
+    assert isinstance(groups, (list, tuple, set,)) and all(isinstance(g, Group) for g in groups), \
+        "{r} instead of a list/tuple/set of Group objects returned: {garbage}".format(r=app_settings.GROUP_RESOLVER, garbage=groups)
+    # update user groups
+    if set(user.groups.all()) != set(groups):
+        user.groups.set(groups)
+        assert set(user.groups.all()) == set(groups)  # dunno how relation.set() behaves, better safe than sorry
+        logger.info("Groups for {user} were updated.".format(user=user))
+    # done
+    logger.info("User {user} is member of: {groups}".format(user=user, groups=set(str(g) for g in groups)))
+
+
+def groups_from_saml2_dn_list(user, groups_dn_list):
+    """ This default group resolver returns list of Group objects based on DN list """
     # using Q to create ignore-case DN lookup since DS is case insensitive
-    q_list = [Q(sso_mapping__dn__iexact=dn) for dn in group_dn_list]
+    q_list = [Q(sso_mapping__dn__iexact=dn) for dn in groups_dn_list]
     if q_list:
         q_combined = functools.reduce(lambda q1, q2: q1 | q2, q_list)
         groups = list(Group.objects.filter(q_combined))
     else:
         groups = list()
-    # modify user groups
-    if set(user.groups.all()) != set(groups):
-        user.groups.set(groups)
-        assert set(user.groups.all()) == set(groups)  # dunno how relation.set() behaves, better safe than sorry
-        logger.info("Groups for {user} are updated to: {groups}".format(user=user, groups=", ".join(g.name for g in groups)))
-    logger.debug("User {user} has {g_n} group(s) based on {dn_n} DN(s): {g_names}".format(
-        user=user, g_n=len(groups), g_names=", ".join(str(g) for g in groups) or "(none)", dn_n=len(group_dn_list)))
+    return groups
 
 
 def cleanup_direct_permissions(user):