mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-02-04 06:22:59 -05:00
wtv
This commit is contained in:
82
lti/views.py
82
lti/views.py
@@ -105,9 +105,22 @@ class OIDCLoginView(View):
|
|||||||
redirect_url = oidc_with_cookies.redirect(target_link_uri)
|
redirect_url = oidc_with_cookies.redirect(target_link_uri)
|
||||||
|
|
||||||
if not redirect_url:
|
if not redirect_url:
|
||||||
state = str(uuid.uuid4())
|
# Generate base state UUID
|
||||||
|
state_uuid = str(uuid.uuid4())
|
||||||
nonce = str(uuid.uuid4())
|
nonce = str(uuid.uuid4())
|
||||||
|
|
||||||
|
# Encode lti_message_hint IN the state parameter for retry reliability
|
||||||
|
# This survives session/cookie issues since it's passed through URLs
|
||||||
|
import base64
|
||||||
|
import json as json_module
|
||||||
|
|
||||||
|
state_data = {'uuid': state_uuid}
|
||||||
|
if lti_message_hint:
|
||||||
|
state_data['hint'] = lti_message_hint
|
||||||
|
|
||||||
|
# Encode as base64 URL-safe string
|
||||||
|
state = base64.urlsafe_b64encode(json_module.dumps(state_data).encode()).decode().rstrip('=')
|
||||||
|
|
||||||
launch_data = {'target_link_uri': target_link_uri, 'nonce': nonce}
|
launch_data = {'target_link_uri': target_link_uri, 'nonce': nonce}
|
||||||
# Store cmid if provided (including 0 for filter-based launches)
|
# Store cmid if provided (including 0 for filter-based launches)
|
||||||
if cmid is not None:
|
if cmid is not None:
|
||||||
@@ -116,7 +129,8 @@ class OIDCLoginView(View):
|
|||||||
if lti_message_hint:
|
if lti_message_hint:
|
||||||
launch_data['lti_message_hint'] = lti_message_hint
|
launch_data['lti_message_hint'] = lti_message_hint
|
||||||
|
|
||||||
session_service.save_launch_data(f'state-{state}', launch_data)
|
# Store using the UUID part of state
|
||||||
|
session_service.save_launch_data(f'state-{state_uuid}', launch_data)
|
||||||
|
|
||||||
# Also store lti_message_hint in regular session for retry mechanism
|
# Also store lti_message_hint in regular session for retry mechanism
|
||||||
# (state-specific storage might be lost due to cookie issues)
|
# (state-specific storage might be lost due to cookie issues)
|
||||||
@@ -341,15 +355,30 @@ class LaunchView(View):
|
|||||||
id_token = request.POST.get('id_token')
|
id_token = request.POST.get('id_token')
|
||||||
state = request.POST.get('state')
|
state = request.POST.get('state')
|
||||||
|
|
||||||
# Log all POST parameters to debug
|
|
||||||
logger.error(f"[LTI RETRY DEBUG] POST keys: {list(request.POST.keys())}")
|
|
||||||
for key in request.POST.keys():
|
|
||||||
if key != 'id_token': # Don't log the full JWT
|
|
||||||
logger.error(f"[LTI RETRY DEBUG] POST[{key}] = {request.POST.get(key)}")
|
|
||||||
|
|
||||||
if not id_token:
|
if not id_token:
|
||||||
raise ValueError("No id_token available for retry")
|
raise ValueError("No id_token available for retry")
|
||||||
|
|
||||||
|
# Decode state to extract lti_message_hint (encoded during OIDC login)
|
||||||
|
import base64
|
||||||
|
import json as json_module
|
||||||
|
|
||||||
|
lti_message_hint_from_state = None
|
||||||
|
try:
|
||||||
|
# Add padding if needed for base64 decode
|
||||||
|
padding = 4 - (len(state) % 4)
|
||||||
|
if padding and padding != 4:
|
||||||
|
state_padded = state + ('=' * padding)
|
||||||
|
else:
|
||||||
|
state_padded = state
|
||||||
|
|
||||||
|
state_decoded = base64.urlsafe_b64decode(state_padded.encode()).decode()
|
||||||
|
state_data = json_module.loads(state_decoded)
|
||||||
|
lti_message_hint_from_state = state_data.get('hint')
|
||||||
|
logger.error(f"[LTI RETRY] Decoded state, found hint: {bool(lti_message_hint_from_state)}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[LTI RETRY] Could not decode state (might be plain UUID): {e}")
|
||||||
|
# State might be a plain UUID from older code, that's OK
|
||||||
|
|
||||||
# Decode JWT to extract issuer and target info (no verification needed for this)
|
# Decode JWT to extract issuer and target info (no verification needed for this)
|
||||||
unverified = jwt.decode(id_token, options={"verify_signature": False})
|
unverified = jwt.decode(id_token, options={"verify_signature": False})
|
||||||
|
|
||||||
@@ -386,37 +415,12 @@ class LaunchView(View):
|
|||||||
'login_hint': login_hint,
|
'login_hint': login_hint,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Moodle doesn't send lti_message_hint in POST, so reconstruct it from JWT
|
# Use lti_message_hint decoded from state parameter
|
||||||
# Format: {"cmid": X, "launchid": "ltilaunch..."}
|
if lti_message_hint_from_state:
|
||||||
import json
|
params['lti_message_hint'] = lti_message_hint_from_state
|
||||||
import random
|
logger.error(f"[LTI RETRY] Using lti_message_hint from state: {lti_message_hint_from_state}")
|
||||||
|
else:
|
||||||
# Get resource link from JWT
|
logger.error("[LTI RETRY] No lti_message_hint available - Moodle may reject retry")
|
||||||
resource_link = unverified.get('https://purl.imsglobal.org/spec/lti/claim/resource_link', {})
|
|
||||||
resource_link_id = resource_link.get('id', '')
|
|
||||||
|
|
||||||
# Try to extract cmid from resource_link_id (Moodle format)
|
|
||||||
cmid = 0 # Default for filter launches
|
|
||||||
if resource_link_id:
|
|
||||||
# Moodle resource link IDs often contain the cmid
|
|
||||||
try:
|
|
||||||
# Common Moodle format: contains numbers
|
|
||||||
import re
|
|
||||||
|
|
||||||
numbers = re.findall(r'\d+', resource_link_id)
|
|
||||||
if numbers:
|
|
||||||
cmid = int(numbers[0])
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Generate a dummy launchid (Moodle format: ltilaunchX_RANDOM)
|
|
||||||
launchid = f"ltilaunch{cmid}_{random.randint(100000000, 999999999)}"
|
|
||||||
|
|
||||||
# Reconstruct lti_message_hint
|
|
||||||
lti_message_hint = json.dumps({"cmid": cmid, "launchid": launchid})
|
|
||||||
params['lti_message_hint'] = lti_message_hint
|
|
||||||
|
|
||||||
logger.error(f"[LTI RETRY] Reconstructed lti_message_hint: {lti_message_hint}")
|
|
||||||
|
|
||||||
# Add retry indicator
|
# Add retry indicator
|
||||||
params['retry'] = retry_count + 1
|
params['retry'] = retry_count + 1
|
||||||
|
|||||||
Reference in New Issue
Block a user