[#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 (
"context"
errorsStd "errors"
"net/http"
"strconv"
"strings"
@ -23,7 +24,20 @@ func (h *handler) logAndSendError(w http.ResponseWriter, logText string, reqInfo
fields = append(fields, additional...)
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) {

View file

@ -93,7 +93,7 @@ func (n *layer) objectHead(ctx context.Context, bktInfo *data.BucketInfo, idObj
res, err := n.neoFS.ReadObject(ctx, prm)
if err != nil {
return nil, n.transformNeofsError(ctx, err)
return nil, err
}
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)
if err != nil {
return nil, n.transformNeofsError(ctx, err)
return nil, err
}
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)
if err != nil {
return nil, n.transformNeofsError(ctx, err)
return nil, err
}
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))
return n.transformNeofsError(ctx, n.neoFS.DeleteObject(ctx, prm))
return n.neoFS.DeleteObject(ctx, prm)
}
// 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)
})
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.
@ -815,19 +815,6 @@ func tryDirectoryName(node *data.NodeVersion, prefix, delimiter string) string {
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 {
if input == nil {
return nil

View file

@ -85,6 +85,9 @@ var (
// ErrNodeNotFound is returned from Tree service in case of not found error.
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 = 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) {
node, err := c.getSystemNodeWithAllAttributes(ctx, bktInfo, []string{bucketTaggingFilename})
if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, layer.ErrNodeNotFound
}
return nil, err
}
@ -549,7 +546,7 @@ func (c *TreeClient) GetLatestVersion(ctx context.Context, bktInfo *data.BucketI
}
nodes, err := c.getNodes(ctx, p)
if err != nil {
return nil, fmt.Errorf("couldn't get nodes: %w", err)
return nil, err
}
if len(nodes) == 0 {
@ -1107,10 +1104,10 @@ func (c *TreeClient) getVersions(ctx context.Context, bktInfo *data.BucketInfo,
}
nodes, err := c.getNodes(ctx, p)
if err != nil {
if strings.Contains(err.Error(), "not found") {
if errors.Is(err, layer.ErrNodeNotFound) {
return nil, nil
}
return nil, fmt.Errorf("couldn't get nodes: %w", err)
return nil, err
}
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)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, layer.ErrNodeNotFound
}
return nil, fmt.Errorf("failed to get sub tree client: %w", err)
return nil, handleError("failed to get sub tree client", err)
}
var subtree []*tree.GetSubTreeResponse_Body
@ -1164,10 +1158,7 @@ func (c *TreeClient) getSubTree(ctx context.Context, bktInfo *data.BucketInfo, t
if err == io.EOF {
break
} else if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, layer.ErrNodeNotFound
}
return nil, fmt.Errorf("failed to get sub tree: %w", err)
return nil, handleError("failed to get sub tree", err)
}
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)
if err != nil {
return nil, fmt.Errorf("couldn't get nodes: %w", err)
return nil, err
}
if len(nodes) == 0 {
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)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, layer.ErrNodeNotFound
}
return nil, fmt.Errorf("failed to get node path: %w", err)
return nil, handleError("failed to get node by path", err)
}
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 {
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != 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)
if err != nil {
return 0, err
return 0, handleError("failed to add node", err)
}
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)
if err != nil {
return 0, err
return 0, handleError("failed to add node by path", err)
}
body := resp.GetBody()
@ -1355,8 +1352,11 @@ func (c *TreeClient) moveNode(ctx context.Context, bktInfo *data.BucketInfo, tre
return err
}
_, err := c.service.Move(ctx, request)
return err
if _, err := c.service.Move(ctx, request); err != nil {
return handleError("failed to move node", err)
}
return nil
}
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
}
_, err := c.service.Remove(ctx, request)
return err
if _, err := c.service.Remove(ctx, request); err != nil {
return handleError("failed to remove node", err)
}
return nil
}
func metaToKV(meta map[string]string) []*tree.KeyValue {

View file

@ -1,9 +1,11 @@
package neofs
import (
"errors"
"testing"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"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))
})
}
}