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

Cannot launch LTI 1.3. assignments in IFrame: Canvas fails to authenticate because cross-site cookie is blocked #1900

Open
jvdm opened this issue Jun 24, 2021 · 5 comments · May be fixed by #2096

Comments

@jvdm
Copy link

jvdm commented Jun 24, 2021

Summary:

In Google Chrome > 91, when using Canvas as an LTI 1.3 platform to launch External Tool assignments connected to an LTI 1.3. tool inside an IFrame, the launch fails with error: login_required and error_description: Must have an active user session.

It is noticeable that log_session_id, the cookie used by Canvas for session management, is blocked during the LTI 1.3. OIDC authentication flow on the request to the authorization endpoint /api/lti/authorize_redirect. This behavior happens since Chrome > 91 started enforcing the new SameSite policies. That policy is blocking cross-site cookies without SameSite=None and Secure set, and redirects within IFrames are considered cross-site.

Steps to reproduce:

  1. Have Google Chrome > 91 (or any other browser enforcing SameSite=None cookies for cross-site calls).
  2. Setup a development stack of Canvas 2021-05-26.01
  3. Configure LTI 1.3.
  4. Configure an LTI tool (I am using a tool that is based on pylti1p3).
  5. Setup an external tool assignment.
  6. Uncheck the "launch in a separate tab" checkbox.
  7. Launch the assignment.
  8. Observe the LTI launch failing. This can be done through the development console.

Expected behavior:

The LTI launch should succeed.

Actual behavior:

The LTI launch fails, here's a breakdown of the requests.

# From To Description
1. BROWSER CANVAS Request assignment in Canvas, which is an External Tool (LTI).
2. CANVAS BROWSER Reply with an empty IFrame and set the log_session_id cookie without SameSite=None. This means cross-site calls to CANVAS will not set the cookie.
3. BROWSER TOOL Request login/ from within the iframe. This is cross-site. It starts the OIDC flow. The frontend code will populate the iframe with the content of this request.
4. TOOL BROWSER Reply with a redirect to CANVAS passing the LTI 1.3. auth parameters. This request does not have log_session_id set. It is blocked in Chrome (but Firefox allows it).
5. BROWSER CANVAS Redirect to authenticate at Canvas is sent, it fails because we are not passing the log_session_id token.
6. CANVAS BROWSER Reply with a redirect to TOOL, with an error.
7. BROWSER TOOL This should be the final tool launch, but it is the error from the authentication.
8. TOOL BROWSER Since it was an error, TOOL reply the "Invalid Tool Launch" message.

Excerpt of the error redirect from /api/lti/authorize:

utf8: ✓
authenticity_token: <a base 64 encodied string that was omited by me>
error: login_required
error_description: Must have an active user session
state: state-891953f5-97dd-4891-837f-5d01958aeb29

Additional notes:

Please, notice there are other resources in Forums and discussions around LTI 1.3. and cross-site cookies handling after the SameSite=None enforcing was added to browsers such as Chrome and Safari, but they are related to updating Tools that uses cross-site cookies. This report is about to perform the LTI 1.3 authentication within an IFrame.

Examples:

  1. https://community.canvaslms.com/t5/Canvas-Developers-Group/Safari-13-1-and-LTI-Integration/ba-p/273051
  2. https://community.canvaslms.com/t5/Canvas-Developers-Group/SameSite-Cookies-and-Canvas/ba-p/257967
@leeyongl5263
Copy link

I am experiencing the same thing. Could you find any remediation or fixes for this?

Thank you :)

@NaurizAitbai
Copy link

I have this problem too.
When I manually change _legacy_normandy_session to Secure,SameSite=None in my Chrome, it starts working.

@jbergfi
Copy link

jbergfi commented Sep 19, 2022

This is a fairly old issue but I'm seeing the same thing. Just went through making sure SameSite=None and Secure flags are set for the tool I'm working on but this seems to be something that needs to be fixed Canvas side.

I'm quite surprised, if this is an issue, why isn't it an issue for all LTI 1.3 deep linking tools?

@NaurizAitbai
Copy link

NaurizAitbai commented Sep 19, 2022

This is a fairly old issue but I'm seeing the same thing. Just went through making sure SameSite=None and Secure flags are set for the tool I'm working on but this seems to be something that needs to be fixed Canvas side.

Hello. Sorry for my bad english.

That's indeed a problem on Canvas side. Bad documentation.
Canvas has session_store.yml file (https://github.com/instructure/canvas-lms/blob/master/config/session_store.yml.example) that has secure field (commented) and you need to uncomment, then it will set SameSite and Secure flags.
But you won't find it in their documentation for production installing (https://github.com/instructure/canvas-lms/wiki/Production-Start), so people install self-hosted Canvas, forgetting uncomment secure field, and half of LTI 1.3 won't work on their instance.

Also Canvas has very bad realization for LTI 1.3.
You can identify LMS instance by two fields issuer and client_id. So these two fields together needs to be globally unique. BrightSpace, Moodle and other LMS systems don't have problem with uniqueness, because they're generating client_id randomly and issuer defaults to instance domain.

But Canvas LMS, set issuer to https://canvas.instructure.com in https://github.com/instructure/canvas-lms/blob/master/config/security.yml.example and not saying people how to change it in production documentation. Not only this, but their client_id not generating randomly, starting from 10000000000001 for every self-hosted instance.

I'm quite surprised, if this is an issue, why isn't it an issue for all LTI 1.3 deep linking tools?

I think they're using Instructure's Canvas instance. This instance doesn't have this problem, because secure field was set.

jbergfi added a commit to jbergfi/canvas-lms that referenced this issue Sep 19, 2022
LTI 1.3 deep linking don't seem to be working properly in latest Chrome. This is because SameSite cookie property is not set properly.

See
instructure#1900
jbergfi added a commit to jbergfi/canvas-lms that referenced this issue Sep 19, 2022
LTI 1.3 deep linking don't seem to be working in latest Chrome. Seemingly this is due to because SameSite property of session and CSRF token cookies are not set to None to allow cross-site. Even though the deep link selection iframe ends up at same domain (Canvas) it's navigated to through the tool domain which effectively makes it cross-site.

Closes instructuregh-1900

Test plan:
- Test LTI 1.3 deep linking with an external tool
- Test compatibility with different browsers (new browsers supporting SameSite: None and browsers not supporting)
- Investigate any undesired security implications this change might have
@jbergfi jbergfi linked a pull request Sep 19, 2022 that will close this issue
@jbergfi
Copy link

jbergfi commented Sep 19, 2022

Adding the session_store.yml config does add the Secure flag which also is needed but as far as I can tell it does not help with adding the SameSite flag. I managed to get it working on my self-hosted instance of Canvas by doing the changes in my pull request above. I had to change in a few different places to make it apply SameSite both to the session cookie and to the CSRF Token cookie.

I'm running a self-hosted instance to test my tool and it has indeed been a bit of a hassle to setup. Not sure if things behaves differently in any Instructure hosted solutions.

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

Successfully merging a pull request may close this issue.

4 participants