Skip to content
Open
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
17 changes: 16 additions & 1 deletion internal/grpc/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ package auth

import (
"context"
"slices"
"sync"
"time"

"github.com/bluele/gcache"
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/mitchellh/mapstructure"
"github.com/owncloud/reva/v2/pkg/appctx"
"github.com/owncloud/reva/v2/pkg/auth/scope"
ctxpkg "github.com/owncloud/reva/v2/pkg/ctx"
Expand All @@ -36,12 +38,12 @@ import (
"github.com/owncloud/reva/v2/pkg/token"
tokenmgr "github.com/owncloud/reva/v2/pkg/token/manager/registry"
"github.com/owncloud/reva/v2/pkg/utils"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)

Expand All @@ -62,6 +64,7 @@ type config struct {
GatewayAddr string `mapstructure:"gateway_addr"`
UserGroupsCacheSize int `mapstructure:"usergroups_cache_size"`
ScopeExpansionCacheSize int `mapstructure:"scope_expansion_cache_size"`
MFAEnabled bool `mapstructure:"mfa_enabled"`
}

func parseConfig(m map[string]interface{}) (*config, error) {
Expand Down Expand Up @@ -154,6 +157,12 @@ func NewUnary(m map[string]interface{}, unprotected []string, tp trace.TracerPro
// store user and scopes in context
ctx = ctxpkg.ContextSetUser(ctx, u)
ctx = ctxpkg.ContextSetScopes(ctx, tokenScope)
if conf.MFAEnabled {
if mfav := metadata.ValueFromIncomingContext(ctx, ctxpkg.MFAOutgoingHeader); !slices.Contains(mfav, "true") {
log.Warn().Str("user_id", u.Id.OpaqueId).Strs("mfa_values", mfav).Msg("MFA is required")
return mfaResponse(ctx, req, info)
}
}
Comment on lines +160 to +165
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be handled by the service. Some services might allow access to some parts to anyone while accessing to other parts might require additional privileges.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, but it is out of the vault storage scope in my opinion.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can leave it for now... all the services should have the MFA disabled except the vault, so it should be fine in the short term. Maybe a TODO comment as a reminder to move this piece is good enough.


span.SetAttributes(semconv.EnduserIDKey.String(u.Id.OpaqueId))

Expand Down Expand Up @@ -243,6 +252,12 @@ func NewStream(m map[string]interface{}, unprotected []string, tp trace.TracerPr
// store user and scopes in context
ctx = ctxpkg.ContextSetUser(ctx, u)
ctx = ctxpkg.ContextSetScopes(ctx, tokenScope)
if conf.MFAEnabled {
if mfav := metadata.ValueFromIncomingContext(ctx, ctxpkg.MFAOutgoingHeader); !slices.Contains(mfav, "true") {
log.Warn().Str("user_id", u.Id.OpaqueId).Strs("mfa_values", mfav).Msg("MFA is required")
return status.Errorf(codes.PermissionDenied, "MFA required to access vault storage")
}
}
wrapped := newWrappedServerStream(ctx, ss)

span.SetAttributes(semconv.EnduserIDKey.String(u.Id.OpaqueId))
Expand Down
73 changes: 73 additions & 0 deletions internal/grpc/interceptors/auth/mfa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package auth

import (
Comment on lines +1 to +3
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new file is missing the standard Apache license header that other files in this package include (e.g. internal/grpc/interceptors/auth/scope.go:1-17). Please add the repository’s usual header block at the top for consistency/compliance.

Copilot uses AI. Check for mistakes.
"context"

provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
rstatus "github.com/owncloud/reva/v2/pkg/rgrpc/status"
"github.com/rs/zerolog/log"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
grpcstatus "google.golang.org/grpc/status"
)

func mfaResponse(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo) (interface{}, error) {
const msg = "MFA required to access vault storage"
switch req.(type) {
case *provider.StatRequest:
return &provider.StatResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.ListContainerRequest:
return &provider.ListContainerResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.GetPathRequest:
return &provider.GetPathResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.GetQuotaRequest:
return &provider.GetQuotaResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.InitiateFileDownloadRequest:
return &provider.InitiateFileDownloadResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.InitiateFileUploadRequest:
return &provider.InitiateFileUploadResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.CreateContainerRequest:
return &provider.CreateContainerResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.TouchFileRequest:
return &provider.TouchFileResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.DeleteRequest:
return &provider.DeleteResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.MoveRequest:
return &provider.MoveResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.CreateHomeRequest:
return &provider.CreateHomeResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.AddGrantRequest:
return &provider.AddGrantResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.RemoveGrantRequest:
return &provider.RemoveGrantResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.UpdateGrantRequest:
return &provider.UpdateGrantResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.ListGrantsRequest:
return &provider.ListGrantsResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.ListFileVersionsRequest:
return &provider.ListFileVersionsResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.RestoreFileVersionRequest:
return &provider.RestoreFileVersionResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.ListRecycleRequest:
return &provider.ListRecycleResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.RestoreRecycleItemRequest:
return &provider.RestoreRecycleItemResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.PurgeRecycleRequest:
return &provider.PurgeRecycleResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.SetArbitraryMetadataRequest:
return &provider.SetArbitraryMetadataResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.UnsetArbitraryMetadataRequest:
return &provider.UnsetArbitraryMetadataResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.ListStorageSpacesRequest:
return &provider.ListStorageSpacesResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.CreateStorageSpaceRequest:
return &provider.CreateStorageSpaceResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.UpdateStorageSpaceRequest:
return &provider.UpdateStorageSpaceResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
case *provider.DeleteStorageSpaceRequest:
return &provider.DeleteStorageSpaceResponse{Status: rstatus.NewPermissionDenied(ctx, nil, msg)}, nil
default:
log.Debug().Str("method", info.FullMethod).Msg("mfa: blocking unknown request type")
return nil, grpcstatus.Errorf(codes.PermissionDenied, "mfa: %s: %T", msg, req)
}
}
17 changes: 17 additions & 0 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ func (s *svc) CreateHome(ctx context.Context, req *provider.CreateHomeRequest) (
},
}
}

// pass storage_id to the storage provider to handle vault storage id
if storageId := utils.ReadPlainFromOpaque(req.GetOpaque(), "storage_id"); storageId != "" {
createReq.Opaque = utils.AppendPlainToOpaque(createReq.Opaque, "storage_id", storageId)
}

res, err := s.CreateStorageSpace(ctx, createReq)
if err != nil {
return &provider.CreateHomeResponse{
Expand Down Expand Up @@ -170,6 +176,11 @@ func (s *svc) CreateStorageSpace(ctx context.Context, req *provider.CreateStorag
}
}

if storageId := utils.ReadPlainFromOpaque(req.GetOpaque(), "storage_id"); storageId != "" {
space.Root = &provider.ResourceId{StorageId: storageId}
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "storage_id", storageId)
}

srClient, err := s.getStorageRegistryClient(ctx, s.c.StorageRegistryEndpoint)
if err != nil {
return &provider.CreateStorageSpaceResponse{
Expand Down Expand Up @@ -247,6 +258,7 @@ func (s *svc) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSp
filters["path"] = path
}

hasFileIdFilter := false
for _, f := range req.Filters {
switch f.Type {
case provider.ListStorageSpacesRequest_Filter_TYPE_ID:
Expand All @@ -255,6 +267,7 @@ func (s *svc) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSp
continue
}
filters["storage_id"], filters["space_id"], filters["opaque_id"] = sid, spid, oid
hasFileIdFilter = true
case provider.ListStorageSpacesRequest_Filter_TYPE_OWNER:
filters["owner_idp"] = f.GetOwner().GetIdp()
filters["owner_id"] = f.GetOwner().GetOpaqueId()
Expand All @@ -270,6 +283,10 @@ func (s *svc) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSp
}
}

if !hasFileIdFilter && utils.ReadPlainFromOpaque(req.Opaque, "storage_id") != "" {
filters["storage_id"] = utils.ReadPlainFromOpaque(req.Opaque, "storage_id")
}

c, err := s.getStorageRegistryClient(ctx, s.c.StorageRegistryEndpoint)
if err != nil {
return &provider.ListStorageSpacesResponse{
Expand Down
15 changes: 11 additions & 4 deletions internal/grpc/services/gateway/storageprovidercache.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
ctxpkg "github.com/owncloud/reva/v2/pkg/ctx"
sdk "github.com/owncloud/reva/v2/pkg/sdk/common"
"github.com/owncloud/reva/v2/pkg/storage/cache"
"github.com/owncloud/reva/v2/pkg/storagespace"
"github.com/owncloud/reva/v2/pkg/utils"
"github.com/pkg/errors"
"google.golang.org/grpc"
Expand All @@ -41,15 +41,22 @@ type cachedRegistryClient struct {
}

func (c *cachedRegistryClient) ListStorageProviders(ctx context.Context, in *registry.ListStorageProvidersRequest, opts ...grpc.CallOption) (*registry.ListStorageProvidersResponse, error) {

spaceID := sdk.DecodeOpaqueMap(in.Opaque)["space_id"]
spaceID := utils.ReadPlainFromOpaque(in.GetOpaque(), "space_id")
resourceID := spaceID
if storageID := utils.ReadPlainFromOpaque(in.GetOpaque(), "storage_id"); storageID != "" {
if spaceID != "" {
resourceID = storagespace.FormatStorageID(storageID, spaceID)
} else {
resourceID = storageID
}
}
Comment thread
2403905 marked this conversation as resolved.

u, ok := ctxpkg.ContextGetUser(ctx)
if !ok {
return nil, errors.New("user not found in context")
}

key := c.cache.GetKey(u.GetId(), spaceID)
key := c.cache.GetKey(u.GetId(), resourceID)
if key != "" {
s := &registry.ListStorageProvidersResponse{}
if err := c.cache.PullFromCache(key, s); err == nil {
Expand Down
3 changes: 2 additions & 1 deletion internal/grpc/services/storageprovider/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/mitchellh/mapstructure"
"github.com/owncloud/reva/v2/pkg/appctx"
"github.com/owncloud/reva/v2/pkg/conversions"
ctxpkg "github.com/owncloud/reva/v2/pkg/ctx"
Expand All @@ -47,7 +48,6 @@ import (
"github.com/owncloud/reva/v2/pkg/storage/fs/registry"
"github.com/owncloud/reva/v2/pkg/storagespace"
"github.com/owncloud/reva/v2/pkg/utils"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/attribute"
Expand Down Expand Up @@ -787,6 +787,7 @@ func (s *Service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
s.addMissingStorageProviderID(md.GetId(), nil)
s.addMissingStorageProviderID(md.GetParentId(), nil)
s.addMissingStorageProviderID(md.GetSpace().GetRoot(), nil)
s.addMissingStorageProviderID(md.GetSpace().GetRootInfo().GetId(), nil)

return &provider.StatResponse{
Status: status.NewOK(ctx),
Expand Down
8 changes: 8 additions & 0 deletions internal/http/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,14 @@ func ctxWithUserInfo(ctx context.Context, r *http.Request, user *userpb.User, to
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.UserAgentHeader, r.UserAgent())
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.InitiatorHeader, initiatorid)
ctx = ctxpkg.ContextSetScopes(ctx, tokenScope)

// Forward MFA status from the proxy's HTTP header into outgoing gRPC metadata.
// Using the autoprop-prefixed key causes the metadata interceptor to propagate
// it automatically at every subsequent gRPC hop.
if mfaVal := r.Header.Get(ctxpkg.MFAHeader); mfaVal != "" {
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.MFAOutgoingHeader, mfaVal)
}

return ctx
}

Expand Down
10 changes: 9 additions & 1 deletion internal/http/services/archiver/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"time"

"regexp"
Expand Down Expand Up @@ -204,8 +205,15 @@ func (s *svc) writeHTTPError(rw http.ResponseWriter, err error) {
s.log.Error().Msg(err.Error())

switch err.(type) {
case errtypes.NotFound, errtypes.PermissionDenied:
case errtypes.NotFound:
rw.WriteHeader(http.StatusNotFound)
case errtypes.PermissionDenied:
if strings.Contains(err.Error(), "MFA required") {
rw.Header().Set("X-Ocis-Mfa-Required", "true")
rw.WriteHeader(http.StatusForbidden)
} else {
rw.WriteHeader(http.StatusNotFound)
}
Comment on lines +210 to +216
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detecting the MFA condition via strings.Contains(err.Error(), "MFA required") is brittle (message wording changes will silently break the behavior). Consider using a dedicated error type/sentinel (e.g., errors.Is), or checking a structured status/detail that the MFA interceptor can set, so this remains stable across refactors/localization.

Copilot uses AI. Check for mistakes.
case manager.ErrMaxSize, manager.ErrMaxFileCount:
rw.WriteHeader(http.StatusRequestEntityTooLarge)
case errtypes.BadRequest:
Expand Down
7 changes: 7 additions & 0 deletions internal/http/services/owncloud/ocdav/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,13 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, sele
}

func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, srcRef, dstRef *provider.Reference, log *zerolog.Logger, destInShareJail bool) *copy {
// restict copy from the vault
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment has a typo: "restict" → "restrict".

Suggested change
// restict copy from the vault
// restrict copy from the vault

Copilot uses AI. Check for mistakes.
if destinationIsNotAllowed(srcRef, dstRef) {
w.WriteHeader(http.StatusConflict)
b, err := errors.Marshal(http.StatusBadRequest, "destination is not allowed", "", "")
Comment on lines +558 to +559
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use the same error code, and StatusConflict doesn't seem a good one to use here. If there is anything else in place (HandleWebdavError might do things), we probably need some comment explaining why the errors are different.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the same pattern as in the Copy and Move functions, most of the errors are handled the same way.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to at least reference the original code so we know this piece has been copied, and where it has been copied from.
I'm pretty sure that later I'll see this code and think that it's a bug and make the change. The comment will help to double-check, and it will also help to know that there are multiple places with the same problem (if it's a problem)

errors.HandleWebdavError(log, w, b, err)
return nil
}
isChild, err := s.referenceIsChildOf(ctx, s.gatewaySelector, dstRef, srcRef)
if err != nil {
switch err.(type) {
Expand Down
7 changes: 7 additions & 0 deletions internal/http/services/owncloud/ocdav/move.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ func (s *svc) handleSpacesMove(w http.ResponseWriter, r *http.Request, srcSpaceI
}

func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Request, src, dst *provider.Reference, log zerolog.Logger) {
// restrict move from the vault
if destinationIsNotAllowed(src, dst) {
w.WriteHeader(http.StatusConflict)
b, err := errors.Marshal(http.StatusBadRequest, "destination is not allowed", "", "")
errors.HandleWebdavError(&log, w, b, err)
return
}
isChild, err := s.referenceIsChildOf(ctx, s.gatewaySelector, dst, src)
if err != nil {
switch err.(type) {
Expand Down
12 changes: 12 additions & 0 deletions internal/http/services/owncloud/ocdav/ocdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ func (s *svc) sspReferenceIsChildOf(ctx context.Context, selector pool.Selectabl
}

func (s *svc) referenceIsChildOf(ctx context.Context, selector pool.Selectable[gateway.GatewayAPIClient], child, parent *provider.Reference) (bool, error) {
if child.ResourceId.StorageId != parent.ResourceId.StorageId {
return false, nil // Not on the same storage -> not a child
}

if child.ResourceId.SpaceId != parent.ResourceId.SpaceId {
return false, nil // Not on the same storage -> not a child
}
Expand Down Expand Up @@ -414,3 +418,11 @@ func isBodyEmpty(r *http.Request) bool {
}
return true
}

func destinationIsNotAllowed(srcRef, dstRef *provider.Reference) bool {
if srcRef.GetResourceId().GetStorageId() == utils.VaultStorageProviderID &&
dstRef.GetResourceId().GetStorageId() != utils.VaultStorageProviderID {
return true
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *p
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting storage provider", err)
return
}

providerClient, err := h.getStorageProviderClient(p)
providerClient, err := pool.GetStorageProviderServiceClient(p.Address)
if err != nil {
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting storage provider client", err)
return
Expand Down Expand Up @@ -244,8 +243,7 @@ func (h *Handler) removeSpaceMember(w http.ResponseWriter, r *http.Request, spac
if ref.ResourceId.OpaqueId == "" {
ref.ResourceId.OpaqueId = ref.ResourceId.SpaceId
}

providerClient, err := h.getStorageProviderClient(prov)
providerClient, err := pool.GetStorageProviderServiceClient(prov.Address)
if err != nil {
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting storage provider client", err)
return
Expand Down Expand Up @@ -290,16 +288,6 @@ func (h *Handler) removeSpaceMember(w http.ResponseWriter, r *http.Request, spac
response.WriteOCSSuccess(w, r, nil)
}

func (h *Handler) getStorageProviderClient(p *registry.ProviderInfo) (provider.ProviderAPIClient, error) {
c, err := pool.GetStorageProviderServiceClient(p.Address)
if err != nil {
err = errors.Wrap(err, "shares spaces: error getting a storage provider client")
return nil, err
}

return c, nil
}

func (h *Handler) findProvider(ctx context.Context, ref *provider.Reference) (*registry.ProviderInfo, error) {
c, err := pool.GetStorageRegistryClient(h.storageRegistryAddr)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions pkg/auth/manager/oidc/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import (
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/juliangruber/go-intersect"
"github.com/mitchellh/mapstructure"
"github.com/owncloud/reva/v2/pkg/appctx"
"github.com/owncloud/reva/v2/pkg/auth"
"github.com/owncloud/reva/v2/pkg/auth/manager/registry"
Expand All @@ -41,8 +43,6 @@ import (
"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
"github.com/owncloud/reva/v2/pkg/rhttp"
"github.com/owncloud/reva/v2/pkg/sharedconf"
"github.com/juliangruber/go-intersect"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"golang.org/x/oauth2"
)
Expand Down
Loading
Loading