realm: Allow only owners to configure auth methods for a realm.

This commit adds the restriction on configuring auth methods for
admins. We now allow only owners to configure the auth methods
for realm.
This commit is contained in:
sahil839 2020-06-11 19:54:15 +05:30 committed by Tim Abbott
parent a6f31c3668
commit 87e72ac8e2
8 changed files with 27 additions and 12 deletions

View File

@ -18,6 +18,9 @@ exports.maybe_disable_widgets = function () {
return; return;
} }
$(".organization-box [data-name='auth-methods']")
.find("input, button, select, checked").attr("disabled", true);
if (page_params.is_admin) { if (page_params.is_admin) {
$("#deactivate_realm_button").attr("disabled", true); $("#deactivate_realm_button").attr("disabled", true);
return; return;
@ -37,9 +40,6 @@ exports.maybe_disable_widgets = function () {
$(".organization-box [data-name='organization-permissions']") $(".organization-box [data-name='organization-permissions']")
.find(".control-label-disabled").addClass('enabled'); .find(".control-label-disabled").addClass('enabled');
$(".organization-box [data-name='auth-methods']")
.find("input, button, select, checked").attr("disabled", true);
}; };
exports.get_sorted_options_list = function (option_values_object) { exports.get_sorted_options_list = function (option_values_object) {
@ -310,7 +310,7 @@ exports.populate_auth_methods = function (auth_methods) {
rendered_auth_method_rows += render_settings_admin_auth_methods_list({ rendered_auth_method_rows += render_settings_admin_auth_methods_list({
method: auth_method, method: auth_method,
enabled: value, enabled: value,
is_admin: page_params.is_admin, is_owner: page_params.is_owner,
}); });
} }
auth_methods_table.html(rendered_auth_method_rows); auth_methods_table.html(rendered_auth_method_rows);
@ -324,6 +324,7 @@ function insert_tip_box() {
$(".organization-box").find(".settings-section:not(.can-edit)") $(".organization-box").find(".settings-section:not(.can-edit)")
.not("#emoji-settings") .not("#emoji-settings")
.not("#user-groups-admin") .not("#user-groups-admin")
.not("#organization-auth-settings")
.prepend(tip_box); .prepend(tip_box);
} }

View File

@ -4,7 +4,7 @@
</td> </td>
<td> <td>
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" {{#if enabled}}checked="checked"{{/if}} {{#unless is_admin}}disabled{{/unless}}/> <input type="checkbox" {{#if enabled}}checked="checked"{{/if}} {{#unless is_owner}}disabled{{/unless}}/>
<span></span> <span></span>
</label> </label>
</td> </td>

View File

@ -1,4 +1,7 @@
<div id="organization-auth-settings" class="settings-section" data-name="auth-methods"> <div id="organization-auth-settings" class="settings-section" data-name="auth-methods">
{{#unless is_owner}}
<div class='tip'>{{t "Only organization owners can edit these settings."}}</div>
{{/unless}}
<form class="form-horizontal admin-realm-form org-authentications-form"> <form class="form-horizontal admin-realm-form org-authentications-form">
<div id="org-auth_settings" class="admin-table-wrapper org-subsection-parent"> <div id="org-auth_settings" class="admin-table-wrapper org-subsection-parent">
<div class ="subsection-header"> <div class ="subsection-header">

View File

@ -87,8 +87,8 @@
<li class="collapse-org-settings {% if not is_admin %}hide-org-settings{% endif %}" tabindex="0" data-section="auth-methods"> <li class="collapse-org-settings {% if not is_admin %}hide-org-settings{% endif %}" tabindex="0" data-section="auth-methods">
<i class="icon fa fa-key" aria-hidden="true"></i> <i class="icon fa fa-key" aria-hidden="true"></i>
<div class="text">{{ _('Authentication methods') }}</div> <div class="text">{{ _('Authentication methods') }}</div>
{% if not is_admin %} {% if not is_owner %}
<i class="locked fa fa-lock" title="{{ _('Only organization administrators can edit these settings.') }}"></i> <i class="locked fa fa-lock" title="{{ _('Only organization owners can edit these settings.') }}"></i>
{% endif %} {% endif %}
</li> </li>
{% if not is_guest %} {% if not is_guest %}

View File

@ -1,6 +1,6 @@
# Configure authentication methods # Configure authentication methods
{!admin-only.md!} {!owner-only.md!}
By default, Zulip allows logging in via email/password as well as By default, Zulip allows logging in via email/password as well as
various social authentication providers like Google, GitHub, and various social authentication providers like Google, GitHub, and

View File

@ -4709,6 +4709,11 @@ class TestAdminSetBackends(ZulipTestCase):
def test_change_enabled_backends(self) -> None: def test_change_enabled_backends(self) -> None:
# Log in as admin # Log in as admin
self.login('iago') self.login('iago')
result = self.client_patch("/json/realm", {
'authentication_methods': ujson.dumps({'Email': False, 'Dev': True})})
self.assert_json_error(result, 'Only organization owners can configure authentication methods.')
self.login('desdemona')
result = self.client_patch("/json/realm", { result = self.client_patch("/json/realm", {
'authentication_methods': ujson.dumps({'Email': False, 'Dev': True})}) 'authentication_methods': ujson.dumps({'Email': False, 'Dev': True})})
self.assert_json_success(result) self.assert_json_success(result)
@ -4718,7 +4723,7 @@ class TestAdminSetBackends(ZulipTestCase):
def test_disable_all_backends(self) -> None: def test_disable_all_backends(self) -> None:
# Log in as admin # Log in as admin
self.login('iago') self.login('desdemona')
result = self.client_patch("/json/realm", { result = self.client_patch("/json/realm", {
'authentication_methods': ujson.dumps({'Email': False, 'Dev': False})}) 'authentication_methods': ujson.dumps({'Email': False, 'Dev': False})})
self.assert_json_error(result, 'At least one authentication method must be enabled.') self.assert_json_error(result, 'At least one authentication method must be enabled.')
@ -4728,7 +4733,7 @@ class TestAdminSetBackends(ZulipTestCase):
def test_supported_backends_only_updated(self) -> None: def test_supported_backends_only_updated(self) -> None:
# Log in as admin # Log in as admin
self.login('iago') self.login('desdemona')
# Set some supported and unsupported backends # Set some supported and unsupported backends
result = self.client_patch("/json/realm", { result = self.client_patch("/json/realm", {
'authentication_methods': ujson.dumps({'Email': False, 'Dev': True, 'GitHub': False})}) 'authentication_methods': ujson.dumps({'Email': False, 'Dev': True, 'GitHub': False})})

View File

@ -312,12 +312,14 @@ def home_real(request: HttpRequest) -> HttpResponse:
if user_profile is not None: if user_profile is not None:
night_mode = user_profile.night_mode night_mode = user_profile.night_mode
is_guest = user_profile.is_guest is_guest = user_profile.is_guest
is_realm_owner = user_profile.is_realm_owner
is_realm_admin = user_profile.is_realm_admin is_realm_admin = user_profile.is_realm_admin
show_webathena = user_profile.realm.webathena_enabled show_webathena = user_profile.realm.webathena_enabled
else: # nocoverage else: # nocoverage
night_mode = False night_mode = False
is_guest = False is_guest = False
is_realm_admin = False is_realm_admin = False
is_realm_owner = False
show_webathena = False show_webathena = False
navbar_logo_url = compute_navbar_logo_url(page_params) navbar_logo_url = compute_navbar_logo_url(page_params)
@ -332,6 +334,7 @@ def home_real(request: HttpRequest) -> HttpResponse:
'show_billing': show_billing, 'show_billing': show_billing,
'corporate_enabled': settings.CORPORATE_ENABLED, 'corporate_enabled': settings.CORPORATE_ENABLED,
'show_plans': show_plans, 'show_plans': show_plans,
'is_owner': is_realm_owner,
'is_admin': is_realm_admin, 'is_admin': is_realm_admin,
'is_guest': is_guest, 'is_guest': is_guest,
'night_mode': night_mode, 'night_mode': night_mode,

View File

@ -98,8 +98,11 @@ def update_realm(
return json_error(_("Organization description is too long.")) return json_error(_("Organization description is too long."))
if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH: if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH:
return json_error(_("Organization name is too long.")) return json_error(_("Organization name is too long."))
if authentication_methods is not None and True not in list(authentication_methods.values()): if authentication_methods is not None:
return json_error(_("At least one authentication method must be enabled.")) if not user_profile.is_realm_owner:
return json_error(_("Only organization owners can configure authentication methods."))
if True not in list(authentication_methods.values()):
return json_error(_("At least one authentication method must be enabled."))
if (video_chat_provider is not None and if (video_chat_provider is not None and
video_chat_provider not in {p['id'] for p in Realm.VIDEO_CHAT_PROVIDERS.values()}): video_chat_provider not in {p['id'] for p in Realm.VIDEO_CHAT_PROVIDERS.values()}):
return json_error(_("Invalid video_chat_provider {}").format(video_chat_provider)) return json_error(_("Invalid video_chat_provider {}").format(video_chat_provider))