satellite/console: add more tests for uplink access permission

Change-Id: Icb93501df70767b36da68ee5b8ffa98ea67d22c0
This commit is contained in:
igor gaidaienko 2021-05-28 13:11:10 +03:00 committed by Igor
parent b9d7874dc2
commit b1201df82c

View File

@ -4,6 +4,7 @@
package consolewasm_test
import (
"context"
"errors"
"testing"
"time"
@ -12,13 +13,13 @@ import (
"storj.io/common/testcontext"
"storj.io/storj/private/testplanet"
console "storj.io/storj/satellite/console/consolewasm"
"storj.io/storj/satellite/console/consolewasm"
"storj.io/uplink"
)
func TestSetPermissionWithBuckets(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 10, UplinkCount: 1,
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
satellitePeer := planet.Satellites[0]
satelliteNodeURL := satellitePeer.NodeURL().String()
@ -69,7 +70,7 @@ func TestSetPermissionWithBuckets(t *testing.T) {
require.Error(t, err)
// Create restricted access with the console access grant code that allows full access to only 1 bucket.
readOnlyPermission := console.Permission{
readOnlyPermission := consolewasm.Permission{
AllowDownload: true,
AllowUpload: false,
AllowList: true,
@ -77,9 +78,9 @@ func TestSetPermissionWithBuckets(t *testing.T) {
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(48 * time.Hour),
}
restrictedKey, err := console.SetPermission(apiKeyString, buckets, readOnlyPermission)
restrictedKey, err := consolewasm.SetPermission(apiKeyString, buckets, readOnlyPermission)
require.NoError(t, err)
restrictedAccessGrant, err := console.GenAccessGrant(satelliteNodeURL, restrictedKey.Serialize(), passphrase, projectID)
restrictedAccessGrant, err := consolewasm.GenAccessGrant(satelliteNodeURL, restrictedKey.Serialize(), passphrase, projectID)
require.NoError(t, err)
restrictedAccess, err := uplink.ParseAccess(restrictedAccessGrant)
require.NoError(t, err)
@ -97,139 +98,295 @@ func TestSetPermissionWithBuckets(t *testing.T) {
})
}
func TestSetPermissionUplinkOperations(t *testing.T) {
func TestSetPermission_Uplink(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 10, UplinkCount: 1,
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
satellitePeer := planet.Satellites[0]
satelliteNodeURL := satellitePeer.NodeURL().String()
uplinkPeer := planet.Uplinks[0]
APIKey := uplinkPeer.APIKey[satellitePeer.ID()]
apiKeyString := APIKey.Serialize()
projectID := uplinkPeer.Projects[0].ID.String()
require.Equal(t, 1, len(uplinkPeer.Projects))
allPermission := console.Permission{
AllowDownload: true,
AllowUpload: true,
AllowList: true,
AllowDelete: true,
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(48 * time.Hour),
}
restrictedKey, err := console.SetPermission(apiKeyString, []string{}, allPermission)
require.NoError(t, err)
passphrase := "supersecretpassphrase"
restrictedAccessGrant, err := console.GenAccessGrant(satelliteNodeURL, restrictedKey.Serialize(), passphrase, projectID)
require.NoError(t, err)
restrictedAccess, err := uplink.ParseAccess(restrictedAccessGrant)
require.NoError(t, err)
uplinkPeer.APIKey[satellitePeer.ID()] = restrictedKey
uplinkPeer.Access[satellitePeer.ID()] = restrictedAccess
testbucket1 := "buckettest1"
testfilename := "file.txt"
testdata := []byte("fun data")
// Confirm that we can create a bucket, upload/download/delete an object, and delete the bucket with the new restricted access.
require.NoError(t, uplinkPeer.CreateBucket(ctx, satellitePeer, testbucket1))
err = uplinkPeer.Upload(ctx, satellitePeer, testbucket1, testfilename, testdata)
require.NoError(t, err)
data, err := uplinkPeer.Download(ctx, satellitePeer, testbucket1, testfilename)
require.NoError(t, err)
require.Equal(t, data, testdata)
buckets, err := uplinkPeer.ListBuckets(ctx, satellitePeer)
require.NoError(t, err)
require.Equal(t, len(buckets), 1)
err = uplinkPeer.DeleteObject(ctx, satellitePeer, testbucket1, testfilename)
require.NoError(t, err)
require.NoError(t, uplinkPeer.DeleteBucket(ctx, satellitePeer, testbucket1))
})
}
func TestSetTimePermissionWithBucket(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
satellitePeer := planet.Satellites[0]
satelliteNodeURL := satellitePeer.NodeURL().String()
uplinkPeer := planet.Uplinks[0]
APIKey := uplinkPeer.APIKey[satellitePeer.ID()]
apiKeyString := APIKey.Serialize()
projectID := uplinkPeer.Projects[0].ID.String()
require.Equal(t, 1, len(uplinkPeer.Projects))
passphrase := "supersecretpassphrase"
// Create an access grant with the uplink API key. With that access grant, create 1 bucket and upload an object.
// Create an access grant with the uplink API key. With that access grant, create 2 bucket and upload files to them
uplinkAccess, err := uplinkPeer.Config.RequestAccessWithPassphrase(ctx, satelliteNodeURL, apiKeyString, passphrase)
require.NoError(t, err)
uplinkPeer.Access[satellitePeer.ID()] = uplinkAccess
testbucket := "buckettest"
testfilename := "file.txt"
testbucket1 := "buckettest1"
testbucket2 := "buckettest2"
testbucket3 := "buckettest3"
testfilename1 := "file1.txt"
testfilename2 := "file2.txt"
testdata := []byte("fun data")
require.NoError(t, uplinkPeer.CreateBucket(ctx, satellitePeer, testbucket))
require.NoError(t, uplinkPeer.Upload(ctx, satellitePeer, testbucket, testfilename, testdata))
require.NoError(t, uplinkPeer.CreateBucket(ctx, satellitePeer, testbucket1))
require.NoError(t, uplinkPeer.CreateBucket(ctx, satellitePeer, testbucket2))
require.NoError(t, uplinkPeer.Upload(ctx, satellitePeer, testbucket1, testfilename1, testdata))
require.NoError(t, uplinkPeer.Upload(ctx, satellitePeer, testbucket2, testfilename1, testdata))
require.NoError(t, uplinkPeer.Upload(ctx, satellitePeer, testbucket2, testfilename2, testdata))
bucket := []string{testbucket}
withAccessKey(ctx, t, planet, passphrase, "only delete", []string{}, consolewasm.Permission{AllowDelete: true}, func(t *testing.T, project *uplink.Project) {
// All operation except delete should be restricted
_, err = project.CreateBucket(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
// Create an access grant with restricted access by time
notAfterRestrictedPermission := console.Permission{
upload, err := project.UploadObject(ctx, testbucket2, testfilename2, nil)
require.NoError(t, err)
_, err = upload.Write(testdata)
require.NoError(t, err)
err = upload.Commit()
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DownloadObject(ctx, testbucket2, testfilename1, nil)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
// We can see buckets names, but not the files inside
buckets := getAllBuckets(ctx, project)
require.Equal(t, 2, len(buckets))
objects := getAllObjects(ctx, project, testbucket1)
require.Equal(t, 0, len(objects))
_, err = project.DeleteObject(ctx, testbucket1, testfilename2)
require.NoError(t, err)
// Current implementation needs also permission to Download/Read/List so having
// only Delete permission for DeleteBucketWithObjects won't work
_, err = project.DeleteBucketWithObjects(ctx, testbucket2)
require.Error(t, err)
})
withAccessKey(ctx, t, planet, passphrase, "only list", []string{testbucket1}, consolewasm.Permission{AllowList: true}, func(t *testing.T, project *uplink.Project) {
// All operation except list inside testbucket1 should be restricted
_, err = project.CreateBucket(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
upload, err := project.UploadObject(ctx, testbucket1, testfilename2, nil)
require.NoError(t, err)
_, err = upload.Write(testdata)
require.NoError(t, err)
err = upload.Commit()
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DownloadObject(ctx, testbucket1, testfilename1, nil)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
// Only one bucket should be visible
buckets := getAllBuckets(ctx, project)
require.Equal(t, 1, len(buckets))
objects := getAllObjects(ctx, project, testbucket1)
require.Equal(t, 1, len(objects))
_, err = project.DeleteObject(ctx, testbucket1, testfilename1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DeleteBucketWithObjects(ctx, testbucket1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
})
withAccessKey(ctx, t, planet, passphrase, "only upload", []string{testbucket1}, consolewasm.Permission{AllowUpload: true}, func(t *testing.T, project *uplink.Project) {
// All operation except upload to the testbucket1 should be restricted
_, err = project.CreateBucket(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
upload, err := project.UploadObject(ctx, testbucket1, testfilename2, nil)
require.NoError(t, err)
_, err = upload.Write(testdata)
require.NoError(t, err)
err = upload.Commit()
require.NoError(t, err)
_, err = project.DownloadObject(ctx, testbucket1, testfilename1, nil)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
// Only one bucket should be visible
buckets := getAllBuckets(ctx, project)
require.Equal(t, 1, len(buckets))
objects := getAllObjects(ctx, project, testbucket1)
require.Equal(t, 0, len(objects))
_, err = project.DeleteObject(ctx, testbucket1, testfilename1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DeleteBucketWithObjects(ctx, testbucket1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
})
withAccessKey(ctx, t, planet, passphrase, "only download", []string{testbucket1}, consolewasm.Permission{AllowDownload: true}, func(t *testing.T, project *uplink.Project) {
// All operation except download from testbucket1 should be restricted
_, err = project.CreateBucket(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
upload, err := project.UploadObject(ctx, testbucket1, testfilename2, nil)
require.NoError(t, err)
_, err = upload.Write(testdata)
require.NoError(t, err)
err = upload.Commit()
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DownloadObject(ctx, testbucket1, testfilename1, nil)
require.NoError(t, err)
// Only one bucket should be visible
buckets := getAllBuckets(ctx, project)
require.Equal(t, 1, len(buckets))
objects := getAllObjects(ctx, project, testbucket1)
require.Equal(t, 0, len(objects))
_, err = project.DeleteObject(ctx, testbucket1, testfilename1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DeleteBucketWithObjects(ctx, testbucket1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
})
withAccessKey(ctx, t, planet, passphrase, "not after", []string{}, consolewasm.Permission{
AllowDownload: true,
AllowUpload: true,
AllowList: true,
AllowDelete: true,
NotAfter: time.Now().Add(-2 * time.Hour),
}
restrictedAfterKey, err := console.SetPermission(apiKeyString, bucket, notAfterRestrictedPermission)
require.NoError(t, err)
restrictedAfterAccessGrant, err := console.GenAccessGrant(satelliteNodeURL, restrictedAfterKey.Serialize(), passphrase, projectID)
require.NoError(t, err)
restrictedAfterAccess, err := uplink.ParseAccess(restrictedAfterAccessGrant)
require.NoError(t, err)
}, func(t *testing.T, project *uplink.Project) {
// All operation should be restricted
_, err = project.CreateBucket(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
uplinkPeer.APIKey[satellitePeer.ID()] = restrictedAfterKey
uplinkPeer.Access[satellitePeer.ID()] = restrictedAfterAccess
upload, err := project.UploadObject(ctx, testbucket1, testfilename2, nil)
require.NoError(t, err)
_, err = upload.Write(testdata)
require.NoError(t, err)
err = upload.Commit()
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
// Expect that we can't download or upload any data
err = uplinkPeer.Upload(ctx, satellitePeer, testbucket, testfilename, testdata)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = uplinkPeer.Download(ctx, satellitePeer, testbucket, testfilename)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = uplinkPeer.ListBuckets(ctx, satellitePeer)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = uplinkPeer.ListObjects(ctx, satellitePeer, testbucket)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
err = uplinkPeer.DeleteObject(ctx, satellitePeer, testbucket, testfilename)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DownloadObject(ctx, testbucket1, testfilename1, nil)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
notBeforeRestrictedPermission := console.Permission{
_, err = project.DeleteBucketWithObjects(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
buckets := getAllBuckets(ctx, project)
require.Equal(t, 0, len(buckets))
objects := getAllObjects(ctx, project, testbucket1)
require.Equal(t, 0, len(objects))
_, err = project.DeleteObject(ctx, testbucket1, testfilename1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
})
withAccessKey(ctx, t, planet, passphrase, "not before", []string{}, consolewasm.Permission{
AllowDownload: true,
AllowUpload: true,
AllowList: true,
AllowDelete: true,
NotBefore: time.Now().Add(2 * time.Hour),
}
restrictedBeforeKey, err := console.SetPermission(apiKeyString, bucket, notBeforeRestrictedPermission)
require.NoError(t, err)
restrictedBeforeAccessGrant, err := console.GenAccessGrant(satelliteNodeURL, restrictedBeforeKey.Serialize(), passphrase, projectID)
require.NoError(t, err)
restrictedBeforeAccess, err := uplink.ParseAccess(restrictedBeforeAccessGrant)
require.NoError(t, err)
}, func(t *testing.T, project *uplink.Project) {
// All operation should be restricted
_, err = project.CreateBucket(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
uplinkPeer.APIKey[satellitePeer.ID()] = restrictedBeforeKey
uplinkPeer.Access[satellitePeer.ID()] = restrictedBeforeAccess
upload, err := project.UploadObject(ctx, testbucket2, testfilename2, nil)
require.NoError(t, err)
_, err = upload.Write(testdata)
require.NoError(t, err)
err = upload.Commit()
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
// Expect that we can't download or upload any data
err = uplinkPeer.Upload(ctx, satellitePeer, testbucket, testfilename, testdata)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = uplinkPeer.Download(ctx, satellitePeer, testbucket, testfilename)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = uplinkPeer.ListBuckets(ctx, satellitePeer)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = uplinkPeer.ListObjects(ctx, satellitePeer, testbucket)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
err = uplinkPeer.DeleteObject(ctx, satellitePeer, testbucket, testfilename)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DownloadObject(ctx, testbucket1, testfilename1, nil)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
_, err = project.DeleteBucketWithObjects(ctx, testbucket2)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
buckets := getAllBuckets(ctx, project)
require.Equal(t, 0, len(buckets))
objects := getAllObjects(ctx, project, testbucket1)
require.Equal(t, 0, len(objects))
_, err = project.DeleteObject(ctx, testbucket1, testfilename1)
require.True(t, errors.Is(err, uplink.ErrPermissionDenied))
})
withAccessKey(ctx, t, planet, passphrase, "all", []string{}, consolewasm.Permission{
AllowDownload: true,
AllowUpload: true,
AllowList: true,
AllowDelete: true,
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(24 * time.Hour),
}, func(t *testing.T, project *uplink.Project) {
// All operation allowed
_, err = project.CreateBucket(ctx, testbucket3)
require.NoError(t, err)
upload, err := project.UploadObject(ctx, testbucket3, testfilename2, nil)
require.NoError(t, err)
_, err = upload.Write(testdata)
require.NoError(t, err)
err = upload.Commit()
require.NoError(t, err)
objects := getAllObjects(ctx, project, testbucket3)
require.Equal(t, 1, len(objects))
_, err = project.DownloadObject(ctx, testbucket3, testfilename2, nil)
require.NoError(t, err)
_, err = project.DeleteBucketWithObjects(ctx, testbucket3)
require.NoError(t, err)
buckets := getAllBuckets(ctx, project)
require.Equal(t, 2, len(buckets))
_, err = project.DeleteObject(ctx, testbucket1, testfilename1)
require.NoError(t, err)
})
})
}
func getAllObjects(ctx *testcontext.Context, project *uplink.Project, bucket string) []*uplink.Object {
var objects = []*uplink.Object{}
iter := project.ListObjects(ctx, bucket, nil)
for iter.Next() {
objects = append(objects, iter.Item())
}
return objects
}
func getAllBuckets(ctx *testcontext.Context, project *uplink.Project) []*uplink.Bucket {
var buckets = []*uplink.Bucket{}
iter := project.ListBuckets(ctx, nil)
for iter.Next() {
buckets = append(buckets, iter.Item())
}
return buckets
}
func withAccessKey(ctx context.Context, t *testing.T, planet *testplanet.Planet, passphrase string, testname string, bucket []string, permissions consolewasm.Permission, fn func(t *testing.T, uplink *uplink.Project)) {
t.Run(testname, func(t *testing.T) {
upl := planet.Uplinks[0]
sat := planet.Satellites[0]
apikey := upl.APIKey[sat.ID()]
restrictedKey, err := consolewasm.SetPermission(apikey.Serialize(), bucket, permissions)
require.NoError(t, err)
restrictedGrant, err := consolewasm.GenAccessGrant(sat.NodeURL().String(), restrictedKey.Serialize(), passphrase, upl.Projects[0].ID.String())
require.NoError(t, err)
access, err := uplink.ParseAccess(restrictedGrant)
require.NoError(t, err)
project, err := uplink.OpenProject(ctx, access)
require.NoError(t, err)
defer func() { require.NoError(t, project.Close()) }()
fn(t, project)
})
}