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

Functionality to map home directory to different storage providers #1142

Merged
merged 4 commits into from
Sep 18, 2020
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
7 changes: 7 additions & 0 deletions changelog/unreleased/home-sp-mapping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Functionality to map home directory to different storage providers

We hardcode the home path for all users to /home. This forbids redirecting
requests for different users to multiple storage providers. This PR provides the
option to map the home directories of different users using user attributes.

https://github.com/cs3org/reva/pull/1142
25 changes: 22 additions & 3 deletions internal/grpc/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ func NewUnary(m map[string]interface{}, unprotected []string) (grpc.UnaryServerI
if utils.Skip(info.FullMethod, unprotected) {
span.AddAttributes(trace.BoolAttribute("auth_enabled", false))
log.Debug().Str("method", info.FullMethod).Msg("skipping auth")

// If a token is present, set it anyway, as we might need the user info
// to decide the storage provider.
tkn, ok := token.ContextGetToken(ctx)
if ok {
u, err := tokenManager.DismantleToken(ctx, tkn)
if err == nil {
ctx = user.ContextSetUser(ctx, u)
}
}
return handler(ctx, req)
}

Expand Down Expand Up @@ -111,7 +121,6 @@ func NewUnary(m map[string]interface{}, unprotected []string) (grpc.UnaryServerI
span.AddAttributes(trace.StringAttribute("user", u.String()), trace.StringAttribute("token", tkn))

ctx = user.ContextSetUser(ctx, u)
ctx = token.ContextSetToken(ctx, tkn)
return handler(ctx, req)
}
return interceptor, nil
Expand Down Expand Up @@ -145,6 +154,18 @@ func NewStream(m map[string]interface{}, unprotected []string) (grpc.StreamServe

if utils.Skip(info.FullMethod, unprotected) {
log.Debug().Str("method", info.FullMethod).Msg("skipping auth")

// If a token is present, set it anyway, as we might need the user info
// to decide the storage provider.
tkn, ok := token.ContextGetToken(ctx)
if ok {
u, err := tokenManager.DismantleToken(ctx, tkn)
if err == nil {
ctx = user.ContextSetUser(ctx, u)
ss = newWrappedServerStream(ctx, ss)
}
}

return handler(srv, ss)
}

Expand All @@ -170,8 +191,6 @@ func NewStream(m map[string]interface{}, unprotected []string) (grpc.StreamServe

// store user and core access token in context.
ctx = user.ContextSetUser(ctx, u)
ctx = token.ContextSetToken(ctx, tkn)

wrapped := newWrappedServerStream(ctx, ss)
return handler(srv, wrapped)
}
Expand Down
5 changes: 3 additions & 2 deletions internal/grpc/services/gateway/authprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
tokenpkg "github.com/cs3org/reva/pkg/token"
userpkg "github.com/cs3org/reva/pkg/user"
"github.com/pkg/errors"
"google.golang.org/grpc/metadata"
)
Expand Down Expand Up @@ -108,11 +109,11 @@ func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest
// we need to pass the token to authenticate the CreateHome request.
// TODO(labkode): appending to existing context will not pass the token.
ctx = tokenpkg.ContextSetToken(ctx, token)
ctx = userpkg.ContextSetUser(ctx, user)
ctx = metadata.AppendToOutgoingContext(ctx, tokenpkg.TokenHeader, token) // TODO(jfd): hardcoded metadata key. use PerRPCCredentials?

// create home directory
createHomeReq := &storageprovider.CreateHomeRequest{}
createHomeRes, err := s.CreateHome(ctx, createHomeReq)
createHomeRes, err := s.CreateHome(ctx, &storageprovider.CreateHomeRequest{})
if err != nil {
log.Err(err).Msg("error calling CreateHome")
return &gateway.AuthenticateResponse{
Expand Down
1 change: 1 addition & 0 deletions internal/grpc/services/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type config struct {
TokenManager string `mapstructure:"token_manager"`
// ShareFolder is the location where to create shares in the recipient's storage provider.
ShareFolder string `mapstructure:"share_folder"`
HomeMapping string `mapstructure:"home_mapping"`
TokenManagers map[string]map[string]interface{} `mapstructure:"token_managers"`
}

Expand Down
41 changes: 33 additions & 8 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import (
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/storage/utils/templates"
"github.com/cs3org/reva/pkg/user"
"github.com/dgrijalva/jwt-go"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -1795,32 +1797,55 @@ func (s *svc) getStorageProviderClient(_ context.Context, p *registry.ProviderIn
}

func (s *svc) findProvider(ctx context.Context, ref *provider.Reference) (*registry.ProviderInfo, error) {
c, err := pool.GetStorageRegistryClient(s.c.StorageRegistryEndpoint)
home, err := s.GetHome(ctx, &provider.GetHomeRequest{})
if err != nil {
err = errors.Wrap(err, "gateway: error getting storage registry client")
return nil, err
}
if strings.HasPrefix(ref.GetPath(), home.Path) && s.c.HomeMapping != "" {
if u, ok := user.ContextGetUser(ctx); ok {
layout := templates.WithUser(u, s.c.HomeMapping)
newRef := &provider.Reference{
Spec: &provider.Reference_Path{
Path: path.Join(layout, strings.TrimPrefix(ref.GetPath(), home.Path)),
},
}
res, err := s.getStorageProvider(ctx, newRef)
if err != nil {
// if we get a NotFound error, default to the original reference
if _, ok := err.(errtypes.IsNotFound); !ok {
return nil, err
}
} else {
return res, nil
}
}
}
return s.getStorageProvider(ctx, ref)
}

func (s *svc) getStorageProvider(ctx context.Context, ref *provider.Reference) (*registry.ProviderInfo, error) {
c, err := pool.GetStorageRegistryClient(s.c.StorageRegistryEndpoint)
if err != nil {
return nil, errors.Wrap(err, "gateway: error getting storage registry client")
}

res, err := c.GetStorageProvider(ctx, &registry.GetStorageProviderRequest{
Ref: ref,
})

if err != nil {
err = errors.Wrap(err, "gateway: error calling GetStorageProvider")
return nil, err
return nil, errors.Wrap(err, "gateway: error calling GetStorageProvider")
}

if res.Status.Code != rpc.Code_CODE_OK {
if res.Status.Code == rpc.Code_CODE_NOT_FOUND {
return nil, errtypes.NotFound("gateway: storage provider not found for reference:" + ref.String())
}
err := status.NewErrorFromCode(res.Status.Code, "gateway")
return nil, err
return nil, status.NewErrorFromCode(res.Status.Code, "gateway")
}

if res.Provider == nil {
err := errors.New("gateway: provider is nil")
return nil, err
return nil, errors.New("gateway: provider is nil")
}

return res.Provider, nil
Expand Down
7 changes: 2 additions & 5 deletions internal/grpc/services/gateway/usershareprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,7 @@ func (s *svc) createReference(ctx context.Context, resourceID *provider.Resource
return status.NewInternal(ctx, err, "error updating received share"), nil
}

fileInfo := statRes.Info

homeReq := &provider.GetHomeRequest{}
homeRes, err := s.GetHome(ctx, homeReq)
homeRes, err := s.GetHome(ctx, &provider.GetHomeRequest{})
if err != nil {
err := errors.Wrap(err, "gateway: error calling GetHome")
return status.NewInternal(ctx, err, "error updating received share"), nil
Expand All @@ -400,7 +397,7 @@ func (s *svc) createReference(ctx context.Context, resourceID *provider.Resource
// It is the responsibility of the gateway to resolve these references and merge the response back
// from the main request.
// TODO(labkode): the name of the share should be the filename it points to by default.
refPath := path.Join(homeRes.Path, s.c.ShareFolder, path.Base(fileInfo.Path))
refPath := path.Join(homeRes.Path, s.c.ShareFolder, path.Base(statRes.Info.Path))
log.Info().Msg("mount path will be:" + refPath)

createRefReq := &provider.CreateReferenceRequest{
Expand Down
5 changes: 2 additions & 3 deletions internal/http/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err
log.Debug().Err(err).Msg("error retrieving credentials")
}
if creds != nil {
log.Debug().Msgf("credentials obtained from credential strategy: %+v", creds)

log.Debug().Msgf("credentials obtained from credential strategy: type: %s, client_id: %s", creds.Type, creds.ClientID)
break
}
}
Expand All @@ -191,7 +190,7 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err
ClientSecret: creds.ClientSecret,
}

log.Debug().Msgf("AuthenticateRequest: %+v against %s", req, conf.GatewaySvc)
log.Debug().Msgf("AuthenticateRequest: type: %s, client_id: %s against %s", req.Type, req.ClientId, conf.GatewaySvc)

client, err := pool.GetGatewayServiceClient(conf.GatewaySvc)
if err != nil {
Expand Down