Skip to content

Commit

Permalink
auth: Add support for Azure Active Directory authentication.
Browse files Browse the repository at this point in the history
This takes advantage of all of our work on making the
python-social-auth integration reusable for other authentication
backends.
  • Loading branch information
seresheim authored and timabbott committed Dec 19, 2018
1 parent 9d058f9 commit 49dbd85
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/production/authentication-methods.md
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions static/styles/portico-signin.scss
Expand Up @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions templates/zerver/login.html
Expand Up @@ -154,6 +154,17 @@ <h1 class="get-started">{{ _("Log in to Zulip") }}</h1>
</div>
{% endif %}

{% if azuread_auth_enabled %}
<div class="login-social">
<form id='azure_login_form' class="form-inline azure-wrapper" action="{{ url('login-social', args=('azuread-oauth2',)) }}" method="get">
<input type="hidden" name="next" value="{{ next }}">
<button class="login-social-button">
{{ _('Log in with %(identity_provider)s', identity_provider="Azure AD") }}
</button>
</form>
</div>
{% endif %}

<div class="actions">
{% if email_auth_enabled %}
<a class="forgot-password" href="/accounts/password/reset/">{{ _('Forgot your password?') }}</a>
Expand Down
21 changes: 21 additions & 0 deletions 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),
),
]
2 changes: 1 addition & 1 deletion zerver/models.py
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions zerver/views/auth.py
Expand Up @@ -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')

Expand Down
7 changes: 7 additions & 0 deletions zproject/backends.py
Expand Up @@ -11,6 +11,7 @@
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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -645,6 +649,9 @@ def user_data(self, access_token: str, *args: Any, **kwargs: Any) -> Dict[str, s

raise AssertionError("Invalid configuration")

class AzureADAuthBackend(SocialAuthMixin, AzureADOAuth2):
auth_backend_name = "AzureAD"

AUTH_BACKEND_NAME_MAP = {
'Dev': DevAuthBackend,
'Email': EmailAuthBackend,
Expand Down
1 change: 1 addition & 0 deletions zproject/dev_settings.py
Expand Up @@ -39,6 +39,7 @@
'zproject.backends.EmailAuthBackend',
'zproject.backends.GitHubAuthBackend',
'zproject.backends.GoogleMobileOauth2Backend',
# 'zproject.backends.AzureADAuthBackend',
)

EXTERNAL_URI_SCHEME = "http://"
Expand Down
18 changes: 18 additions & 0 deletions zproject/prod_settings_template.py
Expand Up @@ -114,6 +114,7 @@
'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
)
Expand Down Expand Up @@ -179,6 +180,23 @@
#
#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.
#
Expand Down
1 change: 1 addition & 0 deletions zproject/settings.py
Expand Up @@ -159,6 +159,7 @@ def get_config(section: str, key: str, default_value: Optional[Any]=None) -> Opt
'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': '',
Expand Down

0 comments on commit 49dbd85

Please sign in to comment.