use the context as a scopes carrier
This commit is contained in:
-72955
File diff suppressed because it is too large
Load Diff
@@ -1228,12 +1228,16 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
|
|||||||
if !isPublicShare {
|
if !isPublicShare {
|
||||||
parentFolderURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetParentId()))
|
parentFolderURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetParentId()))
|
||||||
} else {
|
} else {
|
||||||
publicShare := &link.PublicShare{}
|
if scopes, ok := ctxpkg.ContextGetScopes(ctx); ok {
|
||||||
err := wopiContext.GetScopeByKeyPrefix("publicshare:", publicShare)
|
publicShare := &link.PublicShare{}
|
||||||
if err != nil {
|
if err := helpers.GetScopeByKeyPrefix(scopes, "publicshare:", publicShare); err == nil {
|
||||||
logger.Error().Err(err).Msg("CheckFileInfo: error getting public share scope")
|
parentFolderURL.Path = path.Join(ocisURL.Path, "s", publicShare.GetToken())
|
||||||
|
} else {
|
||||||
|
logger.Error().Err(err).Msg("CheckFileInfo: error getting public share scope")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Error().Err(err).Msg("CheckFileInfo: error getting scopes from the context")
|
||||||
}
|
}
|
||||||
parentFolderURL.Path = path.Join(ocisURL.Path, "s", publicShare.GetToken())
|
|
||||||
}
|
}
|
||||||
// fileinfo map
|
// fileinfo map
|
||||||
infoMap := map[string]interface{}{
|
infoMap := map[string]interface{}{
|
||||||
|
|||||||
@@ -10,12 +10,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
||||||
|
auth "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||||
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||||
|
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||||
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||||
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||||
|
"github.com/cs3org/reva/v2/pkg/utils"
|
||||||
cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
|
cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@@ -1806,6 +1809,109 @@ var _ = Describe("FileConnector", func() {
|
|||||||
Expect(response.Body.(*fileinfo.Collabora)).To(Equal(expectedFileInfo))
|
Expect(response.Body.(*fileinfo.Collabora)).To(Equal(expectedFileInfo))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("Stat success guests", func() {
|
||||||
|
ResourceId := &providerv1beta1.ResourceId{
|
||||||
|
StorageId: "storageid",
|
||||||
|
OpaqueId: "opaqueid",
|
||||||
|
SpaceId: "spaceid",
|
||||||
|
}
|
||||||
|
|
||||||
|
// add user's opaque to include public-share-role
|
||||||
|
u := &userv1beta1.User{}
|
||||||
|
u.Opaque = &typesv1beta1.Opaque{
|
||||||
|
Map: map[string]*typesv1beta1.OpaqueEntry{
|
||||||
|
"public-share-role": {
|
||||||
|
Decoder: "plain",
|
||||||
|
Value: []byte("viewer"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Create a new "scope share" to only expose the required fields `ResourceId` and `Token` to the scope.
|
||||||
|
scopeShare := &link.PublicShare{ResourceId: ResourceId, Token: "ABC123"}
|
||||||
|
val, err := utils.MarshalProtoV1ToJSON(scopeShare)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
scopes := map[string]*auth.Scope{
|
||||||
|
"publicshare:ABC123": {
|
||||||
|
Resource: &typesv1beta1.OpaqueEntry{
|
||||||
|
Decoder: "json",
|
||||||
|
Value: val,
|
||||||
|
},
|
||||||
|
Role: auth.Role(appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY), //
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// change view mode to view only
|
||||||
|
wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
||||||
|
|
||||||
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
||||||
|
ctx = ctxpkg.ContextSetUser(ctx, u)
|
||||||
|
ctx = ctxpkg.ContextSetScopes(ctx, scopes)
|
||||||
|
|
||||||
|
gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
|
||||||
|
Status: status.NewOK(ctx),
|
||||||
|
Info: &providerv1beta1.ResourceInfo{
|
||||||
|
Owner: &userv1beta1.UserId{
|
||||||
|
Idp: "customIdp",
|
||||||
|
OpaqueId: "aabbcc",
|
||||||
|
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
|
||||||
|
},
|
||||||
|
Size: uint64(998877),
|
||||||
|
Mtime: &typesv1beta1.Timestamp{
|
||||||
|
Seconds: uint64(16273849),
|
||||||
|
},
|
||||||
|
Path: "/path/to/test.txt",
|
||||||
|
Id: ResourceId,
|
||||||
|
ParentId: &providerv1beta1.ResourceId{
|
||||||
|
StorageId: "storageid",
|
||||||
|
OpaqueId: "parentopaqueid",
|
||||||
|
SpaceId: "spaceid",
|
||||||
|
},
|
||||||
|
// Other properties aren't used for now.
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
// change wopi app provider
|
||||||
|
cfg.App.Name = "OnlyOffice"
|
||||||
|
cfg.App.Product = "OnlyOffice"
|
||||||
|
|
||||||
|
expectedFileInfo := &fileinfo.OnlyOffice{
|
||||||
|
Version: "v162738490",
|
||||||
|
BaseFileName: "test.txt",
|
||||||
|
BreadcrumbDocName: "test.txt",
|
||||||
|
BreadcrumbFolderName: "/path/to",
|
||||||
|
BreadcrumbFolderURL: "https://ocis.example.prv/s/ABC123",
|
||||||
|
DisablePrint: true,
|
||||||
|
UserCanNotWriteRelative: false,
|
||||||
|
SupportsLocks: true,
|
||||||
|
SupportsUpdate: true,
|
||||||
|
SupportsRename: true,
|
||||||
|
IsAnonymousUser: true,
|
||||||
|
UserCanRename: false,
|
||||||
|
UserCanReview: false,
|
||||||
|
UserCanWrite: false,
|
||||||
|
EnableInsertRemoteImage: false,
|
||||||
|
UserID: "guest-zzz000",
|
||||||
|
UserFriendlyName: "guest zzz000",
|
||||||
|
FileSharingURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=sharing",
|
||||||
|
FileVersionURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=versions",
|
||||||
|
HostEditURL: "https://ocis.example.prv/external-onlyoffice/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=write",
|
||||||
|
PostMessageOrigin: "https://ocis.example.prv",
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := fc.CheckFileInfo(ctx)
|
||||||
|
|
||||||
|
// UserID and UserFriendlyName have random Ids generated which are impossible to guess
|
||||||
|
// Check both separately
|
||||||
|
Expect(response.Body.(*fileinfo.OnlyOffice).UserID).To(HavePrefix(hex.EncodeToString([]byte("guest-"))))
|
||||||
|
Expect(response.Body.(*fileinfo.OnlyOffice).UserFriendlyName).To(HavePrefix("Guest "))
|
||||||
|
// overwrite UserID and UserFriendlyName here for easier matching
|
||||||
|
response.Body.(*fileinfo.OnlyOffice).UserID = "guest-zzz000"
|
||||||
|
response.Body.(*fileinfo.OnlyOffice).UserFriendlyName = "guest zzz000"
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(response.Status).To(Equal(200))
|
||||||
|
Expect(response.Body.(*fileinfo.OnlyOffice)).To(Equal(expectedFileInfo))
|
||||||
|
})
|
||||||
|
|
||||||
It("Stat success authenticated user", func() {
|
It("Stat success authenticated user", func() {
|
||||||
// change view mode to view only
|
// change view mode to view only
|
||||||
wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
auth "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||||
|
"github.com/cs3org/reva/v2/pkg/utils"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetScopeByKeyPrefix returns the scope from the AccessToken Scope map by key prefix
|
||||||
|
func GetScopeByKeyPrefix(scopes map[string]*auth.Scope, keyPrefix string, m proto.Message) error {
|
||||||
|
for k, v := range scopes {
|
||||||
|
if strings.HasPrefix(k, keyPrefix) && v.Resource.Decoder == "json" {
|
||||||
|
err := utils.UnmarshalJSONToProtoV1(v.Resource.Value, m)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't unmarshal public share from scope: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("scope %s not found", keyPrefix)
|
||||||
|
}
|
||||||
@@ -12,13 +12,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
||||||
auth "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
|
||||||
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||||
rjwt "github.com/cs3org/reva/v2/pkg/token/manager/jwt"
|
rjwt "github.com/cs3org/reva/v2/pkg/token/manager/jwt"
|
||||||
"github.com/cs3org/reva/v2/pkg/utils"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
|
"github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
|
||||||
"github.com/owncloud/ocis/v2/services/collaboration/pkg/helpers"
|
"github.com/owncloud/ocis/v2/services/collaboration/pkg/helpers"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
@@ -39,22 +36,6 @@ type WopiContext struct {
|
|||||||
FileReference *providerv1beta1.Reference
|
FileReference *providerv1beta1.Reference
|
||||||
TemplateReference *providerv1beta1.Reference
|
TemplateReference *providerv1beta1.Reference
|
||||||
ViewMode appproviderv1beta1.ViewMode
|
ViewMode appproviderv1beta1.ViewMode
|
||||||
// scope contains decoded Scope map from the AccessToken
|
|
||||||
scope map[string]*auth.Scope
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetScopeByKeyPrefix returns the scope from the AccessToken Scope map by key prefix
|
|
||||||
func (w *WopiContext) GetScopeByKeyPrefix(keyPrefix string, m proto.Message) error {
|
|
||||||
for k, v := range w.scope {
|
|
||||||
if strings.HasPrefix(k, keyPrefix) && v.Resource.Decoder == "json" {
|
|
||||||
err := utils.UnmarshalJSONToProtoV1(v.Resource.Value, m)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("can't unmarshal public share from scope: %w", err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WopiContextAuthMiddleware will prepare an HTTP handler to be used as
|
// WopiContextAuthMiddleware will prepare an HTTP handler to be used as
|
||||||
@@ -139,7 +120,7 @@ func WopiContextAuthMiddleware(cfg *config.Config, st microstore.Store, next htt
|
|||||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user, scope, err := tokenManager.DismantleToken(ctx, wopiContextAccessToken)
|
user, scopes, err := tokenManager.DismantleToken(ctx, wopiContextAccessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wopiLogger.Error().Err(err).Msg("failed to dismantle reva token manager")
|
wopiLogger.Error().Err(err).Msg("failed to dismantle reva token manager")
|
||||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
@@ -147,12 +128,12 @@ func WopiContextAuthMiddleware(cfg *config.Config, st microstore.Store, next htt
|
|||||||
}
|
}
|
||||||
|
|
||||||
claims.WopiContext.AccessToken = wopiContextAccessToken
|
claims.WopiContext.AccessToken = wopiContextAccessToken
|
||||||
claims.WopiContext.scope = scope
|
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, wopiContextKey, claims.WopiContext)
|
ctx = context.WithValue(ctx, wopiContextKey, claims.WopiContext)
|
||||||
// authentication for the CS3 api
|
// authentication for the CS3 api
|
||||||
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, claims.WopiContext.AccessToken)
|
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, claims.WopiContext.AccessToken)
|
||||||
ctx = ctxpkg.ContextSetUser(ctx, user)
|
ctx = ctxpkg.ContextSetUser(ctx, user)
|
||||||
|
ctx = ctxpkg.ContextSetScopes(ctx, scopes)
|
||||||
|
|
||||||
// include additional info in the context's logger
|
// include additional info in the context's logger
|
||||||
wopiLogger = wopiLogger.With().
|
wopiLogger = wopiLogger.With().
|
||||||
|
|||||||
Reference in New Issue
Block a user