@@ -34,11 +34,11 @@ import (
34
34
"time"
35
35
36
36
erpc "github.com/cern-eos/go-eosgrpc"
37
- userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
38
37
"github.com/cs3org/reva/pkg/appctx"
39
38
"github.com/cs3org/reva/pkg/eosclient"
40
39
"github.com/cs3org/reva/pkg/errtypes"
41
40
"github.com/cs3org/reva/pkg/storage/utils/acl"
41
+ "github.com/cs3org/reva/pkg/utils"
42
42
"github.com/google/uuid"
43
43
"github.com/pkg/errors"
44
44
"github.com/rs/zerolog"
@@ -58,27 +58,12 @@ const (
58
58
UserAttr
59
59
)
60
60
61
- func serializeAttribute (a * eosclient.Attribute ) string {
62
- return fmt .Sprintf ("%s.%s=%s" , attrTypeToString (a .Type ), a .Key , a .Val )
63
- }
64
-
65
- func attrTypeToString (at eosclient.AttrType ) string {
66
- switch at {
67
- case eosclient .SystemAttr :
68
- return "sys"
69
- case eosclient .UserAttr :
70
- return "user"
71
- default :
72
- return "invalid"
73
- }
74
- }
75
-
76
- func isValidAttribute (a * eosclient.Attribute ) bool {
77
- // validate that an attribute is correct.
78
- if (a .Type != eosclient .SystemAttr && a .Type != eosclient .UserAttr ) || a .Key == "" {
79
- return false
80
- }
81
- return true
61
+ // Client performs actions against a EOS management node (MGM)
62
+ // using the EOS GRPC interface.
63
+ type Client struct {
64
+ opt * Options
65
+ httpcl * EOSHTTPClient
66
+ cl erpc.EosClient
82
67
}
83
68
84
69
// Options to configure the Client.
@@ -131,15 +116,6 @@ type Options struct {
131
116
TokenExpiry int
132
117
}
133
118
134
- func getUser (ctx context.Context ) (* userpb.User , error ) {
135
- u , ok := appctx .ContextGetUser (ctx )
136
- if ! ok {
137
- err := errors .Wrap (errtypes .UserRequired ("" ), "eosfs: error getting user from ctx" )
138
- return nil , err
139
- }
140
- return u , nil
141
- }
142
-
143
119
func (opt * Options ) init () {
144
120
if opt .XrdcopyBinary == "" {
145
121
opt .XrdcopyBinary = "/opt/eos/xrootd/bin/xrdcopy"
@@ -154,12 +130,27 @@ func (opt *Options) init() {
154
130
}
155
131
}
156
132
157
- // Client performs actions against a EOS management node (MGM)
158
- // using the EOS GRPC interface.
159
- type Client struct {
160
- opt * Options
161
- httpcl * EOSHTTPClient
162
- cl erpc.EosClient
133
+ func serializeAttribute (a * eosclient.Attribute ) string {
134
+ return fmt .Sprintf ("%s.%s=%s" , attrTypeToString (a .Type ), a .Key , a .Val )
135
+ }
136
+
137
+ func attrTypeToString (at eosclient.AttrType ) string {
138
+ switch at {
139
+ case eosclient .SystemAttr :
140
+ return "sys"
141
+ case eosclient .UserAttr :
142
+ return "user"
143
+ default :
144
+ return "invalid"
145
+ }
146
+ }
147
+
148
+ func isValidAttribute (a * eosclient.Attribute ) bool {
149
+ // validate that an attribute is correct.
150
+ if (a .Type != eosclient .SystemAttr && a .Type != eosclient .UserAttr ) || a .Key == "" {
151
+ return false
152
+ }
153
+ return true
163
154
}
164
155
165
156
// Create and connect a grpc eos Client.
@@ -230,28 +221,33 @@ func (c *Client) getRespError(rsp *erpc.NSResponse, err error) error {
230
221
231
222
// Common code to create and initialize a NSRequest.
232
223
func (c * Client ) initNSRequest (ctx context.Context , auth eosclient.Authorization , app string ) (* erpc.NSRequest , error ) {
233
- // Stuff filename, uid, gid into the MDRequest type
234
-
235
224
log := appctx .GetLogger (ctx )
236
225
log .Debug ().Str ("(uid,gid)" , "(" + auth .Role .UID + "," + auth .Role .GID + ")" ).Msg ("New grpcNS req" )
237
226
238
227
rq := new (erpc.NSRequest )
239
228
rq .Role = new (erpc.RoleId )
240
229
241
- uidInt , err := strconv .ParseUint (auth .Role .UID , 10 , 64 )
242
- if err != nil {
243
- return nil , err
244
- }
245
- gidInt , err := strconv .ParseUint (auth .Role .GID , 10 , 64 )
246
- if err != nil {
247
- return nil , err
230
+ // Let's put in the authentication info
231
+ if auth .Token != "" {
232
+ // Map to owner using EOSAUTHZ token
233
+ // We do not become cbox
234
+ rq .Authkey = auth .Token
235
+ } else {
236
+ // We take the secret key from the config, which maps on EOS to cbox
237
+ // cbox is a sudo'er, so we become the user specified in UID/GID, if it is set
238
+ rq .Authkey = c .opt .Authkey
239
+
240
+ uid , gid , err := utils .ExtractUidGid (auth )
241
+ if err == nil {
242
+ rq .Role .Uid = uid
243
+ rq .Role .Gid = gid
244
+ }
248
245
}
249
- rq . Role . Uid = uidInt
250
- rq . Role . Gid = gidInt
246
+
247
+ // For NS operations, specifically for locking, we also need to provide the app
251
248
if app != "" {
252
249
rq .Role .App = app
253
250
}
254
- rq .Authkey = c .opt .Authkey
255
251
256
252
return rq , nil
257
253
}
@@ -263,23 +259,26 @@ func (c *Client) initMDRequest(ctx context.Context, auth eosclient.Authorization
263
259
log := appctx .GetLogger (ctx )
264
260
log .Debug ().Str ("(uid,gid)" , "(" + auth .Role .UID + "," + auth .Role .GID + ")" ).Msg ("New grpcMD req" )
265
261
266
- mdrq := new (erpc.MDRequest )
267
- mdrq .Role = new (erpc.RoleId )
262
+ rq := new (erpc.MDRequest )
263
+ rq .Role = new (erpc.RoleId )
268
264
269
- uidInt , err := strconv .ParseUint (auth .Role .UID , 10 , 64 )
270
- if err != nil {
271
- return nil , err
272
- }
273
- gidInt , err := strconv .ParseUint (auth .Role .GID , 10 , 64 )
274
- if err != nil {
275
- return nil , err
276
- }
277
- mdrq .Role .Uid = uidInt
278
- mdrq .Role .Gid = gidInt
265
+ if auth .Token != "" {
266
+ // Map to owner using EOSAUTHZ token
267
+ // We do not become cbox
268
+ rq .Authkey = auth .Token
269
+ } else {
270
+ // We take the secret key from the config, which maps on EOS to cbox
271
+ // cbox is a sudo'er, so we become the user specified in UID/GID, if it is set
272
+ rq .Authkey = c .opt .Authkey
279
273
280
- mdrq .Authkey = c .opt .Authkey
274
+ uid , gid , err := utils .ExtractUidGid (auth )
275
+ if err == nil {
276
+ rq .Role .Uid = uid
277
+ rq .Role .Gid = gid
278
+ }
279
+ }
281
280
282
- return mdrq , nil
281
+ return rq , nil
283
282
}
284
283
285
284
// AddACL adds an new acl to EOS with the given aclType.
@@ -711,9 +710,14 @@ func getAttribute(key, val string) (*eosclient.Attribute, error) {
711
710
}
712
711
713
712
// GetFileInfoByPath returns the FilInfo at the given path.
714
- func (c * Client ) GetFileInfoByPath (ctx context.Context , auth eosclient.Authorization , path string ) (* eosclient.FileInfo , error ) {
713
+ func (c * Client ) GetFileInfoByPath (ctx context.Context , userAuth eosclient.Authorization , path string ) (* eosclient.FileInfo , error ) {
715
714
log := appctx .GetLogger (ctx )
716
- log .Debug ().Str ("func" , "GetFileInfoByPath" ).Str ("uid,gid" , auth .Role .UID + "," + auth .Role .GID ).Str ("path" , path ).Msg ("entering" )
715
+ log .Debug ().Str ("func" , "GetFileInfoByPath" ).Str ("uid,gid" , userAuth .Role .UID + "," + userAuth .Role .GID ).Str ("path" , path ).Msg ("entering" )
716
+
717
+ // UserAuth may not be sufficient, because the user may not have access to the file
718
+ // e.g. in the case of a guest account. So we check if a uid/gid is set, and if not,
719
+ // revert to the daemon account
720
+ auth := utils .GetUserOrDaemonAuth (userAuth )
717
721
718
722
// Initialize the common fields of the MDReq
719
723
mdrq , err := c .initMDRequest (ctx , auth )
@@ -756,7 +760,16 @@ func (c *Client) GetFileInfoByPath(ctx context.Context, auth eosclient.Authoriza
756
760
}
757
761
758
762
if c .opt .VersionInvariant && ! isVersionFolder (path ) && ! info .IsDir {
759
- inode , err := c .getVersionFolderInode (ctx , auth , path )
763
+ // Here we have to create a missing version folder, irrespective from the user (that could be a sharee, or a lw account, or...)
764
+ // Therefore, we impersonate the owner of the file
765
+ ownerAuth := eosclient.Authorization {
766
+ Role : eosclient.Role {
767
+ UID : strconv .FormatUint (info .UID , 10 ),
768
+ GID : strconv .FormatUint (info .GID , 10 ),
769
+ },
770
+ }
771
+
772
+ inode , err := c .getOrCreateVersionFolderInode (ctx , ownerAuth , path )
760
773
if err != nil {
761
774
return nil , err
762
775
}
@@ -817,13 +830,9 @@ func (c *Client) GetQuota(ctx context.Context, username string, rootAuth eosclie
817
830
return nil , errtypes .InternalError (fmt .Sprintf ("Quota error from eos. info: '%#v'" , resp .Quota ))
818
831
}
819
832
820
- qi := new (eosclient.QuotaInfo )
821
- if resp == nil {
822
- return nil , errtypes .InternalError ("Out of memory" )
823
- }
824
-
825
833
// Let's loop on all the quotas that match this uid (apparently there can be many)
826
834
// If there are many for this node, we sum them up
835
+ qi := new (eosclient.QuotaInfo )
827
836
for i := 0 ; i < len (resp .Quota .Quotanode ); i ++ {
828
837
log .Debug ().Str ("func" , "GetQuota" ).Str ("quotanode:" , fmt .Sprintf ("%d: %#v" , i , resp .Quota .Quotanode [i ])).Msg ("" )
829
838
@@ -954,13 +963,11 @@ func (c *Client) Chown(ctx context.Context, auth, chownAuth eosclient.Authorizat
954
963
955
964
msg := new (erpc.NSRequest_ChownRequest )
956
965
msg .Owner = new (erpc.RoleId )
957
- msg .Owner .Uid , err = strconv .ParseUint (chownAuth .Role .UID , 10 , 64 )
958
- if err != nil {
959
- return err
960
- }
961
- msg .Owner .Gid , err = strconv .ParseUint (chownAuth .Role .GID , 10 , 64 )
962
- if err != nil {
963
- return err
966
+
967
+ uid , gid , err := utils .ExtractUidGid (chownAuth )
968
+ if err == nil {
969
+ msg .Owner .Uid = uid
970
+ msg .Owner .Gid = gid
964
971
}
965
972
966
973
msg .Id = new (erpc.MDId )
@@ -1195,7 +1202,6 @@ func (c *Client) Rename(ctx context.Context, auth eosclient.Authorization, oldPa
1195
1202
// List the contents of the directory given by path.
1196
1203
func (c * Client ) List (ctx context.Context , auth eosclient.Authorization , dpath string ) ([]* eosclient.FileInfo , error ) {
1197
1204
log := appctx .GetLogger (ctx )
1198
- log .Info ().Str ("func" , "List" ).Str ("uid,gid" , auth .Role .UID + "," + auth .Role .GID ).Str ("dpath" , dpath ).Msg ("" )
1199
1205
1200
1206
// Stuff filename, uid, gid into the FindRequest type
1201
1207
fdrq := new (erpc.FindRequest )
@@ -1206,16 +1212,12 @@ func (c *Client) List(ctx context.Context, auth eosclient.Authorization, dpath s
1206
1212
1207
1213
fdrq .Role = new (erpc.RoleId )
1208
1214
1209
- uidInt , err := strconv .ParseUint (auth .Role .UID , 10 , 64 )
1210
- if err != nil {
1211
- return nil , err
1212
- }
1213
- gidInt , err := strconv .ParseUint (auth .Role .GID , 10 , 64 )
1215
+ uid , gid , err := utils .ExtractUidGid (auth )
1214
1216
if err != nil {
1215
- return nil , err
1217
+ return nil , errors . Wrap ( err , "Failed to extract uid/gid from auth" )
1216
1218
}
1217
- fdrq .Role .Uid = uidInt
1218
- fdrq .Role .Gid = gidInt
1219
+ fdrq .Role .Uid = uid
1220
+ fdrq .Role .Gid = gid
1219
1221
1220
1222
fdrq .Authkey = c .opt .Authkey
1221
1223
@@ -1347,7 +1349,7 @@ func (c *Client) Read(ctx context.Context, auth eosclient.Authorization, path st
1347
1349
var localfile io.WriteCloser
1348
1350
localfile = nil
1349
1351
1350
- u , err := getUser (ctx )
1352
+ u , err := utils . GetUser (ctx )
1351
1353
if err != nil {
1352
1354
return nil , errors .Wrap (err , "eos: no user in ctx" )
1353
1355
}
@@ -1383,7 +1385,7 @@ func (c *Client) Write(ctx context.Context, auth eosclient.Authorization, path s
1383
1385
var length int64
1384
1386
length = - 1
1385
1387
1386
- u , err := getUser (ctx )
1388
+ u , err := utils . GetUser (ctx )
1387
1389
if err != nil {
1388
1390
return errors .Wrap (err , "eos: no user in ctx" )
1389
1391
}
@@ -1661,17 +1663,17 @@ func (c *Client) GenerateToken(ctx context.Context, auth eosclient.Authorization
1661
1663
return "" , err
1662
1664
}
1663
1665
1664
- func (c * Client ) getVersionFolderInode (ctx context.Context , auth eosclient.Authorization , p string ) (uint64 , error ) {
1666
+ func (c * Client ) getOrCreateVersionFolderInode (ctx context.Context , ownerAuth eosclient.Authorization , p string ) (uint64 , error ) {
1665
1667
log := appctx .GetLogger (ctx )
1666
- log .Info ().Str ("func" , "getVersionFolderInode " ).Str ("uid,gid" , auth .Role .UID + "," + auth .Role .GID ).Str ("p" , p ).Msg ("" )
1668
+ log .Info ().Str ("func" , "getOrCreateVersionFolderInode " ).Str ("uid,gid" , ownerAuth .Role .UID + "," + ownerAuth .Role .GID ).Str ("p" , p ).Msg ("" )
1667
1669
1668
1670
versionFolder := getVersionFolder (p )
1669
- md , err := c .GetFileInfoByPath (ctx , auth , versionFolder )
1671
+ md , err := c .GetFileInfoByPath (ctx , ownerAuth , versionFolder )
1670
1672
if err != nil {
1671
- if err = c .CreateDir (ctx , auth , versionFolder ); err != nil {
1673
+ if err = c .CreateDir (ctx , ownerAuth , versionFolder ); err != nil {
1672
1674
return 0 , err
1673
1675
}
1674
- md , err = c .GetFileInfoByPath (ctx , auth , versionFolder )
1676
+ md , err = c .GetFileInfoByPath (ctx , ownerAuth , versionFolder )
1675
1677
if err != nil {
1676
1678
return 0 , err
1677
1679
}
0 commit comments