Skip to content

Commit

Permalink
'*' allowed domain now allows no Referer/Origin to be set
Browse files Browse the repository at this point in the history
  • Loading branch information
mattrobenolt committed Feb 4, 2014
1 parent 68867da commit 9e5ecfe
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 12 deletions.
18 changes: 17 additions & 1 deletion src/sentry/testutils/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ def _postWithHeader(self, data, key=None, secret=None):
)
return resp

def _getWithoutReferer(self, data, key=None):
if key is None:
key = self.projectkey.public_key

message = self._makeMessage(data)
qs = {
'sentry_version': '4',
'sentry_client': 'raven-js/lol',
'sentry_key': key,
'sentry_data': message,
}
resp = self.client.get(
'%s?%s' % (reverse('sentry-api-store', args=(self.project.pk,)), urllib.urlencode(qs))
)
return resp

def _getWithReferer(self, data, key=None):
if key is None:
key = self.projectkey.public_key
Expand All @@ -129,7 +145,7 @@ def _getWithReferer(self, data, key=None):
}
resp = self.client.get(
'%s?%s' % (reverse('sentry-api-store', args=(self.project.pk,)), urllib.urlencode(qs)),
HTTP_REFERER='http://lol.com/'
HTTP_REFERER='http://getsentry.com/'
)
return resp

Expand Down
6 changes: 3 additions & 3 deletions src/sentry/utils/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,16 @@ def is_valid_origin(origin, project=None):
- *.domain.com: matches domain.com and all subdomains, on any port
- domain.com: matches domain.com on any port
"""
# we always run a case insensitive check
origin = origin.lower()

allowed = get_origins(project)
if '*' in allowed:
return True

if not origin:
return False

# we always run a case insensitive check
origin = origin.lower()

# Fast check
if origin in allowed:
return True
Expand Down
19 changes: 11 additions & 8 deletions src/sentry/web/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,15 @@ def _dispatch(self, request, project_id=None, *args, **kwargs):
Raven.tags_context({'project': project.id})

origin = self.get_request_origin(request)
if origin is not None:
if not project:
return HttpResponse('Your client must be upgraded for CORS support.')
elif not is_valid_origin(origin, project):
return HttpResponse('Invalid origin: %r' % origin, content_type='text/plain', status=400)
if origin is not None and not project:
return HttpResponse('Your client must be upgraded for CORS support.', content_type='text/plain', status=400)

# XXX: It seems that the OPTIONS call does not always include custom headers
if request.method == 'OPTIONS':
response = self.options(request, project)
if is_valid_origin(origin, project):
response = self.options(request, project)
else:
return HttpResponse('Invalid origin: %r' % origin, content_type='text/plain', status=400)
else:
try:
auth_vars = self._parse_header(request, project)
Expand Down Expand Up @@ -213,8 +213,11 @@ def _dispatch(self, request, project_id=None, *args, **kwargs):
if auth.version >= 3:
if request.method == 'GET':
# GET only requires an Origin/Referer check
if origin is None:
return HttpResponse('Missing required Origin or Referer header', status=400)
if not is_valid_origin(origin, project):
if origin is None:
return HttpResponse('Missing required Origin or Referer header', content_type='text/plain', status=400)
else:
return HttpResponse('Invalid origin: %r' % origin, content_type='text/plain', status=400)
else:
# Version 3 enforces secret key for server side requests
if not auth.secret_key:
Expand Down
14 changes: 14 additions & 0 deletions tests/integration/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from django.conf import settings as django_settings
from django.core.urlresolvers import reverse
from django.test.utils import override_settings
from django.utils import timezone

from raven import Client
Expand Down Expand Up @@ -161,6 +162,7 @@ def test_ungzipped_data(self):
self.assertEquals(instance.site, 'not_a_real_site')
self.assertEquals(instance.level, 40)

@override_settings(SENTRY_ALLOW_ORIGIN='getsentry.com')
def test_correct_data_with_get(self):
kwargs = {'message': 'hello', 'server_name': 'not_dcramer.local', 'level': 40, 'site': 'not_a_real_site'}
resp = self._getWithReferer(kwargs)
Expand All @@ -171,6 +173,18 @@ def test_correct_data_with_get(self):
self.assertEquals(instance.level, 40)
self.assertEquals(instance.site, 'not_a_real_site')

@override_settings(SENTRY_ALLOW_ORIGIN='getsentry.com')
def test_get_without_referer(self):
kwargs = {'message': 'hello', 'server_name': 'not_dcramer.local', 'level': 40, 'site': 'not_a_real_site'}
resp = self._getWithoutReferer(kwargs)
self.assertEquals(resp.status_code, 400, resp.content)

@override_settings(SENTRY_ALLOW_ORIGIN='*')
def test_get_without_referer_allowed(self):
kwargs = {'message': 'hello', 'server_name': 'not_dcramer.local', 'level': 40, 'site': 'not_a_real_site'}
resp = self._getWithoutReferer(kwargs)
self.assertEquals(resp.status_code, 200, resp.content)

# def test_byte_sequence(self):
# """
# invalid byte sequence for encoding "UTF8": 0xedb7af
Expand Down

0 comments on commit 9e5ecfe

Please sign in to comment.