Ejemplo n.º 1
0
    def _common_authenticate(self, *args, **kwargs):
        # type: (*Any, **Any) -> Optional[UserProfile]
        return_data = kwargs.get('return_data', {})

        email_address = self.get_email_address(*args, **kwargs)
        if not email_address:
            return_data['invalid_email'] = True
            return None

        try:
            user_profile = get_user_profile_by_email(email_address)
        except UserProfile.DoesNotExist:
            return_data["valid_attestation"] = True
            return None

        if not user_profile.is_active:
            return_data["inactive_user"] = True
            return None

        if user_profile.realm.deactivated:
            return_data["inactive_realm"] = True
            return None

        if not user_matches_subdomain(kwargs.get("realm_subdomain"),
                                      user_profile):
            return_data["invalid_subdomain"] = True
            return None

        if not auth_enabled_helper([self.auth_backend_name],
                                   user_profile.realm):
            return_data["auth_backend_disabled"] = True
            return None

        return user_profile
Ejemplo n.º 2
0
    def authenticate(self,
                     username=None,
                     password=None,
                     realm_subdomain=None,
                     return_data=None):
        # type: (Optional[Text], Optional[str], Optional[Text], Optional[Dict[str, Any]]) -> Optional[UserProfile]
        """ Authenticate a user based on email address as the user name. """
        if username is None or password is None:
            # Return immediately.  Otherwise we will look for a SQL row with
            # NULL username.  While that's probably harmless, it's needless
            # exposure.
            return None

        user_profile = common_get_active_user_by_email(username,
                                                       return_data=return_data)
        if user_profile is None:
            return None
        if not password_auth_enabled(user_profile.realm):
            if return_data is not None:
                return_data['password_auth_disabled'] = True
            return None
        if not email_auth_enabled(user_profile.realm):
            if return_data is not None:
                return_data['email_auth_disabled'] = True
            return None
        if user_profile.check_password(password):
            if not user_matches_subdomain(realm_subdomain, user_profile):
                if return_data is not None:
                    return_data["invalid_subdomain"] = True
                return None
            return user_profile
        return None
Ejemplo n.º 3
0
    def send_mail(self, context, from_email, to_email):
        # type: (Dict[str, Any], str, str) -> None
        """
        Currently we don't support accounts in multiple subdomains using
        a single email address. We override this function so that we do
        not send a reset link to an email address if the reset attempt is
        done on the subdomain which does not match user.realm.subdomain.

        Once we start supporting accounts with the same email in
        multiple subdomains, we may be able to refactor this function.

        A second reason we override this function is so that we can send
        the mail through the functions in zerver.lib.send_email, to match
        how we send all other mail in the codebase.
        """
        user = get_user_profile_by_email(to_email)
        attempted_subdomain = get_subdomain(self.request)
        context['attempted_realm'] = False
        if not user_matches_subdomain(attempted_subdomain, user):
            context['attempted_realm'] = get_realm(attempted_subdomain)

        send_email('zerver/emails/password_reset',
                   to_user_id=user.id,
                   from_name="Zulip Account Security",
                   from_address=FromAddress.NOREPLY,
                   context=context)
Ejemplo n.º 4
0
    def clean_username(self):
        # type: () -> str
        email = self.cleaned_data['username']
        try:
            user_profile = get_user_profile_by_email(email)
        except UserProfile.DoesNotExist:
            return email

        if user_profile.realm.deactivated:
            error_msg = u"""Sorry for the trouble, but %s has been deactivated.

Please contact %s to reactivate this group.""" % (user_profile.realm.name,
                                                  FromAddress.SUPPORT)
            raise ValidationError(mark_safe(error_msg))

        if not user_profile.is_active and not user_profile.is_mirror_dummy:
            error_msg = (
                u"Sorry for the trouble, but your account has been deactivated. "
                u"Please contact your organization administrator to reactivate it. "
                u"If you're not sure who that is, try contacting %s.") % (
                    FromAddress.SUPPORT, )
            raise ValidationError(mark_safe(error_msg))

        if not user_matches_subdomain(get_subdomain(self.request),
                                      user_profile):
            logging.warning(
                "User %s attempted to password login to wrong subdomain %s" %
                (user_profile.email, get_subdomain(self.request)))
            raise ValidationError(mark_safe(WRONG_SUBDOMAIN_ERROR))
        return email
Ejemplo n.º 5
0
    def authenticate(self, google_oauth2_token=None, realm_subdomain=None, return_data=None):
        # type: (Optional[str], Optional[Text], Optional[Dict[str, Any]]) -> Optional[UserProfile]
        if return_data is None:
            return_data = {}

        try:
            token_payload = googleapiclient.verify_id_token(google_oauth2_token, settings.GOOGLE_CLIENT_ID)
        except AppIdentityError:
            return None
        if token_payload["email_verified"] in (True, "true"):
            try:
                user_profile = get_user_profile_by_email(token_payload["email"])
            except UserProfile.DoesNotExist:
                return_data["valid_attestation"] = True
                return None
            if not user_profile.is_active:
                return_data["inactive_user"] = True
                return None
            if user_profile.realm.deactivated:
                return_data["inactive_realm"] = True
                return None
            if not user_matches_subdomain(realm_subdomain, user_profile):
                return_data["invalid_subdomain"] = True
                return None
            if not google_auth_enabled(realm=user_profile.realm):
                return_data["google_auth_disabled"] = True
                return None
            return user_profile
        else:
            return_data["valid_attestation"] = False
            return None
Ejemplo n.º 6
0
    def clean_username(self):
        # type: () -> str
        email = self.cleaned_data['username']
        try:
            user_profile = get_user_profile_by_email(email)
        except UserProfile.DoesNotExist:
            return email

        if user_profile.realm.deactivated:
            error_msg = u"""Sorry for the trouble, but %s has been deactivated.

Please contact %s to reactivate this group.""" % (
                user_profile.realm.name,
                FromAddress.SUPPORT)
            raise ValidationError(mark_safe(error_msg))

        if not user_profile.is_active and not user_profile.is_mirror_dummy:
            error_msg = (
                u"Sorry for the trouble, but your account has been deactivated. "
                u"Please contact your organization administrator to reactivate it. "
                u"If you're not sure who that is, try contacting %s.") % (FromAddress.SUPPORT,)
            raise ValidationError(mark_safe(error_msg))

        if not user_matches_subdomain(get_subdomain(self.request), user_profile):
            logging.warning("User %s attempted to password login to wrong subdomain %s" %
                            (user_profile.email, get_subdomain(self.request)))
            raise ValidationError(mark_safe(WRONG_SUBDOMAIN_ERROR))
        return email
Ejemplo n.º 7
0
def logged_in_and_active(request: HttpRequest) -> bool:
    if not request.user.is_authenticated:
        return False
    if not request.user.is_active:
        return False
    if request.user.realm.deactivated:
        return False
    return user_matches_subdomain(get_subdomain(request), request.user)
Ejemplo n.º 8
0
def logged_in_and_active(request: HttpRequest) -> bool:
    if not request.user.is_authenticated:
        return False
    if not request.user.is_active:
        return False
    if request.user.realm.deactivated:
        return False
    return user_matches_subdomain(get_subdomain(request), request.user)
Ejemplo n.º 9
0
    def authenticate(self, remote_user, realm_subdomain=None):
        # type: (Optional[str], Optional[Text]) -> Optional[UserProfile]
        if not remote_user:
            return None

        email = remote_user_to_email(remote_user)
        user_profile = common_get_active_user_by_email(email)
        if user_profile is None:
            return None
        if not user_matches_subdomain(realm_subdomain, user_profile):
            return None
        if not auth_enabled_helper(["RemoteUser"], user_profile.realm):
            return None
        return user_profile
Ejemplo n.º 10
0
 def authenticate(self, username=None, realm_subdomain=None, use_dummy_backend=False,
                  return_data=None):
     # type: (Optional[Text], Optional[Text], bool, Optional[Dict[str, Any]]) -> Optional[UserProfile]
     assert username is not None
     if use_dummy_backend:
         user_profile = common_get_active_user_by_email(username)
         if user_profile is None:
             return None
         if not user_matches_subdomain(realm_subdomain, user_profile):
             if return_data is not None:
                 return_data["invalid_subdomain"] = True
             return None
         return user_profile
     return None
Ejemplo n.º 11
0
def validate_account_and_subdomain(request: HttpRequest, user_profile: UserProfile) -> None:
    if user_profile.realm.deactivated:
        raise JsonableError(_("This organization has been deactivated"))
    if not user_profile.is_active:
        raise JsonableError(_("Account is deactivated"))

    # Either the subdomain matches, or we're accessing Tornado from
    # and to localhost (aka spoofing a request as the user).
    if (not user_matches_subdomain(get_subdomain(request), user_profile) and
        not (settings.RUNNING_INSIDE_TORNADO and
             request.META["SERVER_NAME"] == "127.0.0.1" and
             request.META["REMOTE_ADDR"] == "127.0.0.1")):
        logging.warning("User %s (%s) attempted to access API on wrong subdomain (%s)" % (
            user_profile.delivery_email, user_profile.realm.subdomain, get_subdomain(request)))
        raise JsonableError(_("Account is not associated with this subdomain"))
Ejemplo n.º 12
0
 def authenticate(self, username, password, realm_subdomain=None, return_data=None):
     # type: (Text, str, Optional[Text], Optional[Dict[str, Any]]) -> Optional[UserProfile]
     try:
         self._realm = get_realm(realm_subdomain)
         username = self.django_to_ldap_username(username)
         user_profile = ZulipLDAPAuthBackendBase.authenticate(self,
                                                              username=username,
                                                              password=password)
         if user_profile is None:
             return None
         if not user_matches_subdomain(realm_subdomain, user_profile):
             return None
         return user_profile
     except Realm.DoesNotExist:
         return None  # nocoverage # TODO: this may no longer be possible
     except ZulipLDAPException:
         return None  # nocoverage # TODO: this may no longer be possible
Ejemplo n.º 13
0
def validate_account_and_subdomain(request: HttpRequest, user_profile: UserProfile) -> None:
    if user_profile.realm.deactivated:
        raise JsonableError(_("This organization has been deactivated"))
    if not user_profile.is_active:
        raise JsonableError(_("Account is deactivated"))

    # Either the subdomain matches, or processing a websockets message
    # in the message_sender worker (which will have already had the
    # subdomain validated), or we're accessing Tornado from and to
    # localhost (aka spoofing a request as the user).
    if (not user_matches_subdomain(get_subdomain(request), user_profile) and
        not (request.method == "SOCKET" and
             request.META['SERVER_NAME'] == "127.0.0.1") and
        not (settings.RUNNING_INSIDE_TORNADO and
             request.META["SERVER_NAME"] == "127.0.0.1" and
             request.META["REMOTE_ADDR"] == "127.0.0.1")):
        logging.warning("User %s (%s) attempted to access API on wrong subdomain (%s)" % (
            user_profile.email, user_profile.realm.subdomain, get_subdomain(request)))
        raise JsonableError(_("Account is not associated with this subdomain"))
Ejemplo n.º 14
0
    def send_mail(self, context, from_email, to_email):
        # type: (Dict[str, Any], str, str) -> None
        """
        Currently we don't support accounts in multiple subdomains using
        a single email address. We override this function so that we do
        not send a reset link to an email address if the reset attempt is
        done on the subdomain which does not match user.realm.subdomain.

        Once we start supporting accounts with the same email in
        multiple subdomains, we may be able to refactor this function.

        A second reason we override this function is so that we can send
        the mail through the functions in zerver.lib.send_email, to match
        how we send all other mail in the codebase.
        """
        user = get_user_profile_by_email(to_email)
        attempted_subdomain = get_subdomain(self.request)
        context['attempted_realm'] = False
        if not user_matches_subdomain(attempted_subdomain, user):
            context['attempted_realm'] = get_realm(attempted_subdomain)

        send_email('zerver/emails/password_reset', to_user_id=user.id,
                   from_name="Zulip Account Security",
                   from_address=FromAddress.NOREPLY, context=context)
Ejemplo n.º 15
0
    def save(
        self,
        domain_override=None,  # type: Optional[bool]
        subject_template_name='registration/password_reset_subject.txt',  # type: Text
        email_template_name='registration/password_reset_email.html',  # type: Text
        use_https=False,  # type: bool
        token_generator=default_token_generator,  # type: PasswordResetTokenGenerator
        from_email=None,  # type: Optional[Text]
        request=None,  # type: HttpRequest
        html_email_template_name=None,  # type: Optional[Text]
        extra_email_context=None  # type: Optional[Dict[str, Any]]
    ):
        # type: (...) -> None
        """
        If the email address has an account in the target realm,
        generates a one-use only link for resetting password and sends
        to the user.

        We send a different email if an associated account does not exist in the
        database, or an account does exist, but not in the realm.

        Note: We ignore protocol and the various email template arguments (those
        are an artifact of using Django's password reset framework).
        """
        email = self.cleaned_data["email"]

        subdomain = get_subdomain(request)
        realm = get_realm(subdomain)

        if not email_auth_enabled(realm):
            logging.info(
                "Password reset attempted for %s even though password auth is disabled."
                % (email, ))
            return

        try:
            user = get_user_profile_by_email(email)
        except UserProfile.DoesNotExist:
            user = None

        context = {
            'email': email,
            'realm_uri': realm.uri,
            'user': user,
        }

        if user is not None and user_matches_subdomain(subdomain, user):
            token = token_generator.make_token(user)
            uid = urlsafe_base64_encode(force_bytes(user.id))
            endpoint = reverse(
                'django.contrib.auth.views.password_reset_confirm',
                kwargs=dict(uidb64=uid, token=token))

            context['no_account_in_realm'] = False
            context['reset_url'] = "{}{}".format(user.realm.uri, endpoint)

            send_email('zerver/emails/password_reset',
                       to_user_id=user.id,
                       from_name="Zulip Account Security",
                       from_address=FromAddress.NOREPLY,
                       context=context)
        else:
            context['no_account_in_realm'] = True
            if user is not None:
                context['account_exists_another_realm'] = True
            else:
                context['account_exists_another_realm'] = False
            send_email('zerver/emails/password_reset',
                       to_email=email,
                       from_name="Zulip Account Security",
                       from_address=FromAddress.NOREPLY,
                       context=context)