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

OCM: support bearer token access and other refactoring #4670

Merged
merged 13 commits into from
Jul 30, 2024
8 changes: 8 additions & 0 deletions changelog/unreleased/ocm-access.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Enhancement: ocm: support bearer token access

This PR adds support for accessing remote OCM 1.1 shares via bearer token,
as opposed to having the shared secret in the URL only.
In addition, the OCM client package is now part of the OCMD server package,
and the Discover methods have been all consolidated in one place.

https://github.com/cs3org/reva/pull/4670
7 changes: 3 additions & 4 deletions examples/cernbox/cernbox.toml
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ webapp_template = "{{ vars.external_reva_endpoint }}/external/sciencemesh/{{.Tok
file = "{{ vars.ocmshares_json_file }}"

[grpc.services.ocmproviderauthorizer]
driver = "json"
driver = "open" # pure OCM, all remote shares are accepted
#driver = "json" # to enable sciencemesh

[grpc.services.ocmproviderauthorizer.drivers.json]
# this is used by the docker-based test deployment, not in production
Expand Down Expand Up @@ -279,7 +280,7 @@ sender_mail = "sciencemesh@{{ vars.provider_domain }}"
smtp_server = "smtp.{{ vars.provider_domain }}"
smtp_port = 25

[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
address = ":443"
ocm_prefix = "ocm"
provider = "Reva for CERNBox"
Expand Down Expand Up @@ -392,8 +393,6 @@ insecure = true
[http.services.prometheus]
address = ":443"

[http.services.sysinfo]

#[http.services.ui]
#address = ":443"

Expand Down
2 changes: 1 addition & 1 deletion examples/ocm/server-1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ driver = "ocmreceived"
address = "0.0.0.0:8080"
expose_recipient_display_name = true

[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
ocm_prefix = "ocm"
provider = "reva@cern"
endpoint = "http://localhost:{{ http.services.ocm.address.port }}"
Expand Down
2 changes: 1 addition & 1 deletion examples/ocm/server-2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ driver = "ocmreceived"
address = "0.0.0.0:80"
expose_recipient_display_name = true

[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
ocm_prefix = "ocm"
provider = "reva@cesnet"
endpoint = "http://localhost:{{ http.services.ocm.address.port }}"
Expand Down
4 changes: 1 addition & 3 deletions examples/sciencemesh/sciencemesh.toml
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ sender_mail = "sciencemesh@{{ vars.provider_domain }}"
smtp_server = "smtp.{{ vars.provider_domain }}"
smtp_port = 25

[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
address = ":443"
ocm_prefix = "ocm"
provider = "Reva for ownCloud/Nextcloud"
Expand Down Expand Up @@ -284,7 +284,5 @@ metrics_data_driver_type = "json"
metrics_data_location = "/etc/revad/metrics.json"
metrics_record_interval = 5000

[http.services.sysinfo]

[http.middlewares.cors]
[http.middlewares.log]
2 changes: 1 addition & 1 deletion examples/standalone/standalone.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
[http.services.dataprovider]
[http.services.prometheus]
[http.services.ocm]
[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
[http.services.ocdav]
[http.services.ocs]
2 changes: 1 addition & 1 deletion examples/storage-references/gateway.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ app_url = "https://your-collabora-server.org:9980"
[http.services.datagateway]
[http.services.prometheus]
[http.services.ocm]
[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
[http.services.ocdav]
[http.services.ocs]

Expand Down
2 changes: 1 addition & 1 deletion examples/two-server-setup/gateway-1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ address = "0.0.0.0:19001"
[http.services.datagateway]
[http.services.prometheus]
[http.services.ocm]
[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
provider = "Reva-Server-1"
endpoint = "http://localhost:19001"
enable_webapp = true
Expand Down
2 changes: 1 addition & 1 deletion examples/two-server-setup/gateway-2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ address = "0.0.0.0:29001"
[http.services.datagateway]
[http.services.prometheus]
[http.services.ocm]
[http.services.ocmprovider]
[http.services.wellknown.ocmprovider]
provider = "Reva-Server-2"
endpoint = "http://localhost:29001"
enable_webapp = true
Expand Down
4 changes: 3 additions & 1 deletion internal/grpc/services/ocmcore/ocmcore.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package ocmcore

// This package implements the core OCM API for receiving external shares from remote EFSS systems.

import (
"context"
"fmt"
Expand Down Expand Up @@ -102,7 +104,7 @@ func (s *service) UnprotectedEndpoints() []string {
return []string{"/cs3.ocm.core.v1beta1.OcmCoreAPI/CreateOCMCoreShare"}
}

// CreateOCMCoreShare is called when an OCM request comes into this reva instance from.
// CreateOCMCoreShare is called when a remote OCM request comes into this reva instance.
func (s *service) CreateOCMCoreShare(ctx context.Context, req *ocmcore.CreateOCMCoreShareRequest) (*ocmcore.CreateOCMCoreShareResponse, error) {
if req.ShareType != ocm.ShareType_SHARE_TYPE_USER {
return nil, errtypes.NotSupported("share type not supported")
Expand Down
23 changes: 10 additions & 13 deletions internal/grpc/services/ocminvitemanager/ocminvitemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import (
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/internal/http/services/opencloudmesh/ocmd"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/ocm/client"
"github.com/cs3org/reva/pkg/ocm/invite"
"github.com/cs3org/reva/pkg/ocm/invite/repository/registry"
"github.com/cs3org/reva/pkg/plugin"
Expand Down Expand Up @@ -66,7 +66,7 @@ type config struct {
type service struct {
conf *config
repo invite.Repository
ocmClient *client.OCMClient
ocmClient *ocmd.OCMClient
}

func (c *config) ApplyDefaults() {
Expand Down Expand Up @@ -110,12 +110,9 @@ func New(ctx context.Context, m map[string]interface{}) (rgrpc.Service, error) {
}

service := &service{
conf: &c,
repo: repo,
ocmClient: client.New(&client.Config{
Timeout: time.Duration(c.OCMClientTimeout) * time.Second,
Insecure: c.OCMClientInsecure,
}),
conf: &c,
repo: repo,
ocmClient: ocmd.NewClient(time.Duration(c.OCMClientTimeout)*time.Second, c.OCMClientInsecure),
}
return service, nil
}
Expand Down Expand Up @@ -166,7 +163,7 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite
return nil, err
}

remoteUser, err := s.ocmClient.InviteAccepted(ctx, ocmEndpoint, &client.InviteAcceptedRequest{
remoteUser, err := s.ocmClient.InviteAccepted(ctx, ocmEndpoint, &ocmd.InviteAcceptedRequest{
Token: req.InviteToken.GetToken(),
RecipientProvider: s.conf.ProviderDomain,
UserID: user.GetId().GetOpaqueId(),
Expand All @@ -175,19 +172,19 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite
})
if err != nil {
switch {
case errors.Is(err, client.ErrTokenInvalid):
case errors.Is(err, ocmd.ErrTokenInvalid):
return &invitepb.ForwardInviteResponse{
Status: status.NewInvalid(ctx, "token not valid"),
}, nil
case errors.Is(err, client.ErrTokenNotFound):
case errors.Is(err, ocmd.ErrTokenNotFound):
return &invitepb.ForwardInviteResponse{
Status: status.NewNotFound(ctx, "token not found"),
}, nil
case errors.Is(err, client.ErrUserAlreadyAccepted):
case errors.Is(err, ocmd.ErrUserAlreadyAccepted):
return &invitepb.ForwardInviteResponse{
Status: status.NewAlreadyExists(ctx, err, err.Error()),
}, nil
case errors.Is(err, client.ErrServiceNotTrusted):
case errors.Is(err, ocmd.ErrServiceNotTrusted):
return &invitepb.ForwardInviteResponse{
Status: status.NewPermissionDenied(ctx, err, err.Error()),
}, nil
Expand Down
40 changes: 18 additions & 22 deletions internal/grpc/services/ocmshareprovider/ocmshareprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

package ocmshareprovider

// This package implements the OCM client API: it allows shares created on this Reva instance
// to be sent to a remote EFSS system via OCM.

import (
"context"
"fmt"
Expand All @@ -38,7 +41,6 @@ import (

"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/ocm/client"
"github.com/cs3org/reva/pkg/ocm/share"
"github.com/cs3org/reva/pkg/ocm/share/repository/registry"
"github.com/cs3org/reva/pkg/plugin"
Expand Down Expand Up @@ -70,13 +72,13 @@ type config struct {
GatewaySVC string `mapstructure:"gatewaysvc" validate:"required"`
ProviderDomain string `docs:"The same domain registered in the provider authorizer" mapstructure:"provider_domain" validate:"required"`
WebDAVEndpoint string `mapstructure:"webdav_endpoint" validate:"required"`
WebappTemplate string `mapstructure:"webapp_template"`
WebappTemplate string `mapstructure:"webapp_template" validate:"required"`
}

type service struct {
conf *config
repo share.Repository
client *client.OCMClient
client *ocmd.OCMClient
gateway gateway.GatewayAPIClient
webappTmpl *template.Template
walker walker.Walker
Expand All @@ -89,9 +91,6 @@ func (c *config) ApplyDefaults() {
if c.ClientTimeout == 0 {
c.ClientTimeout = 10
}
if c.WebappTemplate == "" {
c.WebappTemplate = "https://cernbox.cern.ch/external/sciencemesh/{{.Token}}{relative-path-to-shared-resource}"
}

c.GatewaySVC = sharedconf.GetGatewaySVC(c.GatewaySVC)
}
Expand Down Expand Up @@ -119,11 +118,6 @@ func New(ctx context.Context, m map[string]interface{}) (rgrpc.Service, error) {
return nil, err
}

client := client.New(&client.Config{
Timeout: time.Duration(c.ClientTimeout) * time.Second,
Insecure: c.ClientInsecure,
})

gateway, err := pool.GetGatewayServiceClient(pool.Endpoint(c.GatewaySVC))
if err != nil {
return nil, err
Expand All @@ -135,10 +129,11 @@ func New(ctx context.Context, m map[string]interface{}) (rgrpc.Service, error) {
}
walker := walker.NewWalker(gateway)

ocmcl := ocmd.NewClient(time.Duration(c.ClientTimeout)*time.Second, c.ClientInsecure)
service := &service{
conf: &c,
repo: repo,
client: client,
client: ocmcl,
gateway: gateway,
webappTmpl: tpl,
walker: walker,
Expand Down Expand Up @@ -178,13 +173,14 @@ func getResourceType(info *providerpb.ResourceInfo) string {
return "unknown"
}

func (s *service) webdavURL(ctx context.Context, share *ocm.Share) string {
// the url is in the form of https://cernbox.cern.ch/remote.php/dav/ocm/token
p, _ := url.JoinPath(s.conf.WebDAVEndpoint, "/remote.php/dav/ocm", share.Token)
func (s *service) webdavURL(share *ocm.Share) string {
// the url is expected to be in the form https://ourserver/remote.php/dav/ocm/{ShareId}, see c.WebdavRoot in ocmprovider.go
// TODO(lopresti) take the root from http.services.wellknown.ocmprovider's config
p, _ := url.JoinPath(s.conf.WebDAVEndpoint, "/remote.php/dav/ocm", share.Id.OpaqueId)
return p
}

func (s *service) getWebdavProtocol(ctx context.Context, share *ocm.Share, m *ocm.AccessMethod_WebdavOptions) *ocmd.WebDAV {
func (s *service) getWebdavProtocol(share *ocm.Share, m *ocm.AccessMethod_WebdavOptions) *ocmd.WebDAV {
var perms []string
if m.WebdavOptions.Permissions.InitiateFileDownload {
perms = append(perms, "read")
Expand All @@ -195,7 +191,7 @@ func (s *service) getWebdavProtocol(ctx context.Context, share *ocm.Share, m *oc

return &ocmd.WebDAV{
Permissions: perms,
URL: s.webdavURL(ctx, share),
URL: s.webdavURL(share),
SharedSecret: share.Token,
}
}
Expand Down Expand Up @@ -233,7 +229,7 @@ func (s *service) getDataTransferProtocol(ctx context.Context, share *ocm.Share)
panic(err)
}
return &ocmd.Datatx{
SourceURI: s.webdavURL(ctx, share),
SourceURI: s.webdavURL(share),
Size: size,
}
}
Expand All @@ -248,7 +244,7 @@ func (s *service) getProtocols(ctx context.Context, share *ocm.Share) ocmd.Proto
for _, m := range share.AccessMethods {
switch t := m.Term.(type) {
case *ocm.AccessMethod_WebdavOptions:
p = append(p, s.getWebdavProtocol(ctx, share, t))
p = append(p, s.getWebdavProtocol(share, t))
case *ocm.AccessMethod_WebappOptions:
p = append(p, s.getWebappProtocol(share))
case *ocm.AccessMethod_TransferOptions:
Expand Down Expand Up @@ -323,7 +319,7 @@ func (s *service) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareReq
}, nil
}

newShareReq := &client.NewShareRequest{
newShareReq := &ocmd.NewShareRequest{
ShareWith: formatOCMUser(req.Grantee.GetUserId()),
Name: ocmshare.Name,
ProviderID: ocmshare.Id.OpaqueId,
Expand All @@ -348,11 +344,11 @@ func (s *service) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareReq
newShareRes, err := s.client.NewShare(ctx, ocmEndpoint, newShareReq)
if err != nil {
switch {
case errors.Is(err, client.ErrInvalidParameters):
case errors.Is(err, ocmd.ErrInvalidParameters):
return &ocm.CreateOCMShareResponse{
Status: status.NewInvalidArg(ctx, err.Error()),
}, nil
case errors.Is(err, client.ErrServiceNotTrusted):
case errors.Is(err, ocmd.ErrServiceNotTrusted):
return &ocm.CreateOCMShareResponse{
Status: status.NewInvalidArg(ctx, err.Error()),
}, nil
Expand Down
2 changes: 1 addition & 1 deletion internal/http/services/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ import (
_ "github.com/cs3org/reva/internal/http/services/helloworld"
_ "github.com/cs3org/reva/internal/http/services/metrics"
_ "github.com/cs3org/reva/internal/http/services/opencloudmesh/ocmd"
_ "github.com/cs3org/reva/internal/http/services/opencloudmesh/ocmprovider"
_ "github.com/cs3org/reva/internal/http/services/owncloud/ocdav"
_ "github.com/cs3org/reva/internal/http/services/owncloud/ocs"
_ "github.com/cs3org/reva/internal/http/services/pingpong"
_ "github.com/cs3org/reva/internal/http/services/plugins"
_ "github.com/cs3org/reva/internal/http/services/pprof"
_ "github.com/cs3org/reva/internal/http/services/preferences"
_ "github.com/cs3org/reva/internal/http/services/prometheus"
_ "github.com/cs3org/reva/internal/http/services/wellknown"
// Add your own service here.
)
Loading
Loading