owncloud / ocis

:atom_symbol: ownCloud Infinite Scale Stack
https://doc.owncloud.com/ocis/next/
Apache License 2.0
1.36k stars 179 forks source link

Support public id-based dav requests #9623

Open JammingBen opened 2 months ago

JammingBen commented 2 months ago

Id-based dav requests via .../dav/spaces/{fileId} currently only work in an authenticated context. Requests via .../dav/public-files on the other hand work publicly, but only path-based, not id-based.

The Web client needs those public dav requests to work id-based as well, otherwise we would need to keep supporting ids and paths. That feels like an unnecessary overhead.

\cc @butonic

butonic commented 2 months ago

Id based requests for public links need to be investigated. The requests use the token in the /dav/public-files/{token}/relative/path/to/file.ext path to authenticate requests.

Currently, the publicstorageprovider only knows one space: /dav/spaces/7993447f-687f-490d-875c-ac95e89a62a4$7993447f-687f-490d-875c-ac95e89a62a4!{token}/relative/path/to/file.ext

We could change that to understand /dav/spaces/7993447f-687f-490d-875c-ac95e89a62a4${token}!{opaqueid}. The token can be used to resolve the resource that was shared. then we can build a new reference in the space with the opaqueid.

The question is how that request can be authorized. The public storageprovider in effect impersonates the owner of the space but jails the request into the subtree referenced by the token. Then the public share scope takes care of verifying the reference is relative to the shared resource:

func checkStorageRef(ctx context.Context, s *link.PublicShare, r *provider.Reference) bool {
    // r: <resource_id:<storage_id:$storageID space_id:$spaceID opaque_id:$opaqueID> path:$path > >
    if utils.ResourceIDEqual(s.ResourceId, r.GetResourceId()) {
        return true
    }

    // r: <path:"/public/$token" >
    if strings.HasPrefix(r.GetPath(), "/public/"+s.Token) || strings.HasPrefix(r.GetPath(), "./"+s.Token) {
        return true
    }

    // r: <resource_id:<storage_id: space_id: opaque_id:$token> path:$path>
    if id := r.GetResourceId(); id.GetStorageId() == PublicStorageProviderID {
        // access to /public
        if id.GetOpaqueId() == PublicStorageProviderID {
            return true
        }
        // access relative to /public/$token
        if id.GetOpaqueId() == s.Token {     // <- this in effect jails requests into the shared tree
            return true
        }
    }
    return false
}

We could add code here that handles references where the token is the space id ... Another option would be to build a reference in the publicstorageprovider that is relative ... so the scope can remain the same. I fear the latter won't work because the scope is checked by the gateway before it reaches the publicstorageprovider.

butonic commented 1 month ago

old related outdated PR https://github.com/cs3org/reva/pull/3875

butonic commented 1 month ago

Replacing the spaceid with the token wont work for the graph API because you always need authentication there. 🤔