Skip to content

Commit bf72c71

Browse files
committed
Fixed access to files via token, i.e. for guest accounts
1 parent d7a0558 commit bf72c71

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Enhancement: access to EOS via tokens over gRPC
2+
3+
As a guest account, accessing a file shared with you relies on a token that is generated on behalf of the resource owner. This method, GenerateToken, has now been implemented in the EOS gRPC client. Additionally, the HTTP client now takes tokens into account.
4+
5+
6+
https://github.com/cs3org/reva/pull/4934

pkg/eosclient/eosgrpc/eosgrpc.go

+47-1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ type Options struct {
125125
// SecProtocol is the comma separated list of security protocols used by xrootd.
126126
// For example: "sss, unix"
127127
SecProtocol string
128+
129+
// TokenExpiry stores in seconds the time after which generated tokens will expire
130+
// Default is 3600
131+
TokenExpiry int
128132
}
129133

130134
func getUser(ctx context.Context) (*userpb.User, error) {
@@ -1603,7 +1607,49 @@ func (c *Client) ReadVersion(ctx context.Context, auth eosclient.Authorization,
16031607

16041608
// GenerateToken returns a token on behalf of the resource owner to be used by lightweight accounts.
16051609
func (c *Client) GenerateToken(ctx context.Context, auth eosclient.Authorization, path string, a *acl.Entry) (string, error) {
1606-
return "", errtypes.NotSupported("TODO")
1610+
log := appctx.GetLogger(ctx)
1611+
log.Info().Str("func", "GenerateToken").Str("uid,gid", auth.Role.UID+","+auth.Role.GID).Str("path", path).Msg("")
1612+
1613+
// Initialize the common fields of the NSReq
1614+
rq, err := c.initNSRequest(ctx, auth, "")
1615+
if err != nil {
1616+
log.Error().Str("func", "GenerateToken").Str("err", err.Error()).Msg("Error on initNSRequest")
1617+
return "", err
1618+
}
1619+
1620+
msg := new(erpc.NSRequest_TokenRequest)
1621+
msg.Token = &erpc.ShareToken{}
1622+
msg.Token.Token = &erpc.ShareProto{}
1623+
msg.Token.Token.Permission = a.Permissions
1624+
msg.Token.Token.Expires = uint64(time.Now().Add(time.Duration(c.opt.TokenExpiry) * time.Second).Unix())
1625+
msg.Token.Token.Allowtree = true
1626+
msg.Token.Token.Path = path
1627+
1628+
rq.Command = &erpc.NSRequest_Token{
1629+
Token: msg,
1630+
}
1631+
1632+
// Now send the req and see what happens
1633+
resp, err := c.cl.Exec(appctx.ContextGetClean(ctx), rq)
1634+
e := c.getRespError(resp, err)
1635+
if e != nil {
1636+
log.Error().Str("func", "GenerateToken").Str("err", e.Error()).Msg("")
1637+
return "", e
1638+
}
1639+
1640+
if resp == nil {
1641+
log.Error().Str("func", "GenerateToken").Msg("nil grpc response")
1642+
return "", errtypes.InternalError(fmt.Sprintf("nil response for uid: '%s' ", auth.Role.UID))
1643+
}
1644+
1645+
// For some reason, the token is embedded in the error, with error code 0
1646+
if resp.GetError() != nil {
1647+
if resp.GetError().Code == 0 {
1648+
return resp.GetError().Msg, nil
1649+
}
1650+
}
1651+
log.Error().Str("func", "GenerateToken").Msg("GenerateToken over gRPC expected an error but did not receive one")
1652+
return "", err
16071653
}
16081654

16091655
func (c *Client) getVersionFolderInode(ctx context.Context, auth eosclient.Authorization, p string) (uint64, error) {

pkg/eosclient/eosgrpc/eoshttp.go

+18-3
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ func (c *EOSHTTPClient) buildFullURL(urlpath string, auth eosclient.Authorizatio
241241
fullurl += "?"
242242
}
243243

244-
if auth.Role.UID != "" {
244+
if auth.Token != "" {
245+
fullurl += "authz=" + auth.Token
246+
} else if auth.Role.UID != "" {
245247
fullurl += fmt.Sprintf("eos.ruid=%s&eos.rgid=%s", auth.Role.UID, auth.Role.GID)
246248
}
247249

@@ -291,7 +293,15 @@ func (c *EOSHTTPClient) GETFile(ctx context.Context, remoteuser string, auth eos
291293
// Execute the request. I don't like that there is no explicit timeout or buffer control on the input stream
292294
log.Debug().Str("func", "GETFile").Str("finalurl", finalurl).Msg("sending req")
293295

294-
resp, err := c.doReq(req, remoteuser)
296+
// c.doReq sets headers such as remoteuser and x-gateway-authorization
297+
// we don't want those when using a token (i.e. ?authz=), so in this case
298+
// we skip this and call the HTTP client directly
299+
var resp *http.Response
300+
if auth.Token != "" {
301+
resp, err = c.cl.Do(req)
302+
} else {
303+
resp, err = c.doReq(req, remoteuser)
304+
}
295305

296306
// Let's support redirections... and if we retry we have to retry at the same FST, avoid going back to the MGM
297307
if resp != nil && (resp.StatusCode == http.StatusFound || resp.StatusCode == http.StatusTemporaryRedirect) {
@@ -390,7 +400,12 @@ func (c *EOSHTTPClient) PUTFile(ctx context.Context, remoteuser string, auth eos
390400
// Execute the request. I don't like that there is no explicit timeout or buffer control on the input stream
391401
log.Debug().Str("func", "PUTFile").Msg("sending req")
392402

393-
resp, err := c.doReq(req, remoteuser)
403+
var resp *http.Response
404+
if auth.Token != "" {
405+
resp, err = c.cl.Do(req)
406+
} else {
407+
resp, err = c.doReq(req, remoteuser)
408+
}
394409

395410
// Let's support redirections... and if we retry we retry at the same FST
396411
if resp != nil && resp.StatusCode == 307 {

pkg/storage/utils/eosfs/eosfs.go

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ func NewEOSFS(ctx context.Context, c *Config) (storage.FS, error) {
193193
VersionInvariant: c.VersionInvariant,
194194
ReadUsesLocalTemp: c.ReadUsesLocalTemp,
195195
WriteUsesLocalTemp: c.WriteUsesLocalTemp,
196+
TokenExpiry: c.TokenExpiry,
196197
}
197198
eosHTTPOpts := &eosgrpc.HTTPOptions{
198199
BaseURL: c.MasterURL,

0 commit comments

Comments
 (0)