diff --git a/static/images/landing-page/logos/azuread-icon.png b/static/images/landing-page/logos/azuread-icon.png new file mode 100644 index 0000000000..70ad2210e7 Binary files /dev/null and b/static/images/landing-page/logos/azuread-icon.png differ diff --git a/static/images/landing-page/logos/github-icon.png b/static/images/landing-page/logos/github-icon.png new file mode 100644 index 0000000000..182a1a3f73 Binary files /dev/null and b/static/images/landing-page/logos/github-icon.png differ diff --git a/static/styles/portico/portico-signin.scss b/static/styles/portico/portico-signin.scss index 842e5cdc45..9b9e1e07d7 100644 --- a/static/styles/portico/portico-signin.scss +++ b/static/styles/portico/portico-signin.scss @@ -632,36 +632,6 @@ button.login-social-button:active { box-shadow: 0px 1px 1px hsla(0, 0%, 0%, 0.3); } -.saml-wrapper button.login-social-button { - background-image: url('/static/images/landing-page/logos/saml-icon.png'); - width: 100%; -} - -.google-wrapper button.login-social-button { - background-image: url('/static/images/landing-page/logos/googl_e-icon.png'); - width: 100%; -} - -.github-wrapper::before { - content: "\f09b"; - position: absolute; - - font-family: "FontAwesome"; - font-size: 2rem; - color: hsl(0, 0%, 20%); - transform: translateX(15px) translateY(13px); -} - -.azuread-oauth2-wrapper::before { - content: "\f17a"; - position: absolute; - - font-family: "FontAwesome"; - font-size: 2rem; - color: hsl(0, 0%, 20%); - transform: translateX(15px) translateY(13px); -} - .login-page-container .right-side .actions, .forgot-password-container .actions { margin: 20px 0px 0px; diff --git a/templates/zerver/accounts_home.html b/templates/zerver/accounts_home.html index 5700ea4290..aec0771584 100644 --- a/templates/zerver/accounts_home.html +++ b/templates/zerver/accounts_home.html @@ -75,9 +75,9 @@ page can be easily identified in it's respective JavaScript file --> {% for backend in social_backends %}
-
+ -
diff --git a/templates/zerver/login.html b/templates/zerver/login.html index 9952e0ceff..e5618feb15 100644 --- a/templates/zerver/login.html +++ b/templates/zerver/login.html @@ -132,9 +132,9 @@ page can be easily identified in it's respective JavaScript file. --> {% for backend in social_backends %}
- diff --git a/tools/linter_lib/custom_check.py b/tools/linter_lib/custom_check.py index c2848fc963..f0034f4d86 100644 --- a/tools/linter_lib/custom_check.py +++ b/tools/linter_lib/custom_check.py @@ -676,6 +676,10 @@ html_rules = whitespace_rules + prose_style_rules + [ 'templates/zerver/email.html', 'templates/zerver/email_log.html', + # Social backend logos are dynamically loaded + 'templates/zerver/accounts_home.html', + 'templates/zerver/login.html', + # Probably just needs to be changed to display: none so the exclude works 'templates/zerver/app/navbar.html', diff --git a/zerver/context_processors.py b/zerver/context_processors.py index 7348528146..05dd333234 100644 --- a/zerver/context_processors.py +++ b/zerver/context_processors.py @@ -3,16 +3,15 @@ from urllib.parse import urljoin 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 ( any_social_backend_enabled, + get_social_backend_dicts, password_auth_enabled, require_email_format_usernames, auth_enabled_helper, AUTH_BACKEND_NAME_MAP, - SOCIAL_AUTH_BACKENDS, ) from zerver.decorator import get_client_name from zerver.lib.send_email import FromAddress @@ -168,7 +167,6 @@ def login_context(request: HttpRequest) -> Dict[str, Any]: # Add the keys for our standard authentication backends. no_auth_enabled = True - social_backends = [] for auth_backend_name in AUTH_BACKEND_NAME_MAP: name_lower = auth_backend_name.lower() key = "%s_auth_enabled" % (name_lower,) @@ -177,19 +175,7 @@ def login_context(request: HttpRequest) -> Dict[str, Any]: if is_enabled: no_auth_enabled = False - # Now add the enabled social backends to the social_backends - # list used to generate buttons for login/register pages. - backend = AUTH_BACKEND_NAME_MAP[auth_backend_name] - if not is_enabled or backend not in SOCIAL_AUTH_BACKENDS: - continue - social_backends.append({ - 'name': backend.name, - 'display_name': backend.auth_backend_name, - 'login_url': reverse('login-social', args=(backend.name,)), - 'signup_url': reverse('signup-social', args=(backend.name,)), - 'sort_order': backend.sort_order, - }) - context['social_backends'] = sorted(social_backends, key=lambda x: x['sort_order'], reverse=True) + context['social_backends'] = get_social_backend_dicts(realm) context['no_auth_enabled'] = no_auth_enabled return context diff --git a/zproject/backends.py b/zproject/backends.py index 6a091bcba9..23c2c48c62 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -17,6 +17,7 @@ import logging import magic import ujson from typing import Any, Dict, List, Optional, Set, Tuple, Union +from typing_extensions import TypedDict from django_auth_ldap.backend import LDAPBackend, LDAPReverseEmailSearch, \ _LDAPUser, ldap_error @@ -992,6 +993,9 @@ def social_auth_finish(backend: Any, class SocialAuthMixin(ZulipAuthMixin): auth_backend_name = "undeclared" + name = "undeclared" + display_logo = None # type: Optional[str] + # Used to determine how to order buttons on login form, backend with # higher sort order are displayed first. sort_order = 0 @@ -1020,8 +1024,10 @@ class SocialAuthMixin(ZulipAuthMixin): return None class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2): + name = "github" auth_backend_name = "GitHub" sort_order = 100 + display_logo = "/static/images/landing-page/logos/github-icon.png" def get_verified_emails(self, *args: Any, **kwargs: Any) -> List[str]: access_token = kwargs["response"]["access_token"] @@ -1085,12 +1091,15 @@ class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2): class AzureADAuthBackend(SocialAuthMixin, AzureADOAuth2): sort_order = 50 + name = "azuread-oauth2" auth_backend_name = "AzureAD" + display_logo = "/static/images/landing-page/logos/azuread-icon.png" class GoogleAuthBackend(SocialAuthMixin, GoogleOAuth2): sort_order = 150 auth_backend_name = "Google" name = "google" + display_logo = "/static/images/landing-page/logos/googl_e-icon.png" def get_verified_emails(self, *args: Any, **kwargs: Any) -> List[str]: verified_emails = [] # type: List[str] @@ -1105,10 +1114,12 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth): standard_relay_params = ["subdomain", "multiuse_object_key", "mobile_flow_otp", "next", "is_signup"] REDIS_EXPIRATION_SECONDS = 60 * 15 + name = "saml" # Organization which go through the trouble of setting up SAML are most likely # to have it as their main authentication method, so it seems appropriate to have # SAML buttons at the top. sort_order = 9999 + display_logo = "/static/images/landing-page/logos/saml-icon.png" def auth_url(self) -> str: """Get the URL to which we must redirect in order to @@ -1222,6 +1233,34 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth): return result +SocialBackendDictT = TypedDict('SocialBackendDictT', { + 'name': str, + 'display_name': str, + 'display_logo': str, + 'login_url': str, + 'signup_url': str, + 'sort_order': int, +}) + +def create_standard_social_backend_dict(social_backend: SocialAuthMixin) -> SocialBackendDictT: + assert social_backend.display_logo is not None + return dict( + name=social_backend.name, + display_name=social_backend.auth_backend_name, + display_logo=social_backend.display_logo, + login_url=reverse('login-social', args=(social_backend.name,)), + signup_url=reverse('signup-social', args=(social_backend.name,)), + sort_order=social_backend.sort_order + ) + +def get_social_backend_dicts(realm: Optional[Realm]=None) -> List[SocialBackendDictT]: + result = [] + for backend in SOCIAL_AUTH_BACKENDS: + if auth_enabled_helper([backend.auth_backend_name], realm): + result.append(create_standard_social_backend_dict(backend)) + + return sorted(result, key=lambda x: x['sort_order'], reverse=True) + AUTH_BACKEND_NAME_MAP = { 'Dev': DevAuthBackend, 'Email': EmailAuthBackend,