@@ -213,13 +213,11 @@ def __init__(self, signature_verifier, issuer, audience, leeway=0):
213
213
if not signature_verifier or not isinstance (signature_verifier , SignatureVerifier ):
214
214
raise TypeError ("signature_verifier must be an instance of SignatureVerifier." )
215
215
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
223
221
224
222
"""Attempts to verify the given ID token, following the steps defined in the OpenID Connect spec.
225
223
@@ -235,51 +233,47 @@ def __init__(self, signature_verifier, issuer, audience, leeway=0):
235
233
236
234
def verify (self , token , nonce = None , max_age = None ):
237
235
# Verify token presence
238
- if not token or type (token ) != str :
236
+ if not token or not isinstance (token , str ) :
239
237
raise TokenValidationError ("ID token is required but missing." )
240
238
241
- opt = self ._options .copy ()
242
- opt ['nonce' ] = nonce
243
- opt ['max_age' ] = max_age
244
-
245
239
# Verify algorithm and signature
246
- payload = opt [ 'signature_verifier' ] .verify_signature (token )
240
+ payload = self . _sv .verify_signature (token )
247
241
248
242
# Verify claims
249
243
# Issuer
250
244
251
- if 'iss' not in payload or type (payload ['iss' ]) != str :
245
+ if 'iss' not in payload or not isinstance (payload ['iss' ], str ) :
252
246
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 :
254
248
raise TokenValidationError (
255
249
'Issuer (iss) claim mismatch in the ID token; expected "{}", '
256
- 'found "{}"' .format (opt [ ' iss' ] , payload ['iss' ]))
250
+ 'found "{}"' .format (self . iss , payload ['iss' ]))
257
251
258
252
# Subject
259
- if 'sub' not in payload or type (payload ['sub' ]) != str :
253
+ if 'sub' not in payload or not isinstance (payload ['sub' ], str ) :
260
254
raise TokenValidationError ('Subject (sub) claim must be a string present in the ID token' )
261
255
262
256
# 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 ) ):
264
258
raise TokenValidationError (
265
259
'Audience (aud) claim must be a string or array of strings present in the ID token' )
266
260
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' ]:
268
262
payload_audiences = ", " .join (payload ['aud' ])
269
263
raise TokenValidationError (
270
264
'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 :
273
267
raise TokenValidationError (
274
268
'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' ]))
276
270
277
271
# --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
280
274
281
275
# 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 ) :
283
277
raise TokenValidationError ('Expiration Time (exp) claim must be a number present in the ID token' )
284
278
285
279
exp_time = payload ['exp' ] + leeway
@@ -289,7 +283,7 @@ def verify(self, token, nonce=None, max_age=None):
289
283
'after expiration time ({})' .format (now , exp_time ))
290
284
291
285
# 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 ) :
293
287
raise TokenValidationError ('Issued At (iat) claim must be a number present in the ID token' )
294
288
295
289
iat_time = payload ['iat' ] - leeway
@@ -299,33 +293,33 @@ def verify(self, token, nonce=None, max_age=None):
299
293
'before issued at time ({})' .format (now , iat_time ))
300
294
301
295
# 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 ) :
304
298
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 :
306
300
raise TokenValidationError (
307
301
'Nonce (nonce) claim mismatch in the ID token; expected "{}", '
308
- 'found "{}"' .format (opt [ ' nonce' ] , payload ['nonce' ]))
302
+ 'found "{}"' .format (nonce , payload ['nonce' ]))
309
303
310
304
# 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 ) :
313
307
raise TokenValidationError (
314
308
'Authorized Party (azp) claim must be a string present in the ID token when '
315
309
'Audience (aud) claim has multiple values' )
316
- if payload ['azp' ] != opt [ ' aud' ] :
310
+ if payload ['azp' ] != self . aud :
317
311
raise TokenValidationError (
318
312
'Authorized Party (azp) claim mismatch in the ID token; expected "{}", '
319
- 'found "{}"' .format (opt [ ' aud' ] , payload ['azp' ]))
313
+ 'found "{}"' .format (self . aud , payload ['azp' ]))
320
314
321
315
# 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 ) :
324
318
raise TokenValidationError (
325
319
'Authentication Time (auth_time) claim must be a number present in the ID token '
326
320
'when Max Age (max_age) is specified' )
327
321
328
- auth_valid_until = payload ['auth_time' ] + opt [ ' max_age' ] + leeway
322
+ auth_valid_until = payload ['auth_time' ] + max_age + leeway
329
323
if now > auth_valid_until :
330
324
raise TokenValidationError (
331
325
'Authentication Time (auth_time) claim in the ID token indicates that too much '
0 commit comments