Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upload directly to dataprovider #4065

Merged
merged 1 commit into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/unreleased/upload-directly-to-dataprovider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: upload directly to dataprovider

The ocdav service can now bypass the datagateway if it is configured with a transfer secret. This prevents unnecessary roundtrips and halves the network traffic during uploads for the proxy.

https://github.com/cs3org/reva/pull/4065
https://github.com/owncloud/ocis/issues/6296
32 changes: 18 additions & 14 deletions internal/http/services/datagateway/datagateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ func init() {
global.Register("datagateway", New)
}

// transferClaims are custom claims for a JWT token to be used between the metadata and data gateways.
type transferClaims struct {
// TransferClaims are custom claims for a JWT token to be used between the metadata and data gateways.
type TransferClaims struct {
jwt.StandardClaims
Target string `json:"target"`
}
Expand Down Expand Up @@ -161,30 +161,34 @@ func addCorsHeader(res http.ResponseWriter) {
headers.Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, HEAD")
}

func (s *svc) verify(ctx context.Context, r *http.Request) (*transferClaims, error) {
// Extract transfer token from request header. If not existing, assume that it's the last path segment instead.
token := r.Header.Get(TokenTransportHeader)
if token == "" {
token = path.Base(r.URL.Path)
r.Header.Set(TokenTransportHeader, token)
}

j, err := jwt.ParseWithClaims(token, &transferClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(s.conf.TransferSharedSecret), nil
// Verify a transfer token against the given secret
func Verify(ctx context.Context, token string, secret string) (*TransferClaims, error) {
j, err := jwt.ParseWithClaims(token, &TransferClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})

if err != nil {
return nil, errors.Wrap(err, "error parsing token")
}

if claims, ok := j.Claims.(*transferClaims); ok && j.Valid {
if claims, ok := j.Claims.(*TransferClaims); ok && j.Valid {
return claims, nil
}

err = errtypes.InvalidCredentials("token invalid")
return nil, err
}

func (s *svc) verify(ctx context.Context, r *http.Request) (*TransferClaims, error) {
// Extract transfer token from request header. If not existing, assume that it's the last path segment instead.
token := r.Header.Get(TokenTransportHeader)
if token == "" {
token = path.Base(r.URL.Path)
r.Header.Set(TokenTransportHeader, token)
}

return Verify(ctx, token, s.conf.TransferSharedSecret)
}

func (s *svc) doHead(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
Expand Down
2 changes: 2 additions & 0 deletions internal/http/services/owncloud/ocdav/ocdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ type Config struct {
Product string `mapstructure:"product"`
ProductName string `mapstructure:"product_name"`
ProductVersion string `mapstructure:"product_version"`
// optional, if set will unpack the transfer token and directly send uploads to the data provider
TransferSharedSecret string `mapstructure:"transfer_shared_secret"`

NameValidation NameValidation `mapstructure:"validation"`

Expand Down
12 changes: 12 additions & 0 deletions internal/http/services/owncloud/ocdav/put.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,18 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
}
}

// if we know the transfer secret we can directly talk to the dataprovider
if s.c.TransferSharedSecret != "" {
claims, err := datagateway.Verify(ctx, token, s.c.TransferSharedSecret)
if err != nil {
log.Error().Err(err).Msg("error verifying transfer token")
w.WriteHeader(http.StatusInternalServerError)
return
}
// directly send request to target
ep = claims.Target
}

httpReq, err := rhttp.NewRequest(ctx, http.MethodPut, ep, r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand Down
13 changes: 13 additions & 0 deletions internal/http/services/owncloud/ocdav/tus.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/datagateway"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup"
Expand Down Expand Up @@ -254,6 +255,18 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http.
}
var httpRes *http.Response

// if we know the transfer secret we can directly talk to the dataprovider
if s.c.TransferSharedSecret != "" {
claims, err := datagateway.Verify(ctx, token, s.c.TransferSharedSecret)
if err != nil {
log.Error().Err(err).Msg("error verifying transfer token")
w.WriteHeader(http.StatusInternalServerError)
return
}
// directly send request to target
ep = claims.Target
}

httpReq, err := rhttp.NewRequest(ctx, http.MethodPatch, ep, r.Body)
if err != nil {
log.Debug().Err(err).Msg("wrong request")
Expand Down
12 changes: 10 additions & 2 deletions pkg/micro/ocdav/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ type Options struct {
Context context.Context
// Metrics *metrics.Metrics
// Flags []cli.Flag
Name string
JWTSecret string
Name string
JWTSecret string
TransferSecret string

FavoriteManager favorite.Manager
GatewaySelector pool.Selectable[gateway.GatewayAPIClient]
Expand Down Expand Up @@ -109,6 +110,13 @@ func JWTSecret(s string) Option {
}
}

// TransferSecret provides a function to set the transfer secret option.
func TransferSecret(s string) Option {
return func(o *Options) {
o.config.TransferSharedSecret = s
}
}

// MachineAuthAPIKey provides a function to set the machine auth api key option.
func MachineAuthAPIKey(s string) Option {
return func(o *Options) {
Expand Down