use service accounts for storage-user commands

Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
jkoberg
2023-08-31 12:11:43 +02:00
parent ab10e5e152
commit e09ddc93ea
5 changed files with 24 additions and 94 deletions
+9 -48
View File
@@ -1,11 +1,9 @@
package task
import (
"fmt"
"time"
apiGateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
apiUser "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
apiRpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
apiProvider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
@@ -17,18 +15,18 @@ import (
// the provided executantID must have space access.
// removeBefore specifies how long an item must be in the trash-bin to be deleted,
// items that stay there for a shorter time are ignored and kept in place.
func PurgeTrashBin(executantID *apiUser.UserId, deleteBefore time.Time, spaceType SpaceType, gatewaySelector pool.Selectable[apiGateway.GatewayAPIClient], machineAuthAPIKey string) error {
func PurgeTrashBin(serviceAccountID string, deleteBefore time.Time, spaceType SpaceType, gatewaySelector pool.Selectable[apiGateway.GatewayAPIClient], serviceAccountSecret string) error {
gatewayClient, err := gatewaySelector.Next()
if err != nil {
return err
}
executantCtx, _, err := utils.Impersonate(executantID, gatewayClient, machineAuthAPIKey)
ctx, err := utils.GetServiceUserContext(serviceAccountID, gatewayClient, serviceAccountSecret)
if err != nil {
return err
}
listStorageSpacesResponse, err := gatewayClient.ListStorageSpaces(executantCtx, &apiProvider.ListStorageSpacesRequest{
listStorageSpacesResponse, err := gatewayClient.ListStorageSpaces(ctx, &apiProvider.ListStorageSpacesRequest{
Filters: []*apiProvider.ListStorageSpacesRequest_Filter{
{
Type: apiProvider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE,
@@ -43,52 +41,15 @@ func PurgeTrashBin(executantID *apiUser.UserId, deleteBefore time.Time, spaceTyp
}
for _, storageSpace := range listStorageSpacesResponse.StorageSpaces {
var (
err error
impersonationID *apiUser.UserId
storageSpaceReference = &apiProvider.Reference{
ResourceId: storageSpace.GetRoot(),
}
)
switch SpaceType(storageSpace.GetSpaceType()) {
case Personal:
impersonationID = storageSpace.GetOwner().GetId()
case Project:
var permissionsMap map[string]*apiProvider.ResourcePermissions
err := utils.ReadJSONFromOpaque(storageSpace.GetOpaque(), "grants", &permissionsMap)
if err != nil {
break
}
for id, permissions := range permissionsMap {
if !permissions.Delete {
continue
}
impersonationID = &apiUser.UserId{
OpaqueId: id,
}
break
}
default:
if typ := storageSpace.GetSpaceType(); typ != "personal" && typ != "project" {
// ignore spaces that are neither personal nor project
continue
}
if err != nil {
return err
storageSpaceReference := &apiProvider.Reference{
ResourceId: storageSpace.GetRoot(),
}
if impersonationID == nil {
return fmt.Errorf("can't impersonate space user for space: %s", storageSpace.GetId().GetOpaqueId())
}
impersonatedCtx, _, err := utils.Impersonate(impersonationID, gatewayClient, machineAuthAPIKey)
if err != nil {
return err
}
listRecycleResponse, err := gatewayClient.ListRecycle(impersonatedCtx, &apiProvider.ListRecycleRequest{Ref: storageSpaceReference})
listRecycleResponse, err := gatewayClient.ListRecycle(ctx, &apiProvider.ListRecycleRequest{Ref: storageSpaceReference})
if err != nil {
return err
}
@@ -99,7 +60,7 @@ func PurgeTrashBin(executantID *apiUser.UserId, deleteBefore time.Time, spaceTyp
continue
}
purgeRecycleResponse, err := gatewayClient.PurgeRecycle(impersonatedCtx, &apiProvider.PurgeRecycleRequest{
purgeRecycleResponse, err := gatewayClient.PurgeRecycle(ctx, &apiProvider.PurgeRecycleRequest{
Ref: storageSpaceReference,
Key: recycleItem.Key,
})
@@ -115,7 +115,7 @@ var _ = Describe("trash", func() {
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(nil, genericError)
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
err := task.PurgeTrashBin("service-user-id", now, task.Project, gatewaySelector, "")
Expect(err).To(HaveOccurred())
})
It("throws an error if space listing fails", func() {
@@ -123,45 +123,9 @@ var _ = Describe("trash", func() {
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(nil, genericError)
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
err := task.PurgeTrashBin("service-user-id", now, task.Project, gatewaySelector, "")
Expect(err).To(HaveOccurred())
})
It("throws an error if a personal space user can't be impersonated", func() {
listStorageSpacesResponse.StorageSpaces = []*apiProvider.StorageSpace{personalSpace}
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listStorageSpacesResponse, nil)
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
Expect(err).To(MatchError(errors.New("can't impersonate space user for space: personal")))
})
It("throws an error if a project space user can't be impersonated", func() {
listStorageSpacesResponse.StorageSpaces = []*apiProvider.StorageSpace{projectSpace}
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listStorageSpacesResponse, nil)
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
Expect(err).To(MatchError(errors.New("can't impersonate space user for space: project")))
})
It("throws an error if a project space has no user with delete permissions", func() {
listStorageSpacesResponse.StorageSpaces = []*apiProvider.StorageSpace{projectSpace}
projectSpace.Opaque.Map = map[string]*apiTypes.OpaqueEntry{
"grants": {
Value: MustMarshal(map[string]*apiProvider.ResourcePermissions{
"admin": {
Delete: false,
},
}),
},
}
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listStorageSpacesResponse, nil)
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
Expect(err).To(MatchError(errors.New("can't impersonate space user for space: project")))
})
It("only deletes items older than the specified period", func() {
var (
recycleItems = map[string][]*apiProvider.RecycleItem{
@@ -231,7 +195,7 @@ var _ = Describe("trash", func() {
}, nil,
)
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
err := task.PurgeTrashBin("service-user-id", now, task.Project, gatewaySelector, "")
Expect(err).To(BeNil())
Expect(recycleItems["personal"]).To(HaveLen(2))
Expect(recycleItems["project"]).To(HaveLen(2))