Ejemplo n.º 1
0
    def post(self, request, *args, **kwargs):
        can_toggle_is_staff = request.user.is_staff
        form = SuperuserManagementForm(can_toggle_is_staff, self.request.POST)
        if form.is_valid():
            users = form.cleaned_data['users']
            is_superuser = '******' in form.cleaned_data['privileges']
            is_staff = 'is_staff' in form.cleaned_data['privileges']
            fields_changed = {}
            for user in users:
                # save user object only if needed and just once
                if user.is_superuser is not is_superuser:
                    user.is_superuser = is_superuser
                    fields_changed['is_superuser'] = is_superuser

                if can_toggle_is_staff and user.is_staff is not is_staff:
                    user.is_staff = is_staff
                    fields_changed['is_staff'] = is_staff

                if fields_changed:
                    user.save()
                    couch_user = CouchUser.from_django_user(user)
                    log_user_change(by_domain=None,
                                    for_domain=None,
                                    couch_user=couch_user,
                                    changed_by_user=self.request.couch_user,
                                    changed_via=USER_CHANGE_VIA_WEB,
                                    fields_changed=fields_changed,
                                    by_domain_required_for_log=False,
                                    for_domain_required_for_log=False)
            messages.success(request,
                             _("Successfully updated superuser permissions"))

        return self.get(request, *args, **kwargs)
Ejemplo n.º 2
0
def log_commcare_user_locations_changes(request, user, old_location_id,
                                        old_assigned_location_ids):
    change_messages = {}
    fields_changed = {}
    if old_location_id != user.location_id:
        location = None
        fields_changed['location_id'] = user.location_id
        if user.location_id:
            location = SQLLocation.objects.get(location_id=user.location_id)
        change_messages.update(
            UserChangeMessage.primary_location_info(location))
    if old_assigned_location_ids != user.assigned_location_ids:
        locations = []
        fields_changed['assigned_location_ids'] = user.assigned_location_ids
        if user.assigned_location_ids:
            locations = SQLLocation.objects.filter(
                location_id__in=user.assigned_location_ids)
        change_messages.update(
            UserChangeMessage.assigned_locations_info(locations))

    if change_messages:
        log_user_change(by_domain=request.domain,
                        for_domain=user.domain,
                        couch_user=user,
                        changed_by_user=request.couch_user,
                        changed_via=USER_CHANGE_VIA_WEB,
                        fields_changed=fields_changed,
                        change_messages=change_messages)
Ejemplo n.º 3
0
 def post(self, request, *args, **kwargs):
     if self.request.couch_user.is_domain_admin(self.domain_to_remove):
         messages.error(
             request,
             _("Unable remove membership because you are the admin of %s") %
             self.domain_to_remove)
     else:
         try:
             self.request.couch_user.delete_domain_membership(
                 self.domain_to_remove, create_record=True)
             self.request.couch_user.save()
             log_user_change(
                 by_domain=None,
                 for_domain=self.domain_to_remove,
                 couch_user=request.couch_user,
                 changed_by_user=request.couch_user,
                 changed_via=USER_CHANGE_VIA_WEB,
                 change_messages=UserChangeMessage.domain_removal(
                     self.domain_to_remove),
                 by_domain_required_for_log=False,
             )
             messages.success(
                 request,
                 _("You are no longer part of the project %s") %
                 self.domain_to_remove)
         except Exception:
             messages.error(
                 request,
                 _("There was an error removing you from this project."))
     return self.get(request, *args, **kwargs)
Ejemplo n.º 4
0
 def process_add_phone_number(self):
     if self.phone_number_is_valid():
         user = self.request.couch_user
         is_new_phone_number = self.phone_number not in user.phone_numbers
         user.add_phone_number(self.phone_number)
         user.save()
         if is_new_phone_number:
             log_user_change(
                 by_domain=None,
                 for_domain=None,
                 couch_user=user,
                 changed_by_user=user,
                 changed_via=USER_CHANGE_VIA_WEB,
                 change_messages=UserChangeMessage.phone_numbers_added(
                     [self.phone_number]),
                 by_domain_required_for_log=False,
                 for_domain_required_for_log=False,
             )
         messages.success(self.request, _("Phone number added."))
     else:
         messages.error(
             self.request,
             _("Invalid phone number format entered. "
               "Please enter number, including country code, in digits only."
               ))
     return HttpResponseRedirect(reverse(MyAccountSettingsView.urlname))
Ejemplo n.º 5
0
def _log_web_user_membership_removed(user, domain, via):
    log_user_change(by_domain=None,
                    for_domain=domain,
                    couch_user=user,
                    changed_by_user=SYSTEM_USER_ID,
                    changed_via=via,
                    change_messages=UserChangeMessage.domain_removal(domain))
Ejemplo n.º 6
0
    def form_valid(self, form):
        change_messages = {}
        if not self.user:
            return self.redirect_response(self.request)

        reset_password = form.cleaned_data['reset_password']
        if reset_password:
            self.user.set_password(uuid.uuid4().hex)
            change_messages.update(UserChangeMessage.password_reset())

        # toggle active state
        self.user.is_active = not self.user.is_active
        self.user.save()

        verb = 're-enabled' if self.user.is_active else 'disabled'
        reason = form.cleaned_data['reason']
        change_messages.update(
            UserChangeMessage.status_update(self.user.is_active, reason))
        couch_user = CouchUser.from_django_user(self.user)
        log_user_change(by_domain=None,
                        for_domain=None,
                        couch_user=couch_user,
                        changed_by_user=self.request.couch_user,
                        changed_via=USER_CHANGE_VIA_WEB,
                        change_messages=change_messages,
                        fields_changed={'is_active': self.user.is_active},
                        by_domain_required_for_log=False,
                        for_domain_required_for_log=False)
        mail_admins(
            "User account {}".format(verb),
            "The following user account has been {verb}: \n"
            "    Account: {username}\n"
            "    Reset by: {reset_by}\n"
            "    Password reset: {password_reset}\n"
            "    Reason: {reason}".format(
                verb=verb,
                username=self.username,
                reset_by=self.request.user.username,
                password_reset=str(reset_password),
                reason=reason,
            ))
        send_HTML_email(
            "%sYour account has been %s" %
            (settings.EMAIL_SUBJECT_PREFIX, verb),
            self.user.get_email() if self.user else self.username,
            render_to_string('hqadmin/email/account_disabled_email.html',
                             context={
                                 'support_email': settings.SUPPORT_EMAIL,
                                 'password_reset': reset_password,
                                 'user': self.user,
                                 'verb': verb,
                                 'reason': form.cleaned_data['reason'],
                             }),
        )

        messages.success(self.request,
                         _('Account successfully %(verb)s.' % {'verb': verb}))
        return redirect(self.redirect_url)
Ejemplo n.º 7
0
 def test_missing_for_domain(self):
     with self.assertRaisesMessage(ValueError,
                                   "missing 'for_domain' argument'"):
         log_user_change(
             by_domain=self.commcare_user.domain,
             for_domain=None,
             couch_user=self.commcare_user,
             changed_by_user=self.web_user,
             changed_via=USER_CHANGE_VIA_WEB,
             action=UserModelAction.UPDATE,
         )
Ejemplo n.º 8
0
def log_user_groups_change(domain, request, user, group_ids=None):
    groups = []
    # no groups assigned would be group ids as []
    # so if group ids were NOT passed or if some were passed, get groups for user
    if group_ids is None or group_ids:
        groups = Group.by_user_id(user.get_id)
    log_user_change(
        by_domain=domain,
        for_domain=domain,  # Groups are bound to a domain, so use domain
        couch_user=user,
        changed_by_user=request.couch_user,
        changed_via=USER_CHANGE_VIA_WEB,
        change_messages=UserChangeMessage.groups_info(groups))
Ejemplo n.º 9
0
 def process_delete_phone_number(self):
     self.request.couch_user.delete_phone_number(self.phone_number)
     log_user_change(
         by_domain=None,
         for_domain=None,
         couch_user=self.request.couch_user,
         changed_by_user=self.request.couch_user,
         changed_via=USER_CHANGE_VIA_WEB,
         change_messages=UserChangeMessage.phone_numbers_removed(
             [self.phone_number]),
         by_domain_required_for_log=False,
         for_domain_required_for_log=False,
     )
     messages.success(self.request, _("Phone number deleted."))
     return HttpResponseRedirect(reverse(MyAccountSettingsView.urlname))
Ejemplo n.º 10
0
    def transfer_domain(self, by_user, *args, transfer_via=None, **kwargs):

        self.confirm_time = datetime.utcnow()
        if 'ip' in kwargs:
            self.confirm_ip = kwargs['ip']

        self.from_user.transfer_domain_membership(self.domain,
                                                  self.to_user,
                                                  is_admin=True)
        self.from_user.save()
        if by_user:
            log_user_change(by_domain=self.domain,
                            for_domain=self.domain,
                            couch_user=self.from_user,
                            changed_by_user=by_user,
                            changed_via=transfer_via,
                            change_messages=UserChangeMessage.domain_removal(
                                self.domain))
            log_user_change(by_domain=self.domain,
                            for_domain=self.domain,
                            couch_user=self.to_user,
                            changed_by_user=by_user,
                            changed_via=transfer_via,
                            change_messages=UserChangeMessage.domain_addition(
                                self.domain))
        self.to_user.save()
        self.active = False
        self.save()

        html_content = render_to_string(
            "{template}.html".format(template=self.DIMAGI_CONFIRM_EMAIL),
            self.as_dict())
        text_content = render_to_string(
            "{template}.txt".format(template=self.DIMAGI_CONFIRM_EMAIL),
            self.as_dict())

        send_html_email_async.delay(
            _('There has been a transfer of ownership of {domain}').format(
                domain=self.domain),
            settings.SUPPORT_EMAIL,
            html_content,
            text_content=text_content,
        )
Ejemplo n.º 11
0
 def save_only_group_changes(self, group_change_message):
     return log_user_change(
         by_domain=self.upload_domain,
         for_domain=self.user_domain,
         couch_user=self.user,
         changed_by_user=self.changed_by_user,
         changed_via=self.changed_via,
         change_messages=group_change_message,
         action=UserModelAction.UPDATE,
         bulk_upload_record_id=self.upload_record_id,
         for_domain_required_for_log=self.user_domain_required_for_log,
     )
Ejemplo n.º 12
0
 def save(self):
     if self.is_new_user or self._save:
         action = UserModelAction.CREATE if self.is_new_user else UserModelAction.UPDATE
         fields_changed = None if self.is_new_user else self.fields_changed
         return log_user_change(
             by_domain=self.upload_domain,
             for_domain=self.user_domain,
             couch_user=self.user,
             changed_by_user=self.changed_by_user,
             changed_via=self.changed_via,
             change_messages=self.change_messages,
             action=action,
             fields_changed=fields_changed,
             bulk_upload_record_id=self.upload_record_id,
             for_domain_required_for_log=self.user_domain_required_for_log,
         )
Ejemplo n.º 13
0
    def test_update(self):
        restore_phone_numbers_to = self.commcare_user.to_json(
        )['phone_numbers']

        self.commcare_user.add_phone_number("9999999999")

        change_messages = UserChangeMessage.phone_numbers_added(["9999999999"])
        user_history = log_user_change(
            self.domain,
            self.domain,
            self.commcare_user,
            self.web_user,
            changed_via=USER_CHANGE_VIA_BULK_IMPORTER,
            change_messages=change_messages,
            fields_changed={
                'phone_numbers': self.commcare_user.phone_numbers,
                'password': '******'
            },
            action=UserModelAction.UPDATE)

        self.assertEqual(user_history.by_domain, self.domain)
        self.assertEqual(user_history.for_domain, self.domain)
        self.assertEqual(user_history.user_type, "CommCareUser")
        self.assertIsNotNone(user_history.user_id)
        self.assertEqual(user_history.user_id, self.commcare_user.get_id)
        self.assertIsNotNone(user_history.changed_by)
        self.assertEqual(user_history.changed_by, self.web_user.get_id)
        self.assertEqual(user_history.changes,
                         {'phone_numbers': ['9999999999']})
        self.assertEqual(user_history.changed_via,
                         USER_CHANGE_VIA_BULK_IMPORTER)
        self.assertEqual(user_history.change_messages, change_messages)
        self.assertEqual(user_history.action, UserModelAction.UPDATE.value)
        self.assertEqual(user_history.user_repr,
                         user_id_to_username(self.commcare_user.get_id))
        self.assertEqual(user_history.changed_by_repr,
                         user_id_to_username(self.web_user.get_id))

        self.commcare_user.phone_numbers = restore_phone_numbers_to
Ejemplo n.º 14
0
    def __call__(self, request, uuid, **kwargs):
        # add the correct parameters to this instance
        self.request = request
        if 'domain' in kwargs:
            self.domain = kwargs['domain']

        if request.GET.get('switch') == 'true':
            logout(request)
            return redirect_to_login(request.path)
        if request.GET.get('create') == 'true':
            logout(request)
            return HttpResponseRedirect(request.path)
        try:
            invitation = Invitation.objects.get(uuid=uuid)
        except (Invitation.DoesNotExist, ValidationError):
            messages.error(
                request,
                _("Sorry, it looks like your invitation has expired. "
                  "Please check the invitation link you received and try again, or "
                  "request a project administrator to send you the invitation again."
                  ))
            return HttpResponseRedirect(reverse("login"))

        if invitation.is_accepted:
            messages.error(
                request,
                _("Sorry, that invitation has already been used up. "
                  "If you feel this is a mistake please ask the inviter for "
                  "another invitation."))
            return HttpResponseRedirect(reverse("login"))

        self.validate_invitation(invitation)

        if invitation.is_expired:
            return HttpResponseRedirect(reverse("no_permissions"))

        # Add zero-width space to username for better line breaking
        username = self.request.user.username.replace("@", "​@")
        context = {
            'formatted_username': username,
            'domain': self.domain,
            'invite_to': self.domain,
            'invite_type': _('Project'),
            'hide_password_feedback': has_custom_clean_password(),
        }
        if request.user.is_authenticated:
            context['current_page'] = {'page_name': _('Project Invitation')}
        else:
            context['current_page'] = {
                'page_name': _('Project Invitation, Account Required')
            }
        if request.user.is_authenticated:
            is_invited_user = request.couch_user.username.lower(
            ) == invitation.email.lower()
            if self.is_invited(invitation, request.couch_user
                               ) and not request.couch_user.is_superuser:
                if is_invited_user:
                    # if this invite was actually for this user, just mark it accepted
                    messages.info(
                        request,
                        _("You are already a member of {entity}.").format(
                            entity=self.inviting_entity))
                    invitation.is_accepted = True
                    invitation.save()
                else:
                    messages.error(
                        request,
                        _("It looks like you are trying to accept an invitation for "
                          "{invited} but you are already a member of {entity} with the "
                          "account {current}. Please sign out to accept this invitation "
                          "as another user.").format(
                              entity=self.inviting_entity,
                              invited=invitation.email,
                              current=request.couch_user.username))
                return HttpResponseRedirect(
                    self.redirect_to_on_success(invitation.email, self.domain))

            if not is_invited_user:
                messages.error(
                    request,
                    _("The invited user {invited} and your user {current} "
                      "do not match!").format(
                          invited=invitation.email,
                          current=request.couch_user.username))

            if request.method == "POST":
                couch_user = CouchUser.from_django_user(request.user,
                                                        strict=True)
                invitation.accept_invitation_and_join_domain(couch_user)
                log_user_change(
                    by_domain=invitation.domain,
                    for_domain=invitation.domain,
                    couch_user=couch_user,
                    changed_by_user=CouchUser.get_by_user_id(
                        invitation.invited_by),
                    changed_via=USER_CHANGE_VIA_INVITATION,
                    change_messages=UserChangeMessage.domain_addition(
                        invitation.domain))
                track_workflow(
                    request.couch_user.get_email(),
                    "Current user accepted a project invitation",
                    {"Current user accepted a project invitation": "yes"})
                send_hubspot_form(HUBSPOT_EXISTING_USER_INVITE_FORM, request)
                return HttpResponseRedirect(
                    self.redirect_to_on_success(invitation.email, self.domain))
            else:
                mobile_user = CouchUser.from_django_user(
                    request.user).is_commcare_user()
                context.update({
                    'mobile_user':
                    mobile_user,
                    "invited_user":
                    invitation.email
                    if request.couch_user.username != invitation.email else "",
                })
                return render(request, self.template, context)
        else:
            idp = None
            if settings.ENFORCE_SSO_LOGIN:
                idp = IdentityProvider.get_active_identity_provider_by_username(
                    invitation.email)

            if request.method == "POST":
                form = WebUserInvitationForm(request.POST,
                                             is_sso=idp is not None)
                if form.is_valid():
                    # create the new user
                    invited_by_user = CouchUser.get_by_user_id(
                        invitation.invited_by)

                    if idp:
                        signup_request = AsyncSignupRequest.create_from_invitation(
                            invitation)
                        return HttpResponseRedirect(
                            idp.get_login_url(signup_request.username))

                    user = activate_new_user_via_reg_form(
                        form,
                        created_by=invited_by_user,
                        created_via=USER_CHANGE_VIA_INVITATION,
                        domain=invitation.domain,
                        is_domain_admin=False,
                    )
                    user.save()
                    messages.success(
                        request,
                        _("User account for %s created!") %
                        form.cleaned_data["email"])
                    invitation.accept_invitation_and_join_domain(user)
                    messages.success(
                        self.request,
                        _('You have been added to the "{}" project space.').
                        format(self.domain))
                    authenticated = authenticate(
                        username=form.cleaned_data["email"],
                        password=form.cleaned_data["password"],
                        request=request)
                    if authenticated is not None and authenticated.is_active:
                        login(request, authenticated)
                    track_workflow(
                        request.POST['email'],
                        "New User Accepted a project invitation",
                        {"New User Accepted a project invitation": "yes"})
                    send_hubspot_form(HUBSPOT_NEW_USER_INVITE_FORM, request,
                                      user)
                    return HttpResponseRedirect(
                        self.redirect_to_on_success(invitation.email,
                                                    invitation.domain))
            else:
                if (CouchUser.get_by_username(invitation.email)
                        or User.objects.filter(
                            username__iexact=invitation.email).count() > 0):
                    login_url = reverse("login")
                    accept_invitation_url = reverse(
                        'domain_accept_invitation',
                        args=[invitation.domain, invitation.uuid])
                    return HttpResponseRedirect(
                        f"{login_url}"
                        f"?next={accept_invitation_url}"
                        f"&username={invitation.email}")
                form = WebUserInvitationForm(
                    initial={
                        'email': invitation.email,
                    },
                    is_sso=idp is not None,
                )

            context.update({
                'is_sso': idp is not None,
                'idp_name': idp.name if idp else None,
                'invited_user': invitation.email,
            })

        context.update({"form": form})
        return render(request, self.template, context)
Ejemplo n.º 15
0
    def form_valid(self, form):
        from django_otp import devices_for_user

        username = form.cleaned_data['username']
        user = User.objects.get(username__iexact=username)
        for device in devices_for_user(user):
            device.delete()

        couch_user = CouchUser.from_django_user(user)
        disable_for_days = form.cleaned_data['disable_for_days']
        if disable_for_days:
            disable_until = datetime.utcnow() + timedelta(
                days=disable_for_days)
            couch_user.two_factor_auth_disabled_until = disable_until
            couch_user.save()

        verification = form.cleaned_data['verification_mode']
        verified_by = form.cleaned_data['via_who'] or self.request.user.username
        change_messages = UserChangeMessage.two_factor_disabled_with_verification(
            verified_by, verification, disable_for_days)
        log_user_change(by_domain=None,
                        for_domain=None,
                        couch_user=couch_user,
                        changed_by_user=self.request.couch_user,
                        changed_via=USER_CHANGE_VIA_WEB,
                        change_messages=change_messages,
                        by_domain_required_for_log=False,
                        for_domain_required_for_log=False)
        mail_admins(
            "Two-Factor account reset",
            "Two-Factor auth was reset. Details: \n"
            "    Account reset: {username}\n"
            "    Reset by: {reset_by}\n"
            "    Request Verification Mode: {verification}\n"
            "    Verified by: {verified_by}\n"
            "    Two-Factor disabled for {days} days.".format(
                username=username,
                reset_by=self.request.user.username,
                verification=verification,
                verified_by=verified_by,
                days=disable_for_days),
        )
        send_HTML_email(
            "%sTwo-Factor authentication reset" %
            settings.EMAIL_SUBJECT_PREFIX,
            couch_user.get_email(),
            render_to_string(
                'hqadmin/email/two_factor_reset_email.html',
                context={
                    'until':
                    disable_until.strftime('%Y-%m-%d %H:%M:%S UTC')
                    if disable_for_days else None,
                    'support_email':
                    settings.SUPPORT_EMAIL,
                    'email_subject':
                    "[URGENT] Possible Account Breach",
                    'email_body':
                    "Two Factor Auth on my CommCare account "
                    "was disabled without my request. My username is: %s" %
                    username,
                }),
        )

        messages.success(self.request,
                         _('Two-Factor Auth successfully disabled.'))
        return redirect('{}?q={}'.format(reverse('web_user_lookup'), username))