Example #1
0
 def validate_spec(self, spec):
     password = spec.get('password')
     if is_password(password):
         try:
             clean_password(password)
         except ValidationError as e:
             return e.message
Example #2
0
    def _update(self, bundle):
        should_save = False
        for key, value in bundle.data.items():
            if getattr(bundle.obj, key, None) != value:
                if key == 'phone_numbers':
                    bundle.obj.phone_numbers = []
                    for idx, phone_number in enumerate(bundle.data.get('phone_numbers', [])):

                        bundle.obj.add_phone_number(strip_plus(phone_number))
                        if idx == 0:
                            bundle.obj.set_default_phone_number(strip_plus(phone_number))
                        should_save = True
                elif key == 'groups':
                    bundle.obj.set_groups(bundle.data.get("groups", []))
                    should_save = True
                elif key in ['email', 'username']:
                    setattr(bundle.obj, key, value.lower())
                    should_save = True
                elif key == 'password':
                    domain = Domain.get_by_name(bundle.obj.domain)
                    if domain.strong_mobile_passwords:
                        try:
                            clean_password(bundle.data.get("password"))
                        except ValidationError as e:
                            if not hasattr(bundle.obj, 'errors'):
                                bundle.obj.errors = []
                            bundle.obj.errors.append(e.message)
                            return False
                    bundle.obj.set_password(bundle.data.get("password"))
                    should_save = True
                else:
                    setattr(bundle.obj, key, value)
                    should_save = True
        return should_save
Example #3
0
    def _update(self, bundle):
        should_save = False
        for key, value in bundle.data.items():
            if getattr(bundle.obj, key, None) != value:
                if key == 'phone_numbers':
                    bundle.obj.phone_numbers = []
                    for idx, phone_number in enumerate(bundle.data.get('phone_numbers', [])):

                        bundle.obj.add_phone_number(strip_plus(phone_number))
                        if idx == 0:
                            bundle.obj.set_default_phone_number(strip_plus(phone_number))
                        should_save = True
                elif key == 'groups':
                    bundle.obj.set_groups(bundle.data.get("groups", []))
                    should_save = True
                elif key in ['email', 'username']:
                    setattr(bundle.obj, key, value.lower())
                    should_save = True
                elif key == 'password':
                    domain = Domain.get_by_name(bundle.obj.domain)
                    if domain.strong_mobile_passwords:
                        try:
                            clean_password(bundle.data.get("password"))
                        except ValidationError as e:
                            if not hasattr(bundle.obj, 'errors'):
                                bundle.obj.errors = []
                            bundle.obj.errors.append(e.message)
                            return False
                    bundle.obj.set_password(bundle.data.get("password"))
                    should_save = True
                else:
                    setattr(bundle.obj, key, value)
                    should_save = True
        return should_save
Example #4
0
def _update_password(user, password, user_change_logger):
    domain = Domain.get_by_name(user.domain)
    if domain.strong_mobile_passwords:
        clean_password(password)
    user.set_password(password)

    if user_change_logger:
        user_change_logger.add_change_message(
            UserChangeMessage.password_reset())
Example #5
0
 def post(self, request, *args, **kwargs):
     if self.password_change_form.is_valid():
         try:
             clean_password(request.POST['new_password1'])
             self.password_change_form.save()
             messages.success(request,
                              _("Your password was successfully changed!"))
         except ValidationError as e:
             messages.error(request, _(e.message))
     return self.get(request, *args, **kwargs)
Example #6
0
 def post(self, request, *args, **kwargs):
     self.extra_context['hide_password_feedback'] = has_custom_clean_password()
     if request.POST['new_password1'] == request.POST['new_password2']:
         try:
             clean_password(request.POST['new_password1'])
         except ValidationError as e:
             messages.error(request, _(e.message))
             return HttpResponseRedirect(request.path_info)
     response = super().post(request, *args, **kwargs)
     uidb64 = kwargs.get('uidb64')
     uid = urlsafe_base64_decode(uidb64)
     user = User.objects.get(pk=uid)
     couch_user = CouchUser.from_django_user(user)
     clear_login_attempts(couch_user)
     return response
Example #7
0
 def clean_new_password1(self):
     password1 = decode_password(self.cleaned_data.get('new_password1'))
     if password1 == '':
         raise ValidationError(
             _("Password cannot be empty"), code='new_password1_empty',
         )
     if self.project.strong_mobile_passwords:
         return clean_password(password1)
     return password1
Example #8
0
 def clean_new_password1(self):
     password1 = decode_password(self.cleaned_data.get('new_password1'))
     if password1 == '':
         raise ValidationError(
             _("Password cannot be empty"), code='new_password1_empty',
         )
     if self.project.strong_mobile_passwords:
         return clean_password(password1)
     return password1
Example #9
0
 def clean_password(self):
     if settings.ENFORCE_SSO_LOGIN and self.is_sso:
         # This field is not used with SSO. A randomly generated
         # password as a fallback is created in SsoBackend.
         return
     try:
         return clean_password(self.cleaned_data.get('password'))
     except forms.ValidationError:
         track_workflow(self.cleaned_data.get('email'), 'Password Failure')
         raise
Example #10
0
    def clean_new_password1(self):
        from corehq.apps.domain.forms import clean_password
        from corehq.apps.hqwebapp.utils import decode_password
        new_password = decode_password(self.cleaned_data.get('new_password1'))
        # User might not be able to submit empty password but decode_password might
        # return empty password in case the password hashing is messed up with
        if new_password == '':
            raise ValidationError(
                _("Password cannot be empty"), code='new_password1_empty',
            )

        return clean_password(new_password)
Example #11
0
 def clean_new_password1(self):
     return clean_password(self.cleaned_data.get('new_password1'))
 def assert_bad_password(self, password):
     with self.assertRaises(forms.ValidationError):
         clean_password(password)
 def test_invalid_passwords(self):
     for password in passwords['invalid']:
         with self.assertRaises(forms.forms.ValidationError):
             forms.clean_password(password)
Example #14
0
def create_or_update_users_and_groups(domain,
                                      user_specs,
                                      group_specs,
                                      task=None):
    from corehq.apps.users.views.mobile.custom_data_fields import UserFieldsView
    custom_data_validator = UserFieldsView.get_validator(domain)
    ret = {"errors": [], "rows": []}
    total = len(user_specs) + len(group_specs)

    def _set_progress(progress):
        if task is not None:
            DownloadBase.set_progress(task, progress, total)

    group_memoizer = create_or_update_groups(domain, group_specs, log=ret)
    current = len(group_specs)

    usernames = set()
    user_ids = set()
    allowed_groups = set(group_memoizer.groups)
    allowed_group_names = [group.name for group in allowed_groups]
    allowed_roles = UserRole.by_domain(domain)
    roles_by_name = {role.name: role for role in allowed_roles}
    can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    if can_assign_locations:
        location_cache = SiteCodeToLocationCache(domain)
    domain_obj = Domain.get_by_name(domain)
    usernames_with_dupe_passwords = users_with_duplicate_passwords(user_specs)

    try:
        for row in user_specs:
            _set_progress(current)
            current += 1

            data = row.get('data')
            email = row.get('email')
            group_names = list(map(str, row.get('group') or []))
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            username = row.get('username')
            location_codes = row.get('location_code') or []
            if location_codes and not isinstance(location_codes, list):
                location_codes = [location_codes]
            # ignore empty
            location_codes = [code for code in location_codes if code]
            role = row.get('role', '')

            if password:
                password = str(password)
            try:
                username = normalize_username(str(username), domain)
            except TypeError:
                username = None
            except ValidationError:
                ret['rows'].append({
                    'username':
                    username,
                    'row':
                    row,
                    'flag':
                    _('username cannot contain spaces or symbols'),
                })
                continue
            status_row = {
                'username': raw_username(username) if username else None,
                'row': row,
            }

            is_active = row.get('is_active')
            if isinstance(is_active, str):
                try:
                    is_active = string_to_boolean(
                        is_active) if is_active else None
                except ValueError:
                    ret['rows'].append({
                        'username':
                        username,
                        'row':
                        row,
                        'flag':
                        _("'is_active' column can only contain 'true' or 'false'"
                          ),
                    })
                    continue

            if username in usernames or user_id in user_ids:
                status_row['flag'] = 'repeat'
            elif not username and not user_id:
                status_row['flag'] = 'missing-data'
            else:
                try:
                    if username:
                        usernames.add(username)
                    if user_id:
                        user_ids.add(user_id)
                    if user_id:
                        user = CommCareUser.get_by_user_id(user_id, domain)
                    else:
                        user = CommCareUser.get_by_username(username)

                    if domain_obj.strong_mobile_passwords and is_password(
                            password):
                        if raw_username(
                                username) in usernames_with_dupe_passwords:
                            raise UserUploadError(
                                _("Provide a unique password for each mobile worker"
                                  ))

                        try:
                            clean_password(password)
                        except forms.ValidationError:
                            if settings.ENABLE_DRACONIAN_SECURITY_FEATURES:
                                msg = _(
                                    "Mobile Worker passwords must be 8 "
                                    "characters long with at least 1 capital "
                                    "letter, 1 special character and 1 number")
                            else:
                                msg = _("Please provide a stronger password")
                            raise UserUploadError(msg)

                    if user:
                        if user.domain != domain:
                            raise UserUploadError(
                                _('User with username %(username)r is '
                                  'somehow in domain %(domain)r') % {
                                      'username': user.username,
                                      'domain': user.domain
                                  })
                        if username and user.username != username:
                            raise UserUploadError(
                                _('Changing usernames is not supported: %(username)r to %(new_username)r'
                                  ) % {
                                      'username': user.username,
                                      'new_username': username
                                  })
                        if is_password(password):
                            user.set_password(password)
                        status_row['flag'] = 'updated'
                    else:
                        max_username_length = get_mobile_worker_max_username_length(
                            domain)
                        if len(raw_username(username)) > max_username_length:
                            ret['rows'].append({
                                'username':
                                username,
                                'row':
                                row,
                                'flag':
                                _("username cannot contain greater than %d characters"
                                  % max_username_length)
                            })
                            continue
                        if not is_password(password):
                            raise UserUploadError(
                                _("Cannot create a new user with a blank password"
                                  ))
                        user = CommCareUser.create(domain,
                                                   username,
                                                   password,
                                                   commit=False)
                        status_row['flag'] = 'created'
                    if phone_number:
                        user.add_phone_number(_fmt_phone(phone_number),
                                              default=True)
                    if name:
                        user.set_full_name(str(name))
                    if data:
                        error = custom_data_validator(data)
                        if error:
                            raise UserUploadError(error)
                        user.user_data.update(data)
                    if uncategorized_data:
                        user.user_data.update(uncategorized_data)
                    if language:
                        user.language = language
                    if email:
                        try:
                            validate_email(email)
                        except ValidationError:
                            raise UserUploadError(
                                _("User has an invalid email address"))

                        user.email = email.lower()
                    if is_active is not None:
                        user.is_active = is_active

                    if can_assign_locations:
                        # Do this here so that we validate the location code before we
                        # save any other information to the user, this way either all of
                        # the user's information is updated, or none of it
                        location_ids = []
                        for code in location_codes:
                            loc = get_location_from_site_code(
                                code, location_cache)
                            location_ids.append(loc.location_id)

                    if role:
                        if role in roles_by_name:
                            user.set_role(
                                domain, roles_by_name[role].get_qualified_id())
                        else:
                            raise UserUploadError(
                                _("Role '%s' does not exist") % role)

                    if can_assign_locations:
                        locations_updated = set(
                            user.assigned_location_ids) != set(location_ids)
                        primary_location_removed = (
                            user.location_id and not location_ids
                            or user.location_id not in location_ids)

                        if primary_location_removed:
                            user.unset_location(commit=False)
                        if locations_updated:
                            user.reset_locations(location_ids, commit=False)

                    user.save()

                    if is_password(password):
                        # Without this line, digest auth doesn't work.
                        # With this line, digest auth works.
                        # Other than that, I'm not sure what's going on
                        # Passing use_primary_db=True because of https://dimagi-dev.atlassian.net/browse/ICDS-465
                        user.get_django_user(
                            use_primary_db=True).check_password(password)

                    for group_id in Group.by_user_id(user.user_id, wrap=False):
                        group = group_memoizer.get(group_id)
                        if group.name not in group_names:
                            group.remove_user(user)

                    for group_name in group_names:
                        if group_name not in allowed_group_names:
                            raise UserUploadError(
                                _("Can't add to group '%s' "
                                  "(try adding it to your spreadsheet)") %
                                group_name)
                        group_memoizer.by_name(group_name).add_user(user,
                                                                    save=False)

                except (UserUploadError, CouchUser.Inconsistent) as e:
                    status_row['flag'] = str(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again.")
            logging.exception(('BulkSaveError saving groups. '
                               'User saw error message "%s". Errors: %s') %
                              (_error_message, e.errors))
            ret['errors'].append(_error_message)

    _set_progress(total)
    return ret
Example #15
0
 def clean_password(self):
     try:
         return clean_password(self.cleaned_data.get('password'))
     except forms.ValidationError:
         track_workflow(self.cleaned_data.get('email'), 'Password Failure')
         raise
Example #16
0
 def clean_password(self):
     return clean_password(self.cleaned_data.get("password"))
Example #17
0
def test_legacy_clean_password_pass(self, password):
    with override_settings(ENABLE_DRACONIAN_SECURITY_FEATURES=True):
        self.assertEqual(forms.clean_password(password), password)
Example #18
0
def test_legacy_clean_password_failures(self, password):
    with override_settings(ENABLE_DRACONIAN_SECURITY_FEATURES=True):
        with self.assertRaises(forms.forms.ValidationError):
            forms.clean_password(password)
Example #19
0
 def clean_password(self):
     if settings.ENFORCE_SSO_LOGIN and self.is_sso:
         # This field is not used with SSO. A randomly generated
         # password as a fallback is created in SsoBackend.
         return
     return clean_password(self.cleaned_data.get('password'))
Example #20
0
 def clean_password(self):
     cleaned_password = decode_password(self.cleaned_data.get('password'))
     if self.project.strong_mobile_passwords:
         return clean_password(cleaned_password)
     return cleaned_password
Example #21
0
def test_legacy_clean_password_failures(self, password):
    with override_settings(ENABLE_DRACONIAN_SECURITY_FEATURES=True):
        with self.assertRaises(forms.forms.ValidationError):
            forms.clean_password(password)
Example #22
0
 def clean_new_password1(self):
     return clean_password(self.cleaned_data.get('new_password1'))
Example #23
0
 def clean_password(self):
     if self.project.strong_mobile_passwords:
         return clean_password(self.cleaned_data.get('password'))
     return self.cleaned_data.get('password')
Example #24
0
 def clean_password(self):
     cleaned_password = decode_password(self.cleaned_data.get('password'))
     if self.project.strong_mobile_passwords:
         return clean_password(cleaned_password)
     return cleaned_password
 def assert_good_password(self, password):
     self.assertEqual(clean_password(password), password)
Example #26
0
 def clean_password(self):
     return clean_password(self.cleaned_data.get('password'))
 def test_valid_passwords(self):
     for password in passwords['valid']:
         forms.clean_password(password)
Example #28
0
 def clean_password(self):
     try:
         return clean_password(self.cleaned_data.get('password'))
     except forms.ValidationError:
         track_workflow(self.cleaned_data.get('email'), 'Password Failure')
         raise
Example #29
0
 def clean_password(self):
     return clean_password(self.cleaned_data.get('password'))
Example #30
0
def test_legacy_clean_password_pass(self, password):
    with override_settings(ENABLE_DRACONIAN_SECURITY_FEATURES=True):
        self.assertEqual(forms.clean_password(password), password)
Example #31
0
def create_or_update_users_and_groups(domain, user_specs, group_specs, task=None):
    from corehq.apps.users.views.mobile.custom_data_fields import UserFieldsView
    custom_data_validator = UserFieldsView.get_validator(domain)
    ret = {"errors": [], "rows": []}
    total = len(user_specs) + len(group_specs)

    def _set_progress(progress):
        if task is not None:
            DownloadBase.set_progress(task, progress, total)

    group_memoizer = create_or_update_groups(domain, group_specs, log=ret)
    current = len(group_specs)

    usernames = set()
    user_ids = set()
    allowed_groups = set(group_memoizer.groups)
    allowed_group_names = [group.name for group in allowed_groups]
    allowed_roles = UserRole.by_domain(domain)
    roles_by_name = {role.name: role for role in allowed_roles}
    can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    if can_assign_locations:
        location_cache = SiteCodeToLocationCache(domain)
    domain_obj = Domain.get_by_name(domain)
    usernames_with_dupe_passwords = users_with_duplicate_passwords(user_specs)

    try:
        for row in user_specs:
            _set_progress(current)
            current += 1

            data = row.get('data')
            email = row.get('email')
            group_names = list(map(six.text_type, row.get('group') or []))
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            username = row.get('username')
            location_codes = row.get('location_code') or []
            if location_codes and not isinstance(location_codes, list):
                location_codes = [location_codes]
            # ignore empty
            location_codes = [code for code in location_codes if code]
            role = row.get('role', '')

            if password:
                password = six.text_type(password)
            try:
                username = normalize_username(six.text_type(username), domain)
            except TypeError:
                username = None
            except ValidationError:
                ret['rows'].append({
                    'username': username,
                    'row': row,
                    'flag': _('username cannot contain spaces or symbols'),
                })
                continue
            status_row = {
                'username': raw_username(username) if username else None,
                'row': row,
            }

            is_active = row.get('is_active')
            if isinstance(is_active, six.string_types):
                soft_assert_type_text(is_active)
                try:
                    is_active = string_to_boolean(is_active) if is_active else None
                except ValueError:
                    ret['rows'].append({
                        'username': username,
                        'row': row,
                        'flag': _("'is_active' column can only contain 'true' or 'false'"),
                    })
                    continue

            if username in usernames or user_id in user_ids:
                status_row['flag'] = 'repeat'
            elif not username and not user_id:
                status_row['flag'] = 'missing-data'
            else:
                try:
                    if username:
                        usernames.add(username)
                    if user_id:
                        user_ids.add(user_id)
                    if user_id:
                        user = CommCareUser.get_by_user_id(user_id, domain)
                    else:
                        user = CommCareUser.get_by_username(username)

                    if domain_obj.strong_mobile_passwords and is_password(password):
                        if raw_username(username) in usernames_with_dupe_passwords:
                            raise UserUploadError(_("Provide a unique password for each mobile worker"))

                        try:
                            clean_password(password)
                        except forms.ValidationError:
                            if settings.ENABLE_DRACONIAN_SECURITY_FEATURES:
                                msg = _("Mobile Worker passwords must be 8 "
                                    "characters long with at least 1 capital "
                                    "letter, 1 special character and 1 number")
                            else:
                                msg = _("Please provide a stronger password")
                            raise UserUploadError(msg)

                    if user:
                        if user.domain != domain:
                            raise UserUploadError(_(
                                'User with username %(username)r is '
                                'somehow in domain %(domain)r'
                            ) % {'username': user.username, 'domain': user.domain})
                        if username and user.username != username:
                            raise UserUploadError(_(
                                'Changing usernames is not supported: %(username)r to %(new_username)r'
                            ) % {'username': user.username, 'new_username': username})
                        if is_password(password):
                            user.set_password(password)
                        status_row['flag'] = 'updated'
                    else:
                        max_username_length = get_mobile_worker_max_username_length(domain)
                        if len(raw_username(username)) > max_username_length:
                            ret['rows'].append({
                                'username': username,
                                'row': row,
                                'flag': _("username cannot contain greater than %d characters" %
                                          max_username_length)
                            })
                            continue
                        if not is_password(password):
                            raise UserUploadError(_("Cannot create a new user with a blank password"))
                        user = CommCareUser.create(domain, username, password, commit=False)
                        status_row['flag'] = 'created'
                    if phone_number:
                        user.add_phone_number(_fmt_phone(phone_number), default=True)
                    if name:
                        user.set_full_name(six.text_type(name))
                    if data:
                        error = custom_data_validator(data)
                        if error:
                            raise UserUploadError(error)
                        user.user_data.update(data)
                    if uncategorized_data:
                        user.user_data.update(uncategorized_data)
                    if language:
                        user.language = language
                    if email:
                        try:
                            validate_email(email)
                        except ValidationError:
                            raise UserUploadError(_("User has an invalid email address"))

                        user.email = email.lower()
                    if is_active is not None:
                        user.is_active = is_active

                    if can_assign_locations:
                        # Do this here so that we validate the location code before we
                        # save any other information to the user, this way either all of
                        # the user's information is updated, or none of it
                        location_ids = []
                        for code in location_codes:
                            loc = get_location_from_site_code(code, location_cache)
                            location_ids.append(loc.location_id)

                    if role:
                        if role in roles_by_name:
                            user.set_role(domain, roles_by_name[role].get_qualified_id())
                        else:
                            raise UserUploadError(_(
                                "Role '%s' does not exist"
                            ) % role)

                    if can_assign_locations:
                        locations_updated = set(user.assigned_location_ids) != set(location_ids)
                        primary_location_removed = (user.location_id and not location_ids or
                                                    user.location_id not in location_ids)

                        if primary_location_removed:
                            user.unset_location(commit=False)
                        if locations_updated:
                            user.reset_locations(location_ids, commit=False)

                    user.save()

                    if is_password(password):
                        # Without this line, digest auth doesn't work.
                        # With this line, digest auth works.
                        # Other than that, I'm not sure what's going on
                        # Passing use_primary_db=True because of https://dimagi-dev.atlassian.net/browse/ICDS-465
                        user.get_django_user(use_primary_db=True).check_password(password)

                    for group_id in Group.by_user(user, wrap=False):
                        group = group_memoizer.get(group_id)
                        if group.name not in group_names:
                            group.remove_user(user)

                    for group_name in group_names:
                        if group_name not in allowed_group_names:
                            raise UserUploadError(_(
                                "Can't add to group '%s' "
                                "(try adding it to your spreadsheet)"
                            ) % group_name)
                        group_memoizer.by_name(group_name).add_user(user, save=False)

                except (UserUploadError, CouchUser.Inconsistent) as e:
                    status_row['flag'] = six.text_type(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again."
            )
            logging.exception((
                'BulkSaveError saving groups. '
                'User saw error message "%s". Errors: %s'
            ) % (_error_message, e.errors))
            ret['errors'].append(_error_message)

    _set_progress(total)
    return ret
Example #32
0
 def clean_password(self):
     if self.project.strong_mobile_passwords:
         return clean_password(self.cleaned_data.get('password'))
     return self.cleaned_data.get('password')
Example #33
0
 def clean_new_password1(self):
     password1 = self.cleaned_data.get('new_password1')
     if self.project.strong_mobile_passwords:
         return clean_password(password1)
     return password1