Skip to content

Commit c169588

Browse files
mark-adamsdbaxa
authored andcommitted
Sem-Ver: feature Add WSGI middleware
Fix a broken test Enhance tests for WSGI middleware Fix extra line at the end of a file Modify WSGI backend to check if request is None instead of falsey Fix some failing tests Fix another test Don't initialize verifier in _process_asap_token if there is no token Pass through the merged settings to backend.get_verifier. Signed-off-by: David Black <dblack@atlassian.com> When creating an instance of JWTAuthVerifier we should not provide a subject_should_match_issuer keyword argument if the settings value is None. Signed-off-by: David Black <dblack@atlassian.com> Add a test for when the django decorator is used to override the settings defined subject_does_need_to_match_issuer value. Signed-off-by: David Black <dblack@atlassian.com> Remove the unused SubjectIssuerMismatchError exception. Signed-off-by: David Black <dblack@atlassian.com> Restore the docstring for requires_asap. Signed-off-by: David Black <dblack@atlassian.com> Do not catch the InvalidTokenError as an exception variable. Signed-off-by: David Black <dblack@atlassian.com>
1 parent b85faf0 commit c169588

16 files changed

Lines changed: 218 additions & 23 deletions

File tree

atlassian_jwt_auth/contrib/django/decorators.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ def validate_asap_wrapper(request, *args, **kwargs):
4444

4545

4646
def requires_asap(issuers=None, subject_should_match_issuer=None, func=None):
47+
"""Decorator for Django endpoints to require ASAP
48+
49+
:param list issuers: *required The 'iss' claims that this endpoint is from.
50+
"""
4751
return with_asap(func=func,
4852
required=True,
4953
issuers=issuers,

atlassian_jwt_auth/contrib/flask_app/decorators.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33

44
def requires_asap(f, issuers=None, subject_should_match_issuer=None):
5+
"""
6+
Wrapper for Flask endpoints to make them require asap authentication to
7+
access.
8+
"""
9+
510
return with_asap(func=f,
611
required=True,
712
issuers=issuers,

atlassian_jwt_auth/frameworks/common/asap.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99
def _process_asap_token(request, backend, settings):
1010
""" Verifies an ASAP token, validates the claims, and returns an error
1111
response"""
12-
verifier = backend.get_verifier()
1312
token = backend.get_asap_token(request)
1413
error_response = None
1514

1615
try:
1716
if token is None:
1817
raise NoTokenProvidedError
19-
18+
verifier = backend.get_verifier(settings=settings)
2019
asap_claims = verifier.verify_jwt(
2120
token,
2221
settings.ASAP_VALID_AUDIENCE,
@@ -26,7 +25,9 @@ def _process_asap_token(request, backend, settings):
2625
_verify_issuers(asap_claims, settings.ASAP_VALID_ISSUERS)
2726
backend.set_asap_claims_for_request(request, asap_claims)
2827
except NoTokenProvidedError:
29-
error_response = backend.get_401_response('Unauthorized')
28+
error_response = backend.get_401_response(
29+
'Unauthorized', request=request
30+
)
3031
except PublicKeyRetrieverException as e:
3132
if e.status_code not in (403, 404):
3233
# Any error other than "not found" is a problem and should
@@ -38,18 +39,18 @@ def _process_asap_token(request, backend, settings):
3839
raise
3940

4041
error_response = backend.get_401_response(
41-
'Unauthorized: Key not found'
42+
'Unauthorized: Key not found', request=request
4243
)
4344
except InvalidIssuerError:
4445
error_response = backend.get_403_response(
45-
'Forbidden: Invalid token issuer'
46+
'Forbidden: Invalid token issuer', request=request
4647
)
4748
except InvalidTokenError:
4849
error_response = backend.get_401_response(
49-
'Unauthorized: Invalid token'
50+
'Unauthorized: Invalid token', request=request
5051
)
5152

52-
if error_response and settings.ASAP_REQUIRED:
53+
if error_response is not None and settings.ASAP_REQUIRED:
5354
return error_response
5455

5556

atlassian_jwt_auth/frameworks/common/backend.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ def get_authorization_header(self, request=None):
4646
pass
4747

4848
@abstractmethod
49-
def get_401_response(self, data=None, headers=None):
49+
def get_401_response(self, data=None, headers=None, request=None):
5050
pass
5151

5252
@abstractmethod
53-
def get_403_response(self, data=None, headers=None):
53+
def get_403_response(self, data=None, headers=None, request=None):
5454
pass
5555

5656
@abstractmethod
@@ -81,17 +81,21 @@ def get_asap_token(self, request):
8181

8282
return auth_values[1]
8383

84-
def get_verifier(self):
84+
def get_verifier(self, settings=None):
8585
"""Returns a verifier for ASAP JWT tokens"""
86-
settings = self.settings
86+
if settings is None:
87+
settings = self.settings
8788

8889
retriever = settings.ASAP_KEY_RETRIEVER_CLASS(
8990
base_url=settings.ASAP_PUBLICKEY_REPOSITORY
9091
)
92+
kwargs = {}
93+
if settings.ASAP_SUBJECT_SHOULD_MATCH_ISSUER is not None:
94+
kwargs = {'subject_should_match_issuer':
95+
settings.ASAP_SUBJECT_SHOULD_MATCH_ISSUER}
9196
return JWTAuthVerifier(
9297
retriever,
93-
# This is handled in utils.validate_claims
94-
subject_should_match_issuer=False,
98+
**kwargs
9599
)
96100

97101
def _process_settings(self, settings):

atlassian_jwt_auth/frameworks/common/decorators.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def with_asap_wrapper(*args, **kwargs):
2929
request, backend, settings
3030
)
3131

32-
if error_response:
32+
if error_response is not None:
3333
return error_response
3434

3535
return func(*args, **kwargs)
@@ -61,18 +61,18 @@ def restrict_asap_wrapper(request, *args, **kwargs):
6161

6262
if required and not asap_claims:
6363
return backend.get_401_response(
64-
'Unauthorized'
64+
'Unauthorized', request=request
6565
)
6666

6767
try:
6868
_verify_issuers(asap_claims, settings.ASAP_VALID_ISSUERS)
6969
except InvalidIssuerError:
7070
error_response = backend.get_403_response(
71-
'Forbidden: Invalid token issuer'
71+
'Forbidden: Invalid token issuer', request=request
7272
)
7373
except InvalidTokenError:
7474
error_response = backend.get_401_response(
75-
'Unauthorized: Invalid token'
75+
'Unauthorized: Invalid token', request=request
7676
)
7777

7878
if error_response and required:

atlassian_jwt_auth/frameworks/common/tests/test_decorators.py

Whitespace-only changes.

atlassian_jwt_auth/frameworks/django/backend.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def get_authorization_header(self, request=None):
1111

1212
return request.META.get('HTTP_AUTHORIZATION', b'')
1313

14-
def get_401_response(self, data=None, headers=None):
14+
def get_401_response(self, data=None, headers=None, request=None):
1515
if headers is None:
1616
headers = {}
1717

@@ -23,7 +23,7 @@ def get_401_response(self, data=None, headers=None):
2323

2424
return response
2525

26-
def get_403_response(self, data=None, headers=None):
26+
def get_403_response(self, data=None, headers=None, request=None):
2727
if headers is None:
2828
headers = {}
2929

atlassian_jwt_auth/frameworks/django/middleware.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def asap_middleware(get_response):
99

1010
def middleware(request):
1111
error_response = _process_asap_token(request, backend, settings)
12-
if error_response:
12+
if error_response is not None:
1313
return error_response
1414

1515
return get_response(request)
@@ -29,5 +29,5 @@ def process_request(self, request):
2929
error_response = _process_asap_token(
3030
request, self.backend, self.settings
3131
)
32-
if error_response:
32+
if error_response is not None:
3333
return error_response

atlassian_jwt_auth/frameworks/django/tests/test_django.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,23 @@ def test_request_subject_does_not_need_to_match_issuer(self):
272272

273273
self.assertContains(response, 'Subject does not need to match issuer.')
274274

275+
def test_request_subject_does_need_to_match_issuer_override_settings(self):
276+
""" tests that the with_asap decorator can override the
277+
ASAP_SUBJECT_SHOULD_MATCH_ISSUER setting.
278+
"""
279+
token = create_token(
280+
issuer='client-app', audience='server-app',
281+
key_id='client-app/key01', private_key=self._private_key_pem,
282+
subject='not-client-app',
283+
)
284+
with override_settings(**dict(
285+
self.test_settings, ASAP_SUBJECT_SHOULD_MATCH_ISSUER=False)):
286+
message = 'Issuer does not match the subject'
287+
with self.assertRaisesRegexp(ValueError, message):
288+
response = self.client.get(
289+
reverse('subject_does_need_to_match_issuer'),
290+
HTTP_AUTHORIZATION=b'Bearer ' + token)
291+
275292
def test_request_subject_does_not_need_to_match_issuer_from_settings(self):
276293
token = create_token(
277294
issuer='client-app', audience='server-app',

atlassian_jwt_auth/frameworks/django/tests/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
url(r'^asap/subject_does_not_need_to_match_issuer$',
1313
views.subject_does_not_need_to_match_issuer_view,
1414
name='subject_does_not_need_to_match_issuer'),
15+
url(r'^asap/subject_does_need_to_match_issuer_view$',
16+
views.subject_does_need_to_match_issuer_view,
17+
name='subject_does_need_to_match_issuer'),
1518

1619
url(r'^asap/subject_does_not_need_to_match_issuer_from_settings$',
1720
views.subject_does_not_need_to_match_issuer_from_settings_view,

0 commit comments

Comments
 (0)