Skip to content

File ownership

Every file can have an owner and there can be only one owner of the file. It's possible to create file without an owner, but usually application will only benefit from keeping every file with its owner. Owner is described with two fields: ID and type.

When file is created, by default the current user from API action's context is assigned as an owner of the file. From now on, the owner can perform other operations, such as renaming/displaying/removing with the file.

Apart from chaining auth function, to modify access rules for the file, plugin can implement IFiles.files_file_allows and IFiles.files_owner_allows methods.

def files_file_allows(
    self,
    context: Context,
    file: File | Multipart,
    operation: types.FileOperation,
) -> bool | None:
    ...

def files_owner_allows(
    self,
    context: Context,
    owner_type: str, owner_id: str,
    operation: types.OwnerOperation,
) -> bool | None:
    ...

These methods receive current action context, the tested object details, and the name of operation(show, update, delete, file_transfer). files_file_allows checks permission for accessed file. It's usually called when user interacts with file directly. files_owner_allows works with owner described by type and ID. It's usually called when user transfer file ownership, perform bulk file operation for owner files, or just trying to get the list of files that belongs to owner.

If method returns true/false, operation is allowed/denied. If method returns None, default logic used to check access.

As already mentoined, by default, user who owns the file, can access it. But what about different owners? What if file owned by other entity, like resource or dataset?

Out of the box, nobody can access such files. But there are three config options that modify this restriction.

ckanext.files.owner.cascade_access = ENTITY_TYPE ANOTHER_TYPE gives access to file owned by entity if user already has access to entity itself. Use words like package, resource, group instead of ENTITY_TYPE.

For example: file is owned by resource. If cascade access is enabled, whoever has access to resource_show of the resource, can also see the file owned by this resource. If user passes resource_update for resource, he can also modify the file owned by this resource, etc.

Danger

Be careful and do not add user to ckanext.files.owner.cascade_access. User's own files are considered private and most likely you don't really need anyone else to be able to see or modify these files.

The second option is ckanext.files.owner.transfer_as_update. When transfer-as-update enabled, any user who has <OWNER_TYPE>_update permission, can transfer own files to this OWNER_TYPE. Intead of using this option, you can define <OWNER_TYPE>_file_transfer.

And the third option is ckanext.files.owner.scan_as_update. Just as with ownership transfer, it gives user permission to list all files of the owner if user can <OWNER_TYPE>_update it. Intead of using this option, you can define <OWNER_TYPE>_file_scan.