Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 256d380

Browse files
committed
use class attr for id token verifier arguments
1 parent eb2f588 commit 256d380

File tree

2 files changed

+36
-41
lines changed

2 files changed

+36
-41
lines changed

auth0/v3/authentication/token_verifier.py

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,11 @@ def __init__(self, signature_verifier, issuer, audience, leeway=0):
213213
if not signature_verifier or not isinstance(signature_verifier, SignatureVerifier):
214214
raise TypeError("signature_verifier must be an instance of SignatureVerifier.")
215215

216-
self._options = {
217-
'signature_verifier': signature_verifier,
218-
'iss': issuer,
219-
'aud': audience,
220-
'leeway': leeway,
221-
'_clock': None
222-
}
216+
self.iss = issuer
217+
self.aud = audience
218+
self.leeway = leeway
219+
self._sv = signature_verifier
220+
self._clock = None # visible for testing
223221

224222
"""Attempts to verify the given ID token, following the steps defined in the OpenID Connect spec.
225223
@@ -235,51 +233,47 @@ def __init__(self, signature_verifier, issuer, audience, leeway=0):
235233

236234
def verify(self, token, nonce=None, max_age=None):
237235
# Verify token presence
238-
if not token or type(token) != str:
236+
if not token or not isinstance(token, str):
239237
raise TokenValidationError("ID token is required but missing.")
240238

241-
opt = self._options.copy()
242-
opt['nonce'] = nonce
243-
opt['max_age'] = max_age
244-
245239
# Verify algorithm and signature
246-
payload = opt['signature_verifier'].verify_signature(token)
240+
payload = self._sv.verify_signature(token)
247241

248242
# Verify claims
249243
# Issuer
250244

251-
if 'iss' not in payload or type(payload['iss']) != str:
245+
if 'iss' not in payload or not isinstance(payload['iss'], str):
252246
raise TokenValidationError('Issuer (iss) claim must be a string present in the ID token')
253-
if payload['iss'] != opt['iss']:
247+
if payload['iss'] != self.iss:
254248
raise TokenValidationError(
255249
'Issuer (iss) claim mismatch in the ID token; expected "{}", '
256-
'found "{}"'.format(opt['iss'], payload['iss']))
250+
'found "{}"'.format(self.iss, payload['iss']))
257251

258252
# Subject
259-
if 'sub' not in payload or type(payload['sub']) != str:
253+
if 'sub' not in payload or not isinstance(payload['sub'], str):
260254
raise TokenValidationError('Subject (sub) claim must be a string present in the ID token')
261255

262256
# Audience
263-
if 'aud' not in payload or not (type(payload['aud']) == str or type(payload['aud']) is list):
257+
if 'aud' not in payload or not (isinstance(payload['aud'], str) or isinstance(payload['aud'], list)):
264258
raise TokenValidationError(
265259
'Audience (aud) claim must be a string or array of strings present in the ID token')
266260

267-
if type(payload['aud']) is list and not opt['aud'] in payload['aud']:
261+
if isinstance(payload['aud'], list) and not self.aud in payload['aud']:
268262
payload_audiences = ", ".join(payload['aud'])
269263
raise TokenValidationError(
270264
'Audience (aud) claim mismatch in the ID token; expected "{}" but was '
271-
'not one of "{}"'.format(opt['aud'], payload_audiences))
272-
elif type(payload['aud']) == str and payload['aud'] != opt['aud']:
265+
'not one of "{}"'.format(self.aud, payload_audiences))
266+
elif isinstance(payload['aud'], str) and payload['aud'] != self.aud:
273267
raise TokenValidationError(
274268
'Audience (aud) claim mismatch in the ID token; expected "{}" '
275-
'but found "{}"'.format(opt['aud'], payload['aud']))
269+
'but found "{}"'.format(self.aud, payload['aud']))
276270

277271
# --Time validation (epoch)--
278-
now = opt.get('_clock', time.time())
279-
leeway = opt['leeway']
272+
now = self._clock or time.time()
273+
leeway = self.leeway
280274

281275
# Expires at
282-
if 'exp' not in payload or type(payload['exp']) != int:
276+
if 'exp' not in payload or not isinstance(payload['exp'], int):
283277
raise TokenValidationError('Expiration Time (exp) claim must be a number present in the ID token')
284278

285279
exp_time = payload['exp'] + leeway
@@ -289,7 +283,7 @@ def verify(self, token, nonce=None, max_age=None):
289283
'after expiration time ({})'.format(now, exp_time))
290284

291285
# Issued at
292-
if 'iat' not in payload or type(payload['iat']) != int:
286+
if 'iat' not in payload or not isinstance(payload['iat'], int):
293287
raise TokenValidationError('Issued At (iat) claim must be a number present in the ID token')
294288

295289
iat_time = payload['iat'] - leeway
@@ -299,33 +293,33 @@ def verify(self, token, nonce=None, max_age=None):
299293
'before issued at time ({})'.format(now, iat_time))
300294

301295
# Nonce
302-
if 'nonce' in opt and opt['nonce']:
303-
if 'nonce' not in payload or type(payload['nonce']) != str:
296+
if nonce:
297+
if 'nonce' not in payload or not isinstance(payload['nonce'], str):
304298
raise TokenValidationError('Nonce (nonce) claim must be a string present in the ID token')
305-
if payload['nonce'] != opt['nonce']:
299+
if payload['nonce'] != nonce:
306300
raise TokenValidationError(
307301
'Nonce (nonce) claim mismatch in the ID token; expected "{}", '
308-
'found "{}"'.format(opt['nonce'], payload['nonce']))
302+
'found "{}"'.format(nonce, payload['nonce']))
309303

310304
# Authorized party
311-
if type(payload['aud']) is list and len(payload['aud']) > 1:
312-
if 'azp' not in payload or type(payload['azp']) != str:
305+
if isinstance(payload['aud'], list) and len(payload['aud']) > 1:
306+
if 'azp' not in payload or not isinstance(payload['azp'], str):
313307
raise TokenValidationError(
314308
'Authorized Party (azp) claim must be a string present in the ID token when '
315309
'Audience (aud) claim has multiple values')
316-
if payload['azp'] != opt['aud']:
310+
if payload['azp'] != self.aud:
317311
raise TokenValidationError(
318312
'Authorized Party (azp) claim mismatch in the ID token; expected "{}", '
319-
'found "{}"'.format(opt['aud'], payload['azp']))
313+
'found "{}"'.format(self.aud, payload['azp']))
320314

321315
# Authentication time
322-
if 'max_age' in opt and opt['max_age']:
323-
if 'auth_time' not in payload or type(payload['auth_time']) != int:
316+
if max_age:
317+
if 'auth_time' not in payload or not isinstance(payload['auth_time'], int):
324318
raise TokenValidationError(
325319
'Authentication Time (auth_time) claim must be a number present in the ID token '
326320
'when Max Age (max_age) is specified')
327321

328-
auth_valid_until = payload['auth_time'] + opt['max_age'] + leeway
322+
auth_valid_until = payload['auth_time'] + max_age + leeway
329323
if now > auth_valid_until:
330324
raise TokenValidationError(
331325
'Authentication Time (auth_time) claim in the ID token indicates that too much '

auth0/v3/test/authentication/test_token_verifier.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,15 @@ def assert_fails_with_error(self, token, error_message, signature_verifier=None,
230230
audience=audience,
231231
leeway=DEFAULT_LEEWAY
232232
)
233-
tv._options['_clock'] = clock
233+
tv._clock = clock
234234
with self.assertRaises(TokenValidationError) as err:
235235
tv.verify(token, nonce, max_age)
236236
self.assertEqual(str(err.exception), error_message)
237237

238238
def test_fails_at_creation_with_invalid_signature_verifier(self):
239239
sv = "string is not an instance of signature verifier"
240240
with self.assertRaises(TypeError) as err:
241+
# noinspection PyTypeChecker
241242
TokenVerifier(signature_verifier=sv, issuer="valid issuer", audience="valid audience")
242243
self.assertEqual(str(err.exception), "signature_verifier must be an instance of SignatureVerifier.")
243244

@@ -264,7 +265,7 @@ def test_HS256_token_signature_passes(self):
264265
issuer=expectations['issuer'],
265266
audience=expectations['audience']
266267
)
267-
tv._options['_clock'] = MOCKED_CLOCK
268+
tv._clock = MOCKED_CLOCK
268269
tv.verify(token)
269270

270271
def test_RS256_token_signature_passes(self):
@@ -276,7 +277,7 @@ def test_RS256_token_signature_passes(self):
276277
issuer=expectations['issuer'],
277278
audience=expectations['audience']
278279
)
279-
tv._options['_clock'] = MOCKED_CLOCK
280+
tv._clock = MOCKED_CLOCK
280281
tv.verify(token)
281282

282283
def test_HS256_token_signature_fails(self):
@@ -345,7 +346,7 @@ def test_passes_when_nonce_missing_but_not_required(self):
345346
issuer=expectations['issuer'],
346347
audience=expectations['audience']
347348
)
348-
tv._options['_clock'] = MOCKED_CLOCK
349+
tv._clock = MOCKED_CLOCK
349350
tv.verify(token)
350351

351352
def test_fails_with_nonce_missing(self):

0 commit comments

Comments
 (0)