mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
subdomains: Add tests for single domain OAuth2.
This commit is contained in:
@@ -4,9 +4,10 @@ from django.http import HttpResponse
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django_auth_ldap.backend import _LDAPUser
|
from django_auth_ldap.backend import _LDAPUser
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
from typing import Any, Callable, Dict
|
from typing import Any, Callable, Dict, Optional
|
||||||
from builtins import object
|
from builtins import object
|
||||||
from oauth2client.crypt import AppIdentityError
|
from oauth2client.crypt import AppIdentityError
|
||||||
|
from django.core import signing
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
import mock
|
import mock
|
||||||
@@ -40,6 +41,7 @@ from social.backends.github import GithubOrganizationOAuth2, GithubTeamOAuth2, \
|
|||||||
|
|
||||||
from six import text_type
|
from six import text_type
|
||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
|
from six.moves.http_cookies import SimpleCookie
|
||||||
import ujson
|
import ujson
|
||||||
from fakeldap import MockLDAP
|
from fakeldap import MockLDAP
|
||||||
|
|
||||||
@@ -485,11 +487,18 @@ class ResponseMock(object):
|
|||||||
# type: () -> str
|
# type: () -> str
|
||||||
return "Response text"
|
return "Response text"
|
||||||
|
|
||||||
class GoogleLoginTest(ZulipTestCase):
|
class GoogleOAuthTest(ZulipTestCase):
|
||||||
def google_oauth2_test(self, token_response, account_response):
|
def google_oauth2_test(self, token_response, account_response, subdomain=None):
|
||||||
# type: (ResponseMock, ResponseMock) -> HttpResponse
|
# type: (ResponseMock, ResponseMock, Optional[str]) -> HttpResponse
|
||||||
result = self.client_get("/accounts/login/google/send/")
|
url = "/accounts/login/google/send/"
|
||||||
|
if subdomain is not None:
|
||||||
|
url += "?subdomain=" + subdomain
|
||||||
|
|
||||||
|
result = self.client_get(url)
|
||||||
self.assertEquals(result.status_code, 302)
|
self.assertEquals(result.status_code, 302)
|
||||||
|
if 'google' not in result.url:
|
||||||
|
return result
|
||||||
|
|
||||||
# Now extract the CSRF token from the redirect URL
|
# Now extract the CSRF token from the redirect URL
|
||||||
parsed_url = urllib.parse.urlparse(result.url)
|
parsed_url = urllib.parse.urlparse(result.url)
|
||||||
csrf_state = urllib.parse.parse_qs(parsed_url.query)['state']
|
csrf_state = urllib.parse.parse_qs(parsed_url.query)['state']
|
||||||
@@ -500,6 +509,100 @@ class GoogleLoginTest(ZulipTestCase):
|
|||||||
dict(state=csrf_state))
|
dict(state=csrf_state))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
class GoogleSubdomainLoginTest(GoogleOAuthTest):
|
||||||
|
def get_signed_subdomain_cookie(self, data):
|
||||||
|
# type: (Dict[str, str]) -> Dict[str, str]
|
||||||
|
key = 'subdomain.signature'
|
||||||
|
salt = key + 'zerver.views.auth'
|
||||||
|
value = ujson.dumps(data)
|
||||||
|
return {key: signing.get_cookie_signer(salt=salt).sign(value)}
|
||||||
|
|
||||||
|
def unsign_subdomain_cookie(self, result):
|
||||||
|
# type: (HttpResponse) -> Dict[str, Any]
|
||||||
|
key = 'subdomain.signature'
|
||||||
|
salt = key + 'zerver.views.auth'
|
||||||
|
cookie = result.cookies.get(key)
|
||||||
|
value = signing.get_cookie_signer(salt=salt).unsign(cookie.value, max_age=15)
|
||||||
|
return ujson.loads(value)
|
||||||
|
|
||||||
|
def test_google_oauth2_start(self):
|
||||||
|
# type: () -> None
|
||||||
|
with mock.patch('zerver.views.auth.get_subdomain', return_value='zulip'):
|
||||||
|
result = self.client_get('/accounts/login/google/')
|
||||||
|
self.assertEquals(result.status_code, 302)
|
||||||
|
parsed_url = urllib.parse.urlparse(result.url)
|
||||||
|
subdomain = urllib.parse.parse_qs(parsed_url.query)['subdomain']
|
||||||
|
self.assertEqual(subdomain, ['zulip'])
|
||||||
|
|
||||||
|
def test_google_oauth2_success(self):
|
||||||
|
# type: () -> None
|
||||||
|
token_response = ResponseMock(200, {'access_token': "unique_token"})
|
||||||
|
account_data = dict(name=dict(formatted="Full Name"),
|
||||||
|
emails=[dict(type="account",
|
||||||
|
value="hamlet@zulip.com")])
|
||||||
|
account_response = ResponseMock(200, account_data)
|
||||||
|
with self.settings(REALMS_HAVE_SUBDOMAINS=True):
|
||||||
|
result = self.google_oauth2_test(token_response, account_response, 'zulip')
|
||||||
|
|
||||||
|
data = self.unsign_subdomain_cookie(result)
|
||||||
|
self.assertEqual(data['email'], 'hamlet@zulip.com')
|
||||||
|
self.assertEqual(data['name'], 'Full Name')
|
||||||
|
self.assertEqual(data['subdomain'], 'zulip')
|
||||||
|
self.assertEquals(result.status_code, 302)
|
||||||
|
parsed_url = urllib.parse.urlparse(result.url)
|
||||||
|
uri = "{}://{}{}".format(parsed_url.scheme, parsed_url.netloc,
|
||||||
|
parsed_url.path)
|
||||||
|
self.assertEquals(uri, 'http://zulip.testserver/accounts/login/subdomain/')
|
||||||
|
|
||||||
|
def test_log_into_subdomain(self):
|
||||||
|
# type: () -> None
|
||||||
|
data = {'name': 'Full Name',
|
||||||
|
'email': 'hamlet@zulip.com',
|
||||||
|
'subdomain': 'zulip'}
|
||||||
|
|
||||||
|
self.client.cookies = SimpleCookie(self.get_signed_subdomain_cookie(data))
|
||||||
|
with mock.patch('zerver.views.auth.get_subdomain', return_value='zulip'):
|
||||||
|
result = self.client_get('/accounts/login/subdomain/')
|
||||||
|
self.assertEquals(result.status_code, 302)
|
||||||
|
user_profile = get_user_profile_by_email('hamlet@zulip.com')
|
||||||
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
||||||
|
|
||||||
|
def test_user_cannot_log_into_nonexisting_realm(self):
|
||||||
|
# type: () -> None
|
||||||
|
token_response = ResponseMock(200, {'access_token': "unique_token"})
|
||||||
|
account_data = dict(name=dict(formatted="Full Name"),
|
||||||
|
emails=[dict(type="account",
|
||||||
|
value="hamlet@zulip.com")])
|
||||||
|
account_response = ResponseMock(200, account_data)
|
||||||
|
result = self.google_oauth2_test(token_response, account_response, 'acme')
|
||||||
|
self.assertEquals(result.status_code, 302)
|
||||||
|
self.assertIn('subdomain=1', result.url)
|
||||||
|
|
||||||
|
def test_user_cannot_log_into_wrong_subdomain(self):
|
||||||
|
# type: () -> None
|
||||||
|
data = {'name': 'Full Name',
|
||||||
|
'email': 'hamlet@zulip.com',
|
||||||
|
'subdomain': 'acme'}
|
||||||
|
|
||||||
|
self.client.cookies = SimpleCookie(self.get_signed_subdomain_cookie(data))
|
||||||
|
with mock.patch('zerver.views.auth.get_subdomain', return_value='zulip'):
|
||||||
|
result = self.client_get('/accounts/login/subdomain/')
|
||||||
|
self.assertEquals(result.status_code, 400)
|
||||||
|
|
||||||
|
def test_log_into_subdomain_when_signature_is_bad(self):
|
||||||
|
# type: () -> None
|
||||||
|
self.client.cookies = SimpleCookie({'subdomain.signature': 'invlaid'})
|
||||||
|
with mock.patch('zerver.views.auth.get_subdomain', return_value='zulip'):
|
||||||
|
result = self.client_get('/accounts/login/subdomain/')
|
||||||
|
self.assertEquals(result.status_code, 400)
|
||||||
|
|
||||||
|
def test_log_into_subdomain_when_state_is_not_passed(self):
|
||||||
|
# type: () -> None
|
||||||
|
with mock.patch('zerver.views.auth.get_subdomain', return_value='zulip'):
|
||||||
|
result = self.client_get('/accounts/login/subdomain/')
|
||||||
|
self.assertEquals(result.status_code, 400)
|
||||||
|
|
||||||
|
class GoogleLoginTest(GoogleOAuthTest):
|
||||||
def test_google_oauth2_success(self):
|
def test_google_oauth2_success(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
token_response = ResponseMock(200, {'access_token': "unique_token"})
|
token_response = ResponseMock(200, {'access_token': "unique_token"})
|
||||||
|
|||||||
Reference in New Issue
Block a user