Skip to content

Inconsistent handling of leeway? #49

@fvkluck

Description

@fvkluck

Hi,

First of all, thank you for creating + maintaining this package.

I'm on drf-oidc-auth version 1.0.0 and Authlib 0.15.3.

I was looking into the code for handling the 'exp' and 'iat' headers, and I have the feeling there's some inconsistency in how the leeway parameter is used/interpreted. Let's introduce two names:
relative leeway: a time delta. Accept the header if the difference between current time and stated time is no more than this time delta.
absolute leeway: a boundary value obtained from subtracting the relative leeway from the current time.

In class JSONWebTokenAuthentication, method validate_claims in oidc_auth/authentication.py, the function id_token.validate is called with an absolute leeway:

            id_token.validate(
                now=int(time.time()),
                leeway=int(time.time()-api_settings.OIDC_LEEWAY)
            )

The DRFIDToken defined in oidc_auth/authentication.py indeed seems to assume an absolute leeway (self['iat'] < leeway):

class DRFIDToken(IDToken):

    def validate_exp(self, now, leeway):
        super(DRFIDToken, self).validate_exp(now, leeway)
        if now > self['exp']:
            msg = _('Invalid Authorization header. JWT has expired.')
            raise AuthenticationFailed(msg)

    def validate_iat(self, now, leeway):
        super(DRFIDToken, self).validate_iat(now, leeway)
        if self['iat'] < leeway:
            msg = _('Invalid Authorization header. JWT too old.')
            raise AuthenticationFailed(msg)

However, the validation of exp in package authlib , file rfc7519/claims.py (which is what the super call leads to) looks as follows:

    def validate_exp(self, now, leeway):
        """The "exp" (expiration time) claim identifies the expiration time on
        or after which the JWT MUST NOT be accepted for processing.  The
        processing of the "exp" claim requires that the current date/time
        MUST be before the expiration date/time listed in the "exp" claim.
        Implementers MAY provide for some small leeway, usually no more than
        a few minutes, to account for clock skew.  Its value MUST be a number
        containing a NumericDate value.  Use of this claim is OPTIONAL.
        """
        if 'exp' in self:
            exp = self['exp']
            if not _validate_numeric_time(exp):
                raise InvalidClaimError('exp')
            if exp < (now - leeway):
                raise ExpiredTokenError()

The line exp < (now - leeway) is a check for a relative leeway.

I notice that there has been a recent change from jwkest to authlib, so I guess this may be related. However, I haven't been able to find exact proof that this is where this inconsistency originates.

Could you confirm if my analysis is correct and/or sounds plausible? And if so, what your ideal solution would look like? I could imagine that the checks in this package's code would also have to change to relative leeways. If so, I might be able to supply a pull request fixing this.

Thanks,
Florian

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions