diff --git a/app/app/settings.py b/app/app/settings.py index 3291a366..618f55e6 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -129,6 +129,11 @@ if GITHUB_ADMIN_ORG_NAME and GITHUB_ADMIN_TEAM_NAME: SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_KEY = env('OAUTH_AAD_KEY', None) SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_SECRET = env('OAUTH_AAD_SECRET', None) SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_TENANT_ID = env('OAUTH_AAD_TENANT', None) +AZUREAD_ADMIN_GROUP_ID = env('AZUREAD_ADMIN_GROUP_ID', None) + +if AZUREAD_ADMIN_GROUP_ID: + SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_RESOURCE = 'https://graph.microsoft.com/' + SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_SCOPE = ['Directory.Read.All'] SOCIAL_AUTH_PIPELINE = [ 'social_core.pipeline.social_auth.social_details', @@ -141,6 +146,7 @@ SOCIAL_AUTH_PIPELINE = [ 'social_core.pipeline.social_auth.load_extra_data', 'social_core.pipeline.user.user_details', 'server.social_auth.fetch_github_permissions', + 'server.social_auth.fetch_azuread_permissions', ] # Database diff --git a/app/server/social_auth.py b/app/server/social_auth.py index 943c63a6..35adf722 100644 --- a/app/server/social_auth.py +++ b/app/server/social_auth.py @@ -1,5 +1,6 @@ import requests from django.conf import settings +from social_core.backends.azuread_tenant import AzureADTenantOAuth2 from social_core.backends.github import GithubOAuth2 @@ -42,3 +43,28 @@ def fetch_github_permissions(strategy, details, user=None, is_new=False, *args, if user.is_superuser != is_superuser: user.is_superuser = is_superuser user.save() + + +# noinspection PyUnusedLocal +def fetch_azuread_permissions(strategy, details, user=None, is_new=False, *args, **kwargs): + group_id = getattr(settings, 'AZUREAD_ADMIN_GROUP_ID', '') + if not user or not isinstance(kwargs['backend'], AzureADTenantOAuth2) or not group_id: + return + + response = requests.post( + url='https://graph.microsoft.com/v1.0/me/checkMemberGroups', + headers={ + 'Authorization': 'Bearer {}'.format(kwargs['response']['access_token']), + }, + json={ + 'groupIds': [group_id] + } + ) + response.raise_for_status() + response = response.json() + + is_superuser = group_id in response['value'] + + if user.is_superuser != is_superuser: + user.is_superuser = is_superuser + user.save() diff --git a/app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_is_admin.yaml b/app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_is_admin.yaml new file mode 100644 index 00000000..a9c7989c --- /dev/null +++ b/app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_is_admin.yaml @@ -0,0 +1,52 @@ +interactions: +- request: + body: '{"groupIds": ["dddddddd-dddd-dddd-dddd-dddddddddddd"]}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '54' + Content-Type: + - application/json + User-Agent: + - python-requests/2.21.0 + method: POST + uri: https://graph.microsoft.com/v1.0/me/checkMemberGroups + response: + body: + string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(Edm.String)","value":["dddddddd-dddd-dddd-dddd-dddddddddddd"]}' + headers: + Cache-Control: + - private + Content-Type: + - application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8 + Date: + - Mon, 20 May 2019 19:34:27 GMT + Duration: + - '89.2611' + Location: + - https://graph.microsoft.com + OData-Version: + - '4.0' + Strict-Transport-Security: + - max-age=31536000 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + client-request-id: + - 78c55087-ba07-4e80-8498-8b23b1901356 + content-length: + - '135' + request-id: + - 78c55087-ba07-4e80-8498-8b23b1901356 + x-ms-ags-diagnostic: + - '{"ServerInfo":{"DataCenter":"East US","Slice":"SliceC","Ring":"2","ScaleUnit":"000","RoleInstance":"AGSFE_IN_51","ADSiteName":"EUS"}}' + status: + code: 200 + message: OK +version: 1 diff --git a/app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_not_admin.yaml b/app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_not_admin.yaml new file mode 100644 index 00000000..7d2cba35 --- /dev/null +++ b/app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_not_admin.yaml @@ -0,0 +1,52 @@ +interactions: +- request: + body: '{"groupIds": ["eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"]}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '54' + Content-Type: + - application/json + User-Agent: + - python-requests/2.21.0 + method: POST + uri: https://graph.microsoft.com/v1.0/me/checkMemberGroups + response: + body: + string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(Edm.String)","value":[]}' + headers: + Cache-Control: + - private + Content-Type: + - application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8 + Date: + - Mon, 20 May 2019 19:34:52 GMT + Duration: + - '84.3986' + Location: + - https://graph.microsoft.com + OData-Version: + - '4.0' + Strict-Transport-Security: + - max-age=31536000 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + client-request-id: + - 69bf4728-ae4e-47ef-afd0-7d2c31129b83 + content-length: + - '97' + request-id: + - 69bf4728-ae4e-47ef-afd0-7d2c31129b83 + x-ms-ags-diagnostic: + - '{"ServerInfo":{"DataCenter":"East US","Slice":"SliceC","Ring":"2","ScaleUnit":"000","RoleInstance":"AGSFE_IN_5","ADSiteName":"EUS"}}' + status: + code: 200 + message: OK +version: 1 diff --git a/app/server/tests/test_social_auth.py b/app/server/tests/test_social_auth.py index 0c5d81e3..e8eca0cd 100644 --- a/app/server/tests/test_social_auth.py +++ b/app/server/tests/test_social_auth.py @@ -1,5 +1,6 @@ from django.contrib.auth import get_user_model from django.test import TestCase, override_settings +from social_core.backends.azuread_tenant import AzureADTenantOAuth2 from social_core.backends.github import GithubOAuth2 from vcr_unittest import VCRMixin @@ -55,3 +56,40 @@ class TestGithubSocialAuth(VCRTestCase): ) self.assertFalse(user.is_superuser) + + +@override_settings(SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_KEY='aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa') +@override_settings(SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_SECRET='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=') +@override_settings(SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_TENANT='cccccccc-cccc-cccc-cccc-cccccccccccc') +class TestAzureADTenantSocialAuth(VCRTestCase): + strategy = None + backend = AzureADTenantOAuth2(strategy=strategy) + access_token = 'censored' + + @override_settings(AZUREAD_ADMIN_GROUP_ID='dddddddd-dddd-dddd-dddd-dddddddddddd') + def test_fetch_permissions_is_admin(self): + user = User() + + social_auth.fetch_azuread_permissions( + strategy=self.strategy, + details={}, + user=user, + backend=self.backend, + response={'access_token': self.access_token}, + ) + + self.assertTrue(user.is_superuser) + + @override_settings(AZUREAD_ADMIN_GROUP_ID='eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee') + def test_fetch_permissions_not_admin(self): + user = User() + + social_auth.fetch_azuread_permissions( + strategy=self.strategy, + details={}, + user=user, + backend=self.backend, + response={'access_token': self.access_token}, + ) + + self.assertFalse(user.is_superuser)