lms.djangoapps.lti_provider package

Contents

lms.djangoapps.lti_provider package#

Subpackages#

Submodules#

lms.djangoapps.lti_provider.apps module#

Configuration for the lti_provider Django application.

class lms.djangoapps.lti_provider.apps.LtiProviderConfig(app_name, app_module)#

Bases: AppConfig

Configuration class for the lti_provider Django application.

name = 'lms.djangoapps.lti_provider'#
ready()#

Override this method in subclasses to run code when Django starts.

verbose_name = 'LTI Provider'#

lms.djangoapps.lti_provider.models module#

Database models for the LTI provider feature.

This app uses migrations. If you make changes to this model, be sure to create an appropriate migration file and check it in at the same time as your model changes. To do that,

  1. Go to the edx-platform dir

  2. ./manage.py lms schemamigration lti_provider –auto “description” –settings=devstack

class lms.djangoapps.lti_provider.models.GradedAssignment(*args, **kwargs)#

Bases: Model

Model representing a single launch of a graded assignment by an individual user. There will be a row created here only if the LTI consumer may require a result to be returned from the LTI launch (determined by the presence of the lis_result_sourcedid parameter in the launch POST). There will be only one row created for a given usage/consumer combination; repeated launches of the same content by the same user from the same LTI consumer will not add new rows to the table.

Some LTI-specified fields use the prefix lis_; this refers to the IMS Learning Information Services standard from which LTI inherits some properties

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

course_key#

DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!

A placeholder class that provides a way to set the attribute on the model.

id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

lis_result_sourcedid#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
outcome_service#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

outcome_service_id#
usage_key#

DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!

A placeholder class that provides a way to set the attribute on the model.

user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
version_number#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class lms.djangoapps.lti_provider.models.LtiConsumer(*args, **kwargs)#

Bases: Model

Database model representing an LTI consumer. This model stores the consumer specific settings, such as the OAuth key/secret pair and any LTI fields that must be persisted.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

consumer_key#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

consumer_name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

consumer_secret#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

static get_or_supplement(instance_guid, consumer_key)#

The instance_guid is the best way to uniquely identify an LTI consumer. However according to the LTI spec, the instance_guid field is optional and so cannot be relied upon to be present.

This method first attempts to find an LtiConsumer by instance_guid. Failing that, it tries to find a record with a matching consumer_key. This can be the case if the LtiConsumer record was created as the result of an LTI launch with no instance_guid.

If the instance_guid is now present, the LtiConsumer model will be supplemented with the instance_guid, to more concretely identify the consumer.

In practice, nearly all major LTI consumers provide an instance_guid, so the fallback mechanism of matching by consumer key should be rarely required.

id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

instance_guid#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

ltiuser_set#

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

objects = <django.db.models.manager.Manager object>#
outcomeservice_set#

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

require_user_account#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

use_lti_pii#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class lms.djangoapps.lti_provider.models.LtiUser(*args, **kwargs)#

Bases: Model

Model mapping the identity of an LTI user to an account on the edX platform. The LTI user_id field is guaranteed to be unique per LTI consumer (per to the LTI spec), so we guarantee a unique mapping from LTI to edX account by using the lti_consumer/lti_user_id tuple.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

edx_user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

edx_user_id#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

lti_consumer#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

lti_consumer_id#
lti_user_id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
class lms.djangoapps.lti_provider.models.OutcomeService(*args, **kwargs)#

Bases: Model

Model for a single outcome service associated with an LTI consumer. Note that a given consumer may have more than one outcome service URL over its lifetime, so we need to store the outcome service separately from the LtiConsumer model.

An outcome service can be identified in two ways, depending on the information provided by an LTI launch. The ideal way to identify the service is by instance_guid, which should uniquely identify a consumer. However that field is optional in the LTI launch, and so if it is missing we can fall back on the consumer key (which should be created uniquely for each consumer although we don’t have a technical way to guarantee that).

Some LTI-specified fields use the prefix lis_; this refers to the IMS Learning Information Services standard from which LTI inherits some properties

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

gradedassignment_set#

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

lis_outcome_service_url#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

lti_consumer#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

lti_consumer_id#
objects = <django.db.models.manager.Manager object>#

lms.djangoapps.lti_provider.outcomes module#

Helper functions for managing interactions with the LTI outcomes service defined in LTI v1.1.

lms.djangoapps.lti_provider.outcomes.check_replace_result_response(response)#

Parse the response sent by the LTI consumer after an score update message has been processed. Return True if the message was properly received, or False if not. The format of this message is defined in the LTI 1.1 spec.

lms.djangoapps.lti_provider.outcomes.generate_replace_result_xml(result_sourcedid, score)#

Create the XML document that contains the new score to be sent to the LTI consumer. The format of this message is defined in the LTI 1.1 spec.

lms.djangoapps.lti_provider.outcomes.get_assignments_for_problem(problem_block, user_id, course_key)#

Trace the parent hierarchy from a given problem to find all blocks that correspond to graded assignment launches for this user. A problem may show up multiple times for a given user; the problem could be embedded in multiple courses (or multiple times in the same course), or the block could be embedded more than once at different granularities (as an individual problem and as a problem in a vertical, for example).

Returns a list of GradedAssignment objects that are associated with the given block for the current user.

lms.djangoapps.lti_provider.outcomes.send_score_update(assignment, score)#

Create and send the XML message to the campus LMS system to update the grade for a single graded assignment.

lms.djangoapps.lti_provider.outcomes.sign_and_send_replace_result(assignment, xml)#

Take the XML document generated in generate_replace_result_xml, and sign it with the consumer key and secret assigned to the consumer. Send the signed message to the LTI consumer.

lms.djangoapps.lti_provider.outcomes.store_outcome_parameters(request_params, user, lti_consumer)#

Determine whether a set of LTI launch parameters contains information about an expected score, and if so create a GradedAssignment record. Create a new OutcomeService record if none exists for the tool consumer, and update any incomplete record with additional data if it is available.

lms.djangoapps.lti_provider.signals module#

Signals handlers for the lti_provider Django app.

lms.djangoapps.lti_provider.signals.increment_assignment_versions(course_key, usage_key, user_id)#

Update the version numbers for all assignments that are affected by a score change event. Returns a list of all affected assignments.

lms.djangoapps.lti_provider.signals.score_changed_handler(sender, **kwargs)#

Consume signals that indicate score changes. See the definition of PROBLEM_WEIGHTED_SCORE_CHANGED for a description of the signal.

lms.djangoapps.lti_provider.signature_validator module#

Subclass of oauthlib’s RequestValidator that checks an OAuth signature.

class lms.djangoapps.lti_provider.signature_validator.SignatureValidator(lti_consumer)#

Bases: RequestValidator

Helper class that verifies the OAuth signature on a request.

The pattern required by the oauthlib library mandates that subclasses of RequestValidator contain instance methods that can be called back into in order to fetch the consumer secret or to check that fields conform to application-specific requirements.

check_client_key(key)#

Verify that the key supplied by the LTI consumer is valid for an LTI launch. This method is only concerned with the structure of the key; whether the key is associated with a known LTI consumer is checked in validate_client_key. This method signature is required by the oauthlib library.

Returns:

True if the client key is valid, or False if it is not.

check_nonce(nonce)#

Verify that the nonce value that accompanies the OAuth signature is valid. This method is concerned only with the structure of the nonce; the validate_timestamp_and_nonce method will check that the nonce has not been used within the specified time frame. This method signature is required by the oauthlib library.

Returns:

True if the OAuth nonce is valid, or False if it is not.

dummy_access_token()#

Unused abstract method from super class. See documentation in RequestValidator

dummy_client()#

Unused abstract method from super class. See documentation in RequestValidator

dummy_request_token()#

Unused abstract method from super class. See documentation in RequestValidator

enforce_ssl = False#
get_access_token_secret(client_key, token, request)#

Unused abstract method from super class. See documentation in RequestValidator

get_client_secret(client_key, request)#

Fetch the client secret from the database. This method signature is required by the oauthlib library.

Returns:

the client secret that corresponds to the supplied key if

present, or None if the key does not exist in the database.

get_default_realms(client_key, request)#

Unused abstract method from super class. See documentation in RequestValidator

get_realms(token, request)#

Unused abstract method from super class. See documentation in RequestValidator

get_redirect_uri(token, request)#

Unused abstract method from super class. See documentation in RequestValidator

get_request_token_secret(client_key, token, request)#

Unused abstract method from super class. See documentation in RequestValidator

get_rsa_key(client_key, request)#

Unused abstract method from super class. See documentation in RequestValidator

invalidate_request_token(client_key, request_token, request)#

Unused abstract method from super class. See documentation in RequestValidator

save_access_token(token, request)#

Unused abstract method from super class. See documentation in RequestValidator

save_request_token(token, request)#

Unused abstract method from super class. See documentation in RequestValidator

save_verifier(token, verifier, request)#

Unused abstract method from super class. See documentation in RequestValidator

validate_access_token(client_key, token, request)#

Unused abstract method from super class. See documentation in RequestValidator

validate_client_key(client_key, request)#

Ensure that the client key supplied with the LTI launch is on that has been generated by our platform, and that it has an associated client secret.

Returns:

True if the key is valid, False if it is not.

validate_realms(client_key, token, request, uri=None, realms=None)#

Unused abstract method from super class. See documentation in RequestValidator

validate_redirect_uri(client_key, redirect_uri, request)#

Unused abstract method from super class. See documentation in RequestValidator

validate_request_token(client_key, token, request)#

Unused abstract method from super class. See documentation in RequestValidator

validate_requested_realms(client_key, realms, request)#

Unused abstract method from super class. See documentation in RequestValidator

validate_timestamp_and_nonce(client_key, timestamp, nonce, request, request_token=None, access_token=None)#

Verify that the request is not too old (according to the timestamp), and that the nonce value has not been used already within the period of time in which the timestamp marks a request as valid. This method signature is required by the oauthlib library.

Returns:

True if the OAuth nonce and timestamp are valid, False if they

are not.

validate_verifier(client_key, token, verifier, request)#

Unused abstract method from super class. See documentation in RequestValidator

verify(request)#

Check the OAuth signature on a request. This method uses the SignatureEndpoint class in the oauthlib library that in turn calls back to the other methods in this class.

Parameters:

request – the HttpRequest object to be verified

Returns:

True if the signature matches, False if it does not.

verify_realms(token, realms, request)#

Unused abstract method from super class. See documentation in RequestValidator

verify_request_token(token, request)#

Unused abstract method from super class. See documentation in RequestValidator

lms.djangoapps.lti_provider.tasks module#

Asynchronous tasks for the LTI provider app.

lms.djangoapps.lti_provider.urls module#

LTI Provider API endpoint urls.

lms.djangoapps.lti_provider.users module#

LTI user management functionality. This module reconciles the two identities that an individual has in the campus LMS platform and on edX.

class lms.djangoapps.lti_provider.users.LtiBackend#

Bases: object

A Django authentication backend that authenticates users via LTI. This backend will only return a User object if it is associated with an LTI identity (i.e. the user was created by the create_lti_user method above).

authenticate(_request, username=None, lti_user_id=None, lti_consumer=None)#

Try to authenticate a user. This method will return a Django user object if a user with the corresponding username exists in the database, and if a record that links that user with an LTI user_id field exists in the LtiUser collection.

If such a user is not found, the method returns None (in line with the authentication backend specification).

get_user(user_id)#

Return the User object for a user that has already been authenticated by this backend.

lms.djangoapps.lti_provider.users.authenticate_lti_user(request, lti_user_id, lti_consumer)#

Determine whether the user specified by the LTI launch has an existing account. If not, create a new Django User model and associate it with an LtiUser object.

If the currently logged-in user does not match the user specified by the LTI launch, log out the old user and log in the LTI identity.

lms.djangoapps.lti_provider.users.create_lti_user(lti_user_id, lti_consumer, profile=None)#

Generate a new user on the edX platform with a random username and password, and associates that account with the LTI identity.

lms.djangoapps.lti_provider.users.generate_random_edx_username()#

Create a valid random edX user ID. An ID is at most 30 characters long, and can contain upper and lowercase letters and numbers. :return:

lms.djangoapps.lti_provider.users.get_lti_user_details(request)#

Returns key LTI user details from the LTI launch request.

lms.djangoapps.lti_provider.users.switch_user(request, lti_user, lti_consumer)#

Log out the current user, and log in using the edX identity associated with the LTI ID.

lms.djangoapps.lti_provider.views module#

LTI Provider view functions

lms.djangoapps.lti_provider.views.get_custom_parameters(params: dict[str]) dict[str]#

Extract all optional LTI parameters from a dictionary. This method does not fail if any parameters are missing.

Parameters:

params – A dictionary containing zero or more parameters.

Returns:

A new dictionary containing all optional parameters from the original dictionary, or an empty dictionary if no optional parameters were present.

lms.djangoapps.lti_provider.views.get_optional_parameters(dictionary)#

Extract all optional LTI parameters from a dictionary. This method does not fail if any parameters are missing.

Parameters:

dictionary – A dictionary containing zero or more optional parameters.

Returns:

A new dictionary containing all optional parameters from the original dictionary, or an empty dictionary if no optional parameters were present.

lms.djangoapps.lti_provider.views.get_required_parameters(dictionary, additional_params=None)#

Extract all required LTI parameters from a dictionary and verify that none are missing.

Parameters:
  • dictionary – The dictionary that should contain all required parameters

  • additional_params – Any expected parameters, beyond those required for the LTI launch.

Returns:

A new dictionary containing all the required parameters from the original dictionary and additional parameters, or None if any expected parameters are missing.

lms.djangoapps.lti_provider.views.lti_launch(request, course_id, usage_id)#

Endpoint for all requests to embed edX content via the LTI protocol. This endpoint will be called by a POST message that contains the parameters for an LTI launch (we support version 1.2 of the LTI specification):

An LTI launch is successful if:
  • The launch contains all the required parameters

  • The launch data is correctly signed using a known client key/secret pair

lms.djangoapps.lti_provider.views.parse_course_and_usage_keys(course_id, usage_id)#

Convert course and usage ID strings into key objects. Return a tuple of (course_key, usage_key), or throw an InvalidKeyError if the translation fails.

lms.djangoapps.lti_provider.views.render_courseware(request, usage_key)#

Render the content requested for the LTI launch. TODO: This method depends on the current refactoring work on the courseware/courseware.html template. It’s signature may change depending on the requirements for that template once the refactoring is complete.

Return an HttpResponse object that contains the template and necessary context to render the courseware.

Module contents#

The LTI Provider app gives a way to launch edX content via a campus LMS platform. LTI is a standard protocol for connecting educational tools, defined by IMS: