diff --git a/static/styles/portico-signin.scss b/static/styles/portico-signin.scss
index c9f3c666f0..10b5dff3fc 100644
--- a/static/styles/portico-signin.scss
+++ b/static/styles/portico-signin.scss
@@ -635,7 +635,7 @@ button.login-google-button {
transform: translateX(15px) translateY(13px);
}
-.azure-wrapper::before {
+.azuread-wrapper::before {
content: "\f17a";
position: absolute;
diff --git a/templates/zerver/login.html b/templates/zerver/login.html
index c738c20cbe..6eb291b637 100644
--- a/templates/zerver/login.html
+++ b/templates/zerver/login.html
@@ -143,27 +143,16 @@
{% endif %}
- {% if github_auth_enabled %}
+ {% for backend in social_backends %}
-
- {% endif %}
-
- {% if azuread_auth_enabled %}
-
-
-
- {% endif %}
+ {% endfor %}
{% if email_auth_enabled %}
diff --git a/zerver/context_processors.py b/zerver/context_processors.py
index 9bf3a55bd4..d05fb41b49 100644
--- a/zerver/context_processors.py
+++ b/zerver/context_processors.py
@@ -2,6 +2,7 @@
from typing import Any, Dict, Optional
from django.http import HttpRequest
from django.conf import settings
+from django.urls import reverse
from zerver.models import UserProfile, get_realm, Realm
from zproject.backends import (
@@ -10,6 +11,7 @@ from zproject.backends import (
require_email_format_usernames,
auth_enabled_helper,
AUTH_BACKEND_NAME_MAP,
+ SOCIAL_AUTH_BACKENDS,
)
from zerver.lib.bugdown import convert as bugdown_convert
from zerver.lib.send_email import FromAddress
@@ -147,4 +149,17 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
name_lower = auth_backend_name.lower()
key = "%s_auth_enabled" % (name_lower,)
context[key] = auth_enabled_helper([auth_backend_name], realm)
+
+ social_backends = []
+ for backend in SOCIAL_AUTH_BACKENDS:
+ if not auth_enabled_helper([backend.auth_backend_name], realm):
+ continue
+ social_backends.append({
+ 'name': backend.name,
+ 'display_name': backend.auth_backend_name,
+ 'login_url': reverse('login-social', args=(backend.name,)),
+ 'sort_order': backend.sort_order,
+ })
+ context['social_backends'] = sorted(social_backends, key=lambda x: x['sort_order'])
+
return context
diff --git a/zproject/backends.py b/zproject/backends.py
index a71d9d1f7f..0418c9e984 100644
--- a/zproject/backends.py
+++ b/zproject/backends.py
@@ -650,6 +650,8 @@ def social_auth_finish(backend: Any,
class SocialAuthMixin(ZulipAuthMixin):
auth_backend_name = "undeclared"
+ # Used to determine how to order buttons on login form
+ sort_order = 0
def auth_complete(self, *args: Any, **kwargs: Any) -> Optional[HttpResponse]:
"""This is a small wrapper around the core `auth_complete` method of
@@ -676,6 +678,7 @@ class SocialAuthMixin(ZulipAuthMixin):
class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2):
auth_backend_name = "GitHub"
+ sort_order = 50
def get_verified_emails(self, *args: Any, **kwargs: Any) -> List[str]:
access_token = kwargs["response"]["access_token"]
@@ -727,6 +730,7 @@ class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2):
raise AssertionError("Invalid configuration")
class AzureADAuthBackend(SocialAuthMixin, AzureADOAuth2):
+ sort_order = 100
auth_backend_name = "AzureAD"
AUTH_BACKEND_NAME_MAP = {
@@ -737,9 +741,11 @@ AUTH_BACKEND_NAME_MAP = {
'RemoteUser': ZulipRemoteUserBackend,
} # type: Dict[str, Any]
OAUTH_BACKEND_NAMES = ["Google"] # type: List[str]
+SOCIAL_AUTH_BACKENDS = [] # type: List[BaseOAuth2]
# Authomatically add all of our social auth backends to relevant data structures.
for social_auth_subclass in SocialAuthMixin.__subclasses__():
AUTH_BACKEND_NAME_MAP[social_auth_subclass.auth_backend_name] = social_auth_subclass
if issubclass(social_auth_subclass, BaseOAuth2):
OAUTH_BACKEND_NAMES.append(social_auth_subclass.auth_backend_name)
+ SOCIAL_AUTH_BACKENDS.append(social_auth_subclass)