Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ AZURE_AUTH = {
"PUBLIC_URLS": ["<public:view_name>",], # Optional, public views accessible by non-authenticated users
"PUBLIC_PATHS": ['/go/',], # Optional, public paths accessible by non-authenticated users
"ROLES": {
"95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": "GroupName1",
"3dc6539e-0589-4663-b782-fef100d839aa": "GroupName2"
"95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": "GroupName1", # mapped to one Django group
"3dc6539e-0589-4663-b782-fef100d839aa": ["GroupName2", "GroupName3"] # mapped to multiple Django groups
}, # Optional, will add user to django group if user is in EntraID group
"USERNAME_ATTRIBUTE": "mail", # The AAD attribute or ID token claim you want to use as the value for the user model `USERNAME_FIELD`
"GROUP_ATTRIBUTE": "roles", # The AAD attribute or ID token claim you want to use as the value for the user's group memberships
Expand Down
27 changes: 16 additions & 11 deletions azure_auth/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,17 +133,22 @@ def sync_groups(self, user, token):
groups_attr = settings.AZURE_AUTH.get("GROUP_ATTRIBUTE", "roles")
azure_token_roles = token.get("id_token_claims", {}).get(groups_attr, None)
if role_mappings: # pragma: no branch
for role, group_name in role_mappings.items():
# all groups are created by default if they not exist
django_group = Group.objects.get_or_create(name=group_name)[0]

if azure_token_roles and role in azure_token_roles:
# Add user with permissions to the corresponding django group
user.groups.add(django_group)
else:
# No permission so check if user is in group and remove
if user.groups.filter(name=group_name).exists():
user.groups.remove(django_group)
for role, group_names in role_mappings.items():
if not isinstance(group_names, list):
group_names = [group_names]
for group_name in group_names:
if not group_name:
continue # Skip empty group names
# all groups are created by default if they not exist
django_group = Group.objects.get_or_create(name=group_name)[0]

if azure_token_roles and role in azure_token_roles:
# Add user with permissions to the corresponding django group
user.groups.add(django_group)
else:
# No permission so check if user is in group and remove
if user.groups.filter(name=group_name).exists():
user.groups.remove(django_group)

return user

Expand Down
108 changes: 108 additions & 0 deletions azure_auth/tests/test_handler.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections import ChainMap

import pytest
from django.conf import settings
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import RequestFactory, TestCase, override_settings
Expand All @@ -8,6 +9,8 @@
from azure_auth.handlers import AuthHandler


@pytest.mark.django_db
@pytest.mark.usefixtures("token")
class TestAzureAuthHandler(TestCase):
def setUp(self):
self.request_factory = RequestFactory()
Expand Down Expand Up @@ -48,3 +51,108 @@ def _build_auth_handler(self) -> AuthHandler:
req = self.request_factory.get("/")
self.session_midleware.process_request(req)
return AuthHandler(req)

def test_group_mapping(self):
handler = self._build_auth_handler()
handler.sync_groups(self.user, self.token)
self.assertEqual(self.user.groups.count(), 1)

@override_settings(
AZURE_AUTH=ChainMap(
{
"ROLES": {
# Just some random GUID, that is not in the token
"a1ad6d75-11c5-442b-9b32-17bdebe82427": "GroupName1",
}
},
settings.AZURE_AUTH,
)
)
def test_no_mapping(self):
handler = self._build_auth_handler()
handler.sync_groups(self.user, self.token)
self.assertEqual(self.user.groups.count(), 0)

@override_settings(
AZURE_AUTH=ChainMap(
{
"ROLES": {
"95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": ["GroupName1"],
}
},
settings.AZURE_AUTH,
)
)
def test_single_group_list_mapping(self):
handler = self._build_auth_handler()
handler.sync_groups(self.user, self.token)
self.assertEqual(self.user.groups.count(), 1)

@override_settings(
AZURE_AUTH=ChainMap(
{
"ROLES": {
"95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": [
"GroupName1",
"GroupName2",
],
}
},
settings.AZURE_AUTH,
)
)
def test_multi_group_list_mapping(self):
handler = self._build_auth_handler()
handler.sync_groups(self.user, self.token)
self.assertEqual(self.user.groups.count(), 2)

@override_settings(
AZURE_AUTH=ChainMap(
{
"ROLES": {
"95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": [
"GroupName1",
"",
],
}
},
settings.AZURE_AUTH,
)
)
def test_multi_group_list_mapping_with_empty(self):
handler = self._build_auth_handler()
handler.sync_groups(self.user, self.token)
self.assertEqual(self.user.groups.count(), 1)

@override_settings(
AZURE_AUTH=ChainMap(
{
"ROLES": {
"95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": [
"GroupName1",
None,
],
}
},
settings.AZURE_AUTH,
)
)
def test_multi_group_list_mapping_with_none(self):
handler = self._build_auth_handler()
handler.sync_groups(self.user, self.token)
self.assertEqual(self.user.groups.count(), 1)

@override_settings(
AZURE_AUTH=ChainMap(
{
"ROLES": {
"95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": [],
}
},
settings.AZURE_AUTH,
)
)
def test_empty_group_list_mapping(self):
handler = self._build_auth_handler()
handler.sync_groups(self.user, self.token)
self.assertEqual(self.user.groups.count(), 0)