Exemple #1
0
    def get_or_create_user(self, username, ldap_user):
        # type: (str, _LDAPUser) -> Tuple[UserProfile, bool]
        try:
            if settings.LDAP_EMAIL_ATTR is not None:
                # Get email from ldap attributes.
                if settings.LDAP_EMAIL_ATTR not in ldap_user.attrs:
                    raise ZulipLDAPException("LDAP user doesn't have the needed %s attribute" % (settings.LDAP_EMAIL_ATTR,))

                username = ldap_user.attrs[settings.LDAP_EMAIL_ATTR][0]

            user_profile = get_user_profile_by_email(username)
            if not user_profile.is_active or user_profile.realm.deactivated:
                raise ZulipLDAPException("Realm has been deactivated")
            if not ldap_auth_enabled(user_profile.realm):
                raise ZulipLDAPException("LDAP Authentication is not enabled")
            return user_profile, False
        except UserProfile.DoesNotExist:
            if self._realm is None:
                raise ZulipLDAPConfigurationError("Realm is None", self.REALM_IS_NONE_ERROR)
            # No need to check for an inactive user since they don't exist yet
            if self._realm.deactivated:
                raise ZulipLDAPException("Realm has been deactivated")

            full_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["full_name"]
            short_name = full_name = ldap_user.attrs[full_name_attr][0]
            try:
                full_name = check_full_name(full_name)
            except JsonableError as e:
                raise ZulipLDAPException(e.msg)
            if "short_name" in settings.AUTH_LDAP_USER_ATTR_MAP:
                short_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["short_name"]
                short_name = ldap_user.attrs[short_name_attr][0]

            user_profile = do_create_user(username, None, self._realm, full_name, short_name)
            return user_profile, True
Exemple #2
0
    def get_or_build_user(self, username: str,
                          ldap_user: _LDAPUser) -> Tuple[UserProfile, bool]:
        return_data = {}  # type: Dict[str, Any]

        if settings.LDAP_EMAIL_ATTR is not None:
            # Get email from ldap attributes.
            if settings.LDAP_EMAIL_ATTR not in ldap_user.attrs:
                return_data[
                    "ldap_missing_attribute"] = settings.LDAP_EMAIL_ATTR
                raise ZulipLDAPException(
                    "LDAP user doesn't have the needed %s attribute" %
                    (settings.LDAP_EMAIL_ATTR, ))

            username = ldap_user.attrs[settings.LDAP_EMAIL_ATTR][0]

        if 'userAccountControl' in settings.AUTH_LDAP_USER_ATTR_MAP:  # nocoverage
            ldap_disabled = self.is_account_control_disabled_user(ldap_user)
            if ldap_disabled:
                # Treat disabled users as deactivated in Zulip.
                return_data["inactive_user"] = True
                raise ZulipLDAPException("User has been deactivated")

        user_profile = common_get_active_user(username, self._realm,
                                              return_data)
        if user_profile is not None:
            # An existing user, successfully authed; return it.
            return user_profile, False

        if return_data.get("inactive_realm"):
            # This happens if there is a user account in a deactivated realm
            raise ZulipLDAPException("Realm has been deactivated")
        if return_data.get("inactive_user"):
            raise ZulipLDAPException("User has been deactivated")
        if return_data.get("invalid_subdomain"):
            # TODO: Implement something in the caller for this to
            # provide a nice user-facing error message for this
            # situation (right now it just acts like any other auth
            # failure).
            raise ZulipLDAPException("Wrong subdomain")
        if self._realm.deactivated:
            # This happens if no account exists, but the realm is
            # deactivated, so we shouldn't create a new user account
            raise ZulipLDAPException("Realm has been deactivated")

        # We have valid LDAP credentials; time to create an account.
        full_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["full_name"]
        short_name = full_name = ldap_user.attrs[full_name_attr][0]
        try:
            full_name = check_full_name(full_name)
        except JsonableError as e:
            raise ZulipLDAPException(e.msg)
        if "short_name" in settings.AUTH_LDAP_USER_ATTR_MAP:
            short_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["short_name"]
            short_name = ldap_user.attrs[short_name_attr][0]

        user_profile = do_create_user(username, None, self._realm, full_name,
                                      short_name)
        self.sync_avatar_from_ldap(user_profile, ldap_user)

        return user_profile, True
Exemple #3
0
    def get_or_build_user(self, username: str, ldap_user: _LDAPUser) -> Tuple[UserProfile, bool]:
        return_data = {}  # type: Dict[str, Any]

        if settings.LDAP_EMAIL_ATTR is not None:
            # Get email from ldap attributes.
            if settings.LDAP_EMAIL_ATTR not in ldap_user.attrs:
                return_data["ldap_missing_attribute"] = settings.LDAP_EMAIL_ATTR
                raise ZulipLDAPException("LDAP user doesn't have the needed %s attribute" % (
                    settings.LDAP_EMAIL_ATTR,))

            username = ldap_user.attrs[settings.LDAP_EMAIL_ATTR][0]

        if 'userAccountControl' in settings.AUTH_LDAP_USER_ATTR_MAP:  # nocoverage
            ldap_disabled = self.is_account_control_disabled_user(ldap_user)
            if ldap_disabled:
                # Treat disabled users as deactivated in Zulip.
                return_data["inactive_user"] = True
                raise ZulipLDAPException("User has been deactivated")

        user_profile = common_get_active_user(username, self._realm, return_data)
        if user_profile is not None:
            # An existing user, successfully authed; return it.
            return user_profile, False

        if return_data.get("inactive_realm"):
            # This happens if there is a user account in a deactivated realm
            raise ZulipLDAPException("Realm has been deactivated")
        if return_data.get("inactive_user"):
            raise ZulipLDAPException("User has been deactivated")
        if return_data.get("invalid_subdomain"):
            # TODO: Implement something in the caller for this to
            # provide a nice user-facing error message for this
            # situation (right now it just acts like any other auth
            # failure).
            raise ZulipLDAPException("Wrong subdomain")
        if self._realm.deactivated:
            # This happens if no account exists, but the realm is
            # deactivated, so we shouldn't create a new user account
            raise ZulipLDAPException("Realm has been deactivated")

        # We have valid LDAP credentials; time to create an account.
        full_name, short_name = self.get_mapped_name(ldap_user)
        try:
            full_name = check_full_name(full_name)
        except JsonableError as e:
            raise ZulipLDAPException(e.msg)

        opts = {}   # type: Dict[str, Any]
        if self._prereg_user:
            invited_as = self._prereg_user.invited_as
            opts['prereg_user'] = self._prereg_user
            opts['is_realm_admin'] = invited_as == PreregistrationUser.INVITE_AS['REALM_ADMIN']
            opts['is_guest'] = invited_as == PreregistrationUser.INVITE_AS['GUEST_USER']
            opts['default_stream_groups'] = get_default_stream_groups(self._realm)

        user_profile = do_create_user(username, None, self._realm, full_name, short_name, **opts)
        self.sync_avatar_from_ldap(user_profile, ldap_user)
        self.sync_custom_profile_fields_from_ldap(user_profile, ldap_user)

        return user_profile, True
Exemple #4
0
    def get_or_create_user(self, username, ldap_user):
        # type: (str, _LDAPUser) -> Tuple[UserProfile, bool]
        try:
            user_profile = get_user_profile_by_email(username)
            if not user_profile.is_active or user_profile.realm.deactivated:
                raise ZulipLDAPException("Realm has been deactivated")
            if not ldap_auth_enabled(user_profile.realm):
                raise ZulipLDAPException("LDAP Authentication is not enabled")
            return user_profile, False
        except UserProfile.DoesNotExist:
            # No need to check for an inactive user since they don't exist yet
            if self._realm.deactivated:
                raise ZulipLDAPException("Realm has been deactivated")

            full_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["full_name"]
            short_name = full_name = ldap_user.attrs[full_name_attr][0]
            try:
                full_name = check_full_name(full_name)
            except JsonableError as e:
                raise ZulipLDAPException(e.error)
            if "short_name" in settings.AUTH_LDAP_USER_ATTR_MAP:
                short_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["short_name"]
                short_name = ldap_user.attrs[short_name_attr][0]

            user_profile = do_create_user(username, None, self._realm, full_name, short_name)
            return user_profile, True
Exemple #5
0
    def get_or_create_user(self, username, ldap_user):
        # type: (str, _LDAPUser) -> Tuple[UserProfile, bool]
        try:
            user_profile = get_user_profile_by_email(username)
            if not user_profile.is_active or user_profile.realm.deactivated:
                raise ZulipLDAPException("Realm has been deactivated")
            if not ldap_auth_enabled(user_profile.realm):
                raise ZulipLDAPException("LDAP Authentication is not enabled")
            return user_profile, False
        except UserProfile.DoesNotExist:
            if self._realm is None:
                raise ZulipLDAPException("Realm is None")
            # No need to check for an inactive user since they don't exist yet
            if self._realm.deactivated:
                raise ZulipLDAPException("Realm has been deactivated")

            full_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["full_name"]
            short_name = full_name = ldap_user.attrs[full_name_attr][0]
            try:
                full_name = check_full_name(full_name)
            except JsonableError as e:
                raise ZulipLDAPException(e.error)
            if "short_name" in settings.AUTH_LDAP_USER_ATTR_MAP:
                short_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP[
                    "short_name"]
                short_name = ldap_user.attrs[short_name_attr][0]

            user_profile = do_create_user(username, None, self._realm,
                                          full_name, short_name)
            return user_profile, True
Exemple #6
0
def create_user_backend(request,
                        user_profile,
                        email=REQ(),
                        password=REQ(),
                        full_name_raw=REQ("full_name"),
                        short_name=REQ()):
    # type: (HttpRequest, UserProfile, Text, Text, Text, Text) -> HttpResponse
    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        return json_error(_('Bad name or username'))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    if not email_allowed_for_realm(email, user_profile.realm):
        return json_error(
            _("Email '%(email)s' not allowed for realm '%(realm)s'") % {
                'email': email,
                'realm': realm.string_id
            })

    try:
        get_user_profile_by_email(email)
        return json_error(_("Email '%s' already in use") % (email, ))
    except UserProfile.DoesNotExist:
        pass

    do_create_user(email, password, realm, full_name, short_name)
    return json_success()
Exemple #7
0
def create_user_backend(request: HttpRequest, user_profile: UserProfile,
                        email: str=REQ(), password: str=REQ(), full_name_raw: str=REQ("full_name"),
                        short_name: str=REQ()) -> HttpResponse:
    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        return json_error(_('Bad name or username'))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    try:
        email_allowed_for_realm(email, user_profile.realm)
    except DomainNotAllowedForRealmError:
        return json_error(_("Email '%(email)s' not allowed in this organization") %
                          {'email': email})
    except DisposableEmailError:
        return json_error(_("Disposable email addresses are not allowed in this organization"))

    try:
        get_user(email, user_profile.realm)
        return json_error(_("Email '%s' already in use") % (email,))
    except UserProfile.DoesNotExist:
        pass

    do_create_user(email, password, realm, full_name, short_name)
    return json_success()
Exemple #8
0
def create_user_backend(request: HttpRequest, user_profile: UserProfile,
                        email: str=REQ(), password: str=REQ(), full_name_raw: str=REQ("full_name"),
                        short_name: str=REQ()) -> HttpResponse:
    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        return json_error(_('Bad name or username'))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    try:
        email_allowed_for_realm(email, user_profile.realm)
    except DomainNotAllowedForRealmError:
        return json_error(_("Email '%(email)s' not allowed in this organization") %
                          {'email': email})
    except DisposableEmailError:
        return json_error(_("Disposable email addresses are not allowed in this organization"))
    except EmailContainsPlusError:
        return json_error(_("Email addresses containing + are not allowed."))

    try:
        get_user_by_delivery_email(email, user_profile.realm)
        return json_error(_("Email '%s' already in use") % (email,))
    except UserProfile.DoesNotExist:
        pass

    do_create_user(email, password, realm, full_name, short_name)
    return json_success()
Exemple #9
0
def create_user_backend(request: HttpRequest, user_profile: UserProfile,
                        email: str=REQ(), password: str=REQ(), full_name_raw: str=REQ("full_name"),
                        short_name: str=REQ()) -> HttpResponse:
    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        return json_error(_('Bad name or username'))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    try:
        email_allowed_for_realm(email, user_profile.realm)
    except DomainNotAllowedForRealmError:
        return json_error(_("Email '{email}' not allowed in this organization").format(
            email=email,
        ))
    except DisposableEmailError:
        return json_error(_("Disposable email addresses are not allowed in this organization"))
    except EmailContainsPlusError:
        return json_error(_("Email addresses containing + are not allowed."))

    try:
        get_user_by_delivery_email(email, user_profile.realm)
        return json_error(_("Email '{}' already in use").format(email))
    except UserProfile.DoesNotExist:
        pass

    if not check_password_strength(password):
        return json_error(PASSWORD_TOO_WEAK_ERROR)

    do_create_user(email, password, realm, full_name, short_name, acting_user=user_profile)
    return json_success()
Exemple #10
0
    def get_or_build_user(self, username: str, ldap_user: _LDAPUser) -> Tuple[UserProfile, bool]:
        return_data = {}  # type: Dict[str, Any]

        if settings.LDAP_EMAIL_ATTR is not None:
            # Get email from ldap attributes.
            if settings.LDAP_EMAIL_ATTR not in ldap_user.attrs:
                return_data["ldap_missing_attribute"] = settings.LDAP_EMAIL_ATTR
                raise ZulipLDAPException("LDAP user doesn't have the needed %s attribute" % (
                    settings.LDAP_EMAIL_ATTR,))

            username = ldap_user.attrs[settings.LDAP_EMAIL_ATTR][0]

        if 'userAccountControl' in settings.AUTH_LDAP_USER_ATTR_MAP:  # nocoverage
            ldap_disabled = self.is_account_control_disabled_user(ldap_user)
            if ldap_disabled:
                # Treat disabled users as deactivated in Zulip.
                return_data["inactive_user"] = True
                raise ZulipLDAPException("User has been deactivated")

        user_profile = common_get_active_user(username, self._realm, return_data)
        if user_profile is not None:
            # An existing user, successfully authed; return it.
            return user_profile, False

        if return_data.get("inactive_realm"):
            # This happens if there is a user account in a deactivated realm
            raise ZulipLDAPException("Realm has been deactivated")
        if return_data.get("inactive_user"):
            raise ZulipLDAPException("User has been deactivated")
        # An invalid_subdomain `return_data` value here is ignored,
        # since that just means we're trying to create an account in a
        # second realm on the server (`ldap_auth_enabled(realm)` would
        # have been false if this user wasn't meant to have an account
        # in this second realm).
        if self._realm.deactivated:
            # This happens if no account exists, but the realm is
            # deactivated, so we shouldn't create a new user account
            raise ZulipLDAPException("Realm has been deactivated")

        # We have valid LDAP credentials; time to create an account.
        full_name, short_name = self.get_mapped_name(ldap_user)
        try:
            full_name = check_full_name(full_name)
        except JsonableError as e:
            raise ZulipLDAPException(e.msg)

        opts = {}   # type: Dict[str, Any]
        if self._prereg_user:
            invited_as = self._prereg_user.invited_as
            opts['prereg_user'] = self._prereg_user
            opts['is_realm_admin'] = invited_as == PreregistrationUser.INVITE_AS['REALM_ADMIN']
            opts['is_guest'] = invited_as == PreregistrationUser.INVITE_AS['GUEST_USER']
            opts['default_stream_groups'] = get_default_stream_groups(self._realm)

        user_profile = do_create_user(username, None, self._realm, full_name, short_name, **opts)
        self.sync_avatar_from_ldap(user_profile, ldap_user)
        self.sync_custom_profile_fields_from_ldap(user_profile, ldap_user)

        return user_profile, True
Exemple #11
0
def check_change_full_name(user_profile: UserProfile, full_name_raw: str,
                           acting_user: Optional[UserProfile]) -> str:
    """Verifies that the user's proposed full name is valid.  The caller
    is responsible for checking check permissions.  Returns the new
    full name, which may differ from what was passed in (because this
    function strips whitespace)."""
    new_full_name = check_full_name(full_name_raw)
    do_change_full_name(user_profile, new_full_name, acting_user)
    return new_full_name
Exemple #12
0
def add_bot_backend(request, user_profile, full_name_raw=REQ("full_name"), short_name=REQ(),
                    default_sending_stream_name=REQ('default_sending_stream', default=None),
                    default_events_register_stream_name=REQ('default_events_register_stream', default=None),
                    default_all_public_streams=REQ(validator=check_bool, default=None)):
    # type: (HttpRequest, UserProfile, Text, Text, Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
    short_name += "-bot"
    full_name = check_full_name(full_name_raw)
    email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        # We validate client-side as well
        return json_error(_('Bad name or username'))

    try:
        get_user_profile_by_email(email)
        return json_error(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        return json_error(_("You may only upload one file at a time"))
    else:
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        (default_sending_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_sending_stream_name)

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        (default_events_register_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_events_register_stream_name)

    bot_profile = do_create_user(email=email, password='',
                                 realm=user_profile.realm, full_name=full_name,
                                 short_name=short_name, active=True,
                                 bot_type=UserProfile.DEFAULT_BOT,
                                 bot_owner=user_profile,
                                 avatar_source=avatar_source,
                                 default_sending_stream=default_sending_stream,
                                 default_events_register_stream=default_events_register_stream,
                                 default_all_public_streams=default_all_public_streams)
    if len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, bot_profile)
    json_result = dict(
        api_key=bot_profile.api_key,
        avatar_url=avatar_url(bot_profile),
        default_sending_stream=get_stream_name(bot_profile.default_sending_stream),
        default_events_register_stream=get_stream_name(bot_profile.default_events_register_stream),
        default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(json_result)
Exemple #13
0
def add_bot_backend(request, user_profile, full_name_raw=REQ("full_name"), short_name=REQ(),
                    default_sending_stream_name=REQ('default_sending_stream', default=None),
                    default_events_register_stream_name=REQ('default_events_register_stream', default=None),
                    default_all_public_streams=REQ(validator=check_bool, default=None)):
    # type: (HttpRequest, UserProfile, Text, Text, Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
    short_name += "-bot"
    full_name = check_full_name(full_name_raw)
    email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        # We validate client-side as well
        return json_error(_('Bad name or username'))

    try:
        get_user_profile_by_email(email)
        return json_error(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        return json_error(_("You may only upload one file at a time"))
    else:
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        (default_sending_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_sending_stream_name)

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        (default_events_register_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_events_register_stream_name)

    bot_profile = do_create_user(email=email, password='',
                                 realm=user_profile.realm, full_name=full_name,
                                 short_name=short_name, active=True,
                                 bot_type=UserProfile.DEFAULT_BOT,
                                 bot_owner=user_profile,
                                 avatar_source=avatar_source,
                                 default_sending_stream=default_sending_stream,
                                 default_events_register_stream=default_events_register_stream,
                                 default_all_public_streams=default_all_public_streams)
    if len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, bot_profile)
    json_result = dict(
        api_key=bot_profile.api_key,
        avatar_url=avatar_url(bot_profile),
        default_sending_stream=get_stream_name(bot_profile.default_sending_stream),
        default_events_register_stream=get_stream_name(bot_profile.default_events_register_stream),
        default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(json_result)
Exemple #14
0
 def sync_full_name_from_ldap(self, user_profile: UserProfile,
                              ldap_user: _LDAPUser) -> None:
     from zerver.lib.actions import do_change_full_name
     full_name, _ = self.get_mapped_name(ldap_user)
     if full_name != user_profile.full_name:
         try:
             full_name = check_full_name(full_name)
         except JsonableError as e:
             raise ZulipLDAPException(e.msg)
         do_change_full_name(user_profile, full_name, None)
Exemple #15
0
 def sync_full_name_from_ldap(self, user_profile: UserProfile,
                              ldap_user: _LDAPUser) -> None:
     from zerver.lib.actions import do_change_full_name
     full_name, _ = self.get_mapped_name(ldap_user)
     if full_name != user_profile.full_name:
         try:
             full_name = check_full_name(full_name)
         except JsonableError as e:
             raise ZulipLDAPException(e.msg)
         do_change_full_name(user_profile, full_name, None)
Exemple #16
0
def create_user_backend(
        request: HttpRequest,
        user_profile: UserProfile,
        email: str = REQ(),
        password: str = REQ(),
        full_name_raw: str = REQ("full_name"),
) -> HttpResponse:
    if not user_profile.can_create_users:
        raise JsonableError(_("User not authorized for this query"))

    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({"full_name": full_name, "email": email})
    if not form.is_valid():
        raise JsonableError(_("Bad name or username"))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    try:
        email_allowed_for_realm(email, user_profile.realm)
    except DomainNotAllowedForRealmError:
        raise JsonableError(
            _("Email '{email}' not allowed in this organization").format(
                email=email, ))
    except DisposableEmailError:
        raise JsonableError(
            _("Disposable email addresses are not allowed in this organization"
              ))
    except EmailContainsPlusError:
        raise JsonableError(_("Email addresses containing + are not allowed."))

    try:
        get_user_by_delivery_email(email, user_profile.realm)
        raise JsonableError(_("Email '{}' already in use").format(email))
    except UserProfile.DoesNotExist:
        pass

    if not check_password_strength(password):
        raise JsonableError(PASSWORD_TOO_WEAK_ERROR)

    target_user = do_create_user(
        email,
        password,
        realm,
        full_name,
        # Explicitly set tos_version=None. For servers that have
        # configured Terms of Service, this means that users created
        # via this mechanism will be prompted to accept the Terms of
        # Service on first login.
        tos_version=None,
        acting_user=user_profile,
    )
    return json_success(request, data={"user_id": target_user.id})
Exemple #17
0
def check_change_bot_full_name(user_profile: UserProfile, full_name_raw: str,
                               acting_user: UserProfile) -> None:
    new_full_name = check_full_name(full_name_raw)

    if new_full_name == user_profile.full_name:
        # Our web app will try to patch full_name even if the user didn't
        # modify the name in the form.  We just silently ignore those
        # situations.
        return

    check_bot_name_available(
        realm_id=user_profile.realm_id,
        full_name=new_full_name,
    )
    do_change_full_name(user_profile, new_full_name, acting_user)
Exemple #18
0
    def get_or_build_user(self, username: str, ldap_user: _LDAPUser) -> Tuple[UserProfile, bool]:
        return_data = {}  # type: Dict[str, Any]

        if settings.LDAP_EMAIL_ATTR is not None:
            # Get email from ldap attributes.
            if settings.LDAP_EMAIL_ATTR not in ldap_user.attrs:
                return_data["ldap_missing_attribute"] = settings.LDAP_EMAIL_ATTR
                raise ZulipLDAPException("LDAP user doesn't have the needed %s attribute" % (
                    settings.LDAP_EMAIL_ATTR,))

            username = ldap_user.attrs[settings.LDAP_EMAIL_ATTR][0]

        user_profile = common_get_active_user(username, self._realm, return_data)
        if user_profile is not None:
            # An existing user, successfully authed; return it.
            return user_profile, False

        if return_data.get("inactive_realm"):
            # This happens if there is a user account in a deactivated realm
            raise ZulipLDAPException("Realm has been deactivated")
        if return_data.get("inactive_user"):
            raise ZulipLDAPException("User has been deactivated")
        if return_data.get("invalid_subdomain"):
            # TODO: Implement something in the caller for this to
            # provide a nice user-facing error message for this
            # situation (right now it just acts like any other auth
            # failure).
            raise ZulipLDAPException("Wrong subdomain")
        if self._realm.deactivated:
            # This happens if no account exists, but the realm is
            # deactivated, so we shouldn't create a new user account
            raise ZulipLDAPException("Realm has been deactivated")

        # We have valid LDAP credentials; time to create an account.
        full_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["full_name"]
        short_name = full_name = ldap_user.attrs[full_name_attr][0]
        try:
            full_name = check_full_name(full_name)
        except JsonableError as e:
            raise ZulipLDAPException(e.msg)
        if "short_name" in settings.AUTH_LDAP_USER_ATTR_MAP:
            short_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["short_name"]
            short_name = ldap_user.attrs[short_name_attr][0]

        user_profile = do_create_user(username, None, self._realm, full_name, short_name)

        return user_profile, True
Exemple #19
0
def create_user_backend(request, user_profile, email=REQ(), password=REQ(),
                        full_name_raw=REQ("full_name"), short_name=REQ()):
    # type: (HttpRequest, UserProfile, Text, Text, Text, Text) -> HttpResponse
    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        return json_error(_('Bad name or username'))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    if not email_allowed_for_realm(email, user_profile.realm):
        return json_error(_("Email '%(email)s' not allowed for realm '%(realm)s'") %
                          {'email': email, 'realm': realm.string_id})

    try:
        get_user_profile_by_email(email)
        return json_error(_("Email '%s' already in use") % (email,))
    except UserProfile.DoesNotExist:
        pass

    do_create_user(email, password, realm, full_name, short_name)
    return json_success()
Exemple #20
0
def add_bot_backend(
    request: HttpRequest,
    user_profile: UserProfile,
    full_name_raw: str = REQ("full_name"),
    short_name_raw: str = REQ("short_name"),
    bot_type: int = REQ(validator=check_int, default=UserProfile.DEFAULT_BOT),
    payload_url: Optional[str] = REQ(validator=check_url, default=""),
    service_name: Optional[str] = REQ(default=None),
    config_data: Dict[str, str] = REQ(
        default={}, validator=check_dict(value_validator=check_string)),
    interface_type: int = REQ(validator=check_int, default=Service.GENERIC),
    default_sending_stream_name: Optional[str] = REQ('default_sending_stream',
                                                     default=None),
    default_events_register_stream_name: Optional[str] = REQ(
        'default_events_register_stream', default=None),
    default_all_public_streams: Optional[bool] = REQ(validator=check_bool,
                                                     default=None)
) -> HttpResponse:
    short_name = check_short_name(short_name_raw)
    if bot_type != UserProfile.INCOMING_WEBHOOK_BOT:
        service_name = service_name or short_name
    short_name += "-bot"
    full_name = check_full_name(full_name_raw)
    try:
        email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
    except InvalidFakeEmailDomain:
        return json_error(
            _("Can't create bots until FAKE_EMAIL_DOMAIN is correctly configured.\n"
              "Please contact your server administrator."))
    form = CreateUserForm({'full_name': full_name, 'email': email})

    if bot_type == UserProfile.EMBEDDED_BOT:
        if not settings.EMBEDDED_BOTS_ENABLED:
            return json_error(_("Embedded bots are not enabled."))
        if service_name not in [bot.name for bot in EMBEDDED_BOTS]:
            return json_error(_("Invalid embedded bot name."))

    if not form.is_valid():
        # We validate client-side as well
        return json_error(_('Bad name or username'))
    try:
        get_user_by_delivery_email(email, user_profile.realm)
        return json_error(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass

    check_bot_name_available(
        realm_id=user_profile.realm_id,
        full_name=full_name,
    )

    check_bot_creation_policy(user_profile, bot_type)
    check_valid_bot_type(user_profile, bot_type)
    check_valid_interface_type(interface_type)

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        return json_error(_("You may only upload one file at a time"))
    else:
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        (default_sending_stream, ignored_rec,
         ignored_sub) = access_stream_by_name(user_profile,
                                              default_sending_stream_name)

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        (default_events_register_stream, ignored_rec,
         ignored_sub) = access_stream_by_name(
             user_profile, default_events_register_stream_name)

    if bot_type in (UserProfile.INCOMING_WEBHOOK_BOT,
                    UserProfile.EMBEDDED_BOT) and service_name:
        check_valid_bot_config(bot_type, service_name, config_data)

    bot_profile = do_create_user(
        email=email,
        password='',
        realm=user_profile.realm,
        full_name=full_name,
        short_name=short_name,
        bot_type=bot_type,
        bot_owner=user_profile,
        avatar_source=avatar_source,
        default_sending_stream=default_sending_stream,
        default_events_register_stream=default_events_register_stream,
        default_all_public_streams=default_all_public_streams)
    if len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, bot_profile)

    if bot_type in (UserProfile.OUTGOING_WEBHOOK_BOT,
                    UserProfile.EMBEDDED_BOT):
        assert (isinstance(service_name, str))
        add_service(name=service_name,
                    user_profile=bot_profile,
                    base_url=payload_url,
                    interface=interface_type,
                    token=generate_api_key())

    if bot_type == UserProfile.INCOMING_WEBHOOK_BOT and service_name:
        set_bot_config(bot_profile, "integration_id", service_name)

    if bot_type in (UserProfile.INCOMING_WEBHOOK_BOT,
                    UserProfile.EMBEDDED_BOT):
        for key, value in config_data.items():
            set_bot_config(bot_profile, key, value)

    notify_created_bot(bot_profile)

    api_key = get_api_key(bot_profile)

    json_result = dict(
        api_key=api_key,
        avatar_url=avatar_url(bot_profile),
        default_sending_stream=get_stream_name(
            bot_profile.default_sending_stream),
        default_events_register_stream=get_stream_name(
            bot_profile.default_events_register_stream),
        default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(json_result)
Exemple #21
0
def add_bot_backend(
        request: HttpRequest, user_profile: UserProfile,
        full_name_raw: Text=REQ("full_name"), short_name_raw: Text=REQ("short_name"),
        bot_type: int=REQ(validator=check_int, default=UserProfile.DEFAULT_BOT),
        payload_url: Optional[Text]=REQ(validator=check_url, default=""),
        service_name: Optional[Text]=REQ(default=None),
        config_data: Optional[Dict[Text, Text]]=REQ(default=None,
                                                    validator=check_dict(value_validator=check_string)),
        interface_type: int=REQ(validator=check_int, default=Service.GENERIC),
        default_sending_stream_name: Optional[Text]=REQ('default_sending_stream', default=None),
        default_events_register_stream_name: Optional[Text]=REQ('default_events_register_stream',
                                                                default=None),
        default_all_public_streams: Optional[bool]=REQ(validator=check_bool, default=None)
) -> HttpResponse:
    short_name = check_short_name(short_name_raw)
    service_name = service_name or short_name
    short_name += "-bot"
    full_name = check_full_name(full_name_raw)
    email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
    form = CreateUserForm({'full_name': full_name, 'email': email})

    if bot_type == UserProfile.EMBEDDED_BOT:
        if not settings.EMBEDDED_BOTS_ENABLED:
            return json_error(_("Embedded bots are not enabled."))
        if service_name not in [bot.name for bot in EMBEDDED_BOTS]:
            return json_error(_("Invalid embedded bot name."))

    if not form.is_valid():
        # We validate client-side as well
        return json_error(_('Bad name or username'))
    try:
        get_user(email, user_profile.realm)
        return json_error(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass
    check_valid_bot_type(user_profile, bot_type)
    check_valid_interface_type(interface_type)

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        return json_error(_("You may only upload one file at a time"))
    else:
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        (default_sending_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_sending_stream_name)

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        (default_events_register_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_events_register_stream_name)

    bot_profile = do_create_user(email=email, password='',
                                 realm=user_profile.realm, full_name=full_name,
                                 short_name=short_name,
                                 bot_type=bot_type,
                                 bot_owner=user_profile,
                                 avatar_source=avatar_source,
                                 default_sending_stream=default_sending_stream,
                                 default_events_register_stream=default_events_register_stream,
                                 default_all_public_streams=default_all_public_streams)
    if len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, bot_profile)

    if bot_type in (UserProfile.OUTGOING_WEBHOOK_BOT, UserProfile.EMBEDDED_BOT):
        add_service(name=service_name,
                    user_profile=bot_profile,
                    base_url=payload_url,
                    interface=interface_type,
                    token=random_api_key())

    if bot_type == UserProfile.EMBEDDED_BOT:
        for key, value in config_data.items():
            set_bot_config(bot_profile, key, value)

    json_result = dict(
        api_key=bot_profile.api_key,
        avatar_url=avatar_url(bot_profile),
        default_sending_stream=get_stream_name(bot_profile.default_sending_stream),
        default_events_register_stream=get_stream_name(bot_profile.default_events_register_stream),
        default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(json_result)
Exemple #22
0
 def clean_full_name(self) -> str:
     try:
         return check_full_name(self.cleaned_data['full_name'])
     except JsonableError as e:
         raise ValidationError(e.msg)
Exemple #23
0
    def get_or_build_user(self, username: str, ldap_user: _LDAPUser) -> Tuple[UserProfile, bool]:
        """The main function of our authentication backend extension of
        django-auth-ldap.  When this is called (from `authenticate`),
        django-auth-ldap will already have verified that the provided
        username and password match those in the LDAP database.

        This function's responsibility is to check (1) whether the
        email address for this user obtained from LDAP has an active
        account in this Zulip realm.  If so, it will log them in.

        Otherwise, to provide a seamless Single Sign-On experience
        with LDAP, this function can automatically create a new Zulip
        user account in the realm (assuming the realm is configured to
        allow that email address to sign up).
        """
        return_data = {}  # type: Dict[str, Any]

        if settings.LDAP_EMAIL_ATTR is not None:
            # Get email from ldap attributes.
            if settings.LDAP_EMAIL_ATTR not in ldap_user.attrs:
                return_data["ldap_missing_attribute"] = settings.LDAP_EMAIL_ATTR
                raise ZulipLDAPException("LDAP user doesn't have the needed %s attribute" % (
                    settings.LDAP_EMAIL_ATTR,))

            username = ldap_user.attrs[settings.LDAP_EMAIL_ATTR][0]

        if 'userAccountControl' in settings.AUTH_LDAP_USER_ATTR_MAP:  # nocoverage
            ldap_disabled = self.is_account_control_disabled_user(ldap_user)
            if ldap_disabled:
                # Treat disabled users as deactivated in Zulip.
                return_data["inactive_user"] = True
                raise ZulipLDAPException("User has been deactivated")

        user_profile = common_get_active_user(username, self._realm, return_data)
        if user_profile is not None:
            # An existing user, successfully authed; return it.
            return user_profile, False

        if return_data.get("inactive_realm"):
            # This happens if there is a user account in a deactivated realm
            raise ZulipLDAPException("Realm has been deactivated")
        if return_data.get("inactive_user"):
            raise ZulipLDAPException("User has been deactivated")
        # An invalid_subdomain `return_data` value here is ignored,
        # since that just means we're trying to create an account in a
        # second realm on the server (`ldap_auth_enabled(realm)` would
        # have been false if this user wasn't meant to have an account
        # in this second realm).
        if self._realm.deactivated:
            # This happens if no account exists, but the realm is
            # deactivated, so we shouldn't create a new user account
            raise ZulipLDAPException("Realm has been deactivated")

        # We have valid LDAP credentials; time to create an account.
        full_name, short_name = self.get_mapped_name(ldap_user)
        try:
            full_name = check_full_name(full_name)
        except JsonableError as e:
            raise ZulipLDAPException(e.msg)

        opts = {}   # type: Dict[str, Any]
        if self._prereg_user:
            invited_as = self._prereg_user.invited_as
            opts['prereg_user'] = self._prereg_user
            opts['is_realm_admin'] = invited_as == PreregistrationUser.INVITE_AS['REALM_ADMIN']
            opts['is_guest'] = invited_as == PreregistrationUser.INVITE_AS['GUEST_USER']
            opts['default_stream_groups'] = get_default_stream_groups(self._realm)

        user_profile = do_create_user(username, None, self._realm, full_name, short_name, **opts)
        self.sync_avatar_from_ldap(user_profile, ldap_user)
        self.sync_custom_profile_fields_from_ldap(user_profile, ldap_user)

        return user_profile, True
Exemple #24
0
 def clean_full_name(self) -> str:
     try:
         return check_full_name(self.cleaned_data['full_name'])
     except JsonableError as e:
         raise ValidationError(e.msg)
Exemple #25
0
def add_bot_backend(request,
                    user_profile,
                    full_name_raw=REQ("full_name"),
                    short_name_raw=REQ("short_name"),
                    bot_type=REQ(validator=check_int,
                                 default=UserProfile.DEFAULT_BOT),
                    payload_url=REQ(validator=check_url, default=""),
                    service_name=REQ(default=None),
                    interface_type=REQ(validator=check_int,
                                       default=Service.GENERIC),
                    default_sending_stream_name=REQ('default_sending_stream',
                                                    default=None),
                    default_events_register_stream_name=REQ(
                        'default_events_register_stream', default=None),
                    default_all_public_streams=REQ(validator=check_bool,
                                                   default=None)):
    # type: (HttpRequest, UserProfile, Text, Text, int, Optional[Text], Optional[Text], int, Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
    short_name = check_short_name(short_name_raw)
    service_name = service_name or short_name
    short_name += "-bot"
    full_name = check_full_name(full_name_raw)
    email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
    form = CreateUserForm({'full_name': full_name, 'email': email})

    if bot_type == UserProfile.EMBEDDED_BOT:
        if not settings.EMBEDDED_BOTS_ENABLED:
            return json_error(_("Embedded bots are not enabled."))
        if service_name not in [bot.name for bot in EMBEDDED_BOTS]:
            return json_error(_("Invalid embedded bot name."))

    if not form.is_valid():
        # We validate client-side as well
        return json_error(_('Bad name or username'))
    try:
        get_user(email, user_profile.realm)
        return json_error(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass
    check_valid_bot_type(bot_type)
    check_valid_interface_type(interface_type)

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        return json_error(_("You may only upload one file at a time"))
    else:
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        (default_sending_stream, ignored_rec,
         ignored_sub) = access_stream_by_name(user_profile,
                                              default_sending_stream_name)

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        (default_events_register_stream, ignored_rec,
         ignored_sub) = access_stream_by_name(
             user_profile, default_events_register_stream_name)

    bot_profile = do_create_user(
        email=email,
        password='',
        realm=user_profile.realm,
        full_name=full_name,
        short_name=short_name,
        active=True,
        bot_type=bot_type,
        bot_owner=user_profile,
        avatar_source=avatar_source,
        default_sending_stream=default_sending_stream,
        default_events_register_stream=default_events_register_stream,
        default_all_public_streams=default_all_public_streams)
    if len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, bot_profile)

    if bot_type in (UserProfile.OUTGOING_WEBHOOK_BOT,
                    UserProfile.EMBEDDED_BOT):
        add_service(name=service_name,
                    user_profile=bot_profile,
                    base_url=payload_url,
                    interface=interface_type,
                    token=random_api_key())

    json_result = dict(
        api_key=bot_profile.api_key,
        avatar_url=avatar_url(bot_profile),
        default_sending_stream=get_stream_name(
            bot_profile.default_sending_stream),
        default_events_register_stream=get_stream_name(
            bot_profile.default_events_register_stream),
        default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(json_result)
Exemple #26
0
    def get_or_build_user(self, username: str, ldap_user: _LDAPUser) -> Tuple[UserProfile, bool]:
        """The main function of our authentication backend extension of
        django-auth-ldap.  When this is called (from `authenticate`),
        django-auth-ldap will already have verified that the provided
        username and password match those in the LDAP database.

        This function's responsibility is to check (1) whether the
        email address for this user obtained from LDAP has an active
        account in this Zulip realm.  If so, it will log them in.

        Otherwise, to provide a seamless Single Sign-On experience
        with LDAP, this function can automatically create a new Zulip
        user account in the realm (assuming the realm is configured to
        allow that email address to sign up).
        """
        return_data = {}  # type: Dict[str, Any]

        if settings.LDAP_EMAIL_ATTR is not None:
            # Get email from ldap attributes.
            if settings.LDAP_EMAIL_ATTR not in ldap_user.attrs:
                return_data["ldap_missing_attribute"] = settings.LDAP_EMAIL_ATTR
                raise ZulipLDAPException("LDAP user doesn't have the needed %s attribute" % (
                    settings.LDAP_EMAIL_ATTR,))

            username = ldap_user.attrs[settings.LDAP_EMAIL_ATTR][0]

        if 'userAccountControl' in settings.AUTH_LDAP_USER_ATTR_MAP:  # nocoverage
            ldap_disabled = self.is_account_control_disabled_user(ldap_user)
            if ldap_disabled:
                # Treat disabled users as deactivated in Zulip.
                return_data["inactive_user"] = True
                raise ZulipLDAPException("User has been deactivated")

        user_profile = common_get_active_user(username, self._realm, return_data)
        if user_profile is not None:
            # An existing user, successfully authed; return it.
            return user_profile, False

        if return_data.get("inactive_realm"):
            # This happens if there is a user account in a deactivated realm
            raise ZulipLDAPException("Realm has been deactivated")
        if return_data.get("inactive_user"):
            raise ZulipLDAPException("User has been deactivated")
        # An invalid_subdomain `return_data` value here is ignored,
        # since that just means we're trying to create an account in a
        # second realm on the server (`ldap_auth_enabled(realm)` would
        # have been false if this user wasn't meant to have an account
        # in this second realm).
        if self._realm.deactivated:
            # This happens if no account exists, but the realm is
            # deactivated, so we shouldn't create a new user account
            raise ZulipLDAPException("Realm has been deactivated")

        # Makes sure that email domain hasn't be restricted for this
        # realm.  The main thing here is email_allowed_for_realm; but
        # we also call validate_email_for_realm just for consistency,
        # even though its checks were already done above.
        try:
            email_allowed_for_realm(username, self._realm)
            validate_email_for_realm(self._realm, username)
        except DomainNotAllowedForRealmError:
            raise ZulipLDAPException("This email domain isn't allowed in this organization.")
        except (DisposableEmailError, EmailContainsPlusError):
            raise ZulipLDAPException("Email validation failed.")

        # We have valid LDAP credentials; time to create an account.
        full_name, short_name = self.get_mapped_name(ldap_user)
        try:
            full_name = check_full_name(full_name)
        except JsonableError as e:
            raise ZulipLDAPException(e.msg)

        opts = {}   # type: Dict[str, Any]
        if self._prereg_user:
            invited_as = self._prereg_user.invited_as
            opts['prereg_user'] = self._prereg_user
            opts['is_realm_admin'] = invited_as == PreregistrationUser.INVITE_AS['REALM_ADMIN']
            opts['is_guest'] = invited_as == PreregistrationUser.INVITE_AS['GUEST_USER']
            opts['default_stream_groups'] = get_default_stream_groups(self._realm)

        user_profile = do_create_user(username, None, self._realm, full_name, short_name, **opts)
        self.sync_avatar_from_ldap(user_profile, ldap_user)
        self.sync_custom_profile_fields_from_ldap(user_profile, ldap_user)

        return user_profile, True
Exemple #27
0
 def clean_full_name(self):
     # type: () -> Text
     try:
         return check_full_name(self.cleaned_data['full_name'])
     except JsonableError as e:
         raise ValidationError(e.error)
Exemple #28
0
 def clean_full_name(self):
     # type: () -> Text
     try:
         return check_full_name(self.cleaned_data['full_name'])
     except JsonableError as e:
         raise ValidationError(e.error)