Skip to content

Commit

Permalink
OCM: Add logic for resolving storage references over webdav (cs3org#1094
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ishank011 authored and glpatcern committed Aug 24, 2020
1 parent 62a089d commit 17712b5
Show file tree
Hide file tree
Showing 25 changed files with 711 additions and 175 deletions.
7 changes: 7 additions & 0 deletions changelog/unreleased/webdav-storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Add logic for resolving storage references over webdav

This PR adds the functionality to resolve webdav references using the ocs
webdav service by passing the resource's owner's token. This would need to be
changed in production.

https://github.com/cs3org/reva/pull/1094
106 changes: 78 additions & 28 deletions cmd/reva/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ import (
"github.com/cheggaaa/pb"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/internal/http/services/datagateway"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rhttp"
tokenpkg "github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/utils"
"github.com/pkg/errors"
"github.com/studio-b12/gowebdav"
)

func downloadCommand() *command {
Expand Down Expand Up @@ -85,51 +89,97 @@ func downloadCommand() *command {
// TODO(labkode): upload to data server
fmt.Printf("Downloading from: %s\n", res.DownloadEndpoint)

dataServerURL := res.DownloadEndpoint
// TODO(labkode): do a protocol switch
httpReq, err := rhttp.NewRequest(ctx, "GET", dataServerURL, nil)
content, err := checkDownloadWebdavRef(res.DownloadEndpoint, res.Opaque)
if err != nil {
return err
}

httpReq.Header.Set(datagateway.TokenTransportHeader, res.Token)
httpClient := rhttp.GetHTTPClient(
rhttp.Context(ctx),
// TODO make insecure configurable
rhttp.Insecure(true),
// TODO make timeout configurable
rhttp.Timeout(time.Duration(24*int64(time.Hour))),
)

httpRes, err := httpClient.Do(httpReq)
if err != nil {
return err
}
defer httpRes.Body.Close()

if httpRes.StatusCode != http.StatusOK {
return err
if _, ok := err.(errtypes.IsNotSupported); !ok {
return err
}

dataServerURL := res.DownloadEndpoint
// TODO(labkode): do a protocol switch
httpReq, err := rhttp.NewRequest(ctx, "GET", dataServerURL, nil)
if err != nil {
return err
}

httpReq.Header.Set(datagateway.TokenTransportHeader, res.Token)
httpClient := rhttp.GetHTTPClient(
rhttp.Context(ctx),
// TODO make insecure configurable
rhttp.Insecure(true),
// TODO make timeout configurable
rhttp.Timeout(time.Duration(24*int64(time.Hour))),
)

httpRes, err := httpClient.Do(httpReq)
if err != nil {
return err
}
defer httpRes.Body.Close()

if httpRes.StatusCode != http.StatusOK {
return err
}
content = httpRes.Body
}

absPath, err := utils.ResolvePath(local)
if err != nil {
return err
}

bar := pb.New(int(info.Size)).SetUnits(pb.U_BYTES)
bar.Start()
reader := bar.NewProxyReader(content)

fd, err := os.OpenFile(absPath, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}

bar := pb.New(int(info.Size)).SetUnits(pb.U_BYTES)
bar.Start()
reader := bar.NewProxyReader(httpRes.Body)
if _, err := io.Copy(fd, reader); err != nil {
return err
}
bar.Finish()
return nil

}
return cmd
}

func checkDownloadWebdavRef(endpoint string, opaque *typespb.Opaque) (io.Reader, error) {
if opaque == nil {
return nil, errtypes.NotSupported("opaque object not defined")
}

var token string
tokenOpaque, ok := opaque.Map["webdav-token"]
if !ok {
return nil, errtypes.NotSupported("webdav token not defined")
}
switch tokenOpaque.Decoder {
case "plain":
token = string(tokenOpaque.Value)
default:
return nil, errors.New("opaque entry decoder not recognized: " + tokenOpaque.Decoder)
}

var filePath string
fileOpaque, ok := opaque.Map["webdav-file-path"]
if !ok {
return nil, errtypes.NotSupported("webdav file path not defined")
}
switch fileOpaque.Decoder {
case "plain":
filePath = string(fileOpaque.Value)
default:
return nil, errors.New("opaque entry decoder not recognized: " + fileOpaque.Decoder)
}

c := gowebdav.NewClient(endpoint, "", "")
c.SetHeader(tokenpkg.TokenHeader, token)

reader, err := c.ReadStream(filePath)
if err != nil {
return nil, err
}
return reader, nil
}
17 changes: 6 additions & 11 deletions cmd/reva/ocm-share-create.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
package main

import (
"encoding/json"
"fmt"
"io"
"os"
"path"
"strconv"
"time"

Expand Down Expand Up @@ -119,20 +117,17 @@ func ocmShareCreateCommand() *command {
},
}

permissionMap := map[string]string{"name": strconv.Itoa(pint)}
val, err := json.Marshal(permissionMap)
if err != nil {
return err
}
fmt.Println("res.Info.Path" + res.Info.Path)

opaqueObj := &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"permissions": &types.OpaqueEntry{
Decoder: "json",
Value: val,
Decoder: "plain",
Value: []byte(strconv.Itoa(pint)),
},
"name": &types.OpaqueEntry{
Decoder: "plain",
Value: []byte(path.Base(res.Info.Path)),
Value: []byte(res.Info.Path),
},
},
}
Expand All @@ -148,12 +143,12 @@ func ocmShareCreateCommand() *command {
if err != nil {
return err
}
fmt.Println("create share done")

if shareRes.Status.Code != rpc.Code_CODE_OK {
return formatError(shareRes.Status)
}

fmt.Println("create share done")
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{"#", "Owner.Idp", "Owner.OpaqueId", "ResourceId", "Permissions", "Type", "Grantee.Idp", "Grantee.OpaqueId", "Created", "Updated"})
Expand Down
65 changes: 61 additions & 4 deletions cmd/reva/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"

"github.com/cs3org/reva/pkg/errtypes"
tokenpkg "github.com/cs3org/reva/pkg/token"
"github.com/eventials/go-tus"
"github.com/eventials/go-tus/memorystore"
"github.com/studio-b12/gowebdav"

// TODO(labkode): this should not come from this package.
"github.com/cs3org/reva/internal/grpc/services/storageprovider"
Expand All @@ -51,11 +52,11 @@ func uploadCommand() *command {
cmd := newCommand("upload")
cmd.Description = func() string { return "upload a local file to the remote server" }
cmd.Usage = func() string { return "Usage: upload [-flags] <file_name> <remote_target>" }
disabletusFlag := cmd.Bool("disable-tus", false, "whether to disable tus protocol")
disableTusFlag := cmd.Bool("disable-tus", false, "whether to disable tus protocol")
xsFlag := cmd.String("xs", "negotiate", "compute checksum")

cmd.ResetFlags = func() {
*disabletusFlag, *xsFlag = false, "negotiate"
*disableTusFlag, *xsFlag = false, "negotiate"
}

cmd.Action = func(w ...io.Writer) error {
Expand Down Expand Up @@ -121,6 +122,14 @@ func uploadCommand() *command {
fmt.Printf("Data server: %s\n", res.UploadEndpoint)
fmt.Printf("Allowed checksums: %+v\n", res.AvailableChecksums)

if err = checkUploadWebdavRef(res.UploadEndpoint, res.Opaque, md, fd); err != nil {
if _, ok := err.(errtypes.IsNotSupported); !ok {
return err
}
} else {
return nil
}

xsType, err := guessXS(*xsFlag, res.AvailableChecksums)
if err != nil {
return err
Expand All @@ -144,7 +153,7 @@ func uploadCommand() *command {
bar.Start()
reader := bar.NewProxyReader(fd)

if *disabletusFlag {
if *disableTusFlag {
httpReq, err := rhttp.NewRequest(ctx, "PUT", dataServerURL, reader)
if err != nil {
bar.Finish()
Expand Down Expand Up @@ -253,6 +262,54 @@ func uploadCommand() *command {
return cmd
}

func checkUploadWebdavRef(endpoint string, opaque *typespb.Opaque, md os.FileInfo, fd *os.File) error {
if opaque == nil {
return errtypes.NotSupported("opaque object not defined")
}

var token string
tokenOpaque, ok := opaque.Map["webdav-token"]
if !ok {
return errtypes.NotSupported("webdav token not defined")
}
switch tokenOpaque.Decoder {
case "plain":
token = string(tokenOpaque.Value)
default:
return errors.New("opaque entry decoder not recognized: " + tokenOpaque.Decoder)
}

var filePath string
fileOpaque, ok := opaque.Map["webdav-file-path"]
if !ok {
return errtypes.NotSupported("webdav file path not defined")
}
switch fileOpaque.Decoder {
case "plain":
filePath = string(fileOpaque.Value)
default:
return errors.New("opaque entry decoder not recognized: " + fileOpaque.Decoder)
}

bar := pb.New(int(md.Size())).SetUnits(pb.U_BYTES)
bar.Start()
reader := bar.NewProxyReader(fd)

c := gowebdav.NewClient(endpoint, "", "")
c.SetHeader(tokenpkg.TokenHeader, token)
c.SetHeader("Upload-Length", strconv.FormatInt(md.Size(), 10))

err := c.WriteStream(filePath, reader, 0700)
if err != nil {
bar.Finish()
return err
}

bar.Finish()
fmt.Println("File uploaded")
return nil
}

func computeXS(t provider.ResourceChecksumType, r io.Reader) (string, error) {
switch t {
case provider.ResourceChecksumType_RESOURCE_CHECKSUM_TYPE_ADLER32:
Expand Down
12 changes: 6 additions & 6 deletions examples/ocm-partners/providers.demo.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"description": "CERNBox Webdav API"
},
"name": "CERNBox - Webdav API",
"path": "https://sciencemesh.cernbox.cern.ch/iop/webdav/",
"path": "https://sciencemesh.cernbox.cern.ch/iop/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
Expand Down Expand Up @@ -63,7 +63,7 @@
"description": "CESNET Webdav API"
},
"name": "CESNET - Webdav API",
"path": "https://sciencemesh.cesnet.cz/iop/webdav/",
"path": "https://sciencemesh.cesnet.cz/iop/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
Expand Down Expand Up @@ -99,7 +99,7 @@
"description": "WWU Webdav API"
},
"name": "WWU - Webdav API",
"path": "https://sciencemesh-test.uni-muenster.de/api/webdav/",
"path": "https://sciencemesh-test.uni-muenster.de/api/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
Expand Down Expand Up @@ -135,7 +135,7 @@
"description": "Cubbit Webdav API"
},
"name": "Cubbit - Webdav API",
"path": "https://sciencemesh.cubbit.io/webdav/",
"path": "https://sciencemesh.cubbit.io/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
Expand Down Expand Up @@ -171,7 +171,7 @@
"description": "Ailleron Webdav API"
},
"name": "Ailleron - Webdav API",
"path": "https://sciencemesh.softwaremind.com/iop/webdav/",
"path": "https://sciencemesh.softwaremind.com/iop/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
Expand Down Expand Up @@ -207,7 +207,7 @@
"description": "Surfsara Webdav API"
},
"name": "Surfsara - Webdav API",
"path": "https://app.cs3mesh-iop.k8s.surfsara.nl/iop/webdav/",
"path": "https://app.cs3mesh-iop.k8s.surfsara.nl/iop/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
Expand Down
2 changes: 2 additions & 0 deletions examples/ocmd/ocmd-server-1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,6 @@ providers = "providers.demo.json"
[http.services.ocs]
prefix = "ocs"

[http.services.ocdav]

[http.middlewares.cors]
2 changes: 2 additions & 0 deletions examples/ocmd/ocmd-server-2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,6 @@ providers = "providers.demo.json"
[http.services.ocs]
prefix = "ocs"

[http.services.ocdav]

[http.middlewares.cors]
Loading

0 comments on commit 17712b5

Please sign in to comment.