auth: Add support for Azure Active Directory authentication.

This takes advantage of all of our work on making the
python-social-auth integration reusable for other authentication
backends.
This commit is contained in:
seresheim 2018-10-05 14:32:02 +02:00 committed by Tim Abbott
parent 9d058f9193
commit 49dbd85a89
10 changed files with 72 additions and 1 deletions

View File

@ -28,6 +28,7 @@ authenticate users with any of several single-sign-on (SSO)
authentication providers: authentication providers:
* Google accounts, with `GoogleMobileOauth2Backend` * Google accounts, with `GoogleMobileOauth2Backend`
* GitHub accounts, with `GitHubAuthBackend` * GitHub accounts, with `GitHubAuthBackend`
* Microsoft Azure Active Directory, with `AzureADAuthBackend`
Each of these requires one to a handful of lines of configuration in 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 `settings.py`, as well as a secret in `zulip-secrets.conf`. Details

View File

@ -635,6 +635,16 @@ button.login-google-button {
transform: translateX(15px) translateY(13px); 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, .login-page-container .right-side .actions,
.forgot-password-container .actions { .forgot-password-container .actions {
margin: 20px 0px 0px; margin: 20px 0px 0px;

View File

@ -154,6 +154,17 @@
</div> </div>
{% endif %} {% 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"> <div class="actions">
{% if email_auth_enabled %} {% if email_auth_enabled %}
<a class="forgot-password" href="/accounts/password/reset/">{{ _('Forgot your password?') }}</a> <a class="forgot-password" href="/accounts/password/reset/">{{ _('Forgot your password?') }}</a>

View File

@ -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),
),
]

View File

@ -145,7 +145,7 @@ class Realm(models.Model):
INVITES_STANDARD_REALM_DAILY_MAX = 3000 INVITES_STANDARD_REALM_DAILY_MAX = 3000
MESSAGE_VISIBILITY_LIMITED = 10000 MESSAGE_VISIBILITY_LIMITED = 10000
VIDEO_CHAT_PROVIDERS = [u"Jitsi", u"Google Hangouts"] 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 = '' SUBDOMAIN_FOR_ROOT_DOMAIN = ''
# User-visible display name and description used on e.g. the organization homepage # User-visible display name and description used on e.g. the organization homepage

View File

@ -319,6 +319,7 @@ def start_social_login(request: HttpRequest, backend: str) -> HttpResponse:
if (backend == "github") and not (settings.SOCIAL_AUTH_GITHUB_KEY and if (backend == "github") and not (settings.SOCIAL_AUTH_GITHUB_KEY and
settings.SOCIAL_AUTH_GITHUB_SECRET): settings.SOCIAL_AUTH_GITHUB_SECRET):
return redirect_to_config_error("github") return redirect_to_config_error("github")
# TODO: Add a similar block of AzureAD.
return oauth_redirect_to_root(request, backend_url, 'social') return oauth_redirect_to_root(request, backend_url, 'social')

View File

@ -11,6 +11,7 @@ from django.http import HttpResponse
from requests import HTTPError from requests import HTTPError
from social_core.backends.github import GithubOAuth2, GithubOrganizationOAuth2, \ from social_core.backends.github import GithubOAuth2, GithubOrganizationOAuth2, \
GithubTeamOAuth2 GithubTeamOAuth2
from social_core.backends.azuread import AzureADOAuth2
from social_core.backends.base import BaseAuth from social_core.backends.base import BaseAuth
from social_core.backends.oauth import BaseOAuth2 from social_core.backends.oauth import BaseOAuth2
from social_core.utils import handle_http_errors 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: def github_auth_enabled(realm: Optional[Realm]=None) -> bool:
return auth_enabled_helper(['GitHub'], realm) 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: def remote_auth_enabled(realm: Optional[Realm]=None) -> bool:
return auth_enabled_helper(['RemoteUser'], realm) return auth_enabled_helper(['RemoteUser'], realm)
@ -645,6 +649,9 @@ class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2):
raise AssertionError("Invalid configuration") raise AssertionError("Invalid configuration")
class AzureADAuthBackend(SocialAuthMixin, AzureADOAuth2):
auth_backend_name = "AzureAD"
AUTH_BACKEND_NAME_MAP = { AUTH_BACKEND_NAME_MAP = {
'Dev': DevAuthBackend, 'Dev': DevAuthBackend,
'Email': EmailAuthBackend, 'Email': EmailAuthBackend,

View File

@ -39,6 +39,7 @@ AUTHENTICATION_BACKENDS = (
'zproject.backends.EmailAuthBackend', 'zproject.backends.EmailAuthBackend',
'zproject.backends.GitHubAuthBackend', 'zproject.backends.GitHubAuthBackend',
'zproject.backends.GoogleMobileOauth2Backend', 'zproject.backends.GoogleMobileOauth2Backend',
# 'zproject.backends.AzureADAuthBackend',
) )
EXTERNAL_URI_SCHEME = "http://" EXTERNAL_URI_SCHEME = "http://"

View File

@ -114,6 +114,7 @@ AUTHENTICATION_BACKENDS = (
'zproject.backends.EmailAuthBackend', # Email and password; just requires SMTP setup 'zproject.backends.EmailAuthBackend', # Email and password; just requires SMTP setup
# 'zproject.backends.GoogleMobileOauth2Backend', # Google Apps, setup below # 'zproject.backends.GoogleMobileOauth2Backend', # Google Apps, setup below
# 'zproject.backends.GitHubAuthBackend', # GitHub auth, 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.ZulipLDAPAuthBackend', # LDAP, setup below
# 'zproject.backends.ZulipRemoteUserBackend', # Local SSO, setup docs on readthedocs # 'zproject.backends.ZulipRemoteUserBackend', # Local SSO, setup docs on readthedocs
) )
@ -179,6 +180,23 @@ AUTHENTICATION_BACKENDS = (
# #
#SOCIAL_AUTH_SUBDOMAIN = 'auth' #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. # SSO via REMOTE_USER.
# #

View File

@ -159,6 +159,7 @@ DEFAULT_SETTINGS = {
'SOCIAL_AUTH_GITHUB_ORG_NAME': None, 'SOCIAL_AUTH_GITHUB_ORG_NAME': None,
'SOCIAL_AUTH_GITHUB_TEAM_ID': None, 'SOCIAL_AUTH_GITHUB_TEAM_ID': None,
'SOCIAL_AUTH_SUBDOMAIN': None, 'SOCIAL_AUTH_SUBDOMAIN': None,
'SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET': get_secret('azure_oauth2_secret'),
# Email gateway # Email gateway
'EMAIL_GATEWAY_PATTERN': '', 'EMAIL_GATEWAY_PATTERN': '',