Skip to content

Commit fa4e9e8

Browse files
committed
Switched to a more secure default for auth
- Added settings overrides to allow tests to pass
1 parent ba78efd commit fa4e9e8

3 files changed

Lines changed: 31 additions & 10 deletions

File tree

codespeed/auth.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@
55
from django.conf import settings
66
from base64 import b64decode
77

8+
__ALL__ = ['basic_auth_required']
9+
810

911
def basic_auth_required(realm='default'):
1012
def _helper(func):
1113
@wraps(func)
1214
def _decorator(request, *args, **kwargs):
1315
allowed = False
16+
logging.info('request is secure? {}'.format(request.is_secure()))
1417
if settings.ALLOW_ANONYMOUS_POST:
1518
allowed = True
1619
elif 'HTTP_AUTHORIZATION' in request.META:
20+
if settings.REQUIRE_SECURE_AUTH and not request.is_secure():
21+
return insecure_connection_response()
1722
http_auth = request.META['HTTP_AUTHORIZATION']
1823
authmeth, auth = http_auth.split(' ', 1)
1924
if authmeth.lower() == 'basic':
20-
authb = b64decode(auth.strip())
21-
auth = authb.decode()
22-
username, password = auth.split(':', 1)
25+
username, password = decode_basic_auth(auth)
2326
user = authenticate(username=username, password=password)
2427
if user is None:
2528
logging.info(
@@ -29,11 +32,25 @@ def _decorator(request, *args, **kwargs):
2932
return HttpResponseForbidden()
3033
if allowed:
3134
return func(request, *args, **kwargs)
32-
res = HttpResponse()
33-
res.status_code = 401
34-
res.reason_phrase = 'Unauthorized'
35-
res['WWW-Authenticate'] = 'Basic realm="{}"'.format(realm)
36-
return res
35+
36+
if settings.REQUIRE_SECURE_AUTH and not request.is_secure():
37+
return insecure_connection_response()
38+
else:
39+
res = HttpResponse()
40+
res.status_code = 401
41+
res.reason_phrase = 'Unauthorized'
42+
res['WWW-Authenticate'] = 'Basic realm="{}"'.format(realm)
43+
return res
3744
return _decorator
3845

3946
return _helper
47+
48+
49+
def insecure_connection_response():
50+
return HttpResponseForbidden('Secure connection required')
51+
52+
53+
def decode_basic_auth(auth):
54+
authb = b64decode(auth.strip())
55+
auth = authb.decode()
56+
return auth.split(':', 1)

codespeed/settings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,5 @@
7070
USE_MEDIAN_BANDS = True # True to enable median bands on Timeline view
7171

7272

73-
ALLOW_ANONYMOUS_POST = True # Whether anonymous users be allowed to post results
73+
ALLOW_ANONYMOUS_POST = False # Whether anonymous users can post results
74+
REQUIRE_SECURE_AUTH = True # Whether auth needs to be over a secure channel

codespeed/tests/test_views.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import copy
44
import json
55

6-
from django.test import TestCase
6+
from django.test import TestCase, override_settings
77
from django.core.urlresolvers import reverse
88

99
from codespeed.models import (Project, Benchmark, Revision, Branch, Executable,
1010
Environment, Result, Report)
1111

1212

13+
@override_settings(ALLOW_ANONYMOUS_POST=True)
1314
class TestAddResult(TestCase):
1415

1516
def setUp(self):
@@ -162,6 +163,7 @@ def test_add_result_with_no_project(self):
162163
response.content.decode(), "Result data saved successfully")
163164

164165

166+
@override_settings(ALLOW_ANONYMOUS_POST=True)
165167
class TestAddJSONResults(TestCase):
166168

167169
def setUp(self):
@@ -361,6 +363,7 @@ def test_gettimelinedata(self):
361363
[u'2011/04/13 17:04:22 ', 2000.0, 1.11111, u'2', u'', u'default'])
362364

363365

366+
@override_settings(ALLOW_ANONYMOUS_POST=True)
364367
class TestReports(TestCase):
365368

366369
def setUp(self):

0 commit comments

Comments
 (0)