pylti1.3
pylti1.3 copied to clipboard
Add support for LTI Platform Storage Specification
Per Canvas:
"Safari blocking cookies inside 3rd-party iframes made it necessary to create a workaround for storing the state property between the login and launch requests, to prevent MITM attacks. The (under final review) LTI Platform Storage spec provides a way for tools that are launching in Safari or another situation where cookies can't get set to still store data across requests in a secure fashion. Tools can send window.postMessages to Canvas asking it to store and retrieve arbitrary data, which acts as a cookie-like proxy."
Other browsers (Firefox and Chrome) have either already implemented 3rd party cookie blocking or have plans to do so by the second half of 2024.
It appears that this library does not currently offer support for Platform Storage as an alternative for 3rd party cookies. Are there any plans to add such support?
The relevant LTI Platform Implementation guide specification
Other LTI Platform Storage spec docs:
I've got reports of problems with my tool in Safari, but it's working fine in my test Moodle and Canvas instances currently. Do you already see this occurring with Safari?
@hmoffatt From what I understand, tools may still work in Safari if your tool and test Canvas instance are running on the same domain, because that is still permissible under the 3rd part (cross-domain) security policy.
@dgwn For now there is workaround for third-party cookies issue: https://github.com/dmitry-viskov/pylti1.3#cookies-issues-in-the-iframes
Solution with postMessages looks more neat and could be considered in the future releases
Also for Chrome one may look at partitioned cookies. It's just like regular cookies but with the extra parameter 'partitioned'. Those remain visible even in incognito mode. They will only be visible under the wrapper domain, which usually for LTI is ok (i.e. more or less they are scoped to the IFrame): https://developer.chrome.com/blog/new-in-chrome-114/#chips - hopefully something Safari will adopt too (see) https://github.com/WebKit/standards-positions/issues/50).
tools may still work in Safari if your tool and test Canvas instance are running on the same domain
Thanks, that was why I didn't see the problem. My LMS and tool were on different hosts in the same domain, which was not enough to trigger the restriction (though it would be considered cross-origin by CORS). When I tested across domains, I see the "click to open in a new tab" behaviour kick in.
The "click to open in a new tab" works OK for a regular launch, but it does not work well for a content-selection launch in my testing with Canvas and Moodle. The launch works, you get to open in a new tab, but then the selection does not get sent back to the LMS correctly.
Canvas just shows a "Retrieving content" spinner and Moodle shows a message saying the content was selected OK, but in both cases the original content selector tab is still waiting for content selection.
I wonder if this could be fixed by having the new window send the response back to the original window via window.opener, which would then submit the form to the LMS.
@hmoffatt
The "click to open in a new tab" works OK for a regular launch, but it does not work well for a content-selection launch in my testing with Canvas and Moodle.
yes. Unfortunately current solution doesn't work in case of DeepLink request
Chrome is going to start rolling this out slowly from 1Q2024. https://developer.chrome.com/blog/cookie-countdown-2023oct/
Is anyone working on this? I need this functionality for my project so I am interested in adding it. But I don't want to step on anyone's toes if they are already in progress.
Is anyone working on this? I need this functionality for my project so I am interested in adding it. But I don't want to step on anyone's toes if they are already in progress.
@jeffbaier That would be great. Please reach out if you need testers!
Has anyone tried using Chrome's partition flag on the cookies? Unfortunately not supported by Safari yet but it might help with the upcoming cookie changes in Chrome. At least until we have support for the platform messaging spec in most LMSs and in pylti1.3.
Has anyone tried using Chrome's partition flag on the cookies?
I was actually just coming back to this thread to discuss this. I ended up not implementing the LTI Platform Storage Spec and instead just added the partition flag. The amount of Safari users we have is really low and with Canvas the only LMS supporting it so far we decided it wasn't worth the effort.
I forked this repo and added support for what Chrome calls "CHIPS". If anyone wants to try using my fork and report any issues here it is: https://github.com/jeffbaier/pylti1.3/tree/chips
Also if anyone wants to code review and suggest anything I am open to it. I had to monkey patch the python cookie lib, but I tried to follow how this project already handled that with SameSite. I also added Partitioned to the special JS code that runs if you use .enable_check_cookies()
https://github.com/jeffbaier/pylti1.3/commit/dad6086f6b1d5d4c2ea3b01b654322950a009adb
reference: https://developers.google.com/privacy-sandbox/3pcd/chips
Thanks @jeffbaier . I use Flask rather than Django but the changes should be similar (and I don't think any monkeypatching will be required). Were you able to test before and after with Chrome and verify this solution works?
Unfortunately we do need Safari to work for our application.
and I don't think any monkeypatching will be required
You have to because the base python cookie library doesn't support Partitioned yet. https://github.com/python/cpython/pull/112714
Were you able to test before and after with Chrome and verify this solution works?
Yes I finished this just in time for when Chrome enabled "Tracking Protection" for 1% of users on January 4th. It works for users that have Tracking Protection (killing 3rd party cookies) and users that don't have Tracking Protection. I have been running this code in our production sites for the last two weeks.
https://blog.google/products/chrome/privacy-sandbox-tracking-protection/
Unfortunately we do need Safari to work for our application.
Safari users still work with .enable_check_cookies(). But yes it will be much nicer for Safari users once LTI Platform Storage is supported.
You have to because the base python cookie library doesn't support
Partitionedyet. python/cpython#112714
I don't think Flask uses the base cookie class but it's still an issue. The problem for Flask is that it depends on Werkzeug to handle all of this, and it doesn't have the Partitioned flag. There's a request for it here: https://github.com/pallets/werkzeug/issues/2797
Safari users still work with
.enable_check_cookies(). But yes it will be much nicer for Safari users once LTI Platform Storage is supported.
Not for a deep linking content-selection launch, which is always in an iframe (discussed earlier in this issue). Theoretically it might be possible to open the content selection in a new window and pass the result back, but the UX would also be horrible.
What about using localstorage for the OIDC launch cookie instead?
It looks like Werkzeug merged support for the 'partitioned' param into main . Making use of this and some patching to pylti1.3 (adding 'partitioned' to the cookie_kwargs dictionary in pylti1p3/contrib/flask/cookie.py and checkCookiesAllowed()) I was able to get the login/launch flow to work for Flask apps in Chrome. Between this and @jeffbaier's Django patches, there is now at least a temporary workaround for 3rd party cookies with this library. It probably makes sense to wait for changes to be officially released in those frameworks before adding explicit support in pylti1.3, though.
I'm not sure what the timeline is for official support in Django, but it looks like activity is at least starting to pick up on all the pieces: Django is waiting on CPython to add support first (https://github.com/python/cpython/pull/112714#issuecomment-1977029003), which looks slated for version 3.13 (https://github.com/python/cpython/issues/112713#issuecomment-1956830267). Still monitoring updates on support for Webkit/Safari.
I was able to get the login/launch flow to work for Flask apps in Chrome
I have also tested this and it's working well. In Chrome you can enable the new 3rd party cookie handling with a command line switch for testing.