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
(current_provider.skip_email_verification or current_provider.send_to_registration_first))
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):
return HttpResponseBadRequest()
elif auth_entry == AUTH_ENTRY_LOGIN:
......
......@@ -640,6 +640,8 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi
"finishAuthUrl": finish_auth_url,
"errorMessage": None,
"registerFormSubmitButtonText": "Create Account",
"hideSignInLink": False,
"syncLearnerProfileData": False,
}
if expected_ec is not None:
# 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"):
} 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
context = {
'data': {
......@@ -145,8 +161,8 @@ def login_and_registration_form(request, initial_mode="login"):
'login_form_desc': json.loads(form_descriptions['login']),
'registration_form_desc': json.loads(form_descriptions['registration']),
'password_reset_form_desc': json.loads(form_descriptions['password_reset']),
'account_creation_allowed': configuration_helpers.get_value(
'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True))
'account_creation_allowed': account_creation_allowed,
'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
'responsive': True,
......@@ -236,6 +252,7 @@ def update_context_for_enterprise(request, context):
context = context.copy()
sidebar_context = enterprise_sidebar_context(request)
sync_learner_profile_data = context['data']['third_party_auth']['syncLearnerProfileData']
if sidebar_context:
context['data']['registration_form_desc']['fields'] = enterprise_fields_only(
......@@ -247,6 +264,11 @@ def update_context_for_enterprise(request, context):
else:
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
......@@ -327,6 +349,7 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None):
"finishAuthUrl": None,
"errorMessage": None,
"registerFormSubmitButtonText": _("Create Account"),
"syncLearnerProfileData": False,
}
if third_party_auth.is_enabled():
......@@ -358,6 +381,8 @@ def _third_party_auth_context(request, redirect_to, tpa_hint=None):
if current_provider is not None:
context["currentProvider"] = current_provider.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:
# For enterprise (and later for everyone), we need to get explicit consent to the
......
......@@ -71,10 +71,12 @@
};
this.platformName = options.platform_name;
this.enterpriseName = options.enterprise_name;
this.supportURL = options.support_link;
this.passwordResetSupportUrl = options.password_reset_support_link;
this.createAccountOption = options.account_creation_allowed;
this.hideAuthWarnings = options.hide_auth_warnings || false;
this.pipelineUserDetails = options.pipeline_user_details;
// The login view listens for 'sync' events from the reset model
this.resetModel = new PasswordResetModel({}, {
......@@ -133,7 +135,8 @@
supportURL: this.supportURL,
passwordResetSupportUrl: this.passwordResetSupportUrl,
createAccountOption: this.createAccountOption,
hideAuthWarnings: this.hideAuthWarnings
hideAuthWarnings: this.hideAuthWarnings,
pipelineUserDetails: this.pipelineUserDetails
});
// Listen for 'password-help' event to toggle sub-views
......@@ -170,6 +173,7 @@
model: model,
thirdPartyAuth: this.thirdPartyAuth,
platformName: this.platformName,
enterpriseName: this.enterpriseName,
hideAuthWarnings: this.hideAuthWarnings
});
......
......@@ -49,6 +49,7 @@
this.createAccountOption = data.createAccountOption;
this.accountActivationMessages = data.accountActivationMessages;
this.hideAuthWarnings = data.hideAuthWarnings;
this.pipelineUserDetails = data.pipelineUserDetails;
this.listenTo(this.model, 'sync', this.saveSuccess);
this.listenTo(this.resetModel, 'sync', this.resetEmail);
......@@ -66,7 +67,8 @@
providers: this.providers,
hasSecondaryProviders: this.hasSecondaryProviders,
platformName: this.platformName,
createAccountOption: this.createAccountOption
createAccountOption: this.createAccountOption,
pipelineUserDetails: this.pipelineUserDetails
}
}));
......
......@@ -55,6 +55,8 @@
data.thirdPartyAuth.secondaryProviders && data.thirdPartyAuth.secondaryProviders.length
);
this.currentProvider = data.thirdPartyAuth.currentProvider || '';
this.hideSignInLink = data.thirdPartyAuth.hideSignInLink || false;
this.enterpriseName = data.enterpriseName || '';
this.errorMessage = data.thirdPartyAuth.errorMessage || '';
this.platformName = data.platformName;
this.autoSubmit = data.thirdPartyAuth.autoSubmitRegForm;
......@@ -141,6 +143,8 @@
context: {
fields: fields,
currentProvider: this.currentProvider,
hideSignInLink: this.hideSignInLink,
enterpriseName: this.enterpriseName,
providers: this.providers,
hasSecondaryProviders: this.hasSecondaryProviders,
platformName: this.platformName,
......
......@@ -259,6 +259,20 @@
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 {
font-size: 1.1em;
line-height: 1.3em;
......@@ -446,7 +460,8 @@
outline: solid 1px $gray-l3;
cursor: pointer;
&:active, &:focus {
&:active,
&:focus {
outline: auto;
}
}
......@@ -462,7 +477,8 @@
}
}
.tip, .label-optional {
.tip,
.label-optional {
@extend %t-copy-sub1;
color: $uxpl-gray-base;
......
......@@ -91,7 +91,8 @@
<% } %>
<% if ( restrictions.min_length ) { %> minlength="<%- restrictions.min_length %>"<% } %>
<% if ( restrictions.max_length ) { %> maxlength="<%- restrictions.max_length %>"<% } %>
<% if ( required ) { %> required<% } %>
<% if ( restrictions.readonly ) { %> readonly <% } %>
<% if ( required ) { %> required <% } %>
<% if ( typeof errorMessages !== 'undefined' ) {
_.each(errorMessages, function( msg, type ) {%>
data-errormsg-<%- type %>="<%- msg %>"
......
<div class="js-form-feedback" aria-live="assertive" tabindex="-1">
</div>
<div class="toggle-form">
<span class="text"><%- edx.StringUtils.interpolate(gettext('Already have an {platformName} account?'), {platformName: context.platformName }) %></span>
<a href="#login" class="form-toggle" data-type="login"><%- gettext("Sign in.") %></a>
</div>
<% if (!context.hideSignInLink) { %>
<div class="toggle-form">
<span class="text"><%- edx.StringUtils.interpolate(gettext('Already have an {platformName} account?'), {platformName: context.platformName }) %></span>
<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">
......
......@@ -835,35 +835,10 @@ class RegistrationFormFactory(object):
current_provider = third_party_auth.provider.Registry.get_from_pipeline(running_pipeline)
if current_provider:
# Override username / email / full name
field_overrides = current_provider.get_register_form_data(
running_pipeline.get('kwargs')
self._override_registration_fields_using_identity_provider_configuration(
request, current_provider, running_pipeline, form_desc
)
# 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(
"password",
default="",
......@@ -881,3 +856,37 @@ class RegistrationFormFactory(object):
default=current_provider.name if current_provider.name else "Third Party",
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):
ALLOWED_TYPES = ["text", "email", "select", "textarea", "checkbox", "password", "hidden"]
ALLOWED_RESTRICTIONS = {
"text": ["min_length", "max_length"],
"password": ["min_length", "max_length"],
"email": ["min_length", "max_length"],
"text": ["min_length", "max_length", "readonly"],
"password": ["min_length", "max_length", "readonly"],
"email": ["min_length", "max_length", "readonly"],
}
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