diff --git a/api/handler/put.go b/api/handler/put.go index 44b7b505..0413c31f 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -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 != "" { diff --git a/api/layer/container.go b/api/layer/container.go index 6bff1924..a6fc5fcc 100644 --- a/api/layer/container.go +++ b/api/layer/container.go @@ -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)) } diff --git a/api/layer/layer.go b/api/layer/layer.go index 5062770c..8336237e 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -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) diff --git a/authmate/authmate.go b/authmate/authmate.go index 13674f6f..05e04429 100644 --- a/authmate/authmate.go +++ b/authmate/authmate.go @@ -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 } } diff --git a/creds/accessbox/accessbox.go b/creds/accessbox/accessbox.go index 3903cbbb..5e54bc54 100644 --- a/creds/accessbox/accessbox.go +++ b/creds/accessbox/accessbox.go @@ -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 } diff --git a/creds/accessbox/bearer_token_test.go b/creds/accessbox/bearer_token_test.go index 0fe0a390..f55cc57b 100644 --- a/creds/accessbox/bearer_token_test.go +++ b/creds/accessbox/bearer_token_test.go @@ -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) {