Skip to content

Commit c3e3ccc

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

File tree

4 files changed

+75
-4
lines changed

4 files changed

+75
-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) {
@@ -1612,7 +1616,49 @@ func (c *Client) ReadVersion(ctx context.Context, auth eosclient.Authorization,
16121616

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

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

pkg/eosclient/eosgrpc/eoshttp.go

+21-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,15 @@ 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+
// c.doReq sets headers such as remoteuser and x-gateway-authorization
404+
// we don't want those when using a token (i.e. ?authz=), so in this case
405+
// we skip this and call the HTTP client directly
406+
var resp *http.Response
407+
if auth.Token != "" {
408+
resp, err = c.cl.Do(req)
409+
} else {
410+
resp, err = c.doReq(req, remoteuser)
411+
}
394412

395413
// Let's support redirections... and if we retry we retry at the same FST
396414
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)