Skip to content

Commit

Permalink
🐛(lti_toolbox) compute origin_url from consumer url instead of referer
Browse files Browse the repository at this point in the history
Due to LMS instances potentially behind proxies or under subpages, relying on
`HTTP_REFERER` to compute the origin url is not feasible.
Instead, the consumer URL, provided via the LTI passport, can be used to compute
the `origin_url`.
  • Loading branch information
wilbrdt committed Jul 15, 2024
1 parent 821f9ee commit 77ec50b
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed

- Compute `origin_url` from consumer URL instead of `HTTP_REFERER`

## [1.3.0] - 2024-04-25

### Added
Expand Down
3 changes: 2 additions & 1 deletion src/lti_toolbox/factories.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Factories for the ``lti_toolbox``."""

import factory
from factory.django import DjangoModelFactory

Expand All @@ -14,7 +15,7 @@ class Meta:

slug = factory.Sequence(lambda n: f"consumer{n}")
title = factory.Sequence(lambda n: f"Consumer {n}")
url = factory.Sequence(lambda n: f"https://www.example.com/consumer-{n}/")
url = factory.Sequence(lambda n: f"https://testserver/consumer-{n}")


class LTIPassportFactory(DjangoModelFactory):
Expand Down
12 changes: 7 additions & 5 deletions src/lti_toolbox/lti.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""LTI module that supports LTI 1.0.
"""
"""LTI module that supports LTI 1.0."""

import re
from typing import Any, Optional, Set
from urllib.parse import urljoin
Expand Down Expand Up @@ -143,16 +143,18 @@ def get_course_info(self) -> dict:
@property
def origin_url(self):
"""Try to recreate the URL that was used to launch the LTI request."""
base_url = self.request.META.get("HTTP_REFERER")
base_url = self.get_consumer().url
if not base_url:
return None
if not base_url.endswith("/"):
base_url = f"{base_url}/"
context_id = self.get_param("context_id")

url = None
if self.is_edx_format:
url = urljoin(base_url, f"/course/{context_id}")
url = urljoin(base_url, f"course/{context_id}")
elif self.is_moodle_format:
url = urljoin(base_url, f"/course/view.php?id={context_id}")
url = urljoin(base_url, f"course/view.php?id={context_id}")

return url

Expand Down
8 changes: 5 additions & 3 deletions tests/lti_toolbox/test_lti.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the LTI interconnection with an LTI consumer."""

from urllib.parse import urlencode

from django.test import RequestFactory, TestCase
Expand Down Expand Up @@ -34,7 +35,6 @@ def _lti_request(self, signed_parameters, url):
url,
data=urlencode(signed_parameters),
content_type=CONTENT_TYPE,
HTTP_REFERER="http://testserver",
)
return LTI(request)

Expand Down Expand Up @@ -366,7 +366,7 @@ def test_lti_origin_url_edx(self):

self.assertEqual(
lti.origin_url,
"http://testserver/course/course-v1:fooschool+mathematics+0042",
"https://testserver/consumer-20/course/course-v1:fooschool+mathematics+0042",
)

def test_lti_origin_url_moodle(self):
Expand All @@ -381,4 +381,6 @@ def test_lti_origin_url_moodle(self):
}
lti = self._verified_lti_request(lti_parameters)

self.assertEqual(lti.origin_url, "http://testserver/course/view.php?id=123")
self.assertEqual(
lti.origin_url, "https://testserver/consumer-21/course/view.php?id=123"
)

0 comments on commit 77ec50b

Please sign in to comment.