Commit fd312ab1 by Ali Mohammad

Merge pull request #7302 from edx/alawibaba/hotfix-cdn-experiment

hotfix: China CDN cleanup and bugfixes
parents c65c19d2 cdc81c88
......@@ -215,6 +215,13 @@ from lms.envs.common import (
COURSE_KEY_PATTERN, COURSE_ID_PATTERN, USAGE_KEY_PATTERN, ASSET_KEY_PATTERN
)
######################### CSRF #########################################
# Forwards-compatibility with Django 1.7
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
#################### CAPA External Code Evaluation #############################
XQUEUE_INTERFACE = {
'url': 'http://localhost:8888',
......
"""Decorators for cross-domain CSRF. """
from django.views.decorators.csrf import ensure_csrf_cookie
def ensure_csrf_cookie_cross_domain(func):
"""View decorator for sending a cross-domain CSRF cookie.
This works like Django's `@ensure_csrf_cookie`, but
will also set an additional CSRF cookie for use
cross-domain.
Arguments:
func (function): The view function to decorate.
"""
def _inner(*args, **kwargs): # pylint: disable=missing-docstring
if args:
# Set the META `CROSS_DOMAIN_CSRF_COOKIE_USED` flag so
# that `CsrfCrossDomainCookieMiddleware` knows to set
# the cross-domain version of the CSRF cookie.
request = args[0]
request.META['CROSS_DOMAIN_CSRF_COOKIE_USED'] = True
# Decorate the request with Django's
# `ensure_csrf_cookie` to ensure that the usual
# CSRF cookie gets set.
return ensure_csrf_cookie(func)(*args, **kwargs)
return _inner
"""
Middleware for handling CSRF checks with CORS requests
CSRF and referrer domain checks
-------------------------------
When processing HTTPS requests, the default CSRF middleware checks that the referer
domain and protocol is the same as the request's domain and protocol. This is meant
to avoid a type of attack for sites which serve their content with both HTTP and HTTPS,
......@@ -15,6 +19,27 @@ middle attack vector.
We thus do the CSRF check of requests coming from an authorized CORS host separately
in this middleware, applying the same protections as the default CSRF middleware, but
without the referrer check, when both the request and the referer use HTTPS.
CSRF cookie domains
-------------------
In addition, in order to make cross-domain AJAX calls to CSRF-protected end-points,
we need to send the CSRF token in the HTTP header of the request.
The simple way to do this would be to set the CSRF_COOKIE_DOMAIN to ".edx.org",
but unfortunately this can cause problems. For example, suppose that
"first.edx.org" sets the cookie with domain ".edx.org", but "second.edx.org"
sets a cookie with domain "second.edx.org". In this case, the browser
would have two different CSRF tokens set (one for each cookie domain),
which can cause non-deterministic failures depending on which cookie
is sent first.
For this reason, we add a second cookie that (a) has the domain set to ".edx.org",
but (b) does NOT have the same name as the CSRF_COOKIE_NAME. Clients making
cross-domain requests can use this cookie instead of the subdomain-specific
CSRF cookie.
"""
import logging
......@@ -22,35 +47,91 @@ import urlparse
from django.conf import settings
from django.middleware.csrf import CsrfViewMiddleware
from django.core.exceptions import MiddlewareNotUsed, ImproperlyConfigured
log = logging.getLogger(__name__)
class CorsCSRFMiddleware(CsrfViewMiddleware):
"""
Middleware for handling CSRF checks with CORS requests
def is_cross_domain_request_allowed(request):
"""Check whether we should allow the cross-domain request.
We allow a cross-domain request only if:
1) The request is made securely and the referer has "https://" as the protocol.
2) The referer domain has been whitelisted.
Arguments:
request (HttpRequest)
Returns:
bool
"""
def is_enabled(self, request):
"""
Override the `is_enabled()` method to allow cross-domain HTTPS requests
"""
if not settings.FEATURES.get('ENABLE_CORS_HEADERS'):
referer = request.META.get('HTTP_REFERER')
referer_parts = urlparse.urlparse(referer) if referer else None
referer_hostname = referer_parts.hostname if referer_parts is not None else None
# Use CORS_ALLOW_INSECURE *only* for development and testing environments;
# it should never be enabled in production.
if not getattr(settings, 'CORS_ALLOW_INSECURE', False):
if not request.is_secure():
log.debug(
u"Request is not secure, so we cannot send the CSRF token. "
u"For testing purposes, you can disable this check by setting "
u"`CORS_ALLOW_INSECURE` to True in the settings"
)
return False
referer = request.META.get('HTTP_REFERER')
if not referer:
log.debug(u"No referer provided over a secure connection, so we cannot check the protocol.")
return False
referer_parts = urlparse.urlparse(referer)
if referer_parts.hostname not in getattr(settings, 'CORS_ORIGIN_WHITELIST', []):
return False
if not request.is_secure() or referer_parts.scheme != 'https':
if not referer_parts.scheme == 'https':
log.debug(u"Referer '%s' must have the scheme 'https'")
return False
return True
domain_is_whitelisted = (
getattr(settings, 'CORS_ORIGIN_ALLOW_ALL', False) or
referer_hostname in getattr(settings, 'CORS_ORIGIN_WHITELIST', [])
)
if not domain_is_whitelisted:
if referer_hostname is None:
# If no referer is specified, we can't check if it's a cross-domain
# request or not.
log.debug(u"Referrer hostname is `None`, so it is not on the whitelist.")
elif referer_hostname != request.get_host():
log.warning(
(
u"Domain '%s' is not on the cross domain whitelist. "
u"Add the domain to `CORS_ORIGIN_WHITELIST` or set "
u"`CORS_ORIGIN_ALLOW_ALL` to True in the settings."
), referer_hostname
)
else:
log.debug(
(
u"Domain '%s' is the same as the hostname in the request, "
u"so we are not going to treat it as a cross-domain request."
), referer_hostname
)
return False
return True
class CorsCSRFMiddleware(CsrfViewMiddleware):
"""
Middleware for handling CSRF checks with CORS requests
"""
def __init__(self):
"""Disable the middleware if the feature flag is disabled. """
if not settings.FEATURES.get('ENABLE_CORS_HEADERS'):
raise MiddlewareNotUsed()
def process_view(self, request, callback, callback_args, callback_kwargs):
if not self.is_enabled(request):
"""Skip the usual CSRF referer check if this is an allowed cross-domain request. """
if not is_cross_domain_request_allowed(request):
log.debug("Could not disable CSRF middleware referer check for cross-domain request.")
return
is_secure_default = request.is_secure
......@@ -65,3 +146,77 @@ class CorsCSRFMiddleware(CsrfViewMiddleware):
res = super(CorsCSRFMiddleware, self).process_view(request, callback, callback_args, callback_kwargs)
request.is_secure = is_secure_default
return res
class CsrfCrossDomainCookieMiddleware(object):
"""Set an additional "cross-domain" CSRF cookie.
Usage:
1) Decorate a view with `@ensure_csrf_cookie_cross_domain`.
2) Set `CROSS_DOMAIN_CSRF_COOKIE_NAME` and `CROSS_DOMAIN_CSRF_COOKIE_DOMAIN`
in settings.
3) Add the domain to `CORS_ORIGIN_WHITELIST`
4) Enable `FEATURES['ENABLE_CROSS_DOMAIN_CSRF_COOKIE']`
For testing, it is often easier to relax the security checks by setting:
* `CORS_ALLOW_INSECURE = True`
* `CORS_ORIGIN_ALLOW_ALL = True`
"""
def __init__(self):
"""Disable the middleware if the feature is not enabled. """
if not settings.FEATURES.get('ENABLE_CROSS_DOMAIN_CSRF_COOKIE'):
raise MiddlewareNotUsed()
if not getattr(settings, 'CROSS_DOMAIN_CSRF_COOKIE_NAME', ''):
raise ImproperlyConfigured(
"You must set `CROSS_DOMAIN_CSRF_COOKIE_NAME` when "
"`FEATURES['ENABLE_CROSS_DOMAIN_CSRF_COOKIE']` is True."
)
if not getattr(settings, 'CROSS_DOMAIN_CSRF_COOKIE_DOMAIN', ''):
raise ImproperlyConfigured(
"You must set `CROSS_DOMAIN_CSRF_COOKIE_DOMAIN` when "
"`FEATURES['ENABLE_CROSS_DOMAIN_CSRF_COOKIE']` is True."
)
def process_response(self, request, response):
"""Set the cross-domain CSRF cookie. """
# Check whether this is a secure request from a domain on our whitelist.
if not is_cross_domain_request_allowed(request):
log.debug("Could not set cross-domain CSRF cookie.")
return response
# Check whether (a) the CSRF middleware has already set a cookie, and
# (b) this is a view decorated with `@ensure_cross_domain_csrf_cookie`
# If so, we can send the cross-domain CSRF cookie.
should_set_cookie = (
request.META.get('CROSS_DOMAIN_CSRF_COOKIE_USED', False) and
request.META.get('CSRF_COOKIE_USED', False) and
request.META.get('CSRF_COOKIE') is not None
)
if should_set_cookie:
# This is very similar to the code in Django's CSRF middleware
# implementation, with two exceptions:
# 1) We change the cookie name and domain so it can be used cross-domain.
# 2) We always set "secure" to True, so that the CSRF token must be
# sent over a secure connection.
response.set_cookie(
settings.CROSS_DOMAIN_CSRF_COOKIE_NAME,
request.META['CSRF_COOKIE'],
max_age=settings.CSRF_COOKIE_AGE,
domain=settings.CROSS_DOMAIN_CSRF_COOKIE_DOMAIN,
path=settings.CSRF_COOKIE_PATH,
secure=True
)
log.debug(
"Set cross-domain CSRF cookie '%s' for domain '%s'",
settings.CROSS_DOMAIN_CSRF_COOKIE_NAME,
settings.CROSS_DOMAIN_CSRF_COOKIE_DOMAIN
)
return response
"""
Tests for the CORS CSRF middleware
"""
from mock import patch, Mock
from django.test import TestCase
from django.test.utils import override_settings
from django.middleware.csrf import CsrfViewMiddleware
from cors_csrf.middleware import CorsCSRFMiddleware
SENTINEL = object()
class TestCorsMiddlewareProcessRequest(TestCase):
"""
Test processing a request through the middleware
"""
def get_request(self, is_secure, http_referer):
"""
Build a test request
"""
request = Mock()
request.META = {'HTTP_REFERER': http_referer}
request.is_secure = lambda: is_secure
return request
def setUp(self):
self.middleware = CorsCSRFMiddleware()
def check_not_enabled(self, request):
"""
Check that the middleware does NOT process the provided request
"""
with patch.object(CsrfViewMiddleware, 'process_view') as mock_method:
res = self.middleware.process_view(request, None, None, None)
self.assertIsNone(res)
self.assertFalse(mock_method.called)
def check_enabled(self, request):
"""
Check that the middleware does process the provided request
"""
def cb_check_req_is_secure_false(request, callback, args, kwargs):
"""
Check that the request doesn't pass (yet) the `is_secure()` test
"""
self.assertFalse(request.is_secure())
return SENTINEL
with patch.object(CsrfViewMiddleware, 'process_view') as mock_method:
mock_method.side_effect = cb_check_req_is_secure_false
res = self.middleware.process_view(request, None, None, None)
self.assertIs(res, SENTINEL)
self.assertTrue(request.is_secure())
@override_settings(FEATURES={'ENABLE_CORS_HEADERS': True},
CORS_ORIGIN_WHITELIST=['foo.com'])
def test_enabled(self):
request = self.get_request(is_secure=True,
http_referer='https://foo.com/bar')
self.check_enabled(request)
@override_settings(FEATURES={'ENABLE_CORS_HEADERS': False},
CORS_ORIGIN_WHITELIST=['foo.com'])
def test_disabled_no_cors_headers(self):
request = self.get_request(is_secure=True,
http_referer='https://foo.com/bar')
self.check_not_enabled(request)
@override_settings(FEATURES={'ENABLE_CORS_HEADERS': True},
CORS_ORIGIN_WHITELIST=['bar.com'])
def test_disabled_wrong_cors_domain(self):
request = self.get_request(is_secure=True,
http_referer='https://foo.com/bar')
self.check_not_enabled(request)
@override_settings(FEATURES={'ENABLE_CORS_HEADERS': True},
CORS_ORIGIN_WHITELIST=['foo.com'])
def test_disabled_wrong_cors_domain_reversed(self):
request = self.get_request(is_secure=True,
http_referer='https://bar.com/bar')
self.check_not_enabled(request)
@override_settings(FEATURES={'ENABLE_CORS_HEADERS': True},
CORS_ORIGIN_WHITELIST=['foo.com'])
def test_disabled_http_request(self):
request = self.get_request(is_secure=False,
http_referer='https://foo.com/bar')
self.check_not_enabled(request)
@override_settings(FEATURES={'ENABLE_CORS_HEADERS': True},
CORS_ORIGIN_WHITELIST=['foo.com'])
def test_disabled_http_referer(self):
request = self.get_request(is_secure=True,
http_referer='http://foo.com/bar')
self.check_not_enabled(request)
"""Tests for cross-domain CSRF decorators. """
import json
import mock
from django.http import HttpResponse
from django.test import TestCase
from cors_csrf.decorators import ensure_csrf_cookie_cross_domain
def fake_view(request):
"""Fake view that returns the request META as a JSON-encoded string. """
return HttpResponse(json.dumps(request.META))
class TestEnsureCsrfCookieCrossDomain(TestCase):
"""Test the `ensucre_csrf_cookie_cross_domain` decorator. """
def test_ensure_csrf_cookie_cross_domain(self):
request = mock.Mock()
request.META = {}
wrapped_view = ensure_csrf_cookie_cross_domain(fake_view)
response = wrapped_view(request)
response_meta = json.loads(response.content)
self.assertEqual(response_meta['CROSS_DOMAIN_CSRF_COOKIE_USED'], True)
self.assertEqual(response_meta['CSRF_COOKIE_USED'], True)
......@@ -4,25 +4,24 @@ consist primarily of authentication, request validation, and serialization.
"""
from ipware.ip import get_ip
from django.conf import settings
from django.utils.decorators import method_decorator
from opaque_keys import InvalidKeyError
from opaque_keys.edx.locator import CourseLocator
from openedx.core.djangoapps.user_api import api as user_api
from openedx.core.lib.api.permissions import ApiKeyHeaderPermission, ApiKeyHeaderPermissionIsAuthenticated
from rest_framework import status
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
from opaque_keys.edx.keys import CourseKey
from opaque_keys import InvalidKeyError
from enrollment import api
from enrollment.errors import (
CourseNotFoundError, CourseEnrollmentError, CourseModeNotFoundError, CourseEnrollmentExistsError
)
from embargo import api as embargo_api
from cors_csrf.decorators import ensure_csrf_cookie_cross_domain
from util.authentication import SessionAuthenticationAllowInactiveUser, OAuth2AuthenticationAllowInactiveUser
from util.disable_rate_limit import can_disable_rate_limit
from enrollment import api
from enrollment.errors import (
CourseNotFoundError, CourseEnrollmentError,
CourseModeNotFoundError, CourseEnrollmentExistsError
)
class EnrollmentUserThrottle(UserRateThrottle):
......@@ -96,6 +95,10 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn):
permission_classes = ApiKeyHeaderPermissionIsAuthenticated,
throttle_classes = EnrollmentUserThrottle,
# Since the course about page on the marketing site
# uses this API to auto-enroll users, we need to support
# cross-domain CSRF.
@method_decorator(ensure_csrf_cookie_cross_domain)
def get(self, request, course_id=None, user=None):
"""Create, read, or update enrollment information for a user.
......@@ -268,6 +271,10 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
permission_classes = ApiKeyHeaderPermissionIsAuthenticated,
throttle_classes = EnrollmentUserThrottle,
# Since the course about page on the marketing site
# uses this API to auto-enroll users, we need to support
# cross-domain CSRF.
@method_decorator(ensure_csrf_cookie_cross_domain)
def get(self, request):
"""
Gets a list of all course enrollments for the currently logged in user.
......
......@@ -3,6 +3,7 @@ A tiny app that checks for a status message.
"""
from django.conf import settings
from django.core.cache import cache
import json
import logging
import os
......@@ -25,6 +26,11 @@ def get_site_status_msg(course_id):
not allowed to break the entire site).
"""
try:
# first check for msg in cache
msg = cache.get('site_status_msg')
if msg is not None:
return msg
if os.path.isfile(settings.STATUS_MESSAGE_PATH):
with open(settings.STATUS_MESSAGE_PATH) as f:
content = f.read()
......@@ -37,6 +43,8 @@ def get_site_status_msg(course_id):
msg = msg + "<br>" if msg else ''
msg += status_dict[course_id]
# set msg to cache, with expiry 5 mins
cache.set('site_status_msg', msg, 60 * 5)
return msg
except:
log.exception("Error while getting a status message.")
......
from django.conf import settings
from django.core.cache import cache
from django.test import TestCase
import os
from django.test.utils import override_settings
from tempfile import NamedTemporaryFile
import ddt
from .status import get_site_status_msg
......@@ -13,6 +15,7 @@ TMP_NAME = TMP_FILE.name
TMP_FILE.close()
@ddt.ddt
@override_settings(STATUS_MESSAGE_PATH=TMP_NAME)
class TestStatus(TestCase):
"""Test that the get_site_status_msg function does the right thing"""
......@@ -64,6 +67,13 @@ class TestStatus(TestCase):
with open(settings.STATUS_MESSAGE_PATH, 'w') as f:
f.write(contents)
def clear_status_cache(self):
"""
Remove the cached status message, if found
"""
if cache.get('site_status_msg') is not None:
cache.delete('site_status_msg')
def remove_status_file(self):
"""Delete the status file if it exists"""
if os.path.exists(settings.STATUS_MESSAGE_PATH):
......@@ -72,18 +82,19 @@ class TestStatus(TestCase):
def tearDown(self):
self.remove_status_file()
def test_get_site_status_msg(self):
@ddt.data(*checks)
@ddt.unpack
def test_get_site_status_msg(self, json_str, exp_none, exp_toy, exp_full):
"""run the tests"""
for (json_str, exp_none, exp_toy, exp_full) in self.checks:
self.remove_status_file()
if json_str:
self.create_status_file(json_str)
print "checking results for {0}".format(json_str)
print "course=None:"
self.assertEqual(get_site_status_msg(None), exp_none)
print "course=toy:"
self.assertEqual(get_site_status_msg(self.toy_id), exp_toy)
print "course=full:"
self.assertEqual(get_site_status_msg(self.full_id), exp_full)
self.remove_status_file()
if json_str:
self.create_status_file(json_str)
for course_id, expected_msg in [(None, exp_none), (self.toy_id, exp_toy), (self.full_id, exp_full)]:
self.assertEqual(get_site_status_msg(course_id), expected_msg)
self.assertEqual(cache.get('site_status_msg'), expected_msg)
# check that `get_site_status_msg` works as expected when the cache
# is warmed, too
self.assertEqual(get_site_status_msg(course_id), expected_msg)
self.clear_status_cache()
......@@ -235,12 +235,15 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
# CDN_VIDEO_URLS is only to be used here and will be deleted
# TODO(ali@edx.org): Delete this after the CDN experiment has completed.
html_id = self.location.html_id()
if getattr(settings, 'PERFORMANCE_GRAPHITE_URL', '') != '' and \
self.system.user_location == 'CN' and \
getattr(settings, 'ENABLE_VIDEO_BEACON', False) and \
self.edx_video_id in getattr(settings, 'CDN_VIDEO_URLS', {}).keys():
cdn_urls = getattr(settings, 'CDN_VIDEO_URLS', {})[self.edx_video_id]
cdn_exp_group, sources[0] = random.choice(zip(range(len(cdn_urls)), cdn_urls))
getattr(settings.FEATURES, 'ENABLE_VIDEO_BEACON', False) and \
html_id in getattr(settings, 'CDN_VIDEO_URLS', {}).keys():
cdn_urls = getattr(settings, 'CDN_VIDEO_URLS', {})[html_id]
cdn_exp_group, new_source = random.choice(zip(range(len(cdn_urls)), cdn_urls))
if cdn_exp_group > 0:
sources[0] = new_source
cdn_eval = True
else:
cdn_eval = False
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -216,6 +216,7 @@ THEME_NAME = ENV_TOKENS.get('THEME_NAME', None)
# Marketing link overrides
MKTG_URL_LINK_MAP.update(ENV_TOKENS.get('MKTG_URL_LINK_MAP', {}))
# Mobile store URL overrides
MOBILE_STORE_URLS = ENV_TOKENS.get('MOBILE_STORE_URLS', MOBILE_STORE_URLS)
......@@ -305,15 +306,44 @@ VIDEO_CDN_URL = ENV_TOKENS.get('VIDEO_CDN_URL', {})
############# CORS headers for cross-domain requests #################
if FEATURES.get('ENABLE_CORS_HEADERS'):
INSTALLED_APPS += ('corsheaders', 'cors_csrf')
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
'cors_csrf.middleware.CorsCSRFMiddleware',
) + MIDDLEWARE_CLASSES
if FEATURES.get('ENABLE_CORS_HEADERS') or FEATURES.get('ENABLE_CROSS_DOMAIN_CSRF_COOKIE'):
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = ENV_TOKENS.get('CORS_ORIGIN_WHITELIST', ())
CORS_ORIGIN_ALLOW_ALL = ENV_TOKENS.get('CORS_ORIGIN_ALLOW_ALL', False)
CORS_ALLOW_INSECURE = ENV_TOKENS.get('CORS_ALLOW_INSECURE', False)
# If setting a cross-domain cookie, it's really important to choose
# a name for the cookie that is DIFFERENT than the cookies used
# by each subdomain. For example, suppose the applications
# at these subdomains are configured to use the following cookie names:
#
# 1) foo.example.com --> "csrftoken"
# 2) baz.example.com --> "csrftoken"
# 3) bar.example.com --> "csrftoken"
#
# For the cross-domain version of the CSRF cookie, you need to choose
# a name DIFFERENT than "csrftoken"; otherwise, the new token configured
# for ".example.com" could conflict with the other cookies,
# non-deterministically causing 403 responses.
#
# Because of the way Django stores cookies, the cookie name MUST
# be a `str`, not unicode. Otherwise there will `TypeError`s will be raised
# when Django tries to call the unicode `translate()` method with the wrong
# number of parameters.
CROSS_DOMAIN_CSRF_COOKIE_NAME = str(ENV_TOKENS.get('CROSS_DOMAIN_CSRF_COOKIE_NAME'))
# When setting the domain for the "cross-domain" version of the CSRF
# cookie, you should choose something like: ".example.com"
# (note the leading dot), where both the referer and the host
# are subdomains of "example.com".
#
# Browser security rules require that
# the cookie domain matches the domain of the server; otherwise
# the cookie won't get set. And once the cookie gets set, the client
# needs to be on a domain that matches the cookie domain, otherwise
# the client won't be able to read the cookie.
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = ENV_TOKENS.get('CROSS_DOMAIN_CSRF_COOKIE_DOMAIN')
############################## SECURE AUTH ITEMS ###############
# Secret things: passwords, access keys, etc.
......@@ -524,3 +554,7 @@ FACEBOOK_APP_SECRET = AUTH_TOKENS.get("FACEBOOK_APP_SECRET")
FACEBOOK_APP_ID = AUTH_TOKENS.get("FACEBOOK_APP_ID")
XBLOCK_SETTINGS = ENV_TOKENS.get('XBLOCK_SETTINGS', {})
##### CDN EXPERIMENT/MONITORING FLAGS #####
PERFORMANCE_GRAPHITE_URL = ENV_TOKENS.get('PERFORMANCE_GRAPHITE_URL', PERFORMANCE_GRAPHITE_URL)
CDN_VIDEO_URLS = ENV_TOKENS.get('CDN_VIDEO_URLS', CDN_VIDEO_URLS)
......@@ -348,6 +348,9 @@ FEATURES = {
# log all information from cybersource callbacks
'LOG_POSTPAY_CALLBACKS': True,
# enable beacons for video timing statistics
'ENABLE_VIDEO_BEACON': False,
}
# Ignore static asset files on import which match this pattern
......@@ -1003,7 +1006,13 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware',
# CORS and CSRF
'corsheaders.middleware.CorsMiddleware',
'cors_csrf.middleware.CorsCSRFMiddleware',
'cors_csrf.middleware.CsrfCrossDomainCookieMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'splash.middleware.SplashMiddleware',
# Allows us to dark-launch particular languages
......@@ -1642,8 +1651,18 @@ INSTALLED_APPS = (
'openedx.core.djangoapps.content.course_structures',
'course_structure_api',
# CORS and cross-domain CSRF
'corsheaders',
'cors_csrf'
)
######################### CSRF #########################################
# Forwards-compatibility with Django 1.7
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
######################### MARKETING SITE ###############################
EDXMKTG_COOKIE_NAME = 'edxloggedin'
MKTG_URLS = {}
......@@ -1696,11 +1715,6 @@ if FEATURES.get('AUTH_USE_CAS'):
############# CORS headers for cross-domain requests #################
if FEATURES.get('ENABLE_CORS_HEADERS'):
INSTALLED_APPS += ('corsheaders', 'cors_csrf')
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
'cors_csrf.middleware.CorsCSRFMiddleware',
) + MIDDLEWARE_CLASSES
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = ()
CORS_ORIGIN_ALLOW_ALL = False
......@@ -2055,6 +2069,10 @@ SEARCH_ENGINE = None
# Use the LMS specific result processor
SEARCH_RESULT_PROCESSOR = "lms.lib.courseware_search.lms_result_processor.LmsSearchResultProcessor"
##### CDN EXPERIMENT/MONITORING FLAGS #####
PERFORMANCE_GRAPHITE_URL = ''
CDN_VIDEO_URLS = {}
# The configuration for learner profiles
PROFILE_CONFIGURATION = {
# Default visibility level for accounts without a specified value
......
......@@ -17,7 +17,7 @@ from status.status import get_site_status_msg
## Provide a hook for themes to inject branding on top.
<%block name="navigation_top" />
<%block cached="False">
<%block>
<%
try:
course_id = course.id.to_deprecated_string()
......
......@@ -17,7 +17,7 @@ from status.status import get_site_status_msg
## Provide a hook for themes to inject branding on top.
<%block name="navigation_top" />
<%block cached="False">
<%block>
<%
try:
course_id = course.id.to_deprecated_string()
......
......@@ -164,7 +164,7 @@
$("#video_${id}").bind("html5:canplaythrough", null, function() {
if (!beaconSent) {
timeElapsed = Date.now() - cdnStartTime;
sendMetricToGraphite("loadtime_${cdn_exp_group}", timeElapsed);
sendMetricToGraphite("videocdnexp.${id}.${cdn_exp_group}.loadtime", timeElapsed);
}
beaconSent = true;
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment