[#1045] Provide sanity check of session token in container service

Without sanity check, container service provides successful response,
even though such request will never be approved by Alphabet nodes.

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
support/v0.27
Alex Vanin 2021-12-16 18:26:13 +03:00 committed by Alex Vanin
parent acb4a9e5b4
commit e610d1ea5f
2 changed files with 122 additions and 6 deletions

View File

@ -2,6 +2,7 @@ package container
import (
"context"
"errors"
"github.com/nspcc-dev/neofs-api-go/v2/container"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
@ -42,6 +43,10 @@ type Writer interface {
PutEACL(*eaclSDK.Table) error
}
// ErrInvalidContext is thrown by morph ServiceExecutor when provided session
// token does not contain expected container context.
var ErrInvalidContext = errors.New("session token does not contain container context")
func NewExecutor(rdr Reader, wrt Writer) containerSvc.ServiceExecutor {
return &morphExecutor{
rdr: rdr,
@ -56,9 +61,12 @@ func (s *morphExecutor) Put(ctx containerSvc.ContextWithToken, body *container.P
signature.NewFromV2(body.GetSignature()),
)
cnr.SetSessionToken(
session.NewTokenFromV2(ctx.SessionToken),
)
tok := session.NewTokenFromV2(ctx.SessionToken)
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
return nil, ErrInvalidContext
}
cnr.SetSessionToken(tok)
cid, err := s.wrt.Put(cnr)
if err != nil {
@ -74,7 +82,11 @@ func (s *morphExecutor) Put(ctx containerSvc.ContextWithToken, body *container.P
func (s *morphExecutor) Delete(ctx containerSvc.ContextWithToken, body *container.DeleteRequestBody) (*container.DeleteResponseBody, error) {
id := cid.NewFromV2(body.GetContainerID())
sig := body.GetSignature().GetSign()
tok := session.NewTokenFromV2(ctx.SessionToken)
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
return nil, ErrInvalidContext
}
var rmWitness containercore.RemovalWitness
@ -131,9 +143,12 @@ func (s *morphExecutor) SetExtendedACL(ctx containerSvc.ContextWithToken, body *
table.SetSignature(sign)
table.SetSessionToken(
session.NewTokenFromV2(ctx.SessionToken),
)
tok := session.NewTokenFromV2(ctx.SessionToken)
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
return nil, ErrInvalidContext
}
table.SetSessionToken(tok)
err := s.wrt.PutEACL(table)
if err != nil {

View File

@ -0,0 +1,101 @@
package container_test
import (
"context"
"testing"
"github.com/nspcc-dev/neofs-api-go/v2/container"
"github.com/nspcc-dev/neofs-api-go/v2/session"
containerCore "github.com/nspcc-dev/neofs-node/pkg/core/container"
containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container"
containerSvcMorph "github.com/nspcc-dev/neofs-node/pkg/services/container/morph"
containerSDK "github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/owner"
"github.com/stretchr/testify/require"
)
type mock struct{}
func (m mock) Put(c *containerSDK.Container) (*cid.ID, error) {
return new(cid.ID), nil
}
func (m mock) Delete(witness containerCore.RemovalWitness) error {
return nil
}
func (m mock) PutEACL(table *eacl.Table) error {
return nil
}
func (m mock) Get(id *cid.ID) (*containerSDK.Container, error) {
panic("implement me")
}
func (m mock) GetEACL(id *cid.ID) (*eacl.Table, error) {
panic("implement me")
}
func (m mock) List(id *owner.ID) ([]*cid.ID, error) {
panic("implement me")
}
func TestInvalidToken(t *testing.T) {
m := mock{}
e := containerSvcMorph.NewExecutor(m, m)
tests := []struct {
name string
op func(e containerSvc.ServiceExecutor, ctx containerSvc.ContextWithToken) error
}{
{
name: "put",
op: func(e containerSvc.ServiceExecutor, ctx containerSvc.ContextWithToken) (err error) {
_, err = e.Put(ctx, new(container.PutRequestBody))
return
},
},
{
name: "delete",
op: func(e containerSvc.ServiceExecutor, ctx containerSvc.ContextWithToken) (err error) {
_, err = e.Delete(ctx, new(container.DeleteRequestBody))
return
},
},
{
name: "setEACL",
op: func(e containerSvc.ServiceExecutor, ctx containerSvc.ContextWithToken) (err error) {
_, err = e.SetExtendedACL(ctx, new(container.SetExtendedACLRequestBody))
return
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctx := containerSvc.ContextWithToken{
Context: context.Background(),
SessionToken: generateToken(new(session.ObjectSessionContext)),
}
require.Error(t, test.op(e, ctx), containerSvcMorph.ErrInvalidContext)
ctx.SessionToken = generateToken(new(session.ContainerSessionContext))
require.NoError(t, test.op(e, ctx))
ctx.SessionToken = nil
require.NoError(t, test.op(e, ctx))
})
}
}
func generateToken(ctx session.SessionTokenContext) *session.SessionToken {
body := new(session.SessionTokenBody)
body.SetContext(ctx)
tok := new(session.SessionToken)
tok.SetBody(body)
return tok
}