Skip to content

Commit

Permalink
Allow list of valid audiences to be passed in to PyJWT.decode() (#306)
Browse files Browse the repository at this point in the history
Resolves #205,
  • Loading branch information
r-springer authored and mark-adams committed Nov 27, 2017
1 parent c1253ec commit 7f7d524
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 11 deletions.
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ Patches and Suggestions
- Wouter Bolsterlee <uws@xs4all.nl>

- Michael Davis <mike.philip.davis@gmail.com> <mike.davis@workiva.com>

- Vinod Gupta <codervinod@gmail.com>
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).

- Dropped support for python 2.6 and 3.3 [#297][297]

- Audience parameter now supports iterables [#205][205]

### Fixed

### Added

[v1.5.3][1.5.3]
Expand Down
1 change: 0 additions & 1 deletion jwt/api_jws.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import binascii
import json
import warnings

from collections import Mapping

from .algorithms import (
Expand Down
13 changes: 8 additions & 5 deletions jwt/api_jwt.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import json
import warnings

from calendar import timegm
from collections import Mapping
from collections import Iterable, Mapping
from datetime import datetime, timedelta

from .api_jws import PyJWS
Expand Down Expand Up @@ -103,8 +102,8 @@ def _validate_claims(self, payload, options, audience=None, issuer=None,
if isinstance(leeway, timedelta):
leeway = leeway.total_seconds()

if not isinstance(audience, (string_types, type(None))):
raise TypeError('audience must be a string or None')
if not isinstance(audience, (string_types, type(None), Iterable)):
raise TypeError('audience must be a string, iterable, or None')

self._validate_required_claims(payload, options)

Expand Down Expand Up @@ -177,7 +176,11 @@ def _validate_aud(self, payload, audience):
raise InvalidAudienceError('Invalid claim format in token')
if any(not isinstance(c, string_types) for c in audience_claims):
raise InvalidAudienceError('Invalid claim format in token')
if audience not in audience_claims:

if isinstance(audience, string_types):
audience = [audience]

if not any(aud in audience_claims for aud in audience):
raise InvalidAudienceError('Invalid audience')

def _validate_iss(self, payload, issuer):
Expand Down
1 change: 0 additions & 1 deletion jwt/contrib/algorithms/pycrypto.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Crypto.Hash.SHA256
import Crypto.Hash.SHA384
import Crypto.Hash.SHA512

from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

Expand Down
1 change: 0 additions & 1 deletion tests/test_api_jws.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

import json

from decimal import Decimal

from jwt.algorithms import Algorithm
Expand Down
20 changes: 18 additions & 2 deletions tests/test_api_jwt.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

import json
import time

from calendar import timegm
from datetime import datetime, timedelta
from decimal import Decimal
Expand Down Expand Up @@ -92,7 +91,7 @@ def test_decode_with_invalid_audience_param_throws_exception(self, jwt):
jwt.decode(example_jwt, secret, audience=1)

exception = context.value
assert str(exception) == 'audience must be a string or None'
assert str(exception) == 'audience must be a string, iterable, or None'

def test_decode_with_nonlist_aud_claim_throws_exception(self, jwt):
secret = 'secret'
Expand Down Expand Up @@ -281,6 +280,23 @@ def test_check_audience_when_valid(self, jwt):
token = jwt.encode(payload, 'secret')
jwt.decode(token, 'secret', audience='urn:me')

def test_check_audience_list_when_valid(self, jwt):
payload = {
'some': 'payload',
'aud': 'urn:me'
}
token = jwt.encode(payload, 'secret')
jwt.decode(token, 'secret', audience=['urn:you', 'urn:me'])

def test_raise_exception_invalid_audience_list(self, jwt):
payload = {
'some': 'payload',
'aud': 'urn:me'
}
token = jwt.encode(payload, 'secret')
with pytest.raises(InvalidAudienceError):
jwt.decode(token, 'secret', audience=['urn:you', 'urn:him'])

def test_check_audience_in_array_when_valid(self, jwt):
payload = {
'some': 'payload',
Expand Down
1 change: 0 additions & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import os
import struct

from calendar import timegm
from datetime import datetime

Expand Down

0 comments on commit 7f7d524

Please sign in to comment.