Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
13c076e6
Commit
13c076e6
authored
Mar 07, 2014
by
Ned Batchelder
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2736 from johncox-google/johncox/feature/auth
Add auth module
parents
9e88fb15
8ecfa867
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
494 additions
and
2 deletions
+494
-2
common/djangoapps/third_party_auth/__init__.py
+0
-0
common/djangoapps/third_party_auth/pipeline.py
+9
-0
common/djangoapps/third_party_auth/provider.py
+125
-0
common/djangoapps/third_party_auth/settings.py
+106
-0
common/djangoapps/third_party_auth/tests/__init__.py
+0
-0
common/djangoapps/third_party_auth/tests/test_provider.py
+71
-0
common/djangoapps/third_party_auth/tests/test_settings.py
+68
-0
common/djangoapps/third_party_auth/tests/test_settings_integration.py
+39
-0
common/djangoapps/third_party_auth/tests/testutil.py
+34
-0
common/djangoapps/third_party_auth/urls.py
+7
-0
lms/envs/aws.py
+3
-0
lms/envs/common.py
+9
-0
lms/startup.py
+14
-0
lms/urls.py
+6
-0
pylintrc
+2
-2
requirements/edx/base.txt
+1
-0
No files found.
common/djangoapps/third_party_auth/__init__.py
0 → 100644
View file @
13c076e6
common/djangoapps/third_party_auth/pipeline.py
0 → 100644
View file @
13c076e6
"""Auth pipeline definitions."""
from
social.pipeline
import
partial
@partial.partial
def
step
(
*
args
,
**
kwargs
):
"""Fake pipeline step; just throws loudly for now."""
raise
NotImplementedError
(
'
%
s,
%
s'
%
(
args
,
kwargs
))
common/djangoapps/third_party_auth/provider.py
0 → 100644
View file @
13c076e6
"""Third-party auth provider definitions.
Loaded by Django's settings mechanism. Consequently, this module must not
invoke the Django armature.
"""
class
BaseProvider
(
object
):
"""Abstract base class for third-party auth providers.
All providers must subclass BaseProvider -- otherwise, they cannot be put
in the provider Registry.
"""
# String. Dot-delimited module.Class. The name of the backend
# implementation to load.
AUTHENTICATION_BACKEND
=
None
# String. User-facing name of the provider. Must be unique across all
# enabled providers.
NAME
=
None
# Dict of string -> object. Settings that will be merged into Django's
# settings instance. In most cases the value will be None, since real
# values are merged from .json files (foo.auth.json; foo.env.json) onto the
# settings instance during application initialization.
SETTINGS
=
{}
@classmethod
def
merge_onto
(
cls
,
settings
):
"""Merge class-level settings onto a django `settings` module."""
for
key
,
value
in
cls
.
SETTINGS
.
iteritems
():
setattr
(
settings
,
key
,
value
)
class
GoogleOauth2
(
BaseProvider
):
"""Provider for Google's Oauth2 auth system."""
AUTHENTICATION_BACKEND
=
'social.backends.google.GoogleOAuth2'
NAME
=
'Google'
SETTINGS
=
{
'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY'
:
None
,
'SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET'
:
None
,
}
class
LinkedInOauth2
(
BaseProvider
):
"""Provider for LinkedIn's Oauth2 auth system."""
AUTHENTICATION_BACKEND
=
'social.backends.linkedin.LinkedinOAuth2'
NAME
=
'LinkedIn'
SETTINGS
=
{
'SOCIAL_AUTH_LINKEDIN_OAUTH2_KEY'
:
None
,
'SOCIAL_AUTH_LINKEDIN_OAUTH2_SECRET'
:
None
,
}
class
MozillaPersona
(
BaseProvider
):
"""Provider for Mozilla's Persona auth system."""
AUTHENTICATION_BACKEND
=
'social.backends.persona.PersonaAuth'
NAME
=
'Mozilla Persona'
class
Registry
(
object
):
"""Singleton registry of third-party auth providers.
Providers must subclass BaseProvider in order to be usable in the registry.
"""
_CONFIGURED
=
False
_ENABLED
=
{}
@classmethod
def
_check_configured
(
cls
):
"""Ensures registry is configured."""
if
not
cls
.
_CONFIGURED
:
raise
RuntimeError
(
'Registry not configured'
)
@classmethod
def
_get_all
(
cls
):
"""Gets all provider implementations loaded into the Python runtime."""
# BaseProvider does so have __subclassess__. pylint: disable-msg=no-member
return
{
klass
.
NAME
:
klass
for
klass
in
BaseProvider
.
__subclasses__
()}
@classmethod
def
_enable
(
cls
,
provider
):
"""Enables a single `provider`."""
if
provider
.
NAME
in
cls
.
_ENABLED
:
raise
ValueError
(
'Provider
%
s already enabled'
%
provider
.
NAME
)
cls
.
_ENABLED
[
provider
.
NAME
]
=
provider
@classmethod
def
configure_once
(
cls
,
provider_names
):
"""Configures providers.
Takes `provider_names`, a list of string.
"""
if
cls
.
_CONFIGURED
:
raise
ValueError
(
'Provider registry already configured'
)
# Flip the bit eagerly -- configure() should not be re-callable if one
# _enable call fails.
cls
.
_CONFIGURED
=
True
for
name
in
provider_names
:
all_providers
=
cls
.
_get_all
()
if
name
not
in
all_providers
:
raise
ValueError
(
'No implementation found for provider '
+
name
)
cls
.
_enable
(
all_providers
.
get
(
name
))
@classmethod
def
enabled
(
cls
):
"""Returns list of enabled providers."""
cls
.
_check_configured
()
return
sorted
(
cls
.
_ENABLED
.
values
(),
key
=
lambda
provider
:
provider
.
NAME
)
@classmethod
def
get
(
cls
,
provider_name
):
"""Gets provider named `provider_name` string if enabled, else None."""
cls
.
_check_configured
()
return
cls
.
_ENABLED
.
get
(
provider_name
)
@classmethod
def
_reset
(
cls
):
"""Returns the registry to an unconfigured state; for tests only."""
cls
.
_CONFIGURED
=
False
cls
.
_ENABLED
=
{}
common/djangoapps/third_party_auth/settings.py
0 → 100644
View file @
13c076e6
"""Settings for the third-party auth module.
Defers configuration of settings so we can inspect the provider registry and
create settings placeholders for only those values actually needed by a given
deployment. Required by Django; consequently, this file must not invoke the
Django armature.
The flow for settings registration is:
The base settings file contains a boolean, ENABLE_THIRD_PARTY_AUTH, indicating
whether this module is enabled. Ancillary settings files (aws.py, dev.py) put
options in THIRD_PARTY_SETTINGS. startup.py probes the ENABLE_THIRD_PARTY_AUTH.
If true, it:
a) loads this module.
b) calls apply_settings(), passing in settings.THIRD_PARTY_AUTH.
THIRD_PARTY AUTH is a dict of the form
'THIRD_PARTY_AUTH': {
'<PROVIDER_NAME>': {
'<PROVIDER_SETTING_NAME>': '<PROVIDER_SETTING_VALUE>',
[...]
},
[...]
}
If you are using a dev settings file, your settings dict starts at the
level of <PROVIDER_NAME> and is a map of provider name string to
settings dict. If you are using an auth.json file, it should contain a
THIRD_PARTY_AUTH entry as above.
c) apply_settings() builds a list of <PROVIDER_NAMES>. These are the
enabled third party auth providers for the deployment. These are enabled
in provider.Registry, the canonical list of enabled providers.
d) then, it sets global, provider-independent settings.
e) then, it sets provider-specific settings. For each enabled provider, we
read its SETTINGS member. These are merged onto the Django settings
object. In most cases these are stubs and the real values are set from
THIRD_PARTY_AUTH. All values that are set from this dict must first be
initialized from SETTINGS. This allows us to validate the dict and
ensure that the values match expected configuration options on the
provider.
f) finally, the (key, value) pairs from the dict file are merged onto the
django settings object.
"""
from
.
import
provider
def
_merge_auth_info
(
django_settings
,
auth_info
):
"""Merge `auth_info` dict onto `django_settings` module."""
enabled_provider_names
=
[]
to_merge
=
[]
for
provider_name
,
provider_dict
in
auth_info
.
items
():
enabled_provider_names
.
append
(
provider_name
)
# Merge iff all settings have been intialized.
for
key
in
provider_dict
:
if
key
not
in
dir
(
django_settings
):
raise
ValueError
(
'Auth setting
%
s not initialized'
%
key
)
to_merge
.
append
(
provider_dict
)
for
passed_validation
in
to_merge
:
for
key
,
value
in
passed_validation
.
iteritems
():
setattr
(
django_settings
,
key
,
value
)
def
_set_global_settings
(
django_settings
):
"""Set provider-independent settings."""
# Register and configure python-social-auth with Django.
django_settings
.
INSTALLED_APPS
+=
(
'social.apps.django_app.default'
,
'third_party_auth'
,
)
django_settings
.
TEMPLATE_CONTEXT_PROCESSORS
+=
(
'social.apps.django_app.context_processors.backends'
,
'social.apps.django_app.context_processors.login_redirect'
,
)
# Inject our customized auth pipeline. All auth backends must work with
# this pipeline.
django_settings
.
SOCIAL_AUTH_PIPELINE
=
(
'third_party_auth.pipeline.step'
,
)
def
_set_provider_settings
(
django_settings
,
enabled_providers
,
auth_info
):
"""Set provider-specific settings."""
# Must prepend here so we get called first.
django_settings
.
AUTHENTICATION_BACKENDS
=
(
tuple
(
enabled_provider
.
AUTHENTICATION_BACKEND
for
enabled_provider
in
enabled_providers
)
+
django_settings
.
AUTHENTICATION_BACKENDS
)
# Merge settings from provider classes, and configure all placeholders.
for
enabled_provider
in
enabled_providers
:
enabled_provider
.
merge_onto
(
django_settings
)
# Merge settings from <deployment>.auth.json.
_merge_auth_info
(
django_settings
,
auth_info
)
def
apply_settings
(
auth_info
,
django_settings
):
"""Apply settings from `auth_info` dict to `django_settings` module."""
provider_names
=
auth_info
.
keys
()
provider
.
Registry
.
configure_once
(
provider_names
)
enabled_providers
=
provider
.
Registry
.
enabled
()
_set_global_settings
(
django_settings
)
_set_provider_settings
(
django_settings
,
enabled_providers
,
auth_info
)
common/djangoapps/third_party_auth/tests/__init__.py
0 → 100644
View file @
13c076e6
common/djangoapps/third_party_auth/tests/test_provider.py
0 → 100644
View file @
13c076e6
"""
Test configuration of providers.
"""
from
third_party_auth
import
provider
from
third_party_auth.tests
import
testutil
class
RegistryTest
(
testutil
.
TestCase
):
"""Tests registry discovery and operation."""
# Allow access to protected methods (or module-protected methods) under
# test.
# pylint: disable-msg=protected-access
def
test_calling_configure_once_twice_raises_value_error
(
self
):
provider
.
Registry
.
configure_once
([
provider
.
GoogleOauth2
.
NAME
])
with
self
.
assertRaisesRegexp
(
ValueError
,
'^.*already configured$'
):
provider
.
Registry
.
configure_once
([
provider
.
GoogleOauth2
.
NAME
])
def
test_configure_once_adds_gettable_providers
(
self
):
provider
.
Registry
.
configure_once
([
provider
.
GoogleOauth2
.
NAME
])
self
.
assertIs
(
provider
.
GoogleOauth2
,
provider
.
Registry
.
get
(
provider
.
GoogleOauth2
.
NAME
))
def
test_configuring_provider_with_no_implementation_raises_value_error
(
self
):
with
self
.
assertRaisesRegexp
(
ValueError
,
'^.*no_implementation$'
):
provider
.
Registry
.
configure_once
([
'no_implementation'
])
def
test_configuring_single_provider_twice_raises_value_error
(
self
):
provider
.
Registry
.
_enable
(
provider
.
GoogleOauth2
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'^.*already enabled'
):
provider
.
Registry
.
configure_once
([
provider
.
GoogleOauth2
.
NAME
])
def
test_custom_provider_can_be_enabled
(
self
):
name
=
'CustomProvider'
with
self
.
assertRaisesRegexp
(
ValueError
,
'^No implementation.*$'
):
provider
.
Registry
.
configure_once
([
name
])
class
CustomProvider
(
provider
.
BaseProvider
):
"""Custom class to ensure BaseProvider children outside provider can be enabled."""
NAME
=
name
provider
.
Registry
.
_reset
()
provider
.
Registry
.
configure_once
([
CustomProvider
.
NAME
])
self
.
assertEqual
([
CustomProvider
],
provider
.
Registry
.
enabled
())
def
test_enabled_raises_runtime_error_if_not_configured
(
self
):
with
self
.
assertRaisesRegexp
(
RuntimeError
,
'^.*not configured$'
):
provider
.
Registry
.
enabled
()
def
test_enabled_returns_list_of_enabled_providers_sorted_by_name
(
self
):
all_providers
=
provider
.
Registry
.
_get_all
()
provider
.
Registry
.
configure_once
(
all_providers
.
keys
())
self
.
assertEqual
(
sorted
(
all_providers
.
values
(),
key
=
lambda
provider
:
provider
.
NAME
),
provider
.
Registry
.
enabled
())
def
test_get_raises_runtime_error_if_not_configured
(
self
):
with
self
.
assertRaisesRegexp
(
RuntimeError
,
'^.*not configured$'
):
provider
.
Registry
.
get
(
'anything'
)
def
test_get_returns_enabled_provider
(
self
):
provider
.
Registry
.
configure_once
([
provider
.
GoogleOauth2
.
NAME
])
self
.
assertIs
(
provider
.
GoogleOauth2
,
provider
.
Registry
.
get
(
provider
.
GoogleOauth2
.
NAME
))
def
test_get_returns_none_if_provider_not_enabled
(
self
):
provider
.
Registry
.
configure_once
([])
self
.
assertIsNone
(
provider
.
Registry
.
get
(
provider
.
MozillaPersona
.
NAME
))
common/djangoapps/third_party_auth/tests/test_settings.py
0 → 100644
View file @
13c076e6
"""
Unit tests for settings code.
"""
from
third_party_auth
import
provider
from
third_party_auth
import
settings
from
third_party_auth.tests
import
testutil
_ORIGINAL_AUTHENTICATION_BACKENDS
=
(
'first_authentication_backend'
,)
_ORIGINAL_INSTALLED_APPS
=
(
'first_installed_app'
,)
_ORIGINAL_TEMPLATE_CONTEXT_PROCESSORS
=
(
'first_template_context_preprocessor'
,)
_SETTINGS_MAP
=
{
'AUTHENTICATION_BACKENDS'
:
_ORIGINAL_AUTHENTICATION_BACKENDS
,
'INSTALLED_APPS'
:
_ORIGINAL_INSTALLED_APPS
,
'TEMPLATE_CONTEXT_PROCESSORS'
:
_ORIGINAL_TEMPLATE_CONTEXT_PROCESSORS
,
}
class
SettingsUnitTest
(
testutil
.
TestCase
):
"""Unit tests for settings management code."""
# Suppress sprurious no-member warning on fakes.
# pylint: disable-msg=no-member
def
setUp
(
self
):
super
(
SettingsUnitTest
,
self
)
.
setUp
()
self
.
settings
=
testutil
.
FakeDjangoSettings
(
_SETTINGS_MAP
)
def
test_apply_settings_adds_third_party_auth_to_installed_apps
(
self
):
settings
.
apply_settings
({},
self
.
settings
)
self
.
assertIn
(
'third_party_auth'
,
self
.
settings
.
INSTALLED_APPS
)
def
test_apply_settings_enables_no_providers_and_completes_when_app_info_empty
(
self
):
settings
.
apply_settings
({},
self
.
settings
)
self
.
assertEqual
([],
provider
.
Registry
.
enabled
())
def
test_apply_settings_initializes_stubs_and_merges_settings_from_auth_info
(
self
):
for
key
in
provider
.
GoogleOauth2
.
SETTINGS
:
self
.
assertFalse
(
hasattr
(
self
.
settings
,
key
))
auth_info
=
{
provider
.
GoogleOauth2
.
NAME
:
{
'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY'
:
'google_oauth2_key'
,
},
}
settings
.
apply_settings
(
auth_info
,
self
.
settings
)
self
.
assertEqual
(
'google_oauth2_key'
,
self
.
settings
.
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY
)
self
.
assertIsNone
(
self
.
settings
.
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET
)
def
test_apply_settings_prepends_auth_backends
(
self
):
self
.
assertEqual
(
_ORIGINAL_AUTHENTICATION_BACKENDS
,
self
.
settings
.
AUTHENTICATION_BACKENDS
)
settings
.
apply_settings
({
provider
.
GoogleOauth2
.
NAME
:
{},
provider
.
MozillaPersona
.
NAME
:
{}},
self
.
settings
)
self
.
assertEqual
((
provider
.
GoogleOauth2
.
AUTHENTICATION_BACKEND
,
provider
.
MozillaPersona
.
AUTHENTICATION_BACKEND
)
+
_ORIGINAL_AUTHENTICATION_BACKENDS
,
self
.
settings
.
AUTHENTICATION_BACKENDS
)
def
test_apply_settings_raises_value_error_if_provider_contains_uninitialized_setting
(
self
):
bad_setting_name
=
'bad_setting'
self
.
assertNotIn
(
'bad_setting_name'
,
provider
.
GoogleOauth2
.
SETTINGS
)
auth_info
=
{
provider
.
GoogleOauth2
.
NAME
:
{
bad_setting_name
:
None
,
},
}
with
self
.
assertRaisesRegexp
(
ValueError
,
'^.*not initialized$'
):
settings
.
apply_settings
(
auth_info
,
self
.
settings
)
common/djangoapps/third_party_auth/tests/test_settings_integration.py
0 → 100644
View file @
13c076e6
"""
Integration tests for settings code.
"""
import
mock
import
unittest
from
django.conf
import
settings
from
third_party_auth
import
provider
from
third_party_auth
import
settings
as
auth_settings
from
third_party_auth.tests
import
testutil
_AUTH_FEATURES_KEY
=
'ENABLE_THIRD_PARTY_AUTH'
class
SettingsIntegrationTest
(
testutil
.
TestCase
):
"""Integration tests of auth settings pipeline."""
@unittest.skipUnless
(
_AUTH_FEATURES_KEY
in
settings
.
FEATURES
,
_AUTH_FEATURES_KEY
+
' not in settings.FEATURES'
)
def
test_enable_third_party_auth_is_disabled_by_default
(
self
):
self
.
assertIs
(
False
,
settings
.
FEATURES
.
get
(
_AUTH_FEATURES_KEY
))
@mock.patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_THIRD_PARTY_AUTH'
:
True
})
def
test_can_enable_google_oauth2
(
self
):
auth_settings
.
apply_settings
({
'Google'
:
{
'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY'
:
'google_key'
}},
settings
)
self
.
assertEqual
([
provider
.
GoogleOauth2
],
provider
.
Registry
.
enabled
())
self
.
assertEqual
(
'google_key'
,
settings
.
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY
)
@mock.patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_THIRD_PARTY_AUTH'
:
True
})
def
test_can_enable_linkedin_oauth2
(
self
):
auth_settings
.
apply_settings
({
'LinkedIn'
:
{
'SOCIAL_AUTH_LINKEDIN_OAUTH2_KEY'
:
'linkedin_key'
}},
settings
)
self
.
assertEqual
([
provider
.
LinkedInOauth2
],
provider
.
Registry
.
enabled
())
self
.
assertEqual
(
'linkedin_key'
,
settings
.
SOCIAL_AUTH_LINKEDIN_OAUTH2_KEY
)
@mock.patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_THIRD_PARTY_ATUH'
:
True
})
def
test_can_enable_mozilla_persona
(
self
):
auth_settings
.
apply_settings
({
'Mozilla Persona'
:
{}},
settings
)
self
.
assertEqual
([
provider
.
MozillaPersona
],
provider
.
Registry
.
enabled
())
common/djangoapps/third_party_auth/tests/testutil.py
0 → 100644
View file @
13c076e6
"""
Utilities for writing third_party_auth tests.
Used by Django and non-Django tests; must not have Django deps.
"""
import
unittest
from
third_party_auth
import
provider
class
FakeDjangoSettings
(
object
):
"""A fake for Django settings."""
def
__init__
(
self
,
mappings
):
"""Initializes the fake from `mappings`, a dict."""
for
key
,
value
in
mappings
.
iteritems
():
setattr
(
self
,
key
,
value
)
class
TestCase
(
unittest
.
TestCase
):
"""Base class for auth test cases."""
# Allow access to protected methods (or module-protected methods) under
# test.
# pylint: disable-msg=protected-access
def
setUp
(
self
):
super
(
TestCase
,
self
)
.
setUp
()
provider
.
Registry
.
_reset
()
def
tearDown
(
self
):
provider
.
Registry
.
_reset
()
super
(
TestCase
,
self
)
.
tearDown
()
common/djangoapps/third_party_auth/urls.py
0 → 100644
View file @
13c076e6
"""Url configuration for the auth module."""
from
django.conf.urls
import
include
,
patterns
,
url
urlpatterns
=
patterns
(
''
,
url
(
r'^auth/'
,
include
(
'social.apps.django_app.urls'
,
namespace
=
'social'
)),
)
lms/envs/aws.py
View file @
13c076e6
...
...
@@ -385,3 +385,6 @@ TIME_ZONE_DISPLAYED_FOR_DEADLINES = ENV_TOKENS.get("TIME_ZONE_DISPLAYED_FOR_DEAD
##### X-Frame-Options response header settings #####
X_FRAME_OPTIONS
=
ENV_TOKENS
.
get
(
'X_FRAME_OPTIONS'
,
X_FRAME_OPTIONS
)
##### Third-party auth options ################################################
THIRD_PARTY_AUTH
=
AUTH_TOKENS
.
get
(
'THIRD_PARTY_AUTH'
,
THIRD_PARTY_AUTH
)
lms/envs/common.py
View file @
13c076e6
...
...
@@ -234,6 +234,10 @@ FEATURES = {
# Turn on/off Microsites feature
'USE_MICROSITES'
:
False
,
# Turn on third-party auth. Disabled for now because full implementations are not yet available. Remember to syncdb
# if you enable this; we don't create tables by default.
'ENABLE_THIRD_PARTY_AUTH'
:
False
,
}
# Used for A/B testing
...
...
@@ -1247,6 +1251,7 @@ LINKEDIN_API = {
'COMPANY_ID'
:
'2746406'
,
}
##### ACCOUNT LOCKOUT DEFAULT PARAMETERS #####
MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED
=
5
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS
=
15
*
60
...
...
@@ -1465,3 +1470,7 @@ for app_name in OPTIONAL_APPS:
except
ImportError
:
continue
INSTALLED_APPS
+=
(
app_name
,)
# Stub for third_party_auth options.
# See common/djangoapps/third_party_auth/settings.py for configuration details.
THIRD_PARTY_AUTH
=
{}
lms/startup.py
View file @
13c076e6
...
...
@@ -26,6 +26,9 @@ def run():
if
settings
.
FEATURES
.
get
(
'USE_MICROSITES'
,
False
):
enable_microsites
()
if
settings
.
FEATURES
.
get
(
'ENABLE_THIRD_PARTY_AUTH'
,
False
):
enable_third_party_auth
()
def
enable_theme
():
"""
...
...
@@ -99,3 +102,14 @@ def enable_microsites():
edxmako
.
startup
.
run
()
settings
.
STATICFILES_DIRS
.
insert
(
0
,
microsites_root
)
def
enable_third_party_auth
():
"""
Enable the use of third_party_auth, which allows users to sign in to edX
using other identity providers. For configuration details, see
common/djangoapps/third_party_auth/settings.py.
"""
from
third_party_auth
import
settings
as
auth_settings
auth_settings
.
apply_settings
(
settings
.
THIRD_PARTY_AUTH
,
settings
)
lms/urls.py
View file @
13c076e6
...
...
@@ -488,6 +488,12 @@ if settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING'):
url
(
r'^auto_auth$'
,
'student.views.auto_auth'
),
)
# Third-party auth.
if
settings
.
FEATURES
.
get
(
'ENABLE_THIRD_PARTY_AUTH'
):
urlpatterns
+=
(
url
(
r''
,
include
(
'third_party_auth.urls'
)),
)
urlpatterns
=
patterns
(
*
urlpatterns
)
if
settings
.
DEBUG
:
...
...
pylintrc
View file @
13c076e6
...
...
@@ -153,10 +153,10 @@ const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__)|log|urlpatterns)$
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=
[a-z_][a-z0-9_]{2,30}
$
function-rgx=
([a-z_][a-z0-9_]{2,30}|test_[a-z0-9_]+)
$
# Regular expression which should only match correct method names
method-rgx=([a-z_][a-z0-9_]{2,60}|setUp|set[Uu]pClass|tearDown|tear[Dd]ownClass|assert[A-Z]\w*|maxDiff)$
method-rgx=([a-z_][a-z0-9_]{2,60}|setUp|set[Uu]pClass|tearDown|tear[Dd]ownClass|assert[A-Z]\w*|maxDiff
|test_[a-z0-9_]+
)$
# Regular expression which should only match correct instance attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
...
...
requirements/edx/base.txt
View file @
13c076e6
...
...
@@ -60,6 +60,7 @@ pyparsing==1.5.6
python-memcached==1.48
python-openid==2.2.5
python-dateutil==2.1
python-social-auth==0.1.21
pytz==2012h
pysrt==0.4.7
PyYAML==3.10
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment