2024-04-26 14:32:58 +00:00
|
|
|
package frostfs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-10-18 13:59:52 +00:00
|
|
|
"errors"
|
2024-10-11 12:20:10 +00:00
|
|
|
"strconv"
|
2024-10-11 08:32:36 +00:00
|
|
|
"strings"
|
2024-04-26 14:32:58 +00:00
|
|
|
"testing"
|
|
|
|
|
2024-10-11 12:20:10 +00:00
|
|
|
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
2024-04-26 14:32:58 +00:00
|
|
|
"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"
|
2024-10-18 13:59:52 +00:00
|
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
2024-10-11 12:20:10 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
2024-04-26 14:32:58 +00:00
|
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
2024-10-11 12:20:10 +00:00
|
|
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
2024-04-26 14:32:58 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
|
|
"github.com/stretchr/testify/require"
|
2024-07-15 12:47:19 +00:00
|
|
|
"go.uber.org/zap/zaptest"
|
2024-04-26 14:32:58 +00:00
|
|
|
)
|
|
|
|
|
2024-10-11 12:20:10 +00:00
|
|
|
func TestCredsObject(t *testing.T) {
|
2024-04-26 14:32:58 +00:00
|
|
|
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,
|
|
|
|
},
|
|
|
|
}})
|
|
|
|
|
2024-07-15 12:47:19 +00:00
|
|
|
frostfs := NewAuthmateFrostFS(layer.NewTestFrostFS(key), zaptest.NewLogger(t))
|
2024-04-26 14:32:58 +00:00
|
|
|
|
2024-10-11 08:32:36 +00:00
|
|
|
cnrID, err := frostfs.CreateContainer(ctx, authmate.PrmContainerCreate{
|
2024-04-26 14:32:58 +00:00
|
|
|
FriendlyName: bktName,
|
2024-11-18 12:31:09 +00:00
|
|
|
Owner: key.PublicKey(),
|
2024-04-26 14:32:58 +00:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2024-10-11 12:20:10 +00:00
|
|
|
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)
|
|
|
|
})
|
2024-04-26 14:32:58 +00:00
|
|
|
})
|
2024-10-11 08:32:36 +00:00
|
|
|
|
2024-10-11 12:20:10 +00:00
|
|
|
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)
|
|
|
|
})
|
2024-10-11 08:32:36 +00:00
|
|
|
})
|
2024-10-18 13:59:52 +00:00
|
|
|
|
|
|
|
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
|
2024-10-11 12:20:10 +00:00
|
|
|
}
|
2024-04-26 14:32:58 +00:00
|
|
|
|
2024-10-11 12:20:10 +00:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
2024-04-26 14:32:58 +00:00
|
|
|
|
2024-10-11 12:20:10 +00:00
|
|
|
func containerAttribute(attrs []object.Attribute, key, val string) bool {
|
|
|
|
for _, attr := range attrs {
|
|
|
|
if attr.Key() == key && attr.Value() == val {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
2024-04-26 14:32:58 +00:00
|
|
|
}
|
2024-10-11 08:32:36 +00:00
|
|
|
|
|
|
|
func getAccessKeyID(addr oid.Address) string {
|
|
|
|
return strings.ReplaceAll(addr.EncodeToString(), "/", "0")
|
|
|
|
}
|