[#589] ir/container: Verify session token lifetime

Session tokens have limited lifetime in NeoFS. Container processor should
verify lifetime of the incoming tokens.

Define `NetworkState` interface with `Epoch` method to get number of the
current epoch. Use Netmap contract client's wrapper as `NetworkState` of
Container `Processor`. Check values of token lifetime, and deny if:

  * NBF value is gt the current epoch;
  * IAT is gt the current epoch;
  * EXP is le the current epoch.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-06-04 18:02:25 +03:00 committed by Alex Vanin
parent 0bfa2dc88f
commit 2f38fef31a
5 changed files with 51 additions and 3 deletions

2
go.mod
View file

@ -13,7 +13,7 @@ require (
github.com/multiformats/go-multiaddr v0.3.1 github.com/multiformats/go-multiaddr v0.3.1
github.com/nspcc-dev/hrw v1.0.9 github.com/nspcc-dev/hrw v1.0.9
github.com/nspcc-dev/neo-go v0.95.1 github.com/nspcc-dev/neo-go v0.95.1
github.com/nspcc-dev/neofs-api-go v1.27.0 github.com/nspcc-dev/neofs-api-go v1.27.1-0.20210607102659-cc1163fd5797
github.com/nspcc-dev/neofs-crypto v0.3.0 github.com/nspcc-dev/neofs-crypto v0.3.0
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20210520210714-9dee13f0d556 github.com/nspcc-dev/neofs-sdk-go v0.0.0-20210520210714-9dee13f0d556
github.com/nspcc-dev/tzhash v1.4.0 github.com/nspcc-dev/tzhash v1.4.0

6
go.sum
View file

@ -211,6 +211,7 @@ github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@ -286,8 +287,8 @@ github.com/nspcc-dev/neo-go v0.95.1 h1:5fgLFOul1Ax/maFkgLkD5rDUwY/nB/xX/Jpcd8hLH
github.com/nspcc-dev/neo-go v0.95.1/go.mod h1:bW07ge1WFXsBgqrcPpLUr6OcyQxHqM26MZNesWMdH0c= github.com/nspcc-dev/neo-go v0.95.1/go.mod h1:bW07ge1WFXsBgqrcPpLUr6OcyQxHqM26MZNesWMdH0c=
github.com/nspcc-dev/neofs-api-go v1.24.0/go.mod h1:G7dqincfdjBrAbL5nxVp82emF05fSVEqe59ICsoRDI8= github.com/nspcc-dev/neofs-api-go v1.24.0/go.mod h1:G7dqincfdjBrAbL5nxVp82emF05fSVEqe59ICsoRDI8=
github.com/nspcc-dev/neofs-api-go v1.26.1/go.mod h1:SHuH1Ba3U/h3j+8HHbb3Cns1LfMlEb88guWog9Qi68Y= github.com/nspcc-dev/neofs-api-go v1.26.1/go.mod h1:SHuH1Ba3U/h3j+8HHbb3Cns1LfMlEb88guWog9Qi68Y=
github.com/nspcc-dev/neofs-api-go v1.27.0 h1:SiqD1wb50l/ahCNV8/D9R3ua/sFS8oRCJ5jV+ux6AzE= github.com/nspcc-dev/neofs-api-go v1.27.1-0.20210607102659-cc1163fd5797 h1:pUFVPj21BaKdeSyuqBXJUFTPgx7H0cO167+2SJ472jU=
github.com/nspcc-dev/neofs-api-go v1.27.0/go.mod h1:i0Cwgvcu9A4M4e58pydbXFisUhSxpfljmuWFPIp2btE= github.com/nspcc-dev/neofs-api-go v1.27.1-0.20210607102659-cc1163fd5797/go.mod h1:i0Cwgvcu9A4M4e58pydbXFisUhSxpfljmuWFPIp2btE=
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM= github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM=
@ -318,6 +319,7 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View file

@ -561,6 +561,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
FeeProvider: server.feeConfig, FeeProvider: server.feeConfig,
ContainerClient: cnrClient, ContainerClient: cnrClient,
NeoFSIDClient: neofsIDClient, NeoFSIDClient: neofsIDClient,
NetworkState: nmClient,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -106,6 +106,12 @@ func (cp *Processor) checkSessionToken(token *session.Token) error {
return errors.New("invalid signature") return errors.New("invalid signature")
} }
// check lifetime
err := cp.checkTokenLifetime(token)
if err != nil {
return err
}
// check token owner's key ownership // check token owner's key ownership
key, err := keys.NewPublicKeyFromBytes(token.Signature().Key(), elliptic.P256()) key, err := keys.NewPublicKeyFromBytes(token.Signature().Key(), elliptic.P256())
@ -149,3 +155,27 @@ func checkTokenContextWithCID(tok *session.Token, id *cid.ID, verbAssert verbAss
return nil return nil
} }
func (cp *Processor) checkTokenLifetime(token *session.Token) error {
curEpoch, err := cp.netState.Epoch()
if err != nil {
return fmt.Errorf("could not read current epoch: %w", err)
}
nbf := token.Nbf()
if curEpoch < nbf {
return fmt.Errorf("token is not valid yet: nbf %d, cur %d", nbf, curEpoch)
}
iat := token.Iat()
if curEpoch < iat {
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
}

View file

@ -31,6 +31,7 @@ type (
feeProvider *config.FeeConfig feeProvider *config.FeeConfig
cnrClient *wrapper.Wrapper // notary must be enabled cnrClient *wrapper.Wrapper // notary must be enabled
idClient *neofsid.ClientWrapper idClient *neofsid.ClientWrapper
netState NetworkState
} }
// Params of the processor constructor. // Params of the processor constructor.
@ -43,9 +44,20 @@ type (
FeeProvider *config.FeeConfig FeeProvider *config.FeeConfig
ContainerClient *wrapper.Wrapper ContainerClient *wrapper.Wrapper
NeoFSIDClient *neofsid.ClientWrapper NeoFSIDClient *neofsid.ClientWrapper
NetworkState NetworkState
} }
) )
// NetworkState is an interface of a component
// that provides access to network state.
type NetworkState interface {
// Epoch must return number of the current epoch.
//
// Must return any error encountered
// which did not allow reading the value.
Epoch() (uint64, error)
}
const ( const (
putNotification = "containerPut" putNotification = "containerPut"
deleteNotification = "containerDelete" deleteNotification = "containerDelete"
@ -68,6 +80,8 @@ func New(p *Params) (*Processor, error) {
return nil, errors.New("ir/container: Container client is not set") return nil, errors.New("ir/container: Container client is not set")
case p.NeoFSIDClient == nil: case p.NeoFSIDClient == nil:
return nil, errors.New("ir/container: NeoFS ID client is not set") return nil, errors.New("ir/container: NeoFS ID client is not set")
case p.NetworkState == nil:
return nil, errors.New("ir/container: network state is not set")
} }
p.Log.Debug("container worker pool", zap.Int("size", p.PoolSize)) p.Log.Debug("container worker pool", zap.Int("size", p.PoolSize))
@ -86,6 +100,7 @@ func New(p *Params) (*Processor, error) {
feeProvider: p.FeeProvider, feeProvider: p.FeeProvider,
cnrClient: p.ContainerClient, cnrClient: p.ContainerClient,
idClient: p.NeoFSIDClient, idClient: p.NeoFSIDClient,
netState: p.NetworkState,
}, nil }, nil
} }