Open edX as LTI Provider -- Anonymous Authentication 500s

Edit 3: Sorry to use the forum as a rubber duck but while trying to make this request more robust I ended up tracking down the root cause to the Foreign Key on lti_provider_ltiuser was for some reason set to the mystery lti_provider_newlticonsumer table’s ID. Dropping the constraint and adding it back pointing at the correct lti_provider_lticonsumer table resolved my issue

I’ve done a bit of digging around the forum and haven’t been able to find any concrete answers on this and definitely not really much movement in the last two years, so here we go:

My team is working on early discovery work to enable open edX as an LTI Provider with the initial goal of integrating with Blackboard but a future goal of (hopefully) not caring what platforms we integrate with

We are using Palm (open-release/palm.2) on tutor 16.1.3

We are enabling the feature with a tutor plugin patch openedx-lms-common-settings with this snippet:

FEATURES['ENABLE_LTI_PROVIDER'] = True

if FEATURES.get('ENABLE_LTI_PROVIDER'):
    INSTALLED_APPS.append('lms.djangoapps.lti_provider.apps.LtiProviderConfig')
    AUTHENTICATION_BACKENDS.append('lms.djangoapps.lti_provider.users.LtiBackend')

This is a fresh Palm installation with all migrations applied and all provider db tables are confirmed to be present like the documentation states, but I was also seeing this exact error on native Juniper, Juniper devstack, and Olive tutor

I’ve been following the documentation about configuring an LTI Tool Provider and have requests from our LTI Consumer successfully authenticating in to our system with the generated ck/cs with no issues, but when our consumers are trying to actually load the content we are getting a 500 error that I haven’t been able to find anyone else having and has actually been consistently reproduced for me across multiple edX installations from native juniper all the way now to tutor palm.

Edit: Unfortunately I was just able to confirm that with a fresh db configuration as per tutor dev quickstart/launch that the problem is not occurring, so it must be something with our database that has been ported forward for multiple releases now. I have no idea where to even begin diagnosing this problem using our deployed databases so any sort of help would be super appreciated, but sort of changes the tone of the post a bit.

Edit2: Upon further review of the tables on my local vs our deployed test environment I’m seeing some weird stuff about the number of tables created for lti_provider in the deployed environment

It has the four tables it’s expected to have:

  • lti_provider_gradedassignment
  • lti_provider_lticonsumer
  • lti_provider_ltiuser
  • lti_provider_outcomeservice

But it also has these erroneous table that I can’t even find mention of in any of our platform code or legacy edx code:

  • lti_provider_nonce
  • lti_provider_newlticonsumer
  • lti_provider_gradesservice

Full stack at end of thread.

This seems to be an issue with anonymous authentication from the Consumer to the Provider, but I haven’t gotten far enough in this process to attempt TPA with it. I’ve been able to reproduce the same stack trace both in Blackboard when trying to load the content and with the saLTIre tool

@sambapete I hate to ping you but I see you’ve also had a lot of work in/around the provider over the last few years, have you ran into anything like this at all? Thanks so much.

2023-06-09 22:57:35,498 ERROR 101027 [root] [user None] [ip None] signals.py:22 - Uncaught exception from None
Traceback (most recent call last):
  File "/edx/app/edxapp/edx-platform/lms/djangoapps/lti_provider/users.py", line 32, in authenticate_lti_user
    lti_user = LtiUser.objects.get(
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/query.py", line 406, in get
    raise self.model.DoesNotExist(
lms.djangoapps.lti_provider.models.LtiUser.DoesNotExist: LtiUser matching query does not exist.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/backends/mysql/base.py", line 71, in execute
    return self.cursor.execute(query, args)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/MySQLdb/cursors.py", line 206, in execute
    res = self._query(query)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/MySQLdb/cursors.py", line 319, in _query
    db.query(q)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/MySQLdb/connections.py", line 254, in query
    _mysql.connection.query(self, query)
MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`edxapp`.`lti_provider_ltiuser`, CONSTRAINT `lti_provider_ltiuser_lti_consumer_id_c1b42ee3_fk_lti_provi` FOREIGN KEY (`lti_consumer_id`) REFERENCES `lti_provider_newlticonsumer` (`id`))')

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/lib/python3.8/contextlib.py", line 75, in inner
    return func(*args, **kwds)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/edx/app/edxapp/edx-platform/common/djangoapps/util/views.py", line 188, in inner
    response = view_func(request, *args, **kwargs)
  File "/edx/app/edxapp/edx-platform/lms/djangoapps/lti_provider/views.py", line 91, in lti_launch
    authenticate_lti_user(request, params['user_id'], lti_consumer)
  File "/edx/app/edxapp/edx-platform/lms/djangoapps/lti_provider/users.py", line 38, in authenticate_lti_user
    lti_user = create_lti_user(lti_user_id, lti_consumer)
  File "/edx/app/edxapp/edx-platform/lms/djangoapps/lti_provider/users.py", line 81, in create_lti_user
    lti_user.save()
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/base.py", line 743, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/base.py", line 780, in save_base
    updated = self._save_table(
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/base.py", line 873, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/base.py", line 910, in _do_insert
    return manager._insert([self], fields=fields, return_id=update_pk,
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/query.py", line 1186, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1377, in execute_sql
    cursor.execute(sql, params)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/db/backends/mysql/base.py", line 71, in execute
    return self.cursor.execute(query, args)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/MySQLdb/cursors.py", line 206, in execute
    res = self._query(query)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/MySQLdb/cursors.py", line 319, in _query
    db.query(q)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/MySQLdb/connections.py", line 254, in query
    _mysql.connection.query(self, query)
django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`edxapp`.`lti_provider_ltiuser`, CONSTRAINT `lti_provider_ltiuser_lti_consumer_id_c1b42ee3_fk_lti_provi` FOREIGN KEY (`lti_consumer_id`) REFERENCES `lti_provider_newlticonsumer` (`id`))')

Sorry, I am on vacation this week and I can’t dig too much into it.

We use LTI on Open edX as a provider for some of our internal Moodle instances. We only use anonymous login through LTI so we only have

ENABLE_LTI_PROVIDER: true

and

'common.djangoapps.third_party_auth.lti.LTIAuthBackend' added to THIRD_PARTY_AUTH_BACKENDS through a plugin.

Note that this is different than what you are doing.

We are still on Nutmeg on our production environment and we have the following tables in MYSQL

  • lti_provider_gradedassignment
  • lti_provider_lticonsumer
  • lti_provider_ltiuser
  • lti_provider_outcomeservice

I do have a test instance with Palm installed. I do not see the following tables:

  • lti_provider_nonce
  • lti_provider_newlticonsumer
  • lti_provider_gradesservice

Could it be an XBlock you have installed previously? I really have no clue where these tables are coming from… Is there any data in them that could give you a hint?

Thanks for the reply on vacation, enjoy your time!

I ended up sorting out the core issue fix, walking through things for posting here helped me organize all the threads/thoughts and eventually settled on those tables being the issue

The Foreign Key on lti_provider_ltiuser was for some reason set to the mystery lti_provider_newlticonsumer table’s ID. Dropping the constraint and adding it back pointing at the correct lti_provider_lticonsumer table resolved things

Did a lot of digging in our legacy code today and still haven’t been able to track down what those three tables are, but between a fresh Tutor not having them and someone else not having them I’m feeling pretty confident in deleting the tables and washing my hands of the issue

1 Like