frostfs-s3-gw/internal/frostfs/authmate_test.go

287 lines
8.4 KiB
Go
Raw Normal View History

package frostfs
import (
"context"
"errors"
"strconv"
"strings"
"testing"
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)
func TestCredsObject(t *testing.T) {
ctx, bktName, payload, newPayload := context.Background(), "bucket", []byte("payload"), []byte("new-payload")
key, err := keys.NewPrivateKey()
require.NoError(t, err)
var userID user.ID
userID.SetScriptHash(key.PublicKey().GetScriptHash())
var token bearer.Token
err = token.Sign(key.PrivateKey)
require.NoError(t, err)
ctx = middleware.SetBox(ctx, &middleware.Box{AccessBox: &accessbox.Box{
Gate: &accessbox.GateData{
BearerToken: &token,
},
}})
frostfs := NewAuthmateFrostFS(layer.NewTestFrostFS(key), zaptest.NewLogger(t))
cnrID, err := frostfs.CreateContainer(ctx, authmate.PrmContainerCreate{
FriendlyName: bktName,
Owner: userID,
})
require.NoError(t, err)
t.Run("regular access key", func(t *testing.T) {
attr1 := object.NewAttribute()
attr1.SetKey("attr1")
attr1.SetValue("val1")
prm := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "regular-obj",
ExpirationEpoch: 10,
Payload: payload,
CustomAttributes: []object.Attribute{*attr1},
}
objID, err := frostfs.CreateObject(ctx, prm)
require.NoError(t, err)
accessKeyID := cnrID.EncodeToString() + "0" + objID.EncodeToString()
obj, err := frostfs.GetCredsObject(ctx, tokens.PrmGetCredsObject{Container: cnrID, AccessKeyID: accessKeyID})
require.NoError(t, err)
assertParamsSet(t, prm, obj, userID)
t.Run("update existing", func(t *testing.T) {
attr2 := object.NewAttribute()
attr2.SetKey("attr2")
attr2.SetValue("val2")
prmNew := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "regular-obj-new",
ExpirationEpoch: 11,
Payload: newPayload,
CustomAttributes: []object.Attribute{*attr2},
NewVersionForAccessKeyID: accessKeyID,
}
_, err = frostfs.CreateObject(ctx, prmNew)
require.NoError(t, err)
obj, err = frostfs.GetCredsObject(ctx, tokens.PrmGetCredsObject{Container: cnrID, AccessKeyID: accessKeyID})
require.NoError(t, err)
assertParamsSet(t, prmNew, obj, userID)
})
t.Run("update not existing", func(t *testing.T) {
attr2 := object.NewAttribute()
attr2.SetKey("attr2")
attr2.SetValue("val2")
addr := oidtest.Address()
accessKeyIDNotExisting := getAccessKeyID(addr)
prmNew := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "regular-obj-new",
ExpirationEpoch: 11,
Payload: newPayload,
CustomAttributes: []object.Attribute{*attr2},
NewVersionForAccessKeyID: accessKeyIDNotExisting,
}
_, err = frostfs.CreateObject(ctx, prmNew)
require.NoError(t, err)
obj, err = frostfs.GetCredsObject(ctx, tokens.PrmGetCredsObject{Container: cnrID, AccessKeyID: accessKeyIDNotExisting})
require.NoError(t, err)
assertParamsSet(t, prmNew, obj, userID)
})
})
t.Run("custom access key", func(t *testing.T) {
attr1 := object.NewAttribute()
attr1.SetKey("attr1")
attr1.SetValue("val1")
accessKeyID := "custom-access-key-id"
prm := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "custom-obj",
ExpirationEpoch: 10,
Payload: payload,
CustomAccessKey: accessKeyID,
CustomAttributes: []object.Attribute{*attr1},
}
_, err = frostfs.CreateObject(ctx, prm)
require.NoError(t, err)
obj, err := frostfs.GetCredsObject(ctx, tokens.PrmGetCredsObject{Container: cnrID, AccessKeyID: accessKeyID})
require.NoError(t, err)
assertParamsSet(t, prm, obj, userID)
t.Run("update", func(t *testing.T) {
attr2 := object.NewAttribute()
attr2.SetKey("attr2")
attr2.SetValue("val2")
prmNew := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "custom-obj-new",
ExpirationEpoch: 11,
Payload: newPayload,
CustomAttributes: []object.Attribute{*attr2},
NewVersionForAccessKeyID: accessKeyID,
}
_, err = frostfs.CreateObject(ctx, prmNew)
require.NoError(t, err)
obj, err = frostfs.GetCredsObject(ctx, tokens.PrmGetCredsObject{Container: cnrID, AccessKeyID: accessKeyID})
require.NoError(t, err)
assertParamsSet(t, prmNew, obj, userID)
})
t.Run("update not existing", func(t *testing.T) {
accessKeyIDNotExisting := "unknown"
prmNew := tokens.PrmObjectCreate{
Container: cnrID,
Payload: newPayload,
NewVersionForAccessKeyID: accessKeyIDNotExisting,
}
_, err = frostfs.CreateObject(ctx, prmNew)
require.Error(t, err)
})
})
t.Run("fallback", func(t *testing.T) {
t.Run("regular", func(t *testing.T) {
prm := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "regular-obj",
Payload: payload,
}
objID, err := frostfs.CreateObject(ctx, prm)
require.NoError(t, err)
accessKeyID := cnrID.EncodeToString() + "0" + objID.EncodeToString()
prmNew := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "regular-obj-new",
Payload: newPayload,
NewVersionForAccessKeyID: accessKeyID,
}
objIDNew, err := frostfs.CreateObject(ctx, prmNew)
require.NoError(t, err)
addr := newAddress(cnrID, objID)
prmFallback := tokens.PrmGetCredsObject{
Container: cnrID,
AccessKeyID: accessKeyID,
FallbackAddress: &addr,
}
frostfs.frostFS.(*layer.TestFrostFS).SetObjectError(newAddress(cnrID, objIDNew), errors.New("error"))
obj, err := frostfs.GetCredsObject(ctx, prmFallback)
require.NoError(t, err)
assertParamsSet(t, prm, obj, userID)
})
t.Run("custom", func(t *testing.T) {
prm := tokens.PrmObjectCreate{
Container: cnrID,
Filepath: "custom-obj",
ExpirationEpoch: 10,
Payload: payload,
CustomAccessKey: "custom-access-key-id",
}
objID, err := frostfs.CreateObject(ctx, prm)
require.NoError(t, err)
addr := newAddress(cnrID, objID)
prmFallback := tokens.PrmGetCredsObject{
Container: cnrID,
AccessKeyID: "unknown",
FallbackAddress: &addr,
}
obj, err := frostfs.GetCredsObject(ctx, prmFallback)
require.NoError(t, err)
assertParamsSet(t, prm, obj, userID)
})
})
}
func newAddress(cnr cid.ID, obj oid.ID) oid.Address {
var addr oid.Address
addr.SetContainer(cnr)
addr.SetObject(obj)
return addr
}
func assertParamsSet(t *testing.T, prm tokens.PrmObjectCreate, obj *object.Object, userID user.ID) {
require.Equal(t, prm.Payload, obj.Payload())
require.True(t, userID.Equals(obj.OwnerID()), "owners not matched")
require.True(t, containerAttribute(obj.Attributes(), object.AttributeFilePath, prm.Filepath), "missing FilePath")
require.True(t, containerAttribute(obj.Attributes(), objectv2.SysAttributeExpEpoch, strconv.FormatUint(prm.ExpirationEpoch, 10)), "missing expiration epoch")
var crdtName string
if prm.CustomAccessKey != "" {
crdtName = prm.CustomAccessKey
} else if prm.NewVersionForAccessKeyID != "" {
crdtName = prm.NewVersionForAccessKeyID
}
if crdtName != "" {
require.Truef(t, containerAttribute(obj.Attributes(), accessBoxCRDTNameAttr, crdtName), "wrong crdt name '%s'", crdtName)
}
for _, attr := range prm.CustomAttributes {
require.True(t, containerAttribute(obj.Attributes(), attr.Key(), attr.Value()), "missing custom attribute")
}
}
func containerAttribute(attrs []object.Attribute, key, val string) bool {
for _, attr := range attrs {
if attr.Key() == key && attr.Value() == val {
return true
}
}
return false
}
func getAccessKeyID(addr oid.Address) string {
return strings.ReplaceAll(addr.EncodeToString(), "/", "0")
}