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
group.
parents
.DS_Store
dist/
build/
*.egg-info
*.py[co]
*.swp
# UW Django SAML Tools
Provides saml tools for Django, include `uw_saml_tools` in INSTALLED_APPS.
Requires djangosaml2 (https://github.com/knaperek/djangosaml2/)
# Tools
- Group Membership Sync
- On login, a users groups will be synced based on groups reported by SAML
-e git+https://github.com/knaperek/djangosaml2.git#egg=djangosaml2
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
setup(name='uw_saml_tools',
version='0.1',
description='UW Saml Tools',
author='Ryan Goggin',
author_email='ryan.goggin@uwaterloo.ca',
url='https://ryangoggin.net',
packages=['uw_saml_tools'],
package_dir={'uw_saml_tools': 'uw_saml_tools'},
)
from django.contrib import admin
from uw_saml_tools.models import SyncGroup
admin.site.register([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 = [
migrations.CreateModel(
name='SyncGroup',
fields=[
('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
affected.
"""
groups = []
for g in Group.objects.filter(user=user):
if g.group_sync.count() > 0:
groups.append(g)
sync_groups = SyncGroup.objects.filter(identifier__in=saml_list)
distinct_sync = set([sg.group for sg in sync_groups])
remove_groups = set(groups).difference(distinct_sync)
add_groups = distinct_sync.difference(set(groups))
for rg in remove_groups:
rg.user_set.remove(user)
for ag in add_groups:
ag.user_set.add(user)
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