@@ -128,6 +128,12 @@ def _check_audience(payload_dict, audience):
128
128
payload_dict: dict, A dictionary containing a JWT payload.
129
129
audience: string or NoneType, an audience to check for in
130
130
the JWT payload.
131
+
132
+ Raises:
133
+ AppIdentityError: If there is no ``'aud'`` field in the payload
134
+ dictionary but there is an ``audience`` to check.
135
+ AppIdentityError: If the ``'aud'`` field in the payload dictionary
136
+ does not match the ``audience``.
131
137
"""
132
138
if audience is None :
133
139
return
@@ -141,6 +147,57 @@ def _check_audience(payload_dict, audience):
141
147
(audience_in_payload , audience , payload_dict ))
142
148
143
149
150
+ def _verify_time_range (payload_dict ):
151
+ """Verifies the issued at and expiration from a JWT payload.
152
+
153
+ Makes sure the current time (in UTC) falls between the issued at and
154
+ expiration for the JWT (with some skew allowed for via
155
+ ``CLOCK_SKEW_SECS``).
156
+
157
+ Args:
158
+ payload_dict: dict, A dictionary containing a JWT payload.
159
+
160
+ Raises:
161
+ AppIdentityError: If there is no ``'iat'`` field in the payload
162
+ dictionary.
163
+ AppIdentityError: If there is no ``'exp'`` field in the payload
164
+ dictionary.
165
+ AppIdentityError: If the JWT expiration is too far in the future (i.e.
166
+ if the expiration would imply a token lifetime
167
+ longer than what is allowed.)
168
+ AppIdentityError: If the token appears to have been issued in the
169
+ future (up to clock skew).
170
+ AppIdentityError: If the token appears to have expired in the past
171
+ (up to clock skew).
172
+ """
173
+ # Get the current time to use throughout.
174
+ now = int (time .time ())
175
+
176
+ # Make sure issued at and expiration are in the payload.
177
+ issued_at = payload_dict .get ('iat' )
178
+ if issued_at is None :
179
+ raise AppIdentityError ('No iat field in token: %s' % (payload_dict ,))
180
+ expiration = payload_dict .get ('exp' )
181
+ if expiration is None :
182
+ raise AppIdentityError ('No exp field in token: %s' % (payload_dict ,))
183
+
184
+ # Make sure the expiration gives an acceptable token lifetime.
185
+ if expiration >= now + MAX_TOKEN_LIFETIME_SECS :
186
+ raise AppIdentityError ('exp field too far in future: %s' %
187
+ (payload_dict ,))
188
+
189
+ # Make sure (up to clock skew) that the token wasn't issued in the future.
190
+ earliest = issued_at - CLOCK_SKEW_SECS
191
+ if now < earliest :
192
+ raise AppIdentityError ('Token used too early, %d < %d: %s' %
193
+ (now , earliest , payload_dict ))
194
+ # Make sure (up to clock skew) that the token isn't already expired.
195
+ latest = expiration + CLOCK_SKEW_SECS
196
+ if now > latest :
197
+ raise AppIdentityError ('Token used too late, %d > %d: %s' %
198
+ (now , latest , payload_dict ))
199
+
200
+
144
201
def verify_signed_jwt_with_certs (jwt , certs , audience = None ):
145
202
"""Verify a JWT against public certs.
146
203
@@ -156,7 +213,7 @@ def verify_signed_jwt_with_certs(jwt, certs, audience=None):
156
213
dict, The deserialized JSON payload in the JWT.
157
214
158
215
Raises:
159
- AppIdentityError if any checks are failed.
216
+ AppIdentityError: if any checks are failed.
160
217
"""
161
218
jwt = _to_bytes (jwt )
162
219
@@ -175,31 +232,11 @@ def verify_signed_jwt_with_certs(jwt, certs, audience=None):
175
232
except :
176
233
raise AppIdentityError ('Can\' t parse token: %s' % (payload_bytes ,))
177
234
178
- # Check signature.
235
+ # Verify that the signature matches the message .
179
236
_verify_signature (message_to_sign , signature , certs )
180
237
181
- # Check creation timestamp.
182
- issued_at = payload_dict .get ('iat' )
183
- if issued_at is None :
184
- raise AppIdentityError ('No iat field in token: %s' % (payload_bytes ,))
185
- earliest = issued_at - CLOCK_SKEW_SECS
186
-
187
- # Check expiration timestamp.
188
- now = int (time .time ())
189
- expiration = payload_dict .get ('exp' )
190
- if expiration is None :
191
- raise AppIdentityError ('No exp field in token: %s' % (payload_bytes ,))
192
- if expiration >= now + MAX_TOKEN_LIFETIME_SECS :
193
- raise AppIdentityError ('exp field too far in future: %s' %
194
- (payload_bytes ,))
195
- latest = expiration + CLOCK_SKEW_SECS
196
-
197
- if now < earliest :
198
- raise AppIdentityError ('Token used too early, %d < %d: %s' %
199
- (now , earliest , payload_bytes ))
200
- if now > latest :
201
- raise AppIdentityError ('Token used too late, %d > %d: %s' %
202
- (now , latest , payload_bytes ))
238
+ # Verify the issued at and created times in the payload.
239
+ _verify_time_range (payload_dict )
203
240
204
241
# Check audience.
205
242
_check_audience (payload_dict , audience )
0 commit comments