From 6dbd2b5fc31034e46d8ca5cbb62cbc3d6473f2e0 Mon Sep 17 00:00:00 2001 From: Mateusz Mandera Date: Tue, 10 Dec 2019 00:42:12 +0100 Subject: [PATCH] auth: Merge RemoteUserBackend into external_authentication_methods. We register ZulipRemoteUserBackend as an external_authentication_method to make it show up in the corresponding field in the /server_settings endpoint. This also allows rendering its login button together with Google/Github/etc. leading to us being able to get rid of some of the code that was handling it as a special case - the js code for plumbing the "next" value and the special {% if only_sso %} block in login.html. An additional consequence of the login.html change is that now the backend will have it button rendered even if it isn't the only backend enabled on the server. --- static/js/portico/signup.js | 3 - static/styles/portico/portico.scss | 1 - templates/zerver/login.html | 247 ++++++++++++++--------------- zerver/tests/test_auth_backends.py | 3 +- zproject/backends.py | 56 ++++--- 5 files changed, 155 insertions(+), 155 deletions(-) diff --git a/static/js/portico/signup.js b/static/js/portico/signup.js index 3faa008058..662de2974b 100644 --- a/static/js/portico/signup.js +++ b/static/js/portico/signup.js @@ -99,9 +99,6 @@ $(function () { const email_formaction = $("#login_form").attr('action'); $("#login_form").attr('action', email_formaction + '/' + window.location.hash); $(".social_login_form input[name='next']").attr('value', '/' + window.location.hash); - - const sso_address = $("#sso-login").attr('href'); - $("#sso-login").attr('href', sso_address + window.location.hash); } } diff --git a/static/styles/portico/portico.scss b/static/styles/portico/portico.scss index 151176baa1..7a282f80b8 100644 --- a/static/styles/portico/portico.scss +++ b/static/styles/portico/portico.scss @@ -1045,7 +1045,6 @@ input.new-organization-button { font-weight: 300; } -.login-sso, .login-social { max-width: 100%; min-width: 300px; diff --git a/templates/zerver/login.html b/templates/zerver/login.html index f2fdfdcddb..29cacfc44e 100644 --- a/templates/zerver/login.html +++ b/templates/zerver/login.html @@ -14,140 +14,127 @@ page can be easily identified in it's respective JavaScript file. -->
- {% if only_sso %} - {# SSO users don't have a password. #} - - - - {% else %} - {# Non-SSO users. #} - - {% if realm_name %} -
-
- -
-
{{ realm_name }}
-
{{ realm_uri }}
-
-
-
- {{ realm_description|safe }} + {% if realm_name %} +
+
+ +
+
{{ realm_name }}
+
{{ realm_uri }}
- {% endif %} - -
- {% if no_auth_enabled %} -
-

No authentication backends are enabled on this - server yet, so it is impossible to login!

- -

See the Zulip - authentication documentation to learn how to configure authentication backends.

-
- {% else %} - {% if password_auth_enabled %} - - - {% if any_social_backend_enabled %} -
{{ _('OR') }}
- {% endif %} - - {% endif %} - - {% for backend in external_authentication_methods %} - - {% endfor %} - -
- {% if email_auth_enabled %} - {{ _('Forgot your password?') }} - {% endif %} - {% if not register_link_disabled %} - {{ _('Sign up') }} - {% endif %} -
- {% endif %} +
+ {{ realm_description|safe }}
+
{% endif %} + +
+ {% if no_auth_enabled %} +
+

No authentication backends are enabled on this + server yet, so it is impossible to login!

+ +

See the Zulip + authentication documentation to learn how to configure authentication backends.

+
+ {% else %} + {% if password_auth_enabled %} + + + {% if any_social_backend_enabled %} +
{{ _('OR') }}
+ {% endif %} + + {% endif %} + + {% for backend in external_authentication_methods %} + + {% endfor %} + +
+ {% if email_auth_enabled %} + {{ _('Forgot your password?') }} + {% endif %} + {% if not register_link_disabled %} + {{ _('Sign up') }} + {% endif %} +
+ {% endif %} +
diff --git a/zerver/tests/test_auth_backends.py b/zerver/tests/test_auth_backends.py index 25ef85d7bb..d4673fc074 100644 --- a/zerver/tests/test_auth_backends.py +++ b/zerver/tests/test_auth_backends.py @@ -1924,6 +1924,7 @@ class ExternalMethodDictsTests(ZulipTestCase): AUTHENTICATION_BACKENDS=('zproject.backends.EmailAuthBackend', 'zproject.backends.GitHubAuthBackend', 'zproject.backends.GoogleAuthBackend', + 'zproject.backends.ZulipRemoteUserBackend', 'zproject.backends.SAMLAuthBackend', 'zproject.backends.AzureADAuthBackend') ): @@ -1933,7 +1934,7 @@ class ExternalMethodDictsTests(ZulipTestCase): self.assertEqual( [social_backend['name'] for social_backend in external_auth_methods[1:]], [social_backend.name for social_backend in sorted( - [GitHubAuthBackend, AzureADAuthBackend, GoogleAuthBackend], + [ZulipRemoteUserBackend, GitHubAuthBackend, AzureADAuthBackend, GoogleAuthBackend], key=lambda x: x.sort_order, reverse=True )] diff --git a/zproject/backends.py b/zproject/backends.py index b5771505af..8bca733578 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -244,25 +244,6 @@ class EmailAuthBackend(ZulipAuthMixin): return user_profile return None -class ZulipRemoteUserBackend(RemoteUserBackend): - """Authentication backend that reads the Apache REMOTE_USER variable. - Used primarily in enterprise environments with an SSO solution - that has an Apache REMOTE_USER integration. For manual testing, see - - https://zulip.readthedocs.io/en/latest/production/authentication-methods.html - - See also remote_user_sso in zerver/views/auth.py. - """ - create_unknown_user = False - - def authenticate(self, *, remote_user: str, realm: Realm, - return_data: Optional[Dict[str, Any]]=None) -> Optional[UserProfile]: - if not auth_enabled_helper(["RemoteUser"], realm): - return None - - email = remote_user_to_email(remote_user) - return common_get_active_user(email, realm, return_data=return_data) - def is_valid_email(email: str) -> bool: try: validate_email(email) @@ -845,6 +826,42 @@ def external_auth_method(cls: Type[ExternalAuthMethod]) -> Type[ExternalAuthMeth EXTERNAL_AUTH_METHODS.append(cls) return cls +@external_auth_method +class ZulipRemoteUserBackend(RemoteUserBackend, ExternalAuthMethod): + """Authentication backend that reads the Apache REMOTE_USER variable. + Used primarily in enterprise environments with an SSO solution + that has an Apache REMOTE_USER integration. For manual testing, see + + https://zulip.readthedocs.io/en/latest/production/authentication-methods.html + + See also remote_user_sso in zerver/views/auth.py. + """ + auth_backend_name = "RemoteUser" + name = "remoteuser" + display_icon = None + sort_order = 9000 # If configured, this backend should have its button near the top of the list. + + create_unknown_user = False + + def authenticate(self, *, remote_user: str, realm: Realm, + return_data: Optional[Dict[str, Any]]=None) -> Optional[UserProfile]: + if not auth_enabled_helper(["RemoteUser"], realm): + return None + + email = remote_user_to_email(remote_user) + return common_get_active_user(email, realm, return_data=return_data) + + @classmethod + def dict_representation(cls) -> List[ExternalAuthMethodDictT]: + return [dict( + name=cls.name, + display_name="SSO", + display_icon=cls.display_icon, + # The user goes to the same URL for both login and signup: + login_url=reverse('login-sso'), + signup_url=reverse('login-sso'), + )] + def redirect_deactivated_user_to_login() -> HttpResponseRedirect: # Specifying the template name makes sure that the user is not redirected to dev_login in case of # a deactivated account on a test server. @@ -1417,7 +1434,6 @@ AUTH_BACKEND_NAME_MAP = { 'Dev': DevAuthBackend, 'Email': EmailAuthBackend, 'LDAP': ZulipLDAPAuthBackend, - 'RemoteUser': ZulipRemoteUserBackend, } # type: Dict[str, Any] for external_method in EXTERNAL_AUTH_METHODS: