Skip to content

Commit 9f78b6b

Browse files
committed
Merge remote-tracking branch 'oauth2cli/dev' into max_age-and-validation
2 parents 0deba2e + 16de114 commit 9f78b6b

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

msal/oauth2cli/oidc.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def decode_id_token(id_token, client_id=None, issuer=None, nonce=None, now=None)
4242
"""
4343
decoded = json.loads(decode_part(id_token.split('.')[1]))
4444
err = None # https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
45-
_now = now or time.time()
45+
_now = int(now or time.time())
4646
skew = 120 # 2 minutes
4747
if _now + skew < decoded.get("nbf", _now - 1): # nbf is optional per JWT specs
4848
# This is not an ID token validation, but a JWT validation
@@ -67,14 +67,14 @@ def decode_id_token(id_token, client_id=None, issuer=None, nonce=None, now=None)
6767
# the Client and the Token Endpoint (which it is during _obtain_token()),
6868
# the TLS server validation MAY be used to validate the issuer
6969
# in place of checking the token signature.
70-
if _now > decoded["exp"]:
70+
if _now - skew > decoded["exp"]:
7171
err = "9. The current time MUST be before the time represented by the exp Claim."
7272
if nonce and nonce != decoded.get("nonce"):
7373
err = ("11. Nonce must be the same value "
7474
"as the one that was sent in the Authentication Request.")
7575
if err:
76-
raise RuntimeError("%s The id_token was: %s" % (
77-
err, json.dumps(decoded, indent=2)))
76+
raise RuntimeError("%s Current epoch = %s. The id_token was: %s" % (
77+
err, _now, json.dumps(decoded, indent=2)))
7878
return decoded
7979

8080

@@ -187,6 +187,8 @@ def initiate_auth_code_flow(
187187
flow = super(Client, self).initiate_auth_code_flow(
188188
scope=_scope, nonce=_nonce_hash(nonce), **kwargs)
189189
flow["nonce"] = nonce
190+
if kwargs.get("max_age") is not None:
191+
flow["max_age"] = kwargs["max_age"]
190192
return flow
191193

192194
def obtain_token_by_auth_code_flow(self, auth_code_flow, auth_response, **kwargs):
@@ -208,6 +210,26 @@ def obtain_token_by_auth_code_flow(self, auth_code_flow, auth_response, **kwargs
208210
raise RuntimeError(
209211
'The nonce in id token ("%s") should match our nonce ("%s")' %
210212
(nonce_in_id_token, expected_hash))
213+
214+
if auth_code_flow.get("max_age") is not None:
215+
auth_time = result.get("id_token_claims", {}).get("auth_time")
216+
if not auth_time:
217+
raise RuntimeError(
218+
"13. max_age was requested, ID token should contain auth_time")
219+
now = int(time.time())
220+
skew = 120 # 2 minutes. Hardcoded, for now
221+
if now - skew > auth_time + auth_code_flow["max_age"]:
222+
raise RuntimeError(
223+
"13. auth_time ({auth_time}) was requested, "
224+
"by using max_age ({max_age}) parameter, "
225+
"and now ({now}) too much time has elasped "
226+
"since last end-user authentication. "
227+
"The ID token was: {id_token}".format(
228+
auth_time=auth_time,
229+
max_age=auth_code_flow["max_age"],
230+
now=now,
231+
id_token=json.dumps(result["id_token_claims"], indent=2),
232+
))
211233
return result
212234

213235
def obtain_token_by_browser(

0 commit comments

Comments
 (0)