Skip to content

Fix NoMethodError in lti_launch_link_course action#2308

Open
dpaceoffice wants to merge 1 commit intoautolab:masterfrom
dpaceoffice:fix/lti-launch-link-course-nil-cud
Open

Fix NoMethodError in lti_launch_link_course action#2308
dpaceoffice wants to merge 1 commit intoautolab:masterfrom
dpaceoffice:fix/lti-launch-link-course-nil-cud

Conversation

@dpaceoffice
Copy link

@dpaceoffice dpaceoffice commented Jan 12, 2026

Title: Fix NoMethodError in lti_launch_link_course when linking LTI course

Description:

The lti_launch_link_course action was incorrectly included in the authenticate_for_action exception list, causing authenticate_for_action to run. However, since UsersController skips both set_course and authorize_user_for_course, the @CUD instance variable is never set, resulting in 'undefined method has_auth_level? for nil:NilClass'.

This fix:

  1. Removes lti_launch_link_course from the authenticate_for_action exception list (so it gets skipped like other actions)
  2. Adds inline authorization check within the action to verify the current user is an instructor for the target course

This maintains security while fixing the nil reference error.

Description

When users attempt to link a Canvas course via LTI at /users/:id/lti_launch_link_course, a 500 Internal Server Error occurs because @cud.has_auth_level?(:instructor) is called on a nil object in authenticate_for_action.

Motivation and Context

LTI course linking is completely broken in the current codebase. Any user attempting to link a Canvas course to Autolab encounters this crash, preventing LTI integration from working.

How Has This Been Tested?

  • Tested on production Autolab instance (v2.x) with Canvas LTI 1.3 integration
  • Verified course linking completes successfully after fix
  • Verified the linked course appears in LtiCourseDatum table
  • Non-instructor denial logic is in place but not explicitly tested in production

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • I have run rubocop and erblint for style check. If you haven't, run overcommit --install && overcommit --sign to use pre-commit hook for linting
  • My change requires a change to the documentation, which is located at Autolab Docs
  • I have updated the documentation accordingly, included in this PR

Other details

This bug was introduced in commit 301689a (October 24, 2024) which added lti_launch_link_course to the authenticate_for_action exception list. This change was part of a PR to add admin checks for password-related actions, but lti_launch_link_course, it seems, was incorrectly included.

The lti_launch_link_course action was incorrectly included in the
authenticate_for_action exception list, causing authenticate_for_action
to run. However, since UsersController skips both set_course and
authorize_user_for_course, the @CUD instance variable is never set,
resulting in 'undefined method has_auth_level? for nil:NilClass'.

This fix:
1. Removes lti_launch_link_course from the authenticate_for_action
   exception list (so it gets skipped like other actions)
2. Adds inline authorization check within the action to verify the
   current user is an instructor for the target course

This maintains security while fixing the nil reference error.

Fixes: NoMethodError in authenticate_for_action when linking LTI course
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

Security enhancement to the lti_launch_link_course endpoint requiring user authentication and verifying instructor permissions before creating course LTI data. Uses the loaded course object instead of re-fetching from parameters.

Changes

Cohort / File(s) Summary
Authentication & Authorization Enhancement
app/controllers/users_controller.rb
Removed lti_launch_link_course from authentication skip list, requiring login. Added instructor role verification before allowing LTI course data creation. Refactored to use course object reference instead of parameter-based re-fetch, eliminating redundant database lookups.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main fix: resolving a NoMethodError that was preventing the lti_launch_link_course action from working properly.
Description check ✅ Passed The description comprehensively addresses the template requirements, including detailed context, motivation, testing approach, and change type classification with all necessary checkboxes completed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
app/controllers/users_controller.rb (1)

340-349: Consider verifying LtiCourseDatum.create succeeded before showing success message.

create returns the object regardless of whether it was persisted. If validation or a unique constraint fails (e.g., duplicate context_id), the user sees a success flash while the record wasn't actually created.

♻️ Suggested fix to handle create failure
-    LtiCourseDatum.create(
+    lcd = LtiCourseDatum.create(
       course_id: course.id,
       context_id: params[:context_id],
       membership_url: params[:course_memberships_url],
       platform: params[:platform],
       last_synced: DateTime.current
     )
 
+    unless lcd.persisted?
+      flash[:error] = "Failed to link course: #{lcd.errors.full_messages.join(', ')}"
+      redirect_to(root_path) && return
+    end
+
     flash[:success] = "#{course.name} successfully linked."
     redirect_to(course)
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 674efe9 and b6f9fa2.

📒 Files selected for processing (1)
  • app/controllers/users_controller.rb
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-09-20T20:46:52.775Z
Learnt from: evanyeyeye
Repo: autolab/Autolab PR: 2209
File: app/controllers/autograders_controller.rb:0-0
Timestamp: 2024-09-20T20:46:52.775Z
Learning: In the `AutogradersController`, ensure that the `download_file` method has `action_auth_level :download_file, :instructor` to restrict access to instructors.

Applied to files:

  • app/controllers/users_controller.rb
📚 Learning: 2024-06-10T19:38:42.782Z
Learnt from: jlge
Repo: autolab/Autolab PR: 2011
File: app/controllers/assessments_controller.rb:28-29
Timestamp: 2024-06-10T19:38:42.782Z
Learning: `destroy_no_redirect` in `app/controllers/assessments_controller.rb` is an internal method used within the controller and not a public endpoint. It should not be included in the `before_action :set_assessment` exclusion list.

Applied to files:

  • app/controllers/users_controller.rb
🧬 Code graph analysis (1)
app/controllers/users_controller.rb (1)
app/models/course_user_datum.rb (2)
  • find_cud_for_course (217-230)
  • has_auth_level? (152-165)
🔇 Additional comments (2)
app/controllers/users_controller.rb (2)

4-5: LGTM!

Removing lti_launch_link_course from the exception list correctly ensures authenticate_for_action is skipped for this action, consistent with other actions in this controller that handle their own authorization. This fixes the NoMethodError caused by @cud being nil.


332-338: Authorization check looks correct.

The inline authorization properly verifies that current_user (not @user from params) has instructor privileges for the target course before allowing the link operation. Using safe navigation handles the nil case appropriately.

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 this pull request may close these issues.

1 participant