mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-01-20 07:12:58 -05:00
exp
This commit is contained in:
@@ -6,6 +6,7 @@ Provides Django-specific implementations for PyLTI1p3 interfaces
|
||||
|
||||
import json
|
||||
import time
|
||||
import uuid
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
import jwt
|
||||
@@ -192,6 +193,8 @@ class DjangoServiceConnector(ServiceConnector):
|
||||
self._access_token_expires = 0
|
||||
|
||||
def get_access_token(self, scopes):
|
||||
print(f"Requesting access token for scopes: {scopes}")
|
||||
|
||||
if self._access_token and time.time() < self._access_token_expires:
|
||||
return self._access_token
|
||||
|
||||
@@ -200,14 +203,19 @@ class DjangoServiceConnector(ServiceConnector):
|
||||
pem_bytes = jwk_obj.export_to_pem(private_key=True, password=None)
|
||||
private_key = serialization.load_pem_private_key(pem_bytes, password=None, backend=default_backend())
|
||||
|
||||
# Use configured audience if available, otherwise auth_token_url
|
||||
# Moodle expects auth_token_url as audience usually, but some platforms differ
|
||||
aud = self._registration.get_auth_audience() if self._registration.get_auth_audience() else self._registration.get_auth_token_url()
|
||||
print(f"Using audience for token request: {aud}")
|
||||
|
||||
now = int(time.time())
|
||||
payload = {
|
||||
'iss': self._registration.get_client_id(),
|
||||
'sub': self._registration.get_client_id(),
|
||||
'aud': self._registration.get_auth_token_url(),
|
||||
'aud': aud,
|
||||
'iat': now,
|
||||
'exp': now + 300,
|
||||
'jti': str(time.time()),
|
||||
'jti': str(uuid.uuid4()),
|
||||
}
|
||||
|
||||
client_assertion = jwt.encode(payload, private_key, algorithm='RS256', headers={'kid': key_obj.private_key_jwk['kid']})
|
||||
@@ -220,7 +228,10 @@ class DjangoServiceConnector(ServiceConnector):
|
||||
'scope': ' '.join(scopes),
|
||||
}
|
||||
|
||||
print(f"Posting to token URL: {token_url}")
|
||||
response = requests.post(token_url, data=data, timeout=10)
|
||||
if not response.ok:
|
||||
print(f"Token request failed: {response.status_code} {response.text}")
|
||||
response.raise_for_status()
|
||||
|
||||
token_data = response.json()
|
||||
@@ -240,11 +251,14 @@ class DjangoServiceConnector(ServiceConnector):
|
||||
if 'accept' in kwargs:
|
||||
headers['Accept'] = kwargs['accept']
|
||||
|
||||
print(f"Making service request to: {url}")
|
||||
if is_post:
|
||||
response = requests.post(url, json=data, headers=headers, timeout=10)
|
||||
else:
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
|
||||
print(f"Service response status: {response.status_code}")
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
try:
|
||||
|
||||
@@ -201,7 +201,8 @@ class SelectMediaView(View):
|
||||
lti_content_items.append(lti_item)
|
||||
|
||||
# Create JWT payload
|
||||
tool_issuer = request.build_absolute_uri('/')[:-1]
|
||||
# Use client_id as issuer to avoid "wrong consumer key" errors in Moodle
|
||||
tool_issuer = platform.client_id
|
||||
|
||||
# Per LTI spec, aud should be the platform's issuer URL
|
||||
# Try just the platform URL (some Moodle versions don't accept arrays)
|
||||
|
||||
@@ -5,6 +5,7 @@ Fetches course membership from Moodle via NRPS and syncs to MediaCMS RBAC groups
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import traceback
|
||||
|
||||
from allauth.account.models import EmailAddress
|
||||
from django.utils import timezone
|
||||
@@ -65,7 +66,9 @@ class LTINRPSClient:
|
||||
|
||||
return members
|
||||
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print(f"Error fetching members: {e}")
|
||||
traceback.print_exc()
|
||||
return []
|
||||
|
||||
def sync_members_to_rbac_group(self, rbac_group):
|
||||
@@ -100,7 +103,9 @@ class LTINRPSClient:
|
||||
|
||||
synced_count += 1
|
||||
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print(f"Error syncing user {member.get('user_id')}: {e}")
|
||||
traceback.print_exc()
|
||||
continue
|
||||
|
||||
removed_count = 0
|
||||
|
||||
14
lti/views.py
14
lti/views.py
@@ -109,6 +109,8 @@ class OIDCLoginView(View):
|
||||
params = {
|
||||
'response_type': 'id_token',
|
||||
'redirect_uri': target_link_uri,
|
||||
# PyLTI1p3 OIDCLogin.redirect() sets cookie with state
|
||||
# But Moodle might need it in the return
|
||||
'state': state,
|
||||
'client_id': client_id,
|
||||
'login_hint': login_hint,
|
||||
@@ -157,8 +159,20 @@ class LaunchView(View):
|
||||
raise ValueError("Missing id_token in launch request")
|
||||
|
||||
unverified = jwt.decode(id_token, options={"verify_signature": False})
|
||||
|
||||
# Debug logging
|
||||
print("LTI LAUNCH UNVERIFIED HEADER:", jwt.get_unverified_header(id_token))
|
||||
print("LTI LAUNCH UNVERIFIED PAYLOAD:", unverified)
|
||||
|
||||
iss = unverified.get('iss')
|
||||
|
||||
# Handle Moodle issuer variations (some versions have trailing slash)
|
||||
# Check exact match first, then try with/without slash
|
||||
# This is a common issue with LTI 1.3 integrations
|
||||
aud = unverified.get('aud')
|
||||
if isinstance(aud, list):
|
||||
aud = aud[0]
|
||||
|
||||
try:
|
||||
platform = LTIPlatform.objects.get(platform_id=iss, client_id=aud)
|
||||
except LTIPlatform.DoesNotExist:
|
||||
|
||||
Reference in New Issue
Block a user