Skip to content

Commit 8e1e80a

Browse files
Merge branch 'master' into hamzawaleed01/upgrade-edx-enterprise-334c0fe
2 parents fe297b2 + 3a9b436 commit 8e1e80a

4 files changed

Lines changed: 58 additions & 74 deletions

File tree

openedx/core/djangoapps/user_authn/views/login_form.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,12 @@ def login_and_registration_form(request, initial_mode="login"):
187187
log.exception("Unknown tpa_hint provider: %s", ex)
188188

189189
# Redirect to authn MFE if it is enabled
190-
# except if user is an enterprise user with tpa_hint_provider coming from a SAML IDP.
190+
# AND
191+
# user is not an enterprise user
192+
# AND
193+
# tpa_hint_provider is not available
194+
# AND
195+
# user is not coming from a SAML IDP.
191196
saml_provider = False
192197
running_pipeline = pipeline.get(request)
193198
if running_pipeline:
@@ -197,8 +202,10 @@ def login_and_registration_form(request, initial_mode="login"):
197202

198203
enterprise_customer = enterprise_customer_for_request(request)
199204

200-
if should_redirect_to_authn_microfrontend() and not \
201-
(enterprise_customer and tpa_hint_provider and saml_provider):
205+
if should_redirect_to_authn_microfrontend() and \
206+
not enterprise_customer and \
207+
not tpa_hint_provider and \
208+
not saml_provider:
202209

203210
# This is to handle a case where a logged-in cookie is not present but the user is authenticated.
204211
# Note: If we don't handle this learner is redirected to authn MFE and then back to dashboard

openedx/core/djangoapps/user_authn/views/tests/test_logistration.py

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -648,75 +648,6 @@ def test_browser_language_dialent(self):
648648

649649
assert response['Content-Language'] == 'es-es'
650650

651-
@ddt.data(
652-
(None, None, None, True),
653-
({'name': 'Test Enterprise', 'uuid': 'test-uuid'}, None, None, True),
654-
({'name': 'Test Enterprise', 'uuid': 'test-uuid'}, 'test-provider', None, True),
655-
({'name': 'Test Enterprise', 'uuid': 'test-uuid'}, 'test-provider', True, False)
656-
)
657-
@ddt.unpack
658-
@override_settings(FEATURES=FEATURES_WITH_AUTHN_MFE_ENABLED)
659-
def test_enterprise_saml_redirection(self, enterprise_customer_data, provider_id, is_saml, should_redirect):
660-
"""
661-
Test that authentication MFE redirection respects the enterprise + SAML provider conditions.
662-
In particular, verify that if we have an enterprise customer with a SAML-based tpa_hint_provider,
663-
we do NOT redirect to the MFE, but handle the request in LMS. All other combinations should
664-
redirect to the MFE when it's enabled.
665-
"""
666-
if provider_id and is_saml:
667-
self.enable_saml()
668-
self._configure_testshib_provider('TestShib', provider_id)
669-
670-
with (
671-
mock.patch(
672-
'openedx.core.djangoapps.user_authn.views.login_form.enterprise_customer_for_request'
673-
) as mock_ec,
674-
mock.patch(
675-
'openedx.core.djangoapps.user_authn.views.login_form.should_redirect_to_authn_microfrontend'
676-
) as mock_should_redirect,
677-
mock.patch(
678-
'openedx.core.djangoapps.user_authn.views.login_form.third_party_auth.utils.is_saml_provider'
679-
) as mock_is_saml
680-
):
681-
mock_ec.return_value = enterprise_customer_data
682-
mock_should_redirect.return_value = should_redirect
683-
mock_is_saml.return_value = (True, None) if is_saml else (False, None)
684-
685-
params = {}
686-
if provider_id:
687-
params['tpa_hint'] = provider_id
688-
689-
if provider_id and is_saml:
690-
pipeline_target = 'openedx.core.djangoapps.user_authn.views.login_form.third_party_auth.pipeline'
691-
with mock.patch(pipeline_target + '.get') as mock_pipeline:
692-
pipeline_data = {
693-
'backend': 'tpa-saml',
694-
'kwargs': {
695-
'response': {
696-
'idp_name': provider_id
697-
},
698-
'details': {
699-
'email': '[email protected]',
700-
'fullname': 'Test User',
701-
'username': 'testuser'
702-
}
703-
}
704-
}
705-
mock_pipeline.return_value = pipeline_data
706-
response = self.client.get(reverse('signin_user'), params)
707-
else:
708-
response = self.client.get(reverse('signin_user'), params)
709-
710-
if should_redirect:
711-
self.assertRedirects(
712-
response,
713-
settings.AUTHN_MICROFRONTEND_URL + '/login' +
714-
('?' + urlencode(params) if params else ''),
715-
fetch_redirect_response=False
716-
)
717-
else:
718-
self.assertEqual(response.status_code, 200)
719-
720651

721652
@skip_unless_lms
722653
class AccountCreationTestCaseWithSiteOverrides(SiteMixin, TestCase):

xmodule/capa/safe_exec/remote_exec.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from importlib import import_module
88
import requests
99

10-
from codejail.safe_exec import SafeExecException
10+
from codejail.safe_exec import SafeExecException, json_safe
1111
from django.conf import settings
1212
from edx_toggles.toggles import SettingToggle
1313
from requests.exceptions import RequestException, HTTPError
@@ -90,7 +90,21 @@ def send_safe_exec_request_v0(data):
9090
extra_files = data.pop("extra_files")
9191

9292
codejail_service_endpoint = get_codejail_rest_service_endpoint()
93-
payload = json.dumps(data)
93+
94+
# In rare cases an XBlock might introduce `bytes` objects (or other
95+
# non-JSON-serializable objects) into the globals dict. The codejail service
96+
# (via the codejail library) will call `json_safe` on the globals before
97+
# JSON-encoding for the sandbox input, but here we need to call it earlier
98+
# in the process so we can even transport the globals *to* the codejail
99+
# service. Otherwise, we may get a TypeError when constructing the payload.
100+
#
101+
# This is a lossy operation (non-serializable objects will be dropped, and
102+
# bytes converted to strings) but it is the same lossy operation that
103+
# codejail will perform anyhow -- and it should be idempotent.
104+
data_send = {**data}
105+
data_send['globals_dict'] = json_safe(data_send['globals_dict'])
106+
107+
payload = json.dumps(data_send)
94108

95109
try:
96110
response = requests.post(
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Tests for remote codejail execution.
3+
"""
4+
5+
import json
6+
from unittest import TestCase
7+
from unittest.mock import patch
8+
9+
from django.test import override_settings
10+
11+
from xmodule.capa.safe_exec.remote_exec import get_remote_exec
12+
13+
14+
class TestRemoteExec(TestCase):
15+
"""Tests for remote_exec."""
16+
17+
@override_settings(
18+
ENABLE_CODEJAIL_REST_SERVICE=True,
19+
CODE_JAIL_REST_SERVICE_HOST='http://localhost',
20+
)
21+
@patch('requests.post')
22+
def test_json_encode(self, mock_post):
23+
get_remote_exec({
24+
'code': "out = 1 + 1",
25+
'globals_dict': {'some_data': b'bytes', 'unusable': object()},
26+
'extra_files': None,
27+
})
28+
29+
mock_post.assert_called_once()
30+
data_arg = mock_post.call_args_list[0][1]['data']
31+
payload = json.loads(data_arg['payload'])
32+
assert payload['globals_dict'] == {'some_data': 'bytes'}

0 commit comments

Comments
 (0)