diff --git a/cmd/http-gw/integration_test.go b/cmd/http-gw/integration_test.go index 2596bee..8e3716d 100644 --- a/cmd/http-gw/integration_test.go +++ b/cmd/http-gw/integration_test.go @@ -20,9 +20,11 @@ import ( containerv2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" + cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" @@ -94,6 +96,7 @@ func TestIntegration(t *testing.T) { t.Run("get by attribute "+version, func(t *testing.T) { getByAttr(ctx, t, clientPool, ownerID, CID) }) t.Run("get zip "+version, func(t *testing.T) { getZip(ctx, t, clientPool, ownerID, CID) }) t.Run("test namespaces "+version, func(t *testing.T) { checkNamespaces(ctx, t, clientPool, ownerID, CID) }) + t.Run("test status codes "+version, func(t *testing.T) { checkStatusCodes(ctx, t, clientPool, ownerID, version) }) cancel() server.Wait() @@ -260,7 +263,7 @@ func putWithDuplicateKeys(t *testing.T, CID cid.ID) { body, err := io.ReadAll(resp.Body) require.NoError(t, err) - require.Equal(t, "key duplication error: "+attr+"\n", string(body)) + require.Contains(t, string(body), "key duplication error: "+attr+"\n") require.Equal(t, http.StatusBadRequest, resp.StatusCode) } @@ -429,7 +432,80 @@ func checkNamespaces(ctx context.Context, t *testing.T, clientPool *pool.Pool, o resp, err = http.DefaultClient.Do(req) require.NoError(t, err) require.Equal(t, http.StatusNotFound, resp.StatusCode) +} +func checkStatusCodes(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, version string) { + cli := http.Client{Timeout: 30 * time.Second} + + t.Run("container not found by name", func(t *testing.T) { + resp, err := cli.Get(testHost + "/get/unknown/object") + require.NoError(t, err) + require.Equal(t, http.StatusNotFound, resp.StatusCode) + requireBodyContains(t, resp, "container not found") + }) + + t.Run("container not found by cid", func(t *testing.T) { + cnrIDTest := cidtest.ID() + resp, err := cli.Get(testHost + "/get/" + cnrIDTest.EncodeToString() + "/object") + require.NoError(t, err) + requireBodyContains(t, resp, "container not found") + require.Equal(t, http.StatusNotFound, resp.StatusCode) + }) + + t.Run("object not found in storage", func(t *testing.T) { + resp, err := cli.Get(testHost + "/get_by_attribute/" + testContainerName + "/FilePath/object2") + require.NoError(t, err) + requireBodyContains(t, resp, "object not found") + require.Equal(t, http.StatusNotFound, resp.StatusCode) + }) + + t.Run("access denied", func(t *testing.T) { + basicACL := acl.Private + var recs []*eacl.Record + if version == "1.2.7" { + basicACL = acl.PublicRWExtended + rec := eacl.NewRecord() + rec.SetAction(eacl.ActionDeny) + rec.SetOperation(eacl.OperationGet) + recs = append(recs, rec) + } + + cnrID, err := createContainerBase(ctx, t, clientPool, ownerID, basicACL, "") + require.NoError(t, err) + + key, err := keys.NewPrivateKey() + require.NoError(t, err) + jsonToken, _ := makeBearerTokens(t, key, ownerID, version, recs...) + + t.Run("get", func(t *testing.T) { + request, err := http.NewRequest(http.MethodGet, testHost+"/get/"+cnrID.EncodeToString()+"/object", nil) + require.NoError(t, err) + request.Header.Set("Authorization", "Bearer "+jsonToken) + + resp, err := cli.Do(request) + require.NoError(t, err) + requireBodyContains(t, resp, "access denied") + require.Equal(t, http.StatusForbidden, resp.StatusCode) + }) + + t.Run("upload", func(t *testing.T) { + request, _, _ := makePutRequest(t, testHost+"/upload/"+cnrID.EncodeToString()) + request.Header.Set("Authorization", "Bearer "+jsonToken) + + resp, err := cli.Do(request) + require.NoError(t, err) + requireBodyContains(t, resp, "access denied") + require.Equal(t, http.StatusForbidden, resp.StatusCode) + }) + }) +} + +func requireBodyContains(t *testing.T, resp *http.Response, msg string) { + data, err := io.ReadAll(resp.Body) + require.NoError(t, err) + defer resp.Body.Close() + + require.Contains(t, strings.ToLower(string(data)), strings.ToLower(msg)) } func createDockerContainer(ctx context.Context, t *testing.T, image string) testcontainers.Container { @@ -478,6 +554,10 @@ func getPool(ctx context.Context, t *testing.T, key *keys.PrivateKey) *pool.Pool } func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID) (cid.ID, error) { + return createContainerBase(ctx, t, clientPool, ownerID, acl.PublicRWExtended, testContainerName) +} + +func createContainerBase(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, basicACL acl.Basic, cnrName string) (cid.ID, error) { var policy netmap.PlacementPolicy err := policy.DecodeString("REP 1") require.NoError(t, err) @@ -485,24 +565,28 @@ func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, o var cnr container.Container cnr.Init() cnr.SetPlacementPolicy(policy) - cnr.SetBasicACL(acl.PublicRWExtended) + cnr.SetBasicACL(basicACL) cnr.SetOwner(ownerID) container.SetCreationTime(&cnr, time.Now()) - var domain container.Domain - domain.SetName(testContainerName) + if cnrName != "" { + var domain container.Domain + domain.SetName(cnrName) - cnr.SetAttribute(containerv2.SysAttributeName, domain.Name()) - cnr.SetAttribute(containerv2.SysAttributeZone, domain.Zone()) + cnr.SetAttribute(containerv2.SysAttributeName, domain.Name()) + cnr.SetAttribute(containerv2.SysAttributeZone, domain.Zone()) + } - var waitPrm pool.WaitParams - waitPrm.SetTimeout(15 * time.Second) - waitPrm.SetPollInterval(3 * time.Second) - - var prm pool.PrmContainerPut - prm.SetContainer(cnr) - prm.SetWaitParams(waitPrm) + prm := pool.PrmContainerPut{ + ClientParams: client.PrmContainerPut{ + Container: &cnr, + }, + WaitParams: &pool.WaitParams{ + Timeout: 15 * time.Second, + PollInterval: 3 * time.Second, + }, + } CID, err := clientPool.PutContainer(ctx, prm) if err != nil { @@ -549,13 +633,18 @@ func registerUser(t *testing.T, ctx context.Context, aioContainer testcontainers require.NoError(t, err) } -func makeBearerTokens(t *testing.T, key *keys.PrivateKey, ownerID user.ID, version string) (jsonTokenBase64, binaryTokenBase64 string) { +func makeBearerTokens(t *testing.T, key *keys.PrivateKey, ownerID user.ID, version string, records ...*eacl.Record) (jsonTokenBase64, binaryTokenBase64 string) { tkn := new(bearer.Token) tkn.ForUser(ownerID) tkn.SetExp(10000) if version == "1.2.7" { - tkn.SetEACLTable(*eacl.NewTable()) + table := eacl.NewTable() + for i := range records { + table.AddRecord(records[i]) + } + + tkn.SetEACLTable(*table) } else { tkn.SetImpersonate(true) }