[#329] Use suitable tokens for container requests

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-01-26 12:09:28 +03:00 committed by Alex Vanin
parent cce79b612a
commit c383f332d5
6 changed files with 73 additions and 28 deletions

View file

@ -549,7 +549,7 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
boxData, err := layer.GetBoxData(r.Context())
if err == nil {
policies = boxData.Policies
p.SessionToken = boxData.Gate.SessionToken
p.SessionToken = boxData.Gate.SessionTokenForPut()
}
if createParams.LocationConstraint != "" {

View file

@ -16,6 +16,7 @@ import (
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/pool"
"github.com/nspcc-dev/neofs-sdk-go/session"
"go.uber.org/zap"
)
@ -170,7 +171,14 @@ func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*ci
func (n *layer) setContainerEACLTable(ctx context.Context, cid *cid.ID, table *eacl.Table) error {
table.SetCID(cid)
if err := n.pool.SetEACL(ctx, table, n.SessionOpt(ctx)); err != nil {
var sessionToken *session.Token
boxData, err := GetBoxData(ctx)
if err == nil {
sessionToken = boxData.Gate.SessionTokenForSetEACL()
}
if err := n.pool.SetEACL(ctx, table, pool.WithSession(sessionToken)); err != nil {
return err
}
@ -225,5 +233,10 @@ func (n *layer) waitEACLPresence(ctx context.Context, cid *cid.ID, table *eacl.T
}
func (n *layer) deleteContainer(ctx context.Context, cid *cid.ID) error {
return n.pool.DeleteContainer(ctx, cid, n.SessionOpt(ctx))
var sessionToken *session.Token
boxData, err := GetBoxData(ctx)
if err == nil {
sessionToken = boxData.Gate.SessionTokenForDelete()
}
return n.pool.DeleteContainer(ctx, cid, pool.WithSession(sessionToken))
}

View file

@ -299,15 +299,6 @@ func (n *layer) CallOptions(ctx context.Context) []pool.CallOption {
return []pool.CallOption{pool.WithKey(&n.anonKey.Key.PrivateKey)}
}
// SessionOpt returns client.WithSession call option with token from context or with nil token.
func (n *layer) SessionOpt(ctx context.Context) pool.CallOption {
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
return pool.WithSession(data.Gate.SessionToken)
}
return pool.WithSession(nil)
}
// Get NeoFS Object by refs.Address (should be used by auth.Center).
func (n *layer) Get(ctx context.Context, address *object.Address) (*object.Object, error) {
ops := new(client.GetObjectParams).WithAddress(address)

View file

@ -484,8 +484,8 @@ func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions, cid *ci
if err != nil {
return nil, err
}
for i, sessionToken := range sessionTokens {
gates[i].SessionToken = sessionToken[0]
for i, sessionTkns := range sessionTokens {
gates[i].SessionTokens = sessionTkns
}
}

View file

@ -11,6 +11,7 @@ import (
"io"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
apisession "github.com/nspcc-dev/neofs-api-go/v2/session"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/token"
@ -33,10 +34,10 @@ type ContainerPolicy struct {
// GateData represents gate tokens in AccessBox.
type GateData struct {
AccessKey string
BearerToken *token.BearerToken
SessionToken *session.Token
GateKey *keys.PublicKey
AccessKey string
BearerToken *token.BearerToken
SessionTokens []*session.Token
GateKey *keys.PublicKey
}
// NewGateData returns GateData from provided bearer token and public gate key.
@ -44,6 +45,39 @@ func NewGateData(gateKey *keys.PublicKey, bearerTkn *token.BearerToken) *GateDat
return &GateData{GateKey: gateKey, BearerToken: bearerTkn}
}
// SessionTokenForPut return the first suitable container session context for PUT operation.
func (g *GateData) SessionTokenForPut() *session.Token {
return g.containerSessionToken(apisession.ContainerVerbPut)
}
// SessionTokenForDelete return the first suitable container session context for DELETE operation.
func (g *GateData) SessionTokenForDelete() *session.Token {
return g.containerSessionToken(apisession.ContainerVerbDelete)
}
// SessionTokenForSetEACL return the first suitable container session context for SetEACL operation.
func (g *GateData) SessionTokenForSetEACL() *session.Token {
return g.containerSessionToken(apisession.ContainerVerbSetEACL)
}
func (g *GateData) containerSessionToken(verb apisession.ContainerSessionVerb) *session.Token {
for _, sessionToken := range g.SessionTokens {
switch ctx := sessionToken.Context().(type) {
case *session.ContainerContext:
if isAppropriateContainerContext(ctx, verb) {
return sessionToken
}
}
}
return nil
}
func isAppropriateContainerContext(ctx *session.ContainerContext, verb apisession.ContainerSessionVerb) bool {
return verb == apisession.ContainerVerbPut && ctx.IsForPut() ||
verb == apisession.ContainerVerbDelete && ctx.IsForDelete() ||
verb == apisession.ContainerVerbSetEACL && ctx.IsForSetEACL()
}
// Secrets represents AccessKey and key to encrypt gate tokens.
type Secrets struct {
AccessKey string
@ -146,18 +180,20 @@ func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *keys.PrivateK
if err != nil {
return fmt.Errorf("%w, sender = %d", err, i)
}
var encSession []byte
if gate.SessionToken != nil {
encSession, err = gate.SessionToken.Marshal()
encSessions := make([][]byte, len(gate.SessionTokens))
for i, sessionToken := range gate.SessionTokens {
encSession, err := sessionToken.Marshal()
if err != nil {
return fmt.Errorf("%w, sender = %d", err, i)
}
encSessions[i] = encSession
}
tokens := new(Tokens)
tokens.AccessKey = secret
tokens.BearerToken = encBearer
tokens.SessionToken = encSession
tokens.SessionTokens = encSessions
boxGate, err := encodeGate(ephemeralKey, gate.GateKey, tokens)
if err != nil {
@ -199,13 +235,18 @@ func decodeGate(gate *AccessBox_Gate, owner *keys.PrivateKey, sender *keys.Publi
if err := bearerTkn.Unmarshal(tokens.BearerToken); err != nil {
return nil, err
}
sessionTkn := session.NewToken()
if err := sessionTkn.Unmarshal(tokens.SessionToken); err != nil {
return nil, err
sessionTkns := make([]*session.Token, len(tokens.SessionTokens))
for i, encSessionToken := range tokens.SessionTokens {
sessionTkn := session.NewToken()
if err := sessionTkn.Unmarshal(encSessionToken); err != nil {
return nil, err
}
sessionTkns[i] = sessionTkn
}
gateData := NewGateData(owner.PublicKey(), bearerTkn)
gateData.SessionToken = sessionTkn
gateData.SessionTokens = sessionTkns
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
return gateData, nil
}

View file

@ -94,7 +94,7 @@ func Test_session_token_in_access_box(t *testing.T) {
require.NoError(t, tkn.Sign(&sec.PrivateKey))
gate := NewGateData(cred.PublicKey(), token.NewBearerToken())
gate.SessionToken = tkn
gate.SessionTokens = []*session.Token{tkn}
box, _, err = PackTokens([]*GateData{gate})
require.NoError(t, err)
@ -107,7 +107,7 @@ func Test_session_token_in_access_box(t *testing.T) {
tkns, err := box2.GetTokens(cred)
require.NoError(t, err)
require.Equal(t, tkn, tkns.SessionToken)
require.Equal(t, []*session.Token{tkn}, tkns.SessionTokens)
}
func Test_accessbox_multiple_keys(t *testing.T) {