def create(self, validated_data):
        """Override of create method."""
        """
        We have a bit of extra checking around this in order to provide
        descriptive messages when something goes wrong, but this method is
        essentially just:
            return ExampleModel.objects.create(**validated_data)
        If there are many to many fields present on the instance then they
        cannot be set until the model is instantiated, in which case the
        implementation is like so:
            example_relationship = validated_data.pop('example_relationship')
            instance = ExampleModel.objects.create(**validated_data)
            instance.example_relationship = example_relationship
            return instance
        The default implementation also does not handle nested relationships.
        If you want to support writable nested relationships you'll need
        to write an explicit `.create()` method.
        """
        raise_errors_on_nested_writes("create", self, validated_data)

        ModelClass = self.Meta.model

        # Remove many-to-many relationships from validated_data.
        # They are not valid arguments to the default `.create()` method,
        # as they require that the instance has already been saved.
        info = model_meta.get_field_info(ModelClass)
        many_to_many = {}
        for field_name, relation_info in info.relations.items():
            if relation_info.to_many and (field_name in validated_data):
                many_to_many[field_name] = validated_data.pop(field_name)

        try:
            for request_tenant in schema_handler(
                    self.context["request"].tenant):
                instance = ModelClass._default_manager.create(
                    **validated_data, tenant=request_tenant)
        except TypeError:
            tb = traceback.format_exc()
            msg = ("Got a `TypeError` when calling `%s.%s.create()`. "
                   "This may be because you have a writable field on the "
                   "serializer class that is not a valid argument to "
                   "`%s.%s.create()`. You may need to make the field "
                   "read-only, or override the %s.create() method to handle "
                   "this correctly.\nOriginal exception was:\n %s" % (
                       ModelClass.__name__,
                       ModelClass._default_manager.name,
                       ModelClass.__name__,
                       ModelClass._default_manager.name,
                       self.__class__.__name__,
                       tb,
                   ))
            raise TypeError(msg)

        # Save many-to-many relationships after the instance is created.
        if many_to_many:
            for field_name, value in many_to_many.items():
                field = getattr(instance, field_name)
                field.set(value)

        return instance
Ejemplo n.º 2
0
def remove_roles(group, role_ids, tenant):
    """Process list of roles and remove them from the group."""
    roles = Role.objects.filter(uuid__in=role_ids)
    role_names = list(roles.values_list("name", flat=True))

    for tenant_schema in schema_handler(tenant):
        group = Group.objects.get(name=group.name, tenant=tenant)
        roles = Role.objects.filter(name__in=role_names, tenant=tenant)
        for policy in group.policies.all():
            policy.roles.remove(*roles)
Ejemplo n.º 3
0
    def update(self, instance, validated_data):
        """Patch the role object."""
        tenant = self.context["request"].tenant
        role_name = instance.name
        update_data = validate_role_update(instance, validated_data)

        for tenant_schema in schema_handler(tenant):
            instance = update_role(role_name,
                                   update_data,
                                   tenant,
                                   clear_access=False)
        return instance
Ejemplo n.º 4
0
    def update(self, instance, validated_data):
        """Update the role object in the database."""
        access_list = validated_data.pop("access")
        tenant = self.context["request"].tenant
        role_name = instance.name
        update_data = validate_role_update(instance, validated_data)

        for tenant_schema in schema_handler(tenant):
            instance = update_role(role_name, update_data, tenant)

            create_access_for_role(instance, access_list, tenant)

        return instance
Ejemplo n.º 5
0
    def create(self, validated_data):
        """Create the role object in the database."""
        name = validated_data.pop("name")
        display_name = validated_data.pop("display_name", name)
        description = validated_data.pop("description", None)
        access_list = validated_data.pop("access")
        tenant = self.context["request"].tenant
        for tenant_schema in schema_handler(tenant):
            role = Role.objects.create(name=name,
                                       description=description,
                                       display_name=display_name,
                                       tenant=tenant)
            create_access_for_role(role, access_list, tenant)

        return role
Ejemplo n.º 6
0
def add_roles(group,
              roles_or_role_ids,
              tenant,
              user=None,
              replace=False,
              duplicate_in_public=False):
    """Process list of roles and add them to the group."""
    if not isinstance(roles_or_role_ids, QuerySet):
        # If given an iterable of UUIDs, get the corresponding objects
        roles = Role.objects.filter(uuid__in=roles_or_role_ids)
    else:
        roles = roles_or_role_ids
    group_name = group.name
    role_names = list(roles.values_list("name", flat=True))

    for tenant_schema in schema_handler(tenant,
                                        include_public=duplicate_in_public):
        group, created = Group.objects.get_or_create(name=group_name,
                                                     tenant=tenant)
        system_policy_name = "System Policy for Group {}".format(group.uuid)
        system_policy, system_policy_created = Policy.objects.update_or_create(
            system=True,
            group=group,
            name=system_policy_name,
            defaults={"tenant": tenant})

        if system_policy_created:
            logger.info(
                f"Created new system policy for tenant {tenant_schema.schema_name}."
            )
        else:
            if replace:
                system_policy.roles.clear()

        roles = Role.objects.filter(
            Q(tenant=tenant)
            | Q(tenant=Tenant.objects.get(schema_name="public")),
            name__in=role_names)
        for role in roles:
            accesses = role.access.all()
            for access in accesses:
                if access.permission_application(
                ) == "rbac" and user and not user.admin:
                    key = "add-roles"
                    message = f"Non-admin users cannot add RBAC role {role.display_name} to groups."
                    raise serializers.ValidationError({key: _(message)})
            system_policy.roles.add(role)