Code Monkey home page Code Monkey logo

django-lti's Introduction

django-lti

A Django reusable app providing support for LTI Advantage.

Installation

Install using pip.

pip install django-lti

Setup

Start by adding lti_tool to your project's INSTALLED_APPS.

INSTALLED_APPS = [
    ...
    "lti_tool",
]

Then, add lti_tool.middleware.LtiLaunchMiddleware to the MIDDLEWARE setting. It's important to list the LtiLaunchMiddleware after SessionMiddleware.

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'lti_tool.middleware.LtiLaunchMiddleware',
]

Finally, run migrations to initialize the needed database tables.

python manage.py migrate lti_tool

Usage

Adding JWKS and OIDC initiation URLs

To allow LTI platforms to retrieve a JWKS and initiate a launch, add paths for lti_tool.views.jwks and lti_tool.views.OIDCLoginInitView to urls.py

...

from lti_tool.views import jwks, OIDCLoginInitView

urlpatterns = [
    path(".well-known/jwks.json", jwks, name="jwks"),
    path("init/<uuid:registration_uuid>/", OIDCLoginInitView.as_view(), name="init"),
]

Generating and rotating keys

Keys for the JWKS can be generated using the rotate_keys management command.

python manage.py rotate_keys

Registering an LTI platform

An LTI platform can be registered through the Django admin, or using a custom interface.

Handling an LTI launch

To handle the LTI launch, inherit from LtiLaunchBaseView and implement the handler methods for the types of LTI message types that the application supports.

class ApplicationLaunchView(LtiLaunchBaseView):

    def handle_resource_launch(self, request, lti_launch):
        ...  # Required. Typically redirects the users to the appropriate page.

    def handle_deep_linking_launch(self, request, lti_launch):
        ...  # Optional.

    def handle_submission_review_launch(self, request, lti_launch):
        ...  # Optional.

    def handle_data_privacy_launch(self, request, lti_launch):
        ...  # Optional.

Each handler method receives the request, as well as a LtiLaunch object.

When a session is initiated by an LTI launch, data about the launch is available from the request at request.lti_launch as an LtiLaunch object. During a non-LTI session request.lti_launch will refer to an AbsentLtiLaunch object.

It is possible to distinguish between LtiLaunch and AbsentLtiLaunch objects using the .is_present and .is_absent properties.

django-lti's People

Contributors

cmurtaugh avatar dependabot[bot] avatar michaelwheeler avatar nikolas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

django-lti's Issues

Add Authentication Backend

It seems like it might be useful to create a Django Authentication Backend to allow apps to authenticate users based on LTILaunch information.

The backend might be something as simple as:

from django.contrib.auth.backends import BaseBackend

class LtiLaunchAuthenticationBackend(BaseBackend):
    def authenticate(self, request, lti_launch=None):
        return lti_launch.user.auth_user

Add support for LTI Dynamic Registration

Spec available at https://www.imsglobal.org/spec/lti-dr/v1p0

Defines a way to automate the exchange of registration information between platforms and tools that use the OpenId Connect and oAuth 2 registration flows, allowing platform administrators to automate tool registrations and avoid tedious and possibly error prone manual configuration while remaining in control of granting or denying tools access to the platform.

Provide launch dimensions as a NamedTuple

Via @doreilly

This is definitely not important for now, but it might be nice to consider whether this is worthwhile to be represented as a Namedtuple. I'm imagining a time where we might want to expose that to a frontend as a dictionary/ESObject, or maybe we want to do a test to see if we're only allowed to be x pixels wide, and destructuring a tuple might be a little strange compared to an attribute access.

Update deprecated input names

Seeing these warnings during the packaging workflow.

Warning: Input 'repository_url' has been deprecated with message: The inputs have been normalized to use kebab-case. Use `repository-url` instead.
Warning: Input 'skip_existing' has been deprecated with message: The inputs have been normalized to use kebab-case. Use `skip-existing` instead.

Appears to originate here...

repository_url: https://test.pypi.org/legacy/
skip_existing: true

Store and use platform audience

This value can optionally be provided by the platform, in which case it will be used by the tool when requesting an auth token.

Add AGS support

At a minimum...

  • Syncing lineitems
  • Creating lineitems
  • Syncing results
  • Sending a score to a lineitem

Handle launches from identical context IDs across deployments

In Canvas it is possible to add multiple placements of a tool to a single course, but using different deployment IDs. While this isn't recommended behavior, it isn't contrary to the description of context.id in the spec.

id (REQUIRED). Stable identifier that uniquely identifies the context from which the LTI message initiates. The context id MUST be locally unique to the deployment_id. It is recommended to also be locally unique to iss (Issuer). The value of id MUST NOT exceed 255 ASCII characters in length and is case-sensitive.

Two contexts with the same ID currently cause launches to fail during retrieval of LtiLaunch.membership.

Add support for LTI 1.1 migration claim

This library could use the LTI 1.1 migration claim in a few ways.

  1. Add fields for LTI 1.1 IDs to LtiUser, LtiContext, and LtiPlatformInstance
  2. Sync those fields when the LTI 1.1 migration claim is present in a launch
  3. Add methods to LtiLaunch to retrieve oauth_consumer_key and its verification status

Fix Cookie problems by implementing Client Side postMessages

First of all, I would like to thank you for your work on this package. We've been using it for a little while at the company I work for, and are very happy with it.

Also, if you just want to read my question, read the last paragraph ;)

Background

The Cookie Problems

Third-party cookies are being blocked by web browsers. By my tests on macOS, at least Safari and Chrome block the cookies. Cookies are being used in the OpenID Connect flow to keep track of the state (in PyLTI1.3), and the fact that there are issues is being acknowledged by the developer of PyLTI1.3. Unfortunately, the mentioned fixes do not work for deep linking, which seems to be needed to be opened in an iframe.

The solutions provided by 1EdTech (still in review and comment status)

As you might know, the solution provided by the proposed specification is to use postMessages.
The specifications, copied and pasted from 1EdTech:
OIDC Login with LTI Client Site PostMessages (start here)
LTI Client Side postMessages
LTI postMessage Storage

Maintainer difficulties PyLTI1.3

The current maintainer of PyLTI1.3 indicated that he does not have time for implementing new features, and that also seems to be the case for reviewing PRs, as you can see with #3 and the PR that has been made upstream.

Implementation of the postMessage solution

At my work, we're trying to patch some classes and implement the postMessage solution ourselves. Although I must admit that the implantation is very much incomplete at this moment. We're willing to collaborate on it, and/or write the code and try to push that code upstream, and make sure it's available for the open-source community.

I guess the main question that we have is: Have you already had a look at the postMessage specification, and have you been thinking of implementing it in this repo? Especially, as probably creating a PR in PyLTI1.3 won't be merged.

Another source on this matter: unicon.net

Support more secure Content-Security-Policy headers

Currently to make Django projects embeddable within an LMS, we need to disable the django.middleware.clickjacking.XFrameOptionsMiddleware middleware. This eliminates a barrier, but opens the site up to potential clickjacking attacks. The more flexible and recommended way of handling these security restrictions is to use Content-Security-Policy headers, with frame-ancestors listing allowable domains. It might be a good idea to have some functionality built into our library to automatically generate the list of allowable domains with the set of active platforms or registrations.

Prevent running publishing workflow on forks

The test-publish job will fail with running from a fork.

test-publish:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v2
with:
python-version: "3.9"
- uses: actions/download-artifact@v3
with:
name: package-build
path: dist/
- uses: pypa/[email protected]
with:
user: __token__
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
skip_existing: true
verbose: true

Disable test-publish when credentials are not present

The test-publish job fails on PRs from dependabot forks (and probably all forks).

Notice: Attempting to perform trusted publishing exchange to retrieve a temporary short-lived API token for authentication against https://test.pypi.org/legacy/ due to __token__ username with no supplied password field
Error: Trusted publishing exchange failure: 
OpenID Connect token retrieval failed: GitHub: missing or insufficient OIDC token permissions, the ACTIONS_ID_TOKEN_REQUEST_TOKEN environment variable was unset

This generally indicates a workflow configuration error, such as insufficient
permissions. Make sure that your workflow has `id-token: write` configured
at the job level, e.g.:

permissions:
  id-token: write

Learn more at https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.