aboutsummaryrefslogtreecommitdiff
path: root/oauth2client/crypt.py
diff options
context:
space:
mode:
authorDanny Hermes <daniel.j.hermes@gmail.com>2015-08-25 18:04:33 -0700
committerDanny Hermes <daniel.j.hermes@gmail.com>2015-09-01 09:58:33 -0700
commit8c2762fdfc1c6d4b327438f4ba0f8cf545094501 (patch)
treeafae1d19007a3bf7343376698164c08e61b11edd /oauth2client/crypt.py
parentf7f279266ba562b393e68b3d11469309a2d52db3 (diff)
downloadoauth2client-8c2762fdfc1c6d4b327438f4ba0f8cf545094501.tar.gz
Refactor exp/iat checking in crypt.verify_signed_jwt_with_certs.
Moved check into protected function _verify_time_range.
Diffstat (limited to 'oauth2client/crypt.py')
-rw-r--r--oauth2client/crypt.py85
1 files changed, 61 insertions, 24 deletions
diff --git a/oauth2client/crypt.py b/oauth2client/crypt.py
index 655c5f7..fe119f5 100644
--- a/oauth2client/crypt.py
+++ b/oauth2client/crypt.py
@@ -128,6 +128,12 @@ def _check_audience(payload_dict, audience):
payload_dict: dict, A dictionary containing a JWT payload.
audience: string or NoneType, an audience to check for in
the JWT payload.
+
+ Raises:
+ AppIdentityError: If there is no ``'aud'`` field in the payload
+ dictionary but there is an ``audience`` to check.
+ AppIdentityError: If the ``'aud'`` field in the payload dictionary
+ does not match the ``audience``.
"""
if audience is None:
return
@@ -141,6 +147,57 @@ def _check_audience(payload_dict, audience):
(audience_in_payload, audience, payload_dict))
+def _verify_time_range(payload_dict):
+ """Verifies the issued at and expiration from a JWT payload.
+
+ Makes sure the current time (in UTC) falls between the issued at and
+ expiration for the JWT (with some skew allowed for via
+ ``CLOCK_SKEW_SECS``).
+
+ Args:
+ payload_dict: dict, A dictionary containing a JWT payload.
+
+ Raises:
+ AppIdentityError: If there is no ``'iat'`` field in the payload
+ dictionary.
+ AppIdentityError: If there is no ``'exp'`` field in the payload
+ dictionary.
+ AppIdentityError: If the JWT expiration is too far in the future (i.e.
+ if the expiration would imply a token lifetime
+ longer than what is allowed.)
+ AppIdentityError: If the token appears to have been issued in the
+ future (up to clock skew).
+ AppIdentityError: If the token appears to have expired in the past
+ (up to clock skew).
+ """
+ # Get the current time to use throughout.
+ now = int(time.time())
+
+ # Make sure issued at and expiration are in the payload.
+ issued_at = payload_dict.get('iat')
+ if issued_at is None:
+ raise AppIdentityError('No iat field in token: %s' % (payload_dict,))
+ expiration = payload_dict.get('exp')
+ if expiration is None:
+ raise AppIdentityError('No exp field in token: %s' % (payload_dict,))
+
+ # Make sure the expiration gives an acceptable token lifetime.
+ if expiration >= now + MAX_TOKEN_LIFETIME_SECS:
+ raise AppIdentityError('exp field too far in future: %s' %
+ (payload_dict,))
+
+ # Make sure (up to clock skew) that the token wasn't issued in the future.
+ earliest = issued_at - CLOCK_SKEW_SECS
+ if now < earliest:
+ raise AppIdentityError('Token used too early, %d < %d: %s' %
+ (now, earliest, payload_dict))
+ # Make sure (up to clock skew) that the token isn't already expired.
+ latest = expiration + CLOCK_SKEW_SECS
+ if now > latest:
+ raise AppIdentityError('Token used too late, %d > %d: %s' %
+ (now, latest, payload_dict))
+
+
def verify_signed_jwt_with_certs(jwt, certs, audience=None):
"""Verify a JWT against public certs.
@@ -156,7 +213,7 @@ def verify_signed_jwt_with_certs(jwt, certs, audience=None):
dict, The deserialized JSON payload in the JWT.
Raises:
- AppIdentityError if any checks are failed.
+ AppIdentityError: if any checks are failed.
"""
jwt = _to_bytes(jwt)
@@ -175,31 +232,11 @@ def verify_signed_jwt_with_certs(jwt, certs, audience=None):
except:
raise AppIdentityError('Can\'t parse token: %s' % (payload_bytes,))
- # Check signature.
+ # Verify that the signature matches the message.
_verify_signature(message_to_sign, signature, certs)
- # Check creation timestamp.
- issued_at = payload_dict.get('iat')
- if issued_at is None:
- raise AppIdentityError('No iat field in token: %s' % (payload_bytes,))
- earliest = issued_at - CLOCK_SKEW_SECS
-
- # Check expiration timestamp.
- now = int(time.time())
- expiration = payload_dict.get('exp')
- if expiration is None:
- raise AppIdentityError('No exp field in token: %s' % (payload_bytes,))
- if expiration >= now + MAX_TOKEN_LIFETIME_SECS:
- raise AppIdentityError('exp field too far in future: %s' %
- (payload_bytes,))
- latest = expiration + CLOCK_SKEW_SECS
-
- if now < earliest:
- raise AppIdentityError('Token used too early, %d < %d: %s' %
- (now, earliest, payload_bytes))
- if now > latest:
- raise AppIdentityError('Token used too late, %d > %d: %s' %
- (now, latest, payload_bytes))
+ # Verify the issued at and created times in the payload.
+ _verify_time_range(payload_dict)
# Check audience.
_check_audience(payload_dict, audience)