frostfs-node/pkg/services/object/acl/v2/util_test.go
Leonard Lyubich e54b52ec03 [#1420] object/acl: Fix correlation of object session to request
In previous implementation of `neofs-node` app object session was not
checked for substitution of the object related to it. Also, for access
checks, the session object was substituted instead of the one from the
request. This, on the one hand, made it possible to inherit the session
from the parent object for authorization for certain actions. On the
other hand, it covered the mentioned object substitution, which is a
critical vulnerability.

Next changes are applied to processing of all Object service requests:
 - check if object session relates to the requested object
 - use requested object in access checks.

Disclosed problem of object context inheritance will be solved within

Signed-off-by: Leonard Lyubich <ctulhurider@gmail.com>
2022-10-07 10:34:38 +03:00

136 lines
4 KiB
Go

package v2
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"testing"
"github.com/nspcc-dev/neofs-api-go/v2/acl"
"github.com/nspcc-dev/neofs-api-go/v2/session"
bearertest "github.com/nspcc-dev/neofs-sdk-go/bearer/test"
aclsdk "github.com/nspcc-dev/neofs-sdk-go/container/acl"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
"github.com/stretchr/testify/require"
)
func TestOriginalTokens(t *testing.T) {
sToken := sessiontest.ObjectSigned()
bToken := bearertest.Token()
pk, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, bToken.Sign(*pk))
var bTokenV2 acl.BearerToken
bToken.WriteToV2(&bTokenV2)
// This line is needed because SDK uses some custom format for
// reserved filters, so `cid.ID` is not converted to string immediately.
require.NoError(t, bToken.ReadFromV2(bTokenV2))
var sTokenV2 session.Token
sToken.WriteToV2(&sTokenV2)
for i := 0; i < 10; i++ {
metaHeaders := testGenerateMetaHeader(uint32(i), &bTokenV2, &sTokenV2)
res, err := originalSessionToken(metaHeaders)
require.NoError(t, err)
require.Equal(t, sToken, res, i)
bTok, err := originalBearerToken(metaHeaders)
require.NoError(t, err)
require.Equal(t, &bToken, bTok, i)
}
}
func testGenerateMetaHeader(depth uint32, b *acl.BearerToken, s *session.Token) *session.RequestMetaHeader {
metaHeader := new(session.RequestMetaHeader)
metaHeader.SetBearerToken(b)
metaHeader.SetSessionToken(s)
for i := uint32(0); i < depth; i++ {
link := metaHeader
metaHeader = new(session.RequestMetaHeader)
metaHeader.SetOrigin(link)
}
return metaHeader
}
func TestIsVerbCompatible(t *testing.T) {
// Source: https://nspcc.ru/upload/neofs-spec-latest.pdf#page=28
table := map[aclsdk.Op][]sessionSDK.ObjectVerb{
aclsdk.OpObjectPut: {sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete},
aclsdk.OpObjectDelete: {sessionSDK.VerbObjectDelete},
aclsdk.OpObjectGet: {sessionSDK.VerbObjectGet},
aclsdk.OpObjectHead: {
sessionSDK.VerbObjectHead,
sessionSDK.VerbObjectGet,
sessionSDK.VerbObjectDelete,
sessionSDK.VerbObjectRange,
sessionSDK.VerbObjectRangeHash,
},
aclsdk.OpObjectRange: {sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash},
aclsdk.OpObjectHash: {sessionSDK.VerbObjectRangeHash},
aclsdk.OpObjectSearch: {sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete},
}
verbs := []sessionSDK.ObjectVerb{
sessionSDK.VerbObjectPut,
sessionSDK.VerbObjectDelete,
sessionSDK.VerbObjectHead,
sessionSDK.VerbObjectRange,
sessionSDK.VerbObjectRangeHash,
sessionSDK.VerbObjectGet,
sessionSDK.VerbObjectSearch,
}
var tok sessionSDK.Object
for op, list := range table {
for _, verb := range verbs {
var contains bool
for _, v := range list {
if v == verb {
contains = true
break
}
}
tok.ForVerb(verb)
require.Equal(t, contains, assertVerb(tok, op),
"%v in token, %s executing", verb, op)
}
}
}
func TestAssertSessionRelation(t *testing.T) {
var tok sessionSDK.Object
cnr := cidtest.ID()
cnrOther := cidtest.ID()
obj := oidtest.ID()
objOther := oidtest.ID()
// make sure ids differ, otherwise test won't work correctly
require.False(t, cnrOther.Equals(cnr))
require.False(t, objOther.Equals(obj))
// bind session to the container (required)
tok.BindContainer(cnr)
// test container-global session
require.NoError(t, assertSessionRelation(tok, cnr, nil))
require.NoError(t, assertSessionRelation(tok, cnr, &obj))
require.Error(t, assertSessionRelation(tok, cnrOther, nil))
require.Error(t, assertSessionRelation(tok, cnrOther, &obj))
// limit the session to the particular object
tok.LimitByObjects(obj)
// test fixed object session (here obj arg must be non-nil everywhere)
require.NoError(t, assertSessionRelation(tok, cnr, &obj))
require.Error(t, assertSessionRelation(tok, cnr, &objOther))
}