Commit 3b9550bd by Saleem Latif

Disable linking of personal accounts to enterprise customers via SSO

parent 773b622e
...@@ -567,6 +567,14 @@ def ensure_user_information(strategy, auth_entry, backend=None, user=None, socia ...@@ -567,6 +567,14 @@ def ensure_user_information(strategy, auth_entry, backend=None, user=None, socia
(current_provider.skip_email_verification or current_provider.send_to_registration_first)) (current_provider.skip_email_verification or current_provider.send_to_registration_first))
if not user: if not user:
details = kwargs.get('details', {})
if 'email' in details or 'username' in details:
# pylint: disable=invalid-name
qs = {'email': details['email']} if details.get('email') else \
{'username': details.get('username')}
if User.objects.filter(**qs).exists():
return dispatch_to_login()
if is_api(auth_entry): if is_api(auth_entry):
return HttpResponseBadRequest() return HttpResponseBadRequest()
elif auth_entry == AUTH_ENTRY_LOGIN: elif auth_entry == AUTH_ENTRY_LOGIN:
......
...@@ -640,6 +640,8 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi ...@@ -640,6 +640,8 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi
"finishAuthUrl": finish_auth_url, "finishAuthUrl": finish_auth_url,
"errorMessage": None, "errorMessage": None,
"registerFormSubmitButtonText": "Create Account", "registerFormSubmitButtonText": "Create Account",
"hideSignInLink": False,
"syncLearnerProfileData": False,
} }
if expected_ec is not None: if expected_ec is not None:
# If we set an EnterpriseCustomer, third-party auth providers ought to be hidden. # If we set an EnterpriseCustomer, third-party auth providers ought to be hidden.
......
...@@ -124,6 +124,22 @@ def login_and_registration_form(request, initial_mode="login"): ...@@ -124,6 +124,22 @@ def login_and_registration_form(request, initial_mode="login"):
} for message in messages.get_messages(request) if 'account-activation' in message.tags } for message in messages.get_messages(request) if 'account-activation' in message.tags
] ]
account_creation_allowed = configuration_helpers.get_value(
'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)
)
# add user details from running pipeline
pipeline_user_details = {}
running_pipeline = pipeline.get(request)
if running_pipeline:
pipeline_user_details = running_pipeline['kwargs']['details']
if 'email' in pipeline_user_details or 'username' in pipeline_user_details:
# pylint: disable=invalid-name
qs = {'email': pipeline_user_details['email']} if pipeline_user_details.get('email') else \
{'username': pipeline_user_details.get('username')}
if User.objects.filter(**qs).exists():
account_creation_allowed = False
# Otherwise, render the combined login/registration page # Otherwise, render the combined login/registration page
context = { context = {
'data': { 'data': {
...@@ -145,8 +161,8 @@ def login_and_registration_form(request, initial_mode="login"): ...@@ -145,8 +161,8 @@ def login_and_registration_form(request, initial_mode="login"):
'login_form_desc': json.loads(form_descriptions['login']), 'login_form_desc': json.loads(form_descriptions['login']),
'registration_form_desc': json.loads(form_descriptions['registration']), 'registration_form_desc': json.loads(form_descriptions['registration']),
'password_reset_form_desc': json.loads(form_descriptions['password_reset']), 'password_reset_form_desc': json.loads(form_descriptions['password_reset']),
'account_creation_allowed': configuration_helpers.get_value( 'account_creation_allowed': account_creation_allowed,
'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)) 'pipeline_user_details': pipeline_user_details
}, },
'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header
'responsive': True, 'responsive': True,
...@@ -236,6 +252,7 @@ def update_context_for_enterprise(request, context): ...@@ -236,6 +252,7 @@ def update_context_for_enterprise(request, context):
context = context.copy() context = context.copy()
sidebar_context = enterprise_sidebar_context(request) sidebar_context = enterprise_sidebar_context(request)
sync_learner_profile_data = context['data']['third_party_auth']['syncLearnerProfileData']
if sidebar_context: if sidebar_context:
context['data']['registration_form_desc']['fields'] = enterprise_fields_only( context['data']['registration_form_desc']['fields'] = enterprise_fields_only(
...@@ -247,6 +264,11 @@ def update_context_for_enterprise(request, context): ...@@ -247,6 +264,11 @@ def update_context_for_enterprise(request, context):
else: else:
context['enable_enterprise_sidebar'] = False context['enable_enterprise_sidebar'] = False
if sync_learner_profile_data:
context['data']['hide_auth_warnings'] = True
enterprise_customer = enterprise_customer_for_request(request)
context['data']['enterprise_name'] = enterprise_customer and enterprise_customer['name']
return context return context
...@@ -327,6 +349,7 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None): ...@@ -327,6 +349,7 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None):
"finishAuthUrl": None, "finishAuthUrl": None,
"errorMessage": None, "errorMessage": None,
"registerFormSubmitButtonText": _("Create Account"), "registerFormSubmitButtonText": _("Create Account"),
"syncLearnerProfileData": False,
} }
if third_party_auth.is_enabled(): if third_party_auth.is_enabled():
...@@ -358,6 +381,8 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None): ...@@ -358,6 +381,8 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None):
if current_provider is not None: if current_provider is not None:
context["currentProvider"] = current_provider.name context["currentProvider"] = current_provider.name
context["finishAuthUrl"] = pipeline.get_complete_url(current_provider.backend_name) context["finishAuthUrl"] = pipeline.get_complete_url(current_provider.backend_name)
context["hideSignInLink"] = bool(current_provider.sync_learner_profile_data)
context["syncLearnerProfileData"] = current_provider.sync_learner_profile_data
if current_provider.skip_registration_form: if current_provider.skip_registration_form:
# For enterprise (and later for everyone), we need to get explicit consent to the # For enterprise (and later for everyone), we need to get explicit consent to the
......
...@@ -71,10 +71,12 @@ ...@@ -71,10 +71,12 @@
}; };
this.platformName = options.platform_name; this.platformName = options.platform_name;
this.enterpriseName = options.enterprise_name;
this.supportURL = options.support_link; this.supportURL = options.support_link;
this.passwordResetSupportUrl = options.password_reset_support_link; this.passwordResetSupportUrl = options.password_reset_support_link;
this.createAccountOption = options.account_creation_allowed; this.createAccountOption = options.account_creation_allowed;
this.hideAuthWarnings = options.hide_auth_warnings || false; this.hideAuthWarnings = options.hide_auth_warnings || false;
this.pipelineUserDetails = options.pipeline_user_details;
// The login view listens for 'sync' events from the reset model // The login view listens for 'sync' events from the reset model
this.resetModel = new PasswordResetModel({}, { this.resetModel = new PasswordResetModel({}, {
...@@ -133,7 +135,8 @@ ...@@ -133,7 +135,8 @@
supportURL: this.supportURL, supportURL: this.supportURL,
passwordResetSupportUrl: this.passwordResetSupportUrl, passwordResetSupportUrl: this.passwordResetSupportUrl,
createAccountOption: this.createAccountOption, createAccountOption: this.createAccountOption,
hideAuthWarnings: this.hideAuthWarnings hideAuthWarnings: this.hideAuthWarnings,
pipelineUserDetails: this.pipelineUserDetails
}); });
// Listen for 'password-help' event to toggle sub-views // Listen for 'password-help' event to toggle sub-views
...@@ -170,6 +173,7 @@ ...@@ -170,6 +173,7 @@
model: model, model: model,
thirdPartyAuth: this.thirdPartyAuth, thirdPartyAuth: this.thirdPartyAuth,
platformName: this.platformName, platformName: this.platformName,
enterpriseName: this.enterpriseName,
hideAuthWarnings: this.hideAuthWarnings hideAuthWarnings: this.hideAuthWarnings
}); });
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
this.createAccountOption = data.createAccountOption; this.createAccountOption = data.createAccountOption;
this.accountActivationMessages = data.accountActivationMessages; this.accountActivationMessages = data.accountActivationMessages;
this.hideAuthWarnings = data.hideAuthWarnings; this.hideAuthWarnings = data.hideAuthWarnings;
this.pipelineUserDetails = data.pipelineUserDetails;
this.listenTo(this.model, 'sync', this.saveSuccess); this.listenTo(this.model, 'sync', this.saveSuccess);
this.listenTo(this.resetModel, 'sync', this.resetEmail); this.listenTo(this.resetModel, 'sync', this.resetEmail);
...@@ -66,7 +67,8 @@ ...@@ -66,7 +67,8 @@
providers: this.providers, providers: this.providers,
hasSecondaryProviders: this.hasSecondaryProviders, hasSecondaryProviders: this.hasSecondaryProviders,
platformName: this.platformName, platformName: this.platformName,
createAccountOption: this.createAccountOption createAccountOption: this.createAccountOption,
pipelineUserDetails: this.pipelineUserDetails
} }
})); }));
......
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
data.thirdPartyAuth.secondaryProviders && data.thirdPartyAuth.secondaryProviders.length data.thirdPartyAuth.secondaryProviders && data.thirdPartyAuth.secondaryProviders.length
); );
this.currentProvider = data.thirdPartyAuth.currentProvider || ''; this.currentProvider = data.thirdPartyAuth.currentProvider || '';
this.hideSignInLink = data.thirdPartyAuth.hideSignInLink || false;
this.enterpriseName = data.enterpriseName || '';
this.errorMessage = data.thirdPartyAuth.errorMessage || ''; this.errorMessage = data.thirdPartyAuth.errorMessage || '';
this.platformName = data.platformName; this.platformName = data.platformName;
this.autoSubmit = data.thirdPartyAuth.autoSubmitRegForm; this.autoSubmit = data.thirdPartyAuth.autoSubmitRegForm;
...@@ -141,6 +143,8 @@ ...@@ -141,6 +143,8 @@
context: { context: {
fields: fields, fields: fields,
currentProvider: this.currentProvider, currentProvider: this.currentProvider,
hideSignInLink: this.hideSignInLink,
enterpriseName: this.enterpriseName,
providers: this.providers, providers: this.providers,
hasSecondaryProviders: this.hasSecondaryProviders, hasSecondaryProviders: this.hasSecondaryProviders,
platformName: this.platformName, platformName: this.platformName,
......
...@@ -259,6 +259,20 @@ ...@@ -259,6 +259,20 @@
display: none; display: none;
} }
input[readonly] {
font-family: OpenSans-Regular;
background-color: #e6e4e4;
color: #292b2c;
font-size: 22px;
border: none;
margin: 5px 0;
&:focus {
outline: none;
}
}
.auto-register-message { .auto-register-message {
font-size: 1.1em; font-size: 1.1em;
line-height: 1.3em; line-height: 1.3em;
...@@ -446,7 +460,8 @@ ...@@ -446,7 +460,8 @@
outline: solid 1px $gray-l3; outline: solid 1px $gray-l3;
cursor: pointer; cursor: pointer;
&:active, &:focus { &:active,
&:focus {
outline: auto; outline: auto;
} }
} }
...@@ -462,7 +477,8 @@ ...@@ -462,7 +477,8 @@
} }
} }
.tip, .label-optional { .tip,
.label-optional {
@extend %t-copy-sub1; @extend %t-copy-sub1;
color: $uxpl-gray-base; color: $uxpl-gray-base;
......
...@@ -91,7 +91,8 @@ ...@@ -91,7 +91,8 @@
<% } %> <% } %>
<% if ( restrictions.min_length ) { %> minlength="<%- restrictions.min_length %>"<% } %> <% if ( restrictions.min_length ) { %> minlength="<%- restrictions.min_length %>"<% } %>
<% if ( restrictions.max_length ) { %> maxlength="<%- restrictions.max_length %>"<% } %> <% if ( restrictions.max_length ) { %> maxlength="<%- restrictions.max_length %>"<% } %>
<% if ( required ) { %> required<% } %> <% if ( restrictions.readonly ) { %> readonly <% } %>
<% if ( required ) { %> required <% } %>
<% if ( typeof errorMessages !== 'undefined' ) { <% if ( typeof errorMessages !== 'undefined' ) {
_.each(errorMessages, function( msg, type ) {%> _.each(errorMessages, function( msg, type ) {%>
data-errormsg-<%- type %>="<%- msg %>" data-errormsg-<%- type %>="<%- msg %>"
......
<div class="js-form-feedback" aria-live="assertive" tabindex="-1"> <div class="js-form-feedback" aria-live="assertive" tabindex="-1">
</div> </div>
<div class="toggle-form"> <% if (!context.hideSignInLink) { %>
<span class="text"><%- edx.StringUtils.interpolate(gettext('Already have an {platformName} account?'), {platformName: context.platformName }) %></span> <div class="toggle-form">
<a href="#login" class="form-toggle" data-type="login"><%- gettext("Sign in.") %></a> <span class="text"><%- edx.StringUtils.interpolate(gettext('Already have an {platformName} account?'), {platformName: context.platformName }) %></span>
</div> <a href="#login" class="form-toggle" data-type="login"><%- gettext("Sign in.") %></a>
</div>
<% } %>
<h2><%- gettext('Create an Account')%></h2>
<form id="register" class="register-form" autocomplete="off" tabindex="-1" method="POST"> <form id="register" class="register-form" autocomplete="off" tabindex="-1" method="POST">
......
...@@ -835,35 +835,10 @@ class RegistrationFormFactory(object): ...@@ -835,35 +835,10 @@ class RegistrationFormFactory(object):
current_provider = third_party_auth.provider.Registry.get_from_pipeline(running_pipeline) current_provider = third_party_auth.provider.Registry.get_from_pipeline(running_pipeline)
if current_provider: if current_provider:
# Override username / email / full name self._override_registration_fields_using_identity_provider_configuration(
field_overrides = current_provider.get_register_form_data( request, current_provider, running_pipeline, form_desc
running_pipeline.get('kwargs')
) )
# When the TPA Provider is configured to skip the registration form and we are in an
# enterprise context, we need to hide all fields except for terms of service and
# ensure that the user explicitly checks that field.
hide_registration_fields_except_tos = (current_provider.skip_registration_form and
enterprise_customer_for_request(request))
for field_name in self.DEFAULT_FIELDS + self.EXTRA_FIELDS:
if field_name in field_overrides:
form_desc.override_field_properties(
field_name, default=field_overrides[field_name]
)
if (field_name not in ['terms_of_service', 'honor_code']
and field_overrides[field_name]
and hide_registration_fields_except_tos):
form_desc.override_field_properties(
field_name,
field_type="hidden",
label="",
instructions="",
)
# Hide the password field
form_desc.override_field_properties( form_desc.override_field_properties(
"password", "password",
default="", default="",
...@@ -881,3 +856,37 @@ class RegistrationFormFactory(object): ...@@ -881,3 +856,37 @@ class RegistrationFormFactory(object):
default=current_provider.name if current_provider.name else "Third Party", default=current_provider.name if current_provider.name else "Third Party",
required=False, required=False,
) )
# pylint: disable=invalid-name
def _override_registration_fields_using_identity_provider_configuration(
self, request, current_provider, running_pipeline, form_desc
):
"""
Apply form field overrides based on configuration of third party auth provider.
"""
field_overrides = current_provider.get_register_form_data(
running_pipeline.get('kwargs')
)
# When the TPA Provider is configured to skip the registration form and we are in an
# enterprise context, we need to hide all fields except for terms of service and
# ensure that the user explicitly checks that field.
hide_registration_fields_except_tos = (
(
current_provider.skip_registration_form and enterprise_customer_for_request(request)
) or current_provider.sync_learner_profile_data
)
for field_name in self.DEFAULT_FIELDS + self.EXTRA_FIELDS:
if field_name in field_overrides:
form_desc.override_field_properties(
field_name, default=field_overrides[field_name]
)
if field_name not in ['terms_of_service', 'honor_code'] and field_overrides[field_name] and \
hide_registration_fields_except_tos:
form_desc.override_field_properties(
field_name,
field_type="hidden",
label="",
instructions="",
)
...@@ -124,9 +124,9 @@ class FormDescription(object): ...@@ -124,9 +124,9 @@ class FormDescription(object):
ALLOWED_TYPES = ["text", "email", "select", "textarea", "checkbox", "password", "hidden"] ALLOWED_TYPES = ["text", "email", "select", "textarea", "checkbox", "password", "hidden"]
ALLOWED_RESTRICTIONS = { ALLOWED_RESTRICTIONS = {
"text": ["min_length", "max_length"], "text": ["min_length", "max_length", "readonly"],
"password": ["min_length", "max_length"], "password": ["min_length", "max_length", "readonly"],
"email": ["min_length", "max_length"], "email": ["min_length", "max_length", "readonly"],
} }
FIELD_TYPE_MAP = { FIELD_TYPE_MAP = {
......
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