Commit f7dae86f authored by Ryan Goggin's avatar Ryan Goggin

Initial SAML tools

Backend for djangosaml2 and a group sync function.

If a GroupSync configuration exists for a group, a user NEEDS to be
in at least one GroupSync config option to have membership in that
# UW Django SAML Tools
Provides saml tools for Django, include `uw_saml_tools` in INSTALLED_APPS.
Requires djangosaml2 (
# Tools
- Group Membership Sync
- On login, a users groups will be synced based on groups reported by SAML
-e git+
from setuptools import setup
except ImportError:
from distutils.core import setup
description='UW Saml Tools',
author='Ryan Goggin',
package_dir={'uw_saml_tools': 'uw_saml_tools'},
from django.contrib import admin
from uw_saml_tools.models import SyncGroup[SyncGroup])
from django.apps import AppConfig
class UwSamlToolsConfig(AppConfig):
name = 'uw_saml_tools'
from djangosaml2.backends import Saml2Backend as djsaml2Backend
from django.conf import settings
from uw_saml_tools.utils import sync_user_groups
class Saml2Backend(djsaml2Backend):
def update_user(self, user, attributes, attribute_mapping, force_save=False):
if not attribute_mapping:
return user
for saml_attr, django_attrs in attribute_mapping.items():
if 'groups' in django_attrs:
group_list = attributes.get(saml_attr)
sync_user_groups(user, group_list)
del attribute_mapping[saml_attr]
return super(Saml2Backend, self).update_user(user, attributes, attribute_mapping, force_save)
# Generated by Django 2.0.4 on 2018-05-04 18:10
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
operations = [
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('identifier', models.CharField(help_text='Group identifier provided by saml', max_length=1024)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='group_sync', to='auth.Group')),
from django.contrib.auth.models import Group
from django.db import models
class SyncGroup(models.Model):
identifier = models.CharField(max_length=1024, null=False, blank=False, help_text="Group identifier provided by saml")
group = models.ForeignKey(Group, related_name="group_sync", on_delete=models.CASCADE)
def __str__(self):
return self.identifier
from django.test import TestCase
# Create your tests here.
from django.contrib.auth.models import Group
from uw_saml_tools.models import SyncGroup
def sync_user_groups(user, saml_list):
Takes a django user and list of groups as provided by saml and syncs the
user's group membership to match based on GroupSync configurations.
Any group that does not have a GroupSync configuration will not be
groups = []
for g in Group.objects.filter(user=user):
if g.group_sync.count() > 0:
sync_groups = SyncGroup.objects.filter(identifier__in=saml_list)
distinct_sync = set([ for sg in sync_groups])
remove_groups = set(groups).difference(distinct_sync)
add_groups = distinct_sync.difference(set(groups))
for rg in remove_groups:
for ag in add_groups:
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment