From 36cd8aba9dd0c62240e5c967bac8a88415309ff8 Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Fri, 24 Jan 2025 10:45:45 +0400 Subject: [PATCH] authmate: Add command to reset container EACL to default state We assume container is private. Signed-off-by: Evgenii Baidakov --- authmate/authmate.go | 6 ++ cmd/s3-authmate/main.go | 126 ++++++++++++++++++++++++++++++++++++++++ internal/neofs/neofs.go | 10 ++++ 3 files changed, 142 insertions(+) diff --git a/authmate/authmate.go b/authmate/authmate.go index 456232d1..c2ecb2c7 100644 --- a/authmate/authmate.go +++ b/authmate/authmate.go @@ -78,6 +78,12 @@ type NeoFS interface { // // It returns any error encountered which prevented computing epochs. TimeToEpoch(context.Context, time.Time) (uint64, uint64, error) + + // SetContainerEACL updates container EACL. + SetContainerEACL(ctx context.Context, table eacl.Table, sessionToken *session.Container) error + + // ContainerEACL gets container EACL. + ContainerEACL(ctx context.Context, containerID cid.ID) (*eacl.Table, error) } // Agent contains client communicating with NeoFS and logger. diff --git a/cmd/s3-authmate/main.go b/cmd/s3-authmate/main.go index bc844787..55037319 100644 --- a/cmd/s3-authmate/main.go +++ b/cmd/s3-authmate/main.go @@ -14,12 +14,14 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-s3-gw/api" + "github.com/nspcc-dev/neofs-s3-gw/api/handler" "github.com/nspcc-dev/neofs-s3-gw/authmate" "github.com/nspcc-dev/neofs-s3-gw/internal/neofs" "github.com/nspcc-dev/neofs-s3-gw/internal/version" "github.com/nspcc-dev/neofs-s3-gw/internal/wallet" "github.com/nspcc-dev/neofs-sdk-go/client" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" + "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/user" "github.com/spf13/viper" @@ -166,6 +168,7 @@ func appCommands() []*cli.Command { return []*cli.Command{ issueSecret(), obtainSecret(), + resetBucketEACL(), } } @@ -617,3 +620,126 @@ func createNeoFS(ctx context.Context, log *zap.Logger, cfg PoolConfig, anonSigne return neofs.NewAuthmateNeoFS(neoFS), nil } + +func resetBucketEACL() *cli.Command { + command := &cli.Command{ + Name: "reset-bucket-acl", + Usage: "Reset bucket ACL to default state", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "wallet", + Value: "", + Usage: "path to the container owner wallet", + Required: true, + Destination: &walletPathFlag, + }, + &cli.StringFlag{ + Name: "peer", + Value: "", + Usage: "address of neofs peer to connect to", + Required: true, + Destination: &peerAddressFlag, + }, + &cli.StringFlag{ + Name: "container-id", + Usage: "neofs container id to update eacl", + Required: true, + Destination: &containerIDFlag, + }, + }, + Action: func(_ *cli.Context) error { + ctx, log := prepare() + + password := wallet.GetPassword(viper.GetViper(), envWalletPassphrase) + if password == nil { + var empty string + password = &empty + } + + key, err := wallet.GetKeyFromPath(walletPathFlag, accountAddressFlag, password) + if err != nil { + return cli.Exit(fmt.Sprintf("failed to load neofs private key: %s", err), 1) + } + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + poolCfg := PoolConfig{ + Key: &key.PrivateKey, + Address: peerAddressFlag, + } + + anonKey, err := keys.NewPrivateKey() + if err != nil { + log.Fatal("obtainSecret: couldn't generate random key", zap.Error(err)) + } + anonSigner := user.NewAutoIDSignerRFC6979(anonKey.PrivateKey) + + neoFS, err := createNeoFS(ctx, log, poolCfg, anonSigner, slicerEnabledFlag) + if err != nil { + return cli.Exit(fmt.Sprintf("failed to create NeoFS component: %s", err), 1) + } + + var containerID cid.ID + if err = containerID.DecodeString(containerIDFlag); err != nil { + return cli.Exit(fmt.Sprintf("failed to parse auth container id: %s", err), 1) + } + + var ( + newEACLTable eacl.Table + ownerID = user.NewFromScriptHash(key.GetScriptHash()) + targetOwner eacl.Target + ) + + newEACLTable.SetCID(containerID) + targetOwner.SetAccounts([]user.ID{ownerID}) + + for op := eacl.OperationGet; op <= eacl.OperationRangeHash; op++ { + record := eacl.NewRecord() + record.SetOperation(op) + record.SetAction(eacl.ActionAllow) + record.SetTargets(targetOwner) + + newEACLTable.AddRecord(record) + } + + for op := eacl.OperationGet; op <= eacl.OperationRangeHash; op++ { + record := eacl.NewRecord() + record.SetOperation(op) + record.SetAction(eacl.ActionDeny) + eacl.AddFormedTarget(record, eacl.RoleOthers) + + newEACLTable.AddRecord(record) + } + + oldEacl, err := neoFS.ContainerEACL(ctx, containerID) + if err != nil { + return cli.Exit(fmt.Sprintf("failed to obtain old neofs EACL: %s", err), 1) + } + + if handler.IsBucketOwnerForced(oldEacl) { + newEACLTable.AddRecord(handler.BucketOwnerEnforcedRecord()) + } + + if handler.IsBucketOwnerPreferred(oldEacl) { + newEACLTable.AddRecord(handler.BucketOwnerPreferredRecord()) + } + + if handler.IsBucketOwnerPreferredAndRestricted(oldEacl) { + newEACLTable.AddRecord(handler.BucketOwnerPreferredAndRestrictedRecord()) + } + + var tcancel context.CancelFunc + ctx, tcancel = context.WithTimeout(ctx, timeoutFlag) + defer tcancel() + + if err = neoFS.SetContainerEACL(ctx, newEACLTable, nil); err != nil { + return cli.Exit(fmt.Sprintf("failed to setup eacl: %s", err), 1) + } + + return nil + }, + } + + return command +} diff --git a/internal/neofs/neofs.go b/internal/neofs/neofs.go index f0abf2e4..30dcde42 100644 --- a/internal/neofs/neofs.go +++ b/internal/neofs/neofs.go @@ -691,6 +691,16 @@ func (x *AuthmateNeoFS) CreateObject(ctx context.Context, prm tokens.PrmObjectCr }) } +// SetContainerEACL implements authmate.NeoFS interface method. +func (x *AuthmateNeoFS) SetContainerEACL(ctx context.Context, table eacl.Table, sessionToken *session.Container) error { + return x.neoFS.SetContainerEACL(ctx, table, sessionToken) +} + +// ContainerEACL implements authmate.NeoFS interface method. +func (x *AuthmateNeoFS) ContainerEACL(ctx context.Context, containerID cid.ID) (*eacl.Table, error) { + return x.neoFS.ContainerEACL(ctx, containerID) +} + // PoolStatistic is a mediator which implements authmate.NeoFS through pool.Pool. type PoolStatistic struct { poolStat *stat.PoolStat