Skip to content

Commit 2c3253f

Browse files
committed
Fix JWT signature verification
1 parent a7cb8ec commit 2c3253f

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

mozilla_django_oidc/auth.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import base64
12
import jwt
23
import requests
4+
35
try:
46
from urllib import urlencode
57
except ImportError:
@@ -26,9 +28,16 @@ def __init__(self, *args, **kwargs):
2628
def verify_token(self, token, **kwargs):
2729
"""Validate the token signature."""
2830

29-
return jwt.decode(token,
30-
self.OIDC_OP_CLIENT_SECRET,
31-
verify=import_from_settings('OIDC_VERIFY_JWT', True))
31+
# Get JWT audience without signature verification
32+
audience = jwt.decode(token, verify=False)['aud']
33+
34+
secret = self.OIDC_OP_CLIENT_SECRET
35+
if import_from_settings('OIDC_RP_CLIENT_SECRET_ENCODED', False):
36+
secret = base64.urlsafe_b64decode(self.OIDC_OP_CLIENT_SECRET)
37+
38+
return jwt.decode(token, secret,
39+
verify=import_from_settings('OIDC_VERIFY_JWT', True),
40+
audience=audience)
3241

3342
def authenticate(self, code=None, state=None):
3443
"""Authenticates a user based on the OIDC code flow."""

tests/test_auth.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from mock import Mock, patch
1+
from mock import Mock, call, patch
22

33
from django.contrib.auth import get_user_model
44
from django.core.urlresolvers import reverse
@@ -138,6 +138,9 @@ def test_authenticate_no_code_no_state(self):
138138
def test_jwt_decode_params(self, request_mock, jwt_mock):
139139
"""Test jwt verification signature."""
140140

141+
jwt_mock.decode.return_value = {
142+
'aud': 'audience'
143+
}
141144
get_json_mock = Mock()
142145
get_json_mock.json.return_value = {
143146
'username': 'username',
@@ -151,14 +154,21 @@ def test_jwt_decode_params(self, request_mock, jwt_mock):
151154
}
152155
request_mock.post.return_value = post_json_mock
153156
self.backend.authenticate(code='foo', state='bar')
154-
jwt_mock.decode.assert_called_once_with('token', 'example_secret', verify=True)
157+
calls = [
158+
call('token', verify=False),
159+
call('token', 'example_secret', verify=True, audience='audience')
160+
]
161+
jwt_mock.decode.assert_has_calls(calls)
155162

156163
@override_settings(OIDC_VERIFY_JWT=False)
157164
@patch('mozilla_django_oidc.auth.jwt')
158165
@patch('mozilla_django_oidc.auth.requests')
159166
def test_jwt_decode_params_verify_false(self, request_mock, jwt_mock):
160167
"""Test jwt verification signature with verify False"""
161168

169+
jwt_mock.decode.return_value = {
170+
'aud': 'audience'
171+
}
162172
get_json_mock = Mock()
163173
get_json_mock.json.return_value = {
164174
'username': 'username',
@@ -171,6 +181,10 @@ def test_jwt_decode_params_verify_false(self, request_mock, jwt_mock):
171181
'access_token': 'access_token'
172182
}
173183
request_mock.post.return_value = post_json_mock
184+
calls = [
185+
call('token', verify=False),
186+
call('token', 'example_secret', verify=False, audience='audience')
187+
]
174188

175189
self.backend.authenticate(code='foo', state='bar')
176-
jwt_mock.decode.assert_called_once_with('token', 'example_secret', verify=False)
190+
jwt_mock.decode.assert_has_calls(calls)

0 commit comments

Comments
 (0)