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 %}
+
{% 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': '',