[#505] Handle access denied from tree service

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-09-13 13:35:30 +03:00 committed by Alex Vanin
parent 80beedf13e
commit 3d08562843
5 changed files with 79 additions and 44 deletions

View file

@ -2,6 +2,7 @@ package handler
import ( import (
"context" "context"
errorsStd "errors"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@ -23,7 +24,20 @@ func (h *handler) logAndSendError(w http.ResponseWriter, logText string, reqInfo
fields = append(fields, additional...) fields = append(fields, additional...)
h.log.Error(logText, fields...) h.log.Error(logText, fields...)
api.WriteErrorResponse(w, reqInfo, err) api.WriteErrorResponse(w, reqInfo, transformToS3Error(err))
}
func transformToS3Error(err error) error {
if _, ok := err.(errors.Error); ok {
return err
}
if errorsStd.Is(err, layer.ErrAccessDenied) ||
errorsStd.Is(err, layer.ErrNodeAccessDenied) {
return errors.GetAPIError(errors.ErrAccessDenied)
}
return errors.GetAPIError(errors.ErrInternalError)
} }
func (h *handler) getBucketAndCheckOwner(r *http.Request, bucket string, header ...string) (*data.BucketInfo, error) { func (h *handler) getBucketAndCheckOwner(r *http.Request, bucket string, header ...string) (*data.BucketInfo, error) {

View file

@ -93,7 +93,7 @@ func (n *layer) objectHead(ctx context.Context, bktInfo *data.BucketInfo, idObj
res, err := n.neoFS.ReadObject(ctx, prm) res, err := n.neoFS.ReadObject(ctx, prm)
if err != nil { if err != nil {
return nil, n.transformNeofsError(ctx, err) return nil, err
} }
return res.Head, nil return res.Head, nil
@ -113,7 +113,7 @@ func (n *layer) initObjectPayloadReader(ctx context.Context, p getParams) (io.Re
res, err := n.neoFS.ReadObject(ctx, prm) res, err := n.neoFS.ReadObject(ctx, prm)
if err != nil { if err != nil {
return nil, n.transformNeofsError(ctx, err) return nil, err
} }
return res.Payload, nil return res.Payload, nil
@ -132,7 +132,7 @@ func (n *layer) objectGet(ctx context.Context, bktInfo *data.BucketInfo, objID o
res, err := n.neoFS.ReadObject(ctx, prm) res, err := n.neoFS.ReadObject(ctx, prm)
if err != nil { if err != nil {
return nil, n.transformNeofsError(ctx, err) return nil, err
} }
return res.Head, nil return res.Head, nil
@ -420,7 +420,7 @@ func (n *layer) objectDelete(ctx context.Context, bktInfo *data.BucketInfo, idOb
n.objCache.Delete(newAddress(bktInfo.CID, idObj)) n.objCache.Delete(newAddress(bktInfo.CID, idObj))
return n.transformNeofsError(ctx, n.neoFS.DeleteObject(ctx, prm)) return n.neoFS.DeleteObject(ctx, prm)
} }
// objectPutAndHash prepare auth parameters and invoke neofs.CreateObject. // objectPutAndHash prepare auth parameters and invoke neofs.CreateObject.
@ -432,7 +432,7 @@ func (n *layer) objectPutAndHash(ctx context.Context, prm PrmObjectCreate, bktIn
hash.Write(buf) hash.Write(buf)
}) })
id, err := n.neoFS.CreateObject(ctx, prm) id, err := n.neoFS.CreateObject(ctx, prm)
return id, hash.Sum(nil), n.transformNeofsError(ctx, err) return id, hash.Sum(nil), err
} }
// ListObjectsV1 returns objects in a bucket for requests of Version 1. // ListObjectsV1 returns objects in a bucket for requests of Version 1.
@ -815,19 +815,6 @@ func tryDirectoryName(node *data.NodeVersion, prefix, delimiter string) string {
return "" return ""
} }
func (n *layer) transformNeofsError(ctx context.Context, err error) error {
if err == nil {
return nil
}
if errors.Is(err, ErrAccessDenied) {
n.log.Debug("error was transformed", zap.String("request_id", api.GetRequestID(ctx)), zap.Error(err))
return apiErrors.GetAPIError(apiErrors.ErrAccessDenied)
}
return err
}
func wrapReader(input io.Reader, bufSize int, f func(buf []byte)) io.Reader { func wrapReader(input io.Reader, bufSize int, f func(buf []byte)) io.Reader {
if input == nil { if input == nil {
return nil return nil

View file

@ -85,6 +85,9 @@ var (
// ErrNodeNotFound is returned from Tree service in case of not found error. // ErrNodeNotFound is returned from Tree service in case of not found error.
ErrNodeNotFound = errors.New("not found") ErrNodeNotFound = errors.New("not found")
// ErrNodeAccessDenied is returned from Tree service in case of access denied error.
ErrNodeAccessDenied = errors.New("access denied")
// ErrNoNodeToRemove is returned from Tree service in case of the lack of node with OID to remove. // ErrNoNodeToRemove is returned from Tree service in case of the lack of node with OID to remove.
ErrNoNodeToRemove = errors.New("no node to remove") ErrNoNodeToRemove = errors.New("no node to remove")
) )

View file

@ -441,9 +441,6 @@ func (c *TreeClient) DeleteObjectTagging(ctx context.Context, bktInfo *data.Buck
func (c *TreeClient) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) { func (c *TreeClient) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) {
node, err := c.getSystemNodeWithAllAttributes(ctx, bktInfo, []string{bucketTaggingFilename}) node, err := c.getSystemNodeWithAllAttributes(ctx, bktInfo, []string{bucketTaggingFilename})
if err != nil { if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, layer.ErrNodeNotFound
}
return nil, err return nil, err
} }
@ -549,7 +546,7 @@ func (c *TreeClient) GetLatestVersion(ctx context.Context, bktInfo *data.BucketI
} }
nodes, err := c.getNodes(ctx, p) nodes, err := c.getNodes(ctx, p)
if err != nil { if err != nil {
return nil, fmt.Errorf("couldn't get nodes: %w", err) return nil, err
} }
if len(nodes) == 0 { if len(nodes) == 0 {
@ -1107,10 +1104,10 @@ func (c *TreeClient) getVersions(ctx context.Context, bktInfo *data.BucketInfo,
} }
nodes, err := c.getNodes(ctx, p) nodes, err := c.getNodes(ctx, p)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "not found") { if errors.Is(err, layer.ErrNodeNotFound) {
return nil, nil return nil, nil
} }
return nil, fmt.Errorf("couldn't get nodes: %w", err) return nil, err
} }
result := make([]*data.NodeVersion, 0, len(nodes)) result := make([]*data.NodeVersion, 0, len(nodes))
@ -1152,10 +1149,7 @@ func (c *TreeClient) getSubTree(ctx context.Context, bktInfo *data.BucketInfo, t
cli, err := c.service.GetSubTree(ctx, request) cli, err := c.service.GetSubTree(ctx, request)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "not found") { return nil, handleError("failed to get sub tree client", err)
return nil, layer.ErrNodeNotFound
}
return nil, fmt.Errorf("failed to get sub tree client: %w", err)
} }
var subtree []*tree.GetSubTreeResponse_Body var subtree []*tree.GetSubTreeResponse_Body
@ -1164,10 +1158,7 @@ func (c *TreeClient) getSubTree(ctx context.Context, bktInfo *data.BucketInfo, t
if err == io.EOF { if err == io.EOF {
break break
} else if err != nil { } else if err != nil {
if strings.Contains(err.Error(), "not found") { return nil, handleError("failed to get sub tree", err)
return nil, layer.ErrNodeNotFound
}
return nil, fmt.Errorf("failed to get sub tree: %w", err)
} }
subtree = append(subtree, resp.Body) subtree = append(subtree, resp.Body)
} }
@ -1213,7 +1204,7 @@ func (c *TreeClient) getNode(ctx context.Context, bktInfo *data.BucketInfo, tree
} }
nodes, err := c.getNodes(ctx, p) nodes, err := c.getNodes(ctx, p)
if err != nil { if err != nil {
return nil, fmt.Errorf("couldn't get nodes: %w", err) return nil, err
} }
if len(nodes) == 0 { if len(nodes) == 0 {
return nil, layer.ErrNodeNotFound return nil, layer.ErrNodeNotFound
@ -1250,15 +1241,21 @@ func (c *TreeClient) getNodes(ctx context.Context, p *getNodesParams) ([]*tree.G
resp, err := c.service.GetNodeByPath(ctx, request) resp, err := c.service.GetNodeByPath(ctx, request)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "not found") { return nil, handleError("failed to get node by path", err)
return nil, layer.ErrNodeNotFound
}
return nil, fmt.Errorf("failed to get node path: %w", err)
} }
return resp.GetBody().GetNodes(), nil return resp.GetBody().GetNodes(), nil
} }
func handleError(msg string, err error) error {
if strings.Contains(err.Error(), "not found") {
return fmt.Errorf("%w: %s", layer.ErrNodeNotFound, err.Error())
} else if strings.Contains(err.Error(), "is denied by") {
return fmt.Errorf("%w: %s", layer.ErrNodeAccessDenied, err.Error())
}
return fmt.Errorf("%s: %w", msg, err)
}
func getBearer(ctx context.Context, bktInfo *data.BucketInfo) []byte { func getBearer(ctx context.Context, bktInfo *data.BucketInfo) []byte {
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil { if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil {
if bd.Gate.BearerToken != nil { if bd.Gate.BearerToken != nil {
@ -1291,7 +1288,7 @@ func (c *TreeClient) addNode(ctx context.Context, bktInfo *data.BucketInfo, tree
resp, err := c.service.Add(ctx, request) resp, err := c.service.Add(ctx, request)
if err != nil { if err != nil {
return 0, err return 0, handleError("failed to add node", err)
} }
return resp.GetBody().GetNodeId(), nil return resp.GetBody().GetNodeId(), nil
@ -1320,7 +1317,7 @@ func (c *TreeClient) addNodeByPath(ctx context.Context, bktInfo *data.BucketInfo
resp, err := c.service.AddByPath(ctx, request) resp, err := c.service.AddByPath(ctx, request)
if err != nil { if err != nil {
return 0, err return 0, handleError("failed to add node by path", err)
} }
body := resp.GetBody() body := resp.GetBody()
@ -1355,8 +1352,11 @@ func (c *TreeClient) moveNode(ctx context.Context, bktInfo *data.BucketInfo, tre
return err return err
} }
_, err := c.service.Move(ctx, request) if _, err := c.service.Move(ctx, request); err != nil {
return err return handleError("failed to move node", err)
}
return nil
} }
func (c *TreeClient) removeNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, nodeID uint64) error { func (c *TreeClient) removeNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, nodeID uint64) error {
@ -1377,8 +1377,11 @@ func (c *TreeClient) removeNode(ctx context.Context, bktInfo *data.BucketInfo, t
return err return err
} }
_, err := c.service.Remove(ctx, request) if _, err := c.service.Remove(ctx, request); err != nil {
return err return handleError("failed to remove node", err)
}
return nil
} }
func metaToKV(meta map[string]string) []*tree.KeyValue { func metaToKV(meta map[string]string) []*tree.KeyValue {

View file

@ -1,9 +1,11 @@
package neofs package neofs
import ( import (
"errors"
"testing" "testing"
"github.com/nspcc-dev/neofs-s3-gw/api/data" "github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -93,3 +95,29 @@ func TestLockConfigurationEncoding(t *testing.T) {
}) })
} }
} }
func TestHandleError(t *testing.T) {
defaultError := errors.New("default error")
for _, tc := range []struct {
err error
expectedError error
}{
{
err: defaultError,
expectedError: defaultError,
},
{
err: errors.New("something not found"),
expectedError: layer.ErrNodeNotFound,
},
{
err: errors.New("something is denied by some acl rule"),
expectedError: layer.ErrNodeAccessDenied,
},
} {
t.Run("", func(t *testing.T) {
err := handleError("err message", tc.err)
require.True(t, errors.Is(err, tc.expectedError))
})
}
}