forked from TrueCloudLab/frostfs-node
e54b52ec03
In previous implementation of `neofs-node` app object session was not checked for substitution of the object related to it. Also, for access checks, the session object was substituted instead of the one from the request. This, on the one hand, made it possible to inherit the session from the parent object for authorization for certain actions. On the other hand, it covered the mentioned object substitution, which is a critical vulnerability. Next changes are applied to processing of all Object service requests: - check if object session relates to the requested object - use requested object in access checks. Disclosed problem of object context inheritance will be solved within Signed-off-by: Leonard Lyubich <ctulhurider@gmail.com>
75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
package session
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"os"
|
|
|
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
|
"github.com/nspcc-dev/neofs-sdk-go/client"
|
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// RPCParameters represents parameters for operations with session token.
|
|
type RPCParameters interface {
|
|
SetClient(*client.Client)
|
|
SetSessionToken(*session.Object)
|
|
}
|
|
|
|
const sessionTokenLifetime = 10 // in epochs
|
|
|
|
// Prepare prepares session for a command.
|
|
func Prepare(cmd *cobra.Command, cnr cid.ID, obj *oid.ID, key *ecdsa.PrivateKey, prms ...RPCParameters) {
|
|
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
|
|
|
var tok session.Object
|
|
if tokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken); len(tokenPath) != 0 {
|
|
data, err := os.ReadFile(tokenPath)
|
|
common.ExitOnErr(cmd, "can't read session token: %w", err)
|
|
|
|
if err := tok.Unmarshal(data); err != nil {
|
|
err = tok.UnmarshalJSON(data)
|
|
common.ExitOnErr(cmd, "can't unmarshal session token: %w", err)
|
|
}
|
|
} else {
|
|
err := CreateSession(&tok, cli, sessionTokenLifetime)
|
|
common.ExitOnErr(cmd, "create session: %w", err)
|
|
}
|
|
|
|
for i := range prms {
|
|
tok := tok
|
|
switch prms[i].(type) {
|
|
case *internalclient.GetObjectPrm:
|
|
tok.ForVerb(session.VerbObjectGet)
|
|
case *internalclient.HeadObjectPrm:
|
|
tok.ForVerb(session.VerbObjectHead)
|
|
case *internalclient.PutObjectPrm:
|
|
tok.ForVerb(session.VerbObjectPut)
|
|
case *internalclient.DeleteObjectPrm:
|
|
tok.ForVerb(session.VerbObjectDelete)
|
|
case *internalclient.SearchObjectsPrm:
|
|
tok.ForVerb(session.VerbObjectSearch)
|
|
case *internalclient.PayloadRangePrm:
|
|
tok.ForVerb(session.VerbObjectRange)
|
|
case *internalclient.HashPayloadRangesPrm:
|
|
tok.ForVerb(session.VerbObjectRangeHash)
|
|
default:
|
|
panic("invalid client parameter type")
|
|
}
|
|
|
|
tok.BindContainer(cnr)
|
|
if obj != nil {
|
|
tok.LimitByObjects(*obj)
|
|
}
|
|
|
|
err := tok.Sign(*key)
|
|
common.ExitOnErr(cmd, "session token signing: %w", err)
|
|
|
|
prms[i].SetClient(cli)
|
|
prms[i].SetSessionToken(&tok)
|
|
}
|
|
}
|