Родитель
f23466819a
Коммит
2daad31407
|
@ -38,7 +38,7 @@ django-aesfield==0.1.2 --hash=sha256:b77932c67dd42f01a119133de1fa88effb2c4d97ab9
|
|||
--hash=sha256:ce07311572aa05f3eaabe1207fb684c2e01b1b4c792cacae1a804c102e8945ae
|
||||
django-cache-nuggets==0.1.1 --hash=sha256:5215ab7ae1d7446a649b27384317afe23e77bf459893d99096ae662538bb547d \
|
||||
--hash=sha256:5376279b9c46288e1c4bae197e84a16f9c35ef21ce93e3ceb74ae9b51acbbb25
|
||||
django-cors-headers==1.1.0 --hash=sha256:fcd96e2be47c8eef34c650e007a6d546e19e7ee61041b89edbbbbe7619aa3987
|
||||
django-cors-headers-multi==1.2.0 --hash=sha256:c40f17823aa59df3c064234cdc890c56667b5db1ea6aac0172c949dc5c42ed53
|
||||
django-cronjobs==0.2.3 --hash=sha256:177295b1442400c92cdb67e8e18f9ff5946fb442f85813b9d0837823722ea08d \
|
||||
--hash=sha256:41fedd899af96b7057bafcad68ff42aefbb4dfe2b0e8a9de34cb32ac8892aff7
|
||||
django_csp==2.0.3 --hash=sha256:149b219d801314cac1dbce9259f485636eeafee48f7d0ca9def4b12986428347 \
|
||||
|
|
|
@ -256,6 +256,13 @@ FXA_CONFIG = {
|
|||
},
|
||||
}
|
||||
|
||||
INTERNAL_DOMAINS = [
|
||||
'addons-admin.dev.mozaws.net',
|
||||
'localhost:3000',
|
||||
]
|
||||
for regex, overrides in CORS_ENDPOINTS:
|
||||
overrides['CORS_ORIGIN_WHITELIST'] = INTERNAL_DOMAINS
|
||||
|
||||
READ_ONLY = env.bool('READ_ONLY', default=False)
|
||||
|
||||
RAVEN_DSN = (
|
||||
|
|
|
@ -221,6 +221,10 @@ FXA_CONFIG = {
|
|||
},
|
||||
}
|
||||
|
||||
INTERNAL_DOMAINS = ['addons-admin.prod.mozaws.net']
|
||||
for regex, overrides in CORS_ENDPOINTS:
|
||||
overrides['CORS_ORIGIN_WHITELIST'] = INTERNAL_DOMAINS
|
||||
|
||||
VALIDATOR_TIMEOUT = 360
|
||||
|
||||
ES_DEFAULT_NUM_SHARDS = 10
|
||||
|
|
|
@ -250,6 +250,10 @@ FXA_CONFIG = {
|
|||
},
|
||||
}
|
||||
|
||||
INTERNAL_DOMAINS = ['addons-admin.stage.mozaws.net']
|
||||
for regex, overrides in CORS_ENDPOINTS:
|
||||
overrides['CORS_ORIGIN_WHITELIST'] = INTERNAL_DOMAINS
|
||||
|
||||
READ_ONLY = env.bool('READ_ONLY', default=False)
|
||||
|
||||
RAVEN_DSN = (
|
||||
|
|
|
@ -3,10 +3,12 @@ import base64
|
|||
import json
|
||||
import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test.utils import override_settings
|
||||
from django.test import override_settings
|
||||
|
||||
import mock
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework_jwt.serializers import VerifyJSONWebTokenSerializer
|
||||
|
||||
from olympia.accounts import verify, views
|
||||
|
@ -196,6 +198,7 @@ class TestLoginStartView(TestCase):
|
|||
scheme=url.scheme, netloc=url.netloc, path=url.path)
|
||||
assert redirect == 'https://accounts.firefox.com/v1/authorization'
|
||||
assert urlparse.parse_qs(url.query) == {
|
||||
'action': ['signin'],
|
||||
'client_id': ['999abc111'],
|
||||
'redirect_url': ['https://addons-frontend/fxa-authenticate'],
|
||||
'scope': ['profile'],
|
||||
|
@ -236,12 +239,31 @@ class TestLoginStartView(TestCase):
|
|||
assert ':' not in query['state'][0]
|
||||
|
||||
|
||||
@override_settings(FXA_CONFIG={'internal': FXA_CONFIG})
|
||||
def has_cors_headers(response, origin='https://addons-frontend'):
|
||||
return (
|
||||
response['Access-Control-Allow-Origin'] == origin and
|
||||
response['Access-Control-Allow-Credentials'] == 'true')
|
||||
|
||||
|
||||
def update_domains(overrides):
|
||||
overrides = overrides.copy()
|
||||
overrides['CORS_ORIGIN_WHITELIST'] = ['addons-frontend', 'localhost:3000']
|
||||
return overrides
|
||||
|
||||
endpoint_overrides = [
|
||||
(regex, update_domains(overrides))
|
||||
for regex, overrides in settings.CORS_ENDPOINT_OVERRIDES]
|
||||
|
||||
|
||||
@override_settings(
|
||||
FXA_CONFIG={'internal': FXA_CONFIG},
|
||||
CORS_ENDPOINT_OVERRIDES=endpoint_overrides)
|
||||
class TestLoginView(BaseAuthenticationView):
|
||||
view_name = 'internal-login'
|
||||
|
||||
def setUp(self):
|
||||
super(TestLoginView, self).setUp()
|
||||
self.client.defaults['HTTP_ORIGIN'] = 'https://addons-frontend'
|
||||
self.state = 'stateaosidoiajsdaagdsasi'
|
||||
self.initialize_session({'fxa_state': self.state})
|
||||
self.code = 'codeaosidjoiajsdioasjdoa'
|
||||
|
@ -253,17 +275,22 @@ class TestLoginView(BaseAuthenticationView):
|
|||
kwargs.setdefault('code', self.code)
|
||||
return self.client.post(self.url, kwargs)
|
||||
|
||||
def options(self, url, origin):
|
||||
return APIClient(HTTP_ORIGIN=origin).options(url)
|
||||
|
||||
def test_no_code_provided(self):
|
||||
response = self.post(code='')
|
||||
assert response.status_code == 422
|
||||
assert response.data['error'] == views.ERROR_NO_CODE
|
||||
assert not self.update_user.called
|
||||
assert has_cors_headers(response)
|
||||
|
||||
def test_wrong_state(self):
|
||||
response = self.post(state='a-different-state')
|
||||
assert response.status_code == 400
|
||||
assert response.data['error'] == views.ERROR_STATE_MISMATCH
|
||||
assert not self.update_user.called
|
||||
assert has_cors_headers(response)
|
||||
|
||||
def test_no_fxa_profile(self):
|
||||
self.fxa_identify.side_effect = verify.IdentificationError
|
||||
|
@ -272,6 +299,7 @@ class TestLoginView(BaseAuthenticationView):
|
|||
assert response.data['error'] == views.ERROR_NO_PROFILE
|
||||
self.fxa_identify.assert_called_with(self.code, config=FXA_CONFIG)
|
||||
assert not self.update_user.called
|
||||
assert has_cors_headers(response)
|
||||
|
||||
def test_no_amo_account_cant_login(self):
|
||||
self.fxa_identify.return_value = {'email': 'me@yeahoo.com', 'uid': '5'}
|
||||
|
@ -280,6 +308,7 @@ class TestLoginView(BaseAuthenticationView):
|
|||
assert response.data['error'] == views.ERROR_NO_USER
|
||||
self.fxa_identify.assert_called_with(self.code, config=FXA_CONFIG)
|
||||
assert not self.update_user.called
|
||||
assert has_cors_headers(response)
|
||||
|
||||
def test_login_success(self):
|
||||
user = UserProfile.objects.create(
|
||||
|
@ -293,6 +322,7 @@ class TestLoginView(BaseAuthenticationView):
|
|||
verify = VerifyJSONWebTokenSerializer().validate(response.data)
|
||||
assert verify['user'] == user
|
||||
self.update_user.assert_called_with(user, identity)
|
||||
assert has_cors_headers(response)
|
||||
|
||||
def test_account_exists_migrated_multiple(self):
|
||||
"""Test that login fails if the user is logged in but the fxa_id is
|
||||
|
@ -303,5 +333,24 @@ class TestLoginView(BaseAuthenticationView):
|
|||
self.fxa_identify.return_value = {'email': 'real@yeahoo.com',
|
||||
'uid': '9005'}
|
||||
with self.assertRaises(UserProfile.MultipleObjectsReturned):
|
||||
self.post()
|
||||
response = self.post()
|
||||
assert has_cors_headers(response)
|
||||
assert not self.update_user.called
|
||||
|
||||
def test_cors_addons_frontend(self):
|
||||
response = self.options(self.url, origin='https://addons-frontend')
|
||||
assert has_cors_headers(response, origin='https://addons-frontend')
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_cors_localhost(self):
|
||||
response = self.options(self.url, origin='http://localhost:3000')
|
||||
assert has_cors_headers(response, origin='http://localhost:3000')
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_cors_other(self):
|
||||
response = self.options(self.url, origin='https://attacker.com')
|
||||
assert 'Access-Control-Allow-Origin' not in response
|
||||
assert 'Access-Control-Allow-Methods' not in response
|
||||
assert 'Access-Control-Allow-Headers' not in response
|
||||
assert 'Access-Control-Allow-Credentials' not in response
|
||||
assert response.status_code == 200
|
||||
|
|
|
@ -47,6 +47,7 @@ class LoginStart(APIView):
|
|||
if next_path and is_safe_url(next_path):
|
||||
state += ':' + urlsafe_b64encode(next_path).rstrip('=')
|
||||
query = {
|
||||
'action': 'signin',
|
||||
'client_id': config['client_id'],
|
||||
'redirect_url': config['redirect_url'],
|
||||
'scope': config['scope'],
|
||||
|
@ -69,3 +70,6 @@ class LoginView(APIView):
|
|||
add_api_token_to_response(response, user, set_cookie=False)
|
||||
log.info('Logging in user {} from FxA'.format(user))
|
||||
return response
|
||||
|
||||
def options(self, request):
|
||||
return Response()
|
||||
|
|
|
@ -74,6 +74,18 @@ NOBODY_EMAIL = 'nobody@mozilla.org'
|
|||
# django-cors-headers.
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
CORS_URLS_REGEX = r'^/api/v3/.*$'
|
||||
INTERNAL_DOMAINS = ['localhost:3000']
|
||||
CORS_ENDPOINT_OVERRIDES = [
|
||||
(r'^/api/v3/internal/accounts/login/?$', {
|
||||
'CORS_ORIGIN_ALLOW_ALL': False,
|
||||
'CORS_ORIGIN_WHITELIST': INTERNAL_DOMAINS,
|
||||
'CORS_ALLOW_CREDENTIALS': True,
|
||||
}),
|
||||
(r'^/api/v3/internal/.*$', {
|
||||
'CORS_ORIGIN_ALLOW_ALL': False,
|
||||
'CORS_ORIGIN_WHITELIST': INTERNAL_DOMAINS,
|
||||
}),
|
||||
]
|
||||
|
||||
DATABASE_URL = os.environ.get('DATABASE_URL',
|
||||
'mysql://root:@localhost/olympia')
|
||||
|
|
Загрузка…
Ссылка в новой задаче