pylti / lti

Learning Tools Interoperability for Python

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

nonce check

petarnikolovski opened this issue · comments

Does this library checks for validity of nonce or is the implementation left to developers?

Nonce checking is implemented via oauthlib's interface, which requires the developer to tell it how to check the nonce. See the oathlib docs for more information on how to write a validator.

https://oauthlib.readthedocs.io/en/latest/oauth1/validator.html

Thanks for the answer. So basically one should subclass RequestValidator from oauthlib and then pass it to TP object, e.g.

from lti.contrib.django import DjangoToolProvider
from oauthlib.oauth1.rfc5849.request_validator import RequestValidator


tool_provider = DjangoToolProvider.from_django_request(request=request)

class LTIValidator(RequestValidator):

    def __init__(self):
        super()

    def validate_timestamp_and_nonce(self, client_key, timestamp, nonce,
                                     request, request_token=None, access_token=None):
        # My implementation of validator
        pass

validator = LTIValidator()
validator.nonce_length = (5, 50)

ok = tool_provider.is_valid_request(validator)

And then validate_timestamp_and_nonce will be used internally by the library to verify nonce?

Edit: Or should I manually check validity of nonce and then proceed to check validity of the request? I.e. (extension of the example above)

validator = LTIValidator()
check_nonce = validator.validate_timestamp_and_nonce(client_key, timestamp, nonce, request)

if check_nonce:
    # raise custom made exception
    raise NonceNotValid()

# if nonce ok, then check request with the library
ok = tool_provider.is_valid_request(validator)

Yes, pass the validator into the appropriate functions. It's important to let oauthlib do the talking to your validator, because it does a bunch of special handling to make sure a lot of stuff with oauth, especially to do with timing, is done carefully.

Also, nonce_length can be set as a class property, rather than adding it to the class after instantiation. That's the way I would do it, at least, and then you can just create an instance of the validator inside your call to is_valid_request like tool_provider.is_valid_request(LTIValidator()).

So the validator you gave as an example could look more like this:

class LTIValidator(RequestValidator):
    nonce_length = (5, 50)

    # No need to override `__init__` if you're not changing it.

    def validate_timestamp_and_nonce(self, client_key, timestamp, nonce,
                                     request, request_token=None, access_token=None):
        # My implementation of validator
        pass

Thank you very much!