mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-05 03:40:01 -06:00
use the context as a scopes carrier
This commit is contained in:
72955
coverage.out
72955
coverage.out
File diff suppressed because it is too large
Load Diff
@@ -1228,12 +1228,16 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
|
||||
if !isPublicShare {
|
||||
parentFolderURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetParentId()))
|
||||
} else {
|
||||
publicShare := &link.PublicShare{}
|
||||
err := wopiContext.GetScopeByKeyPrefix("publicshare:", publicShare)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("CheckFileInfo: error getting public share scope")
|
||||
if scopes, ok := ctxpkg.ContextGetScopes(ctx); ok {
|
||||
publicShare := &link.PublicShare{}
|
||||
if err := helpers.GetScopeByKeyPrefix(scopes, "publicshare:", publicShare); err == nil {
|
||||
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
|
||||
infoMap := map[string]interface{}{
|
||||
|
||||
@@ -10,12 +10,15 @@ import (
|
||||
"strings"
|
||||
|
||||
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"
|
||||
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"
|
||||
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -1806,6 +1809,109 @@ var _ = Describe("FileConnector", func() {
|
||||
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() {
|
||||
// change view mode to view only
|
||||
wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
||||
|
||||
24
services/collaboration/pkg/helpers/scope.go
Normal file
24
services/collaboration/pkg/helpers/scope.go
Normal file
@@ -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"
|
||||
|
||||
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"
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
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/protobuf/proto"
|
||||
"github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
|
||||
"github.com/owncloud/ocis/v2/services/collaboration/pkg/helpers"
|
||||
"github.com/rs/zerolog"
|
||||
@@ -39,22 +36,6 @@ type WopiContext struct {
|
||||
FileReference *providerv1beta1.Reference
|
||||
TemplateReference *providerv1beta1.Reference
|
||||
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
|
||||
@@ -139,7 +120,7 @@ func WopiContextAuthMiddleware(cfg *config.Config, st microstore.Store, next htt
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
user, scope, err := tokenManager.DismantleToken(ctx, wopiContextAccessToken)
|
||||
user, scopes, err := tokenManager.DismantleToken(ctx, wopiContextAccessToken)
|
||||
if err != nil {
|
||||
wopiLogger.Error().Err(err).Msg("failed to dismantle reva token manager")
|
||||
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.scope = scope
|
||||
|
||||
ctx = context.WithValue(ctx, wopiContextKey, claims.WopiContext)
|
||||
// authentication for the CS3 api
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, claims.WopiContext.AccessToken)
|
||||
ctx = ctxpkg.ContextSetUser(ctx, user)
|
||||
ctx = ctxpkg.ContextSetScopes(ctx, scopes)
|
||||
|
||||
// include additional info in the context's logger
|
||||
wopiLogger = wopiLogger.With().
|
||||
|
||||
Reference in New Issue
Block a user