forked from TrueCloudLab/frostfs-s3-gw
[#413] Add signature for tree requests
Signed-off-by: Denis Kirillov <denis@nspcc.ru> Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
5e3220a622
commit
1e86413667
3 changed files with 102 additions and 27 deletions
|
@ -142,7 +142,7 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
||||||
}
|
}
|
||||||
|
|
||||||
treeServiceEndpoint := v.GetString(cfgTreeServiceEndpoint)
|
treeServiceEndpoint := v.GetString(cfgTreeServiceEndpoint)
|
||||||
treeService, err := neofs.NewTreeClient(treeServiceEndpoint)
|
treeService, err := neofs.NewTreeClient(treeServiceEndpoint, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Fatal("failed to create tree service", zap.Error(err))
|
l.Fatal("failed to create tree service", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||||
"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/nspcc-dev/neofs-s3-gw/api/layer"
|
||||||
|
@ -20,6 +21,7 @@ import (
|
||||||
|
|
||||||
type (
|
type (
|
||||||
TreeClient struct {
|
TreeClient struct {
|
||||||
|
key *keys.PrivateKey
|
||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
service tree.TreeServiceClient
|
service tree.TreeServiceClient
|
||||||
}
|
}
|
||||||
|
@ -56,7 +58,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTreeClient creates instance of TreeClient using provided address and create grpc connection.
|
// NewTreeClient creates instance of TreeClient using provided address and create grpc connection.
|
||||||
func NewTreeClient(addr string) (*TreeClient, error) {
|
func NewTreeClient(addr string, key *keys.PrivateKey) (*TreeClient, error) {
|
||||||
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("did not connect: %v", err)
|
return nil, fmt.Errorf("did not connect: %v", err)
|
||||||
|
@ -65,6 +67,7 @@ func NewTreeClient(addr string) (*TreeClient, error) {
|
||||||
c := tree.NewTreeServiceClient(conn)
|
c := tree.NewTreeServiceClient(conn)
|
||||||
|
|
||||||
return &TreeClient{
|
return &TreeClient{
|
||||||
|
key: key,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
service: c,
|
service: c,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -299,11 +302,11 @@ func (c *TreeClient) AddSystemVersion(ctx context.Context, cnrID *cid.ID, filepa
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TreeClient) RemoveVersion(ctx context.Context, cnrID *cid.ID, id uint64) error {
|
func (c *TreeClient) RemoveVersion(ctx context.Context, cnrID *cid.ID, id uint64) error {
|
||||||
return c.removeVersion(ctx, cnrID, versionTree, id)
|
return c.removeNode(ctx, cnrID, versionTree, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TreeClient) RemoveSystemVersion(ctx context.Context, cnrID *cid.ID, id uint64) error {
|
func (c *TreeClient) RemoveSystemVersion(ctx context.Context, cnrID *cid.ID, id uint64) error {
|
||||||
return c.removeVersion(ctx, cnrID, systemTree, id)
|
return c.removeNode(ctx, cnrID, systemTree, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TreeClient) Close() error {
|
func (c *TreeClient) Close() error {
|
||||||
|
@ -346,20 +349,6 @@ func (c *TreeClient) addVersion(ctx context.Context, cnrID *cid.ID, treeID, attr
|
||||||
return c.addNodeByPath(ctx, cnrID, treeID, path[:len(path)-1], meta)
|
return c.addNodeByPath(ctx, cnrID, treeID, path[:len(path)-1], meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TreeClient) removeVersion(ctx context.Context, cnrID *cid.ID, treeID string, id uint64) error {
|
|
||||||
request := &tree.RemoveRequest{
|
|
||||||
Body: &tree.RemoveRequest_Body{
|
|
||||||
ContainerId: []byte(cnrID.EncodeToString()),
|
|
||||||
TreeId: treeID,
|
|
||||||
NodeId: id,
|
|
||||||
BearerToken: getBearer(ctx),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := c.service.Remove(ctx, request)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TreeClient) getVersions(ctx context.Context, cnrID *cid.ID, treeID, filepath string, onlyUnversioned bool) ([]*layer.NodeVersion, error) {
|
func (c *TreeClient) getVersions(ctx context.Context, cnrID *cid.ID, treeID, filepath string, onlyUnversioned bool) ([]*layer.NodeVersion, error) {
|
||||||
keysToReturn := []string{oidKV, isUnversionedKV, isDeleteMarkerKV}
|
keysToReturn := []string{oidKV, isUnversionedKV, isDeleteMarkerKV}
|
||||||
path := strings.Split(filepath, separator)
|
path := strings.Split(filepath, separator)
|
||||||
|
@ -391,13 +380,22 @@ func (c *TreeClient) getVersions(ctx context.Context, cnrID *cid.ID, treeID, fil
|
||||||
func (c *TreeClient) getParent(ctx context.Context, cnrID *cid.ID, treeID string, id uint64) (uint64, error) {
|
func (c *TreeClient) getParent(ctx context.Context, cnrID *cid.ID, treeID string, id uint64) (uint64, error) {
|
||||||
request := &tree.GetSubTreeRequest{
|
request := &tree.GetSubTreeRequest{
|
||||||
Body: &tree.GetSubTreeRequest_Body{
|
Body: &tree.GetSubTreeRequest_Body{
|
||||||
ContainerId: []byte(cnrID.EncodeToString()),
|
ContainerId: cnrID[:],
|
||||||
TreeId: treeID,
|
TreeId: treeID,
|
||||||
RootId: id,
|
RootId: id,
|
||||||
BearerToken: getBearer(ctx),
|
BearerToken: getBearer(ctx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.signRequest(request.Body, func(key, sign []byte) {
|
||||||
|
request.Signature = &tree.Signature{
|
||||||
|
Key: key,
|
||||||
|
Sign: sign,
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
cli, err := c.service.GetSubTree(ctx, request)
|
cli, err := c.service.GetSubTree(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("failed to get sub tree client: %w", err)
|
return 0, fmt.Errorf("failed to get sub tree client: %w", err)
|
||||||
|
@ -446,7 +444,7 @@ func (c *TreeClient) getNode(ctx context.Context, cnrID *cid.ID, treeID, pathAtt
|
||||||
func (c *TreeClient) getNodes(ctx context.Context, cnrID *cid.ID, treeID, pathAttr string, path, meta []string, latestOnly bool) ([]*tree.GetNodeByPathResponse_Info, error) {
|
func (c *TreeClient) getNodes(ctx context.Context, cnrID *cid.ID, treeID, pathAttr string, path, meta []string, latestOnly bool) ([]*tree.GetNodeByPathResponse_Info, error) {
|
||||||
request := &tree.GetNodeByPathRequest{
|
request := &tree.GetNodeByPathRequest{
|
||||||
Body: &tree.GetNodeByPathRequest_Body{
|
Body: &tree.GetNodeByPathRequest_Body{
|
||||||
ContainerId: []byte(cnrID.EncodeToString()),
|
ContainerId: cnrID[:],
|
||||||
TreeId: treeID,
|
TreeId: treeID,
|
||||||
Path: path,
|
Path: path,
|
||||||
Attributes: meta,
|
Attributes: meta,
|
||||||
|
@ -456,9 +454,18 @@ func (c *TreeClient) getNodes(ctx context.Context, cnrID *cid.ID, treeID, pathAt
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.signRequest(request.Body, func(key, sign []byte) {
|
||||||
|
request.Signature = &tree.Signature{
|
||||||
|
Key: key,
|
||||||
|
Sign: sign,
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.service.GetNodeByPath(ctx, request)
|
resp, err := c.service.GetNodeByPath(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get node path: %w", err)
|
return nil, fmt.Errorf("failed to get node path deb: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.GetBody().GetNodes(), nil
|
return resp.GetBody().GetNodes(), nil
|
||||||
|
@ -476,13 +483,21 @@ func getBearer(ctx context.Context) []byte {
|
||||||
func (c *TreeClient) addNode(ctx context.Context, cnrID *cid.ID, treeID string, parent uint64, meta map[string]string) (uint64, error) {
|
func (c *TreeClient) addNode(ctx context.Context, cnrID *cid.ID, treeID string, parent uint64, meta map[string]string) (uint64, error) {
|
||||||
request := &tree.AddRequest{
|
request := &tree.AddRequest{
|
||||||
Body: &tree.AddRequest_Body{
|
Body: &tree.AddRequest_Body{
|
||||||
ContainerId: []byte(cnrID.EncodeToString()),
|
ContainerId: cnrID[:],
|
||||||
TreeId: treeID,
|
TreeId: treeID,
|
||||||
ParentId: parent,
|
ParentId: parent,
|
||||||
Meta: metaToKV(meta),
|
Meta: metaToKV(meta),
|
||||||
BearerToken: getBearer(ctx),
|
BearerToken: getBearer(ctx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if err := c.signRequest(request.Body, func(key, sign []byte) {
|
||||||
|
request.Signature = &tree.Signature{
|
||||||
|
Key: key,
|
||||||
|
Sign: sign,
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.service.Add(ctx, request)
|
resp, err := c.service.Add(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -495,7 +510,7 @@ func (c *TreeClient) addNode(ctx context.Context, cnrID *cid.ID, treeID string,
|
||||||
func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID string, path []string, meta map[string]string) error {
|
func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID string, path []string, meta map[string]string) error {
|
||||||
request := &tree.AddByPathRequest{
|
request := &tree.AddByPathRequest{
|
||||||
Body: &tree.AddByPathRequest_Body{
|
Body: &tree.AddByPathRequest_Body{
|
||||||
ContainerId: []byte(cnrID.EncodeToString()),
|
ContainerId: cnrID[:],
|
||||||
TreeId: treeID,
|
TreeId: treeID,
|
||||||
Path: path,
|
Path: path,
|
||||||
Meta: metaToKV(meta),
|
Meta: metaToKV(meta),
|
||||||
|
@ -504,6 +519,15 @@ func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID st
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.signRequest(request.Body, func(key, sign []byte) {
|
||||||
|
request.Signature = &tree.Signature{
|
||||||
|
Key: key,
|
||||||
|
Sign: sign,
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_, err := c.service.AddByPath(ctx, request)
|
_, err := c.service.AddByPath(ctx, request)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -511,28 +535,47 @@ func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID st
|
||||||
func (c *TreeClient) moveNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID, parentID uint64, meta map[string]string) error {
|
func (c *TreeClient) moveNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID, parentID uint64, meta map[string]string) error {
|
||||||
request := &tree.MoveRequest{
|
request := &tree.MoveRequest{
|
||||||
Body: &tree.MoveRequest_Body{
|
Body: &tree.MoveRequest_Body{
|
||||||
ContainerId: []byte(cnrID.EncodeToString()),
|
ContainerId: cnrID[:],
|
||||||
TreeId: treeID,
|
TreeId: treeID,
|
||||||
NodeId: nodeID,
|
NodeId: nodeID,
|
||||||
ParentId: parentID,
|
ParentId: parentID,
|
||||||
Meta: metaToKV(meta),
|
Meta: metaToKV(meta),
|
||||||
|
BearerToken: getBearer(ctx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.signRequest(request.Body, func(key, sign []byte) {
|
||||||
|
request.Signature = &tree.Signature{
|
||||||
|
Key: key,
|
||||||
|
Sign: sign,
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_, err := c.service.Move(ctx, request)
|
_, err := c.service.Move(ctx, request)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TreeClient) removeNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID uint64) error {
|
func (c *TreeClient) removeNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID uint64) error {
|
||||||
r := &tree.RemoveRequest{
|
request := &tree.RemoveRequest{
|
||||||
Body: &tree.RemoveRequest_Body{
|
Body: &tree.RemoveRequest_Body{
|
||||||
ContainerId: []byte(cnrID.EncodeToString()),
|
ContainerId: cnrID[:],
|
||||||
TreeId: treeID,
|
TreeId: treeID,
|
||||||
NodeId: nodeID,
|
NodeId: nodeID,
|
||||||
BearerToken: getBearer(ctx),
|
BearerToken: getBearer(ctx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err := c.service.Remove(ctx, r)
|
if err := c.signRequest(request.Body, func(key, sign []byte) {
|
||||||
|
request.Signature = &tree.Signature{
|
||||||
|
Key: key,
|
||||||
|
Sign: sign,
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.service.Remove(ctx, request)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
internal/neofs/tree_signature.go
Normal file
32
internal/neofs/tree_signature.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/* REMOVE THIS AFTER SIGNATURE WILL BE AVAILABLE IN TREE CLIENT FROM NEOFS NODE */
|
||||||
|
package neofs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha512"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *TreeClient) signData(buf []byte, f func(key, sign []byte)) error {
|
||||||
|
hash := sha512.Sum512(buf)
|
||||||
|
x, y, err := ecdsa.Sign(rand.Reader, &c.key.PrivateKey, hash[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sign := elliptic.Marshal(elliptic.P256(), x, y)
|
||||||
|
|
||||||
|
f(c.key.PublicKey().Bytes(), sign)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TreeClient) signRequest(requestBody proto.Message, f func(key, sign []byte)) error {
|
||||||
|
buf, err := proto.Marshal(requestBody)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.signData(buf, f)
|
||||||
|
}
|
Loading…
Reference in a new issue