saml: Sanity-check configuration in both login and signup codepaths.

This commit is contained in:
Mateusz Mandera
2019-10-26 01:51:48 +02:00
committed by Tim Abbott
parent db29fcbbc4
commit b870816a75
3 changed files with 32 additions and 13 deletions

View File

@@ -1053,6 +1053,12 @@ class SAMLAuthBackendTest(SocialAuthBase):
self.assertEqual(result.status_code, 302) self.assertEqual(result.status_code, 302)
self.assertEqual(result.url, self.CONFIG_ERROR_URL) self.assertEqual(result.url, self.CONFIG_ERROR_URL)
# Test the signup path too:
result = self.social_auth_test(account_data_dict, is_signup='1',
subdomain='zulip', next='/user_uploads/image')
self.assertEqual(result.status_code, 302)
self.assertEqual(result.url, self.CONFIG_ERROR_URL)
def test_saml_auth_works_without_private_public_keys(self) -> None: def test_saml_auth_works_without_private_public_keys(self) -> None:
with self.settings(SOCIAL_AUTH_SAML_SP_PUBLIC_CERT='', SOCIAL_AUTH_SAML_SP_PRIVATE_KEY=''): with self.settings(SOCIAL_AUTH_SAML_SP_PUBLIC_CERT='', SOCIAL_AUTH_SAML_SP_PRIVATE_KEY=''):
self.test_social_auth_success() self.test_social_auth_success()

View File

@@ -38,7 +38,8 @@ from zerver.models import PreregistrationUser, UserProfile, remote_user_to_email
from zerver.signals import email_on_new_login from zerver.signals import email_on_new_login
from zproject.backends import password_auth_enabled, dev_auth_enabled, \ from zproject.backends import password_auth_enabled, dev_auth_enabled, \
ldap_auth_enabled, ZulipLDAPConfigurationError, ZulipLDAPAuthBackend, \ ldap_auth_enabled, ZulipLDAPConfigurationError, ZulipLDAPAuthBackend, \
AUTH_BACKEND_NAME_MAP, auth_enabled_helper, saml_auth_enabled AUTH_BACKEND_NAME_MAP, auth_enabled_helper, saml_auth_enabled, SAMLAuthBackend, \
redirect_to_config_error
from version import ZULIP_VERSION from version import ZULIP_VERSION
import jwt import jwt
@@ -162,9 +163,6 @@ def redirect_to_subdomain_login_url() -> HttpResponseRedirect:
redirect_url = login_url + '?subdomain=1' redirect_url = login_url + '?subdomain=1'
return HttpResponseRedirect(redirect_url) return HttpResponseRedirect(redirect_url)
def redirect_to_config_error(error_type: str) -> HttpResponseRedirect:
return HttpResponseRedirect("/config-error/%s" % (error_type,))
def login_or_register_remote_user(request: HttpRequest, remote_username: str, def login_or_register_remote_user(request: HttpRequest, remote_username: str,
user_profile: Optional[UserProfile], full_name: str='', user_profile: Optional[UserProfile], full_name: str='',
mobile_flow_otp: Optional[str]=None, mobile_flow_otp: Optional[str]=None,
@@ -355,15 +353,9 @@ def start_social_login(request: HttpRequest, backend: str, extra_arg: Optional[s
backend_url = reverse('social:begin', args=[backend]) backend_url = reverse('social:begin', args=[backend])
extra_url_params = {} # type: Dict[str, str] extra_url_params = {} # type: Dict[str, str]
if backend == "saml": if backend == "saml":
obligatory_saml_settings_list = [ result = SAMLAuthBackend.check_config()
settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID, if result is not None:
settings.SOCIAL_AUTH_SAML_ORG_INFO, return result
settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT,
settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT,
settings.SOCIAL_AUTH_SAML_ENABLED_IDPS
]
if any(not setting for setting in obligatory_saml_settings_list):
return redirect_to_config_error("saml")
# This backend requires the name of the IdP (from the list of configured ones) # This backend requires the name of the IdP (from the list of configured ones)
# to be passed as the parameter. # to be passed as the parameter.
@@ -387,6 +379,10 @@ def start_social_signup(request: HttpRequest, backend: str, extra_arg: Optional[
backend_url = reverse('social:begin', args=[backend]) backend_url = reverse('social:begin', args=[backend])
extra_url_params = {} # type: Dict[str, str] extra_url_params = {} # type: Dict[str, str]
if backend == "saml": if backend == "saml":
result = SAMLAuthBackend.check_config()
if result is not None:
return result
if not extra_arg or extra_arg not in settings.SOCIAL_AUTH_SAML_ENABLED_IDPS: if not extra_arg or extra_arg not in settings.SOCIAL_AUTH_SAML_ENABLED_IDPS:
logging.info("Attempted to initiate SAML authentication with wrong idp argument: {}" logging.info("Attempted to initiate SAML authentication with wrong idp argument: {}"
.format(extra_arg)) .format(extra_arg))

View File

@@ -115,6 +115,9 @@ def any_social_backend_enabled(realm: Optional[Realm]=None) -> bool:
for social_auth_subclass in SOCIAL_AUTH_BACKENDS] for social_auth_subclass in SOCIAL_AUTH_BACKENDS]
return auth_enabled_helper(social_backend_names, realm) return auth_enabled_helper(social_backend_names, realm)
def redirect_to_config_error(error_type: str) -> HttpResponseRedirect:
return HttpResponseRedirect("/config-error/%s" % (error_type,))
def require_email_format_usernames(realm: Optional[Realm]=None) -> bool: def require_email_format_usernames(realm: Optional[Realm]=None) -> bool:
if ldap_auth_enabled(realm): if ldap_auth_enabled(realm):
if settings.LDAP_EMAIL_ATTR or settings.LDAP_APPEND_DOMAIN: if settings.LDAP_EMAIL_ATTR or settings.LDAP_APPEND_DOMAIN:
@@ -1233,6 +1236,20 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
return result return result
@classmethod
def check_config(cls) -> Optional[HttpResponse]:
obligatory_saml_settings_list = [
settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID,
settings.SOCIAL_AUTH_SAML_ORG_INFO,
settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT,
settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT,
settings.SOCIAL_AUTH_SAML_ENABLED_IDPS
]
if any(not setting for setting in obligatory_saml_settings_list):
return redirect_to_config_error("saml")
return None
SocialBackendDictT = TypedDict('SocialBackendDictT', { SocialBackendDictT = TypedDict('SocialBackendDictT', {
'name': str, 'name': str,
'display_name': str, 'display_name': str,