Studio login/registration redirects to LMS
This commit is contained in:
@@ -309,7 +309,7 @@ class AuthTestCase(ContentStoreTestCase):
|
||||
resp = self.client.get_html(course_url)
|
||||
|
||||
# re-request, and we should get a redirect to login page
|
||||
self.assertRedirects(resp, settings.LOGIN_REDIRECT_URL + '?next=/home/')
|
||||
self.assertRedirects(resp, settings.LOGIN_URL + '?next=/home/')
|
||||
|
||||
@mock.patch.dict(settings.FEATURES, {"ALLOW_PUBLIC_ACCOUNT_CREATION": False})
|
||||
def test_signup_button_index_page(self):
|
||||
|
||||
@@ -4,6 +4,7 @@ Public views
|
||||
from django.conf import settings
|
||||
from django.template.context_processors import csrf
|
||||
from django.urls import reverse
|
||||
from django.utils.http import urlquote_plus
|
||||
from django.shortcuts import redirect
|
||||
from django.views.decorators.clickjacking import xframe_options_deny
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
@@ -14,7 +15,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
|
||||
from waffle.decorators import waffle_switch
|
||||
from contentstore.config import waffle
|
||||
|
||||
__all__ = ['signup', 'login_page', 'howitworks', 'accessibility']
|
||||
__all__ = ['signup', 'login_page', 'login_redirect_to_lms', 'howitworks', 'accessibility']
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@@ -66,6 +67,20 @@ def login_page(request):
|
||||
)
|
||||
|
||||
|
||||
def login_redirect_to_lms(request):
|
||||
"""
|
||||
This view redirects to the LMS login view. It is used for Django's LOGIN_URL
|
||||
setting, which is where unauthenticated requests to protected endpoints are redirected.
|
||||
"""
|
||||
next_url = request.GET.get('next')
|
||||
absolute_next_url = request.build_absolute_uri(next_url)
|
||||
login_url = '{base_url}/login{params}'.format(
|
||||
base_url=settings.LMS_ROOT_URL,
|
||||
params='?next=' + urlquote_plus(absolute_next_url) if next_url else '',
|
||||
)
|
||||
return redirect(login_url)
|
||||
|
||||
|
||||
def howitworks(request):
|
||||
"Proxy view"
|
||||
if request.user.is_authenticated:
|
||||
|
||||
@@ -148,7 +148,7 @@ MOCK_SEARCH_BACKING_FILE = (
|
||||
# this secret key should be the same as lms/envs/bok_choy.py's
|
||||
SECRET_KEY = "very_secret_bok_choy_key"
|
||||
|
||||
LMS_ROOT_URL = "http://localhost:8000"
|
||||
LMS_ROOT_URL = "http://localhost:8003"
|
||||
if RELEASE_LINE == "master":
|
||||
# On master, acceptance tests use edX books, not the default Open edX books.
|
||||
HELP_TOKENS_BOOKS = {
|
||||
|
||||
@@ -6,9 +6,10 @@ Settings for Bok Choy tests that are used when running Studio in Docker-based de
|
||||
# noinspection PyUnresolvedReferences
|
||||
from .bok_choy import * # pylint: disable=wildcard-import
|
||||
|
||||
CMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ['BOK_CHOY_CMS_PORT'])
|
||||
LMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ['BOK_CHOY_LMS_PORT'])
|
||||
CMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ.get('BOK_CHOY_CMS_PORT', 8031))
|
||||
LMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ.get('BOK_CHOY_LMS_PORT', 8003))
|
||||
LMS_ROOT_URL = 'http://{}'.format(LMS_BASE)
|
||||
LOGIN_REDIRECT_WHITELIST = [CMS_BASE]
|
||||
|
||||
COMMENTS_SERVICE_URL = 'http://{}:4567'.format(os.environ['BOK_CHOY_HOSTNAME'])
|
||||
EDXNOTES_PUBLIC_API = 'http://{}:8042/api/v1'.format(os.environ['BOK_CHOY_HOSTNAME'])
|
||||
|
||||
@@ -146,6 +146,7 @@ from lms.envs.common import (
|
||||
_make_locale_paths,
|
||||
)
|
||||
from path import Path as path
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
|
||||
from cms.lib.xblock.authoring_mixin import AuthoringMixin
|
||||
@@ -371,6 +372,7 @@ CONTEXT_PROCESSORS = (
|
||||
'django.contrib.auth.context_processors.auth', # this is required for admin
|
||||
'django.template.context_processors.csrf',
|
||||
'help_tokens.context_processor',
|
||||
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
|
||||
)
|
||||
|
||||
# Django templating
|
||||
@@ -426,9 +428,8 @@ DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
|
||||
##############################################################################
|
||||
|
||||
EDX_ROOT_URL = ''
|
||||
|
||||
LOGIN_REDIRECT_URL = EDX_ROOT_URL + '/signin'
|
||||
LOGIN_URL = EDX_ROOT_URL + '/signin'
|
||||
LOGIN_REDIRECT_URL = EDX_ROOT_URL + '/home/'
|
||||
LOGIN_URL = reverse_lazy('login_redirect_to_lms')
|
||||
|
||||
# use the ratelimit backend to prevent brute force attacks
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
|
||||
@@ -9,8 +9,8 @@ LOGGING['handlers']['local'] = LOGGING['handlers']['tracking'] = {
|
||||
|
||||
LOGGING['loggers']['tracking']['handlers'] = ['console']
|
||||
|
||||
LMS_BASE = 'edx.devstack.lms:18000'
|
||||
CMS_BASE = 'edx.devstack.studio:18010'
|
||||
LMS_BASE = 'localhost:18000'
|
||||
CMS_BASE = 'localhost:18010'
|
||||
LMS_ROOT_URL = 'http://{}'.format(LMS_BASE)
|
||||
|
||||
FEATURES.update({
|
||||
|
||||
@@ -134,6 +134,7 @@ if os.environ.get('DISABLE_MIGRATIONS'):
|
||||
LMS_BASE = "localhost:8000"
|
||||
LMS_ROOT_URL = "http://{}".format(LMS_BASE)
|
||||
FEATURES['PREVIEW_LMS_BASE'] = "preview.localhost"
|
||||
LOGIN_URL = EDX_ROOT_URL + '/signin'
|
||||
|
||||
|
||||
CACHES = {
|
||||
|
||||
@@ -229,6 +229,10 @@
|
||||
</nav>
|
||||
|
||||
% else:
|
||||
<%
|
||||
login_url = settings.LMS_ROOT_URL + '/login'
|
||||
register_url = settings.LMS_ROOT_URL + '/register'
|
||||
%>
|
||||
<nav class="nav-not-signedin nav-pitch" aria-label="${_('Account')}">
|
||||
<h2 class="sr-only">${_("Account Navigation")}</h2>
|
||||
<ol>
|
||||
@@ -237,11 +241,11 @@
|
||||
</li>
|
||||
% if static.get_value('ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION')):
|
||||
<li class="nav-item nav-not-signedin-signup">
|
||||
<a class="action action-signup" href="${reverse('signup')}">${_("Sign Up")}</a>
|
||||
<a class="action action-signup" href="${register_url}?next=${current_url}">${_("Sign Up")}</a>
|
||||
</li>
|
||||
% endif
|
||||
<li class="nav-item nav-not-signedin-signin">
|
||||
<a class="action action-signin" href="${reverse('login')}">${_("Sign In")}</a>
|
||||
<a class="action action-signin" href="${login_url}?next=${current_url}">${_("Sign In")}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
</span>
|
||||
<span class="icon fa fa-caret-down ui-toggle-dd" aria-hidden="true"></span>
|
||||
</h3>
|
||||
|
||||
<%
|
||||
logout_url = settings.LMS_ROOT_URL + '/logout'
|
||||
%>
|
||||
<div class="wrapper wrapper-nav-sub">
|
||||
<div class="nav-sub">
|
||||
<ul>
|
||||
@@ -52,7 +54,7 @@
|
||||
</li>
|
||||
% endif
|
||||
<li class="nav-item nav-account-signout">
|
||||
<a class="action action-signout" href="${reverse('logout')}">${_("Sign Out")}</a>
|
||||
<a class="action action-signout" href="${logout_url}?next=${current_site_url}">${_("Sign Out")}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -83,6 +83,7 @@ urlpatterns = [
|
||||
url(r'^howitworks$', contentstore.views.howitworks, name='howitworks'),
|
||||
url(r'^signup$', contentstore.views.signup, name='signup'),
|
||||
url(r'^signin$', contentstore.views.login_page, name='login'),
|
||||
url(r'^signin_redirect_to_lms$', contentstore.views.login_redirect_to_lms, name='login_redirect_to_lms'),
|
||||
url(r'^request_course_creator$', contentstore.views.request_course_creator, name='request_course_creator'),
|
||||
url(r'^course_team/{}(?:/(?P<email>.+))?$'.format(COURSELIKE_KEY_PATTERN),
|
||||
contentstore.views.course_team_handler, name='course_team_handler'),
|
||||
|
||||
@@ -67,12 +67,8 @@ from openedx.features.journals.api import get_journals_context
|
||||
from student.forms import AccountCreationForm, PasswordResetFormNoActive, get_registration_extension_form
|
||||
from student.helpers import (
|
||||
DISABLE_UNENROLL_CERT_STATES,
|
||||
auth_pipeline_urls,
|
||||
cert_info,
|
||||
create_or_set_user_attribute_created_on_site,
|
||||
do_create_account,
|
||||
generate_activation_email_context,
|
||||
get_next_url_for_login_page
|
||||
)
|
||||
from student.message_types import EmailChange, PasswordReset
|
||||
from student.models import (
|
||||
|
||||
@@ -3,4 +3,6 @@ import os
|
||||
# Get the URL of the instance under test
|
||||
HOSTNAME = os.environ.get('BOK_CHOY_HOSTNAME', 'localhost')
|
||||
CMS_PORT = os.environ.get('BOK_CHOY_CMS_PORT', 8031)
|
||||
LMS_PORT = os.environ.get('BOK_CHOY_LMS_PORT', 8003)
|
||||
BASE_URL = os.environ.get('test_url', 'http://{}:{}'.format(HOSTNAME, CMS_PORT))
|
||||
LMS_URL = os.environ.get('test_url', 'http://{}:{}'.format(HOSTNAME, LMS_PORT))
|
||||
|
||||
@@ -4,7 +4,7 @@ Login page for Studio.
|
||||
from bok_choy.page_object import PageObject
|
||||
from bok_choy.promise import EmptyPromise
|
||||
|
||||
from common.test.acceptance.pages.studio import BASE_URL
|
||||
from common.test.acceptance.pages.studio import LMS_URL
|
||||
from common.test.acceptance.pages.studio.course_page import CoursePage
|
||||
from common.test.acceptance.pages.studio.utils import HelpMixin
|
||||
|
||||
@@ -13,24 +13,25 @@ class LoginMixin(object):
|
||||
"""
|
||||
Mixin class used for logging into the system.
|
||||
"""
|
||||
def fill_field(self, css, value):
|
||||
def fill_password(self, password):
|
||||
"""
|
||||
Fill the login form field with the value.
|
||||
Fill the password field with the value.
|
||||
"""
|
||||
self.q(css=css).fill(value)
|
||||
self.q(css="#login-password").fill(password)
|
||||
|
||||
def login(self, email, password, expect_success=True):
|
||||
"""
|
||||
Attempt to log in using 'email' and 'password'.
|
||||
"""
|
||||
self.fill_field('input#email', email)
|
||||
self.fill_field('input#password', password)
|
||||
self.q(css='button#submit').first.click()
|
||||
self.wait_for_element_visibility('#login-email', 'Email field is shown')
|
||||
self.q(css="#login-email").fill(email)
|
||||
self.fill_password(password)
|
||||
self.q(css=".login-button").click()
|
||||
|
||||
# Ensure that we make it to another page
|
||||
if expect_success:
|
||||
EmptyPromise(
|
||||
lambda: "signin" not in self.browser.current_url,
|
||||
lambda: "login" not in self.browser.current_url,
|
||||
"redirected from the login page"
|
||||
).fulfill()
|
||||
|
||||
@@ -39,17 +40,20 @@ class LoginPage(PageObject, LoginMixin, HelpMixin):
|
||||
"""
|
||||
Login page for Studio.
|
||||
"""
|
||||
url = BASE_URL + "/signin"
|
||||
url = LMS_URL + "/login"
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='body.view-signin').visible
|
||||
return (
|
||||
self.q(css="#login-anchor").is_present() and
|
||||
self.q(css=".login-button").visible
|
||||
)
|
||||
|
||||
|
||||
class CourseOutlineSignInRedirectPage(CoursePage, LoginMixin):
|
||||
"""
|
||||
Page shown when the user tries to accesses the course while not signed in.
|
||||
Page shown when the user tries to access the course while not signed in.
|
||||
"""
|
||||
url_path = "course"
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='body.view-signin').visible
|
||||
return self.q(css=".login-button").visible
|
||||
|
||||
@@ -4,7 +4,7 @@ Signup page for studio
|
||||
from bok_choy.page_object import PageObject
|
||||
|
||||
from common.test.acceptance.pages.common.utils import click_css
|
||||
from common.test.acceptance.pages.studio import BASE_URL
|
||||
from common.test.acceptance.pages.studio import LMS_URL
|
||||
from common.test.acceptance.pages.studio.utils import HelpMixin, set_input_value
|
||||
|
||||
|
||||
@@ -13,22 +13,29 @@ class SignupPage(PageObject, HelpMixin):
|
||||
Signup page for Studio.
|
||||
"""
|
||||
|
||||
url = BASE_URL + "/signup"
|
||||
url = LMS_URL + "/register"
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='body.view-signup').visible
|
||||
return (
|
||||
self.q(css="#register-anchor").is_present() and
|
||||
self.q(css=".register-button").visible
|
||||
)
|
||||
|
||||
def input_password(self, password):
|
||||
"""Inputs a password and then returns the password input"""
|
||||
return set_input_value(self, '#password', password)
|
||||
return set_input_value(self, "#register-password", password)
|
||||
|
||||
def sign_up_user(self, registration_dictionary):
|
||||
def sign_up_user(self, email, name, username, password, country="US", favorite_movie="Alf"):
|
||||
"""
|
||||
Register the user.
|
||||
"""
|
||||
for css, value in registration_dictionary.iteritems():
|
||||
set_input_value(self, css, value)
|
||||
self.q(css="#register-email").fill(email)
|
||||
self.q(css="#register-name").fill(name)
|
||||
self.q(css="#register-username").fill(username)
|
||||
self.q(css="#register-password").fill(password)
|
||||
self.q(css="#register-country").results[0].send_keys(country)
|
||||
self.q(css="#register-favorite_movie").fill(favorite_movie)
|
||||
|
||||
click_css(page=self, css='#tos', require_notification=False)
|
||||
click_css(page=self, css='#submit', require_notification=False)
|
||||
self.wait_for_element_absence('#submit', 'Submit button is gone.')
|
||||
# Submit it
|
||||
self.q(css=".register-button").click()
|
||||
self.wait_for_element_absence('.register-button', 'Register button is gone.')
|
||||
|
||||
@@ -8,6 +8,7 @@ from selenium.webdriver.common.keys import Keys
|
||||
from base_studio_test import StudioCourseTest
|
||||
from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
|
||||
from common.test.acceptance.pages.studio import LMS_URL
|
||||
from common.test.acceptance.pages.studio.asset_index import AssetIndexPageStudioFrontend
|
||||
from common.test.acceptance.pages.studio.course_info import CourseUpdatesPage
|
||||
from common.test.acceptance.pages.studio.edit_tabs import PagesPage
|
||||
@@ -118,15 +119,14 @@ class SignUpAndSignInTest(UniqueCourseTest):
|
||||
index_page.visit()
|
||||
index_page.click_sign_up()
|
||||
|
||||
unique_number = uuid.uuid4().hex[:4]
|
||||
registration_dic = {
|
||||
'#email': '{}-email@host.com'.format(unique_number),
|
||||
'#name': '{}-name'.format(unique_number),
|
||||
'#username': '{}-username'.format(unique_number),
|
||||
'#password': '{}-password'.format(unique_number),
|
||||
}
|
||||
# Register the user.
|
||||
self.sign_up_page.sign_up_user(registration_dic)
|
||||
unique_number = uuid.uuid4().hex[:4]
|
||||
self.sign_up_page.sign_up_user(
|
||||
'{}-email@host.com'.format(unique_number),
|
||||
'{}-name'.format(unique_number),
|
||||
'{}-username'.format(unique_number),
|
||||
'{}-password'.format(unique_number),
|
||||
)
|
||||
home = HomePage(self.browser)
|
||||
home.wait_for_page()
|
||||
|
||||
@@ -145,8 +145,8 @@ class SignUpAndSignInTest(UniqueCourseTest):
|
||||
|
||||
password_input = self.sign_up_page.input_password('a') # Arbitrary short password that will fail
|
||||
password_input.send_keys(Keys.TAB) # Focus out of the element
|
||||
index_page.wait_for_element_visibility('#password_error', 'Password Error Message')
|
||||
self.assertIsNotNone(index_page.q(css='#password_error').text) # Make sure there is an error message
|
||||
index_page.wait_for_element_visibility('#register-password-validation-error', 'Password Error Message')
|
||||
self.assertIsNotNone(index_page.q(css='#register-password-validation-error-msg')) # Error message should exist
|
||||
|
||||
def test_login_with_valid_redirect(self):
|
||||
"""
|
||||
@@ -184,9 +184,8 @@ class SignUpAndSignInTest(UniqueCourseTest):
|
||||
self.browser.get(self.browser.current_url.split('=')[0] + '=http://www.google.com')
|
||||
# Login
|
||||
self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
|
||||
home = HomePage(self.browser)
|
||||
home.wait_for_page()
|
||||
self.assertEqual(self.browser.current_url, home.url)
|
||||
# Verify that we land in LMS instead of the invalid redirect url
|
||||
self.assertEqual(self.browser.current_url, LMS_URL + "/dashboard")
|
||||
|
||||
def test_login_with_mistyped_credentials(self):
|
||||
"""
|
||||
@@ -219,16 +218,9 @@ class SignUpAndSignInTest(UniqueCourseTest):
|
||||
)
|
||||
# Verify that login error is shown
|
||||
self.course_outline_sign_in_redirect_page.wait_for_element_visibility(
|
||||
'#login_error',
|
||||
".js-form-errors.status.submission-error",
|
||||
'Login error is visible'
|
||||
)
|
||||
# Change the password
|
||||
self.course_outline_sign_in_redirect_page.fill_field('input#password', 'changed_password')
|
||||
# Login error should not be visible
|
||||
self.course_outline_sign_in_redirect_page.wait_for_element_invisibility(
|
||||
'#login_error',
|
||||
'Login error is not visible'
|
||||
)
|
||||
# Login with correct credentials
|
||||
self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
|
||||
self.course_outline_page.wait_for_page()
|
||||
|
||||
@@ -84,68 +84,6 @@ class StudioHelpTest(StudioCourseTest):
|
||||
)
|
||||
|
||||
|
||||
@attr(shard=20)
|
||||
class SignInHelpTest(AcceptanceTest):
|
||||
"""
|
||||
Tests help links on 'Sign In' page
|
||||
"""
|
||||
def setUp(self):
|
||||
super(SignInHelpTest, self).setUp()
|
||||
self.index_page = IndexPage(self.browser)
|
||||
self.index_page.visit()
|
||||
|
||||
def test_sign_in_nav_help(self):
|
||||
"""
|
||||
Scenario: Help link in navigation bar is working on 'Sign In' page.
|
||||
Given that I am on the 'Sign In" page.
|
||||
And I want help about the sign in
|
||||
And I click the 'Help' in the navigation bar
|
||||
Then Help link should open.
|
||||
And help url should be correct
|
||||
"""
|
||||
sign_in_page = self.index_page.click_sign_in()
|
||||
expected_url = _get_expected_documentation_url('/getting_started/index.html')
|
||||
|
||||
# Assert that help link is correct.
|
||||
assert_nav_help_link(
|
||||
test=self,
|
||||
page=sign_in_page,
|
||||
href=expected_url,
|
||||
signed_in=False
|
||||
)
|
||||
|
||||
|
||||
@attr(shard=20)
|
||||
class SignUpHelpTest(AcceptanceTest):
|
||||
"""
|
||||
Tests help links on 'Sign Up' page.
|
||||
"""
|
||||
def setUp(self):
|
||||
super(SignUpHelpTest, self).setUp()
|
||||
self.index_page = IndexPage(self.browser)
|
||||
self.index_page.visit()
|
||||
|
||||
def test_sign_up_nav_help(self):
|
||||
"""
|
||||
Scenario: Help link in navigation bar is working on 'Sign Up' page.
|
||||
Given that I am on the 'Sign Up" page.
|
||||
And I want help about the sign up
|
||||
And I click the 'Help' in the navigation bar
|
||||
Then Help link should open.
|
||||
And help url should be correct
|
||||
"""
|
||||
sign_up_page = self.index_page.click_sign_up()
|
||||
expected_url = _get_expected_documentation_url('/getting_started/index.html')
|
||||
|
||||
# Assert that help link is correct.
|
||||
assert_nav_help_link(
|
||||
test=self,
|
||||
page=sign_up_page,
|
||||
href=expected_url,
|
||||
signed_in=False
|
||||
)
|
||||
|
||||
|
||||
@attr(shard=20)
|
||||
class HomeHelpTest(StudioCourseTest):
|
||||
"""
|
||||
|
||||
@@ -233,7 +233,10 @@ BADGING_BACKEND = 'lms.djangoapps.badges.backends.tests.dummy_backend.DummyBacke
|
||||
# Configure the LMS to use our stub eCommerce implementation
|
||||
ECOMMERCE_API_URL = 'http://localhost:8043/api/v2/'
|
||||
|
||||
LMS_ROOT_URL = "http://localhost:8000"
|
||||
LMS_ROOT_URL = "http://localhost:{}".format(os.environ.get('BOK_CHOY_LMS_PORT', 8003))
|
||||
CMS_BASE = "localhost:{}".format(os.environ.get('BOK_CHOY_CMS_PORT', 8031))
|
||||
LOGIN_REDIRECT_WHITELIST = [CMS_BASE]
|
||||
|
||||
if RELEASE_LINE == "master":
|
||||
# On master, acceptance tests use edX books, not the default Open edX books.
|
||||
HELP_TOKENS_BOOKS = {
|
||||
|
||||
@@ -6,9 +6,10 @@ Settings for Bok Choy tests that are used when running Studio in Docker-based de
|
||||
# noinspection PyUnresolvedReferences
|
||||
from .bok_choy import * # pylint: disable=wildcard-import
|
||||
|
||||
CMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ['BOK_CHOY_CMS_PORT'])
|
||||
LMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ['BOK_CHOY_LMS_PORT'])
|
||||
CMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ.get('BOK_CHOY_CMS_PORT', 8031))
|
||||
LMS_BASE = '{}:{}'.format(os.environ['BOK_CHOY_HOSTNAME'], os.environ.get('BOK_CHOY_LMS_PORT', 8003))
|
||||
LMS_ROOT_URL = 'http://{}'.format(LMS_BASE)
|
||||
LOGIN_REDIRECT_WHITELIST = [CMS_BASE]
|
||||
|
||||
COMMENTS_SERVICE_URL = 'http://{}:4567'.format(os.environ['BOK_CHOY_HOSTNAME'])
|
||||
EDXNOTES_PUBLIC_API = 'http://{}:8042/api/v1'.format(os.environ['BOK_CHOY_HOSTNAME'])
|
||||
|
||||
@@ -2519,7 +2519,7 @@ if FEATURES.get('ENABLE_CORS_HEADERS'):
|
||||
# to simulate cross-domain requests.
|
||||
XDOMAIN_PROXY_CACHE_TIMEOUT = 60 * 15
|
||||
|
||||
LOGIN_REDIRECT_WHITELIST = []
|
||||
LOGIN_REDIRECT_WHITELIST = [CMS_BASE]
|
||||
|
||||
###################### Registration ##################################
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ SITE_NAME = 'localhost:8000'
|
||||
CELERY_ALWAYS_EAGER = True
|
||||
HTTPS = 'off'
|
||||
|
||||
LMS_ROOT_URL = 'http://localhost:8000'
|
||||
LMS_ROOT_URL = "http://localhost:8000"
|
||||
LMS_INTERNAL_ROOT_URL = LMS_ROOT_URL
|
||||
ENTERPRISE_API_URL = LMS_INTERNAL_ROOT_URL + '/enterprise/api/v1/'
|
||||
|
||||
@@ -229,7 +229,7 @@ CORS_ALLOW_HEADERS = corsheaders_default_headers + (
|
||||
'use-jwt-cookie',
|
||||
)
|
||||
|
||||
LOGIN_REDIRECT_WHITELIST = []
|
||||
LOGIN_REDIRECT_WHITELIST = [CMS_BASE]
|
||||
|
||||
###################### JWTs ######################
|
||||
JWT_AUTH.update({
|
||||
|
||||
@@ -9,8 +9,8 @@ LOGGING['handlers']['local'] = LOGGING['handlers']['tracking'] = {
|
||||
|
||||
LOGGING['loggers']['tracking']['handlers'] = ['console']
|
||||
|
||||
LMS_BASE = 'edx.devstack.lms:18000'
|
||||
CMS_BASE = 'edx.devstack.studio:18010'
|
||||
LMS_BASE = 'localhost:18000'
|
||||
CMS_BASE = 'localhost:18010'
|
||||
SITE_NAME = LMS_BASE
|
||||
LMS_ROOT_URL = 'http://{}'.format(LMS_BASE)
|
||||
LMS_INTERNAL_ROOT_URL = LMS_ROOT_URL
|
||||
|
||||
@@ -3,6 +3,7 @@ Django template context processors.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.http import urlquote_plus
|
||||
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
|
||||
@@ -12,5 +13,7 @@ def configuration_context(request): # pylint: disable=unused-argument
|
||||
Configuration context for django templates.
|
||||
"""
|
||||
return {
|
||||
'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME)
|
||||
'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME),
|
||||
'current_url': urlquote_plus(request.build_absolute_uri(request.path)),
|
||||
'current_site_url': urlquote_plus(request.build_absolute_uri('/')),
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestThemingViews(TestCase):
|
||||
self.assertRedirects(
|
||||
response,
|
||||
'{login_url}?next={url}'.format(
|
||||
login_url=settings.LOGIN_REDIRECT_URL,
|
||||
login_url=settings.LOGIN_URL,
|
||||
url=THEMING_ADMIN_URL,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
""" Test User Authentication utilities """
|
||||
|
||||
from collections import namedtuple
|
||||
import ddt
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
@@ -18,19 +20,27 @@ class TestRedirectUtils(TestCase):
|
||||
super(TestRedirectUtils, self).setUp()
|
||||
self.request = RequestFactory()
|
||||
|
||||
RedirectCase = namedtuple('RedirectCase', ['url', 'host', 'req_is_secure', 'expected_is_safe'])
|
||||
|
||||
@ddt.data(
|
||||
('/dashboard', 'testserver', True),
|
||||
('https://edx.org/courses', 'edx.org', True),
|
||||
('https://test.edx.org/courses', 'edx.org', True),
|
||||
('https://www.amazon.org', 'edx.org', False),
|
||||
('http://edx.org/courses', 'edx.org', False),
|
||||
('http:///edx.org/courses', 'edx.org', False), # Django's is_safe_url protects against "///"
|
||||
RedirectCase('/dashboard', 'testserver', req_is_secure=True, expected_is_safe=True),
|
||||
RedirectCase('https://test.edx.org/courses', 'edx.org', req_is_secure=True, expected_is_safe=True),
|
||||
RedirectCase('https://www.amazon.org', 'edx.org', req_is_secure=True, expected_is_safe=False),
|
||||
|
||||
# https is required only if the request is_secure
|
||||
RedirectCase('https://edx.org/courses', 'edx.org', req_is_secure=True, expected_is_safe=True),
|
||||
RedirectCase('http://edx.org/courses', 'edx.org', req_is_secure=False, expected_is_safe=True),
|
||||
RedirectCase('http://edx.org/courses', 'edx.org', req_is_secure=True, expected_is_safe=False),
|
||||
|
||||
# Django's is_safe_url protects against "///"
|
||||
RedirectCase('http:///edx.org/courses', 'edx.org', req_is_secure=True, expected_is_safe=False),
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_settings(LOGIN_REDIRECT_WHITELIST=['test.edx.org'])
|
||||
def test_safe_redirect(self, url, host, expected_is_safe):
|
||||
def test_safe_redirect(self, url, host, req_is_secure, expected_is_safe):
|
||||
""" Test safe next parameter """
|
||||
req = self.request.get('/login', HTTP_HOST=host)
|
||||
req.is_secure = lambda: req_is_secure
|
||||
actual_is_safe = is_safe_login_or_logout_redirect(req, url)
|
||||
self.assertEqual(actual_is_safe, expected_is_safe)
|
||||
|
||||
|
||||
@@ -23,5 +23,7 @@ def is_safe_login_or_logout_redirect(request, redirect_to):
|
||||
if redirect_to in application.redirect_uris:
|
||||
login_redirect_whitelist.add(urlparse(redirect_to).netloc)
|
||||
|
||||
is_safe_url = http.is_safe_url(redirect_to, allowed_hosts=login_redirect_whitelist, require_https=True)
|
||||
is_safe_url = http.is_safe_url(
|
||||
redirect_to, allowed_hosts=login_redirect_whitelist, require_https=request.is_secure(),
|
||||
)
|
||||
return is_safe_url
|
||||
|
||||
@@ -29,11 +29,11 @@ class LogoutView(TemplateView):
|
||||
@property
|
||||
def target(self):
|
||||
"""
|
||||
If a redirect_url is specified in the querystring for this request, and the value is a url
|
||||
with the same host, the view will redirect to this page after rendering the template.
|
||||
If a redirect_url is specified in the querystring for this request, and the value is a safe
|
||||
url for redirect, the view will redirect to this page after rendering the template.
|
||||
If it is not specified, we will use the default target url.
|
||||
"""
|
||||
target_url = self.request.GET.get('redirect_url')
|
||||
target_url = self.request.GET.get('redirect_url') or self.request.GET.get('next')
|
||||
|
||||
if target_url and is_safe_login_or_logout_redirect(self.request, target_url):
|
||||
return target_url
|
||||
|
||||
@@ -87,7 +87,7 @@ INSTALLED_APPS = (
|
||||
'completion',
|
||||
)
|
||||
|
||||
LMS_ROOT_URL = 'http://localhost:8000'
|
||||
LMS_ROOT_URL = "http://localhost:8000"
|
||||
|
||||
MEDIA_ROOT = tempfile.mkdtemp()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user