diff --git a/docs/production/authentication-methods.md b/docs/production/authentication-methods.md index 064b2deeee..910d8ecfef 100644 --- a/docs/production/authentication-methods.md +++ b/docs/production/authentication-methods.md @@ -28,6 +28,7 @@ authenticate users with any of several single-sign-on (SSO) authentication providers: * Google accounts, with `GoogleMobileOauth2Backend` * GitHub accounts, with `GitHubAuthBackend` +* Microsoft Azure Active Directory, with `AzureADAuthBackend` Each of these requires one to a handful of lines of configuration in `settings.py`, as well as a secret in `zulip-secrets.conf`. Details diff --git a/static/styles/portico-signin.scss b/static/styles/portico-signin.scss index c665cd667c..d23c255d81 100644 --- a/static/styles/portico-signin.scss +++ b/static/styles/portico-signin.scss @@ -635,6 +635,16 @@ button.login-google-button { transform: translateX(15px) translateY(13px); } +.azure-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/login.html b/templates/zerver/login.html index 5cb4371b0e..c738c20cbe 100644 --- a/templates/zerver/login.html +++ b/templates/zerver/login.html @@ -154,6 +154,17 @@ {% endif %} + {% if azuread_auth_enabled %} +
+
+ + +
+
+ {% endif %} +
{% if email_auth_enabled %} {{ _('Forgot your password?') }} diff --git a/zerver/migrations/0197_azure_active_directory_auth.py b/zerver/migrations/0197_azure_active_directory_auth.py new file mode 100644 index 0000000000..93b3066d26 --- /dev/null +++ b/zerver/migrations/0197_azure_active_directory_auth.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.14 on 2018-10-11 00:12 +from __future__ import unicode_literals + +import bitfield.models +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('zerver', '0196_add_realm_logo_fields'), + ] + + operations = [ + migrations.AlterField( + model_name='realm', + name='authentication_methods', + field=bitfield.models.BitField(['Google', 'Email', 'GitHub', 'LDAP', 'Dev', 'RemoteUser', 'AzureAD'], default=2147483647), + ), + ] diff --git a/zerver/models.py b/zerver/models.py index d68dce93a9..53c576423e 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -145,7 +145,7 @@ class Realm(models.Model): INVITES_STANDARD_REALM_DAILY_MAX = 3000 MESSAGE_VISIBILITY_LIMITED = 10000 VIDEO_CHAT_PROVIDERS = [u"Jitsi", u"Google Hangouts"] - AUTHENTICATION_FLAGS = [u'Google', u'Email', u'GitHub', u'LDAP', u'Dev', u'RemoteUser'] + AUTHENTICATION_FLAGS = [u'Google', u'Email', u'GitHub', u'LDAP', u'Dev', u'RemoteUser', u'AzureAD'] SUBDOMAIN_FOR_ROOT_DOMAIN = '' # User-visible display name and description used on e.g. the organization homepage diff --git a/zerver/views/auth.py b/zerver/views/auth.py index 137cef9e5d..3be29d0635 100644 --- a/zerver/views/auth.py +++ b/zerver/views/auth.py @@ -319,6 +319,7 @@ def start_social_login(request: HttpRequest, backend: str) -> HttpResponse: if (backend == "github") and not (settings.SOCIAL_AUTH_GITHUB_KEY and settings.SOCIAL_AUTH_GITHUB_SECRET): return redirect_to_config_error("github") + # TODO: Add a similar block of AzureAD. return oauth_redirect_to_root(request, backend_url, 'social') diff --git a/zproject/backends.py b/zproject/backends.py index 1a8850d865..55a727475b 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -11,6 +11,7 @@ from django.http import HttpResponse from requests import HTTPError from social_core.backends.github import GithubOAuth2, GithubOrganizationOAuth2, \ GithubTeamOAuth2 +from social_core.backends.azuread import AzureADOAuth2 from social_core.backends.base import BaseAuth from social_core.backends.oauth import BaseOAuth2 from social_core.utils import handle_http_errors @@ -66,6 +67,9 @@ def google_auth_enabled(realm: Optional[Realm]=None) -> bool: def github_auth_enabled(realm: Optional[Realm]=None) -> bool: return auth_enabled_helper(['GitHub'], realm) +def azuread_auth_enabled(realm: Optional[Realm]=None) -> bool: + return auth_enabled_helper(['AzureAD'], realm) + def remote_auth_enabled(realm: Optional[Realm]=None) -> bool: return auth_enabled_helper(['RemoteUser'], realm) @@ -645,6 +649,9 @@ class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2): raise AssertionError("Invalid configuration") +class AzureADAuthBackend(SocialAuthMixin, AzureADOAuth2): + auth_backend_name = "AzureAD" + AUTH_BACKEND_NAME_MAP = { 'Dev': DevAuthBackend, 'Email': EmailAuthBackend, diff --git a/zproject/dev_settings.py b/zproject/dev_settings.py index f376035471..994e48a935 100644 --- a/zproject/dev_settings.py +++ b/zproject/dev_settings.py @@ -39,6 +39,7 @@ AUTHENTICATION_BACKENDS = ( 'zproject.backends.EmailAuthBackend', 'zproject.backends.GitHubAuthBackend', 'zproject.backends.GoogleMobileOauth2Backend', + # 'zproject.backends.AzureADAuthBackend', ) EXTERNAL_URI_SCHEME = "http://" diff --git a/zproject/prod_settings_template.py b/zproject/prod_settings_template.py index dd1123076e..cbd4cf48ac 100644 --- a/zproject/prod_settings_template.py +++ b/zproject/prod_settings_template.py @@ -114,6 +114,7 @@ AUTHENTICATION_BACKENDS = ( 'zproject.backends.EmailAuthBackend', # Email and password; just requires SMTP setup # 'zproject.backends.GoogleMobileOauth2Backend', # Google Apps, setup below # 'zproject.backends.GitHubAuthBackend', # GitHub auth, setup below + # 'zproject.backends.AzureADAuthBackend', # Microsoft Azure Active Directory auth, setup below # 'zproject.backends.ZulipLDAPAuthBackend', # LDAP, setup below # 'zproject.backends.ZulipRemoteUserBackend', # Local SSO, setup docs on readthedocs ) @@ -179,6 +180,23 @@ AUTHENTICATION_BACKENDS = ( # #SOCIAL_AUTH_SUBDOMAIN = 'auth' + +######## +# Azure Active Directory OAuth. +# +# To set up Microsoft Azure AD authentication, you'll need to do the following: +# +# (1) Register an OAuth2 application with Microsoft at: +# https://apps.dev.microsoft.com +# Generate a new password under Application Secrets +# Generate a new platform (web) under Platforms. For Redirect URL, enter: +# https://zulip.example.com/complete/azuread-oauth2/ +# Add User.Read permission under Microsoft Graph Permissions +# +# (2) Enter the application ID for the app as SOCIAL_AUTH_AZUREAD_OAUTH2_KEY here +# (3) Put the application password in zulip-secrets.conf as 'azure_oauth2_secret'. +#SOCIAL_AUTH_AZUREAD_OAUTH2_KEY = '' + ######## # SSO via REMOTE_USER. # diff --git a/zproject/settings.py b/zproject/settings.py index 45e9a7abf1..4779fb7d95 100644 --- a/zproject/settings.py +++ b/zproject/settings.py @@ -159,6 +159,7 @@ DEFAULT_SETTINGS = { 'SOCIAL_AUTH_GITHUB_ORG_NAME': None, 'SOCIAL_AUTH_GITHUB_TEAM_ID': None, 'SOCIAL_AUTH_SUBDOMAIN': None, + 'SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET': get_secret('azure_oauth2_secret'), # Email gateway 'EMAIL_GATEWAY_PATTERN': '',