From 6a4e5e6f0a83607d72e485a052c52d11eba47415 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Wed, 21 Dec 2022 19:32:08 +0300 Subject: [PATCH] [#2144] node: Try node's private key if dynamic token fetching failed `GETRANGEHASH` request spawns `GETRANGE` requests if an object could not be found locally. If the original request contains session, it can be static and, therefore, fetching session key can not be performed successfully. As the best effort a node could request object's range with its own key. Signed-off-by: Pavel Karpy --- CHANGELOG.md | 1 + pkg/services/object/get/exec.go | 6 ++++++ pkg/services/object/get/prm.go | 11 +++++++++++ pkg/services/object/get/v2/util.go | 17 +++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8737dd44..b7c97ea3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Changelog for NeoFS Node - Use `sync.Pool` in Object.PUT service (#2139) - Shard uses metabase for `HEAD` requests by default, not write-cache (#2167) - Clarify help for `--expire-at` parameter for commands `object lock/put` and `bearer create` (#2097) +- Node spawns `GETRANGE` requests signed with the node's key if session key was not found for `RANGEHASH` (#2144) ### Fixed - Open FSTree in sync mode by default (#1992) diff --git a/pkg/services/object/get/exec.go b/pkg/services/object/get/exec.go index f1d1098bf..89b3f8aac 100644 --- a/pkg/services/object/get/exec.go +++ b/pkg/services/object/get/exec.go @@ -109,6 +109,12 @@ func (exec execCtx) isChild(obj *objectSDK.Object) bool { } func (exec execCtx) key() (*ecdsa.PrivateKey, error) { + if exec.prm.signerKey != nil { + // the key has already been requested and + // cached in the previous operations + return exec.prm.signerKey, nil + } + var sessionInfo *util.SessionInfo if tok := exec.prm.common.SessionToken(); tok != nil { diff --git a/pkg/services/object/get/prm.go b/pkg/services/object/get/prm.go index 6f737c71d..1050a8958 100644 --- a/pkg/services/object/get/prm.go +++ b/pkg/services/object/get/prm.go @@ -1,6 +1,7 @@ package getsvc import ( + "crypto/ecdsa" "errors" "hash" @@ -74,6 +75,11 @@ type commonPrm struct { raw bool forwarder RequestForwarder + + // signerKey is a cached key that should be used for spawned + // requests (if any), could be nil if incoming request handling + // routine does not include any key fetching operations + signerKey *ecdsa.PrivateKey } // ChunkWriter is an interface of target component @@ -145,6 +151,11 @@ func (p *commonPrm) WithRawFlag(raw bool) { p.raw = raw } +// WithCachedSignerKey sets optional key for all further requests. +func (p *commonPrm) WithCachedSignerKey(signerKey *ecdsa.PrivateKey) { + p.signerKey = signerKey +} + // SetHeaderWriter sets target component to write the object header. func (p *HeadPrm) SetHeaderWriter(w HeaderWriter) { p.objWriter = &partWriter{ diff --git a/pkg/services/object/get/v2/util.go b/pkg/services/object/get/v2/util.go index b2513cfe8..f887b3da9 100644 --- a/pkg/services/object/get/v2/util.go +++ b/pkg/services/object/get/v2/util.go @@ -362,6 +362,23 @@ func (s *Service) toHashRangePrm(req *objectV2.GetRangeHashRequest) (*getsvc.Ran p.WithAddress(addr) + if tok := commonPrm.SessionToken(); tok != nil { + signerKey, err := s.keyStorage.GetKey(&util.SessionInfo{ + ID: tok.ID(), + Owner: tok.Issuer(), + }) + if err != nil && errors.As(err, new(apistatus.SessionTokenNotFound)) { + commonPrm.ForgetTokens() + signerKey, err = s.keyStorage.GetKey(nil) + } + + if err != nil { + return nil, fmt.Errorf("fetching session key: %w", err) + } + + p.WithCachedSignerKey(signerKey) + } + rngsV2 := body.GetRanges() rngs := make([]object.Range, len(rngsV2))