[#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 <p.karpy@yadro.com>
This commit is contained in:
Pavel Karpy 2022-12-21 19:32:08 +03:00 committed by Anton Nikiforov
parent 86a4fba571
commit 6a4e5e6f0a
4 changed files with 35 additions and 0 deletions

View file

@ -29,6 +29,7 @@ Changelog for NeoFS Node
- Use `sync.Pool` in Object.PUT service (#2139) - Use `sync.Pool` in Object.PUT service (#2139)
- Shard uses metabase for `HEAD` requests by default, not write-cache (#2167) - 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) - 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 ### Fixed
- Open FSTree in sync mode by default (#1992) - Open FSTree in sync mode by default (#1992)

View file

@ -109,6 +109,12 @@ func (exec execCtx) isChild(obj *objectSDK.Object) bool {
} }
func (exec execCtx) key() (*ecdsa.PrivateKey, error) { 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 var sessionInfo *util.SessionInfo
if tok := exec.prm.common.SessionToken(); tok != nil { if tok := exec.prm.common.SessionToken(); tok != nil {

View file

@ -1,6 +1,7 @@
package getsvc package getsvc
import ( import (
"crypto/ecdsa"
"errors" "errors"
"hash" "hash"
@ -74,6 +75,11 @@ type commonPrm struct {
raw bool raw bool
forwarder RequestForwarder 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 // ChunkWriter is an interface of target component
@ -145,6 +151,11 @@ func (p *commonPrm) WithRawFlag(raw bool) {
p.raw = raw 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. // SetHeaderWriter sets target component to write the object header.
func (p *HeadPrm) SetHeaderWriter(w HeaderWriter) { func (p *HeadPrm) SetHeaderWriter(w HeaderWriter) {
p.objWriter = &partWriter{ p.objWriter = &partWriter{

View file

@ -362,6 +362,23 @@ func (s *Service) toHashRangePrm(req *objectV2.GetRangeHashRequest) (*getsvc.Ran
p.WithAddress(addr) 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() rngsV2 := body.GetRanges()
rngs := make([]object.Range, len(rngsV2)) rngs := make([]object.Range, len(rngsV2))