forked from TrueCloudLab/frostfs-node
[#1423] session: Upgrade SDK package
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
dda56f1319
commit
4c8ec20e32
41 changed files with 738 additions and 661 deletions
|
@ -337,7 +337,7 @@ func PutObject(prm PutObjectPrm) (*PutObjectRes, error) {
|
||||||
wrt.MarkLocal()
|
wrt.MarkLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
wrt.WithXHeaders(prm.xHeadersPrm()...)
|
wrt.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
if wrt.WriteHeader(*prm.hdr) {
|
if wrt.WriteHeader(*prm.hdr) {
|
||||||
sz := prm.hdr.PayloadSize()
|
sz := prm.hdr.PayloadSize()
|
||||||
|
@ -437,7 +437,7 @@ func DeleteObject(prm DeleteObjectPrm) (*DeleteObjectRes, error) {
|
||||||
delPrm.WithBearerToken(*prm.bearerToken)
|
delPrm.WithBearerToken(*prm.bearerToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
delPrm.WithXHeaders(prm.xHeadersPrm()...)
|
delPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
cliRes, err := prm.cli.ObjectDelete(context.Background(), delPrm)
|
cliRes, err := prm.cli.ObjectDelete(context.Background(), delPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -517,7 +517,7 @@ func GetObject(prm GetObjectPrm) (*GetObjectRes, error) {
|
||||||
getPrm.MarkLocal()
|
getPrm.MarkLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
getPrm.WithXHeaders(prm.xHeadersPrm()...)
|
getPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
rdr, err := prm.cli.ObjectGetInit(context.Background(), getPrm)
|
rdr, err := prm.cli.ObjectGetInit(context.Background(), getPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -599,7 +599,7 @@ func HeadObject(prm HeadObjectPrm) (*HeadObjectRes, error) {
|
||||||
cliPrm.MarkLocal()
|
cliPrm.MarkLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
res, err := prm.cli.ObjectHead(context.Background(), cliPrm)
|
res, err := prm.cli.ObjectHead(context.Background(), cliPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -664,7 +664,7 @@ func SearchObjects(prm SearchObjectsPrm) (*SearchObjectsRes, error) {
|
||||||
cliPrm.MarkLocal()
|
cliPrm.MarkLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
rdr, err := prm.cli.ObjectSearchInit(context.Background(), cliPrm)
|
rdr, err := prm.cli.ObjectSearchInit(context.Background(), cliPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -775,7 +775,7 @@ func HashPayloadRanges(prm HashPayloadRangesPrm) (*HashPayloadRangesRes, error)
|
||||||
cliPrm.WithBearerToken(*prm.bearerToken)
|
cliPrm.WithBearerToken(*prm.bearerToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
res, err := prm.cli.ObjectHash(context.Background(), cliPrm)
|
res, err := prm.cli.ObjectHash(context.Background(), cliPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -841,7 +841,7 @@ func PayloadRange(prm PayloadRangePrm) (*PayloadRangeRes, error) {
|
||||||
cliPrm.SetOffset(prm.rng.GetOffset())
|
cliPrm.SetOffset(prm.rng.GetOffset())
|
||||||
cliPrm.SetLength(prm.rng.GetLength())
|
cliPrm.SetLength(prm.rng.GetLength())
|
||||||
|
|
||||||
cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
rdr, err := prm.cli.ObjectRangeInit(context.Background(), cliPrm)
|
rdr, err := prm.cli.ObjectRangeInit(context.Background(), cliPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -30,15 +30,6 @@ func (x *containerIDPrm) SetContainerID(id *cid.ID) {
|
||||||
x.cnrID = id
|
x.cnrID = id
|
||||||
}
|
}
|
||||||
|
|
||||||
type sessionTokenPrm struct {
|
|
||||||
sessionToken *session.Token
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSessionToken sets the token of the session within which the request should be sent.
|
|
||||||
func (x *sessionTokenPrm) SetSessionToken(tok *session.Token) {
|
|
||||||
x.sessionToken = tok
|
|
||||||
}
|
|
||||||
|
|
||||||
type bearerTokenPrm struct {
|
type bearerTokenPrm struct {
|
||||||
bearerToken *bearer.Token
|
bearerToken *bearer.Token
|
||||||
}
|
}
|
||||||
|
@ -76,12 +67,13 @@ func (x *payloadWriterPrm) SetPayloadWriter(wrt io.Writer) {
|
||||||
|
|
||||||
type commonObjectPrm struct {
|
type commonObjectPrm struct {
|
||||||
commonPrm
|
commonPrm
|
||||||
sessionTokenPrm
|
|
||||||
bearerTokenPrm
|
bearerTokenPrm
|
||||||
|
|
||||||
|
sessionToken *session.Object
|
||||||
|
|
||||||
local bool
|
local bool
|
||||||
|
|
||||||
xHeaders []*session.XHeader
|
xHeaders []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTTL sets request TTL value.
|
// SetTTL sets request TTL value.
|
||||||
|
@ -90,19 +82,11 @@ func (x *commonObjectPrm) SetTTL(ttl uint32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetXHeaders sets request X-Headers.
|
// SetXHeaders sets request X-Headers.
|
||||||
func (x *commonObjectPrm) SetXHeaders(hs []*session.XHeader) {
|
func (x *commonObjectPrm) SetXHeaders(hs []string) {
|
||||||
x.xHeaders = hs
|
x.xHeaders = hs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x commonObjectPrm) xHeadersPrm() (res []string) {
|
// SetSessionToken sets the token of the session within which the request should be sent.
|
||||||
if x.xHeaders != nil {
|
func (x *commonObjectPrm) SetSessionToken(tok *session.Object) {
|
||||||
res = make([]string, len(x.xHeaders)*2)
|
x.sessionToken = tok
|
||||||
|
|
||||||
for i := range x.xHeaders {
|
|
||||||
res[2*i] = x.xHeaders[i].Key()
|
|
||||||
res[2*i+1] = x.xHeaders[i].Value()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,23 +35,11 @@ func ReadBearerToken(cmd *cobra.Command, flagname string) *bearer.Token {
|
||||||
|
|
||||||
// ReadSessionToken reads session token as JSON file with session token
|
// ReadSessionToken reads session token as JSON file with session token
|
||||||
// from path provided in a specified flag.
|
// from path provided in a specified flag.
|
||||||
func ReadSessionToken(cmd *cobra.Command, flag string) *session.Token {
|
func ReadSessionToken(cmd *cobra.Command, dst json.Unmarshaler, fPath string) {
|
||||||
// try to read session token from file
|
// try to read session token from file
|
||||||
var tok *session.Token
|
data, err := os.ReadFile(fPath)
|
||||||
|
|
||||||
path, err := cmd.Flags().GetString(flag)
|
|
||||||
ExitOnErr(cmd, "", err)
|
|
||||||
|
|
||||||
if path == "" {
|
|
||||||
return tok
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
ExitOnErr(cmd, "could not open file with session token: %w", err)
|
ExitOnErr(cmd, "could not open file with session token: %w", err)
|
||||||
|
|
||||||
tok = session.NewToken()
|
err = dst.UnmarshalJSON(data)
|
||||||
err = tok.UnmarshalJSON(data)
|
ExitOnErr(cmd, "could not unmarshal session token from file: %w", err)
|
||||||
ExitOnErr(cmd, "could not ummarshal session token from file: %w", err)
|
|
||||||
|
|
||||||
return tok
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
versionSDK "github.com/nspcc-dev/neofs-sdk-go/version"
|
versionSDK "github.com/nspcc-dev/neofs-sdk-go/version"
|
||||||
|
@ -158,26 +159,33 @@ It will be stored in sidechain when inner ring will accepts it.`,
|
||||||
nonce, err := parseNonce(containerNonce)
|
nonce, err := parseNonce(containerNonce)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
tok := common.ReadSessionToken(cmd, sessionTokenFlag)
|
|
||||||
key := key.GetOrGenerate(cmd)
|
key := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
var idOwner *user.ID
|
cnr := container.New()
|
||||||
|
var tok *session.Container
|
||||||
|
|
||||||
if idOwner = tok.OwnerID(); idOwner == nil {
|
if sessionTokenPath != "" {
|
||||||
idOwner = new(user.ID)
|
tok = new(session.Container)
|
||||||
user.IDFromKey(idOwner, key.PublicKey)
|
common.ReadSessionToken(cmd, tok, sessionTokenPath)
|
||||||
|
|
||||||
|
issuer := tok.Issuer()
|
||||||
|
cnr.SetOwnerID(&issuer)
|
||||||
|
cnr.SetSessionToken(tok)
|
||||||
|
} else {
|
||||||
|
var idOwner user.ID
|
||||||
|
user.IDFromKey(&idOwner, key.PublicKey)
|
||||||
|
|
||||||
|
cnr.SetOwnerID(&idOwner)
|
||||||
}
|
}
|
||||||
|
|
||||||
ver := versionSDK.Current()
|
ver := versionSDK.Current()
|
||||||
|
|
||||||
cnr := container.New()
|
|
||||||
cnr.SetVersion(&ver)
|
cnr.SetVersion(&ver)
|
||||||
cnr.SetPlacementPolicy(placementPolicy)
|
cnr.SetPlacementPolicy(placementPolicy)
|
||||||
cnr.SetBasicACL(basicACL)
|
cnr.SetBasicACL(basicACL)
|
||||||
cnr.SetAttributes(attributes)
|
cnr.SetAttributes(attributes)
|
||||||
cnr.SetNonceUUID(nonce)
|
cnr.SetNonceUUID(nonce)
|
||||||
cnr.SetSessionToken(tok)
|
cnr.SetSessionToken(tok)
|
||||||
cnr.SetOwnerID(idOwner)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
putPrm internalclient.PutContainerPrm
|
putPrm internalclient.PutContainerPrm
|
||||||
|
@ -223,7 +231,12 @@ Only owner of the container has a permission to remove container.`,
|
||||||
id, err := parseContainerID(containerID)
|
id, err := parseContainerID(containerID)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
tok := common.ReadSessionToken(cmd, sessionTokenFlag)
|
var tok *session.Container
|
||||||
|
|
||||||
|
if sessionTokenPath != "" {
|
||||||
|
tok = new(session.Container)
|
||||||
|
common.ReadSessionToken(cmd, tok, sessionTokenPath)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
delPrm internalclient.DeleteContainerPrm
|
delPrm internalclient.DeleteContainerPrm
|
||||||
|
@ -234,7 +247,7 @@ Only owner of the container has a permission to remove container.`,
|
||||||
delPrm.SetContainer(*id)
|
delPrm.SetContainer(*id)
|
||||||
|
|
||||||
if tok != nil {
|
if tok != nil {
|
||||||
delPrm.SetSessionToken(*tok)
|
delPrm.WithinSession(*tok)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = internalclient.DeleteContainer(delPrm)
|
_, err = internalclient.DeleteContainer(delPrm)
|
||||||
|
@ -412,7 +425,12 @@ Container ID in EACL table will be substituted with ID from the CLI.`,
|
||||||
|
|
||||||
eaclTable := common.ReadEACL(cmd, eaclPathFrom)
|
eaclTable := common.ReadEACL(cmd, eaclPathFrom)
|
||||||
|
|
||||||
tok := common.ReadSessionToken(cmd, sessionTokenFlag)
|
var tok *session.Container
|
||||||
|
|
||||||
|
if sessionTokenPath != "" {
|
||||||
|
tok = new(session.Container)
|
||||||
|
common.ReadSessionToken(cmd, tok, sessionTokenPath)
|
||||||
|
}
|
||||||
|
|
||||||
eaclTable.SetCID(*id)
|
eaclTable.SetCID(*id)
|
||||||
eaclTable.SetSessionToken(tok)
|
eaclTable.SetSessionToken(tok)
|
||||||
|
|
|
@ -314,7 +314,7 @@ func init() {
|
||||||
|
|
||||||
type clientKeySession interface {
|
type clientKeySession interface {
|
||||||
clientWithKey
|
clientWithKey
|
||||||
SetSessionToken(*session.Token)
|
SetSessionToken(*session.Object)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareSessionPrm(cmd *cobra.Command, addr *addressSDK.Address, prms ...clientKeySession) {
|
func prepareSessionPrm(cmd *cobra.Command, addr *addressSDK.Address, prms ...clientKeySession) {
|
||||||
|
@ -339,65 +339,54 @@ func prepareSessionPrmWithOwner(
|
||||||
) {
|
) {
|
||||||
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
||||||
|
|
||||||
var sessionToken *session.Token
|
var tok session.Object
|
||||||
if tokenPath, _ := cmd.Flags().GetString(sessionTokenFlag); len(tokenPath) != 0 {
|
if tokenPath, _ := cmd.Flags().GetString(sessionTokenFlag); len(tokenPath) != 0 {
|
||||||
data, err := ioutil.ReadFile(tokenPath)
|
data, err := ioutil.ReadFile(tokenPath)
|
||||||
common.ExitOnErr(cmd, "can't read session token: %w", err)
|
common.ExitOnErr(cmd, "can't read session token: %w", err)
|
||||||
|
|
||||||
sessionToken = session.NewToken()
|
if err := tok.Unmarshal(data); err != nil {
|
||||||
if err := sessionToken.Unmarshal(data); err != nil {
|
err = tok.UnmarshalJSON(data)
|
||||||
err = sessionToken.UnmarshalJSON(data)
|
|
||||||
common.ExitOnErr(cmd, "can't unmarshal session token: %w", err)
|
common.ExitOnErr(cmd, "can't unmarshal session token: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var err error
|
err := sessionCli.CreateSession(&tok, cli, sessionTokenLifetime)
|
||||||
sessionToken, err = sessionCli.CreateSession(cli, ownerID, sessionTokenLifetime)
|
common.ExitOnErr(cmd, "create session: %w", err)
|
||||||
common.ExitOnErr(cmd, "", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range prms {
|
for i := range prms {
|
||||||
objectContext := session.NewObjectContext()
|
|
||||||
switch prms[i].(type) {
|
switch prms[i].(type) {
|
||||||
case *internalclient.GetObjectPrm:
|
case *internalclient.GetObjectPrm:
|
||||||
objectContext.ForGet()
|
tok.ForVerb(session.VerbObjectGet)
|
||||||
case *internalclient.HeadObjectPrm:
|
case *internalclient.HeadObjectPrm:
|
||||||
objectContext.ForHead()
|
tok.ForVerb(session.VerbObjectHead)
|
||||||
case *internalclient.PutObjectPrm:
|
case *internalclient.PutObjectPrm:
|
||||||
objectContext.ForPut()
|
tok.ForVerb(session.VerbObjectPut)
|
||||||
case *internalclient.DeleteObjectPrm:
|
case *internalclient.DeleteObjectPrm:
|
||||||
objectContext.ForDelete()
|
tok.ForVerb(session.VerbObjectDelete)
|
||||||
case *internalclient.SearchObjectsPrm:
|
case *internalclient.SearchObjectsPrm:
|
||||||
objectContext.ForSearch()
|
tok.ForVerb(session.VerbObjectSearch)
|
||||||
case *internalclient.PayloadRangePrm:
|
case *internalclient.PayloadRangePrm:
|
||||||
objectContext.ForRange()
|
tok.ForVerb(session.VerbObjectRange)
|
||||||
case *internalclient.HashPayloadRangesPrm:
|
case *internalclient.HashPayloadRangesPrm:
|
||||||
objectContext.ForRangeHash()
|
tok.ForVerb(session.VerbObjectRangeHash)
|
||||||
default:
|
default:
|
||||||
panic("invalid client parameter type")
|
panic("invalid client parameter type")
|
||||||
}
|
}
|
||||||
objectContext.ApplyTo(addr)
|
|
||||||
|
|
||||||
tok := session.NewToken()
|
tok.ApplyTo(*addr)
|
||||||
tok.SetID(sessionToken.ID())
|
|
||||||
tok.SetSessionKey(sessionToken.SessionKey())
|
|
||||||
tok.SetOwnerID(sessionToken.OwnerID())
|
|
||||||
tok.SetContext(objectContext)
|
|
||||||
tok.SetExp(sessionToken.Exp())
|
|
||||||
tok.SetIat(sessionToken.Iat())
|
|
||||||
tok.SetNbf(sessionToken.Nbf())
|
|
||||||
|
|
||||||
err := tok.Sign(key)
|
err := tok.Sign(*key)
|
||||||
common.ExitOnErr(cmd, "session token signing: %w", err)
|
common.ExitOnErr(cmd, "session token signing: %w", err)
|
||||||
|
|
||||||
prms[i].SetClient(cli)
|
prms[i].SetClient(cli)
|
||||||
prms[i].SetSessionToken(tok)
|
prms[i].SetSessionToken(&tok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type objectPrm interface {
|
type objectPrm interface {
|
||||||
bearerPrm
|
bearerPrm
|
||||||
SetTTL(uint32)
|
SetTTL(uint32)
|
||||||
SetXHeaders([]*session.XHeader)
|
SetXHeaders([]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareObjectPrm(cmd *cobra.Command, prms ...objectPrm) {
|
func prepareObjectPrm(cmd *cobra.Command, prms ...objectPrm) {
|
||||||
|
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/gendoc"
|
"github.com/nspcc-dev/neofs-node/pkg/util/gendoc"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/client"
|
"github.com/nspcc-dev/neofs-sdk-go/client"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -188,8 +187,8 @@ func userFromString(id *user.ID, s string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseXHeaders() []*session.XHeader {
|
func parseXHeaders() []string {
|
||||||
xs := make([]*session.XHeader, 0, len(xHeaders))
|
xs := make([]string, 0, 2*len(xHeaders))
|
||||||
|
|
||||||
for i := range xHeaders {
|
for i := range xHeaders {
|
||||||
kv := strings.SplitN(xHeaders[i], "=", 2)
|
kv := strings.SplitN(xHeaders[i], "=", 2)
|
||||||
|
@ -197,11 +196,7 @@ func parseXHeaders() []*session.XHeader {
|
||||||
panic(fmt.Errorf("invalid X-Header format: %s", xHeaders[i]))
|
panic(fmt.Errorf("invalid X-Header format: %s", xHeaders[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
x := session.NewXHeader()
|
xs = append(xs, kv[0], kv[1])
|
||||||
x.SetKey(kv[0])
|
|
||||||
x.SetValue(kv[1])
|
|
||||||
|
|
||||||
xs = append(xs, x)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return xs
|
return xs
|
||||||
|
|
|
@ -4,13 +4,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/client"
|
"github.com/nspcc-dev/neofs-sdk-go/client"
|
||||||
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
@ -66,10 +67,9 @@ func createSession(cmd *cobra.Command, _ []string) error {
|
||||||
lifetime = lfArg
|
lifetime = lfArg
|
||||||
}
|
}
|
||||||
|
|
||||||
var ownerID user.ID
|
var tok session.Object
|
||||||
user.IDFromKey(&ownerID, privKey.PublicKey)
|
|
||||||
|
|
||||||
tok, err := CreateSession(c, &ownerID, lifetime)
|
err = CreateSession(&tok, c, lifetime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -78,11 +78,11 @@ func createSession(cmd *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
if toJSON, _ := cmd.Flags().GetBool(jsonFlag); toJSON {
|
if toJSON, _ := cmd.Flags().GetBool(jsonFlag); toJSON {
|
||||||
data, err = tok.MarshalJSON()
|
data, err = tok.MarshalJSON()
|
||||||
} else {
|
|
||||||
data, err = tok.Marshal()
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't marshal token: %w", err)
|
return fmt.Errorf("decode session token JSON: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = tok.Marshal()
|
||||||
}
|
}
|
||||||
|
|
||||||
filename, _ := cmd.Flags().GetString(outFlag)
|
filename, _ := cmd.Flags().GetString(outFlag)
|
||||||
|
@ -92,15 +92,18 @@ func createSession(cmd *cobra.Command, _ []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSession returns newly created session token with the specified owner and lifetime.
|
// CreateSession opens a new communication with NeoFS storage node using client connection.
|
||||||
// `Issued-At` and `Not-Valid-Before` fields are set to current epoch.
|
// The session is expected to be maintained by the storage node during the given
|
||||||
func CreateSession(c *client.Client, owner *user.ID, lifetime uint64) (*session.Token, error) {
|
// number of epochs.
|
||||||
|
//
|
||||||
|
// Fills ID, lifetime and session key.
|
||||||
|
func CreateSession(dst *session.Object, c *client.Client, lifetime uint64) error {
|
||||||
var netInfoPrm internalclient.NetworkInfoPrm
|
var netInfoPrm internalclient.NetworkInfoPrm
|
||||||
netInfoPrm.SetClient(c)
|
netInfoPrm.SetClient(c)
|
||||||
|
|
||||||
ni, err := internalclient.NetworkInfo(netInfoPrm)
|
ni, err := internalclient.NetworkInfo(netInfoPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't fetch network info: %w", err)
|
return fmt.Errorf("can't fetch network info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cur := ni.NetworkInfo().CurrentEpoch()
|
cur := ni.NetworkInfo().CurrentEpoch()
|
||||||
|
@ -112,16 +115,30 @@ func CreateSession(c *client.Client, owner *user.ID, lifetime uint64) (*session.
|
||||||
|
|
||||||
sessionRes, err := internalclient.CreateSession(sessionPrm)
|
sessionRes, err := internalclient.CreateSession(sessionPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't open session: %w", err)
|
return fmt.Errorf("can't open session: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tok := session.NewToken()
|
binIDSession := sessionRes.ID()
|
||||||
tok.SetID(sessionRes.ID())
|
|
||||||
tok.SetSessionKey(sessionRes.SessionKey())
|
|
||||||
tok.SetOwnerID(owner)
|
|
||||||
tok.SetExp(exp)
|
|
||||||
tok.SetIat(cur)
|
|
||||||
tok.SetNbf(cur)
|
|
||||||
|
|
||||||
return tok, nil
|
var keySession neofsecdsa.PublicKey
|
||||||
|
|
||||||
|
err = keySession.Decode(sessionRes.SessionKey())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode public session key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var idSession uuid.UUID
|
||||||
|
|
||||||
|
err = idSession.UnmarshalBinary(binIDSession)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode session ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.SetID(idSession)
|
||||||
|
dst.SetNbf(cur)
|
||||||
|
dst.SetIat(cur)
|
||||||
|
dst.SetExp(exp)
|
||||||
|
dst.SetAuthKey(&keySession)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
"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-node/cmd/neofs-cli/internal/commonflags"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,10 +31,19 @@ func initSignSessionCmd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func signSessionToken(cmd *cobra.Command, _ []string) {
|
func signSessionToken(cmd *cobra.Command, _ []string) {
|
||||||
stok := common.ReadSessionToken(cmd, signFromFlag)
|
fPath, err := cmd.Flags().GetString(signFromFlag)
|
||||||
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
|
if fPath == "" {
|
||||||
|
common.ExitOnErr(cmd, "", errors.New("missing session token flag"))
|
||||||
|
}
|
||||||
|
|
||||||
|
var stok session.Object
|
||||||
|
common.ReadSessionToken(cmd, &stok, signFromFlag)
|
||||||
|
|
||||||
pk := key.GetOrGenerate(cmd)
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
err := stok.Sign(pk)
|
err = stok.Sign(*pk)
|
||||||
common.ExitOnErr(cmd, "can't sign token: %w", err)
|
common.ExitOnErr(cmd, "can't sign token: %w", err)
|
||||||
|
|
||||||
data, err := stok.MarshalJSON()
|
data, err := stok.MarshalJSON()
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -19,7 +19,7 @@ require (
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220321144137-d5a9af5860af // indirect
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220321144137-d5a9af5860af // indirect
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1
|
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1
|
||||||
github.com/nspcc-dev/neofs-contract v0.15.1
|
github.com/nspcc-dev/neofs-contract v0.15.1
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220424111116-497053c785f5
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220525080251-1f7fe6864d34
|
||||||
github.com/nspcc-dev/tzhash v1.5.2
|
github.com/nspcc-dev/tzhash v1.5.2
|
||||||
github.com/panjf2000/ants/v2 v2.4.0
|
github.com/panjf2000/ants/v2 v2.4.0
|
||||||
github.com/paulmach/orb v0.2.2
|
github.com/paulmach/orb v0.2.2
|
||||||
|
|
BIN
go.sum
BIN
go.sum
Binary file not shown.
|
@ -12,7 +12,7 @@ type RemovalWitness struct {
|
||||||
|
|
||||||
sig []byte
|
sig []byte
|
||||||
|
|
||||||
token *session.Token
|
token *session.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerID returns the identifier of the container
|
// ContainerID returns the identifier of the container
|
||||||
|
@ -39,12 +39,12 @@ func (x *RemovalWitness) SetSignature(sig []byte) {
|
||||||
|
|
||||||
// SessionToken returns the token of the session within
|
// SessionToken returns the token of the session within
|
||||||
// which the container was removed.
|
// which the container was removed.
|
||||||
func (x RemovalWitness) SessionToken() *session.Token {
|
func (x RemovalWitness) SessionToken() *session.Container {
|
||||||
return x.token
|
return x.token
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSessionToken sets the token of the session within
|
// SetSessionToken sets the token of the session within
|
||||||
// which the container was removed.
|
// which the container was removed.
|
||||||
func (x *RemovalWitness) SetSessionToken(tok *session.Token) {
|
func (x *RemovalWitness) SetSessionToken(tok *session.Container) {
|
||||||
x.token = tok
|
x.token = tok
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
@ -139,10 +137,18 @@ func (v *FormatValidator) validateSignatureKey(obj *object.Object) error {
|
||||||
var sigV2 refs.Signature
|
var sigV2 refs.Signature
|
||||||
sig.WriteToV2(&sigV2)
|
sig.WriteToV2(&sigV2)
|
||||||
|
|
||||||
key := sigV2.GetKey()
|
binKey := sigV2.GetKey()
|
||||||
|
|
||||||
|
var key neofsecdsa.PublicKey
|
||||||
|
|
||||||
|
err := key.Decode(binKey)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode public key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
token := obj.SessionToken()
|
token := obj.SessionToken()
|
||||||
|
|
||||||
if token == nil || !bytes.Equal(token.SessionKey(), key) {
|
if token == nil || !token.AssertAuthKey(&key) {
|
||||||
return v.checkOwnerKey(obj.OwnerID(), key)
|
return v.checkOwnerKey(obj.OwnerID(), key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,14 +157,9 @@ func (v *FormatValidator) validateSignatureKey(obj *object.Object) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *FormatValidator) checkOwnerKey(id *user.ID, key []byte) error {
|
func (v *FormatValidator) checkOwnerKey(id *user.ID, key neofsecdsa.PublicKey) error {
|
||||||
pub, err := keys.NewPublicKeyFromBytes(key, elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var id2 user.ID
|
var id2 user.ID
|
||||||
user.IDFromKey(&id2, (ecdsa.PublicKey)(*pub))
|
user.IDFromKey(&id2, (ecdsa.PublicKey)(key))
|
||||||
|
|
||||||
if !id.Equals(id2) {
|
if !id.Equals(id2) {
|
||||||
return fmt.Errorf("(%T) different owner identifiers %s/%s", v, id, id2)
|
return fmt.Errorf("(%T) different owner identifiers %s/%s", v, id, id2)
|
||||||
|
|
|
@ -88,13 +88,13 @@ func TestFormatValidator_Validate(t *testing.T) {
|
||||||
var idOwner user.ID
|
var idOwner user.ID
|
||||||
user.IDFromKey(&idOwner, ownerKey.PrivateKey.PublicKey)
|
user.IDFromKey(&idOwner, ownerKey.PrivateKey.PublicKey)
|
||||||
|
|
||||||
tok := sessiontest.Token()
|
tok := sessiontest.Object()
|
||||||
tok.SetOwnerID(&idOwner)
|
tok.Sign(ownerKey.PrivateKey)
|
||||||
|
|
||||||
obj := object.New()
|
obj := object.New()
|
||||||
obj.SetContainerID(cidtest.ID())
|
obj.SetContainerID(cidtest.ID())
|
||||||
obj.SetSessionToken(sessiontest.Token())
|
obj.SetSessionToken(tok)
|
||||||
obj.SetOwnerID(tok.OwnerID())
|
obj.SetOwnerID(&idOwner)
|
||||||
|
|
||||||
require.NoError(t, object.SetIDWithSignature(ownerKey.PrivateKey, obj))
|
require.NoError(t, object.SetIDWithSignature(ownerKey.PrivateKey, obj))
|
||||||
|
|
||||||
|
|
|
@ -3,184 +3,167 @@ package container
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/neofsid"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client/neofsid"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
|
||||||
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errWrongSessionContext = errors.New("wrong session context")
|
|
||||||
errWrongSessionVerb = errors.New("wrong token verb")
|
errWrongSessionVerb = errors.New("wrong token verb")
|
||||||
errWrongCID = errors.New("wrong container ID")
|
errWrongCID = errors.New("wrong container ID")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ownerIDSource interface {
|
type signatureVerificationData struct {
|
||||||
OwnerID() *user.ID
|
ownerContainer user.ID
|
||||||
|
|
||||||
|
verb session.ContainerVerb
|
||||||
|
|
||||||
|
idContainerSet bool
|
||||||
|
idContainer cid.ID
|
||||||
|
|
||||||
|
binTokenSession []byte
|
||||||
|
|
||||||
|
binPublicKey []byte
|
||||||
|
|
||||||
|
signature []byte
|
||||||
|
|
||||||
|
signedData []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func tokenFromEvent(src interface {
|
// verifySignature is a common method of Container service authentication. Asserts that:
|
||||||
SessionToken() []byte
|
// - for trusted parties: session is valid (*) and issued by container owner
|
||||||
}) (*session.Token, error) {
|
// - operation data is signed by container owner or trusted party
|
||||||
binToken := src.SessionToken()
|
// - operation data signature is correct
|
||||||
|
//
|
||||||
|
// (*) includes:
|
||||||
|
// - session token decodes correctly
|
||||||
|
// - signature is valid
|
||||||
|
// - session issued by the container owner
|
||||||
|
// - v.binPublicKey is a public session key
|
||||||
|
// - session context corresponds to the container and verb in v
|
||||||
|
// - session is "alive"
|
||||||
|
func (cp *Processor) verifySignature(v signatureVerificationData) error {
|
||||||
|
var err error
|
||||||
|
var key neofsecdsa.PublicKeyRFC6979
|
||||||
|
keyProvided := v.binPublicKey != nil
|
||||||
|
withSession := len(v.binTokenSession) > 0
|
||||||
|
|
||||||
if len(binToken) == 0 {
|
if keyProvided {
|
||||||
return nil, nil
|
err = key.Decode(v.binPublicKey)
|
||||||
}
|
|
||||||
|
|
||||||
tok := session.NewToken()
|
|
||||||
|
|
||||||
err := tok.Unmarshal(binToken)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not unmarshal session token: %w", err)
|
return fmt.Errorf("decode public key: %w", err)
|
||||||
}
|
|
||||||
|
|
||||||
return tok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *Processor) checkKeyOwnership(ownerIDSrc ownerIDSource, key *keys.PublicKey) error {
|
|
||||||
if tokenSrc, ok := ownerIDSrc.(interface {
|
|
||||||
SessionToken() *session.Token
|
|
||||||
}); ok {
|
|
||||||
if token := tokenSrc.SessionToken(); token != nil {
|
|
||||||
return cp.checkKeyOwnershipWithToken(ownerIDSrc, key, tokenSrc.SessionToken())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ownerSrc := ownerIDSrc.OwnerID()
|
if withSession {
|
||||||
if ownerSrc == nil {
|
var tok session.Container
|
||||||
return errors.New("missing owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
var ownerKey user.ID
|
err = tok.Unmarshal(v.binTokenSession)
|
||||||
user.IDFromKey(&ownerKey, (ecdsa.PublicKey)(*key))
|
|
||||||
|
|
||||||
if ownerSrc.Equals(ownerKey) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
prm := neofsid.AccountKeysPrm{}
|
|
||||||
prm.SetID(ownerIDSrc.OwnerID())
|
|
||||||
|
|
||||||
ownerKeys, err := cp.idClient.AccountKeys(prm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not received owner keys %s: %w", ownerIDSrc.OwnerID(), err)
|
return fmt.Errorf("decode session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ownerKey := range ownerKeys {
|
if !tok.VerifySignature() {
|
||||||
if ownerKey.Equal(key) {
|
return errors.New("invalid session token signature")
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("key %s is not tied to the owner of the container", key)
|
// FIXME(@cthulhu-rider): #1387 check token is signed by container owner, see neofs-sdk-go#233
|
||||||
}
|
// We'll get container owner's keys which is needed below, so it's worth to cache them
|
||||||
|
|
||||||
func (cp *Processor) checkKeyOwnershipWithToken(ownerIDSrc ownerIDSource, key *keys.PublicKey, token *session.Token) error {
|
if keyProvided && !tok.AssertAuthKey(&key) {
|
||||||
// check session key
|
|
||||||
if !bytes.Equal(
|
|
||||||
key.Bytes(),
|
|
||||||
token.SessionKey(),
|
|
||||||
) {
|
|
||||||
return errors.New("signed with a non-session key")
|
return errors.New("signed with a non-session key")
|
||||||
}
|
}
|
||||||
|
|
||||||
ownerToken, ownerSrc := token.OwnerID(), ownerIDSrc.OwnerID()
|
if !tok.AssertVerb(v.verb) {
|
||||||
|
return errWrongSessionVerb
|
||||||
// check owner
|
|
||||||
if ownerToken == nil || ownerSrc == nil || !ownerToken.Equals(*ownerSrc) {
|
|
||||||
return errors.New("owner differs with token owner")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := cp.checkSessionToken(token)
|
if v.idContainerSet && !tok.AppliedTo(v.idContainer) {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid session token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *Processor) checkSessionToken(token *session.Token) error {
|
|
||||||
// verify signature
|
|
||||||
if !token.VerifySignature() {
|
|
||||||
return errors.New("invalid signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
// check lifetime
|
|
||||||
err := cp.checkTokenLifetime(token)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// check token owner's key ownership
|
|
||||||
|
|
||||||
// FIXME(@cthulhu-rider): #1387 see neofs-sdk-go#233
|
|
||||||
key, err := keys.NewPublicKeyFromBytes(token.ToV2().GetSignature().GetKey(), elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cp.checkKeyOwnership(token, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
type verbAssert func(*session.ContainerContext) bool
|
|
||||||
|
|
||||||
func contextWithVerifiedVerb(tok *session.Token, verbAssert verbAssert) (*session.ContainerContext, error) {
|
|
||||||
c := session.GetContainerContext(tok)
|
|
||||||
if c == nil {
|
|
||||||
return nil, errWrongSessionContext
|
|
||||||
}
|
|
||||||
|
|
||||||
if !verbAssert(c) {
|
|
||||||
return nil, errWrongSessionVerb
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkTokenContext(tok *session.Token, verbAssert verbAssert) error {
|
|
||||||
_, err := contextWithVerifiedVerb(tok, verbAssert)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkTokenContextWithCID(tok *session.Token, id cid.ID, verbAssert verbAssert) error {
|
|
||||||
c, err := contextWithVerifiedVerb(tok, verbAssert)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tokCID := c.Container()
|
|
||||||
if tokCID != nil && !tokCID.Equals(id) {
|
|
||||||
return errWrongCID
|
return errWrongCID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !session.IssuedBy(tok, v.ownerContainer) {
|
||||||
|
return errors.New("owner differs with token owner")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cp.checkTokenLifetime(tok)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("check session lifetime: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var verificationKeys []neofscrypto.PublicKey
|
||||||
|
|
||||||
|
if keyProvided {
|
||||||
|
if withSession {
|
||||||
|
verificationKeys = []neofscrypto.PublicKey{&key}
|
||||||
|
} else {
|
||||||
|
var idFromKey user.ID
|
||||||
|
user.IDFromKey(&idFromKey, (ecdsa.PublicKey)(key))
|
||||||
|
|
||||||
|
if v.ownerContainer.Equals(idFromKey) {
|
||||||
|
verificationKeys = []neofscrypto.PublicKey{&key}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if verificationKeys == nil {
|
||||||
|
var prm neofsid.AccountKeysPrm
|
||||||
|
prm.SetID(&v.ownerContainer)
|
||||||
|
|
||||||
|
ownerKeys, err := cp.idClient.AccountKeys(prm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("receive owner keys %s: %w", v.ownerContainer, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !keyProvided {
|
||||||
|
verificationKeys = make([]neofscrypto.PublicKey, 0, len(ownerKeys))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range ownerKeys {
|
||||||
|
if keyProvided {
|
||||||
|
// TODO(@cthulhu-rider): keys have been decoded in order to encode only, should be optimized by #1387
|
||||||
|
if bytes.Equal(ownerKeys[i].Bytes(), v.binPublicKey) {
|
||||||
|
verificationKeys = []neofscrypto.PublicKey{(*neofsecdsa.PublicKeyRFC6979)(ownerKeys[i])}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
verificationKeys = append(verificationKeys, (*neofsecdsa.PublicKeyRFC6979)(ownerKeys[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(verificationKeys) == 0 {
|
||||||
|
return errors.New("key is not a container owner's key")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range verificationKeys {
|
||||||
|
if verificationKeys[i].Verify(v.signedData, v.signature) {
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("invalid signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) checkTokenLifetime(token *session.Token) error {
|
func (cp *Processor) checkTokenLifetime(token session.Container) error {
|
||||||
curEpoch, err := cp.netState.Epoch()
|
curEpoch, err := cp.netState.Epoch()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not read current epoch: %w", err)
|
return fmt.Errorf("could not read current epoch: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nbf := token.Nbf()
|
if token.ExpiredAt(curEpoch) {
|
||||||
if curEpoch < nbf {
|
return fmt.Errorf("token is expired at %d", curEpoch)
|
||||||
return fmt.Errorf("token is not valid yet: nbf %d, cur %d", nbf, curEpoch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iat := token.Iat()
|
if token.InvalidAt(curEpoch) {
|
||||||
if curEpoch < iat {
|
return fmt.Errorf("token is not valid at %d", curEpoch)
|
||||||
return fmt.Errorf("token is issued in future: iat %d, cur %d", iat, curEpoch)
|
|
||||||
}
|
|
||||||
|
|
||||||
exp := token.Exp()
|
|
||||||
if curEpoch >= exp {
|
|
||||||
return fmt.Errorf("token is expired: exp %d, cur %d", exp, curEpoch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/sha256"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||||
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/neofsid"
|
|
||||||
morphsubnet "github.com/nspcc-dev/neofs-node/pkg/morph/client/subnet"
|
morphsubnet "github.com/nspcc-dev/neofs-node/pkg/morph/client/subnet"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
||||||
containerEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/container"
|
containerEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/container"
|
||||||
|
@ -62,29 +58,32 @@ func (cp *Processor) processContainerPut(put putEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
||||||
e := ctx.e
|
binCnr := ctx.e.Container()
|
||||||
|
|
||||||
// verify signature
|
|
||||||
key, err := keys.NewPublicKeyFromBytes(e.PublicKey(), elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
binCnr := e.Container()
|
|
||||||
tableHash := sha256.Sum256(binCnr)
|
|
||||||
|
|
||||||
if !key.Verify(e.Signature(), tableHash[:]) {
|
|
||||||
return errors.New("invalid signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmarshal container structure
|
|
||||||
cnr := containerSDK.New()
|
cnr := containerSDK.New()
|
||||||
|
|
||||||
err = cnr.Unmarshal(binCnr)
|
err := cnr.Unmarshal(binCnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid binary container: %w", err)
|
return fmt.Errorf("invalid binary container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ownerContainer := cnr.OwnerID()
|
||||||
|
if ownerContainer == nil {
|
||||||
|
return errors.New("missing container owner")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cp.verifySignature(signatureVerificationData{
|
||||||
|
ownerContainer: *ownerContainer,
|
||||||
|
verb: session.VerbContainerPut,
|
||||||
|
binTokenSession: ctx.e.SessionToken(),
|
||||||
|
binPublicKey: ctx.e.PublicKey(),
|
||||||
|
signature: ctx.e.Signature(),
|
||||||
|
signedData: binCnr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("auth container creation: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// check owner allowance in the subnetwork
|
// check owner allowance in the subnetwork
|
||||||
err = checkSubnet(cp.subnetClient, cnr)
|
err = checkSubnet(cp.subnetClient, cnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -103,25 +102,7 @@ func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
||||||
return fmt.Errorf("incorrect container format: %w", err)
|
return fmt.Errorf("incorrect container format: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmarshal session token if presented
|
return nil
|
||||||
tok, err := tokenFromEvent(e)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if tok != nil {
|
|
||||||
// check token context
|
|
||||||
err = checkTokenContext(tok, func(c *session.ContainerContext) bool {
|
|
||||||
return c.IsForPut()
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cnr.SetSessionToken(tok)
|
|
||||||
|
|
||||||
return cp.checkKeyOwnership(cnr, key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) approvePutContainer(ctx *putContainerContext) {
|
func (cp *Processor) approvePutContainer(ctx *putContainerContext) {
|
||||||
|
@ -175,70 +156,38 @@ func (cp *Processor) processContainerDelete(delete *containerEvent.Delete) {
|
||||||
func (cp *Processor) checkDeleteContainer(e *containerEvent.Delete) error {
|
func (cp *Processor) checkDeleteContainer(e *containerEvent.Delete) error {
|
||||||
binCID := e.ContainerID()
|
binCID := e.ContainerID()
|
||||||
|
|
||||||
|
var idCnr cid.ID
|
||||||
|
|
||||||
|
err := idCnr.Decode(binCID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid container ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// receive owner of the related container
|
// receive owner of the related container
|
||||||
cnr, err := cp.cnrClient.Get(binCID)
|
cnr, err := cp.cnrClient.Get(binCID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not receive the container: %w", err)
|
return fmt.Errorf("could not receive the container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := tokenFromEvent(e)
|
ownerContainer := cnr.OwnerID()
|
||||||
if err != nil {
|
if ownerContainer == nil {
|
||||||
return err
|
return errors.New("missing container owner")
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkKeys keys.PublicKeys
|
err = cp.verifySignature(signatureVerificationData{
|
||||||
|
ownerContainer: *ownerContainer,
|
||||||
if token != nil {
|
verb: session.VerbContainerDelete,
|
||||||
// check token context
|
idContainerSet: true,
|
||||||
// TODO: #1147 think how to avoid version casts
|
idContainer: idCnr,
|
||||||
var id cid.ID
|
binTokenSession: e.SessionToken(),
|
||||||
|
signature: e.Signature(),
|
||||||
err = id.Decode(binCID)
|
signedData: binCID,
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("decode container ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = checkTokenContextWithCID(token, id, func(c *session.ContainerContext) bool {
|
|
||||||
return c.IsForDelete()
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("auth container creation: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := keys.NewPublicKeyFromBytes(token.SessionKey(), elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid session key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check token ownership
|
|
||||||
err = cp.checkKeyOwnershipWithToken(cnr, key, token)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
checkKeys = keys.PublicKeys{key}
|
|
||||||
} else {
|
|
||||||
prm := neofsid.AccountKeysPrm{}
|
|
||||||
prm.SetID(cnr.OwnerID())
|
|
||||||
|
|
||||||
// receive all owner keys from NeoFS ID contract
|
|
||||||
checkKeys, err = cp.idClient.AccountKeys(prm)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not received owner keys %s: %w", cnr.OwnerID(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify signature
|
|
||||||
cidHash := sha256.Sum256(binCID)
|
|
||||||
sig := e.Signature()
|
|
||||||
|
|
||||||
for _, key := range checkKeys {
|
|
||||||
if key.Verify(sig, cidHash[:]) {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("signature verification failed on all owner keys ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) approveDeleteContainer(e *containerEvent.Delete) {
|
func (cp *Processor) approveDeleteContainer(e *containerEvent.Delete) {
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/sha256"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event/container"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/event/container"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
|
@ -33,25 +30,12 @@ func (cp *Processor) processSetEACL(e container.SetEACL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) checkSetEACL(e container.SetEACL) error {
|
func (cp *Processor) checkSetEACL(e container.SetEACL) error {
|
||||||
// verify signature
|
|
||||||
key, err := keys.NewPublicKeyFromBytes(e.PublicKey(), elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
binTable := e.Table()
|
binTable := e.Table()
|
||||||
tableHash := sha256.Sum256(binTable)
|
|
||||||
|
|
||||||
if !key.Verify(e.Signature(), tableHash[:]) {
|
|
||||||
return errors.New("invalid signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify the identity of the container owner
|
|
||||||
|
|
||||||
// unmarshal table
|
// unmarshal table
|
||||||
table := eacl.NewTable()
|
table := eacl.NewTable()
|
||||||
|
|
||||||
err = table.Unmarshal(binTable)
|
err := table.Unmarshal(binTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid binary table: %w", err)
|
return fmt.Errorf("invalid binary table: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -67,30 +51,26 @@ func (cp *Processor) checkSetEACL(e container.SetEACL) error {
|
||||||
return fmt.Errorf("could not receive the container: %w", err)
|
return fmt.Errorf("could not receive the container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmarshal session token if presented
|
ownerContainer := cnr.OwnerID()
|
||||||
tok, err := tokenFromEvent(e)
|
if ownerContainer == nil {
|
||||||
if err != nil {
|
return errors.New("missing container owner")
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tok != nil {
|
err = cp.verifySignature(signatureVerificationData{
|
||||||
// check token context
|
ownerContainer: *ownerContainer,
|
||||||
err = checkTokenContextWithCID(tok, idCnr, func(c *session.ContainerContext) bool {
|
verb: session.VerbContainerSetEACL,
|
||||||
return c.IsForSetEACL()
|
idContainerSet: true,
|
||||||
|
idContainer: idCnr,
|
||||||
|
binTokenSession: e.SessionToken(),
|
||||||
|
binPublicKey: e.PublicKey(),
|
||||||
|
signature: e.Signature(),
|
||||||
|
signedData: binTable,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("auth eACL table setting: %w", err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// statement below is a little hack, but if we write a token from an event to the container,
|
return nil
|
||||||
// checkKeyOwnership method will work just as it should:
|
|
||||||
// * tok == nil => we will check if key is a container owner's key
|
|
||||||
// * tok != nil => we will check if token was signed correctly (context is checked at the statement above)
|
|
||||||
cnr.SetSessionToken(tok)
|
|
||||||
|
|
||||||
// check key ownership
|
|
||||||
return cp.checkKeyOwnership(cnr, key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) approveSetEACL(e container.SetEACL) {
|
func (cp *Processor) approveSetEACL(e container.SetEACL) {
|
||||||
|
|
|
@ -18,20 +18,19 @@ func Delete(c *Client, witness core.RemovalWitness) error {
|
||||||
return errNilArgument
|
return errNilArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
binToken, err := witness.SessionToken().Marshal()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not marshal session token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
binCnr := make([]byte, sha256.Size)
|
binCnr := make([]byte, sha256.Size)
|
||||||
id.Encode(binCnr)
|
id.Encode(binCnr)
|
||||||
|
|
||||||
return c.Delete(
|
var prm DeletePrm
|
||||||
DeletePrm{
|
|
||||||
cid: binCnr,
|
prm.SetCID(binCnr)
|
||||||
signature: witness.Signature(),
|
prm.SetSignature(witness.Signature())
|
||||||
token: binToken,
|
|
||||||
})
|
if tok := witness.SessionToken(); tok != nil {
|
||||||
|
prm.SetToken(tok.Marshal())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Delete(prm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePrm groups parameters of Delete client operation.
|
// DeletePrm groups parameters of Delete client operation.
|
||||||
|
|
|
@ -77,14 +77,14 @@ func (c *Client) GetEACL(cnr *cid.ID) (*eacl.Table, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(binToken) > 0 {
|
if len(binToken) > 0 {
|
||||||
tok := session.NewToken()
|
var tok session.Container
|
||||||
|
|
||||||
err = tok.Unmarshal(binToken)
|
err = tok.Unmarshal(binToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not unmarshal session token: %w", err)
|
return nil, fmt.Errorf("could not unmarshal session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
table.SetSessionToken(tok)
|
table.SetSessionToken(&tok)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(@cthulhu-rider): #1387 temp solution, later table structure won't have a signature
|
// FIXME(@cthulhu-rider): #1387 temp solution, later table structure won't have a signature
|
||||||
|
|
|
@ -24,14 +24,12 @@ func PutEACL(c *Client, table *eacl.Table) error {
|
||||||
return fmt.Errorf("can't marshal eacl table: %w", err)
|
return fmt.Errorf("can't marshal eacl table: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
binToken, err := table.SessionToken().Marshal()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not marshal session token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var prm PutEACLPrm
|
var prm PutEACLPrm
|
||||||
prm.SetTable(data)
|
prm.SetTable(data)
|
||||||
prm.SetToken(binToken)
|
|
||||||
|
if tok := table.SessionToken(); tok != nil {
|
||||||
|
prm.SetToken(tok.Marshal())
|
||||||
|
}
|
||||||
|
|
||||||
if sig := table.Signature(); sig != nil {
|
if sig := table.Signature(); sig != nil {
|
||||||
// TODO(@cthulhu-rider): #1387 implement and use another approach to avoid conversion
|
// TODO(@cthulhu-rider): #1387 implement and use another approach to avoid conversion
|
||||||
|
|
|
@ -96,14 +96,14 @@ func (c *Client) Get(cid []byte) (*container.Container, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tokBytes) > 0 {
|
if len(tokBytes) > 0 {
|
||||||
tok := session.NewToken()
|
var tok session.Container
|
||||||
|
|
||||||
err = tok.Unmarshal(tokBytes)
|
err = tok.Unmarshal(tokBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not unmarshal session token: %w", err)
|
return nil, fmt.Errorf("could not unmarshal session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cnr.SetSessionToken(tok)
|
cnr.SetSessionToken(&tok)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(@cthulhu-rider): #1387 temp solution, later table structure won't have a signature
|
// FIXME(@cthulhu-rider): #1387 temp solution, later table structure won't have a signature
|
||||||
|
|
|
@ -24,19 +24,17 @@ func Put(c *Client, cnr *container.Container) (*cid.ID, error) {
|
||||||
return nil, fmt.Errorf("can't marshal container: %w", err)
|
return nil, fmt.Errorf("can't marshal container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
binToken, err := cnr.SessionToken().Marshal()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not marshal session token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
name, zone := container.GetNativeNameWithZone(cnr)
|
name, zone := container.GetNativeNameWithZone(cnr)
|
||||||
|
|
||||||
var prm PutPrm
|
var prm PutPrm
|
||||||
prm.SetContainer(data)
|
prm.SetContainer(data)
|
||||||
prm.SetToken(binToken)
|
|
||||||
prm.SetName(name)
|
prm.SetName(name)
|
||||||
prm.SetZone(zone)
|
prm.SetZone(zone)
|
||||||
|
|
||||||
|
if tok := cnr.SessionToken(); tok != nil {
|
||||||
|
prm.SetToken(tok.Marshal())
|
||||||
|
}
|
||||||
|
|
||||||
if sig := cnr.Signature(); sig != nil {
|
if sig := cnr.Signature(); sig != nil {
|
||||||
// TODO(@cthulhu-rider): #1387 implement and use another approach to avoid conversion
|
// TODO(@cthulhu-rider): #1387 implement and use another approach to avoid conversion
|
||||||
var sigV2 refs.Signature
|
var sigV2 refs.Signature
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/container"
|
"github.com/nspcc-dev/neofs-api-go/v2/container"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
sessionV2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
containercore "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
containercore "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||||
containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container"
|
containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
|
||||||
|
@ -44,10 +45,6 @@ type Writer interface {
|
||||||
PutEACL(*eaclSDK.Table) error
|
PutEACL(*eaclSDK.Table) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrInvalidContext is thrown by morph ServiceExecutor when provided session
|
|
||||||
// token does not contain expected container context.
|
|
||||||
var ErrInvalidContext = errors.New("session token does not contain container context")
|
|
||||||
|
|
||||||
func NewExecutor(rdr Reader, wrt Writer) containerSvc.ServiceExecutor {
|
func NewExecutor(rdr Reader, wrt Writer) containerSvc.ServiceExecutor {
|
||||||
return &morphExecutor{
|
return &morphExecutor{
|
||||||
rdr: rdr,
|
rdr: rdr,
|
||||||
|
@ -69,12 +66,16 @@ func (s *morphExecutor) Put(ctx containerSvc.ContextWithToken, body *container.P
|
||||||
|
|
||||||
cnr.SetSignature(&sig)
|
cnr.SetSignature(&sig)
|
||||||
|
|
||||||
tok := session.NewTokenFromV2(ctx.SessionToken)
|
if ctx.SessionToken != nil {
|
||||||
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
|
var tok session.Container
|
||||||
return nil, ErrInvalidContext
|
|
||||||
|
err := tok.ReadFromV2(*ctx.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cnr.SetSessionToken(tok)
|
cnr.SetSessionToken(&tok)
|
||||||
|
}
|
||||||
|
|
||||||
idCnr, err := s.wrt.Put(cnr)
|
idCnr, err := s.wrt.Put(cnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -105,9 +106,15 @@ func (s *morphExecutor) Delete(ctx containerSvc.ContextWithToken, body *containe
|
||||||
|
|
||||||
sig := body.GetSignature().GetSign()
|
sig := body.GetSignature().GetSign()
|
||||||
|
|
||||||
tok := session.NewTokenFromV2(ctx.SessionToken)
|
var tok *session.Container
|
||||||
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
|
|
||||||
return nil, ErrInvalidContext
|
if ctx.SessionToken != nil {
|
||||||
|
tok = new(session.Container)
|
||||||
|
|
||||||
|
err := tok.ReadFromV2(*ctx.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid session token: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rmWitness containercore.RemovalWitness
|
var rmWitness containercore.RemovalWitness
|
||||||
|
@ -149,10 +156,18 @@ func (s *morphExecutor) Get(ctx context.Context, body *container.GetRequestBody)
|
||||||
sig.WriteToV2(sigV2)
|
sig.WriteToV2(sigV2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tokV2 *sessionV2.Token
|
||||||
|
|
||||||
|
if tok := cnr.SessionToken(); tok != nil {
|
||||||
|
tokV2 = new(sessionV2.Token)
|
||||||
|
|
||||||
|
tok.WriteToV2(tokV2)
|
||||||
|
}
|
||||||
|
|
||||||
res := new(container.GetResponseBody)
|
res := new(container.GetResponseBody)
|
||||||
res.SetContainer(cnr.ToV2())
|
res.SetContainer(cnr.ToV2())
|
||||||
res.SetSignature(sigV2)
|
res.SetSignature(sigV2)
|
||||||
res.SetSessionToken(cnr.SessionToken().ToV2())
|
res.SetSessionToken(tokV2)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -200,12 +215,16 @@ func (s *morphExecutor) SetExtendedACL(ctx containerSvc.ContextWithToken, body *
|
||||||
|
|
||||||
table.SetSignature(&sig)
|
table.SetSignature(&sig)
|
||||||
|
|
||||||
tok := session.NewTokenFromV2(ctx.SessionToken)
|
if ctx.SessionToken != nil {
|
||||||
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
|
var tok session.Container
|
||||||
return nil, ErrInvalidContext
|
|
||||||
|
err := tok.ReadFromV2(*ctx.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
table.SetSessionToken(tok)
|
table.SetSessionToken(&tok)
|
||||||
|
}
|
||||||
|
|
||||||
err := s.wrt.PutEACL(table)
|
err := s.wrt.PutEACL(table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -240,10 +259,18 @@ func (s *morphExecutor) GetExtendedACL(ctx context.Context, body *container.GetE
|
||||||
sig.WriteToV2(sigV2)
|
sig.WriteToV2(sigV2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tokV2 *sessionV2.Token
|
||||||
|
|
||||||
|
if tok := table.SessionToken(); tok != nil {
|
||||||
|
tokV2 = new(sessionV2.Token)
|
||||||
|
|
||||||
|
tok.WriteToV2(tokV2)
|
||||||
|
}
|
||||||
|
|
||||||
res := new(container.GetExtendedACLResponseBody)
|
res := new(container.GetExtendedACLResponseBody)
|
||||||
res.SetEACL(table.ToV2())
|
res.SetEACL(table.ToV2())
|
||||||
res.SetSignature(sigV2)
|
res.SetSignature(sigV2)
|
||||||
res.SetSessionToken(table.SessionToken().ToV2())
|
res.SetSessionToken(tokV2)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
|
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,6 +43,9 @@ func TestInvalidToken(t *testing.T) {
|
||||||
var cnrV2 refs.ContainerID
|
var cnrV2 refs.ContainerID
|
||||||
cnr.WriteToV2(&cnrV2)
|
cnr.WriteToV2(&cnrV2)
|
||||||
|
|
||||||
|
var tokV2 session.Token
|
||||||
|
sessiontest.ContainerSigned().WriteToV2(&tokV2)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
op func(e containerSvc.ServiceExecutor, ctx containerSvc.ContextWithToken) error
|
op func(e containerSvc.ServiceExecutor, ctx containerSvc.ContextWithToken) error
|
||||||
|
@ -84,9 +88,9 @@ func TestInvalidToken(t *testing.T) {
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
SessionToken: generateToken(new(session.ObjectSessionContext)),
|
SessionToken: generateToken(new(session.ObjectSessionContext)),
|
||||||
}
|
}
|
||||||
require.Error(t, test.op(e, ctx), containerSvcMorph.ErrInvalidContext)
|
require.Error(t, test.op(e, ctx))
|
||||||
|
|
||||||
ctx.SessionToken = generateToken(new(session.ContainerSessionContext))
|
ctx.SessionToken = &tokV2
|
||||||
require.NoError(t, test.op(e, ctx))
|
require.NoError(t, test.op(e, ctx))
|
||||||
|
|
||||||
ctx.SessionToken = nil
|
ctx.SessionToken = nil
|
||||||
|
|
|
@ -84,6 +84,16 @@ func (h headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eaclSDK.Hea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type xHeader session.XHeader
|
||||||
|
|
||||||
|
func (x xHeader) Key() string {
|
||||||
|
return (*session.XHeader)(&x).GetKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x xHeader) Value() string {
|
||||||
|
return (*session.XHeader)(&x).GetValue()
|
||||||
|
}
|
||||||
|
|
||||||
func requestHeaders(msg xHeaderSource) []eaclSDK.Header {
|
func requestHeaders(msg xHeaderSource) []eaclSDK.Header {
|
||||||
return msg.GetXHeaders()
|
return msg.GetXHeaders()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type xHeaderSource interface {
|
type xHeaderSource interface {
|
||||||
|
@ -30,7 +30,7 @@ func (s requestXHeaderSource) GetXHeaders() []eaclSDK.Header {
|
||||||
for meta := s.req.GetMetaHeader(); meta != nil; meta = meta.GetOrigin() {
|
for meta := s.req.GetMetaHeader(); meta != nil; meta = meta.GetOrigin() {
|
||||||
x := meta.GetXHeaders()
|
x := meta.GetXHeaders()
|
||||||
for i := range x {
|
for i := range x {
|
||||||
res = append(res, sessionSDK.NewXHeaderFromV2(&x[i]))
|
res = append(res, (xHeader)(x[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,16 +39,21 @@ func (s requestXHeaderSource) GetXHeaders() []eaclSDK.Header {
|
||||||
|
|
||||||
func (s responseXHeaderSource) GetXHeaders() []eaclSDK.Header {
|
func (s responseXHeaderSource) GetXHeaders() []eaclSDK.Header {
|
||||||
ln := 0
|
ln := 0
|
||||||
|
xHdrs := make([][]session.XHeader, 0)
|
||||||
|
|
||||||
for meta := s.req.GetMetaHeader(); meta != nil; meta = meta.GetOrigin() {
|
for meta := s.req.GetMetaHeader(); meta != nil; meta = meta.GetOrigin() {
|
||||||
ln += len(meta.GetXHeaders())
|
x := meta.GetXHeaders()
|
||||||
|
|
||||||
|
ln += len(x)
|
||||||
|
|
||||||
|
xHdrs = append(xHdrs, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]eaclSDK.Header, 0, ln)
|
res := make([]eaclSDK.Header, 0, ln)
|
||||||
for meta := s.req.GetMetaHeader(); meta != nil; meta = meta.GetOrigin() {
|
|
||||||
x := meta.GetXHeaders()
|
for i := range xHdrs {
|
||||||
for i := range x {
|
for j := range xHdrs[i] {
|
||||||
res = append(res, sessionSDK.NewXHeaderFromV2(&x[i]))
|
res = append(res, xHeader(xHdrs[i][j]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ func (r RequestInfo) RequestRole() eaclSDK.Role {
|
||||||
// verification header and raw API request.
|
// verification header and raw API request.
|
||||||
type MetaWithToken struct {
|
type MetaWithToken struct {
|
||||||
vheader *sessionV2.RequestVerificationHeader
|
vheader *sessionV2.RequestVerificationHeader
|
||||||
token *sessionSDK.Token
|
token *sessionSDK.Object
|
||||||
bearer *bearer.Token
|
bearer *bearer.Token
|
||||||
src interface{}
|
src interface{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,10 @@ func (b Service) Get(request *objectV2.GetRequest, stream object.GetObjectStream
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sTok := originalSessionToken(request.GetMetaHeader())
|
sTok, err := originalSessionToken(request.GetMetaHeader())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
req := MetaWithToken{
|
req := MetaWithToken{
|
||||||
vheader: request.GetVerificationHeader(),
|
vheader: request.GetVerificationHeader(),
|
||||||
|
@ -164,7 +167,10 @@ func (b Service) Head(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sTok := originalSessionToken(request.GetMetaHeader())
|
sTok, err := originalSessionToken(request.GetMetaHeader())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
req := MetaWithToken{
|
req := MetaWithToken{
|
||||||
vheader: request.GetVerificationHeader(),
|
vheader: request.GetVerificationHeader(),
|
||||||
|
@ -207,9 +213,14 @@ func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStr
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sTok, err := originalSessionToken(request.GetMetaHeader())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
req := MetaWithToken{
|
req := MetaWithToken{
|
||||||
vheader: request.GetVerificationHeader(),
|
vheader: request.GetVerificationHeader(),
|
||||||
token: originalSessionToken(request.GetMetaHeader()),
|
token: sTok,
|
||||||
bearer: originalBearerToken(request.GetMetaHeader()),
|
bearer: originalBearerToken(request.GetMetaHeader()),
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
@ -245,7 +256,10 @@ func (b Service) Delete(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sTok := originalSessionToken(request.GetMetaHeader())
|
sTok, err := originalSessionToken(request.GetMetaHeader())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
req := MetaWithToken{
|
req := MetaWithToken{
|
||||||
vheader: request.GetVerificationHeader(),
|
vheader: request.GetVerificationHeader(),
|
||||||
|
@ -281,7 +295,10 @@ func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetOb
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sTok := originalSessionToken(request.GetMetaHeader())
|
sTok, err := originalSessionToken(request.GetMetaHeader())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
req := MetaWithToken{
|
req := MetaWithToken{
|
||||||
vheader: request.GetVerificationHeader(),
|
vheader: request.GetVerificationHeader(),
|
||||||
|
@ -322,7 +339,10 @@ func (b Service) GetRangeHash(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sTok := originalSessionToken(request.GetMetaHeader())
|
sTok, err := originalSessionToken(request.GetMetaHeader())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
req := MetaWithToken{
|
req := MetaWithToken{
|
||||||
vheader: request.GetVerificationHeader(),
|
vheader: request.GetVerificationHeader(),
|
||||||
|
@ -377,7 +397,16 @@ func (p putStreamBasicChecker) Send(request *objectV2.PutRequest) error {
|
||||||
return fmt.Errorf("invalid object owner: %w", err)
|
return fmt.Errorf("invalid object owner: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sTok := sessionSDK.NewTokenFromV2(request.GetMetaHeader().GetSessionToken())
|
var sTok *sessionSDK.Object
|
||||||
|
|
||||||
|
if tokV2 := request.GetMetaHeader().GetSessionToken(); tokV2 != nil {
|
||||||
|
sTok = new(sessionSDK.Object)
|
||||||
|
|
||||||
|
err = sTok.ReadFromV2(*tokV2)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid session token: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
req := MetaWithToken{
|
req := MetaWithToken{
|
||||||
vheader: request.GetVerificationHeader(),
|
vheader: request.GetVerificationHeader(),
|
||||||
|
@ -449,14 +478,18 @@ func (b Service) findRequestInfo(
|
||||||
return info, errors.New("missing owner in container descriptor")
|
return info, errors.New("missing owner in container descriptor")
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.token != nil && req.token.Exp() != 0 {
|
if req.token != nil {
|
||||||
currentEpoch, err := b.nm.Epoch()
|
currentEpoch, err := b.nm.Epoch()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return info, errors.New("can't fetch current epoch")
|
return info, errors.New("can't fetch current epoch")
|
||||||
}
|
}
|
||||||
if req.token.Exp() < currentEpoch {
|
if req.token.ExpiredAt(currentEpoch) {
|
||||||
return info, fmt.Errorf("%w: token has expired (current epoch: %d, expired at %d)",
|
return info, fmt.Errorf("%w: token has expired (current epoch: %d)",
|
||||||
ErrMalformedRequest, currentEpoch, req.token.Exp())
|
ErrMalformedRequest, currentEpoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assertVerb(*req.token, op) {
|
||||||
|
return info, ErrInvalidVerb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,16 +503,10 @@ func (b Service) findRequestInfo(
|
||||||
return info, ErrUnknownRole
|
return info, ErrUnknownRole
|
||||||
}
|
}
|
||||||
|
|
||||||
// find verb from token if it is present
|
|
||||||
verb, isUnknown := sourceVerbOfRequest(req.token, op)
|
|
||||||
if !isUnknown && verb != op && !isVerbCompatible(verb, op) {
|
|
||||||
return info, ErrInvalidVerb
|
|
||||||
}
|
|
||||||
|
|
||||||
info.basicACL = cnr.BasicACL()
|
info.basicACL = cnr.BasicACL()
|
||||||
info.requestRole = res.role
|
info.requestRole = res.role
|
||||||
info.isInnerRing = res.isIR
|
info.isInnerRing = res.isIR
|
||||||
info.operation = verb
|
info.operation = op
|
||||||
info.cnrOwner = cnr.OwnerID()
|
info.cnrOwner = cnr.OwnerID()
|
||||||
info.idCnr = cid
|
info.idCnr = cid
|
||||||
|
|
||||||
|
|
|
@ -75,12 +75,24 @@ func originalBearerToken(header *sessionV2.RequestMetaHeader) *bearer.Token {
|
||||||
|
|
||||||
// originalSessionToken goes down to original request meta header and fetches
|
// originalSessionToken goes down to original request meta header and fetches
|
||||||
// session token from there.
|
// session token from there.
|
||||||
func originalSessionToken(header *sessionV2.RequestMetaHeader) *sessionSDK.Token {
|
func originalSessionToken(header *sessionV2.RequestMetaHeader) (*sessionSDK.Object, error) {
|
||||||
for header.GetOrigin() != nil {
|
for header.GetOrigin() != nil {
|
||||||
header = header.GetOrigin()
|
header = header.GetOrigin()
|
||||||
}
|
}
|
||||||
|
|
||||||
return sessionSDK.NewTokenFromV2(header.GetSessionToken())
|
tokV2 := header.GetSessionToken()
|
||||||
|
if tokV2 == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var tok sessionSDK.Object
|
||||||
|
|
||||||
|
err := tok.ReadFromV2(*tokV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid session token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getObjectIDFromRequestBody(body interface{}) (*oidSDK.ID, error) {
|
func getObjectIDFromRequestBody(body interface{}) (*oidSDK.ID, error) {
|
||||||
|
@ -113,58 +125,35 @@ func getObjectIDFromRequestBody(body interface{}) (*oidSDK.ID, error) {
|
||||||
return &id, nil
|
return &id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sourceVerbOfRequest looks for verb in session token and if it is not found,
|
func useObjectIDFromSession(req *RequestInfo, token *sessionSDK.Object) {
|
||||||
// returns reqVerb. Second return value is true if operation is unknown.
|
|
||||||
func sourceVerbOfRequest(tok *sessionSDK.Token, reqVerb eaclSDK.Operation) (eaclSDK.Operation, bool) {
|
|
||||||
ctx, ok := tok.Context().(*sessionSDK.ObjectContext)
|
|
||||||
if ok {
|
|
||||||
op := tokenVerbToOperation(ctx)
|
|
||||||
if op != eaclSDK.OperationUnknown {
|
|
||||||
return op, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reqVerb, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func useObjectIDFromSession(req *RequestInfo, token *sessionSDK.Token) {
|
|
||||||
if token == nil {
|
if token == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
objCtx, ok := token.Context().(*sessionSDK.ObjectContext)
|
// TODO(@cthulhu-rider): It'd be nice to not pull object identifiers from
|
||||||
|
// the token, but assert them. Track #1420
|
||||||
|
var tokV2 sessionV2.Token
|
||||||
|
token.WriteToV2(&tokV2)
|
||||||
|
|
||||||
|
ctx, ok := tokV2.GetBody().GetContext().(*sessionV2.ObjectSessionContext)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("wrong object session context %T, is it verified?", tokV2.GetBody().GetContext()))
|
||||||
|
}
|
||||||
|
|
||||||
|
idV2 := ctx.GetAddress().GetObjectID()
|
||||||
|
if idV2 == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, ok := objCtx.Address().ObjectID()
|
req.oid = new(oidSDK.ID)
|
||||||
if ok {
|
|
||||||
req.oid = &id
|
err := req.oid.ReadFromV2(*idV2)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("unexpected protocol violation error after correct session token decoding: %v", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tokenVerbToOperation(ctx *sessionSDK.ObjectContext) eaclSDK.Operation {
|
func ownerFromToken(token *sessionSDK.Object) (*user.ID, *keys.PublicKey, error) {
|
||||||
switch {
|
|
||||||
case ctx.IsForGet():
|
|
||||||
return eaclSDK.OperationGet
|
|
||||||
case ctx.IsForPut():
|
|
||||||
return eaclSDK.OperationPut
|
|
||||||
case ctx.IsForHead():
|
|
||||||
return eaclSDK.OperationHead
|
|
||||||
case ctx.IsForSearch():
|
|
||||||
return eaclSDK.OperationSearch
|
|
||||||
case ctx.IsForDelete():
|
|
||||||
return eaclSDK.OperationDelete
|
|
||||||
case ctx.IsForRange():
|
|
||||||
return eaclSDK.OperationRange
|
|
||||||
case ctx.IsForRangeHash():
|
|
||||||
return eaclSDK.OperationRangeHash
|
|
||||||
default:
|
|
||||||
return eaclSDK.OperationUnknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ownerFromToken(token *sessionSDK.Token) (*user.ID, *keys.PublicKey, error) {
|
|
||||||
// 1. First check signature of session token.
|
// 1. First check signature of session token.
|
||||||
if !token.VerifySignature() {
|
if !token.VerifySignature() {
|
||||||
return nil, nil, fmt.Errorf("%w: invalid session token signature", ErrMalformedRequest)
|
return nil, nil, fmt.Errorf("%w: invalid session token signature", ErrMalformedRequest)
|
||||||
|
@ -172,21 +161,32 @@ func ownerFromToken(token *sessionSDK.Token) (*user.ID, *keys.PublicKey, error)
|
||||||
|
|
||||||
// 2. Then check if session token owner issued the session token
|
// 2. Then check if session token owner issued the session token
|
||||||
// TODO(@cthulhu-rider): #1387 implement and use another approach to avoid conversion
|
// TODO(@cthulhu-rider): #1387 implement and use another approach to avoid conversion
|
||||||
tokV2 := token.ToV2()
|
var tokV2 sessionV2.Token
|
||||||
|
token.WriteToV2(&tokV2)
|
||||||
|
|
||||||
|
ownerSessionV2 := tokV2.GetBody().GetOwnerID()
|
||||||
|
if ownerSessionV2 == nil {
|
||||||
|
return nil, nil, errors.New("missing session owner")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ownerSession user.ID
|
||||||
|
|
||||||
|
err := ownerSession.ReadFromV2(*ownerSessionV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("invalid session token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
tokenIssuerKey, err := unmarshalPublicKey(tokV2.GetSignature().GetKey())
|
tokenIssuerKey, err := unmarshalPublicKey(tokV2.GetSignature().GetKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("invalid key in session token signature: %w", err)
|
return nil, nil, fmt.Errorf("invalid key in session token signature: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenOwner := token.OwnerID()
|
if !isOwnerFromKey(&ownerSession, tokenIssuerKey) {
|
||||||
|
|
||||||
if !isOwnerFromKey(tokenOwner, tokenIssuerKey) {
|
|
||||||
// TODO: #767 in this case we can issue all owner keys from neofs.id and check once again
|
// TODO: #767 in this case we can issue all owner keys from neofs.id and check once again
|
||||||
return nil, nil, fmt.Errorf("%w: invalid session token owner", ErrMalformedRequest)
|
return nil, nil, fmt.Errorf("%w: invalid session token owner", ErrMalformedRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokenOwner, tokenIssuerKey, nil
|
return &ownerSession, tokenIssuerKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func originalBodySignature(v *sessionV2.RequestVerificationHeader) *refsV2.Signature {
|
func originalBodySignature(v *sessionV2.RequestVerificationHeader) *refsV2.Signature {
|
||||||
|
@ -216,17 +216,30 @@ func isOwnerFromKey(id *user.ID, key *keys.PublicKey) bool {
|
||||||
return id2.Equals(*id)
|
return id2.Equals(*id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isVerbCompatible checks that tokenVerb operation can create auxiliary op operation.
|
// assertVerb checks that token verb corresponds to op.
|
||||||
func isVerbCompatible(tokenVerb, op eaclSDK.Operation) bool {
|
func assertVerb(tok sessionSDK.Object, op eaclSDK.Operation) bool {
|
||||||
switch tokenVerb {
|
//nolint:exhaustive
|
||||||
case eaclSDK.OperationGet:
|
switch op {
|
||||||
return op == eaclSDK.OperationGet || op == eaclSDK.OperationHead
|
case eaclSDK.OperationPut:
|
||||||
|
return tok.AssertVerb(sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete)
|
||||||
case eaclSDK.OperationDelete:
|
case eaclSDK.OperationDelete:
|
||||||
return op == eaclSDK.OperationPut || op == eaclSDK.OperationHead ||
|
return tok.AssertVerb(sessionSDK.VerbObjectDelete)
|
||||||
op == eaclSDK.OperationSearch
|
case eaclSDK.OperationGet:
|
||||||
case eaclSDK.OperationRange, eaclSDK.OperationRangeHash:
|
return tok.AssertVerb(sessionSDK.VerbObjectGet)
|
||||||
return op == eaclSDK.OperationRange || op == eaclSDK.OperationHead
|
case eaclSDK.OperationHead:
|
||||||
default:
|
return tok.AssertVerb(
|
||||||
return tokenVerb == op
|
sessionSDK.VerbObjectHead,
|
||||||
|
sessionSDK.VerbObjectGet,
|
||||||
|
sessionSDK.VerbObjectDelete,
|
||||||
|
sessionSDK.VerbObjectRange,
|
||||||
|
sessionSDK.VerbObjectRangeHash)
|
||||||
|
case eaclSDK.OperationSearch:
|
||||||
|
return tok.AssertVerb(sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete)
|
||||||
|
case eaclSDK.OperationRange:
|
||||||
|
return tok.AssertVerb(sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash)
|
||||||
|
case eaclSDK.OperationRangeHash:
|
||||||
|
return tok.AssertVerb(sessionSDK.VerbObjectRangeHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,23 +6,28 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
||||||
acltest "github.com/nspcc-dev/neofs-api-go/v2/acl/test"
|
acltest "github.com/nspcc-dev/neofs-api-go/v2/acl/test"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
sessiontest "github.com/nspcc-dev/neofs-api-go/v2/session/test"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOriginalTokens(t *testing.T) {
|
func TestOriginalTokens(t *testing.T) {
|
||||||
sToken := sessiontest.GenerateSessionToken(false)
|
sToken := sessiontest.ObjectSigned()
|
||||||
bTokenV2 := acltest.GenerateBearerToken(false)
|
bTokenV2 := acltest.GenerateBearerToken(false)
|
||||||
|
|
||||||
var bToken bearer.Token
|
var bToken bearer.Token
|
||||||
bToken.ReadFromV2(*bTokenV2)
|
bToken.ReadFromV2(*bTokenV2)
|
||||||
|
|
||||||
|
var sTokenV2 session.Token
|
||||||
|
sToken.WriteToV2(&sTokenV2)
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
metaHeaders := testGenerateMetaHeader(uint32(i), bTokenV2, sToken)
|
metaHeaders := testGenerateMetaHeader(uint32(i), bTokenV2, &sTokenV2)
|
||||||
require.Equal(t, sessionSDK.NewTokenFromV2(sToken), originalSessionToken(metaHeaders), i)
|
res, err := originalSessionToken(metaHeaders)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, sToken, res, i)
|
||||||
require.Equal(t, &bToken, originalBearerToken(metaHeaders), i)
|
require.Equal(t, &bToken, originalBearerToken(metaHeaders), i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,38 +48,48 @@ func testGenerateMetaHeader(depth uint32, b *acl.BearerToken, s *session.Token)
|
||||||
|
|
||||||
func TestIsVerbCompatible(t *testing.T) {
|
func TestIsVerbCompatible(t *testing.T) {
|
||||||
// Source: https://nspcc.ru/upload/neofs-spec-latest.pdf#page=28
|
// Source: https://nspcc.ru/upload/neofs-spec-latest.pdf#page=28
|
||||||
table := map[eacl.Operation][]eacl.Operation{
|
table := map[eacl.Operation][]sessionSDK.ObjectVerb{
|
||||||
eacl.OperationPut: {eacl.OperationPut},
|
eacl.OperationPut: {sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete},
|
||||||
eacl.OperationDelete: {eacl.OperationPut, eacl.OperationHead, eacl.OperationSearch},
|
eacl.OperationDelete: {sessionSDK.VerbObjectDelete},
|
||||||
eacl.OperationHead: {eacl.OperationHead},
|
eacl.OperationGet: {sessionSDK.VerbObjectGet},
|
||||||
eacl.OperationRange: {eacl.OperationRange, eacl.OperationHead},
|
eacl.OperationHead: {
|
||||||
eacl.OperationRangeHash: {eacl.OperationRange, eacl.OperationHead},
|
sessionSDK.VerbObjectHead,
|
||||||
eacl.OperationGet: {eacl.OperationGet, eacl.OperationHead},
|
sessionSDK.VerbObjectGet,
|
||||||
eacl.OperationSearch: {eacl.OperationSearch},
|
sessionSDK.VerbObjectDelete,
|
||||||
|
sessionSDK.VerbObjectRange,
|
||||||
|
sessionSDK.VerbObjectRangeHash,
|
||||||
|
},
|
||||||
|
eacl.OperationRange: {sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash},
|
||||||
|
eacl.OperationRangeHash: {sessionSDK.VerbObjectRangeHash},
|
||||||
|
eacl.OperationSearch: {sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete},
|
||||||
}
|
}
|
||||||
|
|
||||||
ops := []eacl.Operation{
|
verbs := []sessionSDK.ObjectVerb{
|
||||||
eacl.OperationPut,
|
sessionSDK.VerbObjectPut,
|
||||||
eacl.OperationDelete,
|
sessionSDK.VerbObjectDelete,
|
||||||
eacl.OperationHead,
|
sessionSDK.VerbObjectHead,
|
||||||
eacl.OperationRange,
|
sessionSDK.VerbObjectRange,
|
||||||
eacl.OperationRangeHash,
|
sessionSDK.VerbObjectRangeHash,
|
||||||
eacl.OperationGet,
|
sessionSDK.VerbObjectGet,
|
||||||
eacl.OperationSearch,
|
sessionSDK.VerbObjectSearch,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opToken := range ops {
|
var tok sessionSDK.Object
|
||||||
for _, op := range ops {
|
|
||||||
|
for op, list := range table {
|
||||||
|
for _, verb := range verbs {
|
||||||
var contains bool
|
var contains bool
|
||||||
for _, o := range table[opToken] {
|
for _, v := range list {
|
||||||
if o == op {
|
if v == verb {
|
||||||
contains = true
|
contains = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, contains, isVerbCompatible(opToken, op),
|
tok.ForVerb(verb)
|
||||||
"%s in token, %s executing", opToken, op)
|
|
||||||
|
require.Equal(t, contains, assertVerb(tok, op),
|
||||||
|
"%v in token, %s executing", verb, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,15 +243,15 @@ func (exec *execCtx) initTombstoneObject() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
tombOwnerID := exec.commonParameters().SessionToken().OwnerID()
|
tombOwnerID, ok := exec.commonParameters().SessionOwner()
|
||||||
if tombOwnerID == nil {
|
if !ok {
|
||||||
// make local node a tombstone object owner
|
// make local node a tombstone object owner
|
||||||
tombOwnerID = exec.svc.netInfo.LocalNodeID()
|
tombOwnerID = *exec.svc.netInfo.LocalNodeID()
|
||||||
}
|
}
|
||||||
|
|
||||||
exec.tombstoneObj = object.New()
|
exec.tombstoneObj = object.New()
|
||||||
exec.tombstoneObj.SetContainerID(*exec.containerID())
|
exec.tombstoneObj.SetContainerID(*exec.containerID())
|
||||||
exec.tombstoneObj.SetOwnerID(tombOwnerID)
|
exec.tombstoneObj.SetOwnerID(&tombOwnerID)
|
||||||
exec.tombstoneObj.SetType(object.TypeTombstone)
|
exec.tombstoneObj.SetType(object.TypeTombstone)
|
||||||
exec.tombstoneObj.SetPayload(payload)
|
exec.tombstoneObj.SetPayload(payload)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
@ -105,7 +106,18 @@ func (exec execCtx) isChild(obj *objectSDK.Object) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exec execCtx) key() (*ecdsa.PrivateKey, error) {
|
func (exec execCtx) key() (*ecdsa.PrivateKey, error) {
|
||||||
return exec.svc.keyStore.GetKey(exec.prm.common.SessionToken())
|
var sessionInfo *util.SessionInfo
|
||||||
|
|
||||||
|
if tok := exec.prm.common.SessionToken(); tok != nil {
|
||||||
|
ownerSession, _ := exec.prm.common.SessionOwner()
|
||||||
|
|
||||||
|
sessionInfo = &util.SessionInfo{
|
||||||
|
ID: tok.ID(),
|
||||||
|
Owner: ownerSession,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec.svc.keyStore.GetKey(sessionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exec *execCtx) canAssemble() bool {
|
func (exec *execCtx) canAssemble() bool {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package getsvc
|
package getsvc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
||||||
|
@ -11,7 +9,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,9 +45,7 @@ type cfg struct {
|
||||||
currentEpoch() (uint64, error)
|
currentEpoch() (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
keyStore interface {
|
keyStore *util.KeyStorage
|
||||||
GetKey(token *session.Token) (*ecdsa.PrivateKey, error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultCfg() *cfg {
|
func defaultCfg() *cfg {
|
||||||
|
|
|
@ -25,13 +25,13 @@ type commonPrm struct {
|
||||||
|
|
||||||
key *ecdsa.PrivateKey
|
key *ecdsa.PrivateKey
|
||||||
|
|
||||||
tokenSession *session.Token
|
tokenSession *session.Object
|
||||||
|
|
||||||
tokenBearer *bearer.Token
|
tokenBearer *bearer.Token
|
||||||
|
|
||||||
local bool
|
local bool
|
||||||
|
|
||||||
xHeaders []*session.XHeader
|
xHeaders []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetClient sets base client for NeoFS API communication.
|
// SetClient sets base client for NeoFS API communication.
|
||||||
|
@ -58,7 +58,7 @@ func (x *commonPrm) SetPrivateKey(key *ecdsa.PrivateKey) {
|
||||||
// SetSessionToken sets token of the session within which request should be sent.
|
// SetSessionToken sets token of the session within which request should be sent.
|
||||||
//
|
//
|
||||||
// By default the request will be sent outside the session.
|
// By default the request will be sent outside the session.
|
||||||
func (x *commonPrm) SetSessionToken(tok *session.Token) {
|
func (x *commonPrm) SetSessionToken(tok *session.Object) {
|
||||||
x.tokenSession = tok
|
x.tokenSession = tok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,23 +77,10 @@ func (x *commonPrm) SetTTL(ttl uint32) {
|
||||||
// SetXHeaders sets request X-Headers.
|
// SetXHeaders sets request X-Headers.
|
||||||
//
|
//
|
||||||
// By default X-Headers will not be attached to the request.
|
// By default X-Headers will not be attached to the request.
|
||||||
func (x *commonPrm) SetXHeaders(hs []*session.XHeader) {
|
func (x *commonPrm) SetXHeaders(hs []string) {
|
||||||
x.xHeaders = hs
|
x.xHeaders = hs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x commonPrm) xHeadersPrm() (res []string) {
|
|
||||||
if len(x.xHeaders) > 0 {
|
|
||||||
res = make([]string, len(x.xHeaders)*2)
|
|
||||||
|
|
||||||
for i := range x.xHeaders {
|
|
||||||
res[2*i] = x.xHeaders[i].Key()
|
|
||||||
res[2*i+1] = x.xHeaders[i].Value()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type readPrmCommon struct {
|
type readPrmCommon struct {
|
||||||
commonPrm
|
commonPrm
|
||||||
}
|
}
|
||||||
|
@ -163,7 +150,7 @@ func GetObject(prm GetObjectPrm) (*GetObjectRes, error) {
|
||||||
prm.cliPrm.MarkLocal()
|
prm.cliPrm.MarkLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
prm.cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
prm.cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
rdr, err := prm.cli.ObjectGetInit(prm.ctx, prm.cliPrm)
|
rdr, err := prm.cli.ObjectGetInit(prm.ctx, prm.cliPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -258,7 +245,7 @@ func HeadObject(prm HeadObjectPrm) (*HeadObjectRes, error) {
|
||||||
prm.cliPrm.WithBearerToken(*prm.tokenBearer)
|
prm.cliPrm.WithBearerToken(*prm.tokenBearer)
|
||||||
}
|
}
|
||||||
|
|
||||||
prm.cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
prm.cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
cliRes, err := prm.cli.ObjectHead(prm.ctx, prm.cliPrm)
|
cliRes, err := prm.cli.ObjectHead(prm.ctx, prm.cliPrm)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -350,7 +337,7 @@ func PayloadRange(prm PayloadRangePrm) (*PayloadRangeRes, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
prm.cliPrm.SetLength(prm.ln)
|
prm.cliPrm.SetLength(prm.ln)
|
||||||
prm.cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
prm.cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
rdr, err := prm.cli.ObjectRangeInit(prm.ctx, prm.cliPrm)
|
rdr, err := prm.cli.ObjectRangeInit(prm.ctx, prm.cliPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -420,7 +407,7 @@ func PutObject(prm PutObjectPrm) (*PutObjectRes, error) {
|
||||||
w.WithBearerToken(*prm.tokenBearer)
|
w.WithBearerToken(*prm.tokenBearer)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WithXHeaders(prm.xHeadersPrm()...)
|
w.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
if w.WriteHeader(*prm.obj) {
|
if w.WriteHeader(*prm.obj) {
|
||||||
w.WritePayloadChunk(prm.obj.Payload())
|
w.WritePayloadChunk(prm.obj.Payload())
|
||||||
|
@ -492,7 +479,7 @@ func SearchObjects(prm SearchObjectsPrm) (*SearchObjectsRes, error) {
|
||||||
prm.cliPrm.WithBearerToken(*prm.tokenBearer)
|
prm.cliPrm.WithBearerToken(*prm.tokenBearer)
|
||||||
}
|
}
|
||||||
|
|
||||||
prm.cliPrm.WithXHeaders(prm.xHeadersPrm()...)
|
prm.cliPrm.WithXHeaders(prm.xHeaders...)
|
||||||
|
|
||||||
rdr, err := prm.cli.ObjectSearchInit(prm.ctx, prm.cliPrm)
|
rdr, err := prm.cli.ObjectSearchInit(prm.ctx, prm.cliPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -48,7 +48,18 @@ func (t *remoteTarget) WriteHeader(obj *object.Object) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *remoteTarget) Close() (*transformer.AccessIdentifiers, error) {
|
func (t *remoteTarget) Close() (*transformer.AccessIdentifiers, error) {
|
||||||
key, err := t.keyStorage.GetKey(t.commonPrm.SessionToken())
|
var sessionInfo *util.SessionInfo
|
||||||
|
|
||||||
|
if tok := t.commonPrm.SessionToken(); tok != nil {
|
||||||
|
ownerSession, _ := t.commonPrm.SessionOwner()
|
||||||
|
|
||||||
|
sessionInfo = &util.SessionInfo{
|
||||||
|
ID: tok.ID(),
|
||||||
|
Owner: ownerSession,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := t.keyStorage.GetKey(sessionInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("(%T) could not receive private key: %w", t, err)
|
return nil, fmt.Errorf("(%T) could not receive private key: %w", t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,18 @@ func (p *Streamer) initTarget(prm *PutInitPrm) error {
|
||||||
// prepare trusted-Put object target
|
// prepare trusted-Put object target
|
||||||
|
|
||||||
// get private token from local storage
|
// get private token from local storage
|
||||||
sessionKey, err := p.keyStorage.GetKey(sToken)
|
var sessionInfo *util.SessionInfo
|
||||||
|
|
||||||
|
if sToken != nil {
|
||||||
|
ownerSession, _ := prm.common.SessionOwner()
|
||||||
|
|
||||||
|
sessionInfo = &util.SessionInfo{
|
||||||
|
ID: sToken.ID(),
|
||||||
|
Owner: ownerSession,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionKey, err := p.keyStorage.GetKey(sessionInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("(%T) could not receive session key: %w", p, err)
|
return fmt.Errorf("(%T) could not receive session key: %w", p, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package searchsvc
|
package searchsvc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
||||||
|
@ -11,7 +9,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
oidSDK "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oidSDK "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,9 +48,7 @@ type cfg struct {
|
||||||
currentEpoch() (uint64, error)
|
currentEpoch() (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
keyStore interface {
|
keyStore *util.KeyStorage
|
||||||
GetKey(token *session.Token) (*ecdsa.PrivateKey, error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultCfg() *cfg {
|
func defaultCfg() *cfg {
|
||||||
|
|
|
@ -85,7 +85,18 @@ func (c *clientWrapper) searchObjects(exec *execCtx, info client.NodeInfo) ([]oi
|
||||||
return exec.prm.forwarder(info, c.client)
|
return exec.prm.forwarder(info, c.client)
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := exec.svc.keyStore.GetKey(exec.prm.common.SessionToken())
|
var sessionInfo *util.SessionInfo
|
||||||
|
|
||||||
|
if tok := exec.prm.common.SessionToken(); tok != nil {
|
||||||
|
ownerSession, _ := exec.prm.common.SessionOwner()
|
||||||
|
|
||||||
|
sessionInfo = &util.SessionInfo{
|
||||||
|
ID: tok.ID(),
|
||||||
|
Owner: ownerSession,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := exec.svc.keyStore.GetKey(sessionInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,12 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/session/storage"
|
"github.com/nspcc-dev/neofs-node/pkg/services/session/storage"
|
||||||
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,13 +41,28 @@ func NewKeyStorage(localKey *ecdsa.PrivateKey, tokenStore SessionSource, net net
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SessionInfo groups information about NeoFS Object session
|
||||||
|
// which is reflected in KeyStorage.
|
||||||
|
type SessionInfo struct {
|
||||||
|
// Session unique identifier.
|
||||||
|
ID uuid.UUID
|
||||||
|
|
||||||
|
// Session issuer.
|
||||||
|
Owner user.ID
|
||||||
|
}
|
||||||
|
|
||||||
// GetKey returns private key of the node.
|
// GetKey returns private key of the node.
|
||||||
//
|
//
|
||||||
// If token is not nil, session private key is returned.
|
// If token is not nil, session private key is returned.
|
||||||
// Otherwise, node private key is returned.
|
// Otherwise, node private key is returned.
|
||||||
func (s *KeyStorage) GetKey(token *session.Token) (*ecdsa.PrivateKey, error) {
|
func (s *KeyStorage) GetKey(info *SessionInfo) (*ecdsa.PrivateKey, error) {
|
||||||
if token != nil {
|
if info != nil {
|
||||||
pToken := s.tokenStore.Get(token.OwnerID(), token.ID())
|
binID, err := info.ID.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("marshal ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pToken := s.tokenStore.Get(&info.Owner, binID)
|
||||||
if pToken != nil {
|
if pToken != nil {
|
||||||
if pToken.ExpiredAt() <= s.networkState.CurrentEpoch() {
|
if pToken.ExpiredAt() <= s.networkState.CurrentEpoch() {
|
||||||
var errExpired apistatus.SessionTokenExpired
|
var errExpired apistatus.SessionTokenExpired
|
||||||
|
|
|
@ -11,7 +11,9 @@ import (
|
||||||
sessionV2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
sessionV2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
||||||
tokenStorage "github.com/nspcc-dev/neofs-node/pkg/services/session/storage/temporary"
|
tokenStorage "github.com/nspcc-dev/neofs-node/pkg/services/session/storage/temporary"
|
||||||
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
usertest "github.com/nspcc-dev/neofs-sdk-go/user/test"
|
usertest "github.com/nspcc-dev/neofs-sdk-go/user/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -23,6 +25,8 @@ func TestNewKeyStorage(t *testing.T) {
|
||||||
tokenStor := tokenStorage.NewTokenStore()
|
tokenStor := tokenStorage.NewTokenStore()
|
||||||
stor := util.NewKeyStorage(&nodeKey.PrivateKey, tokenStor, mockedNetworkState{42})
|
stor := util.NewKeyStorage(&nodeKey.PrivateKey, tokenStor, mockedNetworkState{42})
|
||||||
|
|
||||||
|
owner := *usertest.ID()
|
||||||
|
|
||||||
t.Run("node key", func(t *testing.T) {
|
t.Run("node key", func(t *testing.T) {
|
||||||
key, err := stor.GetKey(nil)
|
key, err := stor.GetKey(nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -30,48 +34,35 @@ func TestNewKeyStorage(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("unknown token", func(t *testing.T) {
|
t.Run("unknown token", func(t *testing.T) {
|
||||||
tok := generateToken(t)
|
_, err = stor.GetKey(&util.SessionInfo{
|
||||||
_, err = stor.GetKey(tok)
|
ID: uuid.New(),
|
||||||
|
Owner: *usertest.ID(),
|
||||||
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("known token", func(t *testing.T) {
|
t.Run("known token", func(t *testing.T) {
|
||||||
tok := createToken(t, tokenStor, 100)
|
tok := createToken(t, tokenStor, owner, 100)
|
||||||
pubKey, err := keys.NewPublicKeyFromBytes(tok.SessionKey(), elliptic.P256())
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
key, err := stor.GetKey(tok)
|
key, err := stor.GetKey(&util.SessionInfo{
|
||||||
|
ID: tok.ID(),
|
||||||
|
Owner: owner,
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, pubKey.X, key.PublicKey.X)
|
require.True(t, tok.AssertAuthKey((*neofsecdsa.PublicKey)(&key.PublicKey)))
|
||||||
require.Equal(t, pubKey.Y, key.PublicKey.Y)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("expired token", func(t *testing.T) {
|
t.Run("expired token", func(t *testing.T) {
|
||||||
tok := createToken(t, tokenStor, 30)
|
tok := createToken(t, tokenStor, owner, 30)
|
||||||
_, err := stor.GetKey(tok)
|
_, err := stor.GetKey(&util.SessionInfo{
|
||||||
|
ID: tok.ID(),
|
||||||
|
Owner: owner,
|
||||||
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateToken(t *testing.T) *session.Token {
|
func createToken(t *testing.T, store *tokenStorage.TokenStore, owner user.ID, exp uint64) session.Object {
|
||||||
key, err := keys.NewPrivateKey()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
pubKey := key.PublicKey().Bytes()
|
|
||||||
id, err := uuid.New().MarshalBinary()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tok := session.NewToken()
|
|
||||||
tok.SetSessionKey(pubKey)
|
|
||||||
tok.SetID(id)
|
|
||||||
tok.SetOwnerID(usertest.ID())
|
|
||||||
|
|
||||||
return tok
|
|
||||||
}
|
|
||||||
|
|
||||||
func createToken(t *testing.T, store *tokenStorage.TokenStore, exp uint64) *session.Token {
|
|
||||||
owner := usertest.ID()
|
|
||||||
|
|
||||||
var ownerV2 refs.OwnerID
|
var ownerV2 refs.OwnerID
|
||||||
owner.WriteToV2(&ownerV2)
|
owner.WriteToV2(&ownerV2)
|
||||||
|
|
||||||
|
@ -82,10 +73,15 @@ func createToken(t *testing.T, store *tokenStorage.TokenStore, exp uint64) *sess
|
||||||
resp, err := store.Create(context.Background(), req)
|
resp, err := store.Create(context.Background(), req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tok := session.NewToken()
|
pub, err := keys.NewPublicKeyFromBytes(resp.GetSessionKey(), elliptic.P256())
|
||||||
tok.SetSessionKey(resp.GetSessionKey())
|
require.NoError(t, err)
|
||||||
tok.SetID(resp.GetID())
|
|
||||||
tok.SetOwnerID(owner)
|
var id uuid.UUID
|
||||||
|
require.NoError(t, id.UnmarshalBinary(resp.GetID()))
|
||||||
|
|
||||||
|
var tok session.Object
|
||||||
|
tok.SetAuthKey((*neofsecdsa.PublicKey)(pub))
|
||||||
|
tok.SetID(id)
|
||||||
|
|
||||||
return tok
|
return tok
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
sessionsdk "github.com/nspcc-dev/neofs-sdk-go/session"
|
sessionsdk "github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// maxLocalTTL is maximum TTL for an operation to be considered local.
|
// maxLocalTTL is maximum TTL for an operation to be considered local.
|
||||||
|
@ -16,13 +19,15 @@ type CommonPrm struct {
|
||||||
|
|
||||||
netmapEpoch, netmapLookupDepth uint64
|
netmapEpoch, netmapLookupDepth uint64
|
||||||
|
|
||||||
token *sessionsdk.Token
|
token *sessionsdk.Object
|
||||||
|
|
||||||
bearer *bearer.Token
|
bearer *bearer.Token
|
||||||
|
|
||||||
ttl uint32
|
ttl uint32
|
||||||
|
|
||||||
xhdrs []*sessionsdk.XHeader
|
xhdrs []string
|
||||||
|
|
||||||
|
ownerSession user.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// TTL returns TTL for new requests.
|
// TTL returns TTL for new requests.
|
||||||
|
@ -35,7 +40,7 @@ func (p *CommonPrm) TTL() uint32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// XHeaders returns X-Headers for new requests.
|
// XHeaders returns X-Headers for new requests.
|
||||||
func (p *CommonPrm) XHeaders() []*sessionsdk.XHeader {
|
func (p *CommonPrm) XHeaders() []string {
|
||||||
if p != nil {
|
if p != nil {
|
||||||
return p.xhdrs
|
return p.xhdrs
|
||||||
}
|
}
|
||||||
|
@ -59,7 +64,7 @@ func (p *CommonPrm) LocalOnly() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CommonPrm) SessionToken() *sessionsdk.Token {
|
func (p *CommonPrm) SessionToken() *sessionsdk.Object {
|
||||||
if p != nil {
|
if p != nil {
|
||||||
return p.token
|
return p.token
|
||||||
}
|
}
|
||||||
|
@ -67,6 +72,14 @@ func (p *CommonPrm) SessionToken() *sessionsdk.Token {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CommonPrm) SessionOwner() (user.ID, bool) {
|
||||||
|
if p != nil && p.token != nil {
|
||||||
|
return p.ownerSession, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.ID{}, false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *CommonPrm) BearerToken() *bearer.Token {
|
func (p *CommonPrm) BearerToken() *bearer.Token {
|
||||||
if p != nil {
|
if p != nil {
|
||||||
return p.bearer
|
return p.bearer
|
||||||
|
@ -102,17 +115,38 @@ func CommonPrmFromV2(req interface {
|
||||||
}) (*CommonPrm, error) {
|
}) (*CommonPrm, error) {
|
||||||
meta := req.GetMetaHeader()
|
meta := req.GetMetaHeader()
|
||||||
|
|
||||||
|
var tokenSession *sessionsdk.Object
|
||||||
|
var err error
|
||||||
|
var ownerSession user.ID
|
||||||
|
|
||||||
|
if tokenSessionV2 := meta.GetSessionToken(); tokenSessionV2 != nil {
|
||||||
|
ownerSessionV2 := tokenSessionV2.GetBody().GetOwnerID()
|
||||||
|
if ownerSessionV2 == nil {
|
||||||
|
return nil, errors.New("missing session owner")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ownerSession.ReadFromV2(*ownerSessionV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid session token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenSession = new(sessionsdk.Object)
|
||||||
|
|
||||||
|
err = tokenSession.ReadFromV2(*tokenSessionV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid session token: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
xHdrs := meta.GetXHeaders()
|
xHdrs := meta.GetXHeaders()
|
||||||
ttl := meta.GetTTL()
|
ttl := meta.GetTTL()
|
||||||
|
|
||||||
prm := &CommonPrm{
|
prm := &CommonPrm{
|
||||||
local: ttl <= maxLocalTTL,
|
local: ttl <= maxLocalTTL,
|
||||||
xhdrs: make([]*sessionsdk.XHeader, 0, len(xHdrs)),
|
token: tokenSession,
|
||||||
ttl: ttl - 1, // decrease TTL for new requests
|
ttl: ttl - 1, // decrease TTL for new requests
|
||||||
}
|
xhdrs: make([]string, 0, 2*len(xHdrs)),
|
||||||
|
ownerSession: ownerSession,
|
||||||
if tok := meta.GetSessionToken(); tok != nil {
|
|
||||||
prm.token = sessionsdk.NewTokenFromV2(tok)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tok := meta.GetBearerToken(); tok != nil {
|
if tok := meta.GetBearerToken(); tok != nil {
|
||||||
|
@ -121,7 +155,7 @@ func CommonPrmFromV2(req interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range xHdrs {
|
for i := range xHdrs {
|
||||||
switch xHdrs[i].GetKey() {
|
switch key := xHdrs[i].GetKey(); key {
|
||||||
case session.XHeaderNetmapEpoch:
|
case session.XHeaderNetmapEpoch:
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -137,9 +171,7 @@ func CommonPrmFromV2(req interface {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
xhdr := sessionsdk.NewXHeaderFromV2(&xHdrs[i])
|
prm.xhdrs = append(prm.xhdrs, key, xHdrs[i].GetValue())
|
||||||
|
|
||||||
prm.xhdrs = append(prm.xhdrs, xhdr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ type FormatterParams struct {
|
||||||
|
|
||||||
NextTarget ObjectTarget
|
NextTarget ObjectTarget
|
||||||
|
|
||||||
SessionToken *session.Token
|
SessionToken *session.Object
|
||||||
|
|
||||||
NetworkState netmap.State
|
NetworkState netmap.State
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue