canvas-lms
canvas-lms copied to clipboard
LTI 1.3's lti1p1 claim's oauth_consumer_key_sign calculated using a nonce not in the payload
Summary:
oauth_consumer_key_sign is calculated using the oauth_consumer_key, deployment_id, iss, client_id, exp, and nonce, joined together using the ampersand &, and signed using hmac-sha256. This allows LTI 1.3 tools to automatically and securely upgrade LTI 1.1 installs. We finished our implementation of calculating the key sign, and found ours did not match the one provided in the lti1p1 claim.
Steps to reproduce:
- Go to Admin -> pick your account -> settings -> Apps -> View App Configurations -> +App -> Fill out the LTI 1.1 information, making note of the Launch Url
- Create a course.
- Create an assignment. Use submission type "External Tool" finding and selecting the tool above.
- Launch the assignment, showing the LTI 1.1 tool does have the right oauth consumer key/secret
- Go back to Admin -> pick your account -> settings -> developer tools -> +Developer Key -> +LTI key -> Fill out the LTI 1.3 information. Make sure to put the LTI 1.1 Launch Url into the Target Link URI field.
- Relaunch the assignment, now in LTI 1.3. This will provide the oauth_consumer_key_sign
Expected behavior:
The oauth_consumer_key_sign should be signed using the nonce given in the payload
Actual behavior:
The oauth_consumer_key_sign is signed using some other nonce
Additional notes:
You can see that the nonce passed into the generate_oauth_consumer_key_sign method is created here in JwtMessage's add_security_claims. It's a uuid but that's not what comes in the payload. In the payload, the nonce is nonce-<64hexchars>. The nonce is overwritten here in the authentication_controller's cached_launch_with_nonce. Because of this, it is impossible for the LTI 1.3 tool to use oauth_consumer_key_sign
I am also facing the same problem. @JonathanGawrych Did you find out any solution or response from canvas ?
Unfortunately not. LMS oauth_consumer_key_sign support proved to be quite abysmal across LMSs
- Canvas generates
oauth_consumer_key_signincorrectly as we see above. We were never able to get a response from canvas about it. - ~Blackboard doesn't support it, and after conversation for half a year, we think they can't support it. It seems like they delete the
oauth_consumer_key/secreton their side during migration. (you can't go back after migrating). They may in the future be able to support it for future migrations, but it seems like all past migrations will never haveoauth_consumer_key_sign. The ticket has just remained open like this one for half a year, so I'm not hopeful.~ Edit: This isn't true. See my next comment below! - D2L supports it, but only on migrated activities. If your first launch into 1.3 is not something that was migrated, then you don't get
oauth_consumer_key_sign. This kinda makes sense, but renders the feature a little moot for us. You want to test LTI 1.3 works before irrevocably migrating all existing data over, but any sort of migration on your LTI side needs the key sign to verify. This may work if each resource in your LTI tool is completely isolated, but ours is interconnected with the context and tool_platform, and we need to know which LTI 1.1 tool (or none) a LTI 1.3 launch is linked to on first launch. - Moodle's LTI supports it, but Moodle's LMS doesn't. We basically gave up on
oauth_consumer_key_signsupport at this point, so we didn't really pursue it on Moodle's side. Their configuration allows you to go back and forth at ease, so it seems like they could in the future.
As for fixes and workarounds, we briefly considered just allowing LTI 1.3 launches to auto-migrate without oauth_consumer_key_sign. However, this would allow anyone to take over any LTI 1.1 org with a crafted malicious LTI 1.3 launch. We instead built a manual tool on our side to approve LTI 1.1 -> LTI 1.3 migration securely and link them with the correct LTI 1.1. Unfortunately that means when you migrate to LTI 1.3, you get a "contact our support", and our support has to verify your identity, verify you are indeed an admin in the org you are trying to migrate, and verify what LTI 1.1 to link it to, and the users are blocked until it is done. Our documentation for LTI 1.3 migration asks you to contact support first so we can minimize downtime.
Even then we still do actually support oauth_consumer_key_sign, but that code path has never been triggered by a customer, sadly. However, we had to put in code that says "ignore the key sign if canvas and version is less than x.x.x" and plan to set that canvas version when this was fixed... but it never was.
Another issue that would affect this is that Canvas in some edge cases picks the incorrect oauth_consumer_key. Suppose you have two LTI 1.1 installs, one at the org level, and one at the subaccount level, then have two LTI 1.3 migrations, also at the org and subaccount level.
- If you pick the org level LTI 1.3 at the org level, then it'll give you the org level LTI 1.1
oauth_consumer_key - If you pick the subaccount level LTI 1.3 at the subaccount level, then it'll give you the subaccount level LTI 1.1
oauth_consumer_key - If you pick the org level LTI 1.3 at the subaccount level, then it'll give you the subaccount level LTI 1.1
oauth_consumer_key
So even if they fixed oauth_consumer_key_sign, you may accidentally tie the wrong LTI 1.3 deployment (the account level one) to the wrong LTI 1.1 install (the org level one). That seperate bug would also need to be fixed before we enabled key sign for canvas.
For all these reasons we built our manual tool and excluded canvas from using oauth_consumer_key_sign. I hope this helps in your journey to support LTI 1.3.
@JonathanGawrych Your input has been incredibly valuable and has helped me tremendously in navigating through some challenges. Your expertise and suggestions have truly made a difference, and I'm deeply grateful for your support.
@mzohaiba In a surprising twist of events, I just got a notification after 6 month of radio silence that Blackboard has release oauth_consumer_key_sign in version 3900.83. We were very surprised, as they hinted it wasn't possible. We tested it, and it seems work out of the box, for both new and existing activities. It was very exciting!
However, they didn't use to send a lti1p1 claim, but now they do, this time with a user_id. Unfortunately, that user_id doesn't match the LTI 1.1 user_id, but seems to be some internal blackboard user id. This caused our system to create duplicate users when they launch. We had to release an update to ignore blackboard's lti1p1 claim's user_id. Aside from that, it seems like we will actually have an LMS that'll use oauth_consumer_key_sign!