forked from TrueCloudLab/frostfs-s3-gw
[#329] Use suitable tokens for container requests
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
cce79b612a
commit
c383f332d5
6 changed files with 73 additions and 28 deletions
|
@ -549,7 +549,7 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
boxData, err := layer.GetBoxData(r.Context())
|
boxData, err := layer.GetBoxData(r.Context())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
policies = boxData.Policies
|
policies = boxData.Policies
|
||||||
p.SessionToken = boxData.Gate.SessionToken
|
p.SessionToken = boxData.Gate.SessionTokenForPut()
|
||||||
}
|
}
|
||||||
|
|
||||||
if createParams.LocationConstraint != "" {
|
if createParams.LocationConstraint != "" {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
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/eacl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"go.uber.org/zap"
|
"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 {
|
func (n *layer) setContainerEACLTable(ctx context.Context, cid *cid.ID, table *eacl.Table) error {
|
||||||
table.SetCID(cid)
|
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
|
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 {
|
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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,15 +299,6 @@ func (n *layer) CallOptions(ctx context.Context) []pool.CallOption {
|
||||||
return []pool.CallOption{pool.WithKey(&n.anonKey.Key.PrivateKey)}
|
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).
|
// 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) {
|
func (n *layer) Get(ctx context.Context, address *object.Address) (*object.Object, error) {
|
||||||
ops := new(client.GetObjectParams).WithAddress(address)
|
ops := new(client.GetObjectParams).WithAddress(address)
|
||||||
|
|
|
@ -484,8 +484,8 @@ func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions, cid *ci
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for i, sessionToken := range sessionTokens {
|
for i, sessionTkns := range sessionTokens {
|
||||||
gates[i].SessionToken = sessionToken[0]
|
gates[i].SessionTokens = sessionTkns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"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/netmap"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/token"
|
"github.com/nspcc-dev/neofs-sdk-go/token"
|
||||||
|
@ -33,10 +34,10 @@ type ContainerPolicy struct {
|
||||||
|
|
||||||
// GateData represents gate tokens in AccessBox.
|
// GateData represents gate tokens in AccessBox.
|
||||||
type GateData struct {
|
type GateData struct {
|
||||||
AccessKey string
|
AccessKey string
|
||||||
BearerToken *token.BearerToken
|
BearerToken *token.BearerToken
|
||||||
SessionToken *session.Token
|
SessionTokens []*session.Token
|
||||||
GateKey *keys.PublicKey
|
GateKey *keys.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGateData returns GateData from provided bearer token and public gate key.
|
// 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}
|
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.
|
// Secrets represents AccessKey and key to encrypt gate tokens.
|
||||||
type Secrets struct {
|
type Secrets struct {
|
||||||
AccessKey string
|
AccessKey string
|
||||||
|
@ -146,18 +180,20 @@ func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *keys.PrivateK
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w, sender = %d", err, i)
|
return fmt.Errorf("%w, sender = %d", err, i)
|
||||||
}
|
}
|
||||||
var encSession []byte
|
|
||||||
if gate.SessionToken != nil {
|
encSessions := make([][]byte, len(gate.SessionTokens))
|
||||||
encSession, err = gate.SessionToken.Marshal()
|
for i, sessionToken := range gate.SessionTokens {
|
||||||
|
encSession, err := sessionToken.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w, sender = %d", err, i)
|
return fmt.Errorf("%w, sender = %d", err, i)
|
||||||
}
|
}
|
||||||
|
encSessions[i] = encSession
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens := new(Tokens)
|
tokens := new(Tokens)
|
||||||
tokens.AccessKey = secret
|
tokens.AccessKey = secret
|
||||||
tokens.BearerToken = encBearer
|
tokens.BearerToken = encBearer
|
||||||
tokens.SessionToken = encSession
|
tokens.SessionTokens = encSessions
|
||||||
|
|
||||||
boxGate, err := encodeGate(ephemeralKey, gate.GateKey, tokens)
|
boxGate, err := encodeGate(ephemeralKey, gate.GateKey, tokens)
|
||||||
if err != nil {
|
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 {
|
if err := bearerTkn.Unmarshal(tokens.BearerToken); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sessionTkn := session.NewToken()
|
|
||||||
if err := sessionTkn.Unmarshal(tokens.SessionToken); err != nil {
|
sessionTkns := make([]*session.Token, len(tokens.SessionTokens))
|
||||||
return nil, err
|
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 := NewGateData(owner.PublicKey(), bearerTkn)
|
||||||
gateData.SessionToken = sessionTkn
|
gateData.SessionTokens = sessionTkns
|
||||||
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
|
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
|
||||||
return gateData, nil
|
return gateData, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ func Test_session_token_in_access_box(t *testing.T) {
|
||||||
require.NoError(t, tkn.Sign(&sec.PrivateKey))
|
require.NoError(t, tkn.Sign(&sec.PrivateKey))
|
||||||
|
|
||||||
gate := NewGateData(cred.PublicKey(), token.NewBearerToken())
|
gate := NewGateData(cred.PublicKey(), token.NewBearerToken())
|
||||||
gate.SessionToken = tkn
|
gate.SessionTokens = []*session.Token{tkn}
|
||||||
box, _, err = PackTokens([]*GateData{gate})
|
box, _, err = PackTokens([]*GateData{gate})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ func Test_session_token_in_access_box(t *testing.T) {
|
||||||
tkns, err := box2.GetTokens(cred)
|
tkns, err := box2.GetTokens(cred)
|
||||||
require.NoError(t, err)
|
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) {
|
func Test_accessbox_multiple_keys(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue