forked from TrueCloudLab/frostfs-node
[#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>
This commit is contained in:
parent
acb4a9e5b4
commit
e610d1ea5f
2 changed files with 122 additions and 6 deletions
|
@ -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 {
|
||||
|
|
101
pkg/services/container/morph/executor_test.go
Normal file
101
pkg/services/container/morph/executor_test.go
Normal 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
|
||||
}
|
Loading…
Reference in a new issue