Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for LTI Platform Storage Specification #119

Open
dgwn opened this issue Jul 31, 2023 · 18 comments
Open

Add support for LTI Platform Storage Specification #119

dgwn opened this issue Jul 31, 2023 · 18 comments

Comments

@dgwn
Copy link

dgwn commented Jul 31, 2023

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:

@hmoffatt
Copy link
Contributor

hmoffatt commented Aug 12, 2023

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?

@dgwn
Copy link
Author

dgwn commented Aug 15, 2023

@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.

@dmitry-viskov
Copy link
Owner

@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

@claudevervoort
Copy link

claudevervoort commented Aug 15, 2023

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) WebKit/standards-positions#50).

@hmoffatt
Copy link
Contributor

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.

@hmoffatt
Copy link
Contributor

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.

@dmitry-viskov
Copy link
Owner

@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

@hmoffatt
Copy link
Contributor

hmoffatt commented Nov 14, 2023

Chrome is going to start rolling this out slowly from 1Q2024. https://developer.chrome.com/blog/cookie-countdown-2023oct/

@jeffbaier
Copy link

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.

@Thetwam
Copy link

Thetwam commented Nov 17, 2023

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!

@hmoffatt
Copy link
Contributor

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.

@jeffbaier
Copy link

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()

jeffbaier@dad6086

reference: https://developers.google.com/privacy-sandbox/3pcd/chips

@hmoffatt
Copy link
Contributor

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.

@jeffbaier
Copy link

and I don't think any monkeypatching will be required

You have to because the base python cookie library doesn't support Partitioned yet. python/cpython#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.

@hmoffatt
Copy link
Contributor

hmoffatt commented Jan 16, 2024

You have to because the base python cookie library doesn't support Partitioned yet. 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: pallets/werkzeug#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.

@hmoffatt
Copy link
Contributor

hmoffatt commented Mar 1, 2024

What about using localstorage for the OIDC launch cookie instead?

@dgwn
Copy link
Author

dgwn commented Mar 8, 2024

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 (python/cpython#112714 (comment)), which looks slated for version 3.13 (python/cpython#112713 (comment)). Still monitoring updates on support for Webkit/Safari.

@hmoffatt
Copy link
Contributor

hmoffatt commented Mar 8, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants