Example #1
0
    def save(self, force_insert=False, only=None):
        all_rules = lockdown_context.get_rules(self.__class__)

        if self.get_id() is None and not self.is_creatable(all_rules):
            raise LockdownException('Model not creatable in current context')

        if not self.is_writable(all_rules):
            raise LockdownException('Model not writable in current context')

        if all_rules:
            fields_to_check = self._meta.get_fields() if only is None else only
            only = []
            for field in fields_to_check:
                value = getattr(
                    self, field.name) if field.name in self._data else None
                # check if this field has a change context set. if so that means
                # setattr already validated the change and it can just be accepted here.
                # this is useful so one context can set some fields, then maybe a server
                # context could set a field like `modified`.
                change_context = self._change_contexts.get(field.name)
                if change_context or self.check_field_writable(
                        all_rules, field, value, False):
                    only.append(field)

        return super(SecureModel, self).save(force_insert, only)
Example #2
0
    def deserialize_object(self, data, instance):
        all_rules = lockdown_context.get_rules(self.model)
        if all_rules:
            # check if the api should be allowed to create an instance
            if instance is None or instance.get_id(
            ) is None and not SecureModel.is_creatable(all_rules):
                raise LockdownException(
                    'Model not creatable in current context')

            # check if api should be able to edit this instance
            if instance and not instance.is_writable(all_rules):
                raise LockdownException(
                    'Model not writable in current context')

            # remove any non-writable data
            writeable_data = {}
            for k, v in data.items():
                field = self.model._meta.fields.get(k)
                if not field or instance.is_field_writeable(
                        instance, field, all_rules):
                    writeable_data[k] = v
            data = writeable_data

        return super(SecureRestResource,
                     self).deserialize_object(data, instance)
Example #3
0
 def select(cls, *selection):
     query = cls.create_select_query(*selection)
     all_rules = lockdown_context.get_rules(cls)
     for rules in all_rules:
         if rules.read_rule:
             query = query.where(rules.read_rule)
     if cls._meta.order_by:
         query = query.order_by(*cls._meta.order_by)
     return query
Example #4
0
    def is_readable(self, all_rules=None):
        if all_rules is None:
            all_rules = lockdown_context.get_rules(self.__class__)

        for rules in all_rules:
            if rules.read_rule and not check_rule_expr(self, rules.read_rule):
                return False

        return True
Example #5
0
    def is_creatable(cls, all_rules=None):
        if all_rules is None:
            all_rules = lockdown_context.get_rules(cls)

        for rules in all_rules:
            if rules.create_rule and not check_rule_expr(
                    None, rules.create_rule):
                return False

        return True
Example #6
0
    def prepare_data(self, obj, data):
        # remove any fields that are read-only in the current context
        # the data may have already been removed when the object was fetched,
        # but it could have been fetched in a different context, so re-filter.
        all_rules = lockdown_context.get_rules(self.model)
        if all_rules:
            for k in data:
                field = self.model._meta.fields.get(k)
                if field and not obj.is_field_readable(field, all_rules):
                    del data[k]

        return data
Example #7
0
    def is_deleteable(self, all_rules=None):
        if all_rules is None:
            all_rules = lockdown_context.get_rules(self.__class__)

        if not self.is_writable(all_rules):
            return False

        for rules in all_rules:
            if rules.delete_rule and not check_rule_expr(
                    self, rules.delete_rule):
                return False

        return True
Example #8
0
    def is_field_readable(self, field, all_rules=None):
        if all_rules is None:
            all_rules = lockdown_context.get_rules(self.__class__)

        if not self.is_readable(all_rules):
            return False

        for rules in all_rules:
            field_rules = rules.field_read_rules.get(field.name)
            if field_rules and not check_rule_expr(self, field_rules):
                return False

        return True
Example #9
0
    def prepared(self):
        super(SecureModel, self).prepared()
        self._validate = True

        all_rules = lockdown_context.get_rules(self.__class__)
        if all_rules:
            if not self.is_readable(all_rules):
                raise LockdownException(
                    'Model not readable in current context')

            to_remove = []
            for field in self._meta.get_fields():
                if field.name in self._data and not self.is_field_readable(
                        field, all_rules):
                    to_remove.append(field.name)

            if to_remove:
                # make a backup of the raw data so it could still be accessed for things like caching
                self._secure_data = dict(self._data)
                # remove the fields that are not visible
                for field_name in to_remove:
                    del self._data[field_name]
Example #10
0
    def __setattr__(self, key, value):
        field = self._meta.fields.get(key)

        if field:
            # if the object doesn't yet have an id, and this is the id field
            # turn off validation. this ensures that peewee queries aren't
            # self validating since the first field a query will fill is id.
            # once the query is complete, prepared will turn validation back on
            if not self.get_id() and field.primary_key:
                self._validate = False

            # if validation is enabled check that the field is writable
            if getattr(self, '_validate', True):
                all_rules = lockdown_context.get_rules(self.__class__)
                self.check_field_writable(all_rules, field, value, True)

            # capture the role doing the setting. this lets different fields
            # get set by different contexts
            if lockdown_context.role:
                self._change_contexts[key] = lockdown_context.role

        return super(SecureModel, self).__setattr__(key, value)