diff --git a/common/djangoapps/third_party_auth/management/commands/saml.py b/common/djangoapps/third_party_auth/management/commands/saml.py index 01918157ae0acf6787c408e9395708dd443bc97d..dd2c6c104915bf24e2343093a134ec0d5837fd46 100644 --- a/common/djangoapps/third_party_auth/management/commands/saml.py +++ b/common/djangoapps/third_party_auth/management/commands/saml.py @@ -12,16 +12,14 @@ class Command(BaseCommand): """ manage.py commands to manage SAML/Shibboleth SSO """ help = '''Configure/maintain/update SAML-based SSO''' - def handle(self, *args, **options): - if len(args) != 1: - raise CommandError("saml requires one argument: pull") + def add_arguments(self, parser): + parser.add_argument('--pull', action='store_true', help="Pull updated metadata from external IDPs") + def handle(self, *args, **options): if not SAMLConfiguration.is_enabled(): raise CommandError("SAML support is disabled via SAMLConfiguration.") - subcommand = args[0] - - if subcommand == "pull": + if options['pull']: log_handler = logging.StreamHandler(self.stdout) log_handler.setLevel(logging.DEBUG) log = logging.getLogger('third_party_auth.tasks') diff --git a/common/test/acceptance/tests/lms/test_lms_problems.py b/common/test/acceptance/tests/lms/test_lms_problems.py index 789d0e63dfe7bfcd04e3da901e3828f0b809431f..5cb41bb0817b0b370abc7b4296ef03cec5152c2a 100644 --- a/common/test/acceptance/tests/lms/test_lms_problems.py +++ b/common/test/acceptance/tests/lms/test_lms_problems.py @@ -10,6 +10,7 @@ from ..helpers import UniqueCourseTest from ...pages.studio.auto_auth import AutoAuthPage from ...pages.lms.courseware import CoursewarePage from ...pages.lms.problem import ProblemPage +from ...pages.lms.login_and_register import CombinedLoginAndRegisterPage from ...fixtures.course import CourseFixture, XBlockFixtureDesc from ..helpers import EventsTestMixin @@ -20,6 +21,7 @@ class ProblemsTest(UniqueCourseTest): """ USERNAME = "joe_student" EMAIL = "joe@example.com" + PASSWORD = "keep it secret; keep it safe." def setUp(self): super(ProblemsTest, self).setUp() @@ -42,8 +44,14 @@ class ProblemsTest(UniqueCourseTest): ).install() # Auto-auth register for the course. - AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, - course_id=self.course_id, staff=False).visit() + AutoAuthPage( + self.browser, + username=self.USERNAME, + email=self.EMAIL, + password=self.PASSWORD, + course_id=self.course_id, + staff=False + ).visit() def get_problem(self): """ Subclasses should override this to complete the fixture """ @@ -319,3 +327,85 @@ class ProblemPartialCredit(ProblemsTest): problem_page.fill_answer_numerical('-1') problem_page.click_check() self.assertTrue(problem_page.simpleprob_is_partially_correct()) + + +class LogoutDuringAnswering(ProblemsTest): + """ + Tests for the scenario where a user is logged out (their session expires + or is revoked) just before they click "check" on a problem. + """ + def get_problem(self): + """ + Create a problem. + """ + xml = dedent(""" + <problem> + <p>The answer is 1</p> + <numericalresponse answer="1"> + <formulaequationinput label="where are the songs of spring?" /> + <responseparam type="tolerance" default="0.01" /> + </numericalresponse> + </problem> + """) + return XBlockFixtureDesc('problem', 'TEST PROBLEM', data=xml) + + def log_user_out(self): + """ + Log the user out by deleting their session cookie. + """ + self.browser.delete_cookie('sessionid') + + def test_logout_after_click_redirect(self): + """ + 1) User goes to a problem page. + 2) User fills out an answer to the problem. + 3) User is logged out because their session id is invalidated or removed. + 4) User clicks "check", and sees a confirmation modal asking them to + re-authenticate, since they've just been logged out. + 5) User clicks "ok". + 6) User is redirected to the login page. + 7) User logs in. + 8) User is redirected back to the problem page they started out on. + 9) User is able to submit an answer + """ + self.courseware_page.visit() + problem_page = ProblemPage(self.browser) + self.assertEqual(problem_page.problem_name, 'TEST PROBLEM') + problem_page.fill_answer_numerical('1') + + self.log_user_out() + with problem_page.handle_alert(confirm=True): + problem_page.click_check() + + login_page = CombinedLoginAndRegisterPage(self.browser) + login_page.wait_for_page() + + login_page.login(self.EMAIL, self.PASSWORD) + + problem_page.wait_for_page() + self.assertEqual(problem_page.problem_name, 'TEST PROBLEM') + + problem_page.fill_answer_numerical('1') + problem_page.click_check() + self.assertTrue(problem_page.simpleprob_is_correct()) + + def test_logout_cancel_no_redirect(self): + """ + 1) User goes to a problem page. + 2) User fills out an answer to the problem. + 3) User is logged out because their session id is invalidated or removed. + 4) User clicks "check", and sees a confirmation modal asking them to + re-authenticate, since they've just been logged out. + 5) User clicks "cancel". + 6) User is not redirected to the login page. + """ + self.courseware_page.visit() + problem_page = ProblemPage(self.browser) + self.assertEqual(problem_page.problem_name, 'TEST PROBLEM') + problem_page.fill_answer_numerical('1') + self.log_user_out() + with problem_page.handle_alert(confirm=False): + problem_page.click_check() + + self.assertTrue(problem_page.is_browser_on_page()) + self.assertEqual(problem_page.problem_name, 'TEST PROBLEM') diff --git a/lms/static/js/ajax-error.js b/lms/static/js/ajax-error.js index 460d2511fe6dc9d1c289d6364830695c2e2c771c..6b29d4c24bb1ed483a2be53b23d994e4f3f7af53 100644 --- a/lms/static/js/ajax-error.js +++ b/lms/static/js/ajax-error.js @@ -8,8 +8,8 @@ $(document).ajaxError(function (event, jXHR) { ); if (window.confirm(message)) { - var currentLocation = window.location.href; - window.location.href = '/login?next=' + currentLocation; + var currentLocation = window.location.pathname; + window.location.href = '/login?next=' + encodeURIComponent(currentLocation); }; } }); diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index 8a3eef81eccf365c12797c3f0c9b948ca3c73571..dcacfd10049d59727c07d5b60c17ca9041e90159 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -45,7 +45,7 @@ git+https://github.com/edx/nose.git@99c2aff0ff51bf228bfa5482e97e612c97a23245#egg -e git+https://github.com/edx/django-splash.git@ammar/upgrade-to-django1.8#egg=django-splash==0.2 -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock -e git+https://github.com/edx/edx-ora2.git@mzfr/django18-from-release#egg=ora2==0.2.2 --e git+https://github.com/edx/edx-submissions.git@django-upgrade/1.8#egg=edx-submissions==0.1.2 +-e git+https://github.com/edx/edx-submissions.git@d6fc357831fb85ee6fdd169d0e36bfd29b490e31#egg=edx-submissions==0.1.2 -e git+https://github.com/edx/opaque-keys.git@27dc382ea587483b1e3889a3d19cbd90b9023a06#egg=opaque-keys git+https://github.com/edx/ease.git@release-2015-07-14#egg=ease==0.1.3 git+https://github.com/edx/i18n-tools.git@v0.1.3#egg=i18n-tools==v0.1.3