WeBWorK Main Forum

Canvas LTI authentication broken after upgrade to 2.18

Canvas LTI authentication broken after upgrade to 2.18

by Jan Hlavacek -
Number of replies: 3

I recently upgraded to 2.18. I attempted to move all the appropriate authentication parameters from authen_LTI.conf to authen_LTI_1_1.conf and do the other necessary edits, but I must have missed something, because the authentication does not work. This is what I get in the debug file when trying to connect to an assignment:

[Wed Aug 16 12:05:21.111816 2023] (eval): 

===> Begin WeBWorK::dispatch() <===

[Wed Aug 16 12:05:21.111996 2023] (eval): Hi, I'm the new dispatcher!
[Wed Aug 16 12:05:21.112099 2023] (eval): --------------------------------------------------------------------------------
[Wed Aug 16 12:05:21.112180 2023] (eval): Okay, I got some basic information:
[Wed Aug 16 12:05:21.112254 2023] (eval): The site location is /webwork2
[Wed Aug 16 12:05:21.112324 2023] (eval): The request method is GET
[Wed Aug 16 12:05:21.112457 2023] (eval): The URI is /webwork2/Math223_Wi23_JHlavacek/WhatIsLinearAlgebra
[Wed Aug 16 12:05:21.112536 2023] (eval): The argument string is 
[Wed Aug 16 12:05:21.112606 2023] (eval): --------------------------------------------------------------------------------
[Wed Aug 16 12:05:21.112720 2023] (eval): The path is /Math223_Wi23_JHlavacek/WhatIsLinearAlgebra/
[Wed Aug 16 12:05:21.112816 2023] (eval): The current route is problem_list
[Wed Aug 16 12:05:21.112889 2023] (eval): Here is some information about this route:
[Wed Aug 16 12:05:21.112981 2023] (eval): The display module for this route is WeBWorK::ContentGenerator::ProblemSet
[Wed Aug 16 12:05:21.113054 2023] (eval): This route has the following captures:
[Wed Aug 16 12:05:21.113126 2023] (eval):   courseID => Math223_Wi23_JHlavacek
[Wed Aug 16 12:05:21.113198 2023] (eval):   controller => ProblemSet
[Wed Aug 16 12:05:21.113274 2023] (eval):   setID => WhatIsLinearAlgebra
[Wed Aug 16 12:05:21.113343 2023] (eval):   action => go
[Wed Aug 16 12:05:21.113412 2023] (eval): --------------------------------------------------------------------------------
[Wed Aug 16 12:05:21.113479 2023] (eval): Now we want to look at the parameters we got.
[Wed Aug 16 12:05:21.113546 2023] (eval): The raw params:
[Wed Aug 16 12:05:21.113641 2023] (eval): --------------------------------------------------------------------------------
[Wed Aug 16 12:05:21.113713 2023] (eval): We need to get a course environment (with or without a courseID!)
[Wed Aug 16 12:05:21.121656 2023] (eval): Here's the course environment: WeBWorK::CourseEnvironment=HASH(0x558ce5815cd8)
[Wed Aug 16 12:05:21.122095 2023] (eval): Using user_authen_module WeBWorK::Authen::LTIAdvanced: WeBWorK::Authen::LTIAdvanced=HASH(0x558ce594f4c8)
[Wed Aug 16 12:05:21.122210 2023] (eval): We got a courseID from the route, now we can do some stuff:
[Wed Aug 16 12:05:21.122299 2023] (eval): ...we can create a database object...
[Wed Aug 16 12:05:21.130766 2023] (eval): (here's the DB handle: WeBWorK::DB=HASH(0x558ce5810378))
[Wed Aug 16 12:05:21.130902 2023] WeBWorK::Authen::verify: BEGIN VERIFY
[Wed Aug 16 12:05:21.130991 2023] WeBWorK::Authen::LTIAdvanced::request_has_data_for_this_verification_module: LTIAdvanced has been called for data verification
[Wed Aug 16 12:05:21.131133 2023] WeBWorK::Authen::LTIAdvanced::request_has_data_for_this_verification_module: LTIAdvanced returning that it has insufficent data
[Wed Aug 16 12:05:21.131327 2023] WeBWorK::Authen::verify: BEGIN VERIFY
[Wed Aug 16 12:05:21.131423 2023] WeBWorK::Authen::do_verify: db ok
[Wed Aug 16 12:05:21.131506 2023] WeBWorK::Authen::get_credentials: self is WeBWorK::Authen::Basic_TheLastOption=HASH(0x558ce594f4e0) 
[Wed Aug 16 12:05:21.131715 2023] WeBWorK::Authen::fetchCookie: found no cookie for this course. returning nothing.
[Wed Aug 16 12:05:21.132135 2023] WeBWorK::Authen::verify: END VERIFY
[Wed Aug 16 12:05:21.132228 2023] WeBWorK::Authen::verify: result 0
[Wed Aug 16 12:05:21.132315 2023] (eval): Bad news: authentication failed!
[Wed Aug 16 12:05:21.132389 2023] (eval): Rendering WeBWorK::ContentGenerator::Login

The student is presented with the login screen. It seems like there are no LTI data provided at all.

Here is the contents of my authen_LTI.conf:

#!perl
#
################################################################################################
# Configuration for using LTI authentication.
# To enable this file, uncomment the appropriate lines in localOverrides.conf
# The settings in this file apply to both LTI 1.1 and LTI 1.3 authentication.
# The settings specific to the LTI 1.1 authenticatio are in authen_LTI_1_1.conf.
# The settings specific to the LTI 1.3 authenticatio are in authen_LTI_1_3.conf.
################################################################################################

# Set debug_lti_parameters  to 1 to have LTI calling parameters printed to HTML page for
# debugging.  This is useful when setting things up for the first time because
# different LMS systems have different parameters
$debug_lti_parameters = 1; 

# To get more information on passing grades back to the LMS enmass set debug_lti_grade_passback
# to one.  And set the LTIMassUpdateInterval to 60 (seconds).
$debug_lti_grade_passback = 1;

# This will print into the apache log the success or failure of updating each user/set.

# Setting both debug_lti_parameters and debug_lti_grade_passback will cause the full request and 
# response between the LMS and WW to be printed into apache error log file for each
# user/set  update of the grade.

# The switches above can be set in course.conf to enable debugging for just one course.

# If you want even more information enable the debug facility in the webwork2.mojolicious.yml
# file.  This will print extensive debugging messages for all courses.

# Note that for LTI 1.3 not all debug message will make it back to the HTML page due to the
# nature of how LTI 1.3 authentication works with automatic form submissions and redirects.

################################################################################################
# Authentication settings
################################################################################################

# This section enables LTI authentication.  If a course uses LTI 1.1 (see $LTIVersion below),
# then the LTIAdvanced module will be used.  If a course uses LTI 1.3 (see $LTIVersion below),
# the LTIAdvantage will be used.  If you know a site will not use one or the other, it can be
# commented out. Failover to Basic_TheLastOption is necessary to authenticate with cookie keys.
$authen{user_module} = [
    # { '*' => 'WeBWorK::Authen::LTIAdvantage' },          # first try LTI 1.3
    { '*' => 'WeBWorK::Authen::LTIAdvanced' },           # next try LTI 1.1
    { '*' => 'WeBWorK::Authen::Basic_TheLastOption' }    # fallback authorization method
];

# Include configurations.  You must uncomment at least one of the following. You may uncomment
# both if the site may be using both LTI 1.1 and 1.3 in different courses. After uncommenting
# the LTI_1_x line, you must copy the file authen_LTI_1_x.conf.dist to authen_LTI_1_x.conf and
# then edit that file to fill in the settings for LTI_1_x.
include('conf/authen_LTI_1_1.conf');
#include('conf/authen_LTI_1_3.conf');

# This is the default LTI version that will be used for the site.  This must be 'v1p1' for LTI
# 1.1 authentication, 'v1p3' for LTI 1.3 authentication, or '' to disable LTI authentication.
# A course may override this setting to use the other version of LTI authentication or to
# disable LTI authentication for the course.
$LTIVersion = 'v1p1';

# WeBWorK will automatically create users when logging in via the LMS for the first time as long
# as the permission level is less than or equal to the permission level of this setting.  For
# security reasons accounts with high permissions should not be auto created via LTI requests.
# Set this variable to 'professor' if you want professor accounts to be created automatically.
$LTIAccountCreationCutoff = 'ta';

# If the following flag is enabled then the user demographic data will be kept up to date with
# the data from the LMS.  If a user's information changes in the LMS then it will change in
# WeBWorK. This means that any changes to the student data via WeBWorK will be overwritten the
# next time the student logs in.
$LMSManageUserData = 1;

# If the preferred module is an external authentication module but the sequence includes an
# internal authentication system, e.g., Basic_TheLastOption, then $external_auth (below) must be
# set to 1 (or true). If the value is 1, then, if the authentication sequence reaches
# Basic_TheLastOption, then WeBWorK::Login will display a screen directing the user back to an
# external authentication system.  This prevents you from attempting to login in to WeBWorK
# directly.
$external_auth = 0;

# NOTE:  If external authentication is disabled then you should probably also prevent students
# from changing their passwords (because they can't use them).  To do this uncomment the
# following.
$permissionLevels{change_password} = 'ta';

################################################################################################
# Authorization system LTI:  LMS Grade Passback
################################################################################################

# WeBWorK can automatically report grades back to your LMS.  However the system is reasonably
# restrictive.  When you create an LTI link in your LMS you can choose to have that LTI link
# have a grade associated to it.  WeBWorK can report back a single percentage as the "grade" for
# that link.  There are two modes under which this can occur.

# Single Course Grade Mode:  $LTIGradeMode = 'course';
# In this mode you create a single Link/Assignment which points to your WeBWorK Course address.
# Students will receive a LMS grade associated to the Link/Assignment which is determined by
# their percentage total homework grade in WeBWorK.  This total homework grade is the same as
# the grade that is reported on the grades page.  You can change the weight of sets by altering
# the weight of the problems in the set.

# Individual Homework Grade Mode:  $LTIGradeMode = 'homework';
# In this mode you create a single Link/Assignment for *every* homework set in the course.  The
# address should be the address of that set in the Course.  Students will receive a grade for
# each Link/Assignment which is determined by their percentage homework grade on the Set which
# the Link/Assignment points to.  Students need to use the Link/Assignment in the LMS at least
# once to enable grade passback.  In particular when working in this mode it is recommended that
# you only allow students to log in via the LMS.

# Note: For both of these modes only the grades are passed back.  In particular nothing else
# about the Link/Assignment in the LMS and the homework set in WeBWorK is synchronized.  In
# particular the total number of points/problems, the due dates, the open dates are not kept in
# sync automatically (yet).

# Site Administrator Note for LTI 1.3:  This uses OAuth2 RSA private/public keys.  These keys
# are automatically generated the first time that they are needed.  It is recommended that new
# keys are generated on a regular basis.  At this point, key rotation is not automatic for
# webwork2.  Howevever, it is simple.  Delete the files $webwork2_dir/DATA/lti_private_key.json
# and $webwork2_dir/DATA/lti_public_key.json.  New keys will then be automatically generated the
# next time they are needed.  Probably a good rule of thumb (for now) is to do this at the
# beginning of every term.

#$LTIGradeMode = '';
#$LTIGradeMode = 'course';
$LTIGradeMode = 'homework';

# When set this variable sends grades back to the LMS every time a user submits an answer.  This
# keeps students grades up to date but can be a drain on the server.
$LTIGradeOnSubmit = 1;

# If CheckPrior is set to 1 then the current LMS grade will be checked first, and if the grade
# has not changed then the grade will not be updated.  This is intended to reduce changes to LMS
# records when no real grade change occurred.  It requires a 2 round process, first querying the
# current grade from the LMS and then when needed making the grade submission.
$LTICheckPrior = 1;

# The system periodically updates student grades on the LMS.  This variable controls how often
# that happens.  Set to -1 to disable.
$LTIMassUpdateInterval = 86400;    #in seconds

################################################################################################
# Add an 'LTI' tab to the Course Configuration page
################################################################################################

# Uncomment any of the variables listed in the @LTIConfigVariables array below if you would like
# the Course Configuration page to have an LTI tab, granting the course instructor easy access
# to some of the LTI settings. You may leave some of the variables commented out if you would
# like to omit them from the options in this tab.  If all variables are left commented out, then
# the tab will not be shown.  Note that the default values for the variables that will be shown
# in the LTI tab are the values that are set above.  Further note that only the variables listed
# in LTIConfigValues.config may be added to the LTI config tab.  In addition, only the variables
# that pertain to the active LTI version will be shown in the tab.
@LTIConfigVariables = (
    #'LTI{v1p1}{LMS_name}',
    #'LTI{v1p3}{LMS_name}',
    #'LTI{v1p1}{LMS_url}',
    #'LTI{v1p3}{LMS_url}',
    'external_auth',
    'LTIGradeMode',
    'LMSManageUserData',
    'debug_lti_parameters'
);

1;    # final line of the file to reassure perl that it was read properly.

and here is the authen_LTI_1_1.conf with the secret stuff redacted:

#!perl

################################################################################################
# Configuration for using LTI 1.1 authentication.
# To enable this file, uncomment the appropriate lines in authen_LTI.conf
################################################################################################

# This is a string that is used to name the LMS for end users, for example in a message telling
# users to sign in through their LMS.
$LTI{v1p1}{LMS_name} = 'Canvas';
#$LTI{v1p1}{LMS_name} = 'Desire2Learn';

# This is a URL that should take users to a place they can log in to their LMS.  It will use the
# text from LMS_name, but use LMS_url as the href.  If LMS_url is empty or undefined, the
# text from LMS_name is used with no link.
$LTI{v1p1}{LMS_url} = 'https://canvas.svsu.edu/';
#$LTI{v1p1}{LMS_url} = 'https://myschool.edu/lms/';

################################################################################################
# LTI 1.1 preferred and fallback source of WW user_id
################################################################################################

# You MUST set what LTI field is used to set the WeBWorK user_id.
#
# The lis_person_sourcedid (or one of its variants) is formally an OPTIONAL field
#    https://www.imsglobal.org/specs/ltiv1p1/implementation-guide
# but is relatively consistently available.
# However, some LMS systems, Blackboard in particular, do not send lis_person_sourcedid.
#
# The email address lis_person_contact_email_primary is often a more understandable value but
# may not exist.
#
# The LTI standard recommends providing a "user_id" value, which needs to be a unique identifier
# for each student in the LMS. The value is not expected to be people friendly by may be
# available when neither of the others are.
#
# You need to make sure to use a setting such that
#    (1) usernames are unique and
#    (2) the setting is as compatible as possible with the practices of the institutions that
#        are being served in a site.
#
# If each course is only being used by students from a single institution and the value
# lis_person_sourcedid is unique across that population and matches the logon username at that
# institution, then lis_person_sourcedid is probably the better choice.
#
# On the other hand, if a site is serving a population from several institutions or if the
# lis_person_sourcedid is not necessarily unique across the population, then
# lis_person_contact_email_primary is the better choice.
#
# NOTE: As of WeBWorK 2.16 some setting MUST be made.
#
#       If no setting is made, all LTI logins will fail and an error will be reported.
#
#       See the comment further down on how to get WeBWorK 2.16 to behave similarly to
#       the prior behavior.

# NOTE: Even if a course management system sends one of the common misspellings of
# "lis_person_sourcedid", i.e.,
# lis_person_sourced_id, lis_person_source_id, and lis_person_sourceid,
# one must nevertheless use the correct spelling "lis_person_sourcedid" here.
$LTI{v1p1}{preferred_source_of_username} = 'lis_person_contact_email_primary';
#$LTI{v1p1}{preferred_source_of_username} = 'lis_person_sourcedid';

# You can use any parameter the LMS will provide for the preferred_source_of_username, ex:
#$LTI{v1p1}{preferred_source_of_username} = 'user_id';

# You can also optionally provide a fallback_source_of_username which will only be used if WW is
# unable to determine a user_id using preferred_source_of_username.

# Warning: This can be dangerous, e.g. if the fallback were used for some student, and then on a
# later connection by that student the LMS provided a value for the preferred_source_of_username
# field, then the student will get a new WeBWorK account and lose access to their prior account
# and the prior scores will not be associated with their account any longer. Thus, this feature
# should be used carefully!
#$LTI{v1p1}{fallback_source_of_username} = '';
#$LTI{v1p1}{fallback_source_of_username} = 'lis_person_sourcedid';

# Stripping the domain when creating user_id from an email address:
# If you set either preferred_source_of_username or fallback_source_of_username to
# lis_person_contact_email_primary, and the email is being used as the WeBWorK user_id, then if
# the following setting is enabled, then WeBWorK will strip off the domain portion of the email
# (after the '@') and just use the username.
$LTI{v1p1}{strip_domain_from_email} = 1;

# This feature should not be used if emails could collide after the domain is removed.

# To get WeBWorK 2.16 to handle LTI authentication using an approach roughly the same as was
# used until WeBWorK 2.15, you can set one of the 2 pairs of settings:
#
# Option 1: Primary choice is lis_person_contact_email_primary, fallback to lis_person_sourcedid:
#$LTI{v1p1}{preferred_source_of_username} = 'lis_person_contact_email_primary';
#$LTI{v1p1}{fallback_source_of_username} = 'lis_person_sourcedid';
#
# Option 2: Primary choice is lis_person_sourcedid, fallback to lis_person_contact_email_primary:
#$LTI{v1p1}{preferred_source_of_username} = 'lis_person_sourcedid';
#$LTI{v1p1}{fallback_source_of_username} = 'lis_person_contact_email_primary';

# Depending on the username source, capitalization may vary between students, such as when using
# an email address to get the username. Turning this option on will make all usernames
# lowercase. Default is 0 (off).
$LTI{v1p1}{lowercase_username} = 0;

################################################################################################
# LTI 1.1 Preferred source of Student Id
################################################################################################

# If preferred_source_of_student_id is not set, WeBWorK will set student_id to be an empty
# string. You should use debug_lti_parameters in order to determine the value to use for your
# LMS.

# For example, in D2L, student_id is stored in OrgDefinedId and the corresponding LTI parameter
# is called ext_d2l_orgdefinedid.
$LTI{v1p1}{preferred_source_of_student_id} = "sis_login_id";
#$LTI{v1p1}{preferred_source_of_student_id} = 'ext_d2l_orgdefinedid';

################################################################################################
# LTI 1.1 Basic Authentication Parameters
################################################################################################

# This "shared secret" is entered in the LMS request form and needs to be match the entry here.
# This is used to validate all requests between the LMS and WeBWorK.

# You should choose your own secret word for security and should treat it like a password.
$LTI{v1p1}{BasicConsumerSecret}  = "redacted";  #This must be set  

# The purpose of the LTI nonces is to prevent man-in-the-middle attacks.  The NonceLifeTime (in
# seconds) must be short enough to prevent at least casual man-in-the-middle attacks but long
# enough to accommodate normal server and networking delays (and perhaps non-synchronization of
# server time clocks).
$LTI{v1p1}{NonceLifeTime} = 60;    # in seconds

# This allows you to override the URL that Oauth will use to validate the authentication.  This
# is important if you have some sort of setup (e.g. load distributing) where the path in the LMS
# does not match the path that ends up in the webwork page.
#$LTI{v1p1}{OverrideSiteURL} = '';

# This is like $LTI{v1p1}{OverrideSiteURL}, except that you only declare the protocol and domain
# to replace and leave the rest of a URL alone. If somehow both are set in the config chain,
# $LTI{v1p1}{OverrideSiteURL} is used, without being modified by the below.
#$LTI{v1p1}{OverrideSiteProtocolDomain} = 'https://canvas.svsu.edu';
#$LTI{v1p1}{OverrideSiteProtocolDomain} = 'https://vmwebwork42.myschool.edu';

################################################################################################
# LTI 1.1 LMS Roles Mapped to WeBWorK Roles
################################################################################################

# You may need to customize this hash to take into account the roles that are used in your LMS.
# Set the debug_lti_parameters flag to see what roles are being reported to WeBWorK by your LMS.
$LTI{v1p1}{LMSrolesToWeBWorKroles} = {
    'librarian'               => 'guest',
    'observer'                => 'guest',
    'visitor'                 => 'guest',
    'Guest'                   => 'guest',
    'Designer'                => 'professor',
    'instructor'              => 'professor',
    'Instructor'              => 'professor',
    'Faculty'                 => 'professor',
    'Teacher'                 => 'professor',
    'Student'                 => 'student',
    'Learner'                 => 'student',
    'student'                 => 'student',
    'AI/TA'                   => 'ta',
    'TA'                      => 'ta',
    'Teaching Assistant'      => 'ta',
    'Teaching Assistant (TA)' => 'ta',
    'Non-editing teacher'     => 'ta',
    'Grader'                  => 'ta',
};

################################################################################################
# Local routine to modify users
################################################################################################

# When users are added to the system WeBWorK will do its best to fill out user information.
# However, institutions can add code to the following routine to set fields not normally set by
# WeBWorK.  E.G.  The student ID field.

#$LTI{v1p1}{modify_user} = sub {
# The self object from LTIAdvanced.pm
#my $self = shift;
# The user object to be modified
#my $user = shift;

#my $r = $self->{r};
#my @course_id = split / /, $r->param("context_title");
#$user->{"section"} = $course_id[2];
#};

#  # The self object from LTIAdvanced.pm
#  my $self = shift;
#  # The user object to be modified
#  my $user = shift;
#
#  # Parse context_id for additional information.  E.G.
#  my @course_id = split /-/, $self->{context_id};
#  $user->{section} = $course_id[4];
#};

################################################################################################
# Local routine to modify user sets
################################################################################################

# When users are added to the system they are also assigned all visible sets This routine can be
# used to modify the sets before they are assigned.  E.G.  extend due dates based off the number
# of problems students have to do

#$LTI{v1p1}{modify_user_set} = sub {
#  # The self object from LTIAdvanced.pm
#  my $self      = shift;
#  my $globalSet = shift;
#  # The userSet object to be modified
#  my $userSet = shift;
#
#  my $numberOfSetsAssigned   = $self->{numberOfSetsAssigned};
#  my $daysPerSetMakeup       = 2;
#  my $reasonableNumberOfDays = $numberOfSetsAssigned*$daysPerSetMakeup + 1;
#  if ($reasonableNumberOfDays < 2) { $reasonableNumberOfDays = 2; }
#  my $niceDueTime    = $globalSet->due_date + $reasonableNumberOfDays * 86400;
#  my $niceAnswerTime = $niceDueTime + 600;
#
#  $userSet->due_date($niceDueTime);
#  $userSet->answer_date($niceAnswerTime);
#};

# Do not change this.
$LTI{v1p1}{grader} = 'WeBWorK::Authen::LTIAdvanced::SubmitGrade';

1;    # final line of the file to reassure perl that it was read properly.

Anybody has any idea what am I doing wrong?

Thank you!

In reply to Jan Hlavacek

Re: Canvas LTI authentication broken after upgrade to 2.18

by Jan Hlavacek -
Replying to myself:

It looks like the problem is with my browser. It seems to work in chromium on my computer, and in firefox and chrome on several other computers, but for some reason it is not working in firefox on my laptop.
In reply to Jan Hlavacek

Re: Canvas LTI authentication broken after upgrade to 2.18

by Danny Glin -
This may or may not be the cause of your issues, but LTI tends to have issues with browsers that block third party (or cross-site) cookies.  This setting is turned on in Safari  by default, so usually that's the browser that experiences these sorts of issues.

You can check your cookie settings in Firefox to see if this is enabled: https://support.mozilla.org/en-US/kb/third-party-cookies-firefox-tracking-protection

If this is the cause of your issue, then having the LTI link open in a new window usually gets around this since you're not embedding one website within another.  I'm not familiar with Canvas, but there should be a setting for this.
In reply to Danny Glin

Re: Canvas LTI authentication broken after upgrade to 2.18

by Tural Hamzayev -

Thanks for comment,

I checked with different browsers all had the same. Moreover when Grade submission is disabled student can login, the issue happens only when Grading is enabled either "homework" or "course".