mirror of https://github.com/doccano/doccano.git
Browse Source
Merge pull request #210 from CatalystCode/enhancement/social-admin-info
Merge pull request #210 from CatalystCode/enhancement/social-admin-info
Enhancement/Read admin info from third-party authpull/232/head
Hiroki Nakayama
5 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 450 additions and 1 deletions
Unified View
Diff Options
-
26app/app/settings.py
-
70app/server/social_auth.py
-
52app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_is_admin.yaml
-
52app/server/tests/cassettes/TestAzureADTenantSocialAuth.test_fetch_permissions_not_admin.yaml
-
76app/server/tests/cassettes/TestGithubSocialAuth.test_fetch_permissions_is_admin.yaml
-
77app/server/tests/cassettes/TestGithubSocialAuth.test_fetch_permissions_not_admin.yaml
-
95app/server/tests/test_social_auth.py
-
3requirements.txt
@ -0,0 +1,70 @@ |
|||||
|
import requests |
||||
|
from django.conf import settings |
||||
|
from social_core.backends.azuread_tenant import AzureADTenantOAuth2 |
||||
|
from social_core.backends.github import GithubOAuth2 |
||||
|
|
||||
|
|
||||
|
# noinspection PyUnusedLocal |
||||
|
def fetch_github_permissions(strategy, details, user=None, is_new=False, *args, **kwargs): |
||||
|
org_name = getattr(settings, 'GITHUB_ADMIN_ORG_NAME', '') |
||||
|
team_name = getattr(settings, 'GITHUB_ADMIN_TEAM_NAME', '') |
||||
|
if not user or not isinstance(kwargs['backend'], GithubOAuth2) or not org_name or not team_name: |
||||
|
return |
||||
|
|
||||
|
response = requests.post( |
||||
|
url='https://api.github.com/graphql', |
||||
|
headers={ |
||||
|
'Authorization': 'Bearer {}'.format(kwargs['response']['access_token']), |
||||
|
}, |
||||
|
json={ |
||||
|
'query': ''' |
||||
|
query($userName: String!, $orgName: String!, $teamName: String!) { |
||||
|
organization(login: $orgName) { |
||||
|
teams(query: $teamName, userLogins: [$userName], first: 1) { |
||||
|
nodes { |
||||
|
name |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
''', |
||||
|
'variables': { |
||||
|
'userName': details['username'], |
||||
|
'orgName': org_name, |
||||
|
'teamName': team_name, |
||||
|
} |
||||
|
} |
||||
|
) |
||||
|
response.raise_for_status() |
||||
|
response = response.json() |
||||
|
|
||||
|
is_superuser = {'name': team_name} in response['data']['organization']['teams']['nodes'] |
||||
|
|
||||
|
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() |
@ -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 |
@ -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 |
@ -0,0 +1,76 @@ |
|||||
|
interactions: |
||||
|
- request: |
||||
|
body: '{"query": "\n query($userName: String!, $orgName: String!, |
||||
|
$teamName: String!) {\n organization(login: $orgName) {\n teams(query: |
||||
|
$teamName, userLogins: [$userName], first: 1) {\n nodes |
||||
|
{\n name\n }\n }\n }\n }\n ", |
||||
|
"variables": {"userName": "c-w", "orgName": "CatalystCode", "teamName": "doccano-dev"}}' |
||||
|
headers: |
||||
|
Accept: |
||||
|
- '*/*' |
||||
|
Accept-Encoding: |
||||
|
- gzip, deflate |
||||
|
Connection: |
||||
|
- keep-alive |
||||
|
Content-Length: |
||||
|
- '513' |
||||
|
Content-Type: |
||||
|
- application/json |
||||
|
User-Agent: |
||||
|
- python-requests/2.21.0 |
||||
|
method: POST |
||||
|
uri: https://api.github.com/graphql |
||||
|
response: |
||||
|
body: |
||||
|
string: '{"data":{"organization":{"teams":{"nodes":[{"name":"doccano-dev"}]}}}}' |
||||
|
headers: |
||||
|
Access-Control-Allow-Origin: |
||||
|
- '*' |
||||
|
Access-Control-Expose-Headers: |
||||
|
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, |
||||
|
X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, |
||||
|
X-GitHub-Media-Type |
||||
|
Cache-Control: |
||||
|
- no-cache |
||||
|
Content-Security-Policy: |
||||
|
- default-src 'none' |
||||
|
Content-Type: |
||||
|
- application/json; charset=utf-8 |
||||
|
Date: |
||||
|
- Mon, 20 May 2019 17:38:20 GMT |
||||
|
Referrer-Policy: |
||||
|
- origin-when-cross-origin, strict-origin-when-cross-origin |
||||
|
Server: |
||||
|
- GitHub.com |
||||
|
Status: |
||||
|
- 200 OK |
||||
|
Strict-Transport-Security: |
||||
|
- max-age=31536000; includeSubdomains; preload |
||||
|
Transfer-Encoding: |
||||
|
- chunked |
||||
|
X-Accepted-OAuth-Scopes: |
||||
|
- repo |
||||
|
X-Content-Type-Options: |
||||
|
- nosniff |
||||
|
X-Frame-Options: |
||||
|
- deny |
||||
|
X-GitHub-Media-Type: |
||||
|
- github.v4; format=json |
||||
|
X-GitHub-Request-Id: |
||||
|
- E979:03BD:225D930:49FB694:5CE2E60C |
||||
|
X-OAuth-Scopes: |
||||
|
- read:org |
||||
|
X-RateLimit-Limit: |
||||
|
- '5000' |
||||
|
X-RateLimit-Remaining: |
||||
|
- '4955' |
||||
|
X-RateLimit-Reset: |
||||
|
- '1558377500' |
||||
|
X-XSS-Protection: |
||||
|
- 1; mode=block |
||||
|
content-length: |
||||
|
- '70' |
||||
|
status: |
||||
|
code: 200 |
||||
|
message: OK |
||||
|
version: 1 |
@ -0,0 +1,77 @@ |
|||||
|
interactions: |
||||
|
- request: |
||||
|
body: '{"query": "\n query($userName: String!, $orgName: String!, |
||||
|
$teamName: String!) {\n organization(login: $orgName) {\n teams(query: |
||||
|
$teamName, userLogins: [$userName], first: 1) {\n nodes |
||||
|
{\n name\n }\n }\n }\n }\n ", |
||||
|
"variables": {"userName": "hirosan", "orgName": "CatalystCode", "teamName": |
||||
|
"doccano-dev"}}' |
||||
|
headers: |
||||
|
Accept: |
||||
|
- '*/*' |
||||
|
Accept-Encoding: |
||||
|
- gzip, deflate |
||||
|
Connection: |
||||
|
- keep-alive |
||||
|
Content-Length: |
||||
|
- '517' |
||||
|
Content-Type: |
||||
|
- application/json |
||||
|
User-Agent: |
||||
|
- python-requests/2.21.0 |
||||
|
method: POST |
||||
|
uri: https://api.github.com/graphql |
||||
|
response: |
||||
|
body: |
||||
|
string: '{"data":{"organization":{"teams":{"nodes":[]}}}}' |
||||
|
headers: |
||||
|
Access-Control-Allow-Origin: |
||||
|
- '*' |
||||
|
Access-Control-Expose-Headers: |
||||
|
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, |
||||
|
X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, |
||||
|
X-GitHub-Media-Type |
||||
|
Cache-Control: |
||||
|
- no-cache |
||||
|
Content-Security-Policy: |
||||
|
- default-src 'none' |
||||
|
Content-Type: |
||||
|
- application/json; charset=utf-8 |
||||
|
Date: |
||||
|
- Mon, 20 May 2019 17:38:20 GMT |
||||
|
Referrer-Policy: |
||||
|
- origin-when-cross-origin, strict-origin-when-cross-origin |
||||
|
Server: |
||||
|
- GitHub.com |
||||
|
Status: |
||||
|
- 200 OK |
||||
|
Strict-Transport-Security: |
||||
|
- max-age=31536000; includeSubdomains; preload |
||||
|
Transfer-Encoding: |
||||
|
- chunked |
||||
|
X-Accepted-OAuth-Scopes: |
||||
|
- repo |
||||
|
X-Content-Type-Options: |
||||
|
- nosniff |
||||
|
X-Frame-Options: |
||||
|
- deny |
||||
|
X-GitHub-Media-Type: |
||||
|
- github.v4; format=json |
||||
|
X-GitHub-Request-Id: |
||||
|
- E97B:0EFE:220AB47:4963FE2:5CE2E60C |
||||
|
X-OAuth-Scopes: |
||||
|
- read:org |
||||
|
X-RateLimit-Limit: |
||||
|
- '5000' |
||||
|
X-RateLimit-Remaining: |
||||
|
- '4954' |
||||
|
X-RateLimit-Reset: |
||||
|
- '1558377500' |
||||
|
X-XSS-Protection: |
||||
|
- 1; mode=block |
||||
|
content-length: |
||||
|
- '48' |
||||
|
status: |
||||
|
code: 200 |
||||
|
message: OK |
||||
|
version: 1 |
@ -0,0 +1,95 @@ |
|||||
|
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 |
||||
|
|
||||
|
from .. import social_auth |
||||
|
|
||||
|
User = get_user_model() |
||||
|
|
||||
|
|
||||
|
class VCRTestCase(VCRMixin, TestCase): |
||||
|
@property |
||||
|
def access_token(self): |
||||
|
raise NotImplementedError() |
||||
|
|
||||
|
def _get_vcr(self, **kwargs): |
||||
|
kwargs['decode_compressed_response'] = True |
||||
|
kwargs['record_mode'] = 'none' if self.access_token == 'censored' else 'all' |
||||
|
return super()._get_vcr(**kwargs) |
||||
|
|
||||
|
def _get_vcr_kwargs(self, **kwargs): |
||||
|
kwargs['filter_headers'] = ['Authorization'] |
||||
|
return super()._get_vcr_kwargs(**kwargs) |
||||
|
|
||||
|
|
||||
|
@override_settings(GITHUB_ADMIN_ORG_NAME='CatalystCode') |
||||
|
@override_settings(GITHUB_ADMIN_TEAM_NAME='doccano-dev') |
||||
|
class TestGithubSocialAuth(VCRTestCase): |
||||
|
strategy = None |
||||
|
backend = GithubOAuth2(strategy=strategy) |
||||
|
access_token = 'censored' |
||||
|
|
||||
|
def test_fetch_permissions_is_admin(self): |
||||
|
user = User() |
||||
|
|
||||
|
social_auth.fetch_github_permissions( |
||||
|
strategy=self.strategy, |
||||
|
details={'username': 'c-w'}, |
||||
|
user=user, |
||||
|
backend=self.backend, |
||||
|
response={'access_token': self.access_token}, |
||||
|
) |
||||
|
|
||||
|
self.assertTrue(user.is_superuser) |
||||
|
|
||||
|
def test_fetch_permissions_not_admin(self): |
||||
|
user = User() |
||||
|
|
||||
|
social_auth.fetch_github_permissions( |
||||
|
strategy=self.strategy, |
||||
|
details={'username': 'hirosan'}, |
||||
|
user=user, |
||||
|
backend=self.backend, |
||||
|
response={'access_token': self.access_token}, |
||||
|
) |
||||
|
|
||||
|
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) |
Write
Preview
Loading…
Cancel
Save